《JS原理、方法與實(shí)踐》- canvas作圖基礎(chǔ)

canvas簡介

canvas標(biāo)簽是HTML5標(biāo)準(zhǔn)最受歡迎的一個(gè)標(biāo)簽,它的作用就相當(dāng)于一塊畫布,可以通過JS腳本在canvas上面進(jìn)行繪畫,而且還可以對畫面的內(nèi)容進(jìn)行修改,通過不斷修改可以實(shí)現(xiàn)動(dòng)畫的效果,再跟事件結(jié)合后就可以制作游戲了!

canvas標(biāo)簽及其所對應(yīng)的JS對象HTMLCanvasElement本身非常簡單,它們主要包含width、height兩個(gè)屬性和一個(gè)getContext方法。雖然HTML5中新增了setContext等方法,但是各大瀏覽器支持得并不好。

canvas本身并沒有太多得操作,它主要是通過getContext方法獲取的環(huán)境對象進(jìn)行操作。canvas和它所包含的context對象的關(guān)系就好像canvas是一塊畫布,而context是各種筆,拿到筆,然后才可以繪圖。

canvas的用法

首先獲取canvas對象,然后使用這個(gè)對象獲取相應(yīng)的環(huán)境,最后使用獲取的環(huán)境繪圖。
代碼示例:

<body>
    <canvas id="c2d" width="300" height="300">瀏覽器不支持canvas</canvas>
    <canvas id="c3d" width="150" height="150">瀏覽器不支持canvas</canvas>
    <script>
        // 獲取canvas對象
        const canvas2d = document.querySelector('#c2d');
        // 使用這個(gè)對象獲取相應(yīng)的環(huán)境
        const ctx2d = canvas2d.getContext('2d');'

        // 繪制圖形...

        const canvas3d = document.querySelector('#c3d');
        const ctx3d = canvas3d.getContext('webgl');
    </script>
</body>

從示例中,我們可以看出利用getContext()方法獲取繪圖環(huán)境,目前只支持2d('2d')和3d('webgl')環(huán)境。

繪制矩形

繪制矩形是canvas中最簡單的功能,跟繪制矩形相關(guān)的方法一共包括如下三個(gè):

  • strokeRect(x,y,width,height):繪制矩形邊框
  • fillRect(x,y,width,height):繪制矩形并填充
  • clearRect(x,y,width,height): 清除矩形區(qū)域內(nèi)容,實(shí)際上是使用底色填充矩形區(qū)域。
    這三個(gè)方法的參數(shù)中,x,y表示矩形左上角的坐標(biāo),width和height表示矩形的寬和高,坐標(biāo)原點(diǎn)默認(rèn)為canvas的左上角,canvas中矩形的結(jié)構(gòu)如下:


    canvas矩形結(jié)構(gòu)圖

    代碼示例:

    <canvas id="c2d" width="300" height="300">瀏覽器不支持canvas</canvas>
    <script>
        
        const canvas2d = document.querySelector('#c2d');
        const ctx2d = canvas2d.getContext('2d');
        // 繪制矩形
        ctx2d.fillRect(30,50,100,50);
        ctx2d.strokeRect(100,30,100,50);
        ctx2d.clearRect(101,51,28,28);
    </script>
運(yùn)行結(jié)果

繪制路徑

繪制路徑常用方法屬性

使用路徑一共可以分為4步:創(chuàng)建路徑、繪制路徑、關(guān)閉路徑和操作路徑,其中繪制路徑最復(fù)雜也是最重要的內(nèi)容。先介紹其他三種操作,最后詳細(xì)講解繪制路徑。

創(chuàng)建/關(guān)閉路徑

創(chuàng)建路徑

路徑的創(chuàng)建一共有兩種方法,一種是調(diào)用CanvasRenderingContext2D的beginPath方法,另一種是新建Path2D對象。
調(diào)用CanvasRenderingContext2D的beginPath方法后就可以直接使用CanvasRenderingContext2D來繪制路徑,而使用Path2D新建時(shí)會(huì)返回新建的路徑,然后在新建出來的路徑上進(jìn)行操作,例如下面的例子:

    <canvas id="c2d">瀏覽器不支持canvas</canvas>
    <script>
        const c2d = document.querySelector('#c2d');
        const ctx2d = c2d.getContext('2d');

        // 使用beginPath方法創(chuàng)建
        ctx2d.beginPath();
        // 這里可以使用ctx2d繪制路徑
        // ......

        // 使用Path2D新建路徑
        const newPath = new Path2D();
        // 這里實(shí)際newPath來繪制路徑
        //......
    </script>
