請(qǐng)各位讀者添加一下作者的微信公眾號(hào)棍好,以后有新的文章斤寂,將在微信公眾號(hào)直接推送給各位识颊,非常感謝诚镰。
0. 前言
相信各位小伙伴讀了之前的文章,對(duì) Canvas 基礎(chǔ)已經(jīng)有了一定的認(rèn)識(shí)和了解祥款,但是大家也一定記得我在上一篇文章留了一個(gè)小的坑清笨。
就是我沒(méi)有告訴大家該如何去繪制圓,之所以沒(méi)有說(shuō)是因?yàn)槔L制圓實(shí)際上是因?yàn)?CanvasRenderingContext2D 對(duì)象只提供了兩個(gè)繪制矩形的方法刃跛,并沒(méi)有直接提供繪制圓抠艾,橢圓等幾何圖形的方法。為了在 Canvas 上繪制更復(fù)雜的方法桨昙,必須在 Canvas 上啟用路徑检号,借用路徑來(lái)繪制圖形。
那么我們現(xiàn)在就一起來(lái)看一看蛙酪,該如何使用路徑來(lái)繪制圓等圖形吧齐苛。
------------------我是華麗的分割線----------------------
下一篇文章預(yù)告, canvas 的各種圖像特效滤否。
另外脸狸,接下來(lái)一段時(shí)間最仑,小編要享受一下假期藐俺,暫時(shí)不會(huì)給各位讀者老爺更新啦炊甲,希望各位老爺耐心等待欲芹。
1.使用路徑
在 Canvas 上使用路徑菱父,可按照下面的步驟進(jìn)行浙宜。
- 調(diào)用 CanvasRenderingContext2D 對(duì)象的 beginPath()方法開(kāi)始定義路徑同仆。
- 調(diào)用CanvasRenderingContext2D 的各種方法添加子路徑俗批。
- 調(diào)用CanvasRenderingContext2D 的 closePath 方法關(guān)閉路徑。
- 調(diào)用CanvasRenderingContext2D 的fill()或 stroke()方法來(lái)填充路徑或者繪制路徑邊框。
那我們明確了該如何去進(jìn)行應(yīng)該怎么去使用路徑蝠筑,那么我們接下來(lái)就來(lái)介紹一下 canvas 中添加子路徑的方法揩懒。
- | - |
---|---|
arc(float x,float y,float radius,float startAngle,float endAngle,boolean counterclockwise) | 向 canvas 的當(dāng)前路徑上添加一段弧已球。繪制以 x 智亮, y 為圓心阔蛉,radius 為半徑,從 startAngle 角度開(kāi)始苗踪,到 endAngle 角度結(jié)束的圓弧。startAngle 和 endAngle 以角度為單位。 |
arcTo(float x1,float x2,float y1,float y2,float radius) | 向 canvas 的當(dāng)前路徑上添加一段弧吧黄。與上一個(gè)方法不同的地方只是定義弧的方式不同。 |
bezierCurveTo(float cpX1, float cpY1, float cpX2, float cpY2, float x, float y) | 在當(dāng)前路徑上添加一段貝塞爾曲線 |
quadraticCurveTo(float cpX, float cpY,float x,float y) | 向 canvas 當(dāng)前路徑添加一段二次貝塞爾曲線 |
rect(float x, float y,float width, float height) | 向 canvas 的當(dāng)前路徑上添加一個(gè)矩形 |
方法就這些,但是參數(shù)就顯得非常多了昌讲,咱們來(lái)一條條的來(lái)看看這些方法的具體使用吧。
1.1 繪制圓
首先我們來(lái)學(xué)習(xí)下如何繪制圓减噪,首先明確筹裕,我們應(yīng)該去使用 arc ( ) 方法醋闭,那么我們?cè)撊绾稳ナ褂眠@個(gè)方法呢朝卒?
咱們证逻,放“碼”過(guò)來(lái)。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<div>
<h2>繪制圓形</h2>
<canvas id="canvas_1" width="1000" height="500" style="box-shadow: 0px 0px 20px black;">
當(dāng)前瀏覽器不支持 canvas
</canvas>
</div>
</body>
<script type="text/javascript">
// 獲取 canvas 元素對(duì)應(yīng)的 DOM 對(duì)象
var canvas_1 = document.getElementById("canvas_1");
// 獲取在 canvas 上繪圖的 canvasRenderingContent2D 對(duì)象
var ctx = canvas_1.getContext("2d");
// 我們多去繪制幾個(gè)圓形囚企,使用下 for 循環(huán)
for(var i = 0; i < 10 ; i++){
// 開(kāi)始定義路徑
ctx.beginPath();
// 添加一段圓弧
ctx.arc(i * 25,i * 25,(i + 1) * 8, 0, Math.PI * 2, true);
// 關(guān)閉路徑
ctx.closePath();
// 設(shè)置填充顏色
ctx.fillStyle = 'rgba(255,0,255,'+ (10 - i) * 0.1 + ')';
// 填充當(dāng)前路徑
ctx.fill();
}
</script>
</html>
最后實(shí)現(xiàn)效果如下:
不知道小伙伴們是否看懂了上面的程序呢伤疙?
如果沒(méi)看懂也無(wú)所謂,咱們就來(lái)一起說(shuō)一說(shuō)上面內(nèi)容中的難點(diǎn)黍特。
首先說(shuō)一下键菱,Math.PI 實(shí)際上指代的就是 π谬墙,換而言之也就是 180°今布,那么我們上面使用的角度是 Math.PI * 2,也就是繪制了一個(gè)圓形。
之后再說(shuō)一下 arc(float x,float y,float radius,float startAngle,float endAngle,boolean counterclockwise)
這個(gè)方法拭抬。
里面一共有 6 個(gè)參數(shù)部默,這六個(gè)參數(shù)實(shí)際上對(duì)應(yīng)的是:
- | - |
---|---|
float x | 指定圓弧的圓心的 X 坐標(biāo) |
float y | 指定圓弧的圓心的 Y 坐標(biāo) |
float radius | 指定圓弧的半徑 |
float startAngle | 設(shè)置圓弧的開(kāi)始角度 |
float endAngle | 設(shè)置圓弧的結(jié)束角度 |
boolean counterclockwise | 設(shè)置是否順時(shí)針旋轉(zhuǎn) |
這樣不知道大家對(duì)我們繪制圓是否清楚明白了呢?
如果有任何疑問(wèn)請(qǐng)及時(shí)留言回復(fù)呦造虎。
1.2 繪制圓角矩形
我們之前已經(jīng)學(xué)習(xí)過(guò)繪制圓形傅蹂,也學(xué)習(xí)過(guò)繪制矩形,甚至我們也可以通過(guò) lineJoin 去對(duì)我們的元素的圓角去進(jìn)行修改算凿。
但是份蝴,固定的東西我們不需要,我們真正需要的是可以自定義氓轰,可以根據(jù)我們想要的效果能夠隨意訂制的內(nèi)容婚夫。
為了做到這個(gè)目的,我們還可以去使用 arcTo 來(lái)去繪制一段圓弧署鸡。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<div>
<h2>繪制圓形</h2>
<canvas id="canvas_1" width="1000" height="500" style="box-shadow: 0px 0px 20px black;">
當(dāng)前瀏覽器不支持 canvas
</canvas>
</div>
</body>
<script type="text/javascript">
/*
該方法負(fù)責(zé)繪制圓角矩形
x1 , y2 : 圓角矩形左上角的坐標(biāo)
width案糙,height:控制圓角矩形的寬度和高度
radius:控制圓角矩形的四個(gè)圓角的半徑
*/
function creatRoundRect(ctx, x1, y1, width, height, radius){
// 移動(dòng)到左上角的開(kāi)始點(diǎn)
ctx.moveTo(x1 + radius, y1);
// 添加一條連接開(kāi)始點(diǎn)到右上角的線段
ctx.lineTo(x1 + width - radius, y1);
// 添加右上角的一段圓弧
ctx.arcTo(x1 + width, y1, x1 + width, y1 + radius, radius);
// 添加一條連接到右下角的線段
ctx.lineTo(x1 + width, y1 + height - radius);
// 添加右下角的一段圓弧
ctx.arcTo(x1 + width, y1 + height, x1 + width - radius, y1 + height, radius);
// 添加一條由右下角連接到左下角的線段
ctx.lineTo(x1 + radius, y1 + height);
// 添加左下的圓弧
ctx.arcTo(x1, y1 + height, x1, y1 + height - radius,radius);
// 添加一條由左下角連接到左上角的線段
ctx.lineTo(x1, y1 + radius);
// 添加一段圓弧
ctx.arcTo(x1, y1, x1 + radius, y1, radius);
ctx.closePath();
}
// 獲取 canvas 元素對(duì)應(yīng)的 DOM 對(duì)象
var canvas_1 = document.getElementById("canvas_1");
// 獲取在 canvas 上繪圖的 canvasRenderingContent2D 對(duì)象
var ctx = canvas_1.getContext("2d");
ctx.lineWidth = 3;
creatRoundRect(ctx, 30, 30, 200, 100, 20);
ctx.stroke();
</script>
</html>
注意,我在這里分別繪制了四條線和四個(gè)弧度角靴庆,并且讓他們首尾相連时捌,以此來(lái)達(dá)到繪制矩形框的作用。
其次就是專門(mén)去封裝了一個(gè)函數(shù)炉抒,用于繪制圓角矩形奢讨,回頭有需要的小伙伴可以直接自行粘貼呦。
1.3 繪制多角形
不知道大家對(duì)之前繪制三角形是否還記得焰薄?
我們?cè)诶L制三角形的時(shí)候禽笑,主要是去使用 lineTo 和 moveTo 這兩個(gè)方法,可是我們?cè)谏钪杏龅降膱D形遠(yuǎn)遠(yuǎn)不止這么幾種圖形蛤奥。
那么我們今天就來(lái)學(xué)習(xí)一下如何去繪制多角形佳镜。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<div>
<h2>繪制多角形</h2>
<canvas id="canvas_1" width="1000" height="500" style="box-shadow: 0px 0px 20px black;">
當(dāng)前瀏覽器不支持 canvas
</canvas>
</div>
</body>
<script type="text/javascript">
/*
該方法用于繪制多角形
n:該參數(shù)通常設(shè)置為奇數(shù),控制繪制 N 角星
dx凡桥、dy:控制 N 角星的位置
size:控制 N 角星的大小
*/
function creatStar(context, n, dx, dy, size){
// 開(kāi)始創(chuàng)建路徑
context.beginPath();
var dig = Math.PI / n * 4;
context.moveTo(dx, y + dy);
for(var i = 0; i <= n; i++){
var x = Math.sin(i * dig);
var y = Math.cos(i * dig);
// 繪制從當(dāng)前點(diǎn)連接到指定點(diǎn)的線條
context.lineTo(x * size + dx, y * size + dy);
}
// 關(guān)閉路徑
context.closePath();
}
// 獲取 canvas 元素對(duì)應(yīng)的 DOM 對(duì)象
var canvas_1 = document.getElementById("canvas_1");
// 獲取在 canvas 上繪圖的 canvasRenderingContent2D 對(duì)象
var ctx = canvas_1.getContext("2d");
// 繪制三角星
creatStar(ctx, 3, 60, 60, 50);
ctx.fillStyle = '#f00';
ctx.fill();
// 繪制五角星
creatStar(ctx, 5, 160, 60, 50);
ctx.fillStyle = '#0f0';
ctx.fill();
// 繪制七角星
creatStar(ctx, 7, 260, 60, 50);
ctx.fillStyle = '#00f';
ctx.fill();
// 繪制九角星
creatStar(ctx, 9, 360, 60, 50);
ctx.fillStyle = '#f0f';
ctx.fill();
</script>
</html>
可以看到我們又去封裝了一個(gè)方法蟀伸,專門(mén)用于繪制多角星,當(dāng)然我們也可以在這個(gè)基礎(chǔ)之上去繼續(xù)拓展,這些就需要看小伙伴們的發(fā)揮啦啊掏。
1.4 繪制曲線
還記得我們?cè)谝婚_(kāi)始的時(shí)候我們學(xué)習(xí)了五個(gè)方法蠢络,除了現(xiàn)在已經(jīng)學(xué)習(xí)的繪制圓和繪制圓角矩形,是不是還有一些奇奇怪怪的方法迟蜜?
那么我們現(xiàn)在就開(kāi)始來(lái)學(xué)習(xí)這些方法刹孔。
首先先來(lái)學(xué)習(xí)一下,添加貝塞爾曲線娜睛。
- | - |
---|---|
bezierCurveTo(float cpX1, float cpY1, float cpX2, float cpY2, float x, float y) | 在當(dāng)前路徑上添加一段貝塞爾曲線 |
quadraticCurveTo(float cpX, float cpY,float x,float y) | 向 canvas 當(dāng)前路徑添加一段二次貝塞爾曲線 |
首先來(lái)看看第一個(gè)方法髓霞,第一個(gè)方法中實(shí)際上有四個(gè)點(diǎn)需要注意。
他們分別是
- 左下角的開(kāi)始點(diǎn)
- 粉紅色的第一個(gè)控制點(diǎn)(錨點(diǎn))
- 藏青色的第二個(gè)控制點(diǎn)(錨點(diǎn))
- 右上角的結(jié)束點(diǎn)
而方法中 cpX1 和 cpY1 則是控制第一個(gè)控制點(diǎn)的坐標(biāo)畦戒,
后面的 cpX2 和 cpY2 則是控制第二個(gè)控制點(diǎn)的坐標(biāo)方库。
而二次貝塞爾曲線又是怎么回事呢?
和正常貝塞爾不同障斋,二次曲線只需要三個(gè)點(diǎn):
- 左下角的開(kāi)始點(diǎn)
- 藏青色的控制點(diǎn)
- 右上角的結(jié)束點(diǎn)
方法中的 cpX 和 cpY 則是去設(shè)置控制點(diǎn)的坐標(biāo)纵潦。
那么我們來(lái)一起試一試,該如何去繪制一個(gè)個(gè)花朵垃环。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<div>
<h2>繪制花朵</h2>
<canvas id="canvas_1" width="1000" height="500" style="box-shadow: 0px 0px 20px black;">
當(dāng)前瀏覽器不支持 canvas
</canvas>
</div>
</body>
<script type="text/javascript">
/*
該方法負(fù)責(zé)繪制花朵
n:該參數(shù)控制花朵的花瓣數(shù)
dx,dy:控制花朵的位置
size:控制花朵的大小
length:控制花瓣的長(zhǎng)度
*/
function creatFlower(context, n, dx, dy, size, length){
// 開(kāi)始創(chuàng)建路徑
context.beginPath();
context.moveTo(dx, dy + size);
var dig = 2 * Math.PI / n;
for(var i = 1; i < n + 1; i++){
// 計(jì)算控制點(diǎn)的坐標(biāo)
var ctrlX = Math.sin((i - 0.5) * dig) * length + dx;
var ctrlY = Math.cos((i - 0.5) * dig) * length + dy;
// 計(jì)算結(jié)束點(diǎn)的坐標(biāo)
var x = Math.sin(i * dig) * size + dx;
var y = Math.cos(i * dig) * size + dy;
// 繪制二次曲線
context.quadraticCurveTo(ctrlX, ctrlY, x, y);
}
context.closePath();
}
// 獲取 canvas 元素對(duì)應(yīng)的 DOM 對(duì)象
var canvas_1 = document.getElementById("canvas_1");
// 獲取在 canvas 上繪圖的 canvasRenderingContent2D 對(duì)象
var ctx = canvas_1.getContext("2d");
// 繪制五瓣的花朵
creatFlower(ctx, 5, 70, 100, 30, 80);
ctx.fillStyle = "#f00";
ctx.fill();
// 繪制六瓣的花朵
creatFlower(ctx, 6, 220, 100, 30, 80);
ctx.fillStyle = "#ff0";
ctx.fill();
// 繪制七瓣的花朵
creatFlower(ctx, 7, 370, 100, 30, 80);
ctx.fillStyle = "#f0f";
ctx.fill();
</script>
</html>
1.5 繪制位圖
一直到現(xiàn)在我們講了如何去繪制線邀层,三角形,多角星遂庄,矩形寥院,圓,花朵涧团,圓角矩形等各種圖形只磷。
但是除了這些基礎(chǔ)圖形之外,我們還可以去繪制“位圖”泌绣,讓一張圖片繪制在我們的畫(huà)布之上钮追。
那我們?cè)趺磥?lái)做呢?
我們既然想將我們的圖片載入到我們的畫(huà)布中阿迈,怎么做呢元媚?我們先來(lái)差混構(gòu)建一個(gè) Image 對(duì)象。
var image = new Image();
image.src = "lipeng.png";
需要注意兩點(diǎn)苗沧,
- 我們的程序只是創(chuàng)建刊棕,加載圖片,所以調(diào)用 image 時(shí)無(wú)需傳入寬度和高度待逞,這樣創(chuàng)建的 image 將會(huì)與 src 屬性指定的圖片保持相同的寬度和高度甥角。
- src 加載圖片是進(jìn)行異步加載,如果圖片數(shù)據(jù)太大识樱,或者直接來(lái)自于網(wǎng)絡(luò)嗤无,當(dāng)我們網(wǎng)速較慢的時(shí)候震束,會(huì)發(fā)現(xiàn)我們的圖片繪制會(huì)非常慢,導(dǎo)致影響用戶使用当犯。我們可以使用 onload 去保證我們一定是在圖片加載完成后再繪制垢村。
var image = new Image();
image.src = "lipeng.png";
image.onload = function(){
//繪制圖片
}
學(xué)習(xí)了如何去加載圖片,我們就可以向我們的畫(huà)布中添加圖片了么嚎卫?
沒(méi)有方法你怎么去添加圖片呀嘉栓,魂淡。
我們還要學(xué)習(xí)添加圖片的方法拓诸,這里跟大家說(shuō)三種方法侵佃。
- | - |
---|---|
drawImage(Image image, float x, float y) | 把 image 繪制在 x, y 處。該方法不會(huì)對(duì)圖片做任何縮放處理恰响,繪制處理的圖片保持原來(lái)的大小 |
drawImage(Image image, float x, float y, float width, float height) | 把 image 繪制在 x, y 處趣钱。該方法會(huì)對(duì)圖片進(jìn)行縮放涌献,繪制出來(lái)的寬度為 width胚宦,高度為 height。 |
drawImage(Image image, integer sx, integer sy, integer sw, integer sh, float dx, float dy,float dw, float dh) | 該方法將會(huì)從 image 上“挖出”一塊繪制到畫(huà)布上燕垃。其中 sx, sy 兩個(gè)參數(shù)控制從原圖片上的哪一個(gè)位置開(kāi)始挖去, sw枢劝, sh 兩個(gè)參數(shù)控制從原圖片挖球的寬度和高度;dx, dy 兩個(gè)參數(shù)控制把挖取的圖片繪制到畫(huà)布上的哪個(gè)位置卜壕,而 dw, dh 則控制對(duì)繪制圖片進(jìn)行縮放您旁,繪制出來(lái)的寬度是 dw, 高度 dh |
我們知道了方法,那就來(lái)一起學(xué)習(xí)下轴捎,該如何用代碼來(lái)實(shí)現(xiàn)吧鹤盒。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<div>
<h2>繪制位圖</h2>
<canvas id="canvas_1" width="1000" height="500" style="box-shadow: 0px 0px 20px black;">
當(dāng)前瀏覽器不支持 canvas
</canvas>
</div>
</body>
<script type="text/javascript">
// 獲取 canvas 元素對(duì)應(yīng)的 DOM 對(duì)象
var canvas_1 = document.getElementById("canvas_1");
// 獲取在 canvas 上繪圖的 canvasRenderingContent2D 對(duì)象
var ctx = canvas_1.getContext("2d");
// 創(chuàng)建 image 對(duì)象
var image = new Image();
// 創(chuàng)建 image 對(duì)象裝載圖片
image.src = "lipeng.png";
// 當(dāng)圖片加載完成后觸發(fā)該函數(shù)
image.onload = function(){
// 保持原大小繪制圖片
ctx.drawImage(image, 20, 10);
// 繪制圖片的時(shí)候進(jìn)行縮放
ctx.drawImage(image, 600, 10, 76, 110);
// 從原圖中挖去一塊,放大三倍后繪制在 canvas 上
var sd = 50;
var sh = 50;
/*
參數(shù)說(shuō)明
Image image, integer sx, integer sy, integer sw, integer sh, float dx, float dy,float dw, float dh
sx, sy 兩個(gè)參數(shù)控制從原圖片上的哪一個(gè)位置開(kāi)始挖去侦副,
sw, sh 兩個(gè)參數(shù)控制從原圖片挖球的寬度和高度侦锯;
dx, dy 兩個(gè)參數(shù)控制把挖取的圖片繪制到畫(huà)布上的哪個(gè)位置,而
dw, dh 則控制對(duì)繪制圖片進(jìn)行縮放秦驯,繪制出來(lái)的寬度是 dw, 高度 dh
*/
ctx.drawImage(image, 230, 220,sd, sh, 765, 10, sd * 3, sh * 3);
}
</script>
</html>
結(jié)果如下:
怎么樣尺碰,是不是覺(jué)得瞬間高大上了呢?趕快學(xué)起來(lái)啦译隘。