How Can I Add Rounded Corners to Bar Chart in React Native SVG Chart?

210 Views Asked by At

I am working with the library react-native-svg-charts, which is built on top of react-native-svg, chart library: https://github.com/JesperLekland/react-native-svg-charts

With this library, I am using a bar chart. I would like to add rounded corners to the top of the bar chart, though there is no prop to do so.

It seems like a common want, so I am trying to follow one potential solution laid out in the issues page: https://github.com/JesperLekland/react-native-svg-charts/issues/48#issuecomment-832629493

Another solution is to use a transparent fill on the bars themselves, and create a new path with rounded corners.

import React from 'react';
import { G, Path } from 'react-native-svg';

import { roundedRectData } from '../utils/roundedRectData';

// this is a hack to add rounded top to the chart
const RoundedBars = ({ x, y, bandwidth, data, height, contentInset }) => {
  return data.map((item, index) => (
    <G x={x(index)} y={y(item.value)}>
      <Path
        d={roundedRectData(
          bandwidth,
          height - y(item.value) - (contentInset?.bottom || 0),
          bandwidth / 2,
          bandwidth / 2
        )}
        fill={item.svg.fill}
      />
    </G>
  ));
};

export default RoundedBars;

It seems like this persons idea is to make the initial bar chart transparent, and re-render new bars on top with the Path component, and use a translate function roundedRectData to render rounded bars instead.

They also link to a gist with the translate function: https://gist.github.com/danielpquinn/dd966af424030d47e476

/**
 * Get path data for a rounded rectangle. Allows for different radius on each corner.
 * @param  {Number} w   Width of rounded rectangle
 * @param  {Number} h   Height of rounded rectangle
 * @param  {Number} tlr Top left corner radius
 * @param  {Number} trr Top right corner radius
 * @param  {Number} brr Bottom right corner radius
 * @param  {Number} blr Bottom left corner radius
 * @return {String}     Rounded rectangle SVG path data
 */

var roundedRectData = function (w, h, tlr, trr, brr, blr) {
  return 'M 0 ' + tlr
    + ' A ' + tlr + ' ' + tlr + ' 0 0 1 ' + tlr + ' 0'
    + ' L ' + (w - trr) + ' 0'
    + ' A ' + trr + ' ' + trr + ' 0 0 1 ' + w + ' ' + trr
    + ' L ' + w + ' ' + (h - brr)
    + ' A ' + brr + ' ' + brr + ' 0 0 1 ' + (w - brr) + ' ' + h
    + ' L ' + blr + ' ' + h
    + ' A ' + blr + ' ' + blr + ' 0 0 1 0 ' + (h - blr)
    + ' Z';
};

I am trying to implement this, but cannot get it to work. So far I have:

const RoundedBars = ({x, y, bandwidth, data, height, contentInset}) => {
  return data.map((item, index) => (
    <G x={x(index)} y={y(item.value)}>
      <Path
        d={roundedRectData(
          bandwidth,
          height - y(item.value) - (contentInset?.bottom || 0),
          bandwidth / 2,
          bandwidth / 2,
        )}
        fill={GainGreenColor}
      />
    </G>
  ));
};

I then put the RoundedBars component directly in my BarChart:

<BarChart
     data={data.map((item) => item.value)}
     style={styles.chart}
     gridMin={0}
     svg={{
       fill: 'transparent',
     }}>
    <RoundedBars data={data} />
</BarChart>

The child should receive all the needed props by default (besides data).

However, when I run my code, I get an error giving invalid numbers. enter image description here

I'm not sure why this occurs. I tried to follow the provided example as closely as possible. I suspect it might be an issue with the translate function, since only 4 arguments are given, but 6 are expected, though I did copy it verbatim. The new rounded bars do not show up.

Does anyone know how I might fix this, or another concise and easy way to get the desired effect?

0

There are 0 best solutions below