關(guān)閉路徑

關(guān)閉路徑使用的是closePath方法,其主要作用是將路徑閉合起來,也就是從畫筆的終點(diǎn)到路徑的起點(diǎn)繪制一條直線,如果路徑已經(jīng)閉合,那么也可以不調(diào)用該方法。

操作路徑

對路徑的操作只有兩種:填充和描邊,它們所對應(yīng)的方法分別是stroke和fill。如果是使beginPath創(chuàng)建的路徑,那么直接調(diào)用就可以了,如果是新建的Path2D路徑,那么需要將創(chuàng)建出來的路徑傳入?yún)?shù)中,例如下面的例子:

<canvas id="c2d">瀏覽器不支持canvas</canvas>
   <script>
       const c2d = document.querySelector('#c2d');
       const ctx2d = c2d.getContext('2d');

       // 使用beginPath方法創(chuàng)建
       ctx2d.beginPath();
       // 這里可以使用ctx2d繪制路徑
       // ......
       ctx2d.closePath();
       ctx2d.fill();


       // 使用Path2D新建路徑
       const newPath = new Path2D();
       // 這里實(shí)際newPath來繪制路徑
       //......
       newPath.closePath();
       ctx2d.stroke(newPath);
   </script>

繪制路徑

所有平面上的圖形都是由直線和曲線組成的(點(diǎn)其實(shí)是半徑很小的實(shí)心圓),因此路徑的繪制主要分為直線和曲線兩種類型。但是,CanvasRenderingContext2D繪制路徑時(shí)除了這兩種類型外還有一個(gè)輔助操作的方法。

輔助操作

輔助方法:moveTo(x,y),兩個(gè)參數(shù)表示移動(dòng)到的目標(biāo)點(diǎn)的坐標(biāo)值

繪制直線

方法:lineTo(x,y),它可以從畫筆當(dāng)前點(diǎn)到參數(shù)中傳入的坐標(biāo)點(diǎn)畫一條直線,一般會(huì)與moveTo方法配合使用。

樣式的設(shè)置

屬性:lineWidth:指定線條的寬度
屬性:lineDashOffset: 指定虛線的偏移量
方法:setLineDash():設(shè)置虛線的樣式,參數(shù)為一個(gè)數(shù)組,數(shù)組的元素用來表示實(shí)線與空白所占用的寬度,虛線會(huì)按數(shù)組中的值進(jìn)行循環(huán)。
示例(畫一個(gè)正方形和兩條虛線):

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <canvas id="canvas" width="500" width="500"></canvas>
    <script>
        const canvas = document.querySelector('#canvas');
        if(canvas.getContext) {
            const ctx = canvas.getContext('2d');
            ctx.beginPath();
            ctx.lineWidth = 10;
            ctx.moveTo(10,10);
            ctx.lineTo(10,100);
            ctx.lineTo(100,100);
            ctx.lineTo(100,10);
            ctx.closePath();
            ctx.stroke();

            ctx.beginPath();
            ctx.lineWidth = 1;
            ctx.setLineDash([5,10]);
            ctx.moveTo(10,120);
            ctx.lineTo(120,120);
            ctx.closePath();
            ctx.stroke();
            
            ctx.beginPath();
            ctx.setLineDash([5,10]);
            ctx.lineDashOffset = 2;
            ctx.moveTo(10,130);
            ctx.lineTo(130,130);

            ctx.closePath();
            ctx.stroke();
        }
    </script>
</body>
</html>

繪制曲線

繪制圓弧

