..and of course its actually the entire segment, meaning it contains a line for the outer radius, plus one for the inner radius, plus another 2 to join the inner and outer radius of the arc. So when you use startOffset, it's applying to the entire length of the path - not the length of arc- which is the path along which you'd like to create the textPath.

A simple answer is to adjust startOffset to a smaller number than 50% to account for the fact that the path is more than twice as long as the one I want to use - so it should work out to something between 20 & 25%.

Here's the updated version which will calculate an approximate startoffset to center the text

var groupText = group.append("text")

.attr("dy", (outerRadius - innerRadius) / 2 + 4)

.attr("text-anchor", "middle");

var groupTextPath = groupText

.append("textPath")

.attr("xlink:href", function(d) {

return "#group" + d.index;

})

.attr("startOffset", function(d) {

var length = path.nodes()[d.index].getTotalLength();

return (25-(50 *outerRadius)/length+(50 *innerRadius)/length) + "%";

})

.text(function(d) {

return participants[d.index];

});

The code

Here's the complete example. Note that this uses d3 version 4, which is just out at the time of writing. Some of the syntax has changed between v3 and v4, so this code will only work on v4 as is.