Skip to content Skip to sidebar Skip to footer

D3.js Odd Rotation Behavior

I'm in the early stages of a JS project. Everything is going fine so far except for the positioning of one shape. The shape in question is a teal diamond (square rotated 45 degrees

Solution 1:

When you rotate the rect, you also rotate its coordinate system. So when you later move it 250 along the x axis, you're actually moving it 250 units along a 45 degree axis -- the result of the rotation.

As a rule, when you introduce a transform attribute as you did for rotate, you should do all your transformation via this attribute. So, you need to use translate instead of using the "x" attribute. Then it would look like this:

svg
  .append("rect")
  .attr("transform", "translate(250, 0) rotate(45)")
  // remove this: .attr("x", 250)
  .attr("height", w / 10)
  ...

This gets you the results I think you're looking for. Now note that the order of transformations matters here: if your transform was "rotate(45) translate(250, 0)" (i.e. first rotate then translate), you'd get the same, wrong results you got before. That's because when you rotate first, your translation happens, as before, along a rotated x axis.


Solution 2:

In SVG you must set the transform origin to get it to rotate from the center, such as...

.attr("transform", "rotate(45, 250, 100)");

Where 250, 100 is the x and y position of your rect minus it's radius. Putting it all together it would look like...

var svg = d3.select("body")
            .append("svg")
            .attr("width", 400)
            .attr("height", 300);
        svg
            .append("rect")
            .attr("transform", "rotate(30,"+ (diamond.x+diamond.width/2) + ","+ (diamond.y+diamond.width/2) +")")
            .attr("x", diamond.x)
            .attr("y", diamond.y)
            .attr("height", diamond.width)
            .attr("width", diamond.width)
            .attr("fill", "teal")​

You can view a demo here:

http://jsfiddle.net/uwM8u/


Solution 3:

Here is an approach slightly different from the answer Duopixel gave. Here you are not repeating the calculations for X and Y. In Duopixel's example, its a trivial improvement since he is merely referencing a structure. Its often the case that X and Y are functions and I would not want to maintain that loging in two places. This approach allows you to set X and Y a node, then rotate on the center of said node.

You may find that after the rotation, you still want to tweak the final position, which could be done with another transform, or in the case of TEXT, you can use dx, dy.

    svgNode.attr("transform", function (d) {

                    var w = +d3.select(this).attr("x") +  (this.getBBox().width / 2) ;
                    var h = +d3.select(this).attr("y") + (this.getBBox().height / 2);

                    return  "rotate(90," + w + "," + h + ")";

                })

Post a Comment for "D3.js Odd Rotation Behavior"