Canvas 动画与图像处理
约 695 字大约 2 分钟
布欧-Lewyon
2026-05-16
首页 › HTML › HTML5 图形与绘图 › Canvas 动画与图像处理
帧循环与 requestAnimationFrame
Canvas 动画通过每帧清除 → 绘制 → 下一帧循环实现。
<canvas id="bounce" width="400" height="300"></canvas>
<script>
const canvas = document.getElementById('bounce');
const ctx = canvas.getContext('2d');
let x = 50, y = 50;
let vx = 3, vy = 2;
const radius = 20;
function draw() {
// 1. 清除画布
ctx.clearRect(0, 0, canvas.width, canvas.height);
// 2. 绘制小球
ctx.beginPath();
ctx.arc(x, y, radius, 0, Math.PI * 2);
ctx.fillStyle = '#1890ff';
ctx.fill();
// 3. 更新位置
x += vx;
y += vy;
// 4. 边界碰撞检测
if (x + radius > canvas.width || x - radius < 0) vx = -vx;
if (y + radius > canvas.height || y - radius < 0) vy = -vy;
// 5. 请求下一帧
requestAnimationFrame(draw);
}
draw();
</script>
requestAnimationFrame是 HTML5 动画 API,浏览器会在下一次重绘前调用回调,帧率自动适应显示器刷新率。
setInterval 的对比
setInterval(fn, 16.7) | requestAnimationFrame(draw) | |
|---|---|---|
| 帧率 | 固定,可能掉帧 | 自动匹配显示器刷新率 |
| 页面不可见 | 继续执行(浪费资源) | ⏸️ 自动暂停 |
| 节流 | 需要手动控制 | 浏览器自动优化 |
| 性能 | CPU 高 | GPU 加速 |
结论:动画始终用 requestAnimationFrame。
旋转与变换
<canvas id="rotate" width="400" height="300"></canvas>
<script>
const ctx = document.getElementById('rotate').getContext('2d');
let angle = 0;
function draw() {
ctx.clearRect(0, 0, 400, 300);
ctx.save(); // 保存当前状态
ctx.translate(200, 150); // 将原点移动到画布中心
ctx.rotate(angle); // 旋转(弧度)
// 绘制矩形(以原点为中心)
ctx.fillStyle = '#1890ff';
ctx.fillRect(-50, -25, 100, 50);
ctx.restore(); // 恢复之前状态
angle += 0.02;
requestAnimationFrame(draw);
}
draw();
</script>| 变换方法 | 作用 |
|---|---|
translate(x, y) | 平移原点 |
rotate(angle) | 旋转(弧度) |
scale(x, y) | 缩放 |
save() / restore() | 保存/恢复上下文状态 |
图像处理
绘制图片
<canvas id="image" width="400" height="300"></canvas>
<script>
const canvas = document.getElementById('image');
const ctx = canvas.getContext('2d');
const img = new Image();
img.src = 'photo.jpg';
img.onload = function() {
// 原样绘制
ctx.drawImage(img, 0, 0);
// 缩放绘制
ctx.drawImage(img, 200, 0, 150, 100);
// 裁剪后绘制:从原图 (10, 10) 位置截取 100x100 区域,绘制到 (0, 150) 位置 200x200
ctx.drawImage(img, 10, 10, 100, 100, 0, 150, 200, 200);
};
</script>像素级操作
<canvas id="pixels" width="200" height="200"></canvas>
<script>
const ctx = document.getElementById('pixels').getContext('2d');
// 获取像素数据
const imageData = ctx.getImageData(0, 0, 200, 200);
const data = imageData.data; // Uint8ClampedArray [R,G,B,A, R,G,B,A, ...]
// 反色处理
for (let i = 0; i < data.length; i += 4) {
data[i] = 255 - data[i]; // R
data[i + 1] = 255 - data[i + 1]; // G
data[i + 2] = 255 - data[i + 2]; // B
// data[i + 3] 是 Alpha 通道,不变
}
// 写回画布
ctx.putImageData(imageData, 0, 0);
// 导出为图片
const dataURL = canvas.toDataURL('image/png');
console.log(dataURL); // data:image/png;base64,...
</script>小结
| API | 用途 |
|---|---|
requestAnimationFrame | 动画帧循环 |
clearRect | 清除画布 |
translate / rotate / scale | 坐标变换 |
save / restore | 状态保存/恢复 |
drawImage | 绘制图片 |
getImageData / putImageData | 像素操作 |
toDataURL | 导出为图片 |
上一节:Canvas 基础与绘图 下一节:SVG 基础
