前面的話
canvas顧名思義是定義在瀏覽器中的畫布。它不僅是一個普通的元素,更是一個強大的編程工具。它的出現已然超過了web基于文檔的設計初衷,將網頁這一形態的應用推向了另一個高度。利用canvas,可以開發出復雜的動畫、動態圖表、游戲等。關于canvas,有這樣一句話——canvas就像是一場文藝復興,將編程工作者徹底釋放出創造力。本文將詳細介紹canvas基礎知識
添加canvas
在HTML中添加Canvas非常簡單,只需要在HTML的<body>
部分,添加上<canvas>
標簽就可以了
<canvas> <p>The canvas element is not supported!</p> </canvas>
現在,頁面是一個完完全全的空白頁面。Canvas的本意是畫布,畫布在HTML5中是透明的,是不可見的
【HTML屬性】
在網頁上使用canvas元素時,它會創建一塊矩形區域。默認情況下,canvas的寬為300px,高為150px

canvas支持HTML屬性高度height和寬度width,可以在開始和結束標簽之間加入HTML來提供后備內容
height 高度
width 寬度
<canvas width="600" height="300"> <p>The canvas element is not supported!</p> </canvas>

[注意]重置canvas的寬或高可以達到清空畫布的效果
【CSS樣式】
同大多數HTML元素一樣,canvas元素也可以通過應用CSS的樣式來增加邊框,設置內外邊距等。而且一些CSS屬性還可以被canvas內的元素繼承。比如字體樣式,在canvas內添加的文字,默認同canvas元素本身是一樣的。此外,在canvas中為繪圖上下文設置屬性同樣要遵循CSS語法

[注意]通過CSS樣式設置的寬高,是canvas元素的實際占據寬高;通過屬性值設置的寬度,是canvas內部編程的設置寬高;如果沒有通過CSS樣式設置寬度,則canvas元素實際占據寬高等于內容編程設置寬度
如果按照如下進行設置,則canvas的最終寬高為400*100,相當于內部元素寬度縮小2.5倍,高度縮小2倍
canvas.width = 1000;
canvas.height = 200;
canvas.style.width = '400px';
canvas.style.height = '100px';
如果按照如下進行設置,則canvas的最終寬高為400*40,相當于內部元素寬度和高度等比例縮小2.5倍
canvas.width = 1000;
canvas.height = 200;
canvas.style.width = '400px';
繪圖上下文
要在canvas上繪圖,需要以下三個步驟
1、布置畫布:通過添加<canvas>
標簽,添加canvas元素
2、獲取畫布:通過<canvas>
標簽的id,獲得canvas對象
3、取得繪圖上下文:通過canvas對象的getContext("2d")
方法,獲得2D環境;如果要獲取三維上下文,使用"webgl"
上面的三個步驟對應如下代碼
<canvas id=“canvas”></canvas> var canvas = document.getElementById("canvas"); var context = canvas.getContext("2d")
【canvas坐標】
使用2D上下文提供的方法可以繪制簡單的2D圖形,比如矩形、弧線和路徑。2D上下文坐標開始于canvas元素的左上角,原點坐標是(0,0)。所有坐標值都基于這個原點計算,x值越大表示越靠右,y值越大表示越靠下。默認情況下,width和height表示水平和垂直兩個方向上可用的像素數目

