Canvas 核心 API 与实战绘制指南
1. Canvas 基础入门从零认识绘图上下文第一次接触 Canvas 时我把它想象成小时候用的素描本。浏览器中的canvas标签就是这张白纸而 JavaScript 则是我们手中的画笔。这个比喻可能简单但确实能帮助理解核心概念。让我们从最基础的创建画布开始!-- 画布容器 -- canvas idmyCanvas width500 height300/canvas这里有个新手常踩的坑如果不显式设置 width 和 height 属性画布默认会采用 300×150 像素的尺寸。更关键的是如果通过 CSS 设置尺寸会导致画布内容被拉伸变形。记得三年前我做数据可视化项目时就因为这个问题调试了半天线条模糊的问题。获取绘图上下文是核心操作就像画家需要先选择画笔类型const canvas document.getElementById(myCanvas); const ctx canvas.getContext(2d); // 关键获取2D渲染上下文这个ctx对象将成为我们所有绘图操作的指挥官。它包含了所有绘图方法和属性从简单的线条到复杂的贝塞尔曲线都靠它实现。有趣的是虽然我们这里用的是 2D 上下文但 Canvas 还支持 WebGL 的 3D 上下文那是另一个更强大的领域。2. 图形绘制实战从直线到复杂路径2.1 基础图形绘制技巧绘制矩形可能是最直观的入门操作。Canvas 提供了两种矩形绘制方式fillRect(x, y, width, height)绘制填充矩形strokeRect(x, y, width, height)绘制描边矩形ctx.fillStyle #FF6B6B; // 设置填充色 ctx.strokeStyle #4ECDC4; // 设置描边色 ctx.lineWidth 3; // 线宽 ctx.fillRect(50, 50, 100, 80); // 实心矩形 ctx.strokeRect(200, 50, 100, 80); // 空心矩形圆形绘制则稍微复杂些需要使用arc()方法。这个方法接受六个参数ctx.arc(x, y, radius, startAngle, endAngle, anticlockwise);我曾经在制作圆形进度条时被角度参数困扰过。这里有个实用技巧Canvas 中的角度使用弧度制Math.PI表示 180 度所以完整的圆是Math.PI * 2。2.2 路径绘制进阶路径绘制是 Canvas 最强大的功能之一。想象你在玩连点成图的游戏beginPath()就是拿起笔moveTo()把笔移动到起点lineTo()画线到下一个点ctx.beginPath(); ctx.moveTo(50, 150); // 起点 ctx.lineTo(150, 50); // 第二点 ctx.lineTo(250, 150); // 第三点 ctx.closePath(); // 自动闭合路径 ctx.stroke(); // 描边更复杂的曲线绘制可以使用quadraticCurveTo()二次贝塞尔曲线和bezierCurveTo()三次贝塞尔曲线。去年我做签名板功能时发现用贝塞尔曲线处理手写轨迹比单纯用lineTo平滑得多。3. 文本与图像处理技巧3.1 文本渲染控制Canvas 的文本渲染虽然不如 CSS 灵活但足够应对大多数场景。关键属性包括font格式同 CSS font 属性textAlign水平对齐left/center/righttextBaseline垂直对齐top/middle/bottomctx.font bold 24px Helvetica Neue; ctx.fillStyle #333; ctx.textAlign center; ctx.fillText(居中文本, canvas.width/2, 50);有个实用技巧测量文本宽度。在做自适应布局时我经常用ctx.measureText(text).width来精确计算文本占位。3.2 图像操作秘籍图像绘制看似简单但隐藏着不少细节坑。基本用法是const img new Image(); img.src path/to/image.jpg; img.onload function() { ctx.drawImage(img, x, y, width, height); };但实际项目中你可能需要处理图像跨域问题需要服务器设置 CORS图像裁剪使用九参数版本的 drawImage性能优化对频繁绘制的图像使用缓存去年开发图片编辑器时我实现了图像滤镜功能这需要先将图像数据取出处理const imageData ctx.getImageData(0, 0, canvas.width, canvas.height); // 处理像素数据 ctx.putImageData(imageData, 0, 0);4. 高级技巧与性能优化4.1 状态管理艺术Canvas 的状态栈state stack是很多开发者忽视的强大功能。通过save()和restore()可以保存/恢复绘图上下文的所有样式和变换ctx.fillStyle red; ctx.save(); // 保存当前状态 ctx.fillStyle blue; ctx.fillRect(10, 10, 50, 50); // 蓝色矩形 ctx.restore(); // 恢复之前状态 ctx.fillRect(70, 10, 50, 50); // 红色矩形在开发复杂图形组件时合理使用状态栈能让代码更清晰。我曾经重构过一个图表库通过引入状态管理减少了 30% 的样式设置代码。4.2 动画实现原理Canvas 动画的核心是清除-重绘循环。基本模式如下function animate() { ctx.clearRect(0, 0, canvas.width, canvas.height); // 更新并绘制对象 requestAnimationFrame(animate); } animate();性能优化要点尽量减少绘制区域使用 clearRect 局部清除对静态内容使用离屏 Canvas 缓存避免在动画循环中创建新对象去年做粒子系统时我发现使用路径而非单独绘制每个粒子性能提升了近 10 倍。关键代码ctx.beginPath(); particles.forEach(p { ctx.moveTo(p.x, p.y); ctx.arc(p.x, p.y, p.radius, 0, Math.PI*2); }); ctx.fill();4.3 响应式处理技巧让 Canvas 适配不同屏幕尺寸需要特殊处理。我常用的方案function resizeCanvas() { const ratio window.devicePixelRatio || 1; canvas.width canvas.clientWidth * ratio; canvas.height canvas.clientHeight * ratio; ctx.scale(ratio, ratio); } window.addEventListener(resize, resizeCanvas);这里有个细节处理高分屏Retina时需要乘以 devicePixelRatio否则图形会模糊。这个坑我踩过不止一次。

相关新闻