
一條HTML5 canvas路徑是通過繪制指令來連接一系列的點,由這一系列的點構成直線或曲線。路徑可以用于在HTML5 canvas上繪制各種類型的圖形:直線、圓形、多邊形等等。路徑的繪制是canvas的核心,必須很好的理解和掌握。
開始和關閉一條路徑
要開始和關閉一條路徑可以使用2D上下文的beginPath()和closePath()函數。例如下面的例子:
- var canvas = document.getElementById("ex1");
- var context = canvas.getContext("2d");
-
- context.beginPath();
-
- //... 繪制路徑
-
- context.closePath();
moveTo()函數
當你在canvas中繪制一條路徑的時候,你可以想象自己正在使用一支“虛擬筆”。這支虛擬筆總是位于某個位置,你可以使用2D上下文的moveTo(x, y)函數來移動這支虛擬筆。例如下面的代碼:
- context.moveTo(10,10);
這個例子將“虛擬筆”移動到(10,10)這個坐標點上。
lineTo()函數
lineTo函數用于從虛擬筆的當前位置繪制一條直線到lineTo()函數中指定的點。下面是一個例子:
- context.beginPath();
-
- context.moveTo(10,10);
- context.lineTo(50,50);
-
- context.closePath();
這個例子中首先移動虛擬筆到(10,10)坐標點位置,然后從這個點繪制一條直線到(50,50)坐標點。
lineTo()函數還會將虛擬筆移動到執行的結束點位置。上面的例子中是移動到(50,50)的位置。
stroke()函數 + fill()函數
在你沒有通知2D上下文繪制路徑之前,實際是不會在畫布上繪制任何東西的。你可以通過stroke()或fill()函數來通知2D上下文。
stroke()函數用于路徑操作指定的圖形的外輪廓。
fill()函數用于填充有路徑操作指定的圖形。
下面的例子展示了stroke()或fill()函數的用法。
- context.beginPath();
- context.moveTo(10,10);
- context.lineTo(60,50);
- context.lineTo(110,50);
- context.lineTo(10,10);
- context.stroke();
- context.closePath();
-
- context.beginPath();
- context.moveTo(100,10);
- context.lineTo(150,50);
- context.lineTo(200,50);
- context.lineTo(100,10);
- context.fill();
- context.closePath();
上面代碼的返回結果如下:

線條的寬度
你可以使用2D上下文的lineWidth屬性來設置繪制線條的寬度。下面是一個例子:
- context.lineWidth = 10;
上面的例子設置繪制線條的寬度為10像素。
下面的例子繪制3條直線,它們的寬度分別為1,5和10。

當你繪制的線條寬度大于1的時候,擴展的線條寬度將平均分配在線條中心線的兩側。距離來說,如果你從(10,10)這個點繪制一條直線到(100,10)這個點,線條的寬度為10,那么,實際上是從(10,5)這個點開始繪制,然后擴展到(10,15)這個點,在水平繪制到(100,5)和(100,15)這兩個點,就像是繪制一個矩形。
線條的線條(LINE CAP)
在使用路徑來繪制線條的時候,你可以設置線條的線頭樣式。線頭的樣式通過2D上下文的lineCap屬性來設置。它有三個可選值:
- butt
- round
- square
butt樣式的線頭是扁平且和線正交的樣式。
round樣式的線頭是一個圓角的線頭,圓的半徑等于線條寬度的一半。
square樣式的線頭會在線的末端繪制一個矩形。矩形的大小為:線條的寬度 X 線條的寬/2。
下面是幾個不同線頭樣式的線條的例子。所有的線條的寬度都是10。最總版的一組線條的lineCap的取值為butt,中間的一組線條的lineCap的取值為round,最右邊的一組線條的lineCap的取值為square。

lineCap的取值butt和square非常相似。有時難以區別。這里制作了幾個小例子,從這些例子中你可以看出它們之間的微小差別。下面又三組線條,每一組左邊(或上邊)的線條的lineCap屬性取值為butt,右邊(或下邊)的線條的lineCap屬性取值為square。