填充和描邊
2D上下文的兩種基本繪圖操作是填充和描邊
填充是指用指定的樣式(顏色、漸變和圖像)填充圖形;描邊是只在圖形的邊緣畫線
大多數2D上下文操作都會細分為填充和描邊兩個操作,而操作的結果取決于兩個屬性:fillStyle和strokeStyle。這兩個屬性的值可以是字符串表示的顏色、漸變對象或模式對象,它們的默認值都是#000
var context = drawing.getContext('2d'); context.strokeStyle="red"; context.fillStyle="#00f";
關于漸變和模式對象,稍后介紹
繪制矩形
下面先從最簡單的矩形繪制開始說起,矩形是唯一一種可以直接在2D上下文中繪制的形狀,與矩形相關的方法包括fillRect()、strokeRect()、clearRect()。這三個方法都能接收4個參數:矩形的x坐標、矩形的y坐標、矩形寬度和矩形高度。這些參數的單位都是像素
fillRect(x,y,w,h):畫布上繪制的矩形會填充通過fillStyle屬性指定的顏色
strokeRect(x,y,w,h):畫布上繪制的矩形會使用通過strokeStyle屬性指定描邊顏色
clearRect(x,y,w,h):用于清除畫布上的矩形區域。本質上這個方法可以把繪制上下文中的某一矩形區域變透明。通過繪制形狀然后再清除指定區域,就可以生成有意思的效果
下面來繪制一個背景顏色為紅色,尺寸為100*100,位置為(0,0)點的矩形
<canvas id="drawing" style="border:1px solid black"> <p>The canvas element is not supported!</p> </canvas> <script> var drawing = document.getElementById('drawing'); //確定瀏覽器支持<canvas>元素 if(drawing.getContext){ var context = drawing.getContext('2d'); context.fillRect(0,0,100,100); context.fillStyle = 'red'; } </script>
結果如下,背景顏色為黑色。這是因為,使用fillRect()方法時,會使用當前的fillStyle值。由于當前還沒有設置,所以會使用默認的黑色值

進行如下修改后,結果符合預期
<script> var drawing = document.getElementById('drawing'); if(drawing.getContext){ var context = drawing.getContext('2d'); context.fillStyle = 'red'; context.fillRect(0,0,100,100);
} </script>

下面來繪制一個半透明的藍色描邊矩形,尺寸為100*100,位置在(0,0)點
<script> var drawing = document.getElementById('drawing'); if(drawing.getContext){ var context = drawing.getContext('2d'); context.strokeStyle = 'rgba(0,0,255,0.5)'; context.strokeRect(0,0,100,100);
} </script>

接下來,在(0,0)點繪制尺寸為100*100背景為半透明紅色的矩形, 1s后在(50,50)點繪制尺寸為100*100,描邊為半透明藍色的矩形,1s后使用clearRect()清除矩形
<canvas id="drawing" style="border:1px solid black"> <p>The canvas element is not supported!</p> </canvas> <script> var drawing = document.getElementById('drawing'); if(drawing.getContext){ var context = drawing.getContext('2d'); context.fillStyle = 'rgba(255,0,0,0.5)'; context.fillRect(0,0,100,100); setTimeout(function(){ context.strokeStyle = 'rgba(0,0,255,0.5)'; context.strokeRect(50,50,100,100); },1000); setTimeout(function(){ context.clearRect(0,0,300,150); },2000); } </script>

繪制文本
繪制文本主要有兩個方法:fillText()和strokeText(),fillText()方法使用fillStyle屬性繪制文本,strokeText()方法使用strokeStyle屬性為文本描邊
這兩個方法都可以接收4個參數:要繪制的文本字符串、x坐標、y坐標和可選的最大像素寬度
若傳入的字符串大于最大寬度時,則繪制的文本字符的高度正確,而寬度會收縮以適應最大寬度。而且這兩個方法都以下列3個屬性為基礎:font、textAlign、textBaseline
font(與font集合樣式寫法相同)
textAlign(start\end\center)不建議使用left\right,默認為start
textBaseline(top\hanging\middle\alphabetic\ideographic\bottom),默認為alphabetic
【measureText()】
由于繪制文本比較復雜,特別是需要把文本控制在某一區域的時候,因此提供了輔助確定文本大小的方法measureText()方法。該方法接收一個參數,即要繪制的文本,返回一個TextMetrics對象,該對象只有一個width屬性。measureText()方法利用font、textAlign、textBaseline的當前值計算指定文本的大小
假設想在一個100px寬的矩形區域中繪制文本"小火柴",下面代碼從50px字體大小開始遞減,最終會找到合適的字體大小
<script> var drawing = document.getElementById('drawing'); if(drawing.getContext){ var context = drawing.getContext('2d'); var fontSize = 50; context.font= fontSize + 'px arial'; while(context.measureText('小火柴').width > 100){ fontSize--; context.font= fontSize + 'px arial'; } context.fillText('小火柴',10,30); context.fillText('字體大小是' + fontSize + 'px' ,10,80); } </script>

