Canvas动画和交互中,经常需要清除画布内容重新绑制。掌握正确的清除方法很重要。
最常用的清除方法:
const canvas = document.getElementById('canvas')
const ctx = canvas.getContext('2d')
// 清除整个画布
ctx.clearRect(0, 0, canvas.width, canvas.height)
// 重设宽度会清空画布
canvas.width = canvas.width
这种方法会清空画布,但也会重置所有状态(变换、样式等)。
canvas.height = canvas.height
效果同上。
clearRect(x, y, width, height) 清除指定矩形区域:
// 清除整个画布
ctx.clearRect(0, 0, canvas.width, canvas.height)
// 清除部分区域
ctx.clearRect(100, 100, 200, 150)
// 清除特定形状(通过路径)
ctx.beginPath()
ctx.arc(200, 200, 50, 0, Math.PI * 2)
ctx.clip() // 设置裁剪区域
ctx.clearRect(0, 0, canvas.width, canvas.height) // 只清除圆形区域
在动画循环中,每帧都需要清除画布:
function animate() {
// 清除画布
ctx.clearRect(0, 0, canvas.width, canvas.height)
// 更新状态
update()
// 重新绑制
draw()
requestAnimationFrame(animate)
}
// 如果知道物体之前的位置,只清除那个区域
function clearObject(obj) {
ctx.clearRect(
obj.x - obj.size,
obj.y - obj.size,
obj.size * 2,
obj.size * 2
)
}
清除画布不会影响绑制状态,但重设尺寸会:
// 设置样式
ctx.fillStyle = 'red'
ctx.translate(100, 100)
// clearRect 不影响状态
ctx.clearRect(0, 0, canvas.width, canvas.height)
console.log(ctx.fillStyle) // 'red' 保持不变
// 重设尺寸会重置状态
canvas.width = canvas.width
console.log(ctx.fillStyle) // '#000000' 恢复默认
// 保存状态
ctx.save()
// 设置变换和样式
ctx.translate(100, 100)
ctx.fillStyle = 'red'
// 恢复状态
ctx.restore()
function resetCanvas(canvas) {
const ctx = canvas.getContext('2d')
// 重设尺寸(清空内容并重置状态)
canvas.width = canvas.width
// 或者手动重置状态
ctx.setTransform(1, 0, 0, 1, 0, 0) // 重置变换
ctx.globalAlpha = 1
ctx.globalCompositeOperation = 'source-over'
ctx.fillStyle = '#000000'
ctx.strokeStyle = '#000000'
ctx.lineWidth = 1
ctx.lineCap = 'butt'
ctx.lineJoin = 'miter'
ctx.lineDashOffset = 0
ctx.shadowColor = 'rgba(0, 0, 0, 0)'
ctx.shadowBlur = 0
ctx.shadowOffsetX = 0
ctx.shadowOffsetY = 0
ctx.font = '10px sans-serif'
ctx.textAlign = 'start'
ctx.textBaseline = 'alphabetic'
return ctx
}
如果画布有背景色,清除后需要重新填充:
function clearWithBackground(canvas, bgColor = '#fff') {
const ctx = canvas.getContext('2d')
ctx.clearRect(0, 0, canvas.width, canvas.height)
ctx.fillStyle = bgColor
ctx.fillRect(0, 0, canvas.width, canvas.height)
}
const canvas = document.getElementById('canvas')
const ctx = canvas.getContext('2d')
const ball = {
x: 50,
y: 150,
radius: 20,
speed: 3
}
function draw() {
// 清除画布
ctx.clearRect(0, 0, canvas.width, canvas.height)
// 绘制背景
ctx.fillStyle = '#f0f0f0'
ctx.fillRect(0, 0, canvas.width, canvas.height)
// 更新位置
ball.x += ball.speed
if (ball.x > canvas.width + ball.radius) {
ball.x = -ball.radius
}
// 绘制小球
ctx.beginPath()
ctx.arc(ball.x, ball.y, ball.radius, 0, Math.PI * 2)
ctx.fillStyle = '#3498db'
ctx.fill()
requestAnimationFrame(draw)
}
draw()
// 错误:坐标超出范围
ctx.clearRect(0, 0, 100, 100) // 只清除了部分
// 正确:清除整个画布
ctx.clearRect(0, 0, canvas.width, canvas.height)
// 如果用重设尺寸的方法
canvas.width = canvas.width // 样式被重置
// 需要重新设置样式
ctx.fillStyle = 'red'
// 如果使用了 scale(dpr, dpr)
// 清除时需要考虑缩放
const dpr = window.devicePixelRatio || 1
// 方法1:清除时考虑缩放
ctx.clearRect(0, 0, canvas.width / dpr, canvas.height / dpr)
// 方法2:先恢复缩放再清除
ctx.setTransform(1, 0, 0, 1, 0, 0)
ctx.clearRect(0, 0, canvas.width, canvas.height)
ctx.scale(dpr, dpr)