0

I would like to see the corners of the following chart rounded as if it were a borderRadius style prop but cannot figure out what pathData element I am missing. It looks like strokeLineJoin and strokeLineCap does pretty much nothing and updating the pathData with more arc data doesn't seem to help. I'm not sure if it's the spacing I'm trying to create between the pie slices are a limiting factor for viewing the rounded corners however placing a ridiculously high value to round the corners doesn't seem to have an effect either. Here is the code and a screenshot of what it produces:

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

interface PieSlice {
  value: number;
  color: string;
}

interface CustomPieChartProps {
  data: PieSlice[];
  size: number;
}

const CustomPieChart: React.FC<CustomPieChartProps> = ({ data, size }) => {
  const total = data.reduce((sum, slice) => sum + slice.value, 0);
  let cumulativeValue = 0;
  const cornerRadius = size / 20; // Adjust this value for more or less curvature

  const slices = data.map((slice) => {
    const startAngle = (cumulativeValue / total) * 2 * Math.PI;
    cumulativeValue += slice.value;
    const endAngle = (cumulativeValue / total) * 2 * Math.PI;

    const largeArcFlag = endAngle - startAngle > Math.PI ? 1 : 0;

    // Calculate points with corner radius
    const x1 = size / 2 + (size / 2) * Math.cos(startAngle);
    const y1 = size / 2 + (size / 2) * Math.sin(startAngle);

    const x2 = size / 2 + (size / 2) * Math.cos(endAngle);
    const y2 = size / 2 + (size / 2) * Math.sin(endAngle);

    const pathData = `
      M${size / 2},${size / 2}
      L${x1},${y1}
      A${size / 2},${size / 2} 0 ${largeArcFlag} 1 ${x2},${y2}
      L${size / 2},${size / 2}
      Z
    `;

    return (
      <Path
        key={`${slice.color}-${slice.value}`}
        d={pathData}
        fill={slice.color}
        stroke="white"
        strokeWidth={cornerRadius}
        strokeLinejoin="round"
        strokeLinecap="round"
      />
    );
  });

  return (
    <View style={{ justifyContent: 'center', alignItems: 'center' }}>
      <Svg width={size} height={size}>
        <G>
          {slices}
          <Circle cx={size / 2} cy={size / 2} r={size / 4} fill="white" />
        </G>
      </Svg>
    </View>
  );
};

export default CustomPieChart;

pie chart

0

1 Answer 1

1

This has noting to do with react-native-svg. The stroke-linecap and stroke-linejoin are applied to the stroke, not the fill. In your case it will complicate the calculations to give each path a stroke.

My initial idea was to draw three circle dashes parallel, the inner and outer with round line caps, and the one in the middle with square line caps. The line caps add to the length of the slice, and becomes difficult to work with as well.

Now that you have spaces between each slice it looks ridicules if the gap does not have the same width from inner to outer. Therefore it makes sense to mask off the slices using a line, so it forms the gap. And now that we are at it, adding circles to the mask that forms the border radius.

Here you have plain SVG examples. You can see that we both need to draw the colors and then have equally as many "mask lines". In the mask it is just a matter of repeating the grouping (<g>) and rotate them equal to the length of the color slices.

