canvas動畫教程-1 引言

liuyawin000發表於2018-10-07

參加工作以來做了很多和canvas相關的工作,也因此看了一些相關的書籍和文章,所學很是雜亂,於是便有了這些文章,對以往所學進行梳理,以供將來複習所用。 這個系列的文章不會系統的介紹canvas相關的API,有興趣可以去看API文件。我們只在引言部分簡單介紹一下canvas繪製的基本流程和canvas動畫的基本原理。

1. canvas繪製的基本流程

canvas的繪製流程很簡單,大致上有一個套路,分為如下幾步:

  1. 獲取指向canvas的引用
  2. 使用getContext方法獲取繪圖環境變數
  3. 使用繪圖環境變數在canvas元素上進行繪製 先通過一個例子來看如何在canvas上繪製一個Hello Canvas。首先我們需要在HTML裡插入一個canvas標籤:
<canvas id="canvas" width="600" height="300">
    Canvas not support!
</canvas>
複製程式碼

標籤裡面的面的內容“Canvas not support!”只有在瀏覽器不支援canvas的時候才會顯示出來。
接下來看js程式碼:

//1. 獲取指向canvas的引用
var canvas = document.getElementById("canvas");
//2. 獲取指向canvas的引用
var context = canvas.getContext('2d');

//3.使用繪圖環境變數在canvas元素上進行繪製
context.font = "38pt Arial";
context.fillStyle = "cornflowerblue";
context.strokeStyle = "blue";

context.fillText("Hello Canvas", canvas.width / 2 - 150, canvas.height / 2 + 15);
context.strokeText("Hello Canvas", canvas.width / 2 - 150, canvas.height / 2 + 15);
複製程式碼

這樣,就得到了一個很基礎的圖形:

canvas動畫教程-1 引言

2. canvas動畫的基本原理

在canvas中實現動畫的原理很簡單,就是在播放動畫時持續更新並繪製。最簡單的做法,就是在每一幀中擦除上一幀的內容,然後重新繪製這一幀的內容。那麼如何實現這種持續的更新呢?
首先可以想到用while迴圈:

function animate(){
  //這裡面寫動畫更新邏輯
}

while(true){
  animate();  
}
複製程式碼

但是while迴圈是一個死迴圈,會導致瀏覽器失去響應,而且也無法繪製出動畫的效果,因此應該排除。
然後我們可以想到用一些非同步的方法,如setTimeout或者setInterval:

/**
* 使用setInterval
**/
function animate(){
  //這裡面寫動畫更新邏輯
}

setInterval(animate, 1000/60);

/**
* 使用setTimeout
**/
function animate(){
  var start = +new Date(),
      finish;
      
  //這裡面寫動畫更新邏輯
  
  finish = +new Date();
  setTimeout(animate, (1000/60) - (finish-start));
}
複製程式碼

使用setTimeout和setInterval確實可以實現持續的更新,但是這兩個方法並不是專門為動畫而設計的,他們有如下缺陷:

  1. 都是通用方法,並不是專門為動畫設計
  2. 即使向其傳遞以毫秒為單位的引數值,也達不到毫秒的精確度
  3. 沒有對呼叫動畫迴圈的機制作優化
  4. 不會考慮動畫的最佳時機,只會以某個大致的時間間隔來呼叫動畫迴圈 基於以上原因,使用這兩個方法來繪製canvas動畫,其效果可能不如預期流暢,而且還會佔用其他資源。
    因此,瀏覽器提供了一個名為requestAnimationFrame()的方法。從這個方法的名字就可以感覺到,它是專門為動畫而生的。因為瀏覽器是知道繪製的最佳時機的,它會在可以繪製時通知你,而requestAnimationFrame正是用來實現此功能的。該方法不需要使用者指定幀速率,瀏覽器會自行決定最佳幀速率。
    現在,我們就用這個方法來實現一個簡單的動畫。向HTML裡插入一個id為canvas2的canvas標籤,js程式碼如下:
var canvas2 = document.getElementById("canvas2"),
    ctx = canvas2.getContext('2d'),
    img = new Image(),
    x = 0,
    y = 0;

img.onload = function () {
    animate();
}

img.src = './images/ball.png';

function animate() {
    //擦除上一幀的內容
    ctx.clearRect(0, 0, canvas2.width, canvas2.height);

    //更新邏輯
    x += 2;
    y++;
    ctx.drawImage(img, x, y, img.width, img.height);

    //持續更新
    requestAnimationFrame(animate);
}
複製程式碼

這樣就實現了一個動畫效果:

canvas動畫教程-1 引言

requestAnimationFrame的缺點,主要是相容性問題。後續章節中我們會提供一個polyfill方法實現一個相容性比較好的解決方案。

小結

本文主要介紹了canvas的基本用法和動畫原理。為了使用方便,後續章節不會再用這些基本的API,而是對它們進行了一些封裝,實現了幾個基本的類,如Stage、Renderer、Sprite、Graphics和Loader等,在下一篇文章中會有一個簡單的介紹。
最後為大家推薦幾本學習canvas的書籍,這個系列文章的大部分知識點都是來源於這幾本書。

  • HTML5 Canvas核心技術-圖形、動畫與遊戲開發。這本書系統而又詳細地介紹了canvas相關的API及用法,以及各種物理效果、碰撞檢測等技術,最後實現了一個簡單的遊戲引擎,在此基礎上開發了一個彈珠遊戲,並用canvas實現了一些自定義控制元件。該書內容豐富,十分推薦。

奉上本系列文章所涉及的原始碼的git地址,喜歡的話麻煩給個star哦!

相關文章列表

相關文章