requestAnimationFrame以有限的帧速率

fre*_*und 14 javascript

据我所知,JS requestAnimationFrameAPI的使用是针对帧率不需要控制的情况,但我有一个用例,<canvas>只有在某个fps间隔内的更新才可能在1之间的任何地方.和25(每秒 1到25 之间).那么我可以以某种方式仍然有效地使用rAF来实现它提供的优化吗?

这个问题与我的问题有相似之处,但在那个问题的背景下,我接受的答案对我来说几乎没有任何意义.

我有两个可能的解决方案.第一个涉及使用while循环在requestAnimationFrame从回调内调用之前停止脚本执行指定的延迟.在我看到这个的例子中,它有效地限制了动画的fps,但它似乎也减慢了整个标签的速度.这仍然是一个很好的解决方案吗?第二个替代方案,如我在上面提到的问题中所提到的,requestAnimationFrame在一个内部调用setInterval.对我来说似乎有点费解,但它可能是最好的选择吗?

或者有更好的替代方法来实现这一目标吗?

fre*_*und 14

Yoshi的答案可能是解决这个问题的最佳代码.但我仍然认为这个答案是正确的,因为经过一些研究后我基本上发现我的问题无效.requestAnimationFrame实际上是为了保持帧速率尽可能高,并且它优化了动画要保持一致和平滑的场景.

值得注意的是,你不需要requestAnimationFrame进行优化(尽管rAF被吹捧为一个出色的性能助推器),因为浏览器仍然可以优化常规绘图<canvas>.例如,当标签没有聚焦时,Chrome for one会停止绘制其画布.

所以我的结论是这个问题无效.希望这有助于任何想要与我相似的人.


yck*_*art 9

这只是一个概念证明.

我们所做的只是设置每秒帧数和每帧之间的间隔.在绘图功能中,我们从当前时间中扣除最后一帧的执行时间,以检查自最后一帧起经过的时间是否超过我们的间隔(基于fps).如果条件的计算结果为true,我们将设置当前帧的时间,该时间将是下一个绘图调用中的"最后一帧执行时间".

var Timer = function(callback, fps){
  var now = 0;
  var delta = 0;
  var then = Date.now();

  var frames = 0;
  var oldtime = 0;

  fps = 1000 / (this.fps || fps || 60);

  return requestAnimationFrame(function loop(time){
    requestAnimationFrame(loop);

    now = Date.now();
    delta = now - then;

    if (delta > fps) {
      // Update time stuffs
      then = now - (delta % fps);

      // Calculate the frames per second.
      frames = 1000 / (time - oldtime)
      oldtime = time;

      // Call the callback-function and pass
      // our current frame into it.
      callback(frames);
    }
  });
};
Run Code Online (Sandbox Code Playgroud)

用法:

var set;
document.onclick = function(){
  set = true;
};

Timer(function(fps){
  if(set) this.fps = 30;
  console.log(fps);
}, 5);
Run Code Online (Sandbox Code Playgroud)

http://jsfiddle.net/ARTsinn/rPAeN/

  • 您是否会考虑添加一些叙述来解释为什么这段代码有效,以及是什么使它成为问题的答案?这对提出问题的人以及其他任何人来说非常有帮助. (3认同)
  • 我添加了一些解释文字.希望有所帮助. (2认同)

Yos*_*shi 5

你可以做什么,虽然我真的不知道这是否真的更好是:

  • 渲染到一个看不见的上下文 requestAnimationFrame
  • setInterval使用固定的fps 更新可见上下文

例:

<canvas id="canvas"></canvas>?

<script type="text/javascript">
  (function () {
    var
      ctxVisible = document.getElementById('canvas').getContext('2d'),
      ctxHidden = document.createElement('canvas').getContext('2d');

    // quick anim sample
    (function () {
      var x = 0, y = 75;

      (function animLoop() {
        // too lazy to use a polyfill here
        webkitRequestAnimationFrame(animLoop);

        ctxHidden.clearRect(0, 0, 300, 150);
        ctxHidden.fillStyle = 'black';
        ctxHidden.fillRect(x - 1, y - 1, 3, 3);

        x += 1;
        if (x > 300) {
          x = 0;
        }
      }());
    }());

    // copy the hidden ctx to the visible ctx on a fixed interval (25 fps)
    setInterval(function () {
      ctxVisible.putImageData(ctxHidden.getImageData(0, 0, ctxHidden.canvas.width, ctxHidden.canvas.height), 0, 0);
    }, 1000/40);
  }());
</script>
Run Code Online (Sandbox Code Playgroud)

演示:http://jsfiddle.net/54vWN/