As pointed out by Michael Mullany
You need to change your textPath
drawing direction to get the desired alignment.
Ideally, you could use the textPath related side
attribute
(2023: only supported by Firefox!)
<svg class="ring-svg" width="100%" height="100%" viewBox="0 0 1000 1000">
<g class="sector-g" transform="translate(500,500)">
<path id="sectorPath_0" d="M 0 0 433.01270189221935 -249.99999999999997 A 500 500 0 0 0 3.061616997868383e-14 -500Z" fill="#e8ec77"></path>
<text class="segment-label" x="0" y="0" dy="20">
<textPath href="#sectorPath_0" startOffset="50%" text-anchor="middle" side="right">Label Text</textPath>
</text>
</g>
</svg>
<svg class="ring-svg" width="100%" height="100%" viewBox="0 0 1000 1000">
<g class="sector-g" transform="translate(500,500)">
<path id="sectorPath_1" d="M 0 0 433.01270189221935 -249.99999999999997 A 500 500 0 0 0 3.061616997868383e-14 -500Z" fill="#e8ec77"></path>
<text class="segment-label" x="0" y="0" dy="20">
<textPath href="#sectorPath_1" startOffset="50%" text-anchor="middle" side="left">Label Text</textPath>
</text>
</g>
</svg>

Left: Firefox (using side:right
); Right: Chromium (omitting side)
That's a bummer. However, the above example already simplifies the textPath
syntax significantly:
<text class="segment-label" x="0" y="0" dy="20">
<textPath href="#sectorPath_0" startOffset="50%" text-anchor="middle" side="right">Label Text</textPath>
</text>
The <text>
x attribute will add an additional startOffset
We just apply x="0"
as well as startOffset="50%"
and text-anchor="middle"
The dy
attribute is used to apply a baseline-offset.
Reversing the <textPath>
Fortunately, we can (at least in your case) assume, all pie chart segments are generated based on the same pattern/structure:
- starting at the center of the pie chart full circle
- drawing the pie chart "wedge" counter clockwise (for whatever reason ...)
- all commands are absolute
So we can rewrite/reverse the initial segment pathData in a predictable way.
I'm using the getPathData()
polyfill to parse the required command data.
let pieWedges = document.querySelectorAll(".segment");
pieWedges.forEach((path) => {
let pathData = path.getPathData();
let reversedPathData = reversePieWedge(pathData);
path.setPathData(reversedPathData);
});
function reversePieWedge(pathData) {
let reversedPathData = [
// M - unchanged
pathData[0],
{ type: "L", values: [pathData[2].values[5], pathData[2].values[6]] },
// reverse arcto
{
type: "A",
values: [
pathData[2].values[0],
pathData[2].values[1],
pathData[2].values[2],
pathData[2].values[3],
// reverse sweep flag
1,
// inherit final point from first lineto
pathData[1].values[0],
pathData[1].values[1]
]
},
{ type: "Z", values: [] }
];
return reversedPathData;
}
<svg id="svg" class="ring-svg" width="100%" height="100%" viewBox="0 0 1000 1000">
<path d="M500 500L938.15 259.12A500 500 0 0 0 500 0L500 500Z" fill="#80e080" class="segment segment-17_000 segment-1 segCustom" id="seg0" />
<path d="M500 500L593.69 991.14A500 500 0 0 0 938.15 259.12L500 500z" fill="#ccc" class="segment segment-30_000 segment-2 segCustom" id="seg1" />
<!-- labels -->
<text class="segment-label" x="10" y="0" dy="25" >
<textPath href="#seg0" startOffset="50%" text-anchor="middle">Label Text</textPath>
</text>
<text class="segment-label" x="10" y="0" dy="25" >
<textPath href="#seg1" startOffset="50%" text-anchor="middle">Label Text</textPath>
</text>
</svg>
<script src="https://cdn.jsdelivr.net/npm/path-data-polyfill@1.0.4/path-data-polyfill.min.js"></script>
As you can see, regardless of the segments's arc length, the label is always centered.
Check/fix the segment path generating script?
As mentioned before, it is better to draw/generate pie charts in a clockwise direction:
renderPoint(svg, [500, 500], "green", "2%", "1");
renderPoint(svg, [500, 0], "orange", "2%", '2');
renderPoint(svg, [933, 250], "red", "2%", '3');
function renderPoint(
svg,
coords,
fill = "red",
r = "2",
textVal = "",
opacity = "1",
id = "",
className = ""
) {
//console.log(coords);
if (Array.isArray(coords)) {
coords = {
x: coords[0],
y: coords[1]
};
}
let marker = `<circle class="${className}" opacity="${opacity}" id="${id}" cx="${coords.x}" cy="${coords.y}" r="${r}" fill="${fill}">
<title>${coords.x} ${coords.y}</title></circle>
<text
x="${coords.x}"
y="${coords.y}"
font-size="${parseFloat(r)*15}"
dominant-baseline="middle"
text-anchor="middle">${textVal}</text>`;
svg.insertAdjacentHTML("beforeend", marker);
}
svg{
width:30em;
overflow: visible;
}
<svg id="svg" class="ring-svg" width="100%" height="100%" viewBox="0 0 1000 1000">
<g class="sector-g" transform="translate(500,500)">
<path id="sectorPath_0" d="
M 0 0
L 0 -500
A 500 500 0 0 1 433 -250
Z
" fill="#e8ec77"></path>
<text class="segment-label" x="0" y="0" dy="20" >
<textPath xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#sectorPath_0" startOffset="50%" text-anchor="middle">Label Text</textPath>
</text>
</g>
</svg>
So you should check if your pie-chart generator includes an option/parameter to change drawing directions.