Canvas 畫布

一、簡介

HTML5 中的定義:“它是依賴分辨率的位圖畫布,你可以在 canvas 上面繪制任何圖形,甚至加載照片。”

  • 矩形空白區域
  • 通過 javascript 繪制圖形
  • 可以加載圖片

canvas 坐標系

二、HTML 部分

<canvas id="a" width="300" height="300">您的瀏覽器不支持 canvas</canvas>

簡單的在 HTML 頁面添加一個 canvas 元素,設定寬高,添加 id 便于 javascript 獲取。

  • 每個 canvas 初始都是一個白板。
  • 樣式除了寬高,盡量寫在畫布里,而不是使用 CSS
  • canvas 標簽里如果添加文本,那么當瀏覽器不支持 canvas 時顯示文本

三、繪圖上下文環境

var a = document.getElementById('a');
var a_context = a.getContext("2d");
  • 獲取到 canvas 元素
  • 調用它的 getContext() 方法獲取繪圖上下文環境,參數必須為 2d ,未來可能會有 3d
  • 基于上下文環境的方法進行繪圖

繪圖上下文包含所有繪制方法和屬性的定義。

四、路徑

4.1 beginPath() 開始新路徑

表示重新開始新的路徑。

canvas 是基于狀態的繪圖,開啟一條新的路徑,就可以設置新的狀態。但是 beginPath() 不會將狀態重置回默認值。

同一條路徑上的線條和曲線都會是相同的顏色。所以需要繪制不同顏色的時候,必須開啟新的路徑。

4.2 closePath() 結束路徑

用于結束路徑,與 beginPath() 并不一定成對出現。

注意:默認結束路徑后,圖形自動封閉,即首尾相連。所以有些時候不會用到結束路徑。

4.3 stroke() 繪制路徑

繪制已定義的路徑

4.4 fill() 填充路徑

將準備畫的路徑塊填充

fill() 會覆蓋描邊 stroke() 邊框的一半。所以,在需要描邊的填充色,需要先填充,后描邊。

4.5 isPointInPath() 是否在路徑中

如果指定的點位于當前路徑中,則返回 true,否則返回 false

context.isPointInPath(x,y);
  • x 測試點的 x 坐標
  • y 測試點的 y 坐標

4.6 clip() 剪切

從原始畫布剪切任意形狀和尺寸的區域

context.clip();

注意:一旦剪切了某個區域,則所有之后的繪圖都會被限制在被剪切的區域內(不能訪問畫布上的其他區域)。您也可以在使用 clip() 方法前通過使用 save() 方法對當前畫布區域進行保存,并在以后的任意時間通過 restore() 方法進行恢復。

五、線條以及填充顏色

5.1 fillStyle 填充樣式

設置或返回用于填充繪畫的顏色、漸變或模式,需要在填充前聲明才有效

context.fillStyle=color|gradient|pattern;
  • color 指示繪圖填充色的 CSS 顏色值。默認值是 #000000。
  • gradient 用于填充繪圖的漸變對象
  • pattern 用于填充繪圖的 pattern 對象

5.2 strokeStyle 線條樣式

設置或返回用于筆觸的顏色、漸變或模式,需要在繪制前聲明才有效

context.strokeStyle=color|gradient|pattern;
  • color 指示繪圖筆觸顏色的 CSS 顏色值。默認值是 #000000。
  • gradient 用于填充繪圖的漸變對象
  • pattern 用于創建 pattern 筆觸的 pattern 對象

5.3 lineCap 線條結束端點樣式

設置或返回線條的結束端點樣式

context.lineCap="butt|round|square";
  • butt 默認。向線條的每個末端添加平直的邊緣。
  • round 向線條的每個末端添加圓形線帽。
  • square 向線條的每個末端添加正方形線帽。

roundsquare 會使線條略微變長。

5.4 lineJoin 線條拐角類型

設置或返回兩條線相交時,所創建的拐角類型

context.lineJoin="bevel|round|miter";
  • bevel 創建斜角
  • round 創建圓角
  • miter 默認。創建尖角

5.5 lineWidth 線條寬度

設置或返回當前的線條寬度

