學習canvas基礎的總結

jiangxin0211發表於2018-12-19

簡單介紹canvas

<canvas><img>標籤很像,但是沒有src和alt屬性,只有width和height屬性。 css定義的尺寸與canvas的尺寸比例不一致時,會出現扭曲。

canvas起初是空白的,要找到渲染上下文來繪製。 getContext() 該方法用來獲取渲染上下文和繪製功能。

var canvas = document.getElementById('myCanvas');
var ctx = canvas.getContext('2d');// 需要檢查支援性,是否支援canvas.getContext
複製程式碼

矩形

fillRect(x, y, width, height);// 填充矩形
strokeRect(x, y, width, height);//矩形邊框
clearRect(x, y, width,height);// 清除指定矩形區域,清除部分為透明的
複製程式碼

繪製路徑:

  • 建立路徑的起始點
  • 使用畫圖命令,畫出路徑
  • 路徑封閉
  • 路徑生成,繪製圖形(描邊,填充)

beginPath()
新建一條路徑,生成之後,圖形繪製命令被指向到路徑上生成路徑。
列表清空重置,重新繪製新的圖形。

closePath()
閉合路徑之後圖形繪製命令又重新指向到上下文中。
非必需,當你呼叫fill()函式時,所有沒有閉合的形狀都會自動閉合,所以你不需要呼叫closePath()函式。但是呼叫stroke()時不會自動閉合。

stroke()
通過線條來繪製圖形。如果用線條繪製必須用closePath()來閉合曲線。

fill()
通過填充路徑的內容區域生成實心的圖形。

moveTo(x, y)
將筆觸移動到x,y座標點處。

lineTo(x, y)
繪製直線。

arc(x, y, radius, startAngle, endAngle, anticlockwise)
圓心座標,半徑,起始角度,結束角度,false順時針,true逆時針。
三點鐘方向為0°(弧度),弧度=(Math.PI/180)*角度。

arcTo(x1, y1, x2, y2, radius)
根據給定的控制點和半徑畫一段圓弧,再以直線連線兩個控制點。

rect(x, y, width, height)
繪製一個左上角座標為(x,y),寬高為width以及height的矩形。筆觸自動置回(0,0)。

quadraticCurveTo(cp1x, cp1y, x,y)
繪製二次貝塞爾曲線,cp1x,cp1y為一個控制點,x,y為結束點。

bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y)
繪製三次貝塞爾曲線,cp1x,cp1y為控制點一,cp2x,cp2y為控制點二,x,y為結束點。藍色是起始點和結束點,紅色是控制點。

學習canvas基礎的總結

path2D物件:用來快取和記錄繪畫命令,可快速回顧繪製路徑。

Path2D()會返回一個新初始化的Path2D物件(可能將某一個路徑作為變量——建立一個它的副本,或者將一個包含SVG path資料的字元串作為變量)。

new Path2D(); // 空的Path物件
new Path2D(path); // 克隆Path物件
new Path2D(d); // 從SVG建立Path物件
Path2D.addPath(path [, transform]);// 新增了一條路徑到當前路徑(可能新增了一個變換矩陣)。
複製程式碼

新的Path2D API有另一個強大的特點,就是使用SVG path data來初始化canvas上的路徑。這將使你獲取路徑時可以以SVG或canvas的方式來重用它們。

var p = new Path2D("M10 10 h 1 80 v 80 h -80 Z");// 將先移動到點 (M10 10) 然後再水平移動80個單位(h 80),然後下移80個單位 (v80),接著左移80個單位 (h -80),再回到起點處 ( z)。
複製程式碼

透明度:TransparencyValue

globalAlpha = transparencyValue;// 有效值(0.0~1.0),完全透明~完全不透明
複製程式碼

線性樣式

lineWidth = value
設定線條寬度。屬性值必須為正數。預設值是1.0。

lineCap = type
設定線條末端樣式。type的值有buttroundsquare。預設是 butt

lineJoin = type
設定線條與線條間接合處的樣式。round, bevelmiter。預設是 miter

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

getLineDash()
返回一個包含當前虛線樣式,長度為非負偶數的陣列。

setLineDash(segments)
設定當前虛線樣式。

lineDashOffset = value
設定虛線樣式的起始偏移量。
setLineDash方法和 lineDashOffset 屬性來制定虛線樣式。
setLineDash方法接受一個陣列,來指定線段與間隙的交替;
lineDashOffset 屬性設定起始偏移量。

漸變:以用線性或者徑向的漸變來填充或描邊

新建一個 canvasGradient 物件,並且賦給圖形的 fillStyle 或 strokeStyle 屬性。

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 的圓。
gradient.addColorStop(position, color)
addColorStop 方法接受 2 個引數,position 引數必須是一個 0.0 與 1.0 之間的數值,表示漸變中顏色所在的相對位置。

圖案樣式patterns

createPattern(image, type)
該方法接受兩個引數。Image 可以是一個 Image物件的引用,或者另一個 canvas物件。
Type 必須是下面的字元串值之一:repeatrepeat-xrepeat-yno-repeat

陰影shadow

shadowOffsetX = float;
shadowOffsetY = float複製程式碼

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

shadowBlur = float
複製程式碼

