说我有这样的任意路径:
[##########]
我还有一个这样的圈子:o
我想将o
放在任意路径的顶端,所以它看起来像这样:
[##########]o
(假设o
垂直居中于路径对象的顶部和底部之间)当路径增大或缩小时,o
应始终保持在尖端。
[###############]o
最重要的是,当变换应用于路径时,变换也应相应地应用于圆圈 - 它们在运动时应该同步。
我已经尝试将圆圈设为路径标记,但遇到了麻烦
答案 0 :(得分:3)
一个接一个地调用两个转换函数(每组形状一个)通常就足够了,因为浏览器运行代码所花费的时间远远少于动画帧之间的延迟。
但是,如果你的动画足够复杂,两者之间存在明显的滞后,或者你正在做很多会影响两个元素的复杂计算,你可以在一个选择上使用自定义补间函数,并在它选择另一个形状并更新它(你需要在你的“外部”函数中选择它,这样你在每次更新时调用的内部函数都可以快速重新定位它以匹配新值。)
关于转换,保持协调的最简单方法是将两个元素放在<g>
中并转换组而不是单个元素。
将这些想法放在一起,你可以得到一个像这样的过渡过程:
d3.selectAll("g.groups").transition().delay(time)
.attr("transform", function(d,i){ /* Calculate new transform */ })
.tween("stretch", function(d,i){
/* Select the sub-elements, do all the calculations
then create interpolators for both objects */
var g = d3.select(this);
var path = g.select("path");
var dot = g.select("circle");
var newEndPoint = /*** Calculate final position ***/;
var offset = /*** distance from end point to center of circle ***/;
var pathInterpolator = d3.interpolateString(
path.attr(d),
/*** new path including new end point ***/
);
var dotInterpolator = d3.interpolateObject(
{cx=dot.attr("cx"), cy=dot.attr("cy")},
{cx=newEndPoint.x + offset, cy=newEndPoint.y}
);
return function(t){
/* the function that updates both objects at each tick */
path.attr("d", pathInterpolator(t) );
dot.attr( dotInterpolator(t) );
};
});
当然,实际计算的复杂程度取决于“任意路径”的任意性。也许您需要计算x和y偏移以保持圆正确定位。但这成为几何问题,而不是同步问题。无论路径形状在转换时的其他形状如何,如果终点是路径数据中的实际点,它将以直线转换,与圆坐标的转换相同。