原文:http://developer.mozilla.org/en/Canvas_tutorial/Drawing_shapes

在我們開始繪制圖形前,我們先探討一下canvas中的網格及坐標空間。在前一篇教程中,我們定義了一個150*150的canvas區域,并在該區域繪制了一個圖形。在canvas區域中,以左上角為坐標原點(0,0),坐標最小單位為1px。區域內所有元素相對與原點定位。不過在以后的實例中,我們還會向你展示如何重定義坐標原點、旋轉坐標甚至是重新定義坐標單位,但是現在,我們還是從默認設置開始學習。
與SVG語法不同的是,canvas只提供了一個繪制矩形的語法,其他形狀的繪制就必須依靠路徑功能來繪制了,哈哈,其實我們已經收集了很多多繪制各種復雜多邊形的function,拿來就能用嘍。
Rectangles
首先讓我們來看下,目前有三種繪制矩形的語法:
fillRect(x,y,width,height) : 繪制一個實心的舉行strokeRect(x,y,width,height) : 繪制一個矩形邊框clearRect(x,y,width,height) : 繪制一個透明的矩形
以上三種方法中都有x和y參數,這對參數的值就是相對于canvas原點(左上角)的距離。
以下代碼為之前教程中出現過的draw()函數,我們這次將三種矩形繪制的方法都寫進去:
function draw(){ var canvas = document.getElementById('tutorial'); if (canvas.getContext){ var ctx = canvas.getContext('2d'); ctx.fillRect(25,25,100,100); ctx.clearRect(45,45,60,60); ctx.strokeRect(50,50,50,50); }}
繪制的效果見右圖,fillRect函數繪制了一個100*100的大矩形,clearRect函數從這個矩形挖掉了一塊60*60的矩形并且strokeRect函數又繪制了一個50*50的矩形邊框。在以后的教材中我們將看到另外的clearRect方法以及我們如何為矩形填充不同的顏色和繪制不同的邊框。
與接下來我們要講的path方法不同,以上三個矩形繪制方法執行后都會立即應用到canvas區域內。
用路徑來繪制多邊形,以下這些方法我們都是需要的:
beginPath()closePath()stroke()fill()
第一步,我們使用beginPath方法聲明一個路徑,路徑的繪制需要用到一系列字方法(lines,arcs,ect)共同配合來完成一個多邊形,每次我們用到路徑來繪制多邊形時,我們都需要聲明一個beginPath來開始繪制。
第二步,我們將需要調用一些特定方法來繪制我們需要的路徑,我們很快就會了解到。
第三步,closePath,是一個可選步驟,這個方法將封閉繪制路徑的起點,如果該多邊形已經被封閉,那么,這個方法將不產生任何作用。
最后的步驟,是運用stroke或者fill方法,為繪制好的多邊形路徑填充顏色或者描邊。
注意:如果用fill方法填充一個未封閉的多邊形時,該多邊形將被自動封閉,無需closePath幫忙了。
例如,以下代碼將會繪制一個簡單的三角形:
ctx.beginPath();ctx.moveTo(75,50);ctx.lineTo(100,75);ctx.lineTo(100,25);ctx.fill();
moveTo

這是一個非常有用的函數,雖然該函數不會繪制任何東西,但是它是路徑描述中的一個重要的功能。
moveTo函數將傳入2個參數,x坐標和y坐標,以該坐標點為一個新的繪制起點。
當canvas初始化或者beginPath方法執行后,最起始的坐標點默認是(0,0),在絕大多數的應用中,我們會用moveTo方法來定位路徑繪制的起點。我們亦可以用此方法繪制一些沒有連接的路徑,比如右邊的這張笑臉圖,用紅色線條標識出來的就是用moveTo方法來實現的。
示例:
ctx.beginPath();ctx.arc(75,75,50,0,Math.PI*2,true); // Outer circlectx.moveTo(110,75);ctx.arc(75,75,35,0,Math.PI,false); // Mouth (clockwise)ctx.moveTo(65,65);ctx.arc(60,65,5,0,Math.PI*2,true); // Left eyectx.moveTo(95,65);ctx.arc(90,65,5,0,Math.PI*2,true); // Right eyectx.stroke();
Lines
顧名思義,畫直線的方法。
lineTo(x, y)

