本文章為 Mozilla Developer Center 的 Drawing Graphics with Canvas 的翻譯。原文的作者與編修歷史可在它的歷史頁上看到。
內容大綱
簡介Mozilla Firefox 1.5 裡有個新的用來做出可程式化圖片的 HTML 元素。<canvas> 根據 ,而這又是根據 Apple Safari 裡的 <canvas> 實作。此元素可以在用戶端上直接繪製出圖表、介面、或其它自訂圖片。
<canvas> 會建立固定大小的繪圖空間,並會有一個或多個「繪製環境」(rendering context)。在本文裡我們會專注在 2D 的繪製上(這也是目前唯一有定義的 context)。在未來會有更多的 context 提供其它類別的繪製,例如使用 OpenGL 的 3D 繪製。
2D Context(平面繪製環境) 簡單的範例一開始我們先來做一個簡單的練習,底下是一個半透明正方形蓋在另一個正方形之上的範例:
範例一
<html> <head> <script type="application/x-javascript"> function draw() { var canvas = document.getElementById("canvas"); var ctx = canvas.getContext("2d"); ctx.fillStyle = "rgb(200,0,0)"; // 把「填滿樣式」設為紅 200 綠 0 藍 0 ctx.fillRect (10, 10, 50, 50); // 畫一個填充的長方形 ctx.fillStyle = "rgba(0, 0, 200, 0.5)"; // 把「填滿樣式」設為紅 0 綠 0 藍 200 透度 0.5 ctx.fillRect (30, 30, 50, 50); // 畫一個填充的長方形 } </script> </head> <body> <canvas></canvas> </body> </html>draw 函數先取得 canvas 元素,再獲得 2d context。ctx 物件可用來實際在畫板上繪製。本範例以用 CSS 顏色設定 fillStyle(填滿樣式)與呼叫 fillRect 的方式來繪出兩個方形。第二個 fillStyle 是用 rgba() 來一併定義顏色與透度(alpha)的值。
fillRect、strokeRect、與 clearRect calls 繪製填充、輪廓線、與透明的長方形。較複雜的形狀用路徑(path)。
使用路徑beginPath 函數可以開始一個新的路徑,moveTo、lineTo、arcTo、arc、或其他類似的函數可以加入路徑片段。路徑可用 closePath 把頭尾連起來。建立路徑之後你可以用 fill 或 stroke 來把路徑繪製到 canvas 上。
範例二
<html> <head> <script type="application/x-javascript"> function draw() { var canvas = document.getElementById("canvas"); var ctx = canvas.getContext("2d"); ctx.fillStyle = "red"; ctx.beginPath(); // 開始路徑 ctx.moveTo(30, 30); // (起點)移到 30, 30 ctx.lineTo(150, 150); // 做直線到 150, 150 ctx.quadraticCurveTo(60, 70, 70, 150); // 做一元二次方程曲線到 70, 150 ctx.lineTo(30, 30); // 做直線到 30, 30 ctx.fill(); // 路徑內填色 } </script> </head> <body> <canvas></canvas> </body> </html>呼叫 fill() 或 stroke() 會使得目前的路徑被用掉。要再塗滿或畫線的話,路徑必須要重建一次。
圖片狀態Context 的如 fillStyle、strokeStyle、lineWidth、與 lineJoin 的屬性屬於 目前的圖片狀態(graphics state)的一部份。Context 有 save()(儲存)與 restore()(返回)兩個函數讓目前的狀態可以存入狀態堆疊(stack)與從中移除。(注意路徑不屬於圖片狀態。)
較複雜的範例現在來一個複雜一點的範例。這範例用到路徑(path)與狀態(state),此範例也介紹了轉換矩陣(current transformation matrix)的概念。Context 的 translate()(移動)、scale()(縮放)與 rotate()(轉動)方式會轉換目前的矩陣。所有繪製的點都會先用這個矩陣。
範例三
<html> <head> <script type="application/x-javascript"> // 畫蝴蝶結 function drawBowtie(ctx, fillStyle) { ctx.fillStyle = "rgba(200,200,200,0.3)"; // 把「填滿樣式」設為灰色,0.3 透度 ctx.fillRect(-30, -30, 60, 60); // 畫一個填色的方形 ctx.fillStyle = fillStyle; // 設定填色 ctx.globalAlpha = 1.0; // 全域透度 ctx.beginPath(); // 開始路徑 ctx.moveTo(25, 25); // (起點)移到 25, 25 ctx.lineTo(-25, -25); // 做直線到 -25, -25 ctx.lineTo(25, -25); // 做直線到 25, -25 ctx.lineTo(-25, 25); // 做直線到 -25, 25 ctx.closePath(); // 關閉路徑 ctx.fill(); // 填色 } // 畫點 function dot(ctx) { ctx.save(); // 儲存目前狀態 ctx.fillStyle = "black"; // 填色樣式設為黑色 ctx.fillRect(-2, -2, 4, 4); // 畫黑色正方形 ctx.restore(); // 返回狀態 } function draw() { var canvas = document.getElementById("canvas"); var ctx = canvas.getContext("2d"); // 注意其它的移動都是相對於這一個 ctx.translate(45, 45); ctx.save(); //ctx.translate(0, 0); // 不需要 drawBowtie(ctx, "red"); // 畫綠色蝴蝶結 dot(ctx); ctx.restore(); ctx.save(); // 儲存目前狀態 ctx.translate(85, 0); // 移動(向右 85) ctx.rotate(45 * Math.PI / 180); // 轉動 45 度 drawBowtie(ctx, "green"); // 畫綠色蝴蝶結 dot(ctx); // 畫中心點 ctx.restore(); // 返回到先前的狀態 (轉動 0, 移動 45, 45) ctx.save(); // 儲存目前狀態 ctx.translate(0, 85); // 移動(向下 85) ctx.rotate(135 * Math.PI / 180); // 轉動 135 度 drawBowtie(ctx, "blue"); // 畫藍色蝴蝶結 dot(ctx); // 畫中心點 ctx.restore(); // 返回到先前的狀態 (轉動 0, 移動 45, 45) ctx.save(); ctx.translate(85, 85); ctx.rotate(90 * Math.PI / 180); drawBowtie(ctx, "yellow"); // 畫黃色蝴蝶結 dot(ctx); ctx.restore(); } </script> </head> <body onload="draw()"> <canvas id="canvas" width="300" height="300"></canvas> </body> </html>