By default, the CoralBarChart and CoralStackChart will add a 3px corner radius to the top of the bar.
However, you can opt to provide your own custom corner radii via the modifiers.bar.cornerRadius property. Note that if you just provide a single integer value that it will only be applied to the top of the bar. If you want to provide individual corner radii, you can target the specific location per the type.
<CoralBarChart
data={basicTemplateData}
modifiers={{ bar: { cornerRadius: { top: 6, bottom: 6 } } }}
/>
As with the bar chart, the stack chart will add a 3px corner radius to the top of the bar – don't worry if you don't have values for each part of the stack, it will always apply the radius to the top-most item.
<CoralStackChart
data={groupBarTemplateData}
modifiers={{
chart: {
domainPadding: { x: 40, y: 20 },
},
}}
/>
However, unlike with the bar chart, providing a single integer value to the cornerRadius property will result in each bar getting the corner radius.
<CoralStackChart
data={groupBarTemplateData}
modifiers={{
chart: {
domainPadding: { x: 40, y: 20 },
},
bar: { cornerRadius: 10 },
}}
/>
This means you will need to provide a function to the property, in which you will need to calculate the top-most item.
bar: {
cornerRadius: {
top: ({ datum, index }) => {
// Get the data group for the current index
const dataGroup = groupBarTemplateData.map(
(d) => d[index as number]
);
// Find the last non-zero value in the data group
const lastNonZeroIndex = dataGroup
.slice()
.reverse()
.findIndex((item) => item.y > 0);
// Get the original index of the last non-zero value
const originalLastIndex =
groupBarTemplateData.length - lastNonZeroIndex;
// If the current datum is the last non-zero value, return a border radius
return originalLastIndex === datum._stack ? 5 : 0;
},
},
},
"But what about a chart that has negative values?"
If we plug the above in when our dataset has negative values in it, you'll see that there is no rounding on the bottom.
To achieve rounding on the bottom-most element, we need to extend our function so that it can calculate the last positive non-zero value or the last negative non-zero value.
bar: {
cornerRadius: {
top: ({ datum, index }) => {
const positiveDatasets: ChartData[][] = [];
const negativeDatasets: ChartData[][] = [];
// Split the data into positive and negative datasets
groupBarTemplateDataWithNegativeValues.forEach(
(dataset) => {
if (dataset[0].y >= 0) {
positiveDatasets.push(dataset);
} else {
negativeDatasets.push(dataset);
}
}
);
// Get the data group for the current index for the positive datasets
const positiveDataGroup = positiveDatasets.map(
(d) => d[index as number]
);
// Find the last non-zero value in the data group
const lastNonZeroPositiveIndex =
1 +
findLastIndex(
positiveDataGroup,
(item) => item?.y > 0
);
// Do the same for the negative datasets
const negativeDataGroup = negativeDatasets.map(
(d) => d[index as number]
);
const lastNonZeroNegativeIndex =
1 +
positiveDataGroup.length +
findLastIndex(
negativeDataGroup,
(item) => item?.y !== 0
);
// Check if the current datum is the last non-zero value
const isLastNonZeroBar =
lastNonZeroPositiveIndex === datum._stack ||
lastNonZeroNegativeIndex === datum._stack;
// If the current datum is the last non-zero value, return a border radius
return isLastNonZeroBar ? 5 : 0;
},
},
},
Note this makes use of lodash's findLastIndex function, which you can
install via pnpm i lodash.findlastindex. You could also make your own
function to calculate the last index if you don't want to add dependencies.
Voila!
"But my dataset has mixed positive-negative in the same object"
Yes, that is a limitation of this function. If you had a data array that looked something like this...
const groupBarTemplateData = [
[
{ x: '00', y: -1000 },
{ x: '01', y: 800 },
{ x: '02', y: 900 },
],
[
{ x: '00', y: 2300 },
{ x: '01', y: -1100 },
{ x: '02', y: -1940 },
],
[
{ x: '00', y: 1920 },
{ x: '01', y: 0 },
{ x: '02', y: -1300 },
],
];
...then you're going to find that the corner radii will be out of whack, because we check on the first element of the array to determine whether it should be grouped in the positive or the negative data groups.
Such data should be uncommon, however, the recommendation is that you make sure that each data array is either exclusively positive or exclusively negative.