使用requestAnimationFrame实现平滑高效的javascript动画

来源:互联网 发布:hive sql 函数大全 编辑:程序博客网 时间:2024/05/16 16:02
      以往用js实现浏览器上的动画,会使用setTimeout或者setInterval定时器设定时间间隔;碰到有多个动画的需求,可能会使用setInterval创建单一的动画循环,来管理页面上所有的动画,但这都会面临一些问题。
      首先这个时间间隔不是表示何时代码会执行,而是表示何时代码会添加进UI队列(如果队列中有其他工作排在前面,那代码将会等到其他完成才会执行),无法精确知道下一帧何时被执行,然而平滑动画的关键是理解下一帧何时被执行,这样的动画就不够平滑。同时大多数浏览器的刷新频率为60HZ(即每秒60次刷新),时间间隔为1000毫秒/ 60,约17ms,间隔时间越接近这个频率动画越流畅。如果在显示器刷新间隔之前发生了其他绘制请求,会让某些动画帧丢失,从而导致动画断续显示
      跟CSS transitions 和 animations方便动画的使用(浏览器知道哪些动画将会发生,得到正确的间隔来刷新UI)相比,上述javascript实现动画的问题越是明显。为此浏览器厂商提供一些API来优化动画的实现方法,在HTML5新增window.requestAnimationFrame方法;该方法接受一个参数,是一个屏幕重绘前被调用的函数(即下一次重绘何时发生的的时间码);因此解决了浏览器不知道Javascript动画正在执行和不知道多少才是合适的间隔的问题。这是很重要的一点:requestAnimationFrame()实际上列表出将要重绘的点并可以告诉你他们所处的时间。这样你就能够决定怎样更好的来调整你的动画。   

    

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<title>requestAnimFrame</title>
</head>
<body>
     <canvas width="256" height="256" id="J_canvas"></canvas>
     <script> 
     var canvas, context; 
     function draw() {
          canvas=document.getElementById("J_canvas");
          context = canvas.getContext( '2d' );

          var time = new Date().getTime() * 0.002;
          var x = Math.sin( time ) * 96 + 128;
          var y = Math.cos( time * 0.9 ) * 96 + 128;

          context.fillStyle = 'rgb(245,245,245)';
          context.fillRect( 0, 0, 255, 255 );

          context.fillStyle = 'rgb(255,0,0)';
          context.beginPath();
          context.arc( x, y, 10, 0, Math.PI * 2, true );
          context.closePath();
          context.fill();
     }

     window.requestAnimFrame = (function(){
          return window.requestAnimationFrame ||
          window.webkitRequestAnimationFrame ||
          window.mozRequestAnimationFrame ||
          window.oRequestAnimationFrame ||
          window.msRequestAnimationFrame ||
          function(callback, element){               
               window.setTimeout(callback, 1000 / 60);
            };
     })();

     function animate() { 
          draw();
          requestAnimFrame( animate );
          //setTimeout("animate()",10);
      }

          window.onload = function(){
          animate();
     }
     </script>
</body>
</html> 

<iframe width="100%" height="300" src="http://jsfiddle.net/Kt3My/embedded/" allowfullscreen="allowfullscreen" frameborder="0"></iframe>  

将//setTimeout("animate()",10)注释去掉,上述示例可以对比看出requestAnimFrame和setTimeout两种调用方式的动画流畅差异。

   RequestAnimationFrame还具有的优势是可以JS产生的动画以及CSS产生的动画结合入一个单一的页面进行创建及渲染的能力,这种能力将使得动画的实现具有更好的性能;当动画页面不被显示的时候,RequestAnimationFrame暂停执行,不会占用CPU时间 。
参考文章:http://technet.microsoft.com/zh-cn/library/hh920765.aspx
    http://www.cnblogs.com/rubylouvre/archive/2011/08/22/2148793.html

相应的停止动画函数,当满足某个条件时可以停掉动画
window.cancelAnimationFrame = (function(){
return window.cancelAnimationFrame ||
window.webkitCancelAnimationFrame ||
window.mozCancelAnimationFrame ||
window.oCancelAnimationFrame ||
window.msCancelAnimationFrame ||
function(callback, element){               
  window.clearTimeout(callback, 1000 / 60);
};
})();