<svg viewBox="0 0 100 100" width="270">
  <defs>
    <mask id="m1" x="-50" y="-50" width="100" height="100">
      <circle fill="white" r="50" />
      <g transform="rotate(0)">
        <line x2="50" stroke="black" stroke-width="5"/>
        <circle transform="translate(30 0)" fill="black" r="6" />
        <circle transform="translate(51 0)" fill="black" r="9" />
        <circle transform="translate(35 8.5)" fill="white" r="6" />
        <circle transform="translate(35 -8.5)" fill="white" r="6" />
        <circle transform="translate(43.1 8.5)" fill="white" r="6" />
        <circle transform="translate(43.1 -8.5)" fill="white" r="6" />
      </g>
      <g transform="rotate(90)">
        <line x2="50" stroke="black" stroke-width="5"/>
        <circle transform="translate(30 0)" fill="black" r="6" />
        <circle transform="translate(51 0)" fill="black" r="9" />
        <circle transform="translate(35 8.5)" fill="white" r="6" />
        <circle transform="translate(35 -8.5)" fill="white" r="6" />
        <circle transform="translate(43.1 8.5)" fill="white" r="6" />
        <circle transform="translate(43.1 -8.5)" fill="white" r="6" />
      </g>
      <g transform="rotate(270)">
        <line x2="50" stroke="black" stroke-width="5"/>
        <circle transform="translate(30 0)" fill="black" r="6" />
        <circle transform="translate(51 0)" fill="black" r="9" />
        <circle transform="translate(35 8.5)" fill="white" r="6" />
        <circle transform="translate(35 -8.5)" fill="white" r="6" />
        <circle transform="translate(43.1 8.5)" fill="white" r="6" />
        <circle transform="translate(43.1 -8.5)" fill="white" r="6" />
      </g>
    </mask>
  </defs>
  <g transform="translate(50 50)" fill="none"
    stroke-width="20" mask="url(#m1)">
    <circle transform="rotate(0)" r="40" stroke="#88ef9c"
      pathLength="360" stroke-dasharray="90 360" />
    <circle transform="rotate(90)" r="40" stroke="#f67879"
      pathLength="360" stroke-dasharray="180 360" />
    <circle transform="rotate(270)" r="40" stroke="#77c1cc"
      pathLength="360" stroke-dasharray="90 360" />
  </g>
</svg>

<svg viewBox="0 0 100 100" width="270">
  <defs>
    <mask id="m2" x="-50" y="-50" width="100" height="100">
      <circle fill="white" r="50" />
      <g transform="rotate(0)">
        <line x2="50" stroke="black" stroke-width="5"/>
        <circle transform="translate(30 0)" fill="black" r="6" />
        <circle transform="translate(51 0)" fill="black" r="9" />
        <circle transform="translate(35 8.5)" fill="white" r="6" />
        <circle transform="translate(35 -8.5)" fill="white" r="6" />
        <circle transform="translate(43.1 8.5)" fill="white" r="6" />
        <circle transform="translate(43.1 -8.5)" fill="white" r="6" />
      </g>
      <g transform="rotate(90)">
        <line x2="50" stroke="black" stroke-width="5"/>
        <circle transform="translate(30 0)" fill="black" r="6" />
        <circle transform="translate(51 0)" fill="black" r="9" />
        <circle transform="translate(35 8.5)" fill="white" r="6" />
        <circle transform="translate(35 -8.5)" fill="white" r="6" />
        <circle transform="translate(43.1 8.5)" fill="white" r="6" />
        <circle transform="translate(43.1 -8.5)" fill="white" r="6" />
      </g>
      <g transform="rotate(135)">
        <line x2="50" stroke="black" stroke-width="5"/>
        <circle transform="translate(30 0)" fill="black" r="6" />
        <circle transform="translate(51 0)" fill="black" r="9" />
        <circle transform="translate(35 8.5)" fill="white" r="6" />
        <circle transform="translate(35 -8.5)" fill="white" r="6" />
        <circle transform="translate(43.1 8.5)" fill="white" r="6" />
        <circle transform="translate(43.1 -8.5)" fill="white" r="6" />
      </g>
      <g transform="rotate(280)">
        <line x2="50" stroke="black" stroke-width="5"/>
        <circle transform="translate(30 0)" fill="black" r="6" />
        <circle transform="translate(51 0)" fill="black" r="9" />
        <circle transform="translate(35 8.5)" fill="white" r="6" />
        <circle transform="translate(35 -8.5)" fill="white" r="6" />
        <circle transform="translate(43.1 8.5)" fill="white" r="6" />
        <circle transform="translate(43.1 -8.5)" fill="white" r="6" />
      </g>
    </mask>
  </defs>
  <g transform="translate(50 50)" fill="none"
    stroke-width="20" mask="url(#m2)">
    <circle transform="rotate(0)" r="40" stroke="#88ef9c"
      pathLength="360" stroke-dasharray="90 360" />
    <circle transform="rotate(90)" r="40" stroke="#f67879"
      pathLength="360" stroke-dasharray="45 360" />
    <circle transform="rotate(135)" r="40" stroke="#77c1cc"
      pathLength="360" stroke-dasharray="150 360" />
    <circle transform="rotate(280)" r="40" stroke="Plum"
      pathLength="360" stroke-dasharray="80 360" />
  </g>
</svg>

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.