JS動畫 requestAnimationFrame

前端動畫

在前端領域裡,一共有幾種方式可以處理動畫

  • CSS animation 參考舊文
  • CSS transition
  • SVG SMIL <animate> 參考舊文
  • JavaScript setInterval
  • JavaScript setTimeout
  • JavaScript requestAnimationFrame

requestAnimationFrame是一個專門用來處理動態的方法,相對於前5項作法,其用法也相當複雜(但同時也很精細)
注意他不支援IE9(含)以下

RAF(略)用法初探

requestAnimationFrame的用法跟setInterval / setTimeout有一點點很像
這3種動畫函數都是window呼叫(並且都能省略window)
塞的第一個值都必須是動作的function
不過,setInterval / setTimeout都要指定第二個值:「秒數」
然後RAF不用塞秒數,所以我們只要寫成這樣就好▼

window.requestAnimationFrame(function(timestamp){
 console.log(timestamp)
})

注意RAF塞進去的第一個值:函數的裡面
我又在塞了一個callback name:timestamp
這個callback name名字隨意取就行,不叫timestamp也可以

這個timestamp代表什麼。我們開啟開發者工具看看console.log(timestamp)的回傳結果

timestamp回傳的結果是「毫秒」

第一個值15147.488毫秒,換算成正常秒數約等於15秒。代表我打開這個網頁後,等了大約15秒後,我才打開了開發面板,鍵入了window.requestAnimationFrame(...)這坨函數

第二個值16281.32毫秒,約等於16秒。等於網頁準備好後過了16秒,window.request...(...)才被執行(所以他跟第一個console相距1秒)

但是,實務上執行動畫時不能夠像這樣一直key函數上去,所以需要改寫成循環函數,讓RAF可以不斷地被重複執行

function call(timestamp){
 console.log(timestamp);
 window.requestAnimationFrame(call);
}

window.requestAnimationFrame(call);

【補充說明】
想要抓到RAF的index時,可以這樣做

function call(timestamp){
 var idx=window.requestAnimationFrame(call);
 console.log(idx);
}

window.requestAnimationFrame(call);

實作動態

本次實作利用rgb參數調整的方式
做出動態的變色效果

  • b值最小為0
  • b值最大為255

⑴ 用canvas畫一個圓

canvas#canvas(width=500 height=500)
canvas
 border: 1px solid #000
 width: 250px
 height: 250px
var ctx=canvas.getContext('2d');
ctx.beginPath();
ctx.arc(250, 250, 100, 0, 2*Math.PI, false);
ctx.fill();

⑵ 加入RAF函數

定義每毫秒colorIndex就會跑一次

  • colorIndex加到255時,反向遞減
  • colorIndex減到0時,又變成遞增
var colorIndex=0;
var isPlus=true;

function call(timestamp){
 if(colorIndex==255){
  isPlus=false;
 }
 
 if(colorIndex==0){
  isPlus=true;
 }
 
 if(isPlus==true){
  colorIndex++;
 }else{
  colorIndex--;
 }
 
 ctx.fillStyle=`rgb(0, 150, ${colorIndex})`;
 ctx.fill();
 
 window.requestAnimationFrame(call);
}

window.requestAnimationFrame(call);

⑶ RAF的停止

停止運作要用到cancelAnimationFrame這個方法
用法如下

cancelAnimationFrame(★這裏填入要停下的RAF★)

★要停下的RAF★可以用變數的方式預先儲存好
完整範例如下

canvas#canvas(width=500 height=500)
button(onclick="stopAnimation()") STOP IT
canvas
 border: 1px solid #000
 width: 250px
 height: 250px
var ctx=canvas.getContext('2d');
ctx.beginPath();
ctx.arc(250, 250, 100, 0, 2*Math.PI, false);
ctx.fill();

var colorIndex=0;
var isPlus=true;
var myAnimation;

function call(timestamp){
 if(colorIndex==250){
  isPlus=false;
 }
 
 if(colorIndex==0){
  isPlus=true;
 }
 
 if(isPlus==true){
  colorIndex++;
 }else{
  colorIndex--;
 }
 
 ctx.fillStyle=`rgb(0, 150, ${colorIndex})`;
 ctx.fill();
 
 myAnimation=window.requestAnimationFrame(call);
}

window.requestAnimationFrame(call);

function stopAnimation(){
 window.cancelAnimationFrame(myAnimation);
}