d3.js奇怪的旋转行为

10

我正在进行一个JS项目的初期阶段。目前一切都很顺利,除了一个形状的定位问题。这个形状是一个青色的菱形(旋转45度的正方形)。我可以将正方形轻松地放在屏幕上,但当我添加以下内容时:

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

方块可以正确旋转,但是会向屏幕左侧移动,就像这样:

enter image description here

我不确定是什么原因导致了这种情况。如果有帮助的话,这里是一些产生这种结果的代码:
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")

注意:如果我加入“y”属性,正方形就完全消失了。
这是什么原因?我做错了什么,但我看不出来?
3个回答

19

旋转矩形时,它的坐标系也会随之旋转。因此,当您稍后将其沿x轴移动250时,实际上是沿着45度轴线移动了250个单位——即旋转的结果。

通常,当您像对rotate一样使用transform属性时,应通过此属性执行所有变换。所以,你需要使用translate而不是使用"x"属性。那么它会看起来像这样:

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

这将为您提供我认为您正在寻找的结果。现在请注意,转换的顺序在这里很重要:如果您的转换是"rotate(45) translate(250, 0)"(即先旋转再平移),您将获得与之前相同的错误结果。这是因为当您首先进行旋转时,您的平移沿着旋转后的x轴发生,就像之前一样。


啊,你说得完全正确。非常感谢。现在我需要形状正好位于中心。使用勾股定理,我找到了横截面的长度,并将其除以2。该方程的结果是我想要设置为我的平移语句中的y坐标(当然要从画布高度/2中减去)。不过似乎我不能在这里使用变量。你知道我该怎么做吗? - 1080p
2
不需要使用勾股定理,只要按正确的顺序进行转换即可。假设 wh 是画布的大小,rwrh 是矩形的大小,这应该可以实现你所要求的:.attr("transform", "translate(" + (w/2) + "," + (h/2) + ") rotate(45) translate(" + (-rw/2) + "," + (-rh/2) + ")"。换句话说,首先将矩形的左上角移动到中心,然后旋转45度,然后沿着45度轴向后移动矩形宽度和高度的一半,使其居中。如果画布是300x300,矩形是100x100:"translate(150,150) rotate(45) translate(-50,-50)" - meetamit
有趣。我已经在我的代码中设置了勾股定理,但如果你的方法更快,我可能会换一下。非常感谢你的帮助。 - 1080p

12

在 SVG 中,您必须设置变换原点才能使其从中心旋转,例如...

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

其中250,100是矩形的x和y位置减去其半径。将所有内容组合在一起,看起来像这样...

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")​

这里可以查看演示:

http://jsfiddle.net/uwM8u/


已经得到了旋转的答案,但是你的代码片段在rotate属性的语法方面帮助了我很多。非常感谢。 - 1080p
谢谢。我在让它们围绕中心旋转方面遇到了问题。非常有帮助。 - greg

0
这里提供一种与Duopixel所给答案略有不同的方法。在这里,您不需要重复计算X和Y。在Duopixel的示例中,这是一个微不足道的改进,因为他只是参考了一个结构体。通常X和Y是函数,并且我不希望在两个地方维护该日志记录。
这种方法允许您在节点上设置X和Y,然后围绕该节点的中心进行旋转。
在旋转之后,您可能会发现仍然需要微调最终位置,可以使用另一个转换,或者在TEXT的情况下,可以使用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 + ")";

                })

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接