[TOC]
## 屬性
* width
* height
> 當沒有設置寬度和高度的時候,canvas會初始化寬度為300像素和高度為150像素。
> 元素可以使用CSS來定義大小,但在繪制時圖像會伸縮以適應它的框架尺寸:如果CSS的尺寸與初始畫布的比例不一致,它會出現扭曲
>
<br />
<br />
## 渲染上下文
canvas 元素創造了一個固定大小的畫布,它公開了一個或多個渲染上下文,其可以用來繪制和處理要展示的內容。我們將會將注意力放在2D渲染上下文中。其他種類的上下文也許提供了不同種類的渲染方式;比如, WebGL 使用了基于OpenGL ES的3D上下文 ("experimental-webgl") 。
canvas起初是空白的。為了展示,首先腳本需要找到渲染上下文,然后在它的上面繪制。canvas 元素有一個叫做 [**getContext()**](https://developer.mozilla.org/zh-CN/docs/Web/API/HTMLCanvasElement/getContext) 的方法,這個方法是用來獲得渲染上下文和它的繪畫功能。getContext()只有一個參數,上下文的格式。對于2D圖像而言,可以使用 [CanvasRenderingContext2D](https://developer.mozilla.org/zh-CN/docs/Web/API/CanvasRenderingContext2D)。
~~~
var canvas = document.getElementById('tutorial');
var ctx = canvas.getContext('2d');
~~~
> 通過判斷canvas標簽是否有getContent屬性檢測瀏覽器是否支持canvas
~~~
var canvas = document.getElementById('tutorial');
if (canvas.getContext){
var ctx = canvas.getContext('2d');
// drawing code here
} else {
// canvas-unsupported code here
}
~~~
## 柵格
canvas元素默認被網格所覆蓋。通常來說網格中的一個單元相當于canvas元素中的一像素。柵格的起點為左上角(坐標為(0,0))。所有元素的位置都相對于原點定位。所以圖中藍色方形左上角的坐標為距離左邊(X軸)x像素,距離上邊(Y軸)y像素(坐標為(x,y))。

<br />
<br />
## 繪制圖形
### 繪制矩形
HTML中的元素canvas只支持一種原生的圖形繪制:矩形。所有其他的圖形的繪制都至少需要生成一條路徑。
canvas提供了三種方法繪制矩形:
~~~
// 繪制一個填充的矩形
fillRect(x, y, width, height)
~~~
~~~
// 繪制一個矩形的邊框
strokeRect(x, y, width, height)
~~~
~~~
// 繪制一個矩形的邊框
clearRect(x, y, width, height)
~~~
上面提供的方法之中每一個都包含了相同的參數。
x與y指定了在canvas畫布上所繪制的矩形的左上角(相對于原點)的坐標。
width和height設置矩形的尺寸。
<br />
### 繪制路徑
圖形的基本元素是路徑。路徑是通過不同顏色和寬度的線段或曲線相連形成的不同形狀的點的集合。一個路徑,甚至一個子路徑,都是閉合的。使用路徑繪制圖形需要一些額外的步驟。
1. 首先,你需要創建路徑起始點。
2. 然后你使用畫圖命令去畫出路徑。
3. 之后你把路徑封閉。
4. 一旦路徑生成,你就能通過描邊或填充路徑區域來渲染圖形。
以下是所要用到的函數:
~~~
// 新建一條路徑,生成之后,圖形繪制命令被指向到路徑上生成路徑
// 每次這個方法調用之后,列表清空重置,然后我們就可以重新繪制新的圖形
beginPath()
~~~
~~~
// 閉合路徑之后圖形繪制命令又重新指向到上下文中
// 這個方法會通過繪制一條從當前點到開始點的直線來閉合圖形。如果圖形是已經閉合了的,即當前點為開始點,該函數什么也不做。
closePath()
~~~
~~~
// 通過線條來繪制圖形輪廓
stroke()
~~~
~~~
// 通過填充路徑的內容區域生成實心的圖形
fill()
~~~
> 當你調用fill()函數時,所有沒有閉合的形狀都會自動閉合,所以你不需要調用closePath()函數。但是調用stroke()時不會自動閉合。
>
~~~
// 將筆觸移動到指定的坐標x以及y上
moveTo(x, y)
~~~
~~~
// 繪制一條從當前位置到指定x以及y位置的直線
lineTo(x, y)
~~~
<br />
### 圓弧
~~~
// 畫一個以(x,y)為圓心的以radius為半徑的圓弧(圓),從startAngle開始到endAngle結束,按照anticlockwise給定的方向(默認為順時針)來生成
// startAngle以及endAngle參數用弧度定義了開始以及結束的弧度。這些都是以x軸為基準。參數anticlockwise為一個布爾值。為true時,是逆時針方向,否則順時針方向。
arc(x, y, radius, startAngle, endAngle, anticlockwise)
~~~
> arc()函數中的角度單位是弧度,不是度數。角度與弧度的js表達式:radians=(Math.PI/180)*degrees。
~~~
// 根據給定的控制點和半徑畫一段圓弧,再以直線連接兩個控制點
arcTo(x1, y1, x2, y2, radius)
~~~
<br />
### 二次貝塞爾曲線及三次貝塞爾曲線
~~~
// 繪制二次貝塞爾曲線,cp1x,cp1y為一個控制點,x,y為結束點
quadraticCurveTo(cp1x, cp1y, x, y)
~~~
~~~
// 繪制三次貝塞爾曲線,cp1x,cp1y為控制點一,cp2x,cp2y為控制點二,x,y為結束點
bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y)
~~~
>參數x、y在這兩個方法中都是結束點坐標。cp1x,cp1y為坐標中的第一個控制點,cp2x,cp2y為坐標中的第二個控制點。
二次貝塞爾曲線有一個開始點(藍色)、一個結束點(藍色)以及一個控制點(紅色),而三次貝塞爾曲線有兩個控制點。

