我跟着example here关于使用canvas元素的转换。
由于我使用的是d3版本4.2.2,我尝试移植示例但没有成功。
问题是(取决于d3.timer
持续时间)动画停在一个点,点不在其正确的位置。它适用于 d3 v3 。以下是代码的一部分:
var duration = 1000;
var delay = function(d) {
return d.i;
}
var maxDelay = 0;
var timeScale = d3.scaleLinear()
.domain([0, duration])
.range([0, 1]);
data.forEach(function(d) {
d.trans = {
i: d3.interpolateNumber(height, d.y),
delay: delay(d)
};
if (d.trans.delay > maxDelay) {
maxDelay = d.trans.delay;
}
});
var renderTime = 0;
var timer = d3.timer(moveCircles);
function moveCircles(t) {
data.forEach(function(d) {
var time = timeScale(t - d.trans.delay);
d.y = d.trans.i(time);
});
var start = new Date();
drawCircles('black');
var end = new Date();
renderTime += (end - start);
if (t >= duration + maxDelay) {
console.log('Render time:', renderTime);
timer.stop();
return true;
}
}
See this plunker获取完整示例。红点表示数据的正确位置(x / y)。因此,每个黑点应与一个红点重叠。点的y值越高,到其正确位置的距离越高。这导致我假设y值的插值存在误差?
有没有办法设置持续时间(例如1000)并为点s.t设置动画。在指定的持续时间后,每个点都处于正确的位置?
编辑:事实证明,使用与提供的示例中相同的easeCubicInOut
,它可以正常工作。我不知道为什么会这样。
var ease = d3.easeCubicInOut;
...
function moveCircles(t) {
data.forEach(function(d) {
//var time = timeScale(t - d.trans.delay); // without the ease it won't work
var time = ease(timeScale(t - d.trans.delay));
d.y = d.trans.i(time);
});
...
我怎样才能轻松自如?
答案 0 :(得分:1)
不是直接的答案,因为我没有完成所有的计算,但这里有数学的东西:
var time = timeScale(t - d.trans.delay);
d.y = d.trans.i(time);
t - d.trans.delay
需要生成介于0和1000之间的值,以便它在0到1之间缩放。显然,您正在提供的interpolate
函数值大于1.我相信这样:
if (t >= duration + maxDelay) {
是罪魁祸首,因为你要将动画运行超过1000毫秒。
一种天真的方法就是限制它:
var time = timeScale(t - d.trans.delay);
if (time > 1) time = 1;
d.y = d.trans.i(time);
那就是说,我不确定这段代码是否需要如此复杂。一个基本的transition应该可以做你想做的事情:
d3.select({})
.transition()
.duration(duration)
.tween("animate.circles", function() {
return function(t) {
data.forEach(function(d,i){
d.y = d.trans.i(t);
});
drawCircles('black');
};
});
更新了plunker。