描邊線條
關于描邊線條有4個常用屬性分別是lineWidth、lineCap、lineJoin和miterLimit
lineWidth:描邊線條寬度(默認為1)
lineCap:描邊線條末端形狀是平頭、圓頭還是方頭(butt、round、square)(默認為butt)
lineJoin:描邊線條相交方式是圓交、斜交還是斜接(round、bevel、miter)(默認為miter)
miterLimit:描邊線條的最大斜接長度
斜接長度是指兩條交匯處內角和外角之間的距離,邊角的角度越小,斜接長度就越大,為了避免斜接長度過長,可以使得miterLimit屬性,如果斜接長度超過miterLimit的值,邊角會以lineJoin的"bevel"類型來顯示
[注意]只有當lineJoin屬性為"miter"時,miterLimit才有效


漸變
填充和描邊除了可以取顏色值之外,還可以取漸變值,漸變由canvasGradient實例表示
【創建漸變】
漸變分為線性漸變和徑向漸變
調用createLinearGradient()方法創建線性漸變,這個方法接收4個參數:起點的x坐標、y坐標,終點的x坐標、y坐標
調用createRadialGradient()方法創建徑向漸變,這個方法接收6個參數,對應兩個圓的圓心和半徑。前三個參數指定起點圓的圓心(x和y)及半徑。后三個參數指定終點圓的圓心(x和y)及半徑。可以把徑向漸變想象成一個長圓桶,而這6個參數定義的正是這個桶的兩個圓形開口的位置
[注意]如果想從某個形狀的中心點開始創建一個向外擴散的徑向漸變效果,要將兩個圓定義為同心圓
【指定色標】
接下來使用addColorStop()方法來指定色標。這個方法接收兩個參數:色標位置和CSS顏色值。色標位置是一個0(開始的顏色)到1(結束的顏色)之間的數字
最后將漸變對象實例賦值給fillStyle或strokeStyle,進而可以繪制圖形
下面來創建一個垂直方向的從品紅到淺藍色的線性漸變
<canvas id="drawing" style="border:1px solid black"> <p>The canvas element is not supported!</p> </canvas> <script> var drawing = document.getElementById('drawing'); if(drawing.getContext){ var context = drawing.getContext('2d'); var linearGradient = context.createLinearGradient(0,0,0,100); linearGradient.addColorStop(0,'pink'); linearGradient.addColorStop(1,'lightblue'); context.strokeStyle = linearGradient; context.fillStyle = linearGradient; context.fillRect(10,10,100,100); context.strokeRect(120,10,100,100); context.font="20px/50px 宋體"; context.textAlign = 'end'; context.textBaseline = 'top'; context.strokeText("小火柴",290,10); } </script>

下面來創建一個從品紅到淺藍色的徑性漸變
<canvas id="drawing" style="border:1px solid black"> <p>The canvas element is not supported!</p> </canvas> <script> var drawing = document.getElementById('drawing'); if(drawing.getContext){ var context = drawing.getContext('2d'); var radialGradient = context.createRadialGradient(50,50,0,50,50,50); radialGradient.addColorStop(0,'pink'); radialGradient.addColorStop(1,'lightblue'); context.fillStyle = radialGradient; context.fillRect(0,0,100,100); } </script>

