把網頁當畫布揮灑的 Canvas 01:基礎圖形繪製

「把網頁當畫布揮灑的 Canvas 2D」系列文章主要是我記錄吳哲宇老師所開設的「動畫互動網頁特效入門(JS/CANVAS)」這門課的學習過程,輔以網路上的教學資料,綜合撰寫而成的筆記。

現在,就踏進 Canvas 的世界吧!


什麼是 Canvas ?

Canvas 最早由 Apple 為 Mac OS X Dashboard 所提出,而後 Canvas 被 HTML5 標準加以定義為 canvas 元素,現已支援多數主流瀏覽器。我們可以透過 JavaScript 串接 Canvas API ,獲取 Canvas 物件的內部方法,藉此在網頁上繪製許多細緻的特效或動畫。其中,Canvas 物件又可為 2D 或 3D 。

簡而言之,我們可以把 canvas 想像成網頁中一張可以自由揮灑的畫布元素,透過 JavaScript 獲取 Canvas 物件,並利用物件裡的方法在畫布上繪製線條、形狀與顏色。

瞭解原生 Canvas 後,未來接觸特效函式庫如 PixiJSPhaserJsp5JS 將更容易上手。


使用 Canvas

HTML 的 canvas 元素

在 HTML 中加入 canvas 元素,預設的畫布寬高為 300px x 150px。我們可以透過 HTML 的寬高屬性自訂大小,或者,利用 CSS 指定寬高也是可行的(但內部影像也會跟著縮放)。

部分舊版瀏覽器如 IE 9 並不支援 canvas 。我們可以在 canvas 內加入一段替代文字或靜態圖片,作為瀏覽器不支援時的替代內容。

1
2
3
4
5
6
7
<canvas id="my-canvas" width="200" height="100">
你的瀏覽起不支援 canvas
</canvas>

<canvas id="my-canvas-2" width="200" height="100">
<img src="./images/altImg.png" width="200" height="100">
</canvas>

JavaScript 獲取 Canvas API

先透過 DOM 選取器指定 canvas 元素,再利用 getContext() 獲取 Canvas 繪圖物件,傳入參數 '2d' 得到 CanvasRenderingContext2D 物件作為 Canvas 2D 的渲染環境。當然,我們也可以檢查瀏覽器的 canvas 元素是否支援 getContext 串接 Canvas API :

1
2
3
4
5
6
7
const canvas = document.getElementById('my-canvas')

if(canvas.getContent) {
const ctx = canvas.getContext('2d')
} else {
console.log('Canvas Unsupported!')
}

我們也可以透過 JS 動態調整畫布大小:

1
2
canvas.width = window.innerWidth
canvas.height = window.innerHeight


Canvas 2D 的座標系統

和 CSS 的定位系統相似,Canvas 2D 的座標系統以左上角為原點,向右正射出 X 軸,向下正射出 Y 軸,順時針為旋轉方向。

Canvas 2D 座標系


基本圖形繪製

矩形

Canvas 只支援矩形此一基本圖形,語法相對容易:

1
2
3
4
5
6
7
8
// 繪製填色矩形
ctx.fillRect(150, 50, 100, 50)

// 繪製路徑矩形
ctx.strokeRect(150, 150, 100, 50)

// 清除矩形範圍(在動畫中作為清除整塊畫布範圍的影格效果)
ctx.clearRect(x, y, width, height)

路徑

我們可以把路徑想像成我們的畫筆。下筆之前,都必須以 beginPath() 來宣告我們即將畫路徑,JS 會把我們接下來畫的路徑存進一個清單裡面,成為路徑集合。每呼叫一次 beginPath()先前的路徑集合都會被清空,代表我們要重新開始繪製

第一次下筆時,我們要先確定下筆的點。 moveTo() 幫助我們將畫筆移動到(第一個)下筆的點,就像把筆從紙上提起來,移動到另外一個點上,並不會繪製任何圖形。通常 beginPath() 之後會接著 moveTo() 我們想要開始繪製的點上。

1
2
3
4
5
6
7
8
9
10
11
12
13
// 繪製一個 5-12-13 直角三角形
ctx.beginPath() // 宣告繪製路徑
ctx.moveTo(50, 50) // 將畫筆移動至指定座標
ctx.lineTo(100, 50) // 繪製直線
ctx.lineTo(50, 170)
ctx.closePath() // 自動封閉路徑
ctx.rect(50, 200, 50, 50) // 繪製矩形路徑

ctx.lineWidth = 5 // 指定路徑寬度
ctx.strokeStyle = 'red' // 指定路徑顏色(字串,可以是顏色名稱、色票或 RGBA)
ctx.fillStyle = 'blue' // 指定路徑填色(字串,可以是顏色名稱、色票或 RGBA)
ctx.stroke() // 路徑上色
ctx.fill() // 路徑填色

弧形(圓形)

在 Canvas 中,圓形也屬於路徑的一種,不像矩形可以單獨繪製,需要先宣告 beginPath() ,再透過 arc(cx, cy, r, startAngle, endAngle, counterclockwise?) 來繪製。其中 startAngleendAngle 兩參數分別代表起點弧度終點弧度(0度~360度)可以 Math.PI 來表示counterclockwis? 參數則為一布林值,預設為 false ,代表順時針繪製。

記得繪製完弧形路徑也要填色,否則什麼都看不到!

1
2
3
4
5
ctx.beginPath()
ctx.arc(350, 100, 50, 0, Math.PI)
ctx.closePath()
ctx.stroke()
ctx.fill()

文字

Canvas 也支援文字繪製以及字型大小、字體、方向以及對齊方式等設定:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 繪製填色文字
ctx.fillText('Hellow World!', x, y)

// 繪製路徑文字
ctx.strokeText(text, x, y) // text 為字串

// 設定文字大小、字體與粗體
ctx.font = 'bold 18px "Microsoft JhengHei"';

// 設定文字水平對齊方式(start、end、left、right、center,預設為 start)
ctx.textAlign = 'center'

// 設定文字垂直對齊方式(top、hanging、middle、alphabetic、ideographic、bottom,預設為 alphabetic)
ctx.textBaseline = 'middle'


繪製座標系來練習

我們可以利用 for 來繪製 Canvas 的網格座標系統,以便我們練習繪製基本圖形。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
const canvas = document.getElementById('my-canvas')
const ctx = canvas.getContext('2d')

const canvas_size = 500

canvas.width = canvas_size
canvas.height = canvas_size

ctx.beginPath()
for(let i = 0 ; i < canvas_size / 50 ; i++) {
let pos = i * 50

// X Axis
ctx.moveTo(0, pos)
ctx.lineTo(500, pos)
ctx.fillText(pos, 0, pos)

// Y Axis
ctx.moveTo(pos, 0)
ctx.lineTo(pos, 500)
ctx.fillText(pos, pos, 10)
}
ctx.strokeStyle = 'gray'
ctx.stroke()


參考資料

  1. 動畫互動網頁特效入門(JS/CANVAS):5-1 Canvas 繪圖基礎語法與動畫原理
  2. Canvas 2D 學習筆記
  3. MDN:Canvas 教學文件
  4. HTML5 Canvas Tutorials Home
把網頁當畫布揮灑的 Canvas 02:動畫原理 2020 口罩存貨實時地圖開發紀錄

評論

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×