【问题标题】:Can d3's transition and rotation play well together?d3的转场和轮换能很好的配合吗?
【发布时间】:2012-09-11 17:54:48
【问题描述】:

与旋转结合的过渡会产生奇怪的结果。

这是我的问题:http://jsfiddle.net/emperorz/E3G3z/1/ 尝试点击每个方块以查看不同的行为。

请原谅被黑的代码,但如果我使用带有旋转(和 x/y 位置)的过渡,那么它会循环播放。

我试过了:

1) 全部在变换中(旋转然后平移),这似乎还可以。有点摇晃。

2) 只需在变换中旋转,使用 x/y 属性定位。到处飞,但最终到达正确的位置。很奇怪。

3) 全部在变换中(平移然后旋转),飞走,最终在(完全)错误的地方结束。

嗯。奇怪。

是否有使用过渡旋转形状的正确方法?

直观地说,如果第二个选项有效,那就太好了。

谢谢

【问题讨论】:

    标签: javascript rotation d3.js transition jsfiddle


    【解决方案1】:

    iirc 平移是相对于 0,0 而旋转是围绕对象的中心点

    因此,由于您的形状偏离 0,0(例如 100,200 或 200,100),因此它们最终会在翻译时迁移。这可以通过将 Diamond3 的偏移更改为 [50,50] 来看到 - 屏幕周围的迁移要小得多

    解决方案是将 0,0 点重新定位到钻石的中心。在 D3 中有一种方法可以做到这一点 - 但我不记得它是什么 :(

    【讨论】:

    • 可能我误解了你,但实际上,1 和 2 应该是相同的。它们最终位于相同的位置(过渡的端点没有几何差异),但在过渡期间,路径是很好的循环本轮。我猜小摆动是由于 arctan 函数或类似函数中的错误造成的,但大循环只是奇怪的。
    • 在示例中,当您单击时,您将再次将 X、Y 值添加到起点(一次又一次)。因此,当页面加载时,您将 Diamond2 转换为 100,200。当用户点击时,diamond2 会旋转 65 度 - 并再次平移 100,200。不同的行为是由先旋转后平移、边平移边旋转或先平移引起的,而尺度的不同是由平移值的不同引起的。为了证明这一点,请编辑您的小提琴以从点击处理程序转换中删除“Diamond2.x”和“Diamond2.y”。
    • 不,它不会重复更改翻译。旋转增加,但平移保持不变。
    • 我已经稍微清理了一下。 “问题”似乎在于插值的完成方式。嗯。我可能会做一个纯 svg 动画,看看它是否做同样的事情。
    • 好的。在弄乱了原生 SVG 动画,并与绝对定位和相对定位和旋转(太不直观)搏斗之后,我现在知道了避免这个问题的方法。所以,这是我的解决方法,直到我得到答案,尽管我没有屏住呼吸。围绕原点构造所有形状。使用 group 和 transform 定义自己的相对框架(避免绝对位置但相对旋转不愉快)。每个单独和单独的过渡。现在我需要查看转换是并行运行(a la SVG)还是顺序运行。无论如何,不​​要摇晃,耶!
    【解决方案2】:

    要在任意轴上旋转 SVG 对象,您需要两个转换:translate(设置轴)和rotate。您真正想要的是首先完全应用translate,然后旋转已经移动的元素,但似乎translaterotate 独立且同时运行。这在正确的位置结束,但是为translate 设置动画实际上是在旋转期间移动轴,从而产生摆动。您可以将translaterotate 隔离开来,方法是让它们出现在SVG 元素层次结构中的不同位置。例如,看看以下内容:

    <g class="outer">
        <g class="rect-container">
            <rect class="rotate-me" width=200 height=100 />
        </g>
    </g>
    

    您可以使用translate (-100, -50)&lt;rect&gt; 居中在(0,0) 上。如果您将旋转应用于&lt;rect&gt; 元素,它将摇晃,但如果您将rotate g.rect-container 元素旋转,它将完全旋转。如果您想重新定位、缩放或以其他方式进一步转换元素,请在g.outer 上执行此操作。而已。您现在可以完全控制您的变换。

    找到&lt;rect&gt; 的中心很容易,但是找到&lt;path&gt;&lt;g&gt; 等的中心要困难得多。幸运的是,.getBBox() 方法中提供了一个简单的解决方案(CoffeeScript 中的代码;请参阅下面的 JavaScript 版本*):

    centerToOrigin = (el) ->
        boundingBox = el.getBBox()
        return {
            x: -1 * Math.floor(boundingBox.width/2),
            y: -1 * Math.floor(boundingBox.height/2) 
        }
    

    您现在可以通过传递未包装的元素(使用 D3 的 .node() 方法)来居中您的元素/组

    group = d3.select("g.rotate-me")
    center = centerToOrigin(group.node())
    group.attr("transform", "translate(#{center.x}, #{center.y})")
    

    对于在单个 &lt;rect&gt;&lt;g&gt; 中的 2 个 rects 上实现此功能并进行重新定位和缩放的代码,see this fiddle


    *以上代码的Javascript:

    var center, centerToOrigin, group;
    
    centerToOrigin = function(el) {
      var boundingBox;
      boundingBox = el.getBBox();
      return {
        x: -1 * Math.floor(boundingBox.width / 2),
        y: -1 * Math.floor(boundingBox.height / 2)
      };
    };
    
    group = d3.select("g.rotate-me");
    center = centerToOrigin(group.node());
    group.attr("transform", "translate(" + center.x + ", " + center.y + ")");
    

    【讨论】:

    • 你统治,第一段和例子是无价的!赞一个!
    • 谢谢!很高兴它有帮助!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-07-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-28
    相关资源
    最近更新 更多