方法:arc(x,y,radius,startAngle,endAngle,anticlockwise)
參數(shù)說明:x,y為圓心,radius為半徑,startAngle和endAngle分別是起始角度和結(jié)束角度,anticlockwise表示是否逆時(shí)針繪制,默認(rèn)為順時(shí)針。
方法:arcTo(x1,y1,x2,y2,radius)
參數(shù)說明:通過兩條切線和半徑來指定一段圓弧,畫筆當(dāng)前點(diǎn)和(x1,y1), (x1,y1)和(x2,y2)構(gòu)成兩條切線,參數(shù)radius為半徑。兩條切線和一個(gè)半徑可以將一個(gè)圓分成兩段圓弧,acrTo方法繪制的是較短的那段。如果畫筆的起始點(diǎn)不是圓弧的切點(diǎn),那么acrTo方法還會(huì)將起點(diǎn)和切點(diǎn)使用直線連接起來。
示例:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <canvas width="500" height="500" id='c2d'></canvas>
    <script>
        const canvas = document.getElementById('c2d');
        const ctx = canvas.getContext('2d');

        ctx.beginPath();
        ctx.arc(100,100,100,0, 2*Math.PI,false);
        ctx.closePath();
        ctx.stroke();

        ctx.beginPath();
        ctx.lineTo(250,30);
        ctx.lineWidth = 0.5;
        ctx.arcTo(200,30,250,50,20);
        ctx.closePath();
        ctx.stroke();
    </script>
</body>
</html>
運(yùn)行結(jié)果
繪制貝塞爾曲線

方法:quadraticCurveTo(cp1x,xp1y,x,y)
方法:bezierCurveTo(cp1x,cp1y,cp2x,cp2y,x,y)
這兩個(gè)方法分別用于繪制一個(gè)控制點(diǎn)和兩個(gè)控制點(diǎn)的貝塞爾曲線,畫筆當(dāng)前點(diǎn)為曲線的起點(diǎn),(x,y)為曲線的終點(diǎn),(cpx1,cp1y)和(cp2x,cp2y)都是控制點(diǎn),理解了貝塞爾曲線,這兩個(gè)方法就很容易理解:深入理解貝塞爾曲線
實(shí)例:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <canvas id="c2d">瀏覽器不支持canvas</canvas>
    <script>
        const canvas = document.querySelector('#c2d');
        if(canvas.getContext) {
            const ctx = canvas.getContext('2d');
            ctx.beginPath();
            ctx.moveTo(30,50);
            ctx.quadraticCurveTo(40,80,100,50);

            ctx.moveTo(130,60);
            ctx.bezierCurveTo(160,30,200,100,260,50);
            ctx.stroke();
        }
    </script>
</body>
</html>
運(yùn)行結(jié)果

組合與剪切

組合與剪切主要是對應(yīng)多個(gè)圖形來說的,組合指的是多個(gè)圖形重疊時(shí)的組合方式,剪切是指使用路徑來指定繪圖的區(qū)域,類似于Photoshop中的蒙版的效果。

組合

圖形的組合是通過globalCompositeOperation屬性來操作的,該屬性可以取下面的值:

  • source-over: 后繪制的圖形覆蓋原圖,該值為默認(rèn)值
  • source-in: 保留后繪制圖形和原圖形重疊的部分,使用后繪制圖形的樣式,其他區(qū)域透明,也就是保留相交的部分
  • source-out: 保留后繪制圖形不和原圖形重疊的部分,其他區(qū)域透明
  • source-atop: 保留后繪制圖形和原圖形重疊的部分,使用后繪制圖形的樣式,原圖中的非重疊部分不變
  • destination-over: 后繪制圖形被原圖覆蓋,也就是重疊部分顯示原圖
  • destination-in: 保留后繪制圖形和原圖形重疊的部分,使用原圖的樣式,其他區(qū)域透明
  • destination-out: 保留原圖不和后繪制圖形重疊的部分,其他區(qū)域透明
  • destination-atop: 保留后繪制圖形和原圖形重疊的部分,使用原圖的樣式,后繪制圖形中的非重疊部分不變
  • lighter: 后繪制圖形和原圖重疊的部分進(jìn)行疊加
  • copy: 顯示后繪制圖形,不顯示原圖
  • xor: 后繪制圖形和原圖重疊的部分進(jìn)行異或操作
  • multiply: 將后繪制圖形和原圖的像素相乘,圖形變暗
  • screen: 將后繪制圖形和原圖的像素分別反向后相乘再反向,圖形變亮
  • overlay: 組合使用multiply和screen,使亮的部分更亮,暗的部分更暗
  • darken: 取兩個(gè)圖形中較暗的像素值,例如,#aa0011與#cc3300計(jì)算后為#aa0000
  • ighten: 取兩個(gè)圖形中較亮的像素值,例如,#aa0011與#cc3300計(jì)算后為#aa3311
  • color-dodge: 使用原圖像素除以后繪制圖形的反向像素值
  • color-burn: 使用原圖反向像素除以后繪制圖形的像素,然后再反向
  • hard-light: 組合使用multiply和screen,它與overlay的區(qū)別是將原圖和后繪制圖形進(jìn)行交換
  • soft-light: 類似于hard-light,但比hard-light柔和
  • difference: 使用后繪制圖形的像素值減去原圖的像素值
  • exclusion: difference操作后降低對比度
  • hue: 使用后繪制圖形的色調(diào)和原圖的亮度、色度
  • saturation: 使用后繪制圖形的色度和原圖的亮度、色調(diào)
  • color: 使用后繪制圖形的色度、色調(diào)和原圖的亮度
  • luminosity:使用后繪制圖形的亮度和原圖的色度、色調(diào)

