五分鐘學會 Canvas 基礎(二)
0. 前言
相信各位小夥伴讀了之前的文章,對 Canvas 基礎已經有了一定的認識和了解,但是大家也一定記得我在上一篇文章留了一個小的坑。
就是我沒有告訴大家該如何去繪製圓,之所以沒有說是因為繪製圓實際上是因為 CanvasRenderingContext2D 物件只提供了兩個繪製矩形的方法,並沒有直接提供繪製圓,橢圓等幾何圖形的方法。為了在 Canvas 上繪製更復雜的方法,必須在 Canvas 上啟用路徑,借用路徑來繪製圖形。
那麼我們現在就一起來看一看,該如何使用路徑來繪製圓等圖形吧。
——————我是華麗的分割線———————-
下一篇文章預告, canvas 的各種影象特效。
另外,接下來一段時間,小編要享受一下假期,暫時不會給各位讀者老爺更新啦,希望各位老爺耐心等待。
1.使用路徑
在 Canvas 上使用路徑,可按照下面的步驟進行。
- 呼叫 CanvasRenderingContext2D 物件的 beginPath()方法開始定義路徑。
- 呼叫CanvasRenderingContext2D 的各種方法新增子路徑。
- 呼叫CanvasRenderingContext2D 的 closePath 方法關閉路徑。
- 呼叫CanvasRenderingContext2D 的fill()或 stroke()方法來填充路徑或者繪製路徑邊框。
那我們明確了該如何去進行應該怎麼去使用路徑,那麼我們接下來就來介紹一下 canvas 中新增子路徑的方法。
- | - |
---|---|
arc(float x,float y,float radius,float startAngle,float endAngle,boolean counterclockwise) | 向 canvas 的當前路徑上新增一段弧。繪製以 x , y 為圓心,radius 為半徑,從 startAngle 角度開始,到 endAngle 角度結束的圓弧。startAngle 和 endAngle 以角度為單位。 |
arcTo(float x1,float x2,float y1,float y2,float radius) | 向 canvas 的當前路徑上新增一段弧。與上一個方法不同的地方只是定義弧的方式不同。 |
bezierCurveTo(float cpX1, float cpY1, float cpX2, float cpY2, float x, float y) | 在當前路徑上新增一段貝塞爾曲線 |
quadraticCurveTo(float cpX, float cpY,float x,float y) | 向 canvas 當前路徑新增一段二次貝塞爾曲線 |
rect(float x, float y,float width, float height) | 向 canvas 的當前路徑上新增一個矩形 |
方法就這些,但是引數就顯得非常多了,咱們來一條條的來看看這些方法的具體使用吧。
1.1 繪製圓
首先我們來學習下如何繪製圓,首先明確,我們應該去使用 arc ( ) 方法,那麼我們該如何去使用這個方法呢?
咱們,放“碼”過來。
<!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;">
當前瀏覽器不支援 canvas
</canvas>
</div>
</body>
<script type="text/javascript">
// 獲取 canvas 元素對應的 DOM 物件
var canvas_1 = document.getElementById("canvas_1");
// 獲取在 canvas 上繪圖的 canvasRenderingContent2D 物件
var ctx = canvas_1.getContext("2d");
// 我們多去繪製幾個圓形,使用下 for 迴圈
for(var i = 0; i < 10 ; i++){
// 開始定義路徑
ctx.beginPath();
// 新增一段圓弧
ctx.arc(i * 25,i * 25,(i + 1) * 8, 0, Math.PI * 2, true);
// 關閉路徑
ctx.closePath();
// 設定填充顏色
ctx.fillStyle = 'rgba(255,0,255,'+ (10 - i) * 0.1 + ')';
// 填充當前路徑
ctx.fill();
}
</script>
</html>
最後實現效果如下:
不知道小夥伴們是否看懂了上面的程式呢?
如果沒看懂也無所謂,咱們就來一起說一說上面內容中的難點。
首先說一下,Math.PI 實際上指代的就是 π,換而言之也就是 180°,那麼我們上面使用的角度是 Math.PI * 2,也就是繪製了一個圓形。
之後再說一下 arc(float x,float y,float radius,float startAngle,float endAngle,boolean counterclockwise)
這個方法。
裡面一共有 6 個引數,這六個引數實際上對應的是:
- | - |
---|---|
float x | 指定圓弧的圓心的 X 座標 |
float y | 指定圓弧的圓心的 Y 座標 |
float radius | 指定圓弧的半徑 |
float startAngle | 設定圓弧的開始角度 |
float endAngle | 設定圓弧的結束角度 |
boolean counterclockwise | 設定是否順時針旋轉 |
這樣不知道大家對我們繪製圓是否清楚明白了呢?
如果有任何疑問請及時留言回覆呦。
1.2 繪製圓角矩形
我們之前已經學習過繪製圓形,也學習過繪製矩形,甚至我們也可以通過 lineJoin 去對我們的元素的圓角去進行修改。
但是,固定的東西我們不需要,我們真正需要的是可以自定義,可以根據我們想要的效果能夠隨意訂製的內容。
為了做到這個目的,我們還可以去使用 arcTo 來去繪製一段圓弧。
<!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;">
當前瀏覽器不支援 canvas
</canvas>
</div>
</body>
<script type="text/javascript">
/*
該方法負責繪製圓角矩形
x1 , y2 : 圓角矩形左上角的座標
width,height:控制圓角矩形的寬度和高度
radius:控制圓角矩形的四個圓角的半徑
*/
function creatRoundRect(ctx, x1, y1, width, height, radius){
// 移動到左上角的開始點
ctx.moveTo(x1 + radius, y1);
// 新增一條連線開始點到右上角的線段
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 元素對應的 DOM 物件
var canvas_1 = document.getElementById("canvas_1");
// 獲取在 canvas 上繪圖的 canvasRenderingContent2D 物件
var ctx = canvas_1.getContext("2d");
ctx.lineWidth = 3;
creatRoundRect(ctx, 30, 30, 200, 100, 20);
ctx.stroke();
</script>
</html>
注意,我在這裡分別繪製了四條線和四個弧度角,並且讓他們首尾相連,以此來達到繪製矩形框的作用。
其次就是專門去封裝了一個函式,用於繪製圓角矩形,回頭有需要的小夥伴可以直接自行貼上呦。
1.3 繪製多角形
不知道大家對之前繪製三角形是否還記得?
我們在繪製三角形的時候,主要是去使用 lineTo 和 moveTo 這兩個方法,可是我們在生活中遇到的圖形遠遠不止這麼幾種圖形。
那麼我們今天就來學習一下如何去繪製多角形。
<!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;">
當前瀏覽器不支援 canvas
</canvas>
</div>
</body>
<script type="text/javascript">
/*
該方法用於繪製多角形
n:該引數通常設定為奇數,控制繪製 N 角星
dx、dy:控制 N 角星的位置
size:控制 N 角星的大小
*/
function creatStar(context, n, dx, dy, size){
// 開始建立路徑
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);
// 繪製從當前點連線到指定點的線條
context.lineTo(x * size + dx, y * size + dy);
}
// 關閉路徑
context.closePath();
}
// 獲取 canvas 元素對應的 DOM 物件
var canvas_1 = document.getElementById("canvas_1");
// 獲取在 canvas 上繪圖的 canvasRenderingContent2D 物件
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>
可以看到我們又去封裝了一個方法,專門用於繪製多角星,當然我們也可以在這個基礎之上去繼續拓展,這些就需要看小夥伴們的發揮啦。
1.4 繪製曲線
還記得我們在一開始的時候我們學習了五個方法,除了現在已經學習的繪製圓和繪製圓角矩形,是不是還有一些奇奇怪怪的方法?
那麼我們現在就開始來學習這些方法。
首先先來學習一下,新增貝塞爾曲線。
- | - |
---|---|
bezierCurveTo(float cpX1, float cpY1, float cpX2, float cpY2, float x, float y) | 在當前路徑上新增一段貝塞爾曲線 |
quadraticCurveTo(float cpX, float cpY,float x,float y) | 向 canvas 當前路徑新增一段二次貝塞爾曲線 |
首先來看看第一個方法,第一個方法中實際上有四個點需要注意。
他們分別是
- 左下角的開始點
- 粉紅色的第一個控制點(錨點)
- 藏青色的第二個控制點(錨點)
- 右上角的結束點
而方法中 cpX1 和 cpY1 則是控制第一個控制點的座標,
後面的 cpX2 和 cpY2 則是控制第二個控制點的座標。
而二次貝塞爾曲線又是怎麼回事呢?
和正常貝塞爾不同,二次曲線只需要三個點:
- 左下角的開始點
- 藏青色的控制點
- 右上角的結束點
方法中的 cpX 和 cpY 則是去設定控制點的座標。
那麼我們來一起試一試,該如何去繪製一個個花朵。
<!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;">
當前瀏覽器不支援 canvas
</canvas>
</div>
</body>
<script type="text/javascript">
/*
該方法負責繪製花朵
n:該引數控制花朵的花瓣數
dx,dy:控制花朵的位置
size:控制花朵的大小
length:控制花瓣的長度
*/
function creatFlower(context, n, dx, dy, size, length){
// 開始建立路徑
context.beginPath();
context.moveTo(dx, dy + size);
var dig = 2 * Math.PI / n;
for(var i = 1; i < n + 1; i++){
// 計算控制點的座標
var ctrlX = Math.sin((i - 0.5) * dig) * length + dx;
var ctrlY = Math.cos((i - 0.5) * dig) * length + dy;
// 計算結束點的座標
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 元素對應的 DOM 物件
var canvas_1 = document.getElementById("canvas_1");
// 獲取在 canvas 上繪圖的 canvasRenderingContent2D 物件
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 繪製點陣圖
一直到現在我們講了如何去繪製線,三角形,多角星,矩形,圓,花朵,圓角矩形等各種圖形。
但是除了這些基礎圖形之外,我們還可以去繪製“點陣圖”,讓一張圖片繪製在我們的畫布之上。
那我們怎麼來做呢?
我們既然想將我們的圖片載入到我們的畫布中,怎麼做呢?我們先來差混構建一個 Image 物件。
var image = new Image();
image.src = "lipeng.png";
需要注意兩點,
- 我們的程式只是建立,載入圖片,所以呼叫 image 時無需傳入寬度和高度,這樣建立的 image 將會與 src 屬性指定的圖片保持相同的寬度和高度。
- src 載入圖片是進行非同步載入,如果圖片資料太大,或者直接來自於網路,當我們網速較慢的時候,會發現我們的圖片繪製會非常慢,導致影響使用者使用。我們可以使用 onload 去保證我們一定是在圖片載入完成後再繪製。
var image = new Image();
image.src = "lipeng.png";
image.onload = function(){
//繪製圖片
}
學習瞭如何去載入圖片,我們就可以向我們的畫布中新增圖片了麼?
沒有方法你怎麼去新增圖片呀,魂淡。
我們還要學習新增圖片的方法,這裡跟大家說三種方法。
- | - |
---|---|
drawImage(Image image, float x, float y) | 把 image 繪製在 x, y 處。該方法不會對圖片做任何縮放處理,繪製處理的圖片保持原來的大小 |
drawImage(Image image, float x, float y, float width, float height) | 把 image 繪製在 x, y 處。該方法會對圖片進行縮放,繪製出來的寬度為 width,高度為 height。 |
drawImage(Image image, integer sx, integer sy, integer sw, integer sh, float dx, float dy,float dw, float dh) | 該方法將會從 image 上“挖出”一塊繪製到畫布上。其中 sx, sy 兩個引數控制從原圖片上的哪一個位置開始挖去, sw, sh 兩個引數控制從原圖片挖球的寬度和高度;dx, dy 兩個引數控制把挖取的圖片繪製到畫布上的哪個位置,而 dw, dh 則控制對繪製圖片進行縮放,繪製出來的寬度是 dw, 高度 dh |
我們知道了方法,那就來一起學習下,該如何用程式碼來實現吧。
<!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;">
當前瀏覽器不支援 canvas
</canvas>
</div>
</body>
<script type="text/javascript">
// 獲取 canvas 元素對應的 DOM 物件
var canvas_1 = document.getElementById("canvas_1");
// 獲取在 canvas 上繪圖的 canvasRenderingContent2D 物件
var ctx = canvas_1.getContext("2d");
// 建立 image 物件
var image = new Image();
// 建立 image 物件裝載圖片
image.src = "lipeng.png";
// 當圖片載入完成後觸發該函式
image.onload = function(){
// 保持原大小繪製圖片
ctx.drawImage(image, 20, 10);
// 繪製圖片的時候進行縮放
ctx.drawImage(image, 600, 10, 76, 110);
// 從原圖中挖去一塊,放大三倍後繪製在 canvas 上
var sd = 50;
var sh = 50;
/*
引數說明
Image image, integer sx, integer sy, integer sw, integer sh, float dx, float dy,float dw, float dh
sx, sy 兩個引數控制從原圖片上的哪一個位置開始挖去,
sw, sh 兩個引數控制從原圖片挖球的寬度和高度;
dx, dy 兩個引數控制把挖取的圖片繪製到畫布上的哪個位置,而
dw, dh 則控制對繪製圖片進行縮放,繪製出來的寬度是 dw, 高度 dh
*/
ctx.drawImage(image, 230, 220,sd, sh, 765, 10, sd * 3, sh * 3);
}
</script>
</html>
結果如下:
怎麼樣,是不是覺得瞬間高大上了呢?趕快學起來啦。