該方法帶的2個參數為線段終點的坐標,起點坐標則依賴于上一個路徑所申明的終點,當然該線段的起點也可以是由moveTo方法所申明的坐標。
示例:如右邊的圖片所示,我們繪制了2個三角形,一個做填充,一個做描邊。首先用beginPath方法申明一個新的路徑繪制,用moveTo方法定義繪制起點。
你可能會注意到繪制實心和空心的三角形,其語法略有差異,那是因為當一個多邊形需要填充時,其會自動封閉路徑的始末端。
// Filled trianglectx.beginPath();ctx.moveTo(25,25);ctx.lineTo(105,25);ctx.lineTo(25,105);ctx.fill();// Stroked trianglectx.beginPath();ctx.moveTo(125,125);ctx.lineTo(125,45);ctx.lineTo(45,125);ctx.closePath();ctx.stroke();
Arcs
該方法為繪制弧線或者圓形路徑時使用,該方法另一個寫法為arcTo,不過該寫法僅僅用于safari瀏覽器,而不會兼容采用Gecko為核心的瀏覽器。
arc(x, y, radius, startAngle, endAngle, anticlockwise)

該方法接收N個參數:x和y為該段弧線所對應的原點坐標;radius為半徑;startAngle和endAngle則決定了該段弧線的2個端點,起始和結束的角度以坐標系X軸為衡量基準;anticlockwise為一個布爾值參數,當為true時則逆時針方向畫狐,反之則順時針。
警告:在firefox的某些beta版本中,最后一個參數被定義為clockwise,請確保將你的瀏覽器版本升級至最終發布版本。
注意:在本表達式中的Angle是以弧度為單位呈現的,實際運用中,我們經常需要在角度與弧度之間做一個轉換,其JS的轉換表達式為:var radians = (Math.PI/180)*degrees
示例:
for (i=0;i<4;i++){ for(j=0;j<3;j++){ ctx.beginPath(); var x = 25+j*50; // x coordinate var y = 25+i*50; // y coordinate var radius = 20; // Arc radius var startAngle = 0; // Starting point on circle var endAngle = Math.PI+(Math.PI*j)/2; // End point on circle var anticlockwise = i%2==0 ? false : true; // clockwise or anticlockwise ctx.arc(x,y,radius,startAngle,endAngle, anticlockwise); if (i>1){ ctx.fill(); } else { ctx.stroke(); } }}Bezier and quadratic curves
如果我們需繪制更加復雜的曲線路徑,我們或許該用到貝塞爾或者2次方程曲線。
quadraticCurveTo(cp1x, cp1y, x, y) // BROKEN in Firefox 1.5 (see work around below)bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y)

兩種曲線有何區別?我們可以參看一下右邊這張圖,2種曲線都有一個起點和終點(blue point),但是貝塞爾曲線僅有一個“control point”(red point),2次曲線則有2個。
兩個方法中的x和y參數都為曲線的終點坐標,cp1x和cp1y為第一control point的坐標,cp2x和cp2y為2次曲線的第二控制點。
熟練運用2次曲線和貝塞爾曲線進行路徑繪制,是一件蠻有挑戰性的工作,因為它不像某些矢量繪圖軟件,比如ADOBE Illustrator等具有直觀的視覺反饋,所以這使得我們在繪制一些復雜的曲線時會遇到一點小困難,不過如果你有耐心和時間的話,你肯定能繪制出許多復雜的曲線來。
二次曲線示例:

貝塞爾曲線示例:

新聞熱點
疑難解答