整合營銷服務商

          電腦端+手機端+微信端=數據同步管理

          免費咨詢熱線:

          HTML 5 Canvas基礎學習教程(2)

          5色彩 Colors

          fillStyle = color 設置圖形的填充顏色。

          strokeStyle = color設 置圖形輪廓的顏色。

          默認都是黑色的顏色和邊框

          // 這些 fillStyle 的值均為 '橙色'

          ctx.fillStyle ="orange";

          ctx.fillStyle ="#FFA500";

          ctx.fillStyle ="rgb(255,165,0)";

          ctx.fillStyle ="rgba(255,165,0,1)";

          通過for循環,利用i、j的漸變繪制漸變色

          例子:functiondraw(){

          var ctx = document.getElementById('canvas').getContext('2d');

          for(var i=0;i<6;i++){

          for(var j=0;j<6;j++){

          ctx.fillStyle ='rgb('+ Math.floor(255-42.5*i)+','+

          Math.floor(255-42.5*j)+',0)';

          ctx.fillRect(j*25,i*25,25,25);

          }

          }}

          效果:



          例:functiondraw(){

          var ctx = document.getElementById('canvas').getContext('2d');

          for(var i=0;i<6;i++){

          for(var j=0;j<6;j++){

          ctx.strokeStyle ='rgb(0,'+ Math.floor(255-42.5*i)+','+

          Math.floor(255-42.5*j)+')';

          ctx.beginPath();

          ctx.arc(12.5+j*25,12.5+i*25,10,0,Math.PI*2,true);

          ctx.stroke();

          }

          }

          }



          透明度 Transparency

          // 指定透明顏色,用于描邊和填充樣式

          ctx.strokeStyle ="rgba(255,0,0,0.5)";

          ctx.fillStyle ="rgba(255,0,0,0.5)";

          (6)線條樣式

          lineWidth = value設置線條寬度。

          lineCap = type設置線條末端樣式。(butt默認,round圓角 和 square多出一個方塊效果)

          lineJoin = type設定線條與線條間接合處的樣式。(round圓角,bevel角被磨平 和 miter直角。默認是 miter)

          miterLimit = value限制當兩條線相交時交接處最大長度;所謂交接處長度(斜接長度)是指線條交接處內角頂點到外角頂點的長度。

          例子:通過設置線條寬帶漸增畫圖

          functiondraw(){

          var ctx = document.getElementById('canvas').getContext('2d');

          for(var i =0; i <10; i++){

          ctx.lineWidth =1+i;

          ctx.beginPath();

          ctx.moveTo(5+i*14,5);

          ctx.lineTo(5+i*14,140);

          ctx.stroke();

          }}

          效果:



          7漸變 Gradients

          createLinearGradient(x1, y1, x2, y2) createLinearGradient 方法接受 4 個參數,表示漸變的起點 (x1,y1) 與終點 (x2,y2)。

          createRadialGradient(x1, y1, r1, x2, y2, r2) createRadialGradient 方法接受 6 個參數,前三個定義一個以 (x1,y1) 為原點,半徑為 r1 的圓,后三個參數則定義另一個以 (x2,y2) 為原點,半徑為 r2 的圓。

          var lineargradient = ctx.createLinearGradient(0,0,150,150);var radialgradient = ctx.createRadialGradient(75,75,0,75,75,100);

          創建出 canvasGradient 對象后,我們就可以用 addColorStop 方法給它上色了。

          gradient.addColorStop(position, color)

          addColorStop 方法接受 2 個參數,position 參數必須是一個 0.0 與 1.0 之間的數值,表示漸變中顏色所在的相對位置。例如,0.5 表示顏色會出現在正中間。color 參數必須是一個有效的 CSS 顏色值(如 #FFF, rgba(0,0,0,1),等等)。

          你可以根據需要添加任意多個色標(color stops)。下面是最簡單的線性黑白漸變的例子。

          var lineargradient = ctx.createLinearGradient(0,0,150,150);

          lineargradient.addColorStop(0,'white');

          lineargradient.addColorStop(1,'black');

          8圖案樣式 Patterns

          createPattern(image, type)該方法接受兩個參數。Image 可以是一個 Image 對象的引用,或者另一個 canvas 對象。Type 必須是下面的字符串值之一:repeat,repeat-x,repeat-y 和 no-repeat。

          寫法:

          var img =newImage();

          img.src ='someimage.png';var ptrn = ctx.createPattern(img,'repeat');

          案例:

          functiondraw(){

          var ctx = document.getElementById('canvas').getContext('2d');

          // 創建新 image 對象,用作圖案

          var img =newImage();

          img.src ='images/wallpaper.png';

          img.onload =function(){

          // 創建圖案

          var ptrn = ctx.createPattern(img,'repeat');

          ctx.fillStyle = ptrn;

          ctx.fillRect(0,0,150,150);

          }}

          9陰影 Shadows

          shadowOffsetX = float

          shadowOffsetX和shadowOffsetY用來設定陰影在 X 和 Y 軸的延伸距離,它們是不受變換矩陣所影響的。負值表示陰影會往上或左延伸,正值則表示會往下或右延伸,它們默認都為 0。

          shadowOffsetY = float

          shadowOffsetX和 shadowOffsetY用來設定陰影在 X 和 Y 軸的延伸距離,它們是不受變換矩陣所影響的。負值表示陰影會往上或左延伸,正值則表示會往下或右延伸,它們默認都為 0。

          shadowBlur = float

          shadowBlur 用于設定陰影的模糊程度,其數值并不跟像素數量掛鉤,也不受變換矩陣的影響,默認為 0。

          shadowColor = color

          shadowColor 是標準的 CSS 顏色值,用于設定陰影顏色效果,默認是全透明的黑色。

          例:文字陰影的例子

          functiondraw(){

          var ctx = document.getElementById('canvas').getContext('2d');

          ctx.shadowOffsetX =2;

          ctx.shadowOffsetY =2;

          ctx.shadowBlur =2;

          ctx.shadowColor ="rgba(0, 0, 0, 0.5)";

          ctx.font ="20px Times New Roman";

          ctx.fillStyle ="Black";

          ctx.fillText("Sample String",5,30);

          未完待續...

          文簡介

          點贊 + 關注 + 收藏 = 學會了

          在前端領域,如果只是懂 Vue 或者 React ,未來在職場的競爭力可能會比較弱。

          根據我多年在家待業經驗來看,前端未來在 數據可視化AI 這兩個領域會比較香,而 Canvas 是數據可視化在前端方面的基礎技術。

          本文就用光的速度將 canvas 給入門了。

          01.gif

          要入門一個技術,前期最重要是快!所以本文只講入門內容,能應付簡單項目。深入的知識點會在其他文章講解。

          文章同時收錄于小程序-互聯網小兵,不止于前端,收各平臺優質熱門的技術文章(后端、移動端、算法、人工智能...),大家支持支持,點擊前往體驗!

          Canvas 是什么?

          • Canvas 中文名叫 “畫布”,是 HTML5 新增的一個標簽。
          • Canvas 允許開發者通過 JS在這個標簽上繪制各種圖案。
          • Canvas 擁有多種繪制路徑、矩形、圓形、字符以及圖片的方法。
          • Canvas 在某些情況下可以 “代替” 圖片。
          • Canvas 可用于動畫、游戲、數據可視化、圖片編輯器、實時視頻處理等領域。

          Canvas 和 SVG 的區別

          CanvasSVG用JS動態生成元素(一個HTML元素)用XML描述元素(類似HTML元素那樣,可用多個元素來描述一個圖形)位圖(受屏幕分辨率影響)矢量圖(不受屏幕分辨率影響)不支持事件支持事件數據發生變化需要重繪不需要重繪

          就上面的描述而言可能有點難懂,你可以打開 AntV 旗下的圖形編輯引擎做對比。G6[1] 是使用 canvas 開發的,X6[2] 是使用 svg 開發的。

          我的建議是:如果要展示的數據量比較大,比如一條數據就是一個元素節點,那使用 canvas 會比較合適;如果用戶操作的交互比較多,而且對清晰度有要求(矢量圖),那么使用 svg 會比較合適。

          起步

          學習前端一定要動手敲代碼,然后看效果展示。

          起步階段會用幾句代碼說明 canvas 如何使用,本例會畫一條直線。

          畫條直線

          1. HTML 中創建 canvas 元素
          2. 通過 js 獲取 canvas 標簽
          3. canvas 標簽中獲取到繪圖工具
          4. 通過繪圖工具,在 canvas 標簽上繪制圖形

          02.png

          <!-- 1、創建 canvas 元素 -->
          <canvas
            id="c"
            width="300"
            height="200"
            style="border: 1px solid #ccc;"
          ></canvas>
          
          <script>
            // 2、獲取 canvas 對象
            const cnv = document.getElementById('c')
          
            // 3、獲取 canvas 上下文環境對象
            const cxt = cnv.getContext('2d')
          
            // 4、繪制圖形
            cxt.moveTo(100, 100) // 起點坐標 (x, y)
            cxt.lineTo(200, 100) // 終點坐標 (x, y)
            cxt.stroke() // 將起點和終點連接起來
          </script>
          復制代碼
          

          moveTolineTostroke 方法暫時可以不用管,它們的作用是繪制圖形,這些方法在后面會講到~

          注意點

          1、默認寬高

          canvas默認的 寬度(300px) 和 高度(150px)

          如果不在 canvas 上設置寬高,那 canvas 元素的默認寬度是300px,默認高度是150px。

          2、設置 canvas 寬高

          canvas 元素提供了 widthheight 兩個屬性,可設置它的寬高。

          需要注意的是,這兩個屬性只需傳入數值,不需要傳入單位(比如 px 等)。

          <canvas width="600" height="400"></canvas>
          復制代碼
          

          3、不能通過 CSS 設置畫布的寬高

          使用 css 設置 canvas 的寬高,會出現 內容被拉伸 的后果!!!

          03.png

          <style>
            #c {
              width: 400px;
              height: 400px;
              border: 1px solid #ccc;
            }
          </style>
          
          <canvas id="c"></canvas>
          
          <script>
            // 1、獲取canvas對象
            const cnv = document.getElementById('c')
          
            // 2、獲取canvas上下文環境對象
            const cxt = cnv.getContext('2d')
          
            // 3、繪制圖形
            cxt.moveTo(100, 100) // 起點
            cxt.lineTo(200, 100) // 終點
            cxt.stroke() // 將起點和終點連接起來
          
            console.log(cnv.width) // 獲取 canvas 的寬度,輸出:300
            console.log(cnv.height) // 獲取 canvas 的高度,輸出:150
          </script>
          復制代碼
          

          canvas 的默認寬度是300px,默認高度是150px。

          1. 如果使用 css 修改 canvas 的寬高(比如本例變成 400px * 400px),那寬度就由 300px 拉伸到 400px,高度由 150px 拉伸到 400px。
          2. 使用 js 獲取 canvas 的寬高,此時返回的是 canvas 的默認值。

          最后出現的效果如上圖所示。

          4、線條默認寬度和顏色

          線條的默認寬度是 1px ,默認顏色是黑色。

          但由于默認情況下 canvas 會將線條的中心點和像素的底部對齊,所以會導致顯示效果是 2px 和非純黑色問題。

          5、IE兼容性高

          暫時只有 IE 9 以上才支持 canvas 。但好消息是 IE 已經有自己的墓碑了。

          如需兼容 IE 7 和 8 ,可以使用 ExplorerCanvas [3]。但即使是使用了 ExplorerCanvas 仍然會有所限制,比如無法使用 fillText() 方法等。

          基礎圖形

          坐標系

          在繪制基礎圖形之前,需要先搞清除 Canvas 使用的坐標系。

          Canvas 使用的是 W3C 坐標系 ,也就是遵循我們屏幕、報紙的閱讀習慣,從上往下,從左往右。

          04.jpg

          W3C 坐標系數學直角坐標系X軸 是一樣的,只是 Y軸 的反向相反。

          W3C 坐標系Y軸 正方向向下。

          直線

          一條直線

          最簡單的起步方式是畫一條直線。這里所說的 “直線” 是幾何學里的 “線段” 的意思。

          需要用到這3個方法:

          1. moveTo(x1, y1):起點坐標 (x, y)
          2. lineTo(x2, y2):下一個點的坐標 (x, y)
          3. stroke():將所有坐標用一條線連起來

          起步階段可以先這樣理解。

          05.png

          <canvas id="c" style="border: 1px solid #ccc;"></canvas>
          
          <script>
            const cnv = document.getElementById('c')
            const cxt = cnv.getContext('2d')
          
            // 繪制直線
            cxt.moveTo(50, 100) // 起點坐標
            cxt.lineTo(200, 50) // 下一個點的坐標
            cxt.stroke() // 將上面的坐標用一條線連接起來
          </script>
          復制代碼
          

          上面的代碼所呈現的效果,可以看下圖解釋(手不太聰明,畫得不是很標準,希望能看懂)

          06.jpg

          多條直線

          如需畫多條直線,可以用會上面那幾個方法。

          07.png

          <canvas id="c" width="300" height="300" style="border: 1px solid #ccc;"></canvas>
          
          <script>
            const cnv = document.getElementById('c')
            const cxt = cnv.getContext('2d')
          
            cxt.moveTo(20, 100)
            cxt.lineTo(200, 100)
            cxt.stroke()
          
            cxt.moveTo(20, 120.5)
            cxt.lineTo(200, 120.5)
            cxt.stroke()
          </script>
          復制代碼
          

          仔細觀察一下,為什么兩條線的粗細不一樣的?

          明明使用的方法都是一樣的,只是第二條直線的 Y軸 的值是有小數點。

          答:默認情況下 canvas 會將線條的中心點和像素的底部對齊,所以會導致顯示效果是 2px 和非純黑色問題。

          08.jpg

          上圖每個格子代表 1px

          線的中心點會和畫布像素點的底部對齊,所以會線中間是黑色的,但由于一個像素就不能再切割了,所以會有半個像素被染色,就變成了淺灰色。

          所以如果你設置的 Y軸 值是一個整數,就會出現上面那種情況。

          設置樣式

          • lineWidth:線的粗細
          • strokeStyle:線的顏色
          • lineCap:線帽:默認: butt; 圓形: round; 方形: square

          09.png

          <canvas id="c" style="border: 1px solid #ccc;"></canvas>
          
          <script>
            const cnv = document.getElementById('c')
            const cxt = cnv.getContext('2d')
          
            // 繪制直線
            cxt.moveTo(50, 50)
            cxt.lineTo(200, 50)
          
            // 修改直線的寬度
            cxt.lineWidth = 20
          
            // 修改直線的顏色
            cxt.strokeStyle = 'pink'
          
            // 修改直線兩端樣式
            cxt.lineCap = 'round' // 默認: butt; 圓形: round; 方形: square
          
            cxt.stroke()
          </script>
          復制代碼
          

          新開路徑

          開辟新路徑的方法:

          • beginPath()

          在繪制多條線段的同時,還要設置線段樣式,通常需要開辟新路徑。

          要不然樣式之間會相互污染。

          比如這樣

          10.png

          <canvas id="c" width="300" height="300" style="border: 1px solid #ccc;"></canvas>
          
          <script>
            const cnv = document.getElementById('c')
            const cxt = cnv.getContext('2d')
          
            // 第一條線
            cxt.moveTo(20, 100)
            cxt.lineTo(200, 100)
            cxt.lineWidth = 10
            cxt.strokeStyle = 'pink'
            cxt.stroke()
          
            // 第二條線
            cxt.moveTo(20, 120.5)
            cxt.lineTo(200, 120.5)
            cxt.stroke()
          </script>
          復制代碼
          

          如果不想相互污染,需要做2件事:

          1. 使用 beginPath() 方法,重新開一個路徑
          2. 設置新線段的樣式(必須項)

          如果上面2步卻了其中1步都會有影響。

          只使用beginPath()

          11.png

          <canvas id="c" width="300" height="300" style="border: 1px solid #ccc;"></canvas>
          
          <script>
            const cnv = document.getElementById('c')
            const cxt = cnv.getContext('2d')
          
            // 第一條線
            cxt.moveTo(20, 100)
            cxt.lineTo(200, 100)
            cxt.lineWidth = 10
            cxt.strokeStyle = 'pink'
            cxt.stroke()
          
            // 第二條線
            cxt.beginPath() // 重新開啟一個路徑
            cxt.moveTo(20, 120.5)
            cxt.lineTo(200, 120.5)
            cxt.stroke()
          </script>
          復制代碼
          

          第一條線的樣式會影響之后的線。

          但如果使用了 beginPath() ,后面的線段不會影響前面的線段。

          12.png

          <canvas id="c" width="300" height="300" style="border: 1px solid #ccc;"></canvas>
          
          <script>
            const cnv = document.getElementById('c')
            const cxt = cnv.getContext('2d')
          
            // 第一條線
            cxt.moveTo(20, 100)
            cxt.lineTo(200, 100)
            cxt.stroke()
          
            // 第二條線
            cxt.beginPath() // 重新開啟一個路徑
            cxt.moveTo(20, 120.5)
            cxt.lineTo(200, 120.5)
            cxt.lineWidth = 4
            cxt.strokeStyle = 'red'
            cxt.stroke()
          </script>
          復制代碼
          

          設置新線段的樣式,沒使用beginPath()的情況

          這個情況會反過來,后面的線能影響前面的線。

          13.png

          <canvas id="c" width="300" height="300" style="border: 1px solid #ccc;"></canvas>
          
          <script>
            const cnv = document.getElementById('c')
            const cxt = cnv.getContext('2d')
          
            // 第一條線
            cxt.moveTo(20, 100)
            cxt.lineTo(200, 100)
            cxt.lineWidth = 10
            cxt.strokeStyle = 'pink'
            cxt.stroke()
          
            // 第二條線
            cxt.moveTo(20, 120.5)
            cxt.lineTo(200, 120.5)
            cxt.lineWidth = 4
            cxt.strokeStyle = 'red'
            cxt.stroke()
          </script>
          復制代碼
          

          正確的做法

          在設置 beginPath() 的同時,也各自設置樣式。這樣就能做到相互不影響了。

          14.png

          <canvas id="c" width="300" height="300" style="border: 1px solid #ccc;"></canvas>
          
          <script>
            const cnv = document.getElementById('c')
            const cxt = cnv.getContext('2d')
          
            cxt.moveTo(20, 100)
            cxt.lineTo(200, 100)
            cxt.lineWidth = 10
            cxt.strokeStyle = 'pink'
            cxt.stroke()
          
            cxt.beginPath() // 重新開啟一個路徑
            cxt.moveTo(20, 120.5)
            cxt.lineTo(200, 120.5)
            cxt.lineWidth = 4
            cxt.strokeStyle = 'red'
            cxt.stroke()
          </script>
          復制代碼
          

          折線

          直線 差不多,都是使用 moveTo()lineTo()stroke() 方法可以繪制折線。

          15.png

          <canvas id="c" width="300" height="300" style="border: 1px solid #ccc;"></canvas>
          
          <script>
            const cnv = document.getElementById('c')
            const cxt = cnv.getContext('2d')
          
            cxt.moveTo(50, 200)
            cxt.lineTo(100, 50)
            cxt.lineTo(200, 200)
            cxt.lineTo(250, 50)
          
            cxt.stroke()
          </script>
          復制代碼
          

          畫這種折線,最好在草稿紙上畫一個坐標系,自己計算并描繪一下每個點大概在什么什么位置,最后在 canvas 中看看效果。

          矩形

          根據前面的基礎,我們可以 使用線段來描繪矩形,但 canvas 也提供了 rect() 等方法可以直接生成矩形。

          使用線段描繪矩形

          可以使用前面畫線段的方法來繪制矩形

          16.png

          canvas id="c" width="300" height="300" style="border: 1px solid #ccc;"></canvas>
          
          <script>
           const cnv = document.getElementById('c')
           const cxt = cnv.getContext('2d')
          
           // 繪制矩形
           cxt.moveTo(50, 50)
           cxt.lineTo(200, 50)
           cxt.lineTo(200, 120)
           cxt.lineTo(50, 120)
           cxt.lineTo(50, 50) // 需要閉合,又或者使用 closePath() 方法進行閉合,推薦使用 closePath()
          
           cxt.stroke()
          </script>
          復制代碼
          

          上面的代碼幾個點分別對應下圖。

          17.jpg

          使用strokeRect()描邊矩形

          • strokeStyle:設置描邊的屬性(顏色、漸變、圖案)
          • strokeRect(x, y, width, height):描邊矩形(x和y是矩形左上角起點;width 和 height 是矩形的寬高)
          • strokeStyle 必須寫在 strokeRect() 前面,不然樣式不生效。

          18.png

          <canvas id="c" width="300" height="300" style="border: 1px solid #ccc;"></canvas>
          
          <script>
            const cnv = document.getElementById('c')
            const cxt = cnv.getContext('2d')
          
            // strokeStyle 屬性
            // strokeRect(x, y, width, height) 方法
            cxt.strokeStyle = 'pink'
            cxt.strokeRect(50, 50, 200, 100)
          </script>
          復制代碼
          

          上面的代碼可以這樣理解

          19.jpg

          使用fillRect()填充矩形

          fillRect()strokeRect() 方法差不多,但 fillRect() 的作用是填充。

          需要注意的是,fillStyle 必須寫在 fillRect() 之前,不然樣式不生效。

          20.png

          <canvas id="c" width="300" height="300" style="border: 1px solid #ccc;"></canvas>
          
          <script>
            const cnv = document.getElementById('c')
            const cxt = cnv.getContext('2d')
          
            // fillStyle 屬性
            // fillRect(x, y, width, height) 方法
            cxt.fillStyle = 'pink'
            cxt.fillRect(50, 50, 200, 100) // fillRect(x, y, width, height)
          </script>
          復制代碼
          

          同時使用strokeRect()和fillRect()

          同時使用 strokeRect()fillRect() 會產生描邊和填充的效果

          21.png

          <canvas id="c" width="300" height="300" style="border: 1px solid #ccc;"></canvas>
          
          <script>
            const cnv = document.getElementById('c')
            const cxt = cnv.getContext('2d')
          
            cxt.strokeStyle = 'red'
            cxt.strokeRect(50, 50, 200, 100) // strokeRect(x, y, width, height)
            cxt.fillStyle = 'yellow'
            cxt.fillRect(50, 50, 200, 100) // fillRect(x, y, width, height)
          </script>
          復制代碼
          

          使用rect()生成矩形

          rect()fillRect() 、strokeRect() 的用法差不多,唯一的區別是:

          strokeRect()fillRect() 這兩個方法調用后會立即繪制;rect() 方法被調用后,不會立刻繪制矩形,而是需要調用 stroke()fill() 輔助渲染。

          22.png

          <canvas id="c" width="300" height="300" style="border: 1px solid #ccc;"></canvas>
          
          <script>
            const cnv = document.getElementById('c')
            const cxt = cnv.getContext('2d')
          
            cxt.strokeStyle = 'red'
            cxt.fillStyle = 'pink'
          
            cxt.rect(50, 50, 200, 100) // rect(x, y, width, height)
          
            cxt.stroke()
            cxt.fill()
          </script>
          復制代碼
          

          等價公式:

          cxt.strokeStyle = 'red',
          cxt.rect(50, 50, 200, 100)
          cxt.stroke()
          
          // 等價于
          cxt.strokeStyle = 'red'
          cxt.strokerect(50, 50, 200, 100)
          
          
          // -----------------------------
          
          
          cxt.fillStyle = 'hotpink'
          cxt.rect(50, 50, 200, 100)
          cxt.fill()
          
          // 等價于
          cxt.fillStyle = 'yellowgreen'
          cxt.fillRect(50, 50, 200, 100)
          復制代碼
          

          使用clearRect()清空矩形

          使用 clearRect() 方法可以清空指定區域。

          clearRect(x, y, width, height)
          復制代碼
          

          其語法和創建 cxt.rect() 差不多。

          23.png

          <canvas id="c" width="300" height="300" style="border: 1px solid #ccc;"></canvas>
          
          <script>
            const cnv = document.getElementById('c')
            const cxt = cnv.getContext('2d')
          
            cxt.fillStyle = 'pink' // 設置填充顏色
            cxt.fillRect(50, 50, 200, 200) // 填充矩形
          
            cxt.clearRect(60, 60, 180, 90) // 清空矩形
          </script>
          復制代碼
          

          清空畫布

          canvas 畫布元素是矩形,所以可以通過下面的代碼把整個畫布清空掉。

          // 省略部分代碼
          
          cxt.clearRect(0, 0, cnv.width, cnv.height)
          復制代碼
          

          要清空的區域:從畫布左上角開始,直到畫布的寬和畫布的高為止。

          \

          多邊形

          Canvas 要畫多邊形,需要使用 moveTo()lineTo()closePath()

          三角形

          雖然三角形是常見圖形,但 canvas 并沒有提供類似 rect() 的方法來繪制三角形。

          需要確定三角形3個點的坐標位置,然后使用 stroke() 或者 fill() 方法生成三角形。

          24.png

          <canvas id="c" width="300" height="300" style="border: 1px solid #ccc;"></canvas>
          
          <script>
          
            const cnv = document.getElementById('c')
            const cxt = cnv.getContext('2d')
          
            cxt.moveTo(50, 50)
            cxt.lineTo(200, 50)
            cxt.lineTo(200, 200)
          
            // 注意點:如果使用 lineTo 閉合圖形,是不能很好閉合拐角位的。
            cxt.lineTo(50, 50) // 閉合
          
            cxt.stroke()
          
          </script>
          復制代碼
          

          注意,默認情況下不會自動從最后一個點連接到起點。最后一步需要設置一下 cxt.lineTo(50, 50) ,讓它與 cxt.moveTo(50, 50) 一樣。這樣可以讓路徑回到起點,形成一個閉合效果。

          但這樣做其實是有點問題的,而且也比較麻煩,要記住起始點坐標。

          上面的閉合操作,如果遇到設置了 lineWidth 或者 lineJoin 就會有問題,比如:

          25.png

          // 省略部分代碼
          cxt.lineWidth = 20
          復制代碼
          

          當線段變粗后,起始點和結束點的鏈接處,拐角就出現“不正常”現象。

          如果需要真正閉合,可以使用 closePath() 方法。

          26.png

          <canvas id="c" width="300" height="300" style="border: 1px solid #ccc;"></canvas>
          
          <script>
            const cnv = document.getElementById('c')
            const cxt = cnv.getContext('2d')
          
            cxt.moveTo(50, 50)
            cxt.lineTo(200, 50)
            cxt.lineTo(200, 200)
            // 手動閉合
            cxt.closePath()
          
            cxt.lineJoin = 'miter' // 線條連接的樣式。miter: 默認; bevel: 斜面; round: 圓角
            cxt.lineWidth = 20
            cxt.stroke()
          </script>
          復制代碼
          

          使用 cxt.closePath() 可以自動將終點和起始點連接起來,此時看上去就正常多了。

          菱形

          有一組鄰邊相等的平行四邊形是菱形

          27.png

          <canvas id="c" width="300" height="300" style="border: 1px solid #ccc;"></canvas>
          
          <script>
            const cnv = document.getElementById('c')
            const cxt = cnv.getContext('2d')
          
            cxt.moveTo(150, 50)
            cxt.lineTo(250, 100)
            cxt.lineTo(150, 150)
            cxt.lineTo(50, 100)
            cxt.closePath()
            cxt.stroke()
          </script>
          復制代碼
          

          要繪制直線類型的圖形,在草稿紙上標記出起始點和每個拐角的點,然后再連線即可。相對曲線圖形來說,直線圖形是比較容易的。

          圓形

          繪制圓形的方法是 arc()

          語法:

          arc(x, y, r, sAngle, eAngle,counterclockwise)
          復制代碼
          
          • xy: 圓心坐標
          • r: 半徑
          • sAngle: 開始角度
          • eAngle: 結束角度
          • counterclockwise: 繪制方向(true: 逆時針; false: 順時針),默認 false

          28.jpg

          開始角度和結束角度,都是以弧度為單位。例如 180°就寫成 Math.PI ,360°寫成 Math.PI * 2 ,以此類推。

          在實際開發中,為了讓自己或者別的開發者更容易看懂弧度的數值,1°應該寫成 Math.PI / 180

          • 100°: 100 * Math.PI / 180
          • 110°: 110 * Math.PI / 180
          • 241°: 241 * Math.PI / 180

          注意:繪制圓形之前,必須先調用 beginPath() 方法!!!在繪制完成之后,還需要調用 closePath() 方法!!!

          29.png

          <canvas id="c" width="300" height="300" style="border: 1px solid #ccc;"></canvas>
          
          <script>
            const cnv = document.getElementById('c')
            const cxt = cnv.getContext('2d')
          
            cxt.beginPath()
            cxt.arc(150, 150, 80, 0, 360 * Math.PI / 180)
            cxt.closePath()
          
            cxt.stroke()
          </script>
          復制代碼
          

          半圓

          如果使用 arc() 方法畫圓時,沒做到剛好繞完一周(360°)就直接閉合路徑,就會出現半圓的狀態。

          30.png

          <canvas id="c" width="300" height="300" style="border: 1px solid #ccc;"></canvas>
          
          <script>
            const cnv = document.getElementById('c')
            const cxt = cnv.getContext('2d')
          
            cxt.beginPath()
            cxt.arc(150, 150, 100, 0, 180 * Math.PI / 180) // 順時針
            cxt.closePath()
          
            cxt.stroke()
          </script>
          復制代碼
          

          上面的代碼中,cxt.arc 最后一個參數沒傳,默認是 false ,所以是順時針繪制。

          31.jpg

          如果希望半圓的弧面在上方,可以將 cxt.arc 最后一個參數設置成 true

          32.png

          <canvas id="c" width="300" height="300" style="border: 1px solid #ccc;"></canvas>
          
          <script>
            const cnv = document.getElementById('c')
            const cxt = cnv.getContext('2d')
          
            cxt.beginPath()
            cxt.arc(150, 150, 100, 0, 180 * Math.PI / 180, true)
            cxt.closePath()
          
            cxt.stroke()
          </script>
          復制代碼
          

          弧線

          使用 arc() 方法畫半圓時,如果最后不調用 closePath() 方法,就不會出現閉合路徑。也就是說,那是一條弧線。

          canvas 中,畫弧線有2中方法:arc()arcTo()

          arc() 畫弧線

          如果想畫一條 0° ~ 30° 的弧線,可以這樣寫

          33.png

          <canvas id="c" width="300" height="300" style="border: 1px solid #ccc;"></canvas>
          
          <script>
            const cnv = document.getElementById('c')
            const cxt = cnv.getContext('2d')
          
            cxt.beginPath()
            cxt.arc(150, 150, 100, 0, 30 * Math.PI / 180)
          
            cxt.stroke()
          </script>
          復制代碼
          

          原理如下圖所示,紅線代表畫出來的那條弧線。

          34.jpg

          arcTo() 畫弧線

          arcTo() 的使用方法會更加復雜,如果初學看不太懂的話可以先跳過,看完后面的再回來補補。

          語法:

          arcTo(cx, cy, x2, y2, radius)
          復制代碼
          
          • cx: 兩切線交點的橫坐標
          • cy: 兩切線交點的縱坐標
          • x2: 結束點的橫坐標
          • y2: 結束點的縱坐標
          • radius: 半徑

          其中,(cx, cy) 也叫控制點,(x2, y2) 也叫結束點。

          是不是有點奇怪,為什么沒有 x1y1

          (x1, y1) 是開始點,通常是由 moveTo() 或者 lineTo() 提供。

          arcTo() 方法利用 開始點、控制點和結束點形成的家教,繪制一段與家教的兩邊相切并且半徑為 radius 的圓弧

          35.jpg

          舉個例子

          36.png

          <canvas id="c" width="300" height="300" style="border: 1px solid #ccc;"></canvas>
          
          <script>
            const cnv = document.getElementById('c')
            const cxt = cnv.getContext('2d')
          
            cxt.moveTo(40, 40)
            cxt.arcTo(120, 40, 120, 80, 80)
          
            cxt.stroke()
          </script>
          復制代碼
          

          基礎樣式

          前面學完基礎圖形,接下來可以開始了解一下如何設置元素的基礎樣式。

          描邊 stroke()

          前面的案例中,其實已經知道使用 stroke() 方法進行描邊了。這里就不再多講這個方法。

          線條寬度 lineWidth

          lineWidth 默認值是 1 ,默認單位是 px

          語法:

          lineWidth = 線寬
          復制代碼
          

          37.png

          <canvas id="c" width="300" height="300" style="border: 1px solid #ccc;"></canvas>
          
          <script>
            const cnv = document.getElementById('c')
            const cxt = cnv.getContext('2d')
          
            // 線寬 10
            cxt.beginPath()
            cxt.moveTo(50, 50)
            cxt.lineTo(250, 50)
            cxt.lineWidth = 10 // 設置線寬
            cxt.stroke()
          
            // 線寬 20
            cxt.beginPath()
            cxt.moveTo(50, 150)
            cxt.lineTo(250, 150)
            cxt.lineWidth = 20 // 設置線寬
            cxt.stroke()
          
            // 線寬 30
            cxt.beginPath()
            cxt.moveTo(50, 250)
            cxt.lineTo(250, 250)
            cxt.lineWidth = 30 // 設置線寬
            cxt.stroke()
          </script>
          復制代碼
          

          線條顏色 strokeStyle

          使用 strokeStyle 可以設置線條顏色

          語法:

          strokeStyle = 顏色值
          復制代碼
          

          38.png

          <canvas id="c" width="300" height="300" style="border: 1px solid #ccc;"></canvas>
          
          <script>
            const cnv = document.getElementById('c')
            const cxt = cnv.getContext('2d')
          
            cxt.moveTo(50, 50)
            cxt.lineTo(250, 50)
            cxt.lineWidth = 20
            cxt.strokeStyle = 'pink' // 設置顏色
            cxt.stroke()
          </script>
          復制代碼
          

          為了展示方便,我將 lineWidth 設為 20。

          線帽 lineCap

          線帽指的是線段的開始和結尾處的樣式,使用 lineCap 可以設置

          語法:

          lineCap = '屬性值'
          復制代碼
          

          屬性值包括:

          • butt: 默認值,無線帽
          • square: 方形線帽
          • round: 圓形線帽

          39.png

          <canvas id="c" width="300" height="300" style="border: 1px solid #ccc;"></canvas>
          
          <script>
            const cnv = document.getElementById('c')
            const cxt = cnv.getContext('2d')
          
            // 設置線寬,方便演示
            cxt.lineWidth = 16
          
            // 默認線帽 butt
            cxt.beginPath()
            cxt.moveTo(50, 60)
            cxt.lineTo(250, 60)
            cxt.stroke()
          
          
            // 方形線帽 square
            cxt.beginPath()
            cxt.lineCap = 'square'
            cxt.moveTo(50, 150)
            cxt.lineTo(250, 150)
            cxt.stroke()
          
          
            // 圓形線帽 round
            cxt.beginPath()
            cxt.lineCap = 'round'
            cxt.moveTo(50, 250)
            cxt.lineTo(250, 250)
            cxt.stroke()
          </script>
          復制代碼
          

          使用 squareround 的話,會使線條變得稍微長一點點,這是給線條增加線帽的部分,這個長度在日常開發中需要注意。

          線帽只對線條的開始和結尾處產生作用,對拐角不會產生任何作用。

          拐角樣式 lineJoin

          如果需要設置拐角樣式,可以使用 lineJoin

          語法:

          lineJoin = '屬性值'
          復制代碼
          

          屬性值包括:

          • miter: 默認值,尖角
          • round: 圓角
          • bevel: 斜角

          40.png

          <canvas id="c" width="300" height="300" style="border: 1px solid #ccc;"></canvas>
          
          <script>
            const cnv = document.getElementById('c')
            const cxt = cnv.getContext('2d')
            
            cxt.lineWidth = 20
          
            // 默認,尖角
            cxt.moveTo(50, 40)
            cxt.lineTo(200, 40)
            cxt.lineTo(200, 90)
            cxt.stroke()
          
            // 斜角 bevel
            cxt.beginPath()
            cxt.moveTo(50, 140)
            cxt.lineTo(200, 140)
            cxt.lineTo(200, 190)
            cxt.lineJoin = 'bevel'
            cxt.stroke()
          
            // 圓角 round
            cxt.beginPath()
            cxt.moveTo(50, 240)
            cxt.lineTo(200, 240)
            cxt.lineTo(200, 290)
            cxt.lineJoin = 'round'
            cxt.stroke()
          </script>
          復制代碼
          

          虛線 setLineDash()

          使用 setLineDash() 方法可以將描邊設置成虛線。

          語法:

          setLineDash([])
          復制代碼
          

          需要傳入一個數組,且元素是數值型。

          虛線分3種情況

          1. 只傳1個值
          2. 有2個值
          3. 有3個以上的值

          41.png

          <canvas id="c" width="300" height="300" style="border: 1px solid #ccc;"></canvas>
          
          <script>
            const cnv = document.getElementById('c')
            const cxt = cnv.getContext('2d')
          
            cxt.lineWidth = 20
            cxt.strokeStyle = 'pink'
          
            cxt.moveTo(50, 50)
            cxt.lineTo(200, 50)
            cxt.setLineDash([10]) // 只傳1個參數,實線與空白都是 10px
            cxt.stroke()
          
          
            cxt.beginPath()
            cxt.moveTo(50, 100)
            cxt.lineTo(200, 100)
            cxt.setLineDash([10, 20]) // 2個參數,此時,實線是 10px, 空白 20px
            cxt.stroke()
          
          
            cxt.beginPath()
            cxt.moveTo(50, 150)
            cxt.lineTo(200, 150)
            cxt.setLineDash([10, 20, 5]) // 傳3個以上的參數,此例:10px實線,20px空白,5px實線,10px空白,20px實線,5px空白 ……
          
            cxt.stroke()
          </script>
          復制代碼
          

          此外,還可以始終 cxt.getLineDash() 獲取虛線不重復的距離;

          cxt.lineDashOffset 設置虛線的偏移位。

          填充

          使用 fill() 可以填充圖形,根據前面的例子應該掌握了如何使用 fill()

          42.png

          <canvas id="c" width="300" height="300" style="border: 1px solid #ccc;"></canvas>
          
          <script>
            const cnv = document.getElementById('c')
            const cxt = cnv.getContext('2d')
          
            cxt.fillStyle = 'pink'
          
            cxt.rect(50, 50, 200, 100)
          
            cxt.fill()
          </script>
          復制代碼
          

          可以使用 fillStyle 設置填充顏色,默認是黑色。

          非零環繞填充

          在使用 fill() 方法填充時,需要注意一個規則:非零環繞填充

          在使用 moveTolineTo 描述圖形時,如果是按順時針繪制,計數器會加1;如果是逆時針,計數器會減1。

          當圖形所處的位置,計數器的結果為0時,它就不會被填充。

          這樣說有點復雜,先看看例子

          43.png

          <canvas id="c" width="300" height="300" style="border: 1px solid #ccc;"></canvas>
          
          <script>
            const cnv = document.getElementById('c')
            const cxt = cnv.getContext('2d')
          
            // 外層矩形
            cxt.moveTo(50, 50)
            cxt.lineTo(250, 50)
            cxt.lineTo(250, 250)
            cxt.lineTo(50, 250)
            cxt.closePath()
          
            // 內層矩形
            cxt.moveTo(200, 100)
            cxt.lineTo(100, 100)
            cxt.lineTo(100, 200)
            cxt.lineTo(200, 200)
            cxt.closePath()
            cxt.fill()
          </script>
          復制代碼
          

          請看看上面的代碼,我畫了2個矩形,它們都沒有用 beginPath() 方法開辟新路徑。

          44.png

          內層矩形是逆時針繪制的,所以內層的值是 -1 ,它又經過外層矩形,而外層矩形是順時針繪制,所以經過外層時值 +1,最終內層的值為 0 ,所以不會被填充。

          文本

          Canvas 提供了一些操作文本的方法。

          為了方便演示,我們先了解一下在 Canvas 中如何給本文設置樣式。

          樣式 font

          CSS 設置 font 差不多,Canvas 也可以通過 font 設置樣式。

          語法:

          cxt.font = 'font-style font-variant font-weight font-size/line-height font-family'
          復制代碼
          

          如果需要設置字號 font-size,需要同事設置 font-family

          cxt.font = '30px 宋體'
          復制代碼
          

          描邊 strokeText()

          使用 strokeText() 方法進行文本描邊

          語法:

          strokeText(text, x, y, maxWidth)
          復制代碼
          
          • text: 字符串,要繪制的內容
          • x: 橫坐標,文本左邊要對齊的坐標(默認左對齊)
          • y: 縱坐標,文本底邊要對齊的坐標
          • maxWidth: 可選參數,表示文本渲染的最大寬度(px),如果文本超出 maxWidth 設置的值,文本會被壓縮。

          45.png

          <canvas id="c" width="300" height="300" style="border: 1px solid #ccc;"></canvas>
          
          <script>
            const cnv = document.getElementById('c')
            const cxt = cnv.getContext('2d')
          
            cxt.font = '60px Arial' // 將字號設置成 60px,方便觀察
            cxt.strokeText('雷猴', 30, 90)
          </script>
          復制代碼
          

          設置描邊顏色 strokeStyle

          使用 strokeStyle 設置描邊顏色。

          46.png

          <canvas id="c" width="300" height="300" style="border: 1px solid #ccc;"></canvas>
          
          <script>
            const cnv = document.getElementById('c')
            const cxt = cnv.getContext('2d')
          
            cxt.font = '60px Arial' // 將字號設置成 60px,方便觀察
            cxt.strokeStyle = 'pink' // 設置文本描邊顏色
            cxt.strokeText('雷猴', 30, 90)
          </script>
          復制代碼
          

          填充 fillText

          使用 fillText() 可填充文本。

          語法和 strokeText() 一樣。

          fillText(text, x, y, maxWidth)
          復制代碼
          

          47.png

          <canvas id="c" width="300" height="300" style="border: 1px solid #ccc;"></canvas>
          
          <script>
            const cnv = document.getElementById('c')
            const cxt = cnv.getContext('2d')
          
            cxt.font = '60px Arial'
            cxt.fillText('雷猴', 30, 90)
          </script>
          復制代碼
          

          設置填充顏色 fillStyle

          使用 fillStyle 可以設置文本填充顏色。

          48.png

          <canvas id="c" width="300" height="300" style="border: 1px solid #ccc;"></canvas>
          
          <script>
            const cnv = document.getElementById('c')
            const cxt = cnv.getContext('2d')
          
            cxt.font = '60px Arial'
            cxt.fillStyle = 'pink'
            cxt.fillText('雷猴', 30, 90)
          </script>
          復制代碼
          

          獲取文本長度 measureText()

          measureText().width 方法可以獲取文本的長度,單位是 px

          <canvas id="c" width="300" height="300" style="border: 1px solid #ccc;"></canvas>
          
          <script>
            const cnv = document.getElementById('c')
            const cxt = cnv.getContext('2d')
          
            let text = '雷猴'
            cxt.font = 'bold 40px Arial'
            cxt.fillText(text, 40, 80)
          
            console.log(cxt.measureText(text).width) // 80
          </script>
          復制代碼
          

          水平對齊方式 textAlign

          使用 textAlign 屬性可以設置文字的水平對齊方式,一共有5個值可選

          • start: 默認。在指定位置的橫坐標開始。
          • end: 在指定坐標的橫坐標結束。
          • left: 左對齊。
          • right: 右對齊。
          • center: 居中對齊。

          49.png

          紅線是輔助參考線。

          <canvas id="c" width="400" height="400" style="border: 1px solid #ccc;"></canvas>
          
          <script>
            const cnv = document.getElementById('c')
            const cxt = cnv.getContext('2d')
          
            // 豎向的輔助線(參考線,在畫布中間)
            cxt.moveTo(200, 0)
            cxt.lineTo(200, 400)
            cxt.strokeStyle = 'red'
            cxt.stroke()
          
            cxt.font = '30px Arial'
          
            // 橫坐標開始位對齊
            cxt.textAlign = 'start' // 默認值,
            cxt.fillText('雷猴 start', 200, 40)
          
            // 橫坐標結束位對齊
            cxt.textAlign = 'end' // 結束對齊
            cxt.fillText('雷猴 end', 200, 100)
          
            // 左對齊
            cxt.textAlign = 'left' // 左對齊
            cxt.fillText('雷猴 left', 200, 160)
          
            // 右對齊
            cxt.textAlign = 'right' // 右對齊
            cxt.fillText('雷猴 right', 200, 220)
          
            // 居中對齊
            cxt.textAlign = 'center' // 右對齊
            cxt.fillText('雷猴 center', 200, 280)
          </script>
          復制代碼
          

          從上面的例子看,startleft 的效果好像是一樣的,endright 也好像是一樣的。

          在大多數情況下,它們的確一樣。但在某些國家或者某些場合,閱讀文字的習慣是 從右往左 時,start 就和 right 一樣了,endleft 也一樣。這是需要注意的地方。

          垂直對齊方式 textBaseline

          使用 textBaseline 屬性可以設置文字的垂直對齊方式。

          在使用 textBaseline 前,需要自行了解 css 的文本基線。

          50.png

          用一張網圖解釋一下基線

          textBaseline 可選屬性:

          • alphabetic: 默認。文本基線是普通的字母基線。
          • top: 文本基線是 em 方框的頂端。
          • bottom: 文本基線是 em 方框的底端。
          • middle: 文本基線是 em 方框的正中。
          • hanging: 文本基線是懸掛基線。

          51.png

          紅線是輔助參考線。

          <canvas id="c" width="800" height="300" style="border: 1px solid #ccc;"></canvas>
          
          <script>
            const cnv = document.getElementById('c')
            const cxt = cnv.getContext('2d')
          
            // 橫向的輔助線(參考線,在畫布中間)
            cxt.moveTo(0, 150)
            cxt.lineTo(800, 150)
            cxt.strokeStyle = 'red'
            cxt.stroke()
          
            cxt.font = '20px Arial'
          
            // 默認 alphabetic
            cxt.textBaseline = 'alphabetic'
            cxt.fillText('雷猴 alphabetic', 10, 150)
          
            // 默認 top
            cxt.textBaseline = 'top'
            cxt.fillText('雷猴 top', 200, 150)
          
            // 默認 bottom
            cxt.textBaseline = 'bottom'
            cxt.fillText('雷猴 bottom', 320, 150)
          
            // 默認 middle
            cxt.textBaseline = 'middle'
            cxt.fillText('雷猴 middle', 480, 150)
          
            // 默認 hanging
            cxt.textBaseline = 'hanging'
            cxt.fillText('雷猴 hanging', 640, 150)
          </script>
          復制代碼
          

          注意:在繪制文字的時候,默認是以文字的左下角作為參考點進行繪制

          圖片

          Canvas 中可以使用 drawImage() 方法繪制圖片。

          渲染圖片

          渲染圖片的方式有2中,一種是在JS里加載圖片再渲染,另一種是把DOM里的圖片拿到 canvas 里渲染

          渲染的語法:

          drawImage(image, dx, dy)
          復制代碼
          
          • image: 要渲染的圖片對象。
          • dx: 圖片左上角的橫坐標位置。
          • dy: 圖片左上角的縱坐標位置。

          JS版

          JS 里加載圖片并渲染,有以下幾個步驟:

          1. 創建 Image 對象
          2. 引入圖片
          3. 等待圖片加載完成
          4. 使用 drawImage() 方法渲染圖片

          52.png

          <canvas id="c" width="500" height="500" style="border: 1px solid #ccc;"></canvas>
          
          <script>
            const cnv = document.getElementById('c')
            const cxt = cnv.getContext('2d')
          
            // 1 創建 Image 對象
            const image = new Image()
          
            // 2 引入圖片
            image.src = './images/dog.jpg'
          
            // 3 等待圖片加載完成
            image.onload = () => {
              // 4 使用 drawImage() 方法渲染圖片
              cxt.drawImage(image, 30, 30)
            }
          </script>
          復制代碼
          

          DOM版

          53.png

          <style>
            #dogImg {
              display: none;
            }
          </style>
          
          <img src="./images/dog.jpg" id="dogImg"/>
          <canvas id="c" width="500" height="500" style="border: 1px solid #ccc;"></canvas>
          
          <script>
            const cnv = document.getElementById('c')
            const cxt = cnv.getContext('2d')
          
            const image = document.getElementById('dogImg')
          
            cxt.drawImage(image, 70, 70)
          </script>
          復制代碼
          

          因為圖片是從 DOM 里獲取到的,所以一般來說,只要在 window.onload 這個生命周期內使用 drawImage 都可以正常渲染圖片。

          本例使用了 css 的方式,把圖片的 display 設置成 none 。因為我不想被 <img> 影響到本例講解。

          實際開發過程中按照實際情況設置即可。

          設置圖片寬高

          前面的例子都是直接加載圖片,圖片默認的寬高是多少就加載多少。

          如果需要指定圖片寬高,可以在前面的基礎上再添加兩個參數:

          drawImage(image, dx, dy, dw, dh)
          復制代碼
          

          image、 dx、 dy 的用法和前面一樣。

          dw 用來定義圖片的寬度,dy 定義圖片的高度。

          54.png

          <canvas id="c" width="500" height="500" style="border: 1px solid #ccc;"></canvas>
          
          <script>
            const cnv = document.getElementById('c')
            const cxt = cnv.getContext('2d')
          
            const image = new Image()
            image.src = './images/dog.jpg'
          
            image.onload = () => {
              cxt.drawImage(image, 30, 30, 100, 100)
            }
          </script>
          復制代碼
          

          我把圖片的尺寸設為 100px * 100px,圖片看上去比之前就小了很多。

          截取圖片

          截圖圖片同樣使用drawImage() 方法,只不過傳入的參數數量比之前都多,而且順序也有點不一樣了。

          drawImage(image, sx, sy, sw, sh, dx, dy, dw, dh)
          復制代碼
          

          以上參數缺一不可

          • image: 圖片對象
          • sx: 開始截取的橫坐標
          • sy: 開始截取的縱坐標
          • sw: 截取的寬度
          • sh: 截取的高度
          • dx: 圖片左上角的橫坐標位置
          • dy: 圖片左上角的縱坐標位置
          • dw: 圖片寬度
          • dh: 圖片高度

          55.png

          <canvas id="c" width="500" height="500" style="border: 1px solid #ccc;"></canvas>
          
          <script>
            const cnv = document.getElementById('c')
            const cxt = cnv.getContext('2d')
          
            const image = new Image()
            image.src = './images/dog.jpg'
          
            image.onload = () => {
              cxt.drawImage(image, 0, 0, 100, 100, 30, 30, 200, 200)
            }
          </script>
          復制代碼
          

          總結

          本文主要講解了在 Canvas 中繪制一些基礎圖形,還有一些基礎樣式設置。

          還有更多高級的玩法會在之后的文章中講到,比如漸變、投影、濾鏡等等。

          德育處主任,https://juejin.cn/post/7116784455561248775

          條APP上有個截圖分享功能,就是把文章轉成一張圖片,然后分享到各渠道中去,如微信、QQ等,非常實用,因此,打算就這項功能自己封裝為一個組件ImageGenerator,后期專門進行圖片生成,html是其中的一個源。


          頭條截圖分享的實際效果圖


          目前前端使用較多的html轉圖片的工具是Html2Canvas,考慮技術儲備和問題討論的充裕性,決定封裝一下這個工具。步驟如下:


          安裝HTML2Canvas

          按照官方要求,做安裝操作:

          npm

          npm install html2canvas


          我當時下載的是1.4.1的版本。



          這個工具有自身的一些限制,使用時要注意:

          [1] 并非真正的截圖軟件,而是根據DOM繪制出來的,其繪制能力,完全依賴于工具對DOM和對應屬性的支持和理解;

          [2] 因為使用了Canvas支持,生成圖片的區域不能再有Canvas應用,否則會干擾工具的生成,不能保證生成預期,因此,如果使用了Canvas圖表的應用這個工具不推薦使用


          封裝ImageGenerator

          這個很簡單,這里就是封裝一個組件,用于后期引入html之外的源生成圖片,同時也做一下圖片的統一顯示,從而和系統整體的設計進行配合。大致的實現思路如下:



          上圖,我們引入了工具本身,并設置的結果的顯示區。生成的結果將以節點的方式注入 #image-box 中。


          上圖,封裝了一個方法,用途是利用Html2Canvas工具獲得圖片,這里我們引入了一個組件的數據imageData用以存儲和干預生成結果。在這里,我把ImageGenerator封裝為全局組件。


          應用場景

          我們在文章的尾部加入一個share功能,點擊彈出分享設置的彈窗,實際效果如下圖所示:




          以上技術實現比較簡單,這里就不進行贅述了。上圖中,我們設置了一個生成圖像按鈕,點擊該按鈕則可以觸發我們組件中的對應操作。關鍵思路包括:

          【1】這里設置了一個封裝組件shareHandler,封裝了前導模塊和imageGenerator,這兩個模塊的顯示通過一個開關進行控制,該開關則通過圖像生成成功事件進行賦值,這樣的話,我們可以實現圖片生成后,不再顯示前導模塊,而是顯示圖片結果,即ImageGenerator。


          【2】這里有一個比較關鍵的操作是shareHandler通過觸發事件將轉換器發射到文章轉換現場,為什么用事件,還是那句話,事件對于解耦和消除組件依賴是最自然的實現。注意,這里我把imageGenerator通過引用的方式作為參數傳出了,這樣的好處是事件將轉換器代入了轉換現場,并可以攜帶回現場轉換結果。



          【3】在文章查看器,solutionViewer中,自然會訂閱事件、事件處理和取消訂閱。注意這里的事件處理,實際上是調用了轉換器中我們封裝的函數,參數則是現場取得的,這里的機制很簡單,定義要轉換div的id,作為參數傳入函數。



          那么,點擊圖像后,我們可以看到效果圖:



          點擊右鍵另存圖像,我們可以獲得一張png格式的圖片,至于后續對下載和到粘貼板的支持,大家可以自行研究和實現。



          注意事項

          實現過程中有幾個注意事項:

          【1】Canvas返回時,其長寬都是按照實際大小生成的,而我們的例子中,則要根據右抽屜式的彈窗做width=100%,height=auto的處理,這個要如何實現,就是要通過我們在imageGenerator中引入的imageData。


          【2】我們的文章顯示中,引入了文件管理的微服務,因此,文章中圖片的鏈接都是跨域的,所以,必須打開html2Canvas的跨域選項,在封裝的組件里,我是通過一共一個defaultOptions來實現這一點的。



          這個選項可以在轉換場景提供,也可提供一系列的默認值,最常用的除跨域外,還有是否允許log輸出等開關,大家感興趣可以自行查閱html2Canvas的官網。


          內容比較簡單,大家如果有這個應用場景,可以參考實現一下,有問題歡迎大家隨時交流。謝謝大家的支持。


          主站蜘蛛池模板: 日韩精品午夜视频一区二区三区| 一区二区三区波多野结衣| 久久精品一区二区三区四区| 精品免费久久久久国产一区| 国产一区精品视频| 亚洲av无码一区二区三区四区 | 精品一区二区三区高清免费观看 | 国产AV午夜精品一区二区三区| 中文字幕永久一区二区三区在线观看 | 天码av无码一区二区三区四区 | 日韩AV无码一区二区三区不卡毛片| 日本精品一区二区三区四区 | 无码人妻AⅤ一区二区三区水密桃| 国产精品高清一区二区三区| 国产精品xxxx国产喷水亚洲国产精品无码久久一区 | 国产精品福利一区| 亚洲一区二区三区香蕉| 成人免费视频一区二区三区| 国产伦精品一区二区三区精品| 亚洲一区精品视频在线| 亚洲一区二区三区在线| 无码少妇一区二区浪潮免费| 日本一区二区三区免费高清在线| 一区二区日韩国产精品| 亚洲精品日韩一区二区小说| 婷婷国产成人精品一区二| 成人精品视频一区二区| 日本免费电影一区二区| 乱色熟女综合一区二区三区| 国产精品女同一区二区| 国产精品av一区二区三区不卡蜜 | 麻豆精品人妻一区二区三区蜜桃| 性色av无码免费一区二区三区 | 久久久无码精品国产一区| 在线视频一区二区三区四区| 国产日韩AV免费无码一区二区三区 | 无码日韩人妻av一区免费| 人妻体内射精一区二区| 无码一区二区三区AV免费| 国产在线无码视频一区二区三区 | 精品在线一区二区|