D3中过渡效果中的translate、rotate和order。

4

我想尝试使用d3过渡效果 - 我需要同时进行平移和旋转。 我有原始坐标:

let data = [    {x: 100, y: 100, rotation: 45},];

有2个矩形。一个先进行平移,另一个先进行旋转。

这是绘制矩形后的变换结果:

transform="rotate(45 115 105) translate(100, 100)"
transform="translate(100, 100) rotate(45 115 105)"

它们具有相同的平移和旋转变换,唯一不同的是它们的顺序。

然后我更改数据:

data[0].x += 30;
data[0].y += 20;
data[0].rotation += 45;

我期望你最终能完成这个转换:

transform="rotate(90 145 125) translate(130, 120)"
transform="translate(130, 120) rotate(90 145 125)"

但是我真正得到的是这个:
transform="translate(150, 110) rotate(90)"
transform="translate(400, 100) rotate(90)"
  • 请注意,它改变了第一个矩形的translate和rotate的顺序。
  • 它还从旋转变换中删除了旋转中心(是否在过渡期间进行计算?)
  • 它是如何得出结果数字的?

d3过渡效果是如何工作的?我需要得到一些可预期的结果,因为我正在尝试使用更高级的过渡效果。

以下是一个简单的例子:https://jsfiddle.net/pp6npw4g/2 (点击move启动过渡效果)


不是与您实际问题有关,而只是为了简洁明了和消除任何可能的错误来源:在您的JSFiddle中,您正在执行 .attr('transform', (d) => transformFunction(d)); 这样的操作,它只是将对 transformFunction() 的调用包装到另一个匿名函数中。这基本上相当于 .attr('transform', transformFunction);,只是传递函数的引用。 - altocumulus
我知道,这只是一个例子。在实际应用中,我会做更多的事情,而不仅仅是调用一个函数。但你是对的,在这个例子中可以简化。 - Klinki
没关系!很多人都会对此感到困惑。赞扬你保持简单,并提供一个剥离了的示例,而不是仅仅倾倒你的整个代码! - altocumulus
由于您围绕的中心不是原点,所以您需要实现一个自定义的缓动函数。请参考我对“D3 SVG transform rotation transition behaving weirdly”的回答,了解更多详细信息。链接 - altocumulus
1个回答

3
这是D3标准插值对“transform”属性值的预期行为。由于“transform”属性的值可能包含一个复杂的变换定义列表,而且这些定义可能以任何顺序出现甚至在同一列表中出现多次,因此它通常很难进行过渡动画。例如:
transform="translate(100) rotate(30, 100, 100) scale(2.5) translate(-10, -50) skewX(20)"

为了能够在这些值之间进行过渡,transition.attr() 函数在插值 transform 属性值时使用 d3.interpolateTransformSvg(a, b)。这样做会执行以下操作:
在d3-interpolate模块的内部函数parseSvg()中,通过调用接口SVGTransformList.consolidate()方法,将变换定义列表简化为一个列表。然后,使用私有函数decompose()将这个简化的变换分解为其translaterotateskewscale的值。我在我的答案中描述了这个分解变换列表的过程,回答了关于D3 v4中替换d3.transform的问题"Replacing d3.transform in D3 v4"
在转换过程中,由 d3.interpolateTransformSvg(a, b) 返回的插值器将插值计算 (1) translate、(2) rotate、(3) skewX 和 (4) scaleab 的相应值,顺序正好是这样的(链接到一个顺序列表)
这会给你留下合并后的值,可能一开始看起来有些出乎意料。此外,它解释了为什么转换的变换顺序会改变。要解决这个问题并实现自定义转换,您需要提供一个自定义的插值函数,可以通过调用 transition.attrTween() 来分配。这个函数的实现很大程度上取决于您的需求,超出了本回答的范围。

谢谢您的解释!我会尝试使用缓动函数。 - Klinki

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