现在的位置: 首页 > 综合 > 正文

requestAnimationFrame绘制图像

2018年03月29日 ⁄ 综合 ⁄ 共 7828字 ⁄ 字号 评论关闭

转载自http://blog.csdn.net/whqet/article/details/42911059

还在使用setInterval吗,你out了,requestAnimationFrame可以实现更为经济、更加准确的控制动画,今天来看看它的来龙去脉。

------------------------------------------------------------

--我参加了博客之星评选,如果你喜欢我的博客,求投票,您的支持是我的动力之源走起!

-----------------------------------------------------------------------------------------------------------------

以往

在web动画、app动画中,我们经常通过setInterval或setTimeout定时修改DOM、CSS实现动画,如下面代码所示。

[javascript]
view plain
copy在CODE上查看代码片派生到我的代码片
  1. var timer=setInterval(function(){  
  2.    //一些动画  
  3. },1000/60)  
  4. //清除动画  
  5. clearInterval(timer);  

不过如此动画的方式极为耗费资源,经常是这样的结果,刚开始比较流畅,5分钟之后动画就卡住了,于是“大家”都看不下去了,开始想各种办法。

简介

2011年左右,Paul Irish的《requestAnimationFrame for Smart Animating》首先介绍了requestAnimationFrame的使用,然后经过大家的努力《Timing
control for script-based animations
》在2013年成为了w3c的候选标准。

requestAnimationFrame的方式的优势如下:

1.经过浏览器优化,动画更流畅

2.窗口没激活时,动画将停止,省计算资源

3.更省电,尤其是对移动终端

requestAnimationFrame的使用方式,简单调用代码如下。

[javascript]
view plain
copy在CODE上查看代码片派生到我的代码片
  1. function animate() {  
  2.   // Do whatever  
  3.   requestAnimationFrame(animate);  
  4.   // Do something animate  
  5.     
  6. }  
  7. //go->  
  8. requestAnimationFrame(animate);  

有的时候我们必须要加一些控制,requestAnimationFrame也可以像setInterval一样返回一个句柄,然后我们可以取消它。控制动画代码如下。

[javascript]
view plain
copy在CODE上查看代码片派生到我的代码片
  1. var globalID;  
  2. function animate() {  
  3.   // Do whatever  
  4.   globalID=requestAnimationFrame(animate);  
  5.   // Do something animate  
  6.     
  7. }  
  8. //when ot start  
  9.     globalID=requestAnimationFrame(animate);  
  10. //when to stop  
  11.     cancelAnimationFrame(globalID);  

好了,介绍完了吧。

呃,先别走,对于一个前端开发者,我们不能如此“单纯”,因为浏览器太任性,谁知道这些浏览器都是怎么“想的”,我们要看看浏览器兼容情况。

来,上CanIUse


桌面端除了万恶的IE系列低版本9-,移动端除了Opera Mini和Android Browser4.3-其他都支持。总支持率83.38%,不加前缀支持率81.98%,支持率不错。作为一个富有极客精神的前端er,我们还得继续,拯救那些“手里没钱、手里有权却榆木疙瘩,还在使用低版本浏览器”的同胞,来个polyfill

补丁

Paul Irish的简化版的补丁,补丁和使用如下代码所示。

[javascript]
view plain
copy在CODE上查看代码片派生到我的代码片
  1. // 补丁  
  2. window.requestAnimationFrame = (function(){  
  3.   return  window.requestAnimationFrame       ||  
  4.           window.webkitRequestAnimationFrame ||  
  5.           window.mozRequestAnimationFrame    ||  
  6.           function( callback ){  
  7.             window.setTimeout(callback, 1000 / 60);  
  8.           };  
  9. })();  
  10.   
  11.   
  12. // 使用  
  13.   
  14. (function animate(){  
  15.   requestAnimationFrame(animate);  
  16.   //动画  
  17. })();  

这个补丁可以较好的兼容支持该特性的浏览器,但是对于不支持的呢?这里讲了怎么添加,如何停止呢?于是我们的补丁还得继续……

[javascript]
view plain
copy在CODE上查看代码片派生到我的代码片
  1. (function() {    
  2.     var lastTime = 0;    
  3.     var vendors = ['ms''moz''webkit''o'];    
  4.     for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {    
  5.         window.requestAnimationFrame = window[vendors[x]+'RequestAnimationFrame'];    
  6.         window.cancelAnimationFrame = window[vendors[x]+'CancelAnimationFrame']     
  7.                                    || window[vendors[x]+'CancelRequestAnimationFrame'];    
  8.     }    
  9.      
  10.     if (!window.requestAnimationFrame)    
  11.         window.requestAnimationFrame = function(callback, element) {    
  12.             var currTime = new Date().getTime();    
  13.             var timeToCall = Math.max(0, 16 - (currTime - lastTime));    
  14.             var id = window.setTimeout(function() { callback(currTime + timeToCall); },     
  15.               timeToCall);    
  16.             lastTime = currTime + timeToCall;    
  17.             return id;    
  18.         };    
  19.      
  20.     if (!window.cancelAnimationFrame)    
  21.         window.cancelAnimationFrame = function(id) {    
  22.             clearTimeout(id);    
  23.         };    
  24. }());  

有后来,又有了新更新,大家到github查看详情,代码贴过来,大家研究。

