HTML Canvas API 教程
一個用於瀏覽器繪製到屏幕上的方法之一,Canvas API 的指南。
提示:還可以查看我的教程 如何將畫布列印到數據URL、如何將文本寫入到HTML畫布、如何在HTML畫布中加載圖像 和 如何使用Node.js和Canvas創建並保存圖像
HTML Canvas 是一個 HTML 標籤 <canvas>
,我們可以使用 Canvas API 在其中繪製。
創建一個畫布
創建一個畫布就像在空白的 HTML 文件中添加一個 <canvas></canvas>
一樣簡單:
在頁面中看不到任何內容,因為畫布是一個不可見的元素。讓我們添加一些邊框:
Chrome 自動給 body
元素添加了 8px 的邊距。這就是為什麼我們的邊框看起來像一個框架,你可以通過設置
1 | body { |
來刪除邊距。我們暫時使用默認值。
現在我們可以使用 DOM 選擇器 API 從 JavaScript 中訪問我們的畫布,可以使用 document.querySelector()
:
1 | const canvas = document.querySelector('canvas') |
更改畫布的背景顏色
在 CSS 中更改背景顏色:
1 | canvas { |
調整畫布大小
在 CSS 中設置寬度和高度:
1 | canvas { |
這樣,畫布就會擴展到填滿外部元素的尺寸。
如果將畫布作為 HTML 中的一級元素,上面的代碼將使畫布擴展到填滿整個 body。
body 並未填充整個窗口大小。要填滿整個頁面,我們需要使用 JavaScript:
1 | canvas.width = window.innerWidth |
如果現在刪除 body 的邊距,並使用 CSS 設置畫布的背景,我們可以使用畫布填滿整個頁面並開始在其上繪製:
如果窗口調整大小,我們也需要重新計算畫布的寬度,使用防抖動(debounce)來避免過多調用我們的畫布調整大小的函數(例如,resize
事件可能會多次調用,例如你使用鼠標移動窗口時可能調用數百次):
1 | const debounce = (func) => { |
從畫布獲取上下文
我們想要在畫布上繪製。
為了做到這一點,我們需要獲取一個上下文:
1 | const c = canvas.getContext('2d') |
有些人將內容分配給一個名為
c
的變量,有些人使用ctx
- 這是一種方便的「上下文」的縮寫
getContext()
方法根據傳遞給它的參數返回一個繪製上下文。
有效的值為
2d
,我們將使用的值webgl
,使用 WebGL 版本 1webgl2
,使用 WebGL 版本 2bitmaprenderer
,與 ImageBitmap 一起使用
根據上下文類型,您可以將第二個參數傳遞給 getContext()
以指定其他選項。
在 2d
上下文的情況下,我們基本上可以在所有瀏覽器上使用一個參數,它就是 alpha
,一個布爾值,默認為 true。如果設置為 false,瀏覽器知道畫布沒有透明背景,可以加快渲染。
將元素繪製到畫布上
使用上下文,我們現在可以繪製元素。
我們有幾種方法可以這樣做。我們可以繪製:
- 文本
- 線條
- 矩形
- 路徑
- 圖像
對於這些元素的每一個,我們都可以改變填充、描邊、漸變、圖案、陰影、旋轉、比例和執行許多操作。
讓我們從最簡單的事情開始:繪製矩形。
fillRect(x, y, width, height)
方法用於此目的:
1 | c.fillRect(100, 100, 100, 100) |
這將繪製一個 100x100 像素的黑色矩形,從 x 100 和 y 100 的位置開始:
您可以通過使用 fillStyle()
方法為矩形上色,傳遞任何有效的 CSS 顏色字符串來為其上色:
1 | c.fillStyle = 'white' |
現在您可以創意無限,以此方式繪製許多東西:
1 | for (let i = 0; i < 60; i++) { |
或者
1 | for (let i = 0; i < 60; i++) { |
繪製元素
正如前面提到的,您可以繪製許多東西:
- 文本
- 線條
- 矩形
- 路徑
- 圖像
讓我們只看一些,矩形和文本,以便了解事情是如何工作的。您可以在這裡找到您需要的其他所有 API 這裡。
更改顏色
使用 fillStyle
和 strokeStyle
屬性來更改任何圖形的填充和描邊顏色。它們接受任何有效的 CSS 顏色,包括字符串和 RGB 計算:
1 | c.strokeStyle = `rgb(255, 255, 255)` |
矩形
您有三個方法:
- clearRect(x, y, width, height)
- fillRect(x, y, width, height)
- strokeRect(x, y, width, height)
我們在前一節中看到了 fillRect()
。strokeRect()
的調用方式類似,但是不是填充矩形,而是只畫出輪廓使用當前的描邊樣式(可以使用 strokeStyle
上下文屬性更改):
1 | const c = canvas.getContext('2d') |
clearRect()
將區域設置為透明:
文本
繪製文本與矩形類似。您有兩種方法:
- fillText(text, x, y)
- strokeText(text, x, y)
它們讓您在畫布上寫文本。
x
和 y
是指左下角。
您可以使用畫布的 font
屬性更改字體家族和大小:
1 | c.font = '148px Courier New' |
還有其他相關的文本屬性可以更改(* = 默認值):
textAlign
(start*,end,left,right,center)textBaseline
(top,hanging,middle,alphabetic*,ideographic,bottom)direction
(ltr,rtl,inherit*)
線條
要繪製一條線,您需要首先調用 beginPath()
方法,然後使用 moveTo(x, y)
提供一個起始點,然後使用 lineTo(x, y)
使線到達這些新坐標。最後,調用 stroke()
:
1 | c.beginPath() |
線條的顏色將根據 c.strokeStyle
屬性值進行上色。
一個更複雜的例子
此代碼創建了一個生成 800 個圓形的畫布:
每個圓都完全包含在畫布中,其半徑是隨機的。
每次調整窗口大小時,元素會重新生成。
您可以在 Codepen 上玩耍。
1 | const canvas = document.querySelector('canvas') |
另一個例子:對畫布上的元素進行動畫處理
基於上面的例子,我們使用循環來使元素動起來。每個圓都有自己的 “生命”,在畫布邊界內移動。當到達邊界時,它會反彈:
在 CodePen 上看到該例子。
這是通過使用 requestAnimationFrame()
並在每個幀渲染迭代中稍微移動圖像來實現的。
與畫布上的元素互動
這是上面的例子,擴展為讓您使用鼠標與圓互動。
當您將鼠標懸停在畫布上時,靠近鼠標的項目將增大,當您移動到其他地方時,它們將恢復正常:
在 CodePen 上看到該例子。
它是如何工作的?首先,我使用兩個變量來跟踪鼠標位置:
1 | let mousex = undefined |
然後,我們在 Circle 的 update() 方法中使用這些變量來確定半徑是否應該增加(或減小):
1 | if (mousex - this.x < distanceFromMouse && mousex - this.x > -distanceFromMouse && mousey - this.y < distanceFromMouse && mousey - this.y > -distanceFromMouse) { |
distanceFromMouse
是以像素為單位的值(設為 200), 定義了鼠標距離圓的多遠的距離。
性能
如果您嘗試編輯上面的項目並添加更多圓和移動的元素,您可能會注意到性能問題。瀏覽器在渲染帶有動畫和互動的畫布時消耗了大量的能量,因此要注意在運行性能低於您的計算機的機器上不要損壞體驗。
特別是當我試圖創建一個使用表情符號而不是圓的類似體驗時,我遇到了問題,發現文本在渲染時需要更多的能量,因此它很快就變得不流暢。
在這個 MDN 頁面 中列舉了許多性能提示。
總結
這僅僅是對 Canvas 的可能性的介紹,Canvas 是一個驚人的工具,您可以使用它在網頁上創建令人難以置信的體驗。