context.lineWidth=number;
  • number 當前線條的寬度,以像素計

5.6 miterLimit 線條最大斜接長度

設置或返回最大斜接長度

context.miterLimit=number;
  • number 正數
    如果斜接長度超過 miterLimit 的值,邊角會以 lineJoinbevel 類型來顯示。

斜接長度指的是在兩條線交匯處內角和外角之間的距離。


只有當 lineJoin 屬性為 miter 時,miterLimit 才有效。

邊角的角度越小,斜接長度就會越大。
為了避免斜接長度過長,我們可以使用 miterLimit 屬性。
如果斜接長度超過 miterLimit 的值,邊角會以 lineJoin 的 "bevel" 類型來顯示(圖解 3):


六、直線路徑

6.1 moveTo() 起點坐標

把路徑移動到畫布中的指定點,不創建線條。聲明直線開始的起點坐標。括號里面填寫坐標。

context.moveTo(100,100);

6.2 lineTo() 終點坐標

聲明直線結束的終點坐標。括號里面填寫坐標。

context.moveTo(100,100);//起點
context.lineTo(700,700);//終點

連續出現相當于以前一個為起點繼續走向另一個坐標。

context.moveTo(100,100);//起點 
context.lineTo(700,700);//終點
context.lineTo(100,700);//以前一個終點為起點坐標

lineTo()beginPath() 后面使用時,可以代替 moveTo(),和 moveTo() 起到相同效果。

6.3 多邊形

moveTo() 開始,使用 lineTo() 畫直線到三個頂點,最終回到起點坐標。

如三角形:

//路徑描述
context.moveTo(100,100);
context.lineTo(700,700);
context.lineTo(100,700);
context.lineTo(100,100);
//繪制
context.stroke();

七、貝塞爾曲線

7.1 quadraticCurveTo() 二次貝塞爾

通過使用表示二次貝塞爾曲線的指定控制點,向當前路徑添加一個點。

二次貝塞爾曲線需要兩個點。第一個點是用于二次貝塞爾計算中的控制點,第二個點是曲線的結束點。最后添加的是結束點


注意:曲線的開始點是當前路徑中最后一個點。如果路徑不存在,那么請使用 beginPath()moveTo() 方法來定義開始點。

context.quadraticCurveTo(cpx,cpy,x,y);
  • cpxcpy 貝塞爾控制點的坐標
  • xy 結束點的坐標

7.2 bezierCurveTo() 三次貝塞爾

通過使用表示三次貝塞爾曲線的指定控制點,向當前路徑添加一個點。

三次貝塞爾曲線需要三個點。前兩個點是用于三次貝塞爾計算中的控制點,第三個點是曲線的結束點。


context.bezierCurveTo(cp1x,cp1y,cp2x,cp2y,x,y);
  • cp1xcp1y 第一個貝塞爾控制點的坐標
  • cp2xcp2y 第二個貝塞爾控制點的坐標
  • xy 結束點的坐標

八、畫弧線、圓

8.1 arc() 創建圓路徑

創建弧/曲線(用于創建圓形或部分圓)

context.arc(centerX, centerY, radius, startingAngle, endingAngle, anticlockwise=true);
  • centerx , centery 表示圓心位置
  • radius表示半徑
  • startingAngleendingAngle表示開始位置和結束位置
  • anticlockwise 表示 true 時為順時針繪制,false 為逆時針繪制。默認為 true

其中角度參數的值:0 表示圓的最右邊,0.5*Math.PI 表示最下面,1*Math.PI 表示最左邊,1.5*Math.PI 表示最上面,2*Math.PI 表示最右邊。這些規定是固定的,不會因為順逆時針改變。

8.2 arcTo() 兩切線弧

創建兩切線之間的弧/曲線

context.fillRect(x1,y1,x2,y2,r);
  • x1y1 弧的起點坐標
  • x2y2 弧的終點坐標
  • r 弧的半徑

使用 stroke() 方法在畫布上繪制確切的弧。

8.3 繪制

  • lineWidth 定義線條粗細
  • strokeStyle 定義描邊樣式
  • stroke() 描邊
  • fillStyle 定義填充樣式
  • fill() 填充