<br />
### 矩形
~~~
// 繪制一個左上角坐標為(x,y),寬高為width以及height的矩形
rect(x, y, width, height)
~~~
當該方法執行的時候,moveTo()方法自動設置坐標參數(0,0)。也就是說,當前筆觸自動重置回默認坐標。
## 樣式和顏色
### 顏色
~~~
// 設置圖形的填充顏色
fillStyle = color
// 設置圖形輪廓的顏色
strokeStyle = color
~~~
> color 可以是表示 CSS 顏色值的字符串,漸變對象或者圖案對象。
>
<br />
### 透明度
~~~
// 這個屬性影響到 canvas 里所有圖形的透明度,有效的值范圍是 0.0 (完全透明)到 1.0(完全不透明),默認是 1.0。
globalAlpha = transparencyValue
~~~
<br>
### 線型
~~~
// 設置線條寬度。
// 屬性值必須為正數。默認值是1.0。
lineWidth = value
~~~
~~~
// 設置線條末端樣式。
// 可以為下面的三種的其中之一:butt,round 和 square。默認是 butt。
lineCap = type
~~~

~~~
// 設定線條與線條間接合處的樣式。
// 值可以是round, bevel 和 miter。默認是 miter。
lineJoin = type
~~~

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

~~~
// 返回一個包含當前虛線樣式,長度為非負偶數的數組。
getLineDash()
~~~
~~~
// 設置當前虛線樣式。
setLineDash(segments)
~~~
~~~
// 設置虛線樣式的起始偏移量。
lineDashOffset = value
~~~
### 漸變
~~~
// 繪制線性漸變
// 參數表示漸變的起點 (x1,y1) 與終點 (x2,y2)。
createLinearGradient(x1, y1, x2, y2)
~~~
~~~
// 繪制徑向漸變
// 前三個參數定義一個以 (x1,y1) 為原點,半徑為 r1 的圓
// 后三個參數則定義另一個以 (x2,y2) 為原點,半徑為 r2 的圓。
createRadialGradient(x1, y1, r1, x2, y2, r2)
~~~
<br>
創建出 canvasGradient 對象后,我們就可以用 addColorStop 方法給它上色了。
<br>
~~~
// position 參數必須是一個 0.0 與 1.0 之間的數值,表示漸變中顏色所在的相對位置。例如,0.5 表示顏色會出現在正中間
// color 參數必須是一個有效的 CSS 顏色值(如 #FFF, rgba(0,0,0,1),等等)
gradient.addColorStop(position, color)
~~~
<br>
例子
~~~
function draw() {
var ctx = document.getElementById('canvas').getContext('2d');
// Create gradients
var lingrad = ctx.createLinearGradient(0,0,0,150);
lingrad.addColorStop(0, '#00ABEB');
lingrad.addColorStop(0.5, '#fff');
lingrad.addColorStop(0.5, '#26C000');
lingrad.addColorStop(1, '#fff');
// assign gradients to fill and stroke styles
ctx.fillStyle = lingrad;
// draw shapes
ctx.fillRect(10,10,130,130);
}
~~~
<br>
### 圖案樣式
~~~
// 指定的方向內重復指定的元素
// Image 可以是一個 Image 對象的引用,或者另一個 canvas 對象
// Type 必須是下面的字符串值之一:repeat,repeat-x,repeat-y 和 no-repeat
createPattern(image, type)
~~~
> 與 drawImage 有點不同,你需要確認 image 對象已經裝載完畢,否則圖案可能效果不對的。
>
~~~
function draw() {
var ctx = document.getElementById('canvas').getContext('2d');
// 創建新 image 對象,用作圖案
var img = new Image();
img.src = 'images/wallpaper.png';
img.onload = function(){
// 創建圖案
var ptrn = ctx.createPattern(img,'repeat');
ctx.fillStyle = ptrn;
ctx.fillRect(0,0,150,150);
}
}
~~~
<br>
### 陰影
~~~
// 設定陰影在 X 和 Y 軸的延伸距離,它們是不受變換矩陣所影響的。負值表示陰影會往上或左延伸,正值則表示會往下或右延伸,它們默認都為 0
shadowOffsetX = float
shadowOffsetY = float
// 設定陰影的模糊程度,其數值并不跟像素數量掛鉤,也不受變換矩陣的影響,默認為 0
shadowBlur = float
// 用于設定陰影顏色效果,默認是全透明的黑色
shadowColor = color
~~~
例子
~~~
function draw() {
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);
}
~~~
<br>
### Canvas 填充規則
當我們用到 fill(或者 clip和isPointinPath )你可以選擇一個填充規則,該填充規則根據某處在路徑的外面或者里面來決定該處是否被填充,這對于自己與自己路徑相交或者路徑被嵌套的時候是有用的。
兩個可能的值:
* "nonzero": non-zero winding rule, 默認值.
* "evenodd": even-odd winding rule.
<br>
<br>
## 文本
### 填充、繪制文本
~~~
// 在指定的(x,y)位置填充指定的文本,繪制的最大寬度是可選的
fillText(text, x, y [, maxWidth])
// 在指定的(x,y)位置繪制文本邊框,繪制的最大寬度是可選的
strokeText(text, x, y [, maxWidth])
~~~
<br>
### 文本樣式
~~~
// 當前我們用來繪制文本的樣式
// 這個字符串使用和 CSS font 屬性相同的語法. 默認的字體是 10px sans-serif
font = value
// 文本對齊選項
// 可選的值包括:start, end, left, right or center. 默認值是 start
textAlign = value
// 基線對齊選項
// 可選的值包括:top, hanging, middle, alphabetic, ideographic, bottom。默認值是 alphabetic
textBaseline = value
// 文本方向
// 可能的值包括:ltr, rtl, inherit。默認值是 inherit
direction = value
~~~
<br>
<br>
## 圖像
### 獲得需要繪制的圖片
canvas的API可以使用下面這些類型中的一種作為圖片的源:
* HTMLImageElement
這些圖片是由Image()函數構造出來的,或者任何的 img元素
* HTMLVideoElement
用一個HTML的 video元素作為你的圖片源,可以從視頻中抓取當前幀作為一個圖像
* HTMLCanvasElement
可以使用另一個 canvas 元素作為你的圖片源。
* ImageBitmap
這是一個高性能的位圖,可以低延遲地繪制,它可以從上述的所有源以及其它幾種源中生成
> 這些源統一由 CanvasImageSource類型來引用。
>
<br>
### 使用其他域名的圖片
在 HTMLImageElement上使用crossOrigin屬性,你可以請求加載其它域名上的圖片。如果圖片的服務器允許跨域訪問這個圖片,那么你可以使用這個圖片而不污染canvas,否則,使用這個圖片將會污染canvas。
這時不能再調用**toBlob()**, **toDataURL()**和**getImageData()**等方法
<br>
繪制圖片
~~~
// 其中 image 是 image 或者 canvas 對象,x 和 y 是其在目標 canvas 里的起始坐標
drawImage(image, x, y)
~~~
縮放圖片
~~~
// width 和 height,這兩個參數用來控制 當向canvas畫入時應該縮放的大小
drawImage(image, x, y, width, height)
~~~
切片
~~~
// 第一個參數是一個圖像或者另一個 canvas 的引用。
// 前4個是定義圖像源的切片位置和大小
// 后4個則是定義切片的目標顯示位置和大小
drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight)
~~~