示例:

<body>
    <canvas id='c2d'>瀏覽器不支持canvas</canvas>
    <script>
        const canvas = document.getElementById('c2d');
        if (canvas.getContext) {
            let ctx = canvas.getContext('2d');

            ctx.fillStyle = 'red';
            ctx.fillRect(30,60,60,40);

            ctx.globalCompositeOperation = 'destination-over';

            ctx.fillStyle = 'blue';
            ctx.fillRect(70,40,60,40);
        }
    </script>
</body>
運(yùn)行結(jié)果
剪切

剪切的作用其實(shí)是指定新的繪圖區(qū)域,如果將圖像繪制到剪切區(qū)域外面就顯示不出來了,但是剪切操作不會(huì)影響剪切之前的圖形。剪切使用的是clip方法,如下:

  • clip([fillRule="nonzero"])
  • clip(path[,fillRule="nonzero"])
    fillRule:用來指定用你什么算法來判斷一個(gè)點(diǎn)是否在被剪切的區(qū)域內(nèi),可取“nonzero”或“evenodd”
    當(dāng)路徑是使用beginPath創(chuàng)建時(shí),使用第一種方式直接調(diào)用clip,當(dāng)路徑是使用Path2D創(chuàng)建時(shí),需要使用第二種方式將創(chuàng)建的路徑作為參數(shù)傳入。
    示例:
<body>
    <canvas id='c2d'>瀏覽器不支持canvas</canvas>
    <script>
        const canvas = document.getElementById('c2d');
        if (canvas.getContext) {
            let ctx = canvas.getContext('2d');

            ctx.fillRect(110,15,30,45);

            ctx.beginPath();
            ctx.arc(60,60,45,0,2*Math.PI);
            ctx.stroke();

            ctx.clip();
            ctx.fillRect(0,0,60,60);
        }
    </script>
</body>
運(yùn)行結(jié)果

首先畫一個(gè)以(110,15)為左上頂點(diǎn),寬為30、高為45的矩形,接著剪切了一個(gè)(60,60)為圓形、45為半徑的圓,然后又畫了一個(gè)以(0,0)為左上角,寬和高都是60的矩形。這時(shí)第一個(gè)矩形可以正常顯示,但是第二個(gè)矩形只有剪切區(qū)域中的部分(也就是和剪切區(qū)域相交的部分)才可以顯示出來。

坐標(biāo)檢測

坐標(biāo)檢測就是檢測指定的點(diǎn)是否在所畫的路徑中,可以用于動(dòng)畫和游戲的碰撞檢測中。坐標(biāo)檢測使用的是isPointInPath方法,方法如下:

  • isPointInPath(x,y[,fillRule="nonzero"])
  • isPointInPath(path,x,y[,fillRule="nonzero"])
    參數(shù)中,fillRule也用于指定算法,一般不需要修改;x和y為要檢測點(diǎn)的坐標(biāo);path為使用Path2D新建出來的路徑,如果是beginPath新建的路徑,就可以直接調(diào)用。
    示例:
