【问题标题】:D3 V4 - Canvas Transitions: d3.timer durationD3 V4 - 画布过渡:d3.timer 持续时间
【发布时间】:2017-01-12 04:01:55
【问题描述】:

我关注了example here 关于画布元素的过渡。 由于我使用的是 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);
  });
...

我怎样才能跳过轻松?

【问题讨论】:

    标签: javascript animation html5-canvas d3.js


    【解决方案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

    【讨论】:

    • 非常感谢您的努力。我完全同意你的观点,你的 plunker 效果很好!问题是 afaik 转换在数据点的数量方面不可扩展(或者是否有解决方法?),这基本上是我使用画布而不是 svg 的意图之一。如果你例如换size = 10000,转场就不顺畅了。
    猜你喜欢
    • 1970-01-01
    • 2020-10-17
    • 2018-10-20
    • 2019-12-05
    • 1970-01-01
    • 1970-01-01
    • 2015-07-14
    • 2012-07-07
    • 1970-01-01
    相关资源
    最近更新 更多