<br>
<br>
## 變形
### 狀態的保存和恢復
**save** 和 **restore** 方法是用來保存和恢復 canvas 狀態的,都沒有參數。Canvas 的狀態就是當前畫面應用的所有樣式和變形的一個快照。
Canvas狀態存儲在棧中,每當save()方法被調用后,當前的狀態就被推送到棧中保存。一個繪畫狀態包括:
* 當前應用的變形(即移動,旋轉和縮放)
* strokeStyle, fillStyle, globalAlpha, lineWidth, lineCap, lineJoin, miterLimit, shadowOffsetX, shadowOffsetY, shadowBlur, shadowColor, globalCompositeOperation 的值
* 當前的裁切路徑(clipping path)
你可以調用任意多次 save 方法。
每一次調用 restore 方法,上一個保存的狀態就從棧中彈出,所有設定都恢復。
### 移動
~~~
// 用來移動 canvas 和它的原點到一個不同的位置
// x 是左右偏移量,y 是上下偏移量
translate(x, y)
~~~

> 在做變形之前先保存狀態是一個良好的習慣。
>
<br>
### 旋轉
~~~
// 用于以原點為中心旋轉 canvas
// 參數表示旋轉的角度(angle),它是順時針方向的,以弧度為單位的值
rotate(angle)
~~~

