requestAnimationFrame,Web中寫動畫的另一種選擇
HTML5/CSS3時代,我們要在web裏做動畫選擇其實已經很多了:
你可以用CSS3的animattion+keyframes;
你也可以用css3的transition;
你還可以用通過在canvas上作圖來實現動畫,也可以藉助jQuery動畫相關的API方便地實現;
當然最原始的你還可以使用window.setTimout()或者window.setInterval()通過不斷更新元素的狀態位置等來實現動畫,前提是畫面的更新頻率要達到每秒60次才能讓肉眼看到流暢的動畫效果。
現在又多了一種實現動畫的方案,那就是還在草案當中的window.requestAnimationFrame()方法。
window.requestAnimationFrame方法
來看MDN上對其給出的詮釋:
window.requestAnimationFrame() 將告知瀏覽器你馬上要開始動畫效果了,後者需要在下次動畫前調用相應方法來更新畫面。這個方法就是傳遞給window.requestAnimationFrame()的回調函數。
也可這個方法原理其實也就跟setTimeout/setInterval差不多,通過遞歸調用同一方法來不斷更新畫面以達到動起來的效果,但它優於setTimeout/setInterval的地方在於它是由瀏覽器專門爲動畫提供的API,在運行時瀏覽器會自動優化方法的調用,並且如果頁面不是激活狀態下的話,動畫會自動暫停,有效節省了CPU開銷。
基本語法
可以直接調用,也可以通過window來調用,接收一個函數作爲回調,返回一個ID值,通過把這個ID值傳給window.cancelAnimationFrame()可以取消該次動畫。
window.requestAnimationFrame(move);//move爲回調函數
arc()方法:
arc(x,y,radius,x1,y2,false) 六個參數 x,y 圓心的座標 , radius 圓的半徑,x1爲其實弧度,y1爲終止弧度,如果畫圓 x1 = 0,y1 = 2*Math.PI, 最後一個參數畫圓的方向,有兩個值 false (順時針)和 true (逆時針)。
clearRect() 方法:
clearRect(x,y,w,h) 四個參數 x,y 爲要清除位置的起始座標, w,h 爲要清除的寬高
開始畫圓
畫太陽,地球,月球的過程都是用 canvas 畫圓,因爲它們除了 圓心座標和半徑不一樣以爲 ,其他過程都是一樣的,所以我將畫圓的方法封裝起來,在畫的時候給不同的參數來調用這個類
封裝類
function Point(x,y){
this.x = x; //圓心的 X 座標
this.y = y; //圓心的 Y 座標
}
function Circle(origin,radius,speed){
this.origin = origin; //圓心
this.radius = radius; //半徑
this.speed = speed; //轉動速度
this.draw = drawCircle; //畫圓的方法
}
function drawCircle(){
con.beginPath(); //開始繪製
con.arc(this.origin.x,this.origin.y,this.radius,0,2*Math.PI,false); //繪製圓
con.stroke(); //繪製的框
con.closePath(); //繪製結束
}
畫太陽,地球,月亮
這裏只需要調用前面封裝好的類,傳入參數即可
//畫太陽
var sun = new Circle(new Point(400,300),30,0);
sun.draw();
//畫地球軌跡
var earthPath = new Circle(sun.origin,200,0);
earthPath.draw();
//畫地球
var earth = new Circle(new Point(earthPath.origin.x + earthPath.radius, earthPath.origin.y),20,0);
earth.draw();
//畫月亮軌跡
var moonPath = new Circle(earth.origin,80,0);
moonPath.draw();
//畫月亮
var moon = new Circle(new Point(moonPath.origin.x + moonPath.radius, moonPath.origin.y),10,0);
moon.draw();
讓地球和月亮轉動起來
function move(){
con.clearRect(0,0,canvas.width,canvas.height);
sun.draw();
earthPath.draw();
moonPath.draw();
earth.draw();
moon.draw();
earth.origin.x = earthPath.origin.x + earthPath.radius * Math.cos(earth.speed);
earth.origin.y = earthPath.origin.y + earthPath.radius * Math.sin(earth.speed);
earth.speed += 0.02;
moon.origin.x = moonPath.origin.x + moonPath.radius * Math.cos(moon.speed);
moon.origin.y = moonPath.origin.y + moonPath.radius * Math.sin(moon.speed);
moon.speed += -0.05;
window.requestAnimationFrame(move);
}
move();
效果圖:
畫面雖然簡單了點 ,但轉動的效果還是可以看見的
完整代碼:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<style type="text/css">
canvas {border: 1px solid black;}
</style>
</head>
<body>
<canvas id="myCanvas" width="800" height="600"></canvas>
</body>
<script type="text/javascript">
var canvas = document.getElementById('myCanvas');
var con = canvas.getContext('2d');
function Point(x,y){
this.x = x; //圓心的 X 座標
this.y = y; //圓心的 Y 座標
}
function Circle(origin,radius,speed){
this.origin = origin; //圓心
this.radius = radius; //半徑
this.speed = speed; //轉動速度
this.draw = drawCircle; //畫圓的方法
}
function drawCircle(){
con.beginPath(); //開始繪製
con.arc(this.origin.x,this.origin.y,this.radius,0,2*Math.PI,false); //繪製圓
con.stroke(); //繪製的框
con.closePath(); //繪製結束
}
//畫太陽
var sun = new Circle(new Point(400,300),30,0);
sun.draw();
//畫地球軌跡0
var earthPath = new Circle(sun.origin,200,0);
earthPath.draw();
//畫地球
var earth = new Circle(new Point(earthPath.origin.x + earthPath.radius, earthPath.origin.y),20,0);
earth.draw();
//畫月亮軌跡
var moonPath = new Circle(earth.origin,80,0);
moonPath.draw();
//畫月亮
var moon = new Circle(new Point(moonPath.origin.x + moonPath.radius, moonPath.origin.y),10,0);
moon.draw();
function move(){
con.clearRect(0,0,canvas.width,canvas.height);
sun.draw();
earthPath.draw();
moonPath.draw();
earth.draw();
moon.draw();
earth.origin.x = earthPath.origin.x + earthPath.radius * Math.cos(earth.speed);
earth.origin.y = earthPath.origin.y + earthPath.radius * Math.sin(earth.speed);
earth.speed += 0.02;
moon.origin.x = moonPath.origin.x + moonPath.radius * Math.cos(moon.speed);
moon.origin.y = moonPath.origin.y + moonPath.radius * Math.sin(moon.speed);
moon.speed += -0.05;
window.requestAnimationFrame(move);
}
move();
</script>
</html>