正如上面的結果所示,square線頭的線條要比butt線頭的線條要長。
線條的連接
2D上下文的lineJoin屬性用于定義兩條線條連接處的點如何繪制。兩條線條連接處的點被稱為“連接點”。lineJoin屬性有下面的三種取值:
- miter
- bevel
- round
下面是這三種取值的示例代碼:
- context.lineJoin = "miter";
- context.lineJoin = "bevel";
- context.lineJoin = "round";
miter的連接點是一個三角形的連接點。
bevel的連接點是一個平頭的連接點。
round的連接點是一個圓角的連接點。
下面分別是三種線條連接點的例子,從左到右的lineJoin屬性分別是:miter,bevel和round。

繪制曲線
2D上下文的arc()函數可以用于繪制一條曲線。arc()函數有6個參數:
- x:圓弧的中心點的X坐標位置。
- y:圓弧的中心點的Y坐標位置。
- radius:圓弧的半徑。
- startAngle:圓弧開始的角弧度。
- endAngle:圓弧結束的角弧度。
- anticlockwise:設置是以順時針還是逆時針繪制圓弧,false為順時針。
下面是一段示例代碼:
- context.lineWidth = 3;
-
- var x = 50;
- var y = 50;
- var radius = 25;
- var startAngle = (Math.PI / 180) * 45;
- var endAngle = (Math.PI / 180) * 180;
- var anticlockwise = false;
-
- context.beginPath();
- context.arc(x, y, radius, startAngle, endAngle, anticlockwise);
- context.stroke();
- context.closePath();
上面的代碼繪制了一條弧線,它的中心點位于(50,50)坐標點,半徑為25,從45度開始到180度結束。
下面是上面代碼的返回結果:

上面的例子如果將anticlockwise設置為true,會得到下面的結果:

如果你要花一個完整的圓,可以簡單的設置startAngle為0,endAngle設置為2 * Math.PI,它相當于(Math.PI / 180) * 360。
arcTo()函數
2D上下文中有一個arcTo()函數,它用于從當前的點繪制一條曲線到參數指定的點,曲線的半徑也由參數指定。它的語法為:arcTo(x1, y1, x2, y2, radius)。注意:參數中x1, y1, x2, y2指的是這個點的控制點。arcTo()函數可以使用lineTo()和arc函數來模仿。
quadraticCurveTo()函數
quadraticCurveTo()函數用于繪制一條二次貝茲曲線。這條曲線由一個控制點來控制,它的語法為:quadraticCurveTo(cp1x, cp1y, x, y)。下面是一個示例代碼:
- context.lineWidth = 3;
-
- var fromX = 50;
- var fromY = 50;
- var toX = 100;
- var toY = 50;
- var cpX = 75;
- var cpY = 100;
-
- context.beginPath();
- context.moveTo(fromX, fromY);
- context.quadraticCurveTo(cpX, cpY, toX, toY);
- context.stroke();
- context.closePath();
上面的代碼繪制一條從(50,50)開始到(100,50)的二次貝茲曲線,這條曲線的控制點為(75,100)。得到的結果如下所示:

仔細看,在曲線下方有一個小點,那是這條曲線的控制點。(這個點是專門繪制出來讓大家看的)
關于控制點,可以參考下面的圖像:

bezierCurveTo()函數
bezierCurveTo()函數用于從一個點到另一個點繪制一條三次貝茲曲線。三次貝茲曲線有兩個控制點,而二次貝茲曲線只有一個控制點。它的語法為:bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y)。下面是一個例子:
- context.lineWidth = 3;
-
- var fromX = 50;
- var fromY = 50;
- var toX = 300;
- var toY = 50;
- var cp1X = 100;
- var cp1Y = 100;
- var cp2X = 250;
- var cp2Y = 100;
-
- context.beginPath();
- context.moveTo(fromX, fromY);
- context.bezierCurveTo(cp1X, cp1Y, cp2X, cp2Y, toX, toY);
- context.stroke();
- context.closePath();
這段代碼從(50,50)繪制一條三次貝茲曲線到(300,50),兩個控制點分別為:(100,100)和(250,100)。得到的結果如下:

