Maria
Maria

Reputation: 91

Aligning text around center in pie chart using svg circle and text

I've created a pie chart using react and svg circles. Now I want to position the text labels so that the text starts close to the middle of the circle and continue outwards, wheel of fortune style.

This is my code, rendering the svgs. In chrome dev tools I tried to apply tranform: rotate(45deg); and adjusting the number but the text keeps flyying away outside the circle.

<svg viewBox="0 0 32 32">
    {elements.map((element, index) => (
        <g>
            <circle
                key={_id}
                r={16 / 1.0053}
                cx={'50%'}
                cy={'50%'}
                style={{
                    strokeDasharray: `${percentage}, 100.53`,
                    strokeDashoffset: -offset,
                    stroke: segmentColor,
                }}
                textAnchor="middle"
            ></circle>
            <text
                textAnchor="middle"
                x={'50%'}
                y={'50%'}
                fontFamily={'sans-serif'}
                fontSize={'20px'}
                fill="black"
                textAnchor="start"
            >
                {title}
            </text>
        </g>
    ))}
</svg>
``` 

Upvotes: 0

Views: 694

Answers (1)

Peter Collingridge
Peter Collingridge

Reputation: 10979

The issue is that rotation is about the origin, which is the top left of your image. The easiest way around this is to change the viewBox so the origin is in the center of your SVG: viewBox="-16 -16 32 32".

Then you calculate the angle based on the offset and the percentage.

I assume you have some elements like this:

const elements = [
    { percentage: 15, offset: 0, title: 'title', segmentColor: 'red' },
    { percentage: 40, offset: 15, title: 'another title', segmentColor: 'blue' },
    { percentage: 25, offset: 55, title: 'and another', segmentColor: 'green' },
    { percentage: 20, offset: 80, title: 'yet another', segmentColor: 'black' },
];

So something like this would work:

<svg viewBox="-16 -16 32 32">
    {elements.map((element, index) => {
        const angle = (element.offset + element.percentage / 2) * 360 / 100;

        return <g key={index}>
            <circle
                r={15.5}
                style={{
                    fill: 'none',
                    strokeDasharray: `${element.percentage}, 100.53`,
                    strokeDashoffset: -element.offset,
                    stroke: element.segmentColor,
                }}
                textAnchor="middle"
            ></circle>
            <text
                x="10%"
                transform={`rotate(${angle})`}
                fontFamily={'sans-serif'}
                fontSize={'2px'}
                fill="black"
                textAnchor="start"
                alignmentBaseline="middle"
            >
                {element.title}
            </text>
        </g>
    })}
</svg>

Now the x value on the text determined how from the center the text starts.

enter image description here

Upvotes: 1

Related Questions