繪製矩形
// 填充矩形
ctx.fillRect(
// x y
10, 10,
// width height
120, 120
)
// 描邊矩形
ctx.strokeRect(
// x y
180, 10,
// width height
120, 120
)
// 清除矩形:將指定矩形與當前剪輯區域相交範圍內所有畫素清除
ctx.clearRect(
// x y
0, 0,
// width height
canvas.width, canvas.height
)
複製程式碼
畫素清除
將其顏色設定為全透明的黑色,等同於清除某個畫素
圖示
樣式設定
API
// 設定描邊樣式
ctx.strokeStyle="color|gradient|pattern"
// 設定填充樣式
ctx.fillStyle="color|gradient|pattern"
複製程式碼
設定顏色
ctx.strokeStyle = 'red'
ctx.fillStyle = 'rgba(0,0,0,0.5)'
ctx.fillStyle = '#000'
複製程式碼
設定漸變色
線性漸變
點1到點2的線性漸變
const gradient = ctx.createLinearGradient(
// 點1
x1, y1,
// 點2
x2, y2
)
gradient.addColorStop(0, 'blue')
gradient.addColorStop(0.25, 'yellow')
gradient.addColorStop(0.8, 'pink')
複製程式碼
放射漸變
以
x1,y1
為圓心,半徑為radius1
的圓 到 以x2,y2
為圓心,半徑為radius2
的圓 的放射漸變
const gradient = ctx.createRadialGradient(
// x1, y1, radius1
canvas.width / 2, 0, 10,
// x2, y2, radius2
canvas.width / 2, canvas.height, 100
)
// 顏色停止點 ([0~1],'color')
gradient.addColorStop(0, 'blue')
gradient.addColorStop(0.25, 'yellow')
gradient.addColorStop(0.8, 'pink')
複製程式碼
設定圖案
const image = new Image()
image.src = '/img/redball.png'
image.onload = () => {
ctx.fillStyle = ctx.createPattern(
image,
// 圖案重複情況 repeat-x no-repeat...
'repeat'
)
ctx.fillRect(
0, 0,
canvas.width, canvas.height
)
}
複製程式碼
陰影
偏移量為負數有內嵌陰影的效果,陰影顏色建議用帶透明度的顏色
// x 偏移
ctx.shadowOffsetX = 4
// y 偏移
ctx.shadowOffsetY = 6
// 陰影顏色
ctx.shadowColor = 'rgba(0,0,0,1)'
// 高斯模糊
ctx.shadowBlur = 10
ctx.strokeRect(10, 10, 100, 100)
複製程式碼
路徑
繪製方法
// 使用fillStyle對當前路徑的內部進行填充
ctx.fill()
// 使用strokeStyle來描繪當前路徑的輪廓線
ctx.stroke()
複製程式碼
路徑形狀
需要呼叫fill()或stroke()進行繪製
** 建立路徑後對齊進行描邊或填充**
- 好比使用隱形筆繪製好(rect,arc)
- 然後用加熱等讓其顯式出來(stroke,fill)
// 繪製矩形路徑。預設是逆時針繪製
ctx.rect(
// x y
40, 120,
// width height
100, 100
)
// 圓弧路徑
ctx.arc(
x,y,
radius,
startAngle,endAngle,
// 逆時針
anticlockwise=false
)
// 圓弧之 arcTo
複製程式碼
beginPath和closePath
// 將當前路徑之中的所有子路徑都清除,重置當前路徑,在需要開始一段新的路徑時,需要呼叫此方法
ctx.beginPath()
// 顯式封閉某段開放路徑
ctx.closePath()
複製程式碼
對比有無beginPath
ctx.beginPath() // 1
ctx.strokeStyle = 'blue'
ctx.lineWidth = 10
ctx.rect(50, 50, 100, 100)
ctx.stroke()
// 沒有開始新的路徑,會從1處再次繪製
ctx.strokeStyle = 'red'
ctx.lineWidth = 5
ctx.rect(50, 200, 100, 100)
ctx.stroke()
ctx.beginPath() // -> 2
ctx.strokeStyle = 'blue'
ctx.lineWidth = 10
ctx.rect(250, 50, 100, 100)
ctx.stroke()
// 此處開始了新的路徑
ctx.beginPath()
ctx.strokeStyle = 'red'
ctx.lineWidth = 5
ctx.rect(250, 200, 100, 100)
ctx.stroke()
複製程式碼
左邊一列的明顯將左上的矩形再次繪製了一次
對比有無closePath
主要用於封閉圓弧路徑或由曲線或線段組成的開放路徑
ctx.beginPath()
ctx.arc(100, 100, 40, 0, Math.PI * 3 / 2)
ctx.stroke()
ctx.beginPath()
ctx.arc(240, 100, 40, 0, Math.PI * 3 / 2)
ctx.closePath()
ctx.stroke()
複製程式碼
非零環繞規則
定義
只要位置上存在包含關係的繪製方向不一致即有剪紙效果
ctx.shadowBlur = 10
ctx.shadowOffsetX = 2
ctx.shadowOffsetY = 10
ctx.shadowColor = 'rgba(0,0,0,0.3)'
ctx.beginPath()
// 只要兩個圓弧的繪製方向不一致即可有剪紙效果
ctx.arc(160, 160, 100, 0, Math.PI * 2)
ctx.arc(160, 160, 50, 0, Math.PI * 2, true)
ctx.fill()
複製程式碼
線段
ctx.moveTo(x, y)
ctx.lineTo(x, y)
複製程式碼
線段及邊界
ctx.beginPath()
ctx.moveTo(40, 40)
ctx.lineTo(200, 40)
ctx.stroke()
ctx.beginPath()
ctx.moveTo(40, 80.5)
ctx.lineTo(200, 80.5)
ctx.stroke()
複製程式碼
第一條線感覺有2px
邊界問題
網格
// 參考畫素邊界
ctx.lineWidth = 0.5
// 水平方向
for (let i = stepX; i < canvas.width; i += stepX) {
ctx.beginPath()
ctx.moveTo(i, 0)
ctx.lineTo(i, canvas.height)
ctx.stroke()
}
// 垂直方向
for (let i = stepY; i < canvas.height; i += stepY) {
ctx.beginPath()
ctx.moveTo(0, i)
ctx.lineTo(canvas.width, i)
ctx.stroke()
}
複製程式碼
座標系
橡皮筋繪製線條
在handleMouseDown記錄線段開始位置,handleMouseMove儲存線段結束位置,handleMouseUp儲存拖動線段資料
擴充套件虛線繪製
繪製上下文ctx的類是CanvasRenderingContext2D
const moveToFn = CanvasRenderingContext2D.prototype.moveTo
CanvasRenderingContext2D.prototype.lastMoveToData = {}
CanvasRenderingContext2D.prototype.moveTo = function (x, y) {
// 劫持原生moveTo
moveToFn.apply(this, [ x, y ])
// 保留moveTo位置
this.lastMoveToData = {
x, y
}
}
// 擴充套件dashedTo
CanvasRenderingContext2D.prototype.dashedTo = function (x, y, dashLength = 5) {
const { x: startX, y: startY } = this.lastMoveToData
const deltaX = x - startX
const deltaY = y - startY
const dashedNum = Math.floor(
Math.sqrt(
deltaX * deltaX + deltaY * deltaY
) / dashLength
)
for (let i = 0; i < dashedNum; i++) {
const fn = i % 2 === 0 ? 'moveTo' : 'lineTo'
this[ fn ](
startX + deltaX / dashedNum * i,
startY + deltaY / dashedNum * i
)
}
}
複製程式碼
使用
ctx.beginPath()
ctx.moveTo(100, 100)
ctx.dashedTo(200, 200)
ctx.stroke()
複製程式碼
線段端點
ctx.lineCap = 'butt' // 預設
ctx.lineCap = 'square' // 方塊
ctx.lineCap = 'round' // 圓角
複製程式碼
連線點繪製
// 線寬度
ctx.lineWidth = 20
ctx.lineJoin = 'miter'
ctx.lineJoin = 'round'
ctx.lineJoin = 'bevel'
複製程式碼
橡皮筋畫圓
數學知識
貝塞爾曲線
二次貝塞爾曲線
只向一個方向彎曲的簡單曲線
ctx.quadraticCurveTo(
// 控制點
180, 180,
// 錨點
200, 100
)
複製程式碼
紅色點是控制點,藍色點是錨點