<body>
    <canvas id='c2d'>瀏覽器不支持canvas</canvas>
    <div></div>
    <script>
        const canvas = document.getElementById('c2d');
        if (canvas.getContext) {
            let ctx = canvas.getContext('2d');

            const newPath = new Path2D();
            newPath.rect(30,30,40,60);

            const div = document.querySelector('div');
            const spanValue =  `<span>30,40 is in Path: ${ctx.isPointInPath(newPath,30,40)}</span>`;
            const spanValue1 =  `<span>20,40 is in Path: ${ctx.isPointInPath(newPath,20,40)}</span>`;
            div.innerHTML = spanValue + '<br>' + spanValue1;
        }
    </script>
</body>
運(yùn)行結(jié)果

顏色和樣式是通過strokeStyle和fillStyle兩個(gè)屬性修改的,它們的默認(rèn)值都是black,strokeStyle表示畫線(描邊)用的樣式,fillStyle表示填充用的樣式,它們可以被賦予三種類型的值:純色、漸變和模式。

純色

純色有以下三種賦值方法:

  • 直接賦予顏色值,包括賦予十六進(jìn)制和顏色的單詞,例如#323232、red等
  • 使用rgb函數(shù)賦值,rgb函數(shù)有三個(gè)十進(jìn)制(0~255)的參數(shù),分別表示紅、綠、藍(lán)的值
  • 使用rgba函數(shù)賦值,rgba函數(shù)在rgb函數(shù)的基礎(chǔ)上添加了透明度(alpha),它用第四個(gè)參數(shù)表示透明度。透明度的取值范圍為【0,1】,其中,0表示完全透明,1表示完全不透明。
    示例:
<body>
    <canvas id='c2d'>瀏覽器不支持canvas</canvas>
    <script>
        const canvas = document.getElementById('c2d');
        if (canvas.getContext) {
            let ctx = canvas.getContext('2d');

            ctx.fillStyle = "blue";
            ctx.beginPath();
            ctx.rect(0,0,20,20);
            ctx.fill();

            ctx.fillStyle = "rgb(249,27,27)";
            ctx.beginPath();
            ctx.rect(20,20,20,20);
            ctx.fill();

            ctx.fillStyle = "rgb(249,27,27, 0.5)";
            ctx.beginPath();
            ctx.rect(40,40,20,20);
            ctx.fill(); 
        }
    </script>
</body>

漸變

漸變的顏色是通過CanvasGradient對象來表示的,它可以使用下面兩個(gè)方法來創(chuàng)建:

  • createLinearGradient(x0,y0,x1,y1): 創(chuàng)建線性漸變
  • createRadialGradient(x0,y0,x1,y1,r1): 創(chuàng)建徑向漸變,也就是散漸變
    CanvasGradient對象包含一個(gè)addColorStop方法,用來添加漸變的顏色控制點(diǎn),語法如下:
addColorStop(offset,color)

offset用于設(shè)置控制點(diǎn),取值范圍【0,1】;color用于設(shè)置控制點(diǎn)的顏色。
示例:

<body>
    <canvas id='c2d'>瀏覽器不支持canvas</canvas>
    <script>
        const canvas = document.getElementById('c2d');
        if (canvas.getContext) {
            let ctx = canvas.getContext('2d');

            let lineGradient = ctx.createLinearGradient(20,20,100,150); 
            lineGradient.addColorStop(0, 'red');           
            lineGradient.addColorStop(0.5, 'rgba(255,255,0,0.7)');           
            lineGradient.addColorStop(1, '#ff6d00');
            ctx.fillStyle = lineGradient;

            ctx.beginPath();
            ctx.arc(50,50,30,0,2*Math.PI);
            ctx.fill();   

            let radiaGradient = ctx.createRadialGradient(130,50,10,130,50,30);
            radiaGradient.addColorStop(0,'rgba(255,204,205,0.3)');      
            radiaGradient.addColorStop(0.5,'#ffff00');      
            radiaGradient.addColorStop(1,'#ff6d00'); 
            ctx.fillStyle = radiaGradient;
            ctx.fillRect(100,20,60,60);     
        }
    </script>
