本文主要是介绍requestAnimationFrame绘制图像,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
转载自http://blog.csdn.net/whqet/article/details/42911059
还在使用setInterval吗,你out了,requestAnimationFrame可以实现更为经济、更加准确的控制动画,今天来看看它的来龙去脉。
------------------------------------------------------------
--我参加了博客之星评选,如果你喜欢我的博客,求投票,您的支持是我的动力之源,走起!
-----------------------------------------------------------------------------------------------------------------
以往
在web动画、app动画中,我们经常通过setInterval或setTimeout定时修改DOM、CSS实现动画,如下面代码所示。
- var timer=setInterval(function(){
- //一些动画
- },1000/60)
- //清除动画
- clearInterval(timer);
不过如此动画的方式极为耗费资源,经常是这样的结果,刚开始比较流畅,5分钟之后动画就卡住了,于是“大家”都看不下去了,开始想各种办法。
简介
2011年左右,Paul Irish的《requestAnimationFrame for Smart Animating》首先介绍了requestAnimationFrame的使用,然后经过大家的努力《Timing control for script-based animations》在2013年成为了w3c的候选标准。
requestAnimationFrame的方式的优势如下:
1.经过浏览器优化,动画更流畅
2.窗口没激活时,动画将停止,省计算资源
3.更省电,尤其是对移动终端
requestAnimationFrame的使用方式,简单调用代码如下。
- function animate() {
- // Do whatever
- requestAnimationFrame(animate);
- // Do something animate
- }
- //go->
- requestAnimationFrame(animate);
有的时候我们必须要加一些控制,requestAnimationFrame也可以像setInterval一样返回一个句柄,然后我们可以取消它。控制动画代码如下。
- var globalID;
- function animate() {
- // Do whatever
- globalID=requestAnimationFrame(animate);
- // Do something animate
- }
- //when ot start
- globalID=requestAnimationFrame(animate);
- //when to stop
- cancelAnimationFrame(globalID);
好了,介绍完了吧。
呃,先别走,对于一个前端开发者,我们不能如此“单纯”,因为浏览器太任性,谁知道这些浏览器都是怎么“想的”,我们要看看浏览器兼容情况。
来,上CanIUse。
桌面端除了万恶的IE系列低版本9-,移动端除了Opera Mini和Android Browser4.3-其他都支持。总支持率83.38%,不加前缀支持率81.98%,支持率不错。作为一个富有极客精神的前端er,我们还得继续,拯救那些“手里没钱、手里有权却榆木疙瘩,还在使用低版本浏览器”的同胞,来个polyfill。
补丁
Paul Irish的简化版的补丁,补丁和使用如下代码所示。
- // 补丁
- window.requestAnimationFrame = (function(){
- return window.requestAnimationFrame ||
- window.webkitRequestAnimationFrame ||
- window.mozRequestAnimationFrame ||
- function( callback ){
- window.setTimeout(callback, 1000 / 60);
- };
- })();
- // 使用
- (function animate(){
- requestAnimationFrame(animate);
- //动画
- })();
这个补丁可以较好的兼容支持该特性的浏览器,但是对于不支持的呢?这里讲了怎么添加,如何停止呢?于是我们的补丁还得继续……
- (function() {
- var lastTime = 0;
- var vendors = ['ms', 'moz', 'webkit', 'o'];
- for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
- window.requestAnimationFrame = window[vendors[x]+'RequestAnimationFrame'];
- window.cancelAnimationFrame = window[vendors[x]+'CancelAnimationFrame']
- || window[vendors[x]+'CancelRequestAnimationFrame'];
- }
- if (!window.requestAnimationFrame)
- window.requestAnimationFrame = function(callback, element) {
- var currTime = new Date().getTime();
- var timeToCall = Math.max(0, 16 - (currTime - lastTime));
- var id = window.setTimeout(function() { callback(currTime + timeToCall); },
- timeToCall);
- lastTime = currTime + timeToCall;
- return id;
- };
- if (!window.cancelAnimationFrame)
- window.cancelAnimationFrame = function(id) {
- clearTimeout(id);
- };
- }());
有后来,又有了新更新,大家到github查看详情,代码贴过来,大家研究。
- // requestAnimationFrame polyfill by Erik Möller.
- // Fixes from Paul Irish, Tino Zijdel, Andrew Mao, Klemen Slavič, Darius Bacon
- // MIT license
- if (!Date.now)
- Date.now = function() { return new Date().getTime(); };
- (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;
- }
- }());
当然,实战的时候我们把这些代码单独放到一个文件中,到这里下载。
案例
最后,我们来个粒子案例,体会体会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 );
这篇关于requestAnimationFrame绘制图像的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!