曲線下方的兩個小圓點是兩個控制點,他們并不是曲線的一部分。
下面是一個不同的例子,它的開始點和結束點于上面的例子相同,但是控制點和上面的例子不相同。
- context.lineWidth = 3;
-
- var fromX = 50;
- var fromY = 50;
- var toX = 300;
- var toY = 50;
- var cp1X = 100;
- var cp1Y = 10;
- var cp2X = 250;
- var cp2Y = 100;
-
- context.beginPath();
- context.moveTo(fromX, fromY);
- context.bezierCurveTo(cp1X, cp1Y, cp2X, cp2Y, toX, toY);
- context.stroke();
- context.closePath();
上面的代碼得到的結果如下:

文章的最后,我們引用MDN上的一個例子,它用Canvas路徑繪制出“吃豆人”游戲的一個小場景:

實現的代碼如下:
- function draw() {
- var canvas = document.getElementById('canvas');
- if (canvas.getContext){
- var ctx = canvas.getContext('2d');
-
- roundedRect(ctx,12,12,150,150,15);
- roundedRect(ctx,19,19,150,150,9);
- roundedRect(ctx,53,53,49,33,10);
- roundedRect(ctx,53,119,49,16,6);
- roundedRect(ctx,135,53,49,33,10);
- roundedRect(ctx,135,119,25,49,10);
-
- ctx.beginPath();
- ctx.arc(37,37,13,Math.PI/7,-Math.PI/7,false);
- ctx.lineTo(31,37);
- ctx.fill();
-
- for(var i=0;i<8;i++){
- ctx.fillRect(51+i*16,35,4,4);
- }
-
- for(i=0;i<6;i++){
- ctx.fillRect(115,51+i*16,4,4);
- }
-
- for(i=0;i<8;i++){
- ctx.fillRect(51+i*16,99,4,4);
- }
-
- ctx.beginPath();
- ctx.moveTo(83,116);
- ctx.lineTo(83,102);
- ctx.bezierCurveTo(83,94,89,88,97,88);
- ctx.bezierCurveTo(105,88,111,94,111,102);
- ctx.lineTo(111,116);
- ctx.lineTo(106.333,111.333);
- ctx.lineTo(101.666,116);
- ctx.lineTo(97,111.333);
- ctx.lineTo(92.333,116);
- ctx.lineTo(87.666,111.333);
- ctx.lineTo(83,116);
- ctx.fill();
-
- ctx.fillStyle = "white";
- ctx.beginPath();
- ctx.moveTo(91,96);
- ctx.bezierCurveTo(88,96,87,99,87,101);
- ctx.bezierCurveTo(87,103,88,106,91,106);
- ctx.bezierCurveTo(94,106,95,103,95,101);
- ctx.bezierCurveTo(95,99,94,96,91,96);
- ctx.moveTo(103,96);
- ctx.bezierCurveTo(100,96,99,99,99,101);
- ctx.bezierCurveTo(99,103,100,106,103,106);
- ctx.bezierCurveTo(106,106,107,103,107,101);
- ctx.bezierCurveTo(107,99,106,96,103,96);
- ctx.fill();
-
- ctx.fillStyle = "black";
- ctx.beginPath();
- ctx.arc(101,102,2,0,Math.PI*2,true);
- ctx.fill();
-
- ctx.beginPath();
- ctx.arc(89,102,2,0,Math.PI*2,true);
- ctx.fill();
- }
- }
-
- // A utility function to draw a rectangle with rounded corners.
-
- function roundedRect(ctx,x,y,width,height,radius){
- ctx.beginPath();
- ctx.moveTo(x,y+radius);
- ctx.lineTo(x,y+height-radius);
- ctx.quadraticCurveTo(x,y+height,x+radius,y+height);
- ctx.lineTo(x+width-radius,y+height);
- ctx.quadraticCurveTo(x+width,y+height,x+width,y+height-radius);
- ctx.lineTo(x+width,y+radius);
- ctx.quadraticCurveTo(x+width,y,x+width-radius,y);
- ctx.lineTo(x+radius,y);
- ctx.quadraticCurveTo(x,y,x,y+radius);
- ctx.stroke();
- }
本文版權屬于jQuery之家,轉載請注明出處:http://www.htmleaf.com/ziliaoku/ ... g/201507122217.html
【網站聲明】本站除付費源碼經過測試外,其他素材未做測試,不保證完整性,網站上部分源碼僅限學習交流,請勿用于商業用途。如損害你的權益請聯系客服QQ:2655101040 給予處理,謝謝支持。