> 旋轉的中心點始終是 canvas 的原點,如果要改變它,我們需要用到 translate 方法
>
<br>
### 縮放
增減圖形在 canvas 中的像素數目,對形狀,位圖進行縮小或者放大。
~~~
// x,y 分別是橫軸和縱軸的縮放因子,它們都必須是正值。值比 1.0 小表示縮小,比 1.0 大則表示放大,值為 1.0 時什么效果都沒有。
scale(x, y)
~~~
默認情況下,canvas 的 1 單位就是 1 個像素。舉例說,如果我們設置縮放因子是 0.5,1 個單位就變成對應 0.5 個像素,這樣繪制出來的形狀就會是原先的一半。同理,設置為 2.0 時,1 個單位就對應變成了 2 像素,繪制的結果就是圖形放大了 2 倍。
<br>
<br>
### 變形
將當前的變形矩陣乘上一個基于自身參數的矩陣
~~~
transform(m11, m12, m21, m22, dx, dy)
~~~
矩陣如下
~~~
m11 m21 dx
m12 m22 dy
0 0 1
~~~
這個函數的參數各自代表如下:
* m11:水平方向的縮放
* m12:水平方向的傾斜偏移
* m21:豎直方向的傾斜偏移
* m22:豎直方向的縮放
* dx:水平方向的移動
* dy:豎直方向的移動
<br>
~~~
setTransform(m11, m12, m21, m22, dx, dy)
~~~
這個方法會將當前的變形矩陣重置為單位矩陣,然后用相同的參數調用 transform 方法。如果任意一個參數是無限大,那么變形矩陣也必須被標記為無限大,否則會拋出異常。從根本上來說,該方法是取消了當前變形,然后設置為指定的變形,一步完成。
<br>
重置當前變形為單位矩陣
~~~
resetTransform()
~~~
它和調用以下語句是一樣的:
~~~
ctx.setTransform(1, 0, 0, 1, 0, 0);
~~~
## 組合
### globalCompositeOperation
這個屬性設定了在畫新圖形時采用的遮蓋策略,其值是一個標識12種遮蓋方式的字符串。
* source-over 默認。在目標圖像上顯示源圖像。
* source-atop 在目標圖像頂部顯示源圖像。源圖像位于目標圖像之外的部分是不可見的。
* source-in 在目標圖像中顯示源圖像。只有目標圖像內的源圖像部分會顯示,目標圖像是透明的。
* source-out 在目標圖像之外顯示源圖像。只會顯示目標圖像之外源圖像部分,目標圖像是透明的。
* destination-over 在源圖像上方顯示目標圖像。
* destination-atop 在源圖像頂部顯示目標圖像。源圖像之外的目標圖像部分不會被顯示。
* destination-in 在源圖像中顯示目標圖像。只有源圖像內的目標圖像部分會被顯示,源圖像是透明的。
* destination-out 在源圖像外顯示目標圖像。只有源圖像外的目標圖像部分會被顯示,源圖像是透明的。
* lighter 顯示源圖像 + 目標圖像。
* copy 顯示源圖像。忽略目標圖像。
* xor 使用異或操作對源圖像與目標圖像進行組合。

