Canvas API 提供了經過 JavaScript 繪製圖形的能力 。它普遍用於動畫、遊戲圖形、數據可視化、照片處理和實時視頻處理領域。本文將會簡單介紹下 canvas 。文章的大部份內容來源於 MDN 的 canvas 教程,想深刻了解 canvas 的能夠去看一下。javascript
// 栗子 1
<canvas id="tutorial" width="150" height="150"></canvas>
複製代碼
這就是一個 canvas 標籤,看起來和普通的 html 標籤沒什麼不一樣,重要的經過 canvas 標籤咱們能夠獲取其渲染上下文,canvas 的全部API都經過這個渲染上下文暴露出來,如下講解的 API 也都基於此上下文。html
canvas 翻譯過來是畫布的意思,因此接下來咱們會對照畫布來介紹 canvas 的API。java
var canvas = document.getElementById("tutorial");
var ctx = canvas.getContext("2d");
複製代碼
canvas 座標系統中,元素的左上角爲座標原點,向右下延伸座標軸,全部圖形相對於原點繪製,默認 1 網格單位對應 1 像素,好比栗子1 中的 canvas 元素就造成一個 150X150 的座標系。 上圖中的矩形座標即爲 (x, y)。
和 svg 不一樣,canvas 只提供了一種基本圖形:矩形,不過藉助路徑咱們能夠繪製想要的任意圖形。 git
canvas 提供了三種矩形 API,咱們能夠經過渲染上下文獲取到它們。全部 API 接受四個參數: x, y, width, height。github
function draw() {
var canvas = document.getElementById("canvas");
if (canvas.getContext) {
var ctx = canvas.getContext("2d");
ctx.fillRect(25, 25, 100, 100);
ctx.clearRect(45, 45, 60, 60);
ctx.strokeRect(50, 50, 50, 50);
}
}
複製代碼
fillRect 和 strokeRect 分別會 「填充」 和 「描邊「 一片矩形區域。調用它們會當即繪製到畫布上。
clearRect 會像橡皮擦同樣清除特定的矩形區域。
結果如圖:編程
路徑由一系列的點組成,經過路徑的組合咱們能夠繪製須要的任何圖形。繪製一條路徑步驟以下:canvas
beginPath
建立路徑,並建立一個路徑緩存區,當前座標爲起點。closePath
會在當前座標和起點連起一條直線(可選), 最後能夠 填充 或 描邊 路徑。這個繪製步驟和畫畫差很少,落筆、描邊到填充和真實世界的心智模型是相同的。其中的重頭戲就是步驟2的繪製命令:lineTo
、 arc
、[bezierCurveTo()](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/bezierCurveTo)
等命令分別繪製直線、弧線和貝塞爾曲線路徑。而 moveTo
命令接受 x、y 兩個參數,調用其會將畫筆移動到指定的 x,y 座標。
好比這裏有個稍微複雜的栗子,繪製一個吃豆人。緩存
在吃豆人的栗子裏,咱們反覆調用 roundedRect
函數來生成圓角矩形, canvas 提供了路徑複用的方法,這就是 Path2D,經過 Path2d 咱們能夠建立路徑對象,調用繪製命令、甚至合併兩個路徑對象。以吃豆人中的圓角矩形函數爲慄,使用Path2D 後的代碼:dom
// A utility function to draw a rectangle with rounded corners.
function roundedRect(ctx, x, y, width, height, radius) {
const path = new Path2D();
path.moveTo(x, y + radius);
path.lineTo(x, y + height - radius);
path.arcTo(x, y + height, x + radius, y + height, radius);
path.lineTo(x + width - radius, y + height);
path.arcTo(x + width, y + height, x + width, y + height - radius, radius);
path.lineTo(x + width, y + radius);
path.arcTo(x + width, y, x + width - radius, y, radius);
path.lineTo(x + radius, y);
path.arcTo(x, y, x, y + radius, radius);
ctx.stroke(path);
}
複製代碼
canvas 經過狀態機來保持 畫筆 和 畫布的狀態,咱們能夠經過 API 來改變畫筆的狀態來繪製不一樣樣式的圖形。好比經過 fillStyle 和 strokeStyle 改變填充和描邊的樣式,經過 lineWidth 改變畫筆的尺寸等。經過 createLinearGradient
、[createPattern(image, type)](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/createPattern)
來繪製漸變色和圖片背景,這裏再也不贅述。svg
canvas 動畫的限制在於:圖形繪製結束後沒法再更改圖形的狀態(尺寸、顏色、座標等)。這和咱們熟悉的 html 元素不同,dom 元素在渲染後還能夠進行作位移、縮放等動畫。因爲以上緣由,在 canvas 中作動畫須要遵循如下步驟:
這裏有一個時鐘動畫的栗子,咱們將不一樣的圖形封裝爲對象,繪製圖形時只須要調用對象的 draw
方法,這樣統一了編程模型。
class Hour {
constructor(ctx) {
this.ctx = ctx;
}
draw() {
this.ctx.lineWidth = 14;
this.ctx.beginPath();
this.ctx.moveTo(-20, 0);
this.ctx.lineTo(80, 0);
this.ctx.stroke();
}
}
複製代碼
繪製的每一幀咱們會不斷更新畫布的狀態,爲了避免污染下一幀的畫布狀態,咱們須要不斷調用 save
和 restore
來保存和回退畫布狀態。
這一章簡單介紹了 canvas的基本知識,下篇文章會涉及 canvas 內的事件處理、碰撞檢測等內容,並利用這些實現一些炫酷的效果,敬請期待。
本人正在編寫數據可視化之路系列文章,輸出一些可視化方面的教程和經驗,你能夠經過如下途徑閱讀它們。