0

I have a bunch of dots that I'm placing at even intervals around a circle. I'm doing this by setting their cx and cy attributes to the initial position, then iterating over each dot and giving it a transform(rotate) to move it to where I want it.

var dot = dotPlaces.append("circle")
                    .attr("cx", dotOriginX )
                    .attr("cy", dotOriginY )
                    .attr("r", 20 / 2)
                    .attr("opacity", 1)
                    .attr("id", function(d) { return d.name; })
                    .attr('fill', function(d) {
                        return color(d.type);
                    })
                    .attr("transform", function(d,i) {
                        return "rotate("+ (i * (360/actualData.length)) +"," + originX + "," + originY + ")";
                    })
                    .attr("stroke", "white");

My problem arrives when later in the code I want to draw lines to these dots. Whether I get their cx/cy attributes or their bounding box, it always references the original pre-transform position. I need their post-transform position. Apparently in d3 v3 there was a transform call that could be used, but in v4 this has vanished. Since I'm using a rotation and not a simple translation, this is less trivial than just adding some x and y offset.

This is what I'm using now, for reference:

var x = svg2.select("#"+key).node().getAttribute("cx");
var y = svg2.select("#"+key).node().getAttribute("cy");
//alternatively node().getBBox(); which also fails to give post-transform position.
IronWaffleMan
  • 2,513
  • 5
  • 30
  • 59
  • Can you use trig functions to calculate the x and y shifts that resulted from the rotation? – anbnyc Jul 05 '17 at 15:41
  • @anbnyc Yeah, probably, but I was hoping for a built-in way of doing it instead. – IronWaffleMan Jul 05 '17 at 15:49
  • You could try to access the transform matrix. One suggested replacement for d3.transform: https://stackoverflow.com/questions/38224875/replacing-d3-transform-in-d3-v4 – anbnyc Jul 05 '17 at 16:13

1 Answers1

1

As long as you only need to figure out the position relative to the <svg> element (or, to be precise, to the nearest viewport element), you can use the SVG interface .getCTM(). It gets you the transform matrix you can then apply to the cx/cy attributes.

var circle = d3.select('circle');
var cx = circle.attr('cx');
var cy = circle.attr('cy');
var ctm = circle.node().getCTM();
var x = cx * ctm.a + cy * ctm.c + ctm.e;
var y = cx * ctm.b + cy * ctm.d + ctm.f;
d3.select('p').text(x + ',' + y);
<script src="https://d3js.org/d3-selection.v1.min.js"></script>
<svg width="200" height="100">
    <circle cx="30" cy="30" r="10" transform="rotate(90 100 100)" />
</svg>
<p></p>
ccprog
  • 20,308
  • 4
  • 27
  • 44