共计 2540 个字符,预计需要花费 7 分钟才能阅读完成。
一、Canvas 基础概念
Canvas 是 HTML5 提供的图形绘制 API,通过 JavaScript 脚本在网页上动态生成位图。它就像一块虚拟画布,开发者可以通过调用 API 在这块画布上绘制各种图形、文字、图像甚至实现动画效果。与 SVG 不同,Canvas 是即时渲染的——绘制完成后就变成像素集合,无法直接修改已绘制的内容(需要擦除重绘)。

Canvas 的核心价值在于:
- 高性能的 2D 图形渲染能力
- 不依赖外部插件(如 Flash)
- 适合游戏、数据可视化等动态场景
二、核心 API 解析
1. 基础设置
// 获取 Canvas 元素
const canvas = document.getElementById('myCanvas');
// 获取绘图上下文(参数 '2d' 表示二维绘图)const ctx = canvas.getContext('2d');
2. 路径绘制
// 开始新路径
ctx.beginPath();
// 移动笔触到 (50,50)
ctx.moveTo(50, 50);
// 画线到 (150,50)
ctx.lineTo(150, 50);
// 设置线条颜色
ctx.strokeStyle = 'blue';
// 设置线条宽度
ctx.lineWidth = 5;
// 实际绘制路径
ctx.stroke();
3. 文本渲染
ctx.font = '30px Arial';
ctx.fillStyle = 'red';
// 填充文本
ctx.fillText('Hello Canvas', 50, 50);
// 描边文本
ctx.strokeText('Hello Canvas', 50, 100);
三、实战示例
示例 1:绘制笑脸
function drawSmile() {
// 绘制脸部(黄色圆形)ctx.beginPath();
ctx.arc(100, 100, 50, 0, Math.PI * 2);
ctx.fillStyle = 'yellow';
ctx.fill();
ctx.stroke();
// 绘制眼睛
ctx.beginPath();
ctx.arc(80, 80, 10, 0, Math.PI * 2);
ctx.arc(120, 80, 10, 0, Math.PI * 2);
ctx.fillStyle = 'black';
ctx.fill();
// 绘制嘴巴(半圆)ctx.beginPath();
ctx.arc(100, 100, 30, 0, Math.PI);
ctx.stroke();}
示例 2:弹跳小球动画
let y = 0;
let velocity = 0;
const gravity = 0.1;
const damping = 0.9;
function animate() {
// 清除画布
ctx.clearRect(0, 0, canvas.width, canvas.height);
// 更新物理参数
velocity += gravity;
y += velocity;
// 底部碰撞检测
if (y > canvas.height - 30) {
y = canvas.height - 30;
velocity = -velocity * damping;
}
// 绘制小球
ctx.beginPath();
ctx.arc(100, y, 30, 0, Math.PI * 2);
ctx.fillStyle = 'blue';
ctx.fill();
// 继续动画
requestAnimationFrame(animate);
}
animate();
示例 3:简单绘图板
let isDrawing = false;
canvas.addEventListener('mousedown', startDrawing);
canvas.addEventListener('mousemove', draw);
canvas.addEventListener('mouseup', stopDrawing);
function startDrawing(e) {
isDrawing = true;
ctx.beginPath();
ctx.moveTo(e.offsetX, e.offsetY);
}
function draw(e) {if (!isDrawing) return;
ctx.lineTo(e.offsetX, e.offsetY);
ctx.stroke();}
function stopDrawing() {isDrawing = false;}
四、性能优化
-
减少重绘区域 :只清除和重绘发生变化的部分,而非整个画布
// 只清除小球所在区域 ctx.clearRect(x-1, y-1, radius*2+2, radius*2+2); -
使用离屏 Canvas:将不常变化的图形预先绘制到内存中的 Canvas
const offscreen = document.createElement('canvas'); const offCtx = offscreen.getContext('2d'); // 预先绘制复杂图形 drawComplexShape(offCtx); // 主绘制时直接复制 ctx.drawImage(offscreen, 0, 0); -
避免浮点坐标 :使用整数坐标可以避免浏览器额外的抗锯齿计算
五、避坑指南
- 忘记 beginPath():如果不调用 beginPath(),所有路径会连在一起
-
解决方法:每次开始新路径前都调用 beginPath()
-
坐标系混淆 :Canvas 的 Y 轴是向下递增的
-
解决方法:绘制前明确坐标系,必要时进行数学转换
-
性能问题 :在动画中频繁创建新对象会导致内存泄漏
-
解决方法:重用对象,使用对象池技术
-
高清屏显示模糊 :Canvas 默认不处理设备像素比
-
解决方法:根据 window.devicePixelRatio 调整 Canvas 尺寸
-
事件坐标错误 :直接使用 clientX 会忽略 Canvas 的偏移
- 解决方法:使用 getBoundingClientRect() 计算相对位置
六、进阶建议
- 学习 WebGL:当需要 3D 图形或更复杂效果时
- 探索 Canvas 库:如 Fabric.js、Konva.js 等
- 实践项目:尝试制作小游戏、数据可视化仪表盘
- 性能分析:学习使用 Chrome DevTools 的 Performance 面板
思考题
如何实现一个基于 Canvas 的简易绘图应用?可以考虑以下功能:
- 不同颜色的画笔
- 粗细调节
- 橡皮擦功能
- 保存绘图为图片
- 撤销 / 重做功能
可以从基本的鼠标绘图开始,逐步添加这些功能模块。
正文完
发表至: 未分类
近两天内
