A sideways answer, after having had a look at the gist:
which has all the 'Node xx' texts sticking out (correctly, I assume).
The trick wasn't so much getting at the X/Y of the centroid, but taking a step back and reconsider your angle() function, which was doing two things at once, or rather three (which was one too many ;-) ):
1a- average the start and end angle of the arc
1b- convert from radians to degrees
2- rotate by another 90 degrees and flip the rotation when the angle was above the threshold
#2 was indeed very handy to get the correct 'put it there, turn it 90 degrees in the "proper" direction for legibility' transform statement for the inner texts, but the outer texts had one extra bit, that required a different threshold (legibility there being also determined by "text-anchor" being either 'start' or 'end' depending on where you are, arc-wise.
And since angle() as it was already reduced the 0-360 degree angle range (after 1a+1b) to a 0-180 angle range, you're SOL when you have only that data and need to determine the correct "text-anchor" value.
So I parameterized the angle function:
function angle(d, offset, threshold) {
var a = (d.startAngle + d.endAngle) * 90 / Math.PI + offset;
return a > threshold ? a - 180 : a;
}
so that the "text-anchor" section could use a different offset and threshold (0,0) than the others (-90, 90).
Compare the index.html in the gist above with yours to see the differences.
HTH