Accessing an Arc's Centroid X and Y Coordinates

2,181 views
Skip to first unread message

Guerino1

unread,
Jul 25, 2012, 8:27:59 AM7/25/12
to d3...@googlegroups.com
Hi,

I have a block of code that relies on Arcs and therefore the Arcs' centroids to place text on a Radial Hub and Spoke Diagram.  Does anyone know what the syntax is for accessing the Arc's X and Y centroid coordinates?  I believe I need them to properly evaluate what the correct text-anchor should be.

My current code looks as follows...

        // Add node names to the arcs, translated to the arc centroid and rotated.
        arcs3.filter(function(d) {
          return d.endAngle - d.startAngle > .2; }).append("svg:text")
            .attr("dy", "5px")
            .attr("angle", function(d) { return angle(d); })
            .attr("startAngle", function(d) { return d.startAngle; })
            .attr("endAngle", function(d) { return d.endAngle; })
            .attr("text-anchor", function(d) { return angle(d) < 0 ? "start" : "end"; })  // <---  CURRENTLY WRONG
            .attr("transform", function(d) { //set text'ss origin to the centroid
               // Make sure to set these before calling arc.centroid
               d.innerRadius = (height/2); // Set Inner Coordinate
               d.outerRadius = (height/2); // Set Outer Coordinate
               return "translate(" + arc3.centroid(d) + ")rotate(" + angle(d) + ")";
             })
            .style("fill", "Black")
            .style("font", "normal 12px Arial")
            .text(function(d) { return d.data.name; });


Thanks for your help,

Frank

Ger Hobbelt

unread,
Jul 25, 2012, 9:13:26 AM7/25/12
to d3...@googlegroups.com
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



Met vriendelijke groeten / Best regards,

Ger Hobbelt

--------------------------------------------------
web:    http://www.hobbelt.com/
        http://www.hebbut.net/
mail:   g...@hobbelt.com
mobile: +31-6-11 120 978
--------------------------------------------------

Ger Hobbelt

unread,
Jul 25, 2012, 9:23:10 AM7/25/12
to d3...@googlegroups.com
On Wed, Jul 25, 2012 at 2:27 PM, Guerino1 <fgue...@gmail.com> wrote:
Hi,

I have a block of code that relies on Arcs and therefore the Arcs' centroids to place text on a Radial Hub and Spoke Diagram.  Does anyone know what the syntax is for accessing the Arc's X and Y centroid coordinates?

And a direct answer, though that won't help with getting the Node texts positioned correctly, I fear:

looking at the d3.js code (grep for .centroid --> arc.js), we see:

  arc.centroid = function() {
    var r = (innerRadius.apply(this, arguments)
        + outerRadius.apply(this, arguments)) / 2,
        a = (startAngle.apply(this, arguments)
        + endAngle.apply(this, arguments)) / 2 + d3_svg_arcOffset;
    return [Math.cos(a) * r, Math.sin(a) * r];
  };

which means that the .centroid function itself delivers an array as a return value, where the X coordinate is at index [0], and the Y at index [1].

The fact that user code like this:

  return "translate(" + arc2.centroid(d) + ")rotate(" + angle(d, -90, 90) + ")";

works out so well as it does is because javaScript implicitly adds a ',' between array elements when it has to convert it to a string. https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/toString
That's another one of the JavaScript 'handy features' that d3 code is so fond of. (And which took me a while to grok.)

Frank Guerino

unread,
Jul 25, 2012, 11:05:34 AM7/25/12
to d3...@googlegroups.com
Thanks Ger.  I find this to be a very elegant way of addressing this.  I appreciate your help.

Frank
Reply all
Reply to author
Forward
0 new messages