在网页上绘制图形、创建动画、实现图像处理——这些需求在传统的 Web 开发中一直存在但直到 HTML5 带来了canvas元素才真正让浏览器拥有了“画布”能力。Canvas 是一个位图绘图 API通过 JavaScript 在网页上绘制 2D 图形、图像和动画是游戏开发、数据可视化、图像编辑、动态图表等场景的核心技术。本文将从零开始系统讲解 Canvas 的核心 API、绘图原理、动画机制以及性能优化技巧带你从入门到精通。一、Canvas 是什么1.1 定义与定位Canvas 是 HTML5 引入的一个用于动态绘制图形的元素它本身只是一个“容器”真正的绘图工作通过 JavaScript 调用其上下文ContextAPI 来完成。与 SVG 不同Canvas 是位图像素级别的绘图适合频繁更新和复杂渲染的场景。1.2 Canvas vs SVG对比维度CanvasSVG图形类型位图像素级矢量图保留对象性能大量图形时性能好大量图形时 DOM 节点多性能下降交互性需手动计算点击位置原生支持事件绑定放大会模糊不失真适用场景游戏、动画、图像处理图表、图标、静态图形一句话选择需要频繁重绘和大规模图形用 Canvas需要交互和缩放用 SVG。二、快速上手第一个 Canvas 程序2.1 基本结构!DOCTYPE html html head style /* 可选给画布加边框以便看清区域 */ canvas { border: 1px solid #ccc; } /style /head body !-- 1. 在 HTML 中放置 canvas 元素 -- canvas idmyCanvas width600 height400/canvas script // 2. 获取画布元素 const canvas document.getElementById(myCanvas); // 3. 获取绘图上下文2D const ctx canvas.getContext(2d); // 4. 开始绘图 ctx.fillStyle skyblue; ctx.fillRect(50, 50, 200, 100); ctx.fillStyle orange; ctx.fillRect(300, 50, 150, 150); /script /body /html2.2 核心三要素canvas元素HTML 中的画布容器需设置width和height注意CSS 尺寸会缩放画布而width/height属性定义的是绘图分辨率。getContext(2d)获取 2D 绘图上下文所有绘图操作都通过它完成。绘图 API如fillRect、strokeRect、fillStyle等。⚠️关键提示canvas的width和height属性与 CSS 尺寸是两回事。CSS 拉伸画布会导致图像模糊建议始终用属性设置尺寸CSS 只控制布局。三、坐标系与基础形状Canvas 的坐标系原点(0, 0)位于左上角x轴向右为正y轴向下为正。3.1 矩形// 填充矩形 ctx.fillStyle #ff0000; ctx.fillRect(10, 10, 100, 50); // (x, y, width, height) // 描边矩形 ctx.strokeStyle #00ff00; ctx.lineWidth 3; ctx.strokeRect(130, 10, 100, 50); // 清除矩形区域恢复为透明 ctx.clearRect(20, 20, 80, 30);3.2 路径绘制Canvas 中大多数复杂图形都通过路径Path绘制javascriptctx.beginPath(); // 开始路径 ctx.moveTo(50, 50); // 移动笔触到起点 ctx.lineTo(150, 50); // 画线到 (150, 50) ctx.lineTo(100, 120); // 画线到 (100, 120) ctx.closePath(); // 闭合路径回到起点 ctx.fillStyle purple; ctx.fill(); // 填充 ctx.strokeStyle black; ctx.lineWidth 2; ctx.stroke(); // 描边3.3 圆形与弧线ctx.beginPath(); // arc(x, y, radius, startAngle, endAngle, counterclockwise) ctx.arc(200, 150, 80, 0, Math.PI * 2); // 整圆 ctx.fillStyle gold; ctx.fill(); ctx.stroke(); // 半圆弧 ctx.beginPath(); ctx.arc(400, 150, 80, 0, Math.PI); ctx.stroke();四、样式与状态管理4.1 常用样式属性属性说明示例fillStyle填充颜色/渐变/图案#ff0000,rgba(255,0,0,0.5)strokeStyle描边颜色同上lineWidth线条宽度px3lineCap线条端点样式round,squarelineJoin线条拐角样式round,bevelglobalAlpha全局透明度0~10.5shadowColor阴影颜色rgba(0,0,0,0.3)shadowBlur阴影模糊程度104.2 状态栈save() 与 restore()ctx.fillStyle red; ctx.save(); // 保存当前状态红色 ctx.fillStyle blue; // 修改为蓝色 ctx.fillRect(10, 10, 50, 50); ctx.restore(); // 恢复到红色 ctx.fillRect(70, 10, 50, 50); // 红色矩形使用场景在绘制复杂图形时频繁使用save()和restore()避免样式污染。4.3 渐变与图案// 线性渐变 const gradient ctx.createLinearGradient(0, 0, 200, 0); gradient.addColorStop(0, red); gradient.addColorStop(0.5, yellow); gradient.addColorStop(1, blue); ctx.fillStyle gradient; ctx.fillRect(10, 10, 200, 100); // 径向渐变 const radial ctx.createRadialGradient(300, 60, 10, 300, 60, 80); radial.addColorStop(0, white); radial.addColorStop(1, darkblue); ctx.fillStyle radial; ctx.beginPath(); ctx.arc(300, 60, 80, 0, Math.PI * 2); ctx.fill(); // 图案填充 const img new Image(); img.src pattern.png; img.onload function() { const pattern ctx.createPattern(img, repeat); ctx.fillStyle pattern; ctx.fillRect(0, 150, 600, 100); };五、文本绘制ctx.font bold 30px Arial; ctx.fillStyle #333; ctx.textAlign center; // left, center, right ctx.textBaseline middle; // top, middle, bottom ctx.fillText(Hello Canvas, 300, 200); ctx.strokeStyle #ff0000; ctx.lineWidth 1; ctx.strokeText(描边文字, 300, 250); // 测量文字宽度 const metrics ctx.measureText(Hello Canvas); console.log(metrics.width);六、图像处理6.1 绘制图像const img new Image(); img.src photo.jpg; img.onload function() { // 绘制原图 ctx.drawImage(img, 0, 0); // 缩放绘制 ctx.drawImage(img, 200, 0, 100, 100); // 裁剪绘制 (sx, sy, sw, sh, dx, dy, dw, dh) ctx.drawImage(img, 50, 50, 100, 100, 300, 0, 100, 100); };6.2 像素操作// 获取像素数据 const imageData ctx.getImageData(0, 0, canvas.width, canvas.height); const data imageData.data; // Uint8ClampedArray [R,G,B,A, R,G,B,A, ...] // 转换为灰度图 for (let i 0; i data.length; i 4) { const gray data[i] * 0.3 data[i1] * 0.59 data[i2] * 0.11; data[i] gray; data[i1] gray; data[i2] gray; } ctx.putImageData(imageData, 0, 0);七、变换与坐标系操作7.1 平移、旋转、缩放ctx.save(); ctx.translate(300, 200); // 将原点移到 (300, 200) ctx.rotate(Math.PI / 4); // 旋转 45 度 ctx.scale(1.5, 1.5); // 放大 1.5 倍 ctx.fillStyle red; ctx.fillRect(-50, -50, 100, 100); ctx.restore();注意变换操作是累加的建议在变换前save()操作完成后restore()。7.2 矩阵变换ctx.setTransform(a, b, c, d, e, f); // 对应矩阵[[a, c, e], [b, d, f], [0, 0, 1]]八、动画基础Canvas 动画的核心是循环重绘通过requestAnimationFrame实现平滑动画。8.1 基本动画循环let x 0; let direction 1; function animate() { // 清除画布 ctx.clearRect(0, 0, canvas.width, canvas.height); // 更新状态 x 2 * direction; if (x canvas.width - 50 || x 0) { direction * -1; } // 绘制 ctx.fillStyle blue; ctx.fillRect(x, 150, 50, 50); // 请求下一帧 requestAnimationFrame(animate); } animate();8.2 帧率控制与 deltaTimelet lastTime 0; const speed 100; // 像素/秒 function animate(timestamp) { const deltaTime (timestamp - lastTime) / 1000; // 转为秒 lastTime timestamp; x speed * deltaTime; // ... 绘制 requestAnimationFrame(animate); } requestAnimationFrame(animate);使用deltaTime确保动画在不同刷新率的设备上速度一致。九、交互与事件Canvas 本身不提供“点击某个圆形”的事件需要手动计算。9.1 鼠标点击检测const circles [ { x: 100, y: 150, r: 40, color: red }, { x: 300, y: 150, r: 40, color: blue }, ]; function drawCircles() { circles.forEach(c { ctx.beginPath(); ctx.arc(c.x, c.y, c.r, 0, Math.PI * 2); ctx.fillStyle c.color; ctx.fill(); }); } canvas.addEventListener(click, function(e) { const rect canvas.getBoundingClientRect(); const mouseX e.clientX - rect.left; const mouseY e.clientY - rect.top; // 从后往前遍历上层优先 for (let i circles.length - 1; i 0; i--) { const c circles[i]; const dx mouseX - c.x; const dy mouseY - c.y; if (dx * dx dy * dy c.r * c.r) { alert(点击了 c.color 圆); break; } } });提示getBoundingClientRect()用于将鼠标坐标转换为 canvas 坐标系需考虑 canvas 的 CSS 缩放。十、性能优化优化策略说明离屏渲染在内存中创建不可见 Canvas 绘制复杂内容再一次性绘制到主画布减少绘制调用合并在同一路径中的绘制避免频繁beginPath()/stroke()使用requestAnimationFrame取代setInterval/setTimeout避免getImageData频繁调用除非必要减少像素级操作控制重绘区域使用drawImage裁剪或clearRect局部清除合理使用will-change提示浏览器优化canvas.style.willChange transform十一、总结速查表知识点关键 API获取上下文canvas.getContext(2d)矩形fillRect(x,y,w,h),strokeRect(),clearRect()路径beginPath(),moveTo(),lineTo(),closePath(),fill(),stroke()圆弧arc(x,y,r,startAngle,endAngle)样式fillStyle,strokeStyle,lineWidth,globalAlpha,shadow*状态save(),restore()文本fillText(),strokeText(),measureText()图像drawImage(),getImageData(),putImageData()变换translate(),rotate(),scale(),setTransform()动画requestAnimationFrame(callback)一句话记忆Canvas 是浏览器的像素级画布——通过 JavaScript 获取 2D 上下文用路径、样式和变换绘制图形用requestAnimationFrame驱动动画用手动坐标计算实现交互用离屏渲染和减少绘制调用优化性能。Canvas 是现代 Web 前端开发的核心技能之一。从本章的示例出发尝试实现一个“画板”应用支持鼠标绘制、颜色切换、清空再挑战一个简单的“弹球”游戏你会逐步感受到 Canvas 的强大。动画和游戏开发才是它真正的用武之地祝你创作愉快。
网站建设
高端定制
企业官网