详细讲解Canvas清除与重置方法,clearRect使用技巧,动画循环中的清除策略,包含多个交互式案例 在Canvas动画和交互应用中,清除画布是必不可少的操作。掌握正确的清除方法对于创建流畅的动画至关重要。
Canvas提供了多种清除画布的方式:
| 方法 | 说明 | 适用场景 |
|---|---|---|
clearRect() | 清除指定矩形区域 | 局部清除、动画 |
设置width/height | 重置整个画布 | 完全重置 |
| 绘制背景色 | 覆盖式清除 | 简单场景 |
<canvas id="myCanvas" width="400" height="200"></canvas>
<button onclick="clearRect()">清除红色区域</button>
<button onclick="clearAll()">清除全部</button>
<script>
const canvas = document.getElementById('myCanvas')
const ctx = canvas.getContext('2d')
function draw() {
// 绘制内容
ctx.fillStyle = '#e74c3c'
ctx.fillRect(50, 50, 100, 100)
ctx.fillStyle = '#3498db'
ctx.fillRect(200, 50, 100, 100)
}
function clearRect() {
// 清除指定区域
ctx.clearRect(50, 50, 100, 100)
}
function clearAll() {
// 清除整个画布
ctx.clearRect(0, 0, canvas.width, canvas.height)
}
draw()
</script>
| 方法 | 参数 | 说明 |
|---|---|---|
clearRect(x, y, w, h) | x,y: 起始坐标, w,h: 尺寸 | 清除指定矩形区域 |
clearRect(0, 0, w, h) | w,h: 画布尺寸 | 清除整个画布 |
每帧清除(正常)
不清除(轨迹效果)
<canvas id="canvas1" width="180" height="150"></canvas>
<canvas id="canvas2" width="180" height="150"></canvas>
<script>
// 方式1:每帧清除(正常动画)
const canvas1 = document.getElementById('canvas1')
const ctx1 = canvas1.getContext('2d')
let angle1 = 0
function animate1() {
// 每帧清除画布
ctx1.clearRect(0, 0, canvas1.width, canvas1.height)
// 计算位置
const x = 90 + Math.cos(angle1) * 50
const y = 75 + Math.sin(angle1) * 50
// 绘制
ctx1.fillStyle = '#3498db'
ctx1.beginPath()
ctx1.arc(x, y, 15, 0, Math.PI * 2)
ctx1.fill()
angle1 += 0.05
requestAnimationFrame(animate1)
}
// 方式2:不清除(轨迹效果)
const canvas2 = document.getElementById('canvas2')
const ctx2 = canvas2.getContext('2d')
let angle2 = 0
function animate2() {
// 不清除,直接绘制
const x = 90 + Math.cos(angle2) * 50
const y = 75 + Math.sin(angle2) * 50
ctx2.fillStyle = 'rgba(52, 152, 219, 0.1)'
ctx2.beginPath()
ctx2.arc(x, y, 15, 0, Math.PI * 2)
ctx2.fill()
angle2 += 0.05
requestAnimationFrame(animate2)
}
animate1()
animate2()
</script>
| 策略 | 效果 | 适用场景 |
|---|---|---|
| 每帧清除 | 正常动画效果 | 大多数动画 |
| 不清除 | 轨迹/拖尾效果 | 特殊视觉效果 |
| 半透明覆盖 | 渐隐轨迹效果 | 粒子效果 |
<canvas id="myCanvas" width="400" height="200"></canvas>
<button onclick="resetByClearRect()">clearRect</button>
<button onclick="resetByWidth()">重置width</button>
<script>
const canvas = document.getElementById('myCanvas')
const ctx = canvas.getContext('2d')
function draw() {
ctx.fillStyle = '#3498db'
ctx.fillRect(50, 50, 100, 100)
// 应用变换
ctx.scale(2, 2)
}
function resetByClearRect() {
// 方式1:clearRect
// 只清除内容,变换状态保留
ctx.clearRect(0, 0, canvas.width, canvas.height)
}
function resetByWidth() {
// 方式2:重置width
// 完全重置,包括变换状态
canvas.width = canvas.width
}
draw()
</script>
| 方法 | 清除内容 | 清除变换 | 清除样式 |
|---|---|---|---|
clearRect() | ✓ | ✗ | ✗ |
canvas.width = width | ✓ | ✓ | ✓ |
绿色方块使用局部清除,红色方块使用全画布清除
<canvas id="myCanvas" width="400" height="200"></canvas>
<script>
const canvas = document.getElementById('myCanvas')
const ctx = canvas.getContext('2d')
const block = { x: 50, y: 80, w: 40, h: 40, vx: 2 }
// 缓存背景
let bgCache = null
function drawBackground() {
ctx.fillStyle = '#f8f9fa'
ctx.fillRect(0, 0, canvas.width, canvas.height)
// 绘制网格...
}
function animate() {
// 方式1:局部清除(优化)
// 只清除方块移动经过的区域
const padding = 2
ctx.clearRect(
block.x - padding,
block.y - padding,
block.w + padding * 2,
block.h + padding * 2
)
// 方式2:使用缓存的背景
if (!bgCache) {
drawBackground()
bgCache = ctx.getImageData(0, 0, canvas.width, canvas.height)
}
ctx.putImageData(bgCache, 0, 0)
// 绘制方块
ctx.fillStyle = '#2ecc71'
ctx.fillRect(block.x, block.y, block.w, block.h)
// 更新位置
block.x += block.vx
if (block.x > canvas.width - block.w) {
block.vx = -block.vx
}
requestAnimationFrame(animate)
}
animate()
</script>
| 优化方法 | 说明 |
|---|---|
| 局部清除 | 只清除需要更新的区域 |
| 背景缓存 | 使用getImageData缓存不变的内容 |
| 脏矩形 | 记录变化区域,只重绘该区域 |
<canvas id="myCanvas" width="400" height="200"></canvas>
<script>
const canvas = document.getElementById('myCanvas')
const ctx = canvas.getContext('2d')
// 初始化白色背景
ctx.fillStyle = '#fff'
ctx.fillRect(0, 0, canvas.width, canvas.height)
const particles = []
for (let i = 0; i < 5; i++) {
particles.push({
x: Math.random() * canvas.width,
y: Math.random() * canvas.height,
vx: (Math.random() - 0.5) * 4,
vy: (Math.random() - 0.5) * 4,
hue: i * 60
})
}
function animate() {
// 渐隐清除:用半透明背景覆盖
ctx.fillStyle = 'rgba(255, 255, 255, 0.05)'
ctx.fillRect(0, 0, canvas.width, canvas.height)
particles.forEach(p => {
p.x += p.vx
p.y += p.vy
// 边界反弹
if (p.x < 0 || p.x > canvas.width) p.vx = -p.vx
if (p.y < 0 || p.y > canvas.height) p.vy = -p.vy
// 绘制粒子
ctx.fillStyle = `hsla(${p.hue}, 70%, 50%, 0.8)`
ctx.beginPath()
ctx.arc(p.x, p.y, 10, 0, Math.PI * 2)
ctx.fill()
})
requestAnimationFrame(animate)
}
animate()
</script>
| 参数 | 说明 |
|---|---|
rgba(255, 255, 255, 0.05) | 5%透明度的白色覆盖 |
| 透明度值 | 越小轨迹越长 |
hsla() | 使用HSL颜色便于动态变化色相 |
const ClearStrategy = {
fullClear(ctx, canvas) {
ctx.clearRect(0, 0, canvas.width, canvas.height)
},
localClear(ctx, x, y, w, h, padding = 2) {
ctx.clearRect(x - padding, y - padding, w + padding * 2, h + padding * 2)
},
fadeClear(ctx, canvas, opacity = 0.05) {
ctx.fillStyle = `rgba(255, 255, 255, ${opacity})`
ctx.fillRect(0, 0, canvas.width, canvas.height)
},
resetCanvas(canvas) {
canvas.width = canvas.width
}
}
Canvas清除与重置要点:
clearRect()是最常用的清除方法