1. 程式人生 > >五分鐘學會 Canvas 基礎(二)

五分鐘學會 Canvas 基礎(二)

0. 前言

相信各位小夥伴讀了之前的文章,對 Canvas 基礎已經有了一定的認識和了解,但是大家也一定記得我在上一篇文章留了一個小的坑。

就是我沒有告訴大家該如何去繪製圓,之所以沒有說是因為繪製圓實際上是因為 CanvasRenderingContext2D 物件只提供了兩個繪製矩形的方法,並沒有直接提供繪製圓,橢圓等幾何圖形的方法。為了在 Canvas 上繪製更復雜的方法,必須在 Canvas 上啟用路徑,借用路徑來繪製圖形。

那麼我們現在就一起來看一看,該如何使用路徑來繪製圓等圖形吧。

——————我是華麗的分割線———————-

下一篇文章預告, canvas 的各種影象特效。

另外,接下來一段時間,小編要享受一下假期,暫時不會給各位讀者老爺更新啦,希望各位老爺耐心等待。

1.使用路徑

在 Canvas 上使用路徑,可按照下面的步驟進行。

  1. 呼叫 CanvasRenderingContext2D 物件的 beginPath()方法開始定義路徑。
  2. 呼叫CanvasRenderingContext2D 的各種方法新增子路徑。
  3. 呼叫CanvasRenderingContext2D 的 closePath 方法關閉路徑。
  4. 呼叫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>

最後實現效果如下:

Paste_Image.png

不知道小夥伴們是否看懂了上面的程式呢?

如果沒看懂也無所謂,咱們就來一起說一說上面內容中的難點。

首先說一下,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>

注意,我在這裡分別繪製了四條線和四個弧度角,並且讓他們首尾相連,以此來達到繪製矩形框的作用。

其次就是專門去封裝了一個函式,用於繪製圓角矩形,回頭有需要的小夥伴可以直接自行貼上呦。

Paste_Image.png

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>

可以看到我們又去封裝了一個方法,專門用於繪製多角星,當然我們也可以在這個基礎之上去繼續拓展,這些就需要看小夥伴們的發揮啦。

Paste_Image.png

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 當前路徑新增一段二次貝塞爾曲線

首先來看看第一個方法,第一個方法中實際上有四個點需要注意。

Paste_Image.png

他們分別是

  • 左下角的開始點
  • 粉紅色的第一個控制點(錨點)
  • 藏青色的第二個控制點(錨點)
  • 右上角的結束點

而方法中 cpX1 和 cpY1 則是控制第一個控制點的座標,

後面的 cpX2 和 cpY2 則是控制第二個控制點的座標。

而二次貝塞爾曲線又是怎麼回事呢?

Paste_Image.png

和正常貝塞爾不同,二次曲線只需要三個點:

  • 左下角的開始點
  • 藏青色的控制點
  • 右上角的結束點

方法中的 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>

Paste_Image.png

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>

結果如下:

Paste_Image.png

怎麼樣,是不是覺得瞬間高大上了呢?趕快學起來啦。