8.4 圓

context.arc(100,100,80,0,2*Math.PI,true);

表示從右邊(0)開始,順時針畫圓,到右邊(2 PI)結束。

九、文本

不同于網頁中的文本,繪制在 canvas 中的文本是沒有盒模型的,沒有浮動、邊距、留白、自動換行等。

9.1 fillText() 填充文本

context.fillText("text",x,y);
  • text 規定在畫布上輸出的文本
  • xy 開始繪制文本的坐標位置

9.2 strokeText() 描邊文本

context.strokeText(text,x,y,maxWidth);
  • text 規定在畫布上輸出的文本
  • xy 開始繪制文本的坐標位置
  • maxWidth 可選。允許的最大文本寬度,以像素計

9.3 measureText() 測量文本寬度

measureText() 方法返回包含一個對象,該對象包含以像素計的指定字體寬度。

context.measureText(text).width;
  • text 要測量的文本

9.4 font 字體樣式

canvas 中的字體會繼承 canvas 元素的字體大小和樣式風格。
設置 font 屬性覆蓋繼承值。符合 CSS 規則。

context.font = "bold 12px sans-serif";

屬性值里面的每個取值用空格隔開

  • font style
  • font variant
  • font size
  • font weight
  • lineheight
  • font family

使用相對字體大小,如 1.5em150%,是基于 canvas 元素本身的字體大小。rem 仍是基于根元素。

9.5 textAlign 對齊方式

類似 CSS 中的 text-align

context.textAlign = "start";

取值:start(默認)、endleftrightcenter

9.6 textBaseline 相對于起點的位置

控制文本相對于起點的位置。

context.textBaseline = "top";

必須使用引號。

取值:topbottomhangingmiddlealphabeticideographic

十、矩形

10.1 rect() 創建矩形

context.rect(x,y,width,height);
  • xy 矩形左上角的坐標
  • widthheight 矩形的寬高

使用 stroke()fill() 方法在畫布上實際地繪制矩形。

10.2 fillRect() 已填充矩形

fillRect(x,y,width,height);
  • xy 表示矩形左上角坐標
  • widthheight表示寬高

使用 fillStyle 屬性來設置用于填充繪圖的顏色、漸變或模式。

10.3 strokeRect() 已描邊矩形

strokeRect(x,y,width,height);
  • xy 表示矩形左上角坐標
  • widthheight表示寬高

使用 strokeStyle 屬性來設置筆觸的顏色、漸變或模式。

10.4 clearRect() 清空矩形區域

context.clearRect(x,y,width,height);
  • xy 表示矩形左上角坐標
  • widthheight表示寬高

十一、添加圖片

11.1 drawImage() 添加圖片

三種用法:

context.drawImage(img,x,y);
context.drawImage(img,x,y,width,height);
context.drawImage(image,sx,sy,sw,sh,dx,dy,dw,dh)
  • image 為圖片對象,必須
  • sxsy 為裁剪開始位置,左上角坐標,可選
  • swsh 為裁剪寬高,可選
  • dxdy 為繪制起點,左上角坐標,必須
  • dwdh 為自定義的圖片寬高,可選

11.2 圖片對象

  1. 已存在的 <img> 元素
//HTML部分
<img id="cat" src="images/cat.png">
//javascript部分
window.onload = function() {
  .
  .
  var cat = document.getElementById('cat');
  context.drawImage(cat,0,0); 
}

window.onload 事件處理器中,獲取已有圖片對象,然后在 canvas 中安全繪制圖片。

  1. 自己創建的圖片對象
var cat = new Image();
cat.src = "images/cat.png";
cat.onload = function() {
  context.drawImage(cat,0,0);
};

創建圖片對象,然后在 cat.onload 事件處理器中安全地把圖片繪制在 canvas 中。

十二、特殊樣式

12.1 shadowColor 陰影顏色

設置或返回用于陰影的顏色

context.shadowColor=color;
  • color 用于陰影的 CSS 顏色值。默認值是 #000000。

12.2 shadowBlur 陰影模糊程度

