javascript d3.js 奇数旋转行为

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/10985077/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-26 11:43:28  来源:igfitidea点击:

d3.js Odd Rotation Behavior

javascriptd3.js

提问by 1080p

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:

我正处于 JS 项目的早期阶段。到目前为止,除了一个形状的定位外,一切都很好。有问题的形状是蓝绿色钻石(正方形旋转 45 度)。我可以在屏幕上显示方块没问题,但是当我添加时:

    .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.

注意:如果我输入“y”属性,方块会完全消失。

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

这是什么原因造成的?我做错了什么,我只是看不到吗?

回答by meetamit

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.

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

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

通常,当您transform像为 一样引入一个属性时rotate,您应该通过该属性完成所有转换。因此,您需要使用translate而不是使用该"x"属性。然后它看起来像这样:

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.

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

回答by methodofaction

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

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

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

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

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

You can view a demo here:

您可以在此处查看演示:

http://jsfiddle.net/uwM8u/

http://jsfiddle.net/uwM8u/

回答by greg

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.

这是一种与 Duopixel 给出的答案略有不同的方法。在这里你没有重复 X 和 Y 的计算。在 Duopixel 的例子中,这是一个微不足道的改进,因为他只是引用了一个结构。通常情况下 X 和 Y 是函数,我不想在两个地方维护那个登录。这种方法允许您将 X 和 Y 设置为一个节点,然后在该节点的中心旋转。

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.

你可能会发现在旋转之后,你仍然想要调整最终位置,这可以通过另一个变换来完成,或者在 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 + ")";

                })