</body>

模式

模式使用CanvasPattern對象來表示的,它使用createPattern方法來創(chuàng)建,語法如下:

 createPattern(image,repetition);

參數(shù)中,image為CanvasImageSource類型,它可以是html中的img節(jié)點(diǎn)、video節(jié)點(diǎn)、canvas節(jié)點(diǎn)或者CanvasRenderingContext2D對象。repetion為重復(fù)方式,它可以取下面4個(gè)值:

  • repeat: 水平和豎直兩個(gè)方向重復(fù)
  • repeat-x: 水平重復(fù)
  • repeat-y: 豎直重復(fù)
  • no-repeat: 不重復(fù)

模式的用法就好像使用圖片作為畫筆繪圖,其中repetition屬性跟css中的background-repeat屬性類似。
示例:

<body>
    <canvas id='c2d'>瀏覽器不支持canvas</canvas>
    <script>
        const canvas = document.getElementById('c2d');
        if (canvas.getContext) {
            let ctx = canvas.getContext('2d');

            var img = new Image();
            img.src = 'https://mdn.mozillademos.org/files/222/Canvas_createpattern.png';
            img.onload = function () {
                var pattern = ctx.createPattern(img, 'repeat');
                ctx.fillStyle = pattern;
                ctx.fillRect(0, 0, 400, 400);
            };
        }
    </script>
</body>

插入文本

在繪圖的過程中經(jīng)常需要插入一些文本內(nèi)容,在CanvasRenderingContext2D中可以使用下面的方法來插入:

  • fillText(text,x,y[,maxWidth]):實(shí)心文本
  • strokeText(text,x,y[,maxWidth]):空心wenb
    相關(guān)屬性:
  • font: 字體
  • textAlign:排列方式,可選值[start, end, left, right, center]
  • direction: 文本方向
  • textBaseline: 文本的基線,漢字用不到,值為top,hanging,middle,alphabetic,ideographic,bottom.

實(shí)例:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <canvas id="c2d">瀏覽器不支持canvas</canvas>
    <script>
        const canvas = document.querySelector('#c2d');
        if(canvas.getContext) {
            const ctx = canvas.getContext('2d');
            
            ctx.font='28px 行楷';
            ctx.fillText('愛我中華', 10, 50);

            ctx.font = '38px 宋體';
            ctx.strokeText('中國加油', 10, 100);
        }
    </script>
</body>
</html>
運(yùn)行結(jié)果

插入圖片

在CanvasRenderingContext2D中可以插入圖片,使用drawImage方法,有以下三種調(diào)用方式:

  • drawImage(image, x, y)
    指定圖片繪制位置的左上角
  • drawImage(image,x,y,width,height)
    指定繪制后的寬和高,這個(gè)方法可能會(huì)產(chǎn)生變形
  • drawImage(image,sx,sy,sWidth,sHeight,dx,dy,dWidth,dHeight)
    可以截取原圖的一部分繪制到當(dāng)前canvas中,并且可以進(jìn)行縮放,它的后8個(gè)參數(shù)中的前4個(gè)表示在原圖中要截取得位置,sx,sy為截取的左上角的位置,sWidth和sHeight為截取的寬度和高度,后4個(gè)參數(shù)表示在當(dāng)前canvas中繪制的位置,dx,dy為繪制的左上角,dWidth和dHeight為繪制的寬度和高度。

參數(shù)中,image為CanvasImageSource類型,可以是html中的img節(jié)點(diǎn)、video節(jié)點(diǎn)、canvas節(jié)點(diǎn)或者Canvas'RenderingContext2D對象。

實(shí)例:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <canvas id="c2d" width="800" height="800">瀏覽器不支持canvas</canvas>
    <img id="pic" src="./img/Pic2.png" hidden="true">
    <script>
        window.onload = function () {
            const canvas = document.querySelector('#c2d');
            if (canvas.getContext) {
                const ctx = canvas.getContext('2d');
                const pic = document.getElementById('pic');

                ctx.drawImage(pic, 0, 0, 100, 100);
                ctx.drawImage(pic, 50, 50, 100, 100);
                ctx.drawImage(pic, 100, 100, 100, 100);
            }
        }
    </script>