shadowBlur 用於設定陰影的模糊程度,其數值並不跟畫素數量掛鉤,也不受變換矩陣的影響,預設為 0。

shadowColor = color
複製程式碼

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

canvas填充規則:

  • nonzero:non-zero winding rule, 預設值. 填充
  • evenodd: even-odd winding rule,鏤空

動畫:

  1. 清空canvas:clearRect();
  2. 儲存canvas狀態
  3. 繪製動畫圖形:重繪動畫幀
  4. 恢復canvas狀態:如果已經儲存了 canvas的狀態,可以先恢復它,然後重繪下一幀。

你可以使用setInterval()方法,它就可以定期執行指定程式碼。如果我們需要做一個遊戲,我們可以使用鍵盤或者滑鼠事件配合上setTimeout()方法來實現。通過設定事件監聽,我們可以捕捉使用者的互動,並執行相應的動作。 採用window.requestAnimationFrame()實現動畫效果。這個方法提供了更加平緩並更加有效率的方式來執行動畫,當系統準備好了重繪條件的時候,才呼叫繪製動畫幀。一般每秒鐘回撥函式執行60次,也有可能會被降低。

變形transformations:

save()restore(): save 和 restore 方法是用來儲存和恢復 canvas 狀態的,canvas的狀態儲存在棧中。
tanslate(x, y); 左右,上下平移。
rotate旋轉。
scale縮放。
transform(m11, m12, m21, m22, dx, dy) 這個方法是將當前的變形矩陣乘上一個基於自身引數的矩陣,在這里我們用下面的矩陣

m11   m21   dx    
m12   m22   dy  
0     0     1    
複製程式碼
 m11:水平方向的縮放     
 m12:水平方向的傾斜偏移     
 m21:豎直方向的傾斜偏移     
 m22:豎直方向的縮放 
 dx:水平方向的移動
 dy:豎直方向的移動
複製程式碼
 setTransform(m11, m12, m21, m22, dx, dy)
 resetTransform()
複製程式碼

canvas優化

使用requestAnimationFrame進行動畫迴圈

setTimeoutsetInterval並非是專為連續迴圈產生的 API,所以可能無法達到流暢的動畫表現,故用 requestAnimationFrame,可能需要polyfill

const raf = window.requestAnimationFrame
  || window.webkitRequestAnimationFrame
  || window.mozRequestAnimationFrame
  || window.oRequestAnimationFrame
  || window.msRequestAnimationFrame
  || function(callback) {
    window.setTimeout(callback, 1000 / 60)
  }
複製程式碼

利用剪輯區域來處理動畫背景或其他不變的影像

背景比較複雜可以使用剪輯區域技術,通過每幀較少的繪製來獲得較好的效能。

利用剪輯區域技術來恢復上一幀動畫所佔背景圖的執行步驟:

  • 呼叫 context.save(),儲存螢幕 canvas的狀態
  • 通過呼叫 beginPath來開始一段新的路徑
  • 在 context物件上呼叫 arc()、rect()等方法來設定路徑
  • 呼叫 context.clip()方法,將當前路徑設定為螢幕 canvas的剪輯區域
  • 擦除螢幕 canvas中的影像(實際上只會擦除剪輯區域所在的這一塊範圍)
  • 將背景影像繪製到螢幕canvas上(繪製操作實際上只會影響剪輯區域所在的範圍,所以每幀繪製影像畫素數更少)
  • 恢復螢幕 canvas的狀態引數,重置剪輯區域

離屏緩衝區(離屏canvas)

先繪製到一個離屏 canvas中,然後再通過 drawImage把離屏 canvas 畫到主 canvas中,就是把離屏 canvas當成一個快取區。把需要重複繪製的畫面資料進行快取起來,減少呼叫 canvas的 API的消耗。

const cacheCanvas = document.createElement('canvas')
const cacheCtx = cacheCanvas.getContext('2d')
cacheCtx.width = 200
cacheCtx.height = 200
// 繪製到主canvas上
ctx.drawImage(0, 0)
複製程式碼

必要時,可以使用多個離屏 canvas另外,離屏canvas不再使用時,最好把手動將引用重置為 null,避免因為 js和dom之間存在的關聯,導致垃圾回收機制無法正常工作,佔用資源。

儘量利用CSS

儘量少的呼叫 canvas API

相比於正常的js操作,頻繁的呼叫canvasAPI更加消耗資源。

避免阻塞

在進行某些耗時操作,例如計算大量資料,一幀中包含了太多的繪製狀態,大規模的 DOM操作等,可能會導致頁面卡頓,影響使用者體驗,可以通過以下兩種手段:

  • web worker
    web worker最常用的場景就是大量的頻繁計算,減輕主執行緒壓力,如果遇到大規模的計算,可以通過此 API分擔主執行緒壓力,此 API相容性已經很不錯了,既然 canvas可以用,那 web worker也就完全可以考慮使用。

  • 分解任務
    滿足:
    1.迴圈處理操作並不要求同步
    2.資料並不要求按照順序處理

      根據任務總量分配:   
      根據執行時間分配:
    複製程式碼

以上內容均是看文件學習歸納的常用的基礎的知識點,覺得有用的小夥伴點個小心心吧

相關文章