概述
Canvas(畫布)用於在網頁實時生成影象,並且可以操作影象內容,基本上它是一個可以用JavaScript操作的點陣圖(bitmap)。
開始使用
- 新建一個
<canvas>
網頁元素。
<canvas id="myCanvas" width="400" height="200">
你的瀏覽器不支援canvas!
</canvas>
複製程式碼
- 替換內容
- 支援
<canvas>
的瀏覽器將會忽略在容器中包含的內容,正常渲染canvas。 - 不支援
<canvas>
的瀏覽器會顯示代替內容
- 支援
width
和height
- 預設寬度為300畫素,預設高度為150畫素。
html
屬性設定width/height
時隻影響畫布本身不影畫布內容css
屬性設定width/height
時不但會影響畫布本身的高寬,還會使畫布中的內容等比例縮放(縮放參照於畫布預設的尺寸)
<canvas>
元素只是創造了一個固定大小的畫布,要想在它上面去繪製內容,需要用getContext()
方法找到它的渲染上下文。
//獲取canvas容器
var canvas = document.getElementById('myCanvas');
//建立一個渲染上下文
if (canvas.getContext) {
var ctx = canvas.getContext('2d');
}
複製程式碼
上面程式碼中,getContext
方法指定引數2d
,表示該canvas
節點用於生成2D圖案(即平面圖案)。如果引數是webgl
,就表示用於生成3D影象(即立體圖案),這部分實際上單獨叫做WebGL API。
繪圖方法
canvas
畫布提供了一個用來作圖的平面空間,該空間的每個點都有自己的座標,x表示橫座標,y表示豎座標。原點(0, 0)位於影象左上角,x軸的正向是原點向右,y軸的正向是原點向下
樣式和顏色
fillStyle
:設定填充顏色,預設黑色strokeStyle
:設定輪廓顏色,預設黑色lineWidth
:設定線條寬度,屬性值為任意正整數,預設值是1.0。lineJoin
:控制線條相交的方式(預設是miter
)round
: 圓角bevel
: 斜角miter
: 直角
lineCap
:線段末端的形狀(預設值是butt
)butt
:線段末端以方形結束。round
:線段末端以圓形結束square
:線段末端以方形結束,但是增加了一個寬度和線段相同,高度是線段厚度一半的矩形區域
save()、restore()、beginPath()
- 樣式容器
- 每次呼叫樣式api時,都會往樣式容器裡做登記
- 呼叫
save()
時,將樣式容器中的狀態壓棧,儲存上下文環境 - 呼叫
restore()
時,將樣式棧的棧頂狀態彈出到樣式容器中,恢復到上一次儲存的上下文環境
//用save方法,儲存了當前設定
ctx.save();
ctx.shadowOffsetX = 10;
ctx.shadowOffsetY = 10;
ctx.shadowBlur = 5;
ctx.shadowColor = 'rgba(0,0,0,0.5)';
//繪製了一個有陰影的矩形
ctx.fillStyle = '#CC0000';
ctx.fillRect(10,10,150,100);
//使用restore方法,恢復了儲存前的設定
ctx.restore();
//繪製了一個沒有陰影的矩形
ctx.fillStyle = '#000000';
ctx.fillRect(180,10,150,100);
複製程式碼
- 路徑容器
- 每次呼叫路徑api時,都會往路徑容器裡做登記
- 呼叫
beginPath
時,清空整個路徑容器
ctx.save();
//關於樣式的設定
ctx.beginPath();
//關於路徑的設定
ctx.restore();
複製程式碼
變換
translate(x, y)
:將canvas座標原點移動到(x,y),translate是累加的rotate(angle)
:圍繞原點旋轉影象angle弧度(順時針),rotate是累加的scale(x, y)
:縮放影象;x和y分別是橫軸和縱軸的縮放因子(正值),scale是累加的- 比 1.0 小:縮小
- 比 1.0 大:放大
- 為 1.0 時什麼效果都沒有
(1)繪製矩形
//填充矩形(x, y是橫縱座標,原點在canvas的左上角)
ctx.fillRect(x, y, width, height);
//邊框矩形,預設1px 黑色。
ctx.strokeRect(x, y, width, height);
//清除指定的矩形區域,變為透明
ctx.clearRect(x, y, width, height); //繪製動態效果時,常用來清除整個畫布
複製程式碼
rect(x, y, width, height)
:繪製矩形路徑
(2)繪製路徑
//新建路徑,beginPath是繪製新圖形的開始
ctx.beginPath()
//路徑(線)的起點,一般在上面這條命令後執行
ctx.moveTo(x, y)
//線的終點
ctx.lineTo(x, y)
//閉合路徑,不是必須的,如果線的終點跟起點一樣,會自動閉合。
ctx.closePath()
//通過線條繪製輪廓(邊框)
ctx.stroke() //不會自動呼叫closePath()
//通過路徑填充區域(實心)
ctx.fill() //自動呼叫closePath()
複製程式碼
例:繪製一個三角形
ctx.beginPath();
ctx.moveTo(75, 50); //路徑起點
ctx.lineTo(100, 75);
ctx.lineTo(100, 25);
ctx.fill(); //自動將路徑閉合,並預設填充黑色。
複製程式碼
quadraticCurveTo(cp1x, cp1y, x, y)
:繪製二次貝塞爾曲線,cp1x,cp1y為一個控制點,起始點為moveto時指定的點,x,y為結束點。bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y)
:繪製三次貝塞爾曲線,cp1x,cp1y為控制點一,cp2x,cp2y為控制點二,起始點為moveto時指定的點,x,y為結束點。ctx.isPointInPath(x, y)
:判斷在當前路徑中是否包含檢測點- x:檢測點的X座標
- y:檢測點的Y座標
- 注意,此方法只作用於最新畫出的canvas影象
(3)繪製文字
fillText(string, x, y)
:在指定的(x,y)位置填充指定的文字- 4個引數:文字字串、起點的x座標、y座標、可選的最大畫素寬度。
strokeText(string, x, y)
:在指定的(x,y)位置填充指定的文字
// 設定字型,必須要有大小和字型
ctx.font = "Bold 20px Arial";
// 設定對齊方式,可選值包括: left, right center
ctx.textAlign = "left";
// 設定填充顏色
ctx.fillStyle = "#008600";
// 設定字型內容,以及在畫布上的位置
ctx.fillText("Hello!", 10, 50);
// 繪製空心字
ctx.strokeText("Hello!", 10, 100);
複製程式碼
measureText()
方法:返回一個TextMetrics 物件,包含關於文字尺寸的資訊(例如文字的寬度)
(4)繪製圓形和扇形
//繪製圓形
ctx.arc(x, y, r, start, end, true/false) //(x, y)圓心,r半徑,start和end是開始和結束角度,false表示順時針(預設),true表示逆時針。
//繪製弧線
ctx.arcTo(x1, y1, x2, y2, r); //當前端點、(x1,y1)和(x2,y2)這三個點連成的弧線,r是半徑。
複製程式碼
例:繪製實心的圓形
ctx.beginPath();
ctx.arc(60, 60, 50, 0, Math.PI*2, true);
ctx.fillStyle = "#000000";
ctx.fill();
複製程式碼
例:繪製空心圓形
ctx.beginPath();
ctx.arc(60, 60, 50, 0, Math.PI*2, true);
ctx.lineWidth = 1.0;
ctx.strokeStyle = "#000";
ctx.stroke();
複製程式碼
(5)設定陰影
ctx.shadowOffsetX = 10; // 設定水平位移
ctx.shadowOffsetY = 10; // 設定垂直位移
ctx.shadowBlur = 5; // 設定模糊度
ctx.shadowColor = "rgba(0,0,0,0.5)"; // 設定陰影顏色
ctx.fillStyle = "#CC0000";
ctx.fillRect(10,10,200,100);
複製程式碼
(6)設定漸變
createLinearGradient(x1, y1, x2, y2)
:建立一個canvas漸變(線性漸變)- 漸變起點 (x1,y1) 與終點 (x2,y2)
gradient.addColorStop(position, color)
gradient
:createLinearGradient
的返回值addColorStop
方法接受 2 個引數:position
引數必須是一個 0.0 與 1.0 之間的數值,表示漸變中顏色所在的相對位置,例如,0.5 表示顏色會出現在正中間。color
引數必須是一個有效的 CSS 顏色值,如 #FFF, rgba(0,0,0,1)等等
//建立一個canvas線性漸變,返回`CanvasGradient`物件的例項
var myGradient = ctx.createLinearGradient(0, 0, 0, 160);
myGradient.addColorStop(0, "#BABABA");
myGradient.addColorStop(1, "#636363");
//繪製漸變填充的矩形
ctx.fillStyle = myGradient;
ctx.fillRect(10,10,200,100);
複製程式碼
createRadialGradient(x1, y1, r1, x2, y2, r2)
:canvas漸變(徑向漸變)- 前三個引數則定義另一個以(x1,y1) 為原點,半徑為 r1 的圓
- 後三個引數則定義另一個以 (x2,y2) 為原點,半徑為 r2 的圓
影象處理方法
drawImage()方法
Canvas API 允許將影象檔案插入畫布,做法是讀取圖片後,使用
drawImage
方法在畫布內進行重繪。
- canvas操作圖片時,必須要等圖片載入完才能操作
drawImage(image, x, y, width, height)
image
:影象檔案的DOM元素x
和y
:繪製該影象的起始座標width
和height
:目標寬高
var image = new Image();
image.src = 'image.png';
image.onload = function() {
var canvas = document.createElement('canvas');
canvas.width = image.width;
canvas.height = image.height;
canvas.getContext('2d').drawImage(image, 0, 0);
// 插入頁面底部
document.body.appendChild(image);
return canvas;
}
複製程式碼
createPattern()方法:設定背景模式
createPattern(image, repetition)
image
:影象源epetition
repeat
repeat-x
repeat-y
no-repeat
一般情況下,我們都會將fillstyle
的值設定為createPattern
返回的物件,只表示在某個特定的區域內顯示重複的影象。
getImageData()方法,putImageData()方法
通過
getImageData
方法和putImageData
方法,可以處理每個畫素,進而操作影象內容。
ctx.getImageData(sx, sy, sw, sh)
:獲得一個包含畫布場景畫素資料的ImageData
物件,它代表了畫布區域的物件資料- 引數
- sx:要被提取的畫面區域的 x 座標。
- sy:要被提取的畫面區域的 y 座標。
- sw:要被提取的畫素寬度。
- sh:要被提取的畫素高度。
ImageData
物件中儲存著canvas物件真實的畫素資料,它包含以下幾個只讀屬性:width
:圖片寬度,單位是畫素height
:圖片高度,單位是畫素data
:Uint8ClampedArray型別的一維陣列, 包含著RGBA
格式的整型資料,範圍在0至255之間(包括255)
- 引數
var imageData = context.getImageData(0, 0, canvas.width, canvas.height);
複製程式碼
putImageData(myImageData, dx, dy)
:把影象資料繪製到畫布上
context.putImageData(imageData, 0, 0);
複製程式碼
- 套路程式碼
假定filter是一個處理畫素的函式,那麼整個對Canvas的處理流程,可以用下面的程式碼表示。
if (canvas.width > 0 && canvas.height > 0) {
var imageData = context.getImageData(0, 0, canvas.width, canvas.height);
filter(imageData);
context.putImageData(imageData, 0, 0);
}
複製程式碼
createImageData()方法
ctx.createImageData(width, height)
:建立一個ImageData物件- width : ImageData 新物件的寬度。
- height: ImageData 新物件的高度。
- 預設建立出來的是透明的
合成
globalAlpha = value
:設定全域性透明度,這個屬性影響到 canvas 裡所有圖形的透明度- 有效的值範圍是 0.0 (完全透明)到 1.0(完全不透明)
- 預設是 1.0
globalCompositeOperation
:覆蓋合成(source--->新的影象(源);destination--->已經繪製過的圖形(目標))source-over
(預設值):源在上面,新的影象層級比較高source-in
:只留下源與目標的重疊部分(源的那一部分)source-out
:只留下源超過目標的部分source-atop
:砍掉源溢位的部分destination-over
:目標在上面,舊的影象層級比較高destination-in
:只留下源與目標的重疊部分(目標的那一部分)destination-out
:只留下目標超過源的部分destination-atop
:砍掉目標溢位的部分
toDataURL():將畫布匯出為影象
注意是canvas元素介面上的方法
function convertCanvasToImage(canvas) {
var image = new Image();
image.src = canvas.toDataURL('image/png');
return image;
}
複製程式碼
上面的程式碼將Canvas資料,轉化成PNG data URI。
常見效果
灰度效果
灰度圖(grayscale)就是取紅、綠、藍三個畫素值的算術平均值。假定d[i]是畫素陣列中一個象素的紅色值,則d[i+1]為綠色值,d[i+2]為藍色值,d[i+3]就是alpha通道值。轉成灰度的演算法,就是將紅、綠、藍三個值相加後除以3,再將結果寫回陣列。
grayscale = function (pixels) {
var d = pixels.data;
for (var i = 0; i < d.length; i += 4) {
var r = d[i];
var g = d[i + 1];
var b = d[i + 2];
d[i] = d[i + 1] = d[i + 2] = (r+g+b)/3;
}
return pixels;
};
複製程式碼
復古效果
復古效果(sepia)則是將紅、綠、藍三個畫素,分別取這三個值的某種加權平均值,使得影象有一種古舊的效果。
sepia = function (pixels) {
var d = pixels.data;
for (var i = 0; i < d.length; i += 4) {
var r = d[i];
var g = d[i + 1];
var b = d[i + 2];
d[i] = (r * 0.393)+(g * 0.769)+(b * 0.189); // red
d[i + 1] = (r * 0.349)+(g * 0.686)+(b * 0.168); // green
d[i + 2] = (r * 0.272)+(g * 0.534)+(b * 0.131); // blue
}
return pixels;
};
複製程式碼