How to use requestAnimationFrame to animate multiple squares in a loop

本小妞迷上赌 提交于 2019-12-20 05:21:26

问题


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 using requestAnimationFrame to draw these square one at a time. How can I achieve this. Here is a jsFiddle

var canvas = document.getElementById('canvas'),
       ctx = canvas.getContext('2d');

    function rect(x, y, w, h) {
      ctx.beginPath();
      ctx.rect(x, y, w, h);
      ctx.stroke();
    }

    function drawRect(number, size) {
      for (var i = 0; i <= number; i++) {
        rect(i * size, i * size, (i * size) * 2, (i * size) * 2);
      }
    }

    drawRect(10, 5);

回答1:


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());
        };
    })();



回答2:


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>


来源:https://stackoverflow.com/questions/35590348/how-to-use-requestanimationframe-to-animate-multiple-squares-in-a-loop

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!