画布清除与重置

详细讲解Canvas清除与重置方法,clearRect使用技巧,动画循环中的清除策略,包含多个交互式案例 在Canvas动画和交互应用中,清除画布是必不可少的操作。掌握正确的清除方法对于创建流畅的动画至关重要。

清除方法概述

Canvas提供了多种清除画布的方式:

方法说明适用场景
clearRect()清除指定矩形区域局部清除、动画
设置width/height重置整个画布完全重置
绘制背景色覆盖式清除简单场景

案例一:clearRect 基本用法

clearRect 清除区域

代码实现

<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()是最常用的清除方法
  • 动画中通常每帧清除后重绘
  • 重置width/height会清除所有状态
  • 局部清除可优化性能
  • 半透明覆盖可创建渐隐效果