How to use requestAnimationFrame to animate multiple squares in a loop

前端 未结 2 1371
自闭症患者
自闭症患者 2021-01-24 01:32

I am using HTML canvas to draw multiple squares. I have 2 functions: 1) draw a square and 2) draw multiple squares inside a loop.

Now I want to animate these squares us

相关标签:
2条回答
  • 2021-01-24 02:16

    You can do something like

    var numRects = 10;
    var size = 5;
    var i = 1;                          // which rectangle we're drawing
    var delay = 1000/60;                // num miliseconds between frames
    var before = new Date().getTime(),  // last draw time in ms
        now;                            // current time in ms
    
    function animateRect() {
      // get the current time to find if we should draw
      now = new Date().getTime();
    
      // if sufficient time passed since last draw, draw a rect
      if ( now - before > delay && i <= numRects) {
        rect(i * size, i * size, (i * size) * 2, (i * size) * 2);
        i++;
        before = now;
      }
    
      requestAnimFrame(animateRect);
    }
    

    Edit:

    As Blindman67 pointed out below, requestAnimFrame passes the current timestamp since the beginning of the animation to the callback. Here's how to take advantage of it:

    var numRects = 10;
    var size = 5;
    var i = 1;                          // which rectangle we're drawing
    var delay = 1000/60;                // num miliseconds between frames
    var before;                         // last draw time in ms
    
    function animateRect(now) {
        if ( !before ) before = now;
        // if sufficient time passed since last draw, draw a rect   
        if ( now - before > delay && i <= numRects) {
            rect(i * size, i * size, (i * size) * 2, (i * size) * 2);
            i++;
            before = now;
        }
    
        requestAnimFrame(animateRect);
    }
    

    However, this would necessitate modifying the shim the OP is using, in order to pass the current timestamp to the callback in setTimeout:

    window.requestAnimFrame = (function() {
        return window.requestAnimationFrame ||
            window.webkitRequestAnimationFrame ||
            window.mozRequestAnimationFrame ||
            window.oRequestAnimationFrame ||
            window.msRequestAnimationFrame ||
            function( /* function */ callback, /* DOMElement */ element) {
                window.setTimeout(callback, 1000 / 60, new Date.now());
            };
        })();
    
    0 讨论(0)
  • 2021-01-24 02:18

    I provided a frame limiter and tween to show you different ways of animating. The frame limiter has the steps in your example and the tween has as many steps as it takes to complete in a given amount of time.

    var canvas = document.getElementById('canvas'),
      ctx = canvas.getContext('2d');
    
    //requestAnim shim layer by Paul Irish
    //http://www.paulirish.com/2011/requestanimationframe-for-smart-animating/
    window.requestAnimFrame = (function() {
      return window.requestAnimationFrame ||
        window.webkitRequestAnimationFrame ||
        window.mozRequestAnimationFrame ||
        window.oRequestAnimationFrame ||
        window.msRequestAnimationFrame ||
        function( /* function */ callback, /* DOMElement */ element) {
          window.setTimeout(callback, 1000 / 60);
        };
    })();
    
    function rect(x, y, w, h, color) {
      ctx.beginPath();
      ctx.strokeStyle = color;
      ctx.rect(x, y, w, h);
      ctx.stroke();
    }
    
    function drawRect(i, size, color) {
      //for (var i = 0; i <= number; i++) {
      rect(i * size, i * size, (i * size) * 2, (i * size) * 2, color);
      //}
    }
    
    var i = 0;
    var incr = 1;
    var i_max = 10;
    var size = 5;
    var fps = 10;
    var delay = 1000 / fps;
    var lastFrame = 0;
    
    var animationTime = 5000
    var tweenStep = i_max / ((animationTime/1000) * 60);
    var j = 0;
    
    function animateRect() {
    
      // draw at 60fps
      ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
      drawRect(i, size, "#0000FF");
      
      // This is a frame limiter.
      var currentFrame = Date.now();
      
      if ((currentFrame - lastFrame) >= delay) {
        i += incr;
        if (i >= i_max) i = i_max - 2, incr = -1;
        if (i < 0) i = 1, incr = 1;
        lastFrame = currentFrame;
      }
      
      // this is a tween. The step is calculated for the desired time.
      drawRect(j, size, "#FF0000");
      j += tweenStep;
      if (j >= i_max) tweenStep *= -1,j=i_max-1;
      if (j < 0) tweenStep *= -1, j=0;
      
    
      requestAnimFrame(animateRect);
      //draw rectangle one by one here...
    }
    
    animateRect();
    //drawRect(10, 5);
    <canvas id="canvas" width="600" height="600"></canvas>

    0 讨论(0)
提交回复
热议问题