Custom Corner Radii

Bar Chart

By default, the CoralBarChart and CoralStackChart will add a 3px corner radius to the top of the bar.

01,0002,0003,0004,00023

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.

01,0002,0003,0004,00023
<CoralBarChart
  data={basicTemplateData}
  modifiers={{ bar: { cornerRadius: { top: 6, bottom: 6 } } }}
/>

Stack Chart

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.

01,0002,0003,0004,0005,0006,00008
<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.

01,0002,0003,0004,0005,0006,00008
<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.

01,0002,0003,0004,0005,0006,000000102030405060708
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.

−6,000−4,000−2,00002,0004,0006,000000102030405060708

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;
      },
  },

},
−6,000−4,000−2,00002,0004,0006,000000102030405060708

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.