<br>
### 裁剪路徑
將當前正在構建的路徑轉換為當前剪切路徑
~~~
clip()
~~~
默認情況下,canvas 有一個與它自身一樣大的裁切路徑(也就是沒有裁切效果)。
> 一旦剪切了某個區域,則所有之后的繪圖都會被限制在被剪切的區域內(不能訪問畫布上的其他區域)。您也可以在使用 clip() 方法前通過使用 save() 方法對當前畫布區域進行保存,并在以后的任意時間對其進行恢復(通過 restore() 方法)。
>
<br>
例子
~~~
function draw() {
var ctx = document.getElementById('canvas').getContext('2d');
ctx.fillRect(0,0,150,150);
ctx.translate(75,75);
// Create a circular clipping path
ctx.beginPath();
ctx.arc(0,0,60,0,Math.PI*2,true);
ctx.clip();
// draw background
var lingrad = ctx.createLinearGradient(0,-75,0,75);
lingrad.addColorStop(0, '#232256');
lingrad.addColorStop(1, '#143778');
ctx.fillStyle = lingrad;
ctx.fillRect(-75,-75,150,150);
// draw stars
for (var j=1;j<50;j++){
ctx.save();
ctx.fillStyle = '#fff';
ctx.translate(75-Math.floor(Math.random()*150),
75-Math.floor(Math.random()*150));
drawStar(ctx,Math.floor(Math.random()*4)+2);
ctx.restore();
}
}
function drawStar(ctx,r){
ctx.save();
ctx.beginPath()
ctx.moveTo(r,0);
for (var i=0;i<9;i++){
ctx.rotate(Math.PI/5);
if(i%2 == 0) {
ctx.lineTo((r/0.525731)*0.200811,0);
} else {
ctx.lineTo(r,0);
}
}
ctx.closePath();
ctx.fill();
ctx.restore();
}
~~~