繪制路徑
繪制路徑包括開始繪制、實際繪制和結束繪制三個步驟
【開始繪制】
要繪制路徑,首先必須調用beginPath()方法,表示要開始繪制新路徑
[注意]beginPath()之后的strokeStyle或fillStyle用于當前路徑
【實際繪制】
實際繪制路徑時可以使用以下方法:
1、moveTo(x,y):將繪圖游標移動到(x,y),不畫線。如果其他方法需要使用上一點的坐標,一定要先使用moveTo(x,y)確定坐標
context.moveTo(100,100)
表示移動畫筆至(100,100)這個點(單位是px)
2、lineTo(x,y):從上一點開始繪制一條直線,到(x,y)為止
context.lineTo(600,600)
表示從上一筆的停止點繪制到(600,600)
3、arcTo(x1,y1,x2,y2,radius):從上一點開始繪制一條弧線到(x2,y2)為止,并以給定半徑radius穿過(x1,y1)
context.arcTo(30,80,100,100,60);
表示從上一點開始繪制一條弧線到(100,100)為止,該弧線穿過(30,80),且半徑為60
4、arc(x,y,radius,startAngle,endAngle,counterclockwise):以(x,y)為圓心繪制一條弧線,弧線半徑為radius,起始和結束角度(用弧度表示)分別為startAngle和endAngle。最后一個參數表示startAngle和endAngle是否按逆時針方向計算。默認值為false表示按順時針方向計算

context.arc(50,50,40,0,2*Math.PI,false);
表示以(50,50)為圓心繪制一條弧線,半徑為40,起始和結束角度分別為0和2PI,按順時針方向計算
5、bezierCurveTo(c1x,c1y,c2x,c2y,x,y):從上一點開始繪制一條曲線,到(x,y)為止,并且以(c1x,c1y)和(c2x,c2y)為控制點
context.bezierCurveTo(0,50,100,50,100,0);
表示從上一點開始繪制一條曲線,到(100,0)為止,并且以(0,50)和(100,50)為控制點
6、quadraticCurveTo(cx,cy,x,y):從上一點開始繪制一條二次曲線,到(x,y)為止,并且以(cx,cy)為控制點
context.quadraticCurveTo(50,50,0,100);
表示從上一點開始繪制一條二次曲線,到(0,100)為止,并且以(50,50)為控制點
7、rect(x,y,width,height):從點(x,y)開始繪制一個矩形,寬度和高度分別由width和height指定。這個方法繪制的是矩形路徑,而不是strokeRect()和fillRect()所繪制的獨立的形狀
context.rect(20,20,50,50);
表示從(20,20)開始繪制一個矩形,寬高分別是50和50
【結束繪制】
創建路徑后有以下4種選擇
1、用fillStyle填充,調用fill()方法
2、用strokeStyle描邊,調用stroke()方法
[注意]如果fill()和stroke()同時使用,應該先使用fill(),后使用stroke()。否則,fill()會覆蓋stroke()的部分線條寬度
3、在路徑上創建一個剪切區域,調用clip()方法
[注意]canvas中的clip()方法用于從原始畫布中剪切任意形狀和尺寸。一旦剪切了某個區域,則所有之后的繪圖都會被限制在被剪切區域內(不能訪問畫布上的其他區域)。也可以在使用clip()方法前通過使用save()方法對當前畫布區域進行保存,并在以后任意時間通過restore()方法對其進行恢復。可以使用clip()實現類似于探照燈效果
4、繪制一條連接到路徑起點的線條,調用closePath()方法
在2D繪圖上下文中,路徑是一種主要的繪圖方式,因為路徑能為要繪制的圖形提供更多控制。由于路徑的使用很頻繁,所以有一個isPointInPath()方法,接收x和y坐標作為參數,用于在路徑被關閉之前確定畫布上的某一點是否位于路徑上
if(context.isPointInPath(100,100)){ console.log('this point is in the path'); }
文章列表