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:
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?
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.
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/
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With