不知道大家是否有这样的感觉,当你使用window.setInterval()或者window.setTimeout()制作出来的动画,效果总是一卡一卡的,这绝对不是大家想看到的。
两个函数的特征决定了它能展示给我们的效果:
(1)其实它们从一生下来,就不是为动画服务的;
(2)它们虽然可以以毫秒作为单位,但是它们永远达不到毫秒的精确性;
(3)它们是死的,并不会考虑动画什么时间绘制才是最佳的,它们比较专一,脑子中只有你给予的那个数字(时间参数)。
所以大家在想,有没有这样一个方法:它们可以根据浏览器的性能自己决定绘制动画的速率。
也许在将来伟大的程序员会将window.setInterval()和window.setTimeout()的孙子打造出这样的性能,但是就现在来说,这个需求完全可以使用requestAnimationFrame()来完成。
requestAnimationFrame()接受一个参数,这个参数就是你要的动画引用(函数名)——为你省去了调试时间参数的烦恼。
通过递归的方式,来完成动画的效果。下面来说说兼容性的问题:
(1)Firefox浏览器对requestAnimationFrame()的实现:
Firefox浏览器在4.0版本中首次提供了该方法的变种——mozRequestAnimationFrame(),使用方法上是跟requestAnimationFrame()一致的。
window.mozRequestAnimationFrame()在4.0版本中存在一个bug,就是动画的帧速率只能达到每秒30~40帧。如果要在Firefox4.0中应用动画,不要用mozRequestAnimationFrame()。
(2)Chorme浏览器对requestAnimationFrame()的实现;
Chrome同样提供了动画实现函数——window.webkitRequestAnimationFrame()。Chrome10中也存在一个bug,就是浏览器没有将绘制的时间传递给动画的回调函数。所以导致回调函数中的time变量的值变成了undefined。在这种情况下,可以使用下面的表达式赋值time:
time = +new Date();
(3)Internet Explorer浏览器对requestAnimationFrame()的实现:
从IE10开始,提供了和W3C标准想似的方法——window.msRequestAnimationFrame()。
下面给大家写一个能兼容浏览器的requestAnimationFrame():
window.requestNextAnimationFrame = (function(){
var originalWebkitMethod,
wrapper = undefined,
callback = undefined,
geckoVersion = 0,
userAgent = navigator.userAgent,
index = 0,
self = this;
if(window.webkitRequestAnimationFrame){
wrapper = function(time){
if(time === undefined){
time += new Date();
}
self.callback(time);
};
originalWebkitMethod = window.webkitRequestAnimationFrame;
window.webkitRequestAnimationFrame = function(callback,element){
self.callback = callback;
originalWebkitMethod(wrapper , element);
}
}
if(window.mozRequestAnimationFrame){
index = userAgent.indexOf('rv:');
if(userAgent.indexOf('Gecko') != -1){
geckoVersion = userAgent.substr(index+3 , 3);
if(geckoVersion === '2.0'){
window.mozRequestAnimationFrame = undefined;
}
}
}
return window.requestNextAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function (callback , element){
var start,
finish;
window.setTimeout(function(){
start = +new Date();
callback(start);
finish = +new Date();
self.timeout = 1000/60 - (finish - start);
} , self.timeout);
};
})();
只要将上面的动画的引用传入到方法,例如:
function animate(){
...
requestAnimationFrame(animate);
}
requestAnimationFrame(animate);
最后,如果要取消动画还有
cancelRequestAnimationFrame()、
webkitCancelRequestAnimationFrame()、
msCancelRequestAnimationFrame()、
mozCancelRequestAnimationFrame()
说了那么多废话,一定觉得不实际。上案例,让亲们更好地体验函数的强大:
html
<head>
<title>Using requestAnimationFrame()</title>
<style>
body {
background: #dddddd;
}
#canvas {
background: #ffffff;
cursor: pointer;
margin-left: 10px;
margin-top: 10px;
-webkit-box-shadow: 3px 3px 6px rgba(0,0,0,0.5);
-moz-box-shadow: 3px 3px 6px rgba(0,0,0,0.5);
box-shadow: 3px 3px 6px rgba(0,0,0,0.5);
}
#controls {
margin-top: 10px;
margin-left: 15px;
}
</style>
</head>
<body>
<div id='controls'>
<input id='animateButton' type='button' value='Animate'/>
</div>
<canvas id='canvas' width='750' height='500'>
Canvas not supported
</canvas>
<script src='../../shared/js/requestNextAnimationFrame.js'></script>
<script src='example.js'></script>
</body>
</html>
JS
var canvas = document.getElementById('canvas'),
context = canvas.getContext('2d'),
paused = true,
discs = [
{
x: 150,
y: 250,
lastX: 150,
lastY: 250,
velocityX: -3.2,
velocityY: 3.5,
radius: 25,
innerColor: 'rgba(255,255,0,1)',
middleColor: 'rgba(255,255,0,0.7)',
outerColor: 'rgba(255,255,0,0.5)',
strokeStyle: 'gray',
},
{
x: 50,
y: 150,
lastX: 50,
lastY: 150,
velocityX: 2.2,
velocityY: 2.5,
radius: 25,
innerColor: 'rgba(100,145,230,1.0)',
middleColor: 'rgba(100,145,230,0.7)',
outerColor: 'rgba(100,145,230,0.5)',
strokeStyle: 'blue'
},
{
x: 150,
y: 75,
lastX: 150,
lastY: 75,
velocityX: 1.2,
velocityY: 1.5,
radius: 25,
innerColor: 'rgba(255,0,0,1.0)',
middleColor: 'rgba(255,0,0,0.7)',
outerColor: 'rgba(255,0,0,0.5)',
strokeStyle: 'orange'
},
],
numDiscs = discs.length,
animateButton = document.getElementById('animateButton');
// Functions.....................................................
function drawBackground() {
var STEP_Y = 12,
i = context.canvas.height;
context.strokeStyle = 'lightgray';
context.lineWidth = 0.5;
while(i > STEP_Y*4) {
context.beginPath();
context.moveTo(0, i);
context.lineTo(context.canvas.width, i);
context.stroke();
i -= STEP_Y;
}
context.save();
context.strokeStyle = 'rgba(100,0,0,0.3)';
context.lineWidth = 1;
context.beginPath();
context.moveTo(35,0);
context.lineTo(35,context.canvas.height);
context.stroke();
context.restore();
}
function update() {
var disc = null;
for(var i=0; i < numDiscs; ++i) {
disc = discs[i];
if (disc.x + disc.velocityX + disc.radius > context.canvas.width ||
disc.x + disc.velocityX - disc.radius < 0)
disc.velocityX = -disc.velocityX;
if (disc.y + disc.velocityY + disc.radius > context.canvas.height ||
disc.y + disc.velocityY - disc.radius < 0)
disc.velocityY= -disc.velocityY;
disc.x += disc.velocityX;
disc.y += disc.velocityY;
}
}
function draw() {
var disc = discs[i];
for(var i=0; i < numDiscs; ++i) {
disc = discs[i];
gradient = context.createRadialGradient(disc.x, disc.y, 0,
disc.x, disc.y, disc.radius);
gradient.addColorStop(0.3, disc.innerColor);
gradient.addColorStop(0.5, disc.middleColor);
gradient.addColorStop(1.0, disc.outerColor);
context.save();
context.beginPath();
context.arc(disc.x, disc.y, disc.radius, 0, Math.PI*2, false);
context.fillStyle = gradient;
context.strokeStyle = disc.strokeStyle;
context.fill();
context.stroke();
context.restore();
}
}
// Animation.....................................................
function animate(time) {
if (!paused) {
context.clearRect(0,0,canvas.width,canvas.height);
drawBackground();
update();
draw();
window.requestNextAnimationFrame(animate);
}
}
// Initialization................................................
context.font = '48px Helvetica';
animateButton.onclick = function (e) {
paused = paused ? false : true;
if (paused) {
animateButton.value = 'Animate';
}
else {
window.requestNextAnimationFrame(animate);
animateButton.value = 'Pause';
}
};
好了,这篇就到此结束,有什么问题欢迎亲们留言哦!
网友评论