參加工作以來做了很多和canvas相關的工作,也因此看了一些相關的書籍和文章,所學很是雜亂,於是便有了這些文章,對以往所學進行梳理,以供將來複習所用。 這個系列的文章不會系統的介紹canvas相關的API,有興趣可以去看API文件。我們只在引言部分簡單介紹一下canvas繪製的基本流程和canvas動畫的基本原理。
1. canvas繪製的基本流程
canvas的繪製流程很簡單,大致上有一個套路,分為如下幾步:
- 獲取指向canvas的引用
- 使用getContext方法獲取繪圖環境變數
- 使用繪圖環境變數在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);
複製程式碼
這樣,就得到了一個很基礎的圖形:
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確實可以實現持續的更新,但是這兩個方法並不是專門為動畫而設計的,他們有如下缺陷:
- 都是通用方法,並不是專門為動畫設計
- 即使向其傳遞以毫秒為單位的引數值,也達不到毫秒的精確度
- 沒有對呼叫動畫迴圈的機制作優化
- 不會考慮動畫的最佳時機,只會以某個大致的時間間隔來呼叫動畫迴圈
基於以上原因,使用這兩個方法來繪製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);
}
複製程式碼
這樣就實現了一個動畫效果:
requestAnimationFrame的缺點,主要是相容性問題。後續章節中我們會提供一個polyfill方法實現一個相容性比較好的解決方案。
小結
本文主要介紹了canvas的基本用法和動畫原理。為了使用方便,後續章節不會再用這些基本的API,而是對它們進行了一些封裝,實現了幾個基本的類,如Stage、Renderer、Sprite、Graphics和Loader等,在下一篇文章中會有一個簡單的介紹。
最後為大家推薦幾本學習canvas的書籍,這個系列文章的大部分知識點都是來源於這幾本書。
- HTML5 Canvas核心技術-圖形、動畫與遊戲開發。這本書系統而又詳細地介紹了canvas相關的API及用法,以及各種物理效果、碰撞檢測等技術,最後實現了一個簡單的遊戲引擎,在此基礎上開發了一個彈珠遊戲,並用canvas實現了一些自定義控制元件。該書內容豐富,十分推薦。
奉上本系列文章所涉及的原始碼的git地址,喜歡的話麻煩給個star哦!