一.Canvas基本用法
canvas對應中文是“畫布”,<canvas>是HTML5的新元素,IE9+支持
canvas元素的默認大小是300px * 150px,最簡單的代碼將生成一個透明的矩形畫布,例如:
<canvas> 瀏覽器不支持canvas </canvas>
如果瀏覽器支持的話,那么你將不會看到一個300px * 150px的透明塊(因為透明了嘛,審查元素就找到它了)。如果瀏覽器不支持,那么將會顯示替換文字:“瀏覽器不支持canvas”,例如IE8。
有了畫布,我好想畫點兒什么。不過對於canvas來說,最容易的是畫個空心/實心矩形,而不是畫條直線,例如:
<canvas id="my_canvas"> 瀏覽器不支持canvas </canvas>
<script type="text/javascript">
var canvas = document.getElementById('my_canvas');
if(canvas.getContext){
var ctx = canvas.getContext('2d');//獲取2d上下文
ctx.strokeStyle = '#f00';//邊框設置為紅色
ctx.lineWidth = 3;//線寬設置為3px
ctx.fillStyle = 'rgba(0, 0, 255, 0.5)';//填充半透明藍色
ctx.strokeRect(0, 0, 50, 50);//描邊
ctx.fillRect(0, 0, 50, 50);//填充
}
</script>
結果就是這個樣子:
二.畫方畫圓畫線
矩形在上面已經畫過了,用到了上下文對象的描邊和填充方法,除此之外還有一個關於矩形的方法:clearRect()參數意義相同,作用是掏空一個矩形塊(用透明色填充指定區域)
畫圓相對麻煩一點,比如要畫一個圓心為(30, 30)半徑為20的圓:
ctx.beginPath();//創建路徑 ctx.arc(30,30,20,0,Math.PI*2,true);//設置弧線路徑 ctx.closePath();//閉合路徑 ctx.stroke();//描邊 ctx.fill();//填充
arc(x, y, radius, startAngle, endAngle, counterclockwise)方法是用來畫弧線的,表示以(x, y)為圓心,radius為半徑,起始角度和結束角度分別為startAngle和endAngle,最后一個參數表示前兩個角度值是按順時針還是逆時針算,false表示順時針。
畫線比畫圓要簡單些(從(30, 30)畫一條50px的橫線):
ctx.beginPath();//創建路徑 ctx.moveTo(30, 30);//把起點移動到(30, 30) ctx.lineTo(80, 30);//設置路徑連接兩點 ctx.closePath();//閉合路徑 ctx.stroke();//繪制
能畫線畫弧了,那畫三角五角也就不在話下了,除了上面用到的路徑方法之外,還有以下方法:
-
arcTo(x1, y1, x2, y2, radius):從上一點開始繪制一條弧線,到(x2, y2)為止,並且以給定的半徑radius穿過(x1, y1)
-
bezierCurveTo(c1x, c1y, c2x, c2y, x, y):貝塞爾曲線,從上一點開始繪制一條曲線,到(x, y)為止,並且以(c1x, c1y)和(c2x, c2y)為控制點
-
quadraticCurveTo(cx, cy, x, y):二次貝塞爾曲線,從上一點開始繪制一條二次曲線,到(x, y)為止,並且以(cx, cy)為控制點
-
rect(x, y, width, height):繪制矩形路徑
設置好路徑之后,可以用fill()方法填充或者用stroke()方法描邊,還可以用clip()方法對下面的繪圖作以限制(相當於PS的選區,詳情參見W3School)
三.畫圖片
這個功能無疑是最重要的,簡單的圖形繪制並不是很實用(不信你拿坐標畫個肖像畫試試)
1.導入圖像
-
獲得一個指向HTMLImageElement或者另一個canvas元素的引用作為源,也可以通過提供一個URL的方式來使用圖片
圖像源可以是img, video, canvas元素的引用,當然,也可以是當場創建的new Image(),但要注意應該在新的Image對象的load事件處理器中引用它,否則因為圖像沒有加載完成,某些瀏覽器可能會出錯。當然,此外還可以用Base64編碼圖像源。
-
使用drawImage()函數將圖片繪制到畫布上
-
drawImage(image, x, y):簡單明了的好方法
-
drawImage(image, x, y, width, height):支持縮放
-
drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight):支持裁剪(從大圖里摳出一小部分,詳情參見MDN)
2.導出圖像
這個當然要比圖像操作更重要,拿着畫布畫了半天,該怎么把它導出成圖片呢
canvas.toDataURL():返回圖像URL,直接把URL賦值給img的src就可以顯示了,它就像一個普通圖片地址一樣,想怎么用就怎么用。但需要注意:
-
圖像不能來自其它域,嗯,沒錯,又是跨域安全限制,如果來自其它域,toDataURL()方法會拋出錯誤
-
看清楚toDataURL方法是canvas的,而不是上面一直在用的ctx上下文對象的,而且方法名的大小寫也比較特殊
3.圖像操作
canvas最強大的功能莫過於獲取圖像數據了,我們可以獲取畫布上每一點的色值,不用canvas能搞定嗎?不能。所以簡單的圖像處理現在已經可以用js搞定了,而不需要后台函數的參與。
比如,對上文中的截圖做一個簡單的反色:
var canvas = document.getElementById('my_canvas');
if(canvas.getContext){
var ctx = canvas.getContext('2d');//獲取2d上下文
//畫圖
var img = document.images[0];
ctx.drawImage(img, 0, 0);
//獲取ImageData
var imgData = ctx.getImageData(0, 0, canvas.width, canvas.height);
var data = imgData.data;//獲取rgba(ImageData的data屬性是每個像素點的rgba值)
//反色
var r, g, b, a;
for(var i = 0, len = data.length;i < len; i+=4){
//取色
r = data[i];
g = data[i+1];
b = data[i+2];
//a = data[i+3];//反色不需要透明度
//反色
data[i] = 255 - r;
data[i+1] = 255 - g;
data[i+2] = 255 - b;
}
imgData.data = data;//寫回圖像數據
ctx.putImageData(imgData, 0, 0);//顯示結果
}
處理效果還是很棒的,如下圖:
需要注意一個小問題,Chrome不允許用drawImage畫本地圖片,所以上面的結果是FF下的,在測試Ajax的時候也遇到了類似問題,FF一般在限制跨域安全時不會限制本地資源,而Chrome會,對於服務器上的同源資源則不存在這樣的差異。
四.Canvas的更多功能
漸變、圖案填充、線條控制、陰影、旋轉、變形、縮放、組合、動畫等等更多內容參見參考資料MDN教程
參考資料
-
MDN教程:很不錯的一篇教程
-
《JavaScript高級程序設計》:不舍得還給圖書館的一本好書