</body>

</html>
運(yùn)行結(jié)果

環(huán)境的保存和恢復(fù)

在繪圖的過程中經(jīng)常需要對環(huán)境進(jìn)行設(shè)置,例如填充樣式、描邊,在操作完之后,往往需要恢復(fù)到原來的環(huán)境,CanvasRenderingContext2D中可以使用save和restore方法快速操作。
環(huán)境的保存和恢復(fù)還可以進(jìn)行多層嵌套。多次使用save方法可以創(chuàng)建多個(gè)保存點(diǎn),每次調(diào)用restore方法都會(huì)按save相反的順序獲取所保存的環(huán)境。
實(shí)例:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <canvas id="c2d" width="600" height="600">瀏覽器不支持canvas</canvas>
    <script>
        const canvas = document.querySelector('#c2d');
        if(canvas.getContext) {
            const ctx = canvas.getContext('2d');
            ctx.save();

            ctx.fillStyle = 'red';
            ctx.fillRect(0,0,100,100);

            ctx.restore();
            ctx.fillRect(100,100,100,100);
        }
    </script>
</body>
</html>
運(yùn)行結(jié)果

移動(dòng)坐標(biāo)原點(diǎn)

方法:translate(x,y):x,y代表移動(dòng)后x,y坐標(biāo)

旋轉(zhuǎn)坐標(biāo)系

方法:rotate(angle), 旋轉(zhuǎn)角度,整數(shù)為逆時(shí)針,負(fù)數(shù)為順時(shí)針。

實(shí)例

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <canvas id="c2d" width="500" height="500">不支持canvas</canvas>
    <script>
        const canvas = document.querySelector('#c2d');
        if(canvas.getContext) {
            const ctx = canvas.getContext('2d');
            ctx.fillRect(0,0,10,30);

            ctx.translate(10,30);
            ctx.fillRect(0,0,10,30);

            ctx.translate(10,30);
            ctx.rotate(-Math.PI * 1/2);
            ctx.fillStyle='red';
            ctx.fillRect(0,0,10,30);
        }
    </script>
</body>
</html>
運(yùn)行結(jié)果

縮放

方法: scale(x, y)
坐標(biāo)系除了可以移動(dòng)和旋轉(zhuǎn)外還可以進(jìn)行縮放,縮放使用的是scale方法,它有兩個(gè)參數(shù),分別標(biāo)識(shí)橫軸和縱軸縮放的比例, 1為原始大小,大于1為放大,小于1為縮小。
示例:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <canvas id="c2d" height="600" width="600">瀏覽器不支持canvas</canvas>
    <script>
        const canvas = document.querySelector('#c2d');
        if(canvas.getContext) {
            const ctx = canvas.getContext('2d');
            
            ctx.fillText('愛我中華', 10, 50);

            ctx.scale(2,2);

            ctx.translate(50,50);

            ctx.fillText('愛我中華', 10, 50);
        }
    </script>
</body>
</html>

同樣是填充一個(gè)文本,由于第二次填充文字時(shí),x軸和y軸都同比增加了2倍,所以文字的大小也相應(yīng)的增加。

陰影

屬性值:

  • shadowOffsetX: 陰影的水平偏移距離
  • shadowOffsetY: 陰影的豎直偏移距離
  • shadowBlur: 陰影的模糊效果,數(shù)字越大越模糊
  • shadowColor: 陰影顏色

示例:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <canvas id="c2d">瀏覽器不支持canvas</canvas>
    <script>
        const canvas = document.querySelector('#c2d');
        if(canvas.getContext) {
            const ctx = canvas.getContext('2d');
            
            // 設(shè)置陰影效果
            ctx.shadowOffsetX = -7;
            ctx.shadowOffsetY = 5;
            ctx.shadowBlur = 3;
            ctx.shadowColor = 'rgba(255,255,0,0.7)';
            
            ctx.fillStyle = 'red';
            ctx.fillRect(15,30,130,40);
        }
    </script>

</body>
</html>
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容