<br>
<br>
## 基本的動畫
### 動畫的基本步驟
通過以下的步驟來畫出一幀:
* 清空 canvas
除非接下來要畫的內容會完全充滿 canvas (例如背景圖),否則你需要清空所有。最簡單的做法就是用 clearRect 方法。
* 保存 canvas 狀態
如果你要改變一些會改變 canvas 狀態的設置(樣式,變形之類的),又要在每畫一幀之時都是原始狀態的話,你需要先保存一下。
* 繪制動畫圖形
這一步才是重繪動畫幀。
* 恢復 canvas 狀態
如果已經保存了 canvas 的狀態,可以先恢復它,然后重繪下一幀
<br>
### 操控動畫
通過 **setInterval** 、 **setTimeout** 和 **requestAnimationFrame** 方法來控制在設定的時間點上執行重繪。
如果我們需要做一個游戲,我們可以使用鍵盤或者鼠標事件配合上setTimeout()方法來實現。通過設置事件監聽,我們可以捕捉用戶的交互,并執行相應的動作。
<br>
<br>
## 像素操作
### ImageData對象
ImageData對象中存儲著canvas對象真實的像素數據,它包含以下幾個只讀屬性:
* width: 圖片寬度,單位是像素
* height: 圖片高度,單位是像素
* data: Uint8ClampedArray類型的一維數組,包含著RGBA格式的整型數據,范圍在0至255之間(包括255)
data屬性返回一個 Uint8ClampedArray,它可以被使用作為查看初始像素數據。每個像素用4個1bytes值(按照紅,綠,藍和透明值的順序; 這就是"RGBA"格式) 來代表。每個顏色值部份用0至255來代表。每個部份被分配到一個在數組內連續的索引,左上角像素的紅色部份在數組的索引0位置。像素從左到右被處理,然后往下,遍歷整個數組。
Uint8ClampedArray 包含**高度 × 寬度 × 4** bytes數據,索引值從0到(高度×寬度×4)-1
<br>
### 創建一個ImageData對象
創建了一個新的具體特定尺寸的ImageData對象。所有像素被預設為透明黑。
~~~
var myImageData = ctx.createImageData(width, height);
~~~
創建一個被anotherImageData對象指定的相同像素的ImageData對象。這個新的對象像素全部被預設為透明黑。這個并非復制了圖片數據。
~~~
var myImageData = ctx.createImageData(anotherImageData);
~~~
<br>
### 得到場景像素數據
這個方法會返回一個ImageData對象,它代表了畫布區域的對象數據,此畫布的四個角落分別表示為(left, top), (left + width, top), (left, top + height), 以及(left + width, top + height)四個點。這些坐標點被設定為畫布坐標空間元素。
~~~
var myImageData = ctx.getImageData(left, top, width, height);
~~~
> 任何在畫布以外的元素都會被返回成一個透明黑的ImageData對像。
>
<br>
**例子:顏色選擇器**
我們會使用getImageData()去展示鼠標光標下的顏色。為此,我們要當前鼠標的位置,記為layerX和layerY,然后我們去查詢getImageData()給我們提供的在那個位置的像數數組里面的像素數據。最后我們使用數組數據去設置背景顏色和<div>的文字去展示顏色值。
~~~
var img = new Image();
img.src = 'https://mdn.mozillademos.org/files/5397/rhino.jpg';
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
img.onload = function() {
ctx.drawImage(img, 0, 0);
img.style.display = 'none';
};
var color = document.getElementById('color');
function pick(event) {
var x = event.layerX;
var y = event.layerY;
var pixel = ctx.getImageData(x, y, 1, 1);
var data = pixel.data;
var rgba = 'rgba(' + data[0] + ',' + data[1] +
',' + data[2] + ',' + (data[3] / 255) + ')';
color.style.background = rgba;
color.textContent = rgba;
}
canvas.addEventListener('mousemove', pick);
~~~
<br>
### 在場景中寫入像素數據
~~~
ctx.putImageData(myImageData, dx, dy);
~~~
dx 和 dy參數表示你希望在場景內左上角繪制的像素數據所得到的設備坐標。
**例子:圖片灰度和反相顏色**
在這個例子里,我們遍歷所有像素以改變他們的數值。然后我們將被修改的像素數組通過putImageData()放回到畫布中去。invert函數僅僅是去減掉顏色的最大色值255.grayscale函數僅僅是用紅綠和藍的平均值。你也可以用加權平均,例如x = 0.299r + 0.587g + 0.114b這個公式。[更多資料請參考維基百科的Grayscale](https://en.wikipedia.org/wiki/Grayscale)。
~~~
var img = new Image();
img.src = 'https://mdn.mozillademos.org/files/5397/rhino.jpg';
img.onload = function() {
draw(this);
};
function draw(img) {
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
ctx.drawImage(img, 0, 0);
img.style.display = 'none';
var imageData = ctx.getImageData(0,0,canvas.width, canvas.height);
var data = imageData.data;
var invert = function() {
for (var i = 0; i < data.length; i += 4) {
data[i] = 225 - data[i]; // red
data[i + 1] = 225 - data[i + 1]; // green
data[i + 2] = 225 - data[i + 2]; // blue
}
ctx.putImageData(imageData, 0, 0);
};
var grayscale = function() {
for (var i = 0; i < data.length; i += 4) {
var avg = (data[i] + data[i +1] + data[i +2]) / 3;
data[i] = avg; // red
data[i + 1] = avg; // green
data[i + 2] = avg; // blue
}
ctx.putImageData(imageData, 0, 0);
};
var invertbtn = document.getElementById('invertbtn');
invertbtn.addEventListener('click', invert);
var grayscalebtn = document.getElementById('grayscalebtn');
grayscalebtn.addEventListener('click', grayscale);
}
~~~
<br>
### 縮放和反鋸齒
我們得到鼠標的位置并裁剪出距左和上5像素,距右和下5像素的圖片。然后我們將這幅圖復制到另一個畫布然后將圖片調整到我們想要的大小。在縮放畫布里,我們將10×10像素的對原畫布的裁剪調整為 200×200 。
~~~
zoomctx.drawImage(canvas,
Math.abs(x - 5), Math.abs(y - 5),
10, 10, 0, 0, 200, 200);
~~~
<br>
CanvasRenderingContext2D.imageSmoothingEnabled 是 Canvas 2D API 用來設置圖片是否平滑的屬性,true表示圖片平滑(默認值),false表示圖片不平滑。當我們獲取 imageSmoothingEnabled 屬性值時, 它會返回最新設置的值。
~~~
// 一個Boolean 類型的值,表示圖片是否平滑。
ctx.imageSmoothingEnabled = value;
~~~
以縮放畫布為例,這個屬性對像素為主的游戲很有用。默認的改變大小的算法會造成圖片模糊并且破壞圖片原有的像素。 如果那樣的話,設置屬性值為false。
**例子**
~~~
<canvas id="canvas" width="300" height="227"></canvas>
<canvas id="zoom" width="300" height="227"></canvas>
<div>
<label for="smoothbtn">
? <input type="checkbox" name="smoothbtn" checked="checked" id="smoothbtn">
? Enable image smoothing
</label>
</div>
var img = new Image();
img.src = 'https://mdn.mozillademos.org/files/5397/rhino.jpg';
img.onload = function() {
draw(this);
};
function draw(img) {
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
ctx.drawImage(img, 0, 0);
img.style.display = 'none';
var zoomctx = document.getElementById('zoom').getContext('2d');
var smoothbtn = document.getElementById('smoothbtn');
var toggleSmoothing = function(event) {
zoomctx.imageSmoothingEnabled = this.checked;
zoomctx.mozImageSmoothingEnabled = this.checked;
zoomctx.webkitImageSmoothingEnabled = this.checked;
zoomctx.msImageSmoothingEnabled = this.checked;
};
smoothbtn.addEventListener('change', toggleSmoothing);
var zoom = function(event) {
var x = event.layerX;
var y = event.layerY;
zoomctx.drawImage(canvas,
Math.abs(x - 5),
Math.abs(y - 5),
10, 10,
0, 0,
200, 200);
};
canvas.addEventListener('mousemove', zoom);
}
~~~
<br>
### 保存圖片
當你從畫布中生成了一個數據鏈接,例如,你可以將它用于任何<image>元素,或者將它放在一個有download屬性的超鏈接里用于保存到本地
~~~
// 默認設定。創建一個PNG圖片
canvas.toDataURL('image/png')
// 創建一個JPG圖片。你可以有選擇地提供從0到1的品質量,1表示最好品質,0基本不被辨析但有比較小的文件大小
canvas.toDataURL('image/jpeg', quality)
~~~
你也可以從畫布中創建一個Blob對象。
~~~
// 這個創建了一個在畫布中的代表圖片的Blob對象
canvas.toBlob(callback, type, encoderOptions)
~~~
- 第一部分 HTML
- meta
- meta標簽
- HTML5
- 2.1 語義
- 2.2 通信
- 2.3 離線&存儲
- 2.4 多媒體
- 2.5 3D,圖像&效果
- 2.6 性能&集成
- 2.7 設備訪問
- SEO
- Canvas
- 壓縮圖片
- 制作圓角矩形
- 全局屬性
- 第二部分 CSS
- CSS原理
- 層疊上下文(stacking context)
- 外邊距合并
- 塊狀格式化上下文(BFC)
- 盒模型
- important
- 樣式繼承
- 層疊
- 屬性值處理流程
- 分辨率
- 視口
- CSS API
- grid(未完成)
- flex
- 選擇器
- 3D
- Matrix
- AT規則
- line-height 和 vertical-align
- CSS技術
- 居中
- 響應式布局
- 兼容性
- 移動端適配方案
- CSS應用
- CSS Modules(未完成)
- 分層
- 面向對象CSS(未完成)
- 布局
- 三列布局
- 單列等寬,其他多列自適應均勻
- 多列等高
- 圣杯布局
- 雙飛翼布局
- 瀑布流
- 1px問題
- 適配iPhoneX
- 橫屏適配
- 圖片模糊問題
- stylelint
- 第三部分 JavaScript
- JavaScript原理
- 內存空間
- 作用域
- 執行上下文棧
- 變量對象
- 作用域鏈
- this
- 類型轉換
- 閉包(未完成)
- 原型、面向對象
- class和extend
- 繼承
- new
- DOM
- Event Loop
- 垃圾回收機制
- 內存泄漏
- 數值存儲
- 連等賦值
- 基本類型
- 堆棧溢出
- JavaScriptAPI
- document.referrer
- Promise(未完成)
- Object.create
- 遍歷對象屬性
- 寬度、高度
- performance
- 位運算
- tostring( ) 與 valueOf( )方法
- JavaScript技術
- 錯誤
- 異常處理
- 存儲
- Cookie與Session
- ES6(未完成)
- Babel轉碼
- let和const命令
- 變量的解構賦值
- 字符串的擴展
- 正則的擴展
- 數值的擴展
- 數組的擴展
- 函數的擴展
- 對象的擴展
- Symbol
- Set 和 Map 數據結構
- proxy
- Reflect
- module
- AJAX
- ES5
- 嚴格模式
- JSON
- 數組方法
- 對象方法
- 函數方法
- 服務端推送(未完成)
- JavaScript應用
- 復雜判斷
- 3D 全景圖
- 重載
- 上傳(未完成)
- 上傳方式
- 文件格式
- 渲染大量數據
- 圖片裁剪
- 斐波那契數列
- 編碼
- 數組去重
- 淺拷貝、深拷貝
- instanceof
- 模擬 new
- 防抖
- 節流
- 數組扁平化
- sleep函數
- 模擬bind
- 柯里化
- 零碎知識點
- 第四部分 進階
- 計算機原理
- 數據結構(未完成)
- 算法(未完成)
- 排序算法
- 冒泡排序
- 選擇排序
- 插入排序
- 快速排序
- 搜索算法
- 動態規劃
- 二叉樹
- 瀏覽器
- 瀏覽器結構
- 瀏覽器工作原理
- HTML解析
- CSS解析
- 渲染樹構建
- 布局(Layout)
- 渲染
- 瀏覽器輸入 URL 后發生了什么
- 跨域
- 緩存機制
- reflow(回流)和repaint(重繪)
- 渲染層合并
- 編譯(未完成)
- Babel
- 設計模式(未完成)
- 函數式編程(未完成)
- 正則表達式(未完成)
- 性能
- 性能分析
- 性能指標
- 首屏加載
- 優化
- 瀏覽器層面
- HTTP層面
- 代碼層面
- 構建層面
- 移動端首屏優化
- 服務器層面
- bigpipe
- 構建工具
- Gulp
- webpack
- Webpack概念
- Webpack工具
- Webpack優化
- Webpack原理
- 實現loader
- 實現plugin
- tapable
- Webpack打包后代碼
- rollup.js
- parcel
- 模塊化
- ESM
- 安全
- XSS
- CSRF
- 點擊劫持
- 中間人攻擊
- 密碼存儲
- 測試(未完成)
- 單元測試
- E2E測試
- 框架測試
- 樣式回歸測試
- 異步測試
- 自動化測試
- PWA
- PWA官網
- web app manifest
- service worker
- app install banners
- 調試PWA
- PWA教程
- 框架
- MVVM原理
- Vue
- Vue 餓了么整理
- 樣式
- 技巧
- Vue音樂播放器
- Vue源碼
- Virtual Dom
- computed原理
- 數組綁定原理
- 雙向綁定
- nextTick
- keep-alive
- 導航守衛
- 組件通信
- React
- Diff 算法
- Fiber 原理
- batchUpdate
- React 生命周期
- Redux
- 動畫(未完成)
- 異常監控、收集(未完成)
- 數據采集
- Sentry
- 貝塞爾曲線
- 視頻
- 服務端渲染
- 服務端渲染的利與弊
- Vue SSR
- React SSR
- 客戶端
- 離線包
- 第五部分 網絡
- 五層協議
- TCP
- UDP
- HTTP
- 方法
- 首部
- 狀態碼
- 持久連接
- TLS
- content-type
- Redirect
- CSP
- 請求流程
- HTTP/2 及 HTTP/3
- CDN
- DNS
- HTTPDNS
- 第六部分 服務端
- Linux
- Linux命令
- 權限
- XAMPP
- Node.js
- 安裝
- Node模塊化
- 設置環境變量
- Node的event loop
- 進程
- 全局對象
- 異步IO與事件驅動
- 文件系統
- Node錯誤處理
- koa
- koa-compose
- koa-router
- Nginx
- Nginx配置文件
- 代理服務
- 負載均衡
- 獲取用戶IP
- 解決跨域
- 適配PC與移動環境
- 簡單的訪問限制
- 頁面內容修改
- 圖片處理
- 合并請求
- PM2
- MongoDB
- MySQL
- 常用MySql命令
- 自動化(未完成)
- docker
- 創建CLI
- 持續集成
- 持續交付
- 持續部署
- Jenkins
- 部署與發布
- 遠程登錄服務器
- 增強服務器安全等級
- 搭建 Nodejs 生產環境
- 配置 Nginx 實現反向代理
- 管理域名解析
- 配置 PM2 一鍵部署
- 發布上線
- 部署HTTPS
- Node 應用
- 爬蟲(未完成)
- 例子
- 反爬蟲
- 中間件
- body-parser
- connect-redis
- cookie-parser
- cors
- csurf
- express-session
- helmet
- ioredis
- log4js(未完成)
- uuid
- errorhandler
- nodeclub源碼
- app.js
- config.js
- 消息隊列
- RPC
- 性能優化
- 第七部分 總結
- Web服務器
- 目錄結構
- 依賴
- 功能
- 代碼片段
- 整理
- 知識清單、博客
- 項目、組件、庫
- Node代碼
- 面試必考
- 91算法
- 第八部分 工作代碼總結
- 樣式代碼
- 框架代碼
- 組件代碼
- 功能代碼
- 通用代碼