<canvas> 是 HTML5 新增的元素,可使用JavaScript腳本來繪制圖形。例如:畫圖,合成照片,創建動畫甚至實時視頻處理與渲染。
兼容性方面,除了一些骨灰級瀏覽器IE6、IE7、IE8等,大部分現代瀏覽器都能支持。
一、屬性與方法
1)屬性
<canvas> 看起來和 <img> 元素很相像,唯一的不同就是它並沒有 src 和 alt 屬性。實際上,<canvas> 標簽只有兩個屬性—— width和height。
<canvas id="strick" width="150" height="150"></canvas>
還有些默認的屬性,id、style等
2)方法
1. getContext(in DOMString contextId)
canvas起初是空白的。為了展示,首先腳本需要找到渲染上下文,然后在它的上面繪制。這個方法是用來獲得渲染上下文和它的繪畫功能。
contextType中可選的參數有“2d”、“webgl”、“webgl2”、“bitmaprenderer”。
如果是“2d”,就會返回 CanvasRenderingContext2D 對象。如果是“webgl”,就會返回 WebGLRenderingContext 對象。
contextAttributes屬性會根據 “2d” 或 “webgl” 會需要不同的參數。
var canvas = document.getElementById('strick'); var ctx = canvas.getContext('2d');
2. toDataURL(in optional DOMString type, in any ...args)
返回一個data: URL,將canvas中的圖片編碼成字符串形式,有多種格式選擇,type參數的默認值為image/png。
曾做過一個圖片合成的功能,就使用到了這個功能。這里要注意一個“畫布污染”。
就是嵌入的圖片是跨域的,那么就不能使用這個方法。在《預覽、旋轉、合成》做過簡單的分析。
3. toBlob(in Function callback, in optional DOMString type, in any ...args)
返回一個Blob(binary large object)對象。Blob代表了一段二進制數據,就是一個包含只讀原始數據的類文件對象。
在《移動端圖片操作(一)——上傳》曾做過簡單的介紹。
二、繪制2D圖形
這里繪制的是2D圖形,會用到 CanvasRenderingContext2D 對象中的屬性或方法。
在MDN上面有個基礎教程《Canvas教程》,覆蓋面蠻全的。
1)坐標空間
畫布的起點為左上角,這個起始點通過方法 translate 可以自定義,例如做旋轉縮放等操作。
上圖所示,canvas的坐標軸與普通的坐標軸是相反的。
所以順時針是正值,逆時針是負值。
2)繪制形狀
矩形是canvas支持的唯一一種原生的圖形繪制。要畫其他形狀,就需要通過繪制路徑實現。繪制矩形提供了3個方法。
路徑是通過不同顏色和寬度的線段或曲線相連形成的不同形狀的點的集合。有操縱路徑和繪制路徑(包含貝塞爾曲線)的方法。
操作過程大致為4步,先創建路徑起始點,再畫出路徑,然后閉合路徑,最后填充。
1. 簡單圖形
下圖中是些簡單的圖形,兩個三角形中有一個是旋轉了畫布的,逆時針畫的半圓,三個圓圈與一個半圓組成的笑臉,用貝塞爾曲線畫的對話氣泡,可以在線調試下面的效果。
2. 復雜圖形
在CSS中,邊框、字體等都能設置寬度、大小、顏色等,高級點的還有陰影、漸變、rgba等。
在canvas中也有相應的操作,繪制文本、線型、文本樣式、填充和描邊樣式、漸變和圖案、陰影。
有網友畫了頭灰太狼,非常逼真,可以在線調試,通過查看源碼,里面用到的就是beginPath、moveTo、quadraticCurveTo等路徑相關的方法或屬性。
3)使用圖片
canvas可以對圖片進行合成、縮放、裁剪、旋轉、變形等操作。
a. 簡單的合成
現在有些網站會讓你DIY做張海報,然后分享到朋友圈。前段時間做了個簡易的海報,僅僅是將圖片合成在一起,沒有做塗鴉等操作,詳細的介紹可以查看《移動端圖片操作系列》
b. 高級點的合成
高級點的制作海報,能夠輸入自定義的文字,用到了上面所說的繪制形狀的一些概念,在看源碼的時候,發現引用了腳本“hidpi-canvas-polyfill”,解決canvas 在高清屏下繪制圖片變模糊。
![]() |
![]() |
簡單合成 | 高級合成 |
除了基礎的操作,還有高級的像素操作,獲取圖片中某一像素的RGBA,然后修改其中的R、G、B或A的值,來修改顏色或透明度。
例如鼠標移動獲取RGBA值,將彩色照變成黑白照,打馬賽克等。
第一張圖片是獲取像素值,第二張圖是變灰。
除了能操縱圖片,canvas還能操縱視頻,也就是<video>標簽。
4)變換矩陣
CSS3中的transform有個矩陣的概念,旋轉、平移、扭曲、縮放等都可以用矩陣來實現。關於CSS3的動畫可以參考《CSS3中的動畫效果記錄》
canvas中有一個rotate()方法,實現旋轉,但其實旋轉的是canvas畫布,並不是旋轉畫出來的那個圖形。
如果用transform()方法的話,就可以實現旋轉圖形。這邊有個對比實例,可以在線調試。
2D渲染的上下文矩陣如下,可以忽略最后一行:
2D渲染的坐標計算如下,關於計算過程可以研究下線性代數,簡單點說就是a和x、y、1分別相乘。
rotate與skew的矩陣計算會涉及到三角函數中的正弦、余弦還有正切。
//scale()對應的矩陣 下面是CSS3中的寫法,對應的方法是CanvasRenderingContext2D.transform matrix(sx,0,0,sy,0,0);/*sx和sy分別對應X軸和Y軸的縮放比率*/ //rotate()對應的矩陣 //在JS中θ對應的是弧度轉換公式為 弧度= 2 * PI / 360 * 角度 matrix(cosθ,sinθ,-sinθ,cosθ,0,0); //skew()對應的矩陣 //θy對應的是Y軸的弧度 θx對應的是X軸的弧度 matrix(1,tan(θy),tan(θx),1,0,0)
矩陣計算還會涉及到很多其他的數學知識,例如一次函數,我基本都已經忘記了,囧,都得重新查看了。
有個在線編輯matrix的網站,可以在線制作。
5)相關的計算公式
a. 三角函數基礎公式
JavaScript中有兩個反正切函數,Math.atan(ratio)與Math.atan2(y, x)。
第一個方法返回一個 -pi/2 到 pi/2 弧度之間的數值,第二個方法返回一個 -pi 到 pi 之間的數值。
b. 角度與弧度的互轉
在JavaScript中,三角函數等用的是弧度,例如Math.sin、Math.cos等方法;旋轉是用角度。所以兩者之間是需要換算的。
radians是弧度,degrees是角度
c. 兩點間的距離
使用了直角三角形的勾股定理。坐標軸中的P1與P2,就相當於公式中的A與B。
6)繪制文本
文本一般會設置文本內容(fillText)、尺寸字體(font),顏色(fillStyle),對齊(textAlign、textBaseline)等。
ctx.fillStyle = '#1d1d72';//字體顏色 ctx.font = size+'px serif';//字體尺寸 ctx.textBaseline = 'middle';//上下居中 ctx.textAlign = 'center';//水平居中 ctx.fillText(param.txt, width/2, height/2);
三、canvas動畫
要實現動畫就需要用JavaScript實現很多物理概念。
關於canvas動畫可以參考兩本書《HTML5 JavaScript動畫基礎》和《HTML5 Canvas基礎教程》。pdf和源碼都已經分享了出來。
1)速度向量
速度(speed)是速度向量(velocity)中的一部分,速度向量還包括方向。
用vx表示x軸上的速度向量,有vy表示y軸上的速度向量。還可以表示角度旋轉,用vr表示。
vx為正數表示向右,負數表示向左。vy為正數表示向下,負數表示向上。
下圖就是一個向右移動的球,vx=1,詳細代碼可以參考這里。
2)角速度
假設物體以1個像素的速度向45°方向移動,那么vx和vy可以通過余弦與正弦獲取。
速度和方向映射成一個直角三角形。
vx = Math.cos(angle)*speed;
vy = Math.sin(angle)*speed;
上圖就是經過計算后的角速度示例。
3)加速度
速度向量改變的是物體的物理位置,加速度改變的是速度向量。
下面的圖片與速度向量中的gif內容是相同的,只是每次循環給vx加了0.1個值。
4)邊界
處理邊界,有多種選擇,移除、置回邊界內、屏幕環繞、反彈回邊界內等。
左圖是置回邊界內,右圖是反彈回邊界內的效果。
5)摩擦力
一個比較簡單的實現是,設置一個friction(摩擦力變量,一個小於1的數字),將這個數與vx和vy分別相乘,獲取新的值。
這兩個值會越來越小,最終停止。
除了上面幾種基礎的動畫,還有些高級的動畫,緩動、彈動、碰撞檢測等。
四、canvas的優缺點
1)優點:
1. 在呈現圖像、文本和動畫的時候,由於 canvas 不存在與解析 HTML 和維護分層文檔模型有關的開銷,因此,在 canvas 中這些任務總是要比在 HTML 中快。
2. 可以實現一致的、跨平台的呈現。例如瀏覽器的transform屬性,不同瀏覽器可能就需要使用自己獨特的前綴。
3. 畫出來的圖形可以直接保存為 .png 或者 .jpg的圖形。
4. 最適合於畫光柵圖像(如游戲和不規則幾何圖形等),編輯圖片還有其他基於像素的圖形操作。
2)缺點:
1. 由於 canvas 里面沒有dom節點,當某個元素需要執行交互事件(如click)的時候只能是通過坐標來判斷。
2. 沒有實現動畫的API,你必須依靠定時器和其他事件來更新 canvas。
3. 對文本的渲染支持是比較差,例如自動換行。canvas中也不存在超鏈接的概念。
4. 由於在 canvas 上以編程方式顯示的文本其實就是位圖,因此搜索爬行器將完全忽略文本。文本內容也無法被屏幕閱讀器識別。
參考資料:
使用 HTML 標記來補充 canvas,第 2 部分: 動畫和文本渲染
使用 HTML 標記來補充 canvas,第 1 部分 : 混合使用 canvas API 和 HTML/CSS 模型