Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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). I can get the square on the screen no problem, but when I add:

    .attr("transform", "rotate(45)")

the square rotates properly, but shifts towards the left portion of the screen, like this:

enter image description here

I am not sure what is causing this to happen. If it helps, here is some of the code that produced this result:

var svg = d3.select("body")
            .append("svg")
            .attr("width", w)
            .attr("height", h);
        svg
            .append("rect")
            .attr("transform", "rotate(45)")
            .attr("x", 250)
            .attr("height", w / 10)
            .attr("width", w / 10)
            .attr("fill", "teal")

Note: If I put the "y" attribute in, the square disappears completely.

What is causing this? Did I do something wrong that I just can't see?

like image 365
1080p Avatar asked Jun 11 '12 17:06

1080p


2 Answers

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.

like image 120
meetamit Avatar answered Oct 26 '22 13:10

meetamit


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/

like image 40
methodofaction Avatar answered Oct 26 '22 13:10

methodofaction