設置或返回用于陰影的模糊級別

context.shadowBlur=number;
  • number 陰影的模糊級數

12.3 shadowOffsetX 陰影水平偏移

設置或返回陰影距形狀的水平距離

context.shadowOffsetX=number;
  • number 正值或負值,定義陰影與形狀的水平距離。

12.4 shadowOffsetY 陰影垂直偏移

設置或返回陰影距形狀的垂直距離

context.shadowOffsetY=number;
  • number 正值或負值,定義陰影與形狀的垂直距離

12.5 createPattern() 重復

在指定的方向內重復指定的元素。

元素可以是圖片、視頻,或者其他 canvas 元素。
被重復的元素可用于繪制/填充矩形、圓形或線條等等。

context.createPattern(image,"repeat|repeat-x|repeat-y|no-repeat");
  • image 規定要使用的圖片、畫布或視頻元素。
  • repeat 默認。該模式在水平和垂直方向重復。
  • repeat-x 該模式只在水平方向重復。
  • repeat-y 該模式只在垂直方向重復。
  • no-repeat 該模式只顯示一次(不重復)。

12.6 createLinearGradient() 創建線性漸變

調用 createLinearGradient() 方法創建線性漸變

createLinearGradient(x0,y0,x1,y1);

表示沿直線從(x0,y0)到(x1,y1)繪制漸變。

如水平漸變:

var my_gradient = context.createLinearGradient(0,0,300,0);

設置兩個 y 值為 0,漸變會沿水平從左到右。

注意:創建漸變需要賦給一個變量,通過這個變量設置色標

12.7 createRadialGradient() 創建徑向漸變

調用 createRadialGradient() 方法創建徑向漸變

createRadialGradient(x0,y0,r0,x1,y1,r1)

表示沿著兩個圓之間的錐面繪制漸變。
前三個參數代表開始圓,后三個參數表示結束圓。

12.8 addColorStop() 添加色標

addColorStop(index,color);
  • index 漸變位置,可以在 0 - 1 之間取任意值
  • color 漸變顏色,關鍵字及十六進制顏色要添加引號

注意:這個方法屬于創建的漸變對象,也就是前面創建漸變時的變量。

my_gradient.addColorStop(0,"block");
my_gradient.addColorStop(1,"white");

12.9 繪制漸變

context.fillStyle = my_gradient;
context.fillRect(0,0,300,225);
  • 將填充顏色設置為創建的漸變
  • 填充所需要的圖形

十三、轉換

轉換都應該放在繪制之前

13.1 scale() 縮放

縮放當前繪圖至更大或更小

注意:如果您對繪圖進行縮放,所有之后的繪圖也會被縮放。定位也會被縮放,線條大小也會被縮放。

context.scale(scalewidth,scaleheight);
  • scalewidth 縮放當前繪圖的寬度 (1=100%, 0.5=50%, 2=200%, 依次類推)
  • scaleheight 縮放當前繪圖的高度 (1=100%, 0.5=50%, 2=200%, etc.)

13.2 rotate() 旋轉

旋轉當前繪圖

conntext.rotate(angle);
  • angle 旋轉角度,以弧度計。

將角度轉換為弧度,請使用 degrees*Math.PI/180 公式進行計算。

13.3 translate() 改變原點坐標

重新映射畫布上的 (0,0) 位置,改變坐標原點的位置

context.translate(x,y);
  • x 添加到水平坐標上的值
  • y 添加到垂直坐標上的值

當您在 translate() 之后調用諸如 fillRect() 之類的方法時,值會添加到 xy 坐標值上。,即后面的繪圖涉及到坐標都會在此基礎上增加值。

13.4 transform() 變換矩陣

畫布上的每個對象都擁有一個當前的變換矩陣。
transform() 方法替換當前的變換矩陣。

它以下面描述的矩陣來操作當前的變換矩陣:

a  c  e
b  d  f
0  0  1

也就是說,transform() 允許您縮放、旋轉、移動并傾斜當前的環境。

