Here's a snapshot of my code:
const data = filteredKeys.map((key, index) => {
return {
key,
value: filteredValues[index],
svg: { fill: colors[index] },
arc: {
outerRadius: 70 + filteredValues[index] + '%',
padAngle: label === key ? 0.1 : 0,
},
onPress: () =>
setSelectedSlice({ label: key, value: filteredValues[index] }),
};
});
const Labels = ({ slices, height, width }) => {
return slices.map((slice, index) => {
console.log(slice);
const { labelCentroid, pieCentroid, data } = slice;
return (
<Text
key={index}
x={labelCentroid[0]}
y={labelCentroid[1]}
fill={'#000'}
textAnchor={'middle'}
alignmentBaseline={'center'}
fontSize={14}
stroke={'black'}
strokeWidth={0.2}
>
{data.key}
</Text>
);
});
};
return (
<View style={styles.container}>
<PieChart
style={{ height: 300 }}
outerRadius={'100%'}
innerRadius={'10%'}
data={data}
labelRadius={'85%'}
>
<Labels />
</PieChart>
</View>
);
This is the result:
I want to labels to align like this:
The labels look very inconsistent on different pie charts, that's why I want to render the labels along the curve of their respective arcs (center of the arc is prefered).
I have tried TextPath and TSpan from react-native-svg, but couldn't figure out how to draw the TextPath when it is child of the component along which the path is to be drawn.
Hate to resurrect this but since I was wanting to do the same thing I figured I would show the math behind it.
Given we know the center of the circle is 0,0 and we have the x,y of the labels current position we can calculate the adjacent angle which is what your looking for. Heres a simple diagram to illustrate .
tx,ty = labelCentroid
R = atan2(ty, tx)
Given that information the example code below gives the desired results.
function TestPieChart() {
const Labels: any = ({slices, height, width}) => {
return slices.map((slice, index) => {
const {labelCentroid, data} = slice;
const labelAngle =
Math.atan2(labelCentroid[1], labelCentroid[0]) + Math.PI / 2;
return (
<G key={index}>
<Text
transform={
`translate(${labelCentroid[0]}, ${labelCentroid[1]})` +
`rotate(${(360 * labelAngle) / (2 * Math.PI)})`
}
fill={'#000000'}
textAnchor={'middle'}
alignmentBaseline={'center'}
fontSize={14}
stroke={'black'}
strokeWidth={0.2}
>
{data.key}
</Text>
</G>
);
});
};
return (
<View style={{backgroundColor: 'white'}}>
<PieChart
data={[
{key: 'arms', value: 20, svg: {fill: '#FAA'}},
{key: 'legs', value: 20, svg: {fill: '#1bb234'}},
{key: 'chest', value: 50, svg: {fill: '#8a5a00'}},
{key: 'foot', value: 30, svg: {fill: '#00ffbb'}},
{key: 'finger', value: 20, svg: {fill: '#223193'}},
]}
style={{height: 270, marginTop: 0, padding: 10}}
padAngle={0}
outerRadius={'90%'}
innerRadius={'80%'}
labelRadius={'100%'}
>
<Labels></Labels>
</PieChart>
</View>
);
}