[javascript]
view plain
copy在CODE上查看代码片派生到我的代码片
  1. // requestAnimationFrame polyfill by Erik Möller.  
  2. // Fixes from Paul Irish, Tino Zijdel, Andrew Mao, Klemen Slavič, Darius Bacon  
  3.   
  4. // MIT license  
  5.   
  6. if (!Date.now)  
  7.     Date.now = function() { return new Date().getTime(); };  
  8.   
  9. (function() {  
  10.     'use strict';  
  11.       
  12.     var vendors = ['webkit''moz'];  
  13.     for (var i = 0; i < vendors.length && !window.requestAnimationFrame; ++i) {  
  14.         var vp = vendors[i];  
  15.         window.requestAnimationFrame = window[vp+'RequestAnimationFrame'];  
  16.         window.cancelAnimationFrame = (window[vp+'CancelAnimationFrame']  
  17.                                    || window[vp+'CancelRequestAnimationFrame']);  
  18.     }  
  19.     if (/iP(ad|hone|od).*OS 6/.test(window.navigator.userAgent) // iOS6 is buggy  
  20.         || !window.requestAnimationFrame || !window.cancelAnimationFrame) {  
  21.         var lastTime = 0;  
  22.         window.requestAnimationFrame = function(callback) {  
  23.             var now = Date.now();  
  24.             var nextTime = Math.max(lastTime + 16, now);  
  25.             return setTimeout(function() { callback(lastTime = nextTime); },  
  26.                               nextTime - now);  
  27.         };  
  28.         window.cancelAnimationFrame = clearTimeout;  
  29.     }  
  30. }());  

当然,实战的时候我们把这些代码单独放到一个文件中,到这里下载

案例

最后,我们来个粒子案例,体会体会requestAnimatonFrame的使用。

------------------------------------------------------------------------------------------------------------------------------------------------------------------------
                                                         == 粒子案例==全屏预览==在线编辑==下载收藏==
------------------------------------------------------------------------------------------------------------------------------------------------------------------------

参考文献和深入阅读

1. Paul Irish, requestAnimationFrame for Smart Animating

2. MDN, Window.requestAnimationFrame()

3. Chris Coyier, Using requestAnimationFrame

4. Matt West,
Efficient Animations with requestAnimationFrame

5. W3C CR, Timing control for script-based animations

6. Polyfill for requestAnimationFrame/cancelAnimationFrame

7. 张鑫旭, CSS3动画那么强,requestAnimationFrame还有毛线用?

8. 朱永盛, 理解WebKit和Chromium: 渲染主循环(main loop)和requestAnimationFrame

感谢您耐心读完,如果对您有帮助,请支持我

----------------------------------------------------------

前端开发whqet,关注web前端开发,分享相关资源,欢迎点赞,欢迎拍砖。

==========================================================================================

以上是原文内容  下面是我对绘制上面canvas的js脚本的注解

//解决Date.now() 函数的浏览器支持问题
if (!Date.now)
    Date.now = function() { return new Date().getTime(); };
    
    
//解决requestAnimationFrame的浏览器支持问题
(function() {
    'use strict';
    
    var vendors = ['webkit', 'moz'];
    for (var i = 0; i < vendors.length && !window.requestAnimationFrame; ++i) {
        var vp = vendors[i];
        window.requestAnimationFrame = window[vp+'RequestAnimationFrame'];
        window.cancelAnimationFrame = (window[vp+'CancelAnimationFrame']
                                   || window[vp+'CancelRequestAnimationFrame']);
    }
    if (/iP(ad|hone|od).*OS 6/.test(window.navigator.userAgent) // iOS6 is buggy
        || !window.requestAnimationFrame || !window.cancelAnimationFrame) {
        var lastTime = 0;
        window.requestAnimationFrame = function(callback) {
            var now = Date.now();
            var nextTime = Math.max(lastTime + 16, now);
            return setTimeout(function() { callback(lastTime = nextTime); },
                              nextTime - now);
        };
        window.cancelAnimationFrame = clearTimeout;
    }
}());

//定义获取随机颜色的函数
var getRandomColor = function(){
  return '#'+(Math.random()*0xffffff<<0).toString(16);
}

//获取绘图对象
var canvas = document.getElementById("motion"),
    c = canvas.getContext("2d"),
    particles = {},  //定义记录颗粒的数组
    particleIndex = 0,  //颗粒index
    particleNum = 0.2;   //一个限定值 来控制颗粒出现的概率  具体见后文

canvas.width = window.innerWidth/2;
canvas.height = window.innerHeight/2;

//生成一个颗粒相关的参数
function Particle(){
  this.x = canvas.width/2;   //所在位置
  this.y = canvas.height/2;

  this.vx = Math.random() * 6 - 3;  //偏移参数
  this.vy = Math.random() * 4 - 2;

  this.growth = ( Math.abs(this.vx) + Math.abs(this.vy) ) * 0.007;

  particleIndex++;
  particles[particleIndex] = this;
  this.id = particleIndex;
  this.size = Math.random() * 1;
  this.color = getRandomColor();
}

//定义绘图函数
Particle.prototype.draw = function(){
  this.x += this.vx;
  this.y += this.vy;

  this.size += this.growth;
  if(this.x > canvas.width || this.y > canvas.height){
    delete particles[this.id];
  }
//调用从canvas拿来的上下文对象绘图
  c.fillStyle = this.color;
  c.beginPath();
  c.arc(this.x, this.y, this.size,0*Math.PI,2*Math.PI);
  c.fill();
};

//动画
function animate(){
  requestAnimationFrame( animate );
  //绘制背景黑幕
  c.fillStyle = "#000";
  c.fillRect(0,0,canvas.width,canvas.height);
  //决定是否产生新点
  if(Math.random() > particleNum){
    new Particle();
  }
  //绘制点
  for(var i in particles){
    particles[i].draw();
  }
}

//开始动画
requestAnimationFrame( animate );

抱歉!评论已关闭.