代码之家  ›  专栏  ›  技术社区  ›  tic

如何使用d3重新启动(恢复)画布动画中暂停的计时器

  •  0
  • tic  · 技术社区  · 7 年前

    我构建了以下玩具示例(jsfiddle here ; 请在10秒内单击停止按钮):

    var width = 750, height = 400;
    var canvas = d3.select("body")
      .append("canvas")
      .attr("width", width)
      .attr("height", height);
    var context = canvas.node().getContext("2d");   
    var x=Math.random()*50;
    var y=Math.random()*50;
    
    d3.select("body")
    .append("button")
    .html("stop")
    .on("click",function(){ti.stop()});
    d3.select("body")
    .append("button")
    .html("restart")
    .on("click",function(){ti.restart()});
    
    var ti = d3.timer(function(elapsed) {
    context.clearRect(0, 0, width, height); // Clear the canvas.
    context.fillStyle="red";
    var t=Math.min(1,elapsed/10000)
    context.fillRect(x*(1-t)+width*t,y*(1-t)+height*t,10,10);
    })  
    

    time.restart() 命令也不起作用,所以我想我还不明白在D3中如何暂停/重新启动计时器。

    2 回复  |  直到 7 年前
        1
  •  2
  •   David    7 年前

    timer.restart() 没有你想的那么有用。从 docs :

    定时器 重新启动 回拨 [, 时间 ]])

    另外,正如您在函数定义中看到的,参数 callback 是强制性的。所以你才会 TypeError: callback is not a function

    基本上,您应该将匿名回调函数转换为命名回调函数,并将其传递给构造函数和 restart

    elapsed 要计算动画的位置,需要自己计算时间。在使用创建计时器之前设置开始时间 d3.now() 减去动画已经运行的时间(即第一次调用为0)。

    var totalElapsedTime = 0;
    var startTime = d3.now() - totalElapsedTime;
    var t = d3.timer(myCallback);
    

    var elapsedTime = d3.now() - startTime;
    // This is how d3.js calculates `elapsed`.
    // The actual code is more complicated but the result is the same.
    

    click 的事件处理程序 stop 按钮:

    on("click",function(){
        totalElapsedTime = d3.now() - startTime; 
        ti.stop();
    });
    

    更新 startTime 的事件处理程序 重新启动

    .on("click",function(){
        startTime = d3.now() - totalElapsedTime;
        ti.restart(myCallback);
    });
    

    你就完了。

    was suggested on GitHub ,但已被解雇。其他开发商 forked the project 如果你有兴趣的话。

    注意 :在下面的代码片段中,我稍微简化了代码并缩小了画布的大小,这样在代码片段窗口中跟踪动画就更容易了。

    var width = 300,
        height = 150;
    var canvas = d3.select("body")
      .append("canvas")
      .attr("width", width)
      .attr("height", height);
    var context = canvas.node().getContext("2d");
    
    d3.select("body")
      .append("button")
      .html("stop")
      .on("click", function() {
        totalElapsedTime = d3.now() - startTime;
        ti.stop();
      });
    d3.select("body")
      .append("button")
      .html("restart")
      .on("click", function() {
        startTime = d3.now() - totalElapsedTime;
        ti.restart(myCallback);
      });
    
    var startTime = d3.now();
    var totalElapsedTime = 0;
    var ti = d3.timer(myCallback);
    
    function myCallback() {
      var elapsedTime = d3.now() - startTime;
      context.clearRect(0, 0, width, height);
      context.fillStyle = "red";
      var t = Math.min(1, elapsedTime / 10000)
      context.fillRect( width * t, height * t, 10, 10);
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
        2
  •  1
  •   rioV8    7 年前

    当你停止计时时,你必须记下时间。

    var width = 750, height = 400;
    var canvas = d3.select("body")
      .append("canvas")
      .attr("width", width)
      .attr("height", height);
    var context = canvas.node().getContext("2d");	
    var x=Math.random()*50;
    var y=Math.random()*50;
    
    d3.select("body")
      .append("button")
      .html("stop")
      .on("click",function(){t.stop(); alreadyElapsed = stopAt;});
    d3.select("body")
      .append("button")
      .html("restart")
      .on("click",function(){t = createTimer();});
    
    var t = createTimer();
    var stopAt;
    var alreadyElapsed = 0;
    
    function createTimer() {
      return d3.timer(function(elapsed) {
        elapsed += alreadyElapsed;
        stopAt = elapsed;
        context.clearRect(0, 0, width, height); // Clear the canvas.
        context.fillStyle="red";
        var t=Math.min(1,elapsed/10000)
        context.fillRect(x*(1-t)+width*t,y*(1-t)+height*t,10,10);
      });
    }
    rect {
      fill:steelblue;
    }
    <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.13.0/d3.js"></script>