注意:該變換只會影響 transform() 方法調用之后的繪圖。
前面的 rotate(), scale(), translate(), transform() 方法都會影響到當前的 transform()
例如:如果您已經將繪圖設置為放到兩倍,則 transform() 方法會把繪圖放大兩倍,您的繪圖最終將放大四倍。

context.transform(a,b,c,d,e,f);
  • a 水平縮放繪圖
  • b 水平傾斜繪圖
  • c 垂直傾斜繪圖
  • d 垂直縮放繪圖
  • e 水平移動繪圖
  • f 垂直移動繪圖

13.5 setTransform()

將當前轉換重置為單位矩陣。然后以同樣的參數運行 transform(),這樣就可以不受前面的影響了。

context.setTransform(a,b,c,d,e,f);
  • a 水平縮放繪圖,默認值為 1
  • b 水平傾斜繪圖,默認值為 0
  • c 垂直傾斜繪圖,默認值為 0
  • d 垂直縮放繪圖,默認值為 1
  • e 水平移動繪圖,默認值為 0
  • f 垂直移動繪圖,默認值為 0

所以矩陣默認為單位矩陣:

1  0  0
0  1  0
0  0  1

13.6 save()、 restore()

  • save() 保存當前環境的狀態
    • 原點位置
    • 縮放大小
    • 旋轉
    • 矩陣變換
    • 裁剪塊
  • restore() 返回之前保存過的路徑狀態和屬性

十四 ImageData 對象

對于 ImageData 對象中的每個像素,都存在著四方面的信息,即 RGBA 值:

  • R - 紅色 (0-255)
  • G - 綠色 (0-255)
  • B - 藍色 (0-255)
  • A - alpha 通道 (0-255; 0 是透明的,255 是完全可見的)

因此 ,transparent black 表示 (0,0,0,0)

color/alpha 以數組形式存在,并且既然數組包含了每個像素的四條信息,數組的大小是 ImageData 對象的四倍。獲得數組大小的辦法,就是使用 ImageDataObject.data.length

包含 color/alpha 信息的數組存儲于 ImageData 對象的 data 屬性中。

14.1 createImageData() 創建 ImageData 對象

創建新的空白 ImageData 對象。

有兩個版本的 createImageData() 方法:

//以指定的尺寸(以像素計)創建新的 ImageData 對象
var imgData=context.createImageData(width,height);
//創建與指定的另一個 ImageData 對象尺寸相同的新 ImageData 對象(不會復制圖像數據)
var imgData=context.createImageData(imageData);

新對象的默認像素值 transparent black

  • width ImageData 對象的寬度,以像素計。
  • height ImageData 對象的高度,以像素計。
  • imageData 另一個 ImageData 對象。

14.2 getImageData() 復制畫布像素數據

返回 ImageData 對象,該對象拷貝了畫布指定矩形的像素數據,進行操作后,通過 putImageData() 將圖像數據放回畫布

var imgData = context.getImageData(x,y,width,height);
  • xy 開始復制的左上角位置的坐標
  • widthheight 將要復制的矩形區域的寬高

14.3 putImageData() 放入像素數據

將圖像數據(從指定的 ImageData 對象)放回畫布上。

context.putImageData(imgData,x,y,dirtyX,dirtyY,dirtyWidth,dirtyHeight);
  • imgData 規定要放回畫布的 ImageData 對象
  • xy ImageData 對象放置在畫布上的位置左上角的坐標,以像素計
  • dirtyXdirtyY 可選。以像素計,在畫布上繪制的圖像在 ImageData 對象上的位置坐標
  • dirtyWidthdirtyHeight 可選。在畫布上繪制圖像的寬高

后面四個屬性相當于裁剪,但是,在畫布上,依然是整個 ImageData 對象。
如:

var imgData=ctx.getImageData(10,10,50,50);
ctx.putImageData(imgData,10,70,20,40,30,10);

在畫布上放置裁剪部分的位置就變成了(10+20,70+40),寬高是 30, 10。

注意:如果裁剪位置加上裁剪寬度,超出了原來的寬高,超出部分不會繪制

14.4 widthheight寬高

返回 ImageData 對象的寬高,以像素計。

imgData.width;
imgData.height;

14.5 data 圖像數據

返回一個對象,該對象包含指定的 ImageData 對象的圖像數據。

對于 ImageData 對象中的每個像素,都存在著四方面的信息,即 RGBA 值:
R - 紅色 (0-255)
G - 綠色 (0-255)
B - 藍色 (0-255)
A - alpha 通道 (0-255; 0 是透明的,255 是完全可見的)
color/alpha 以數組形式存在,并存儲于 ImageData 對象的 data 屬性中。

將 ImageData 對象中的第一個像素變為紅色的語法:

imgData=ctx.createImageData(100,100);

imgData.data[0]=255;
imgData.data[1]=0;
imgData.data[2]=0;
imgData.data[3]=255;

將 ImageData 對象中的第二個像素變為綠色的語法:

imgData=ctx.createImageData(100,100);

imgData.data[4]=0;
imgData.data[5]=255;
imgData.data[6]=0;
imgData.data[7]=255;

十五、合成

15.1 globalAlpha 透明度

設置或返回繪圖的當前 alpha 或透明值

context.globalAlpha=number;
  • number 透明值。必須介于 0.0(完全透明) 與 1.0(不透明) 之間。

15.2 globalCompositeOperation

設置或返回新圖像如何繪制到已有的圖像上

源圖像 = 您打算放置到畫布上的繪圖。
目標圖像 = 您已經放置在畫布上的繪圖。

context.globalCompositeOperation="source-in";
  • source-over 默認。在目標圖像上顯示源圖像。
  • source-atop 在目標圖像頂部顯示源圖像。源圖像位于目標圖像之外的部分是不可見的。
  • source-in 在目標圖像中顯示源圖像。只有目標圖像內的源圖像部分會顯示,目標圖像是透明的。
  • source-out 在目標圖像之外顯示源圖像。只會顯示目標圖像之外源圖像部分,目標圖像是透明的。
  • destination-over 在源圖像上方顯示目標圖像。
  • destination-atop 在源圖像頂部顯示目標圖像。源圖像之外的目標圖像部分不會被顯示。
  • destination-in 在源圖像中顯示目標圖像。只有源圖像內的目標圖像部分會被顯示,源圖像是透明的。
  • destination-out 在源圖像外顯示目標圖像。只有源圖像外的目標圖像部分會被顯示,源圖像是透明的。
  • lighter 顯示源圖像 + 目標圖像。
  • copy 顯示源圖像。忽略目標圖像。
  • xor 使用異或操作對源圖像與目標圖像進行組合。

十六、兼容IE

雖然 IE 瀏覽器不支持 canvas API,但是他有一個叫 VML 的技術,可以完成 canvas 元素能做的大部分工作。

16.1 ExplorerCanvas——excanvas.js

excanvas.js 是一個開源的,采用 Apache license 許可的 javascript 類庫,在 IE 中實現了 canvas 的 API。

<!--[if lt IE9]>
  <script src="excanvas.js"></script>
<![endif]-->

16.2 限制

  • 顏色漸變只支持線性漸變
  • 模式必須在兩個方向上重復
  • 不支持裁剪
  • 非等比縮放
  • 很慢
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 一、什么是 Canvas? HTML5 的 canvas 元素使用 JavaScript 在網頁上繪制圖像 畫布是...
    EndEvent閱讀 721評論 0 1
  • 一:canvas簡介 1.1什么是canvas? ①:canvas是HTML5提供的一種新標簽 ②:HTML5 ...
    GreenHand1閱讀 4,719評論 2 32
  • canvas用途 游戲 小游戲 圖表 報表 如 Charts插件 炫酷效果 banner 模擬器、圖形編輯器 等...
    飛魚_JS閱讀 949評論 0 2
  • --繪圖與濾鏡全面解析 概述 在iOS中可以很容易的開發出絢麗的界面效果,一方面得益于成功系統的設計,另一方面得益...
    韓七夏閱讀 2,791評論 2 10
  • 剛開始參加時候,擔心自己沒時間去讀書,怕自己做不好,一轉眼21.天結束了。每天的一問堅持去完成,還偶爾參加社群...
    流年七里香農莊閱讀 270評論 0 0