LOGO 首页 OA教程 ERP教程 模切知识交流 PMS教程 CRM教程 技术文档 其他文档  
 
网站管理员

别再死记硬背了!这份HTML5 Canvas入门教程让你秒懂绘图原理

admin
2026年4月22日 17:52 本文热度 39

本文详细讲解Canvas的绘图原理、基本操作、动画实现、性能优化以及WebGL、图像处理、物理引擎等进阶主题,包含丰富的代码示例和最佳实践,适合初学者和有一定经验的开发者阅读。

Canvas是HTML5最具代表性的特性之一,它为Web页面带来了动态图形和图像处理的能力。无论是数据可视化、游戏开发、图像编辑还是创意编程,Canvas都扮演着核心角色。本文将带领您系统学习Canvas的基础知识,并深入探讨其高级用法,帮助您全面掌握这一强大的绘图技术。

一、Canvas 基础


1.1 创建 Canvas 元素

Canvas 是一个矩形区域的容器,通过 JavaScript 在区域内绘制图形。在 HTML 中定义 Canvas 非常简单:

<canvas id="myCanvas" width="800" height="600">  您的浏览器不支持 Canvas,请升级或更换浏览器。</canvas>

  • width 和 height 属性设置画布的像素尺寸(注意:CSS 设置的宽高会影响显示比例,但绘图区域仍以属性值为准)。

  • 标签内的文本是降级内容,仅在浏览器不支持 Canvas 时显示。


1.2 获取 2D 绘图上下文

要真正开始绘图,必须获取 Canvas 的绘图上下文(context)。2D 上下文提供了所有绘制方法。

const canvas = document.getElementById('myCanvas');const ctx = canvas.getContext('2d');

1.3 基本绘图操作
绘制矩形

Canvas 提供了三个绘制矩形的方法:fillRect、strokeRect 和 clearRect。

// 填充矩形ctx.fillStyle = 'red';ctx.fillRect(101010050);   // (x, y, width, height)// 描边矩形ctx.strokeStyle = 'blue';ctx.lineWidth = 2;ctx.strokeRect(1201010050);// 清除矩形区域ctx.clearRect(20208030);   // 擦除部分区域

绘制路径

路径是绘制复杂图形的基础。通过 beginPath() 开始新路径,然后使用 moveTo、lineTo 等方法定义路径,最后调用 stroke() 或 fill() 进行绘制。

ctx.beginPath();ctx.moveTo(5050);   // 起点ctx.lineTo(15050);  // 画到 (150,50)ctx.lineTo(100150); // 画到 (100,150)ctx.closePath();  // 闭合路径(回到起点)ctx.stroke();   // 描边// 也可以 ctx.fill() 填充

绘制圆形和弧线

使用 arc() 方法绘制圆弧或圆。

ctx.beginPath();ctx.arc(200200500, Math.PI * 2);  // 圆心 (200,200),半径50,起始角0,结束角2πctx.fillStyle = 'green';ctx.fill();

1.4 样式和颜色

颜色设置

fillStyle 和 strokeStyle 可以接受颜色字符串、渐变色或图案。

ctx.fillStyle = 'red';   // 颜色名称ctx.fillStyle = '#ff0000';  // 十六进制ctx.fillStyle = 'rgb(255,0,0)'; // RGBctx.fillStyle = 'rgba(255,0,0,0.5)';  // RGBA 带透明度

渐变

Canvas 支持线性渐变和径向渐变。

// 线性渐变const gradient = ctx.createLinearGradient(002000);  // 从 (0,0) 到 (200,0)gradient.addColorStop(0'red');gradient.addColorStop(1'blue');ctx.fillStyle = gradient;ctx.fillRect(1010200100);
// 径向渐变const radialGradient = ctx.createRadialGradient(100100010010050);radialGradient.addColorStop(0'white');radialGradient.addColorStop(1'black');ctx.fillStyle = radialGradient;ctx.fillRect(25010200100);

1.5 文本绘制

使用 fillText 和 strokeText 绘制文本,并可通过 font、textAlign 等属性设置样式。

ctx.font = '30px Arial';ctx.fillStyle = 'black';ctx.textAlign = 'center';ctx.textBaseline = 'middle';ctx.fillText('Hello Canvas', canvas.width / 2, canvas.height / 2);

1.6 图像操作
绘制图像

通过 drawImage 方法可以将 Image 对象、Canvas 元素或视频帧绘制到画布上。

const img = new Image();img.onload = function() {  // 在 (0,0) 绘制原图  ctx.drawImage(img, 00);  // 缩放绘制:在 (0,0) 绘制宽100、高100的图像  ctx.drawImage(img, 00100100);};img.src = 'image.png';

1.7 变换操作

Canvas 支持平移、旋转、缩放等变换,且可以通过 save 和 restore 管理状态栈。

ctx.save();   // 保存当前状态ctx.translate(100100);  // 平移ctx.rotate(Math.PI / 4);  // 旋转 45°ctx.scale(20.5);  // 缩放// 绘制变换后的图形ctx.fillRect(005050);ctx.restore();  // 恢复到保存的状态

1.8 动画实现

动画的核心是反复清除画布并重新绘制。使用 requestAnimationFrame 。

let x = 0;const speed = 2;function animate() {  // 1. 清除画布  ctx.clearRect(00, canvas.width, canvas.height);  // 2. 更新位置  x += speed;  if (x > canvas.width) x = 0;  // 3. 绘制  ctx.fillRect(x, 505050);  // 4. 请求下一帧  requestAnimationFrame(animate);}animate();

1.9 事件处理

Canvas 本身不记录绘制的图形,但可以通过坐标计算实现交互。

canvas.addEventListener('click'(event) => {  const rect = canvas.getBoundingClientRect();  const x = event.clientX - rect.left;  const y = event.clientY - rect.top;  // 检查点是否在路径内(需要提前构建路径)  if (ctx.isPointInPath(x, y)) {    console.log('点击了图形!');  }});

1.10 性能优化技巧
离屏 Canvas

预先在内存中的 Canvas 绘制复杂图形,然后快速复制到主画布上,减少重复计算。

const offCanvas = document.createElement('canvas');const offCtx = offCanvas.getContext('2d');
// 在离屏画布上绘制复杂图形offCtx.fillStyle = 'red';offCtx.fillRect(00200200);// 在主画布上直接绘制离屏画布ctx.drawImage(offCanvas, 00);

批量操作

减少不必要的状态改变,尽量将相同样式的绘制集中处理。

ctx.save();ctx.fillStyle = 'red';ctx.strokeStyle = 'blue';for (let i = 0; i < 100; i++) {  ctx.fillRect(i * 10088);}ctx.restore();

1.11 实际应用示例:简单绘图板

实现一个基本的鼠标绘图功能。

let isDrawing = false;let lastX = 0lastY = 0;
canvas.addEventListener('mousedown'(e) => {  isDrawing = true;  [lastX, lastY] = [e.offsetX, e.offsetY];});
canvas.addEventListener('mousemove'(e) => {  if (!isDrawing) return;  ctx.beginPath();  ctx.moveTo(lastX, lastY);  ctx.lineTo(e.offsetX, e.offsetY);  ctx.stroke();  [lastX, lastY] = [e.offsetX, e.offsetY];});
canvas.addEventListener('mouseup'() => isDrawing = false);canvas.addEventListener('mouseleave'() => isDrawing = false);

1.12 常见问题解决:高清屏适配

在 Retina 等高清屏幕上,Canvas 可能模糊。需要根据设备像素比调整画布尺寸。

const dpr = window.devicePixelRatio || 1;const displayWidth = canvas.clientWidth;const displayHeight = canvas.clientHeight;
canvas.width = displayWidth * dpr;canvas.height = displayHeight * dpr;canvas.style.width = displayWidth + 'px';canvas.style.height = displayHeight + 'px';
ctx.scale(dpr, dpr);

二、Canvas 进阶


2.1 Canvas 绘图的通用流程

无论简单还是复杂的绘图,都遵循一个清晰的流程:

  1. 获取上下文(2D 或 WebGL)。

  2. 设置样式(颜色、线宽、渐变等)。

  3. 构建路径(或直接调用绘图方法)。

  4. 执行绘制(填充、描边等)。

  5. 动画循环(如需动效,重复以上步骤)。

这一流程体现了 Canvas 的“即时模式”绘图思想,每次绘制都是直接操作像素,不保留图形对象。

2.2 Canvas 必须依赖 JavaScript 吗?

是的,Canvas 完全依赖 JavaScript 实现绘图。

<canvas> 标签本身只是一个空容器,不提供任何绘图能力。真正的绘制工作必须通过 JavaScript 调用绘图 API 完成。如果禁用 JavaScript,Canvas 区域将是一片空白(除非有降级内容)。这种设计使得 Canvas 极其灵活,可以与用户交互、动态生成内容,并与各种 JavaScript 库无缝集成。

3. 高阶用法
3.1 WebGL – 3D 图形渲染

通过 getContext('webgl') 可以获取 WebGL 上下文,利用 GPU 加速渲染 3D 场景。以下是一个极简的三角形绘制示例:

const gl = canvas.getContext('webgl');const vsSource = `  attribute vec4 aPosition;  void main() {    gl_Position = aPosition;  }`;const fsSource = `  void main() {    gl_FragColor = vec4(1.00.00.01.0);  }`;// 编译着色器、创建程序、绑定缓冲区等(详细代码略)// 最后绘制gl.drawArrays(gl.TRIANGLES, 03);

WebGL 编程较为复杂,通常借助 Three.js 等库简化开发。

3.2 图像处理与滤镜

通过 getImageData 和 putImageData 可以逐像素操作图像,实现各种滤镜效果。

function applyGrayscale() {  const imageData = ctx.getImageData(00, canvas.width, canvas.height);  const data = imageData.data;  for (let i = 0; i < data.length; i += 4) {    const gray = 0.299 * data[i] + 0.587 * data[i+1] + 0.114 * data[i+2];    data[i] = data[i+1] = data[i+2] = gray;  }  ctx.putImageData(imageData, 00);}

3.3 物理引擎集成

将 Canvas 与简单的物理模拟结合,可以创建逼真的运动效果。

class Ball {  constructor(x, y, vx, vy) {    this.x = x; this.y = y;    this.vx = vx; this.vy = vy;    this.radius = 10;  }  update() {    this.vy += 0.5// 重力    this.x += this.vx;    this.y += this.vy;    // 边界反弹    if (this.y + this.radius > canvas.height) {      this.y = canvas.height - this.radius;      this.vy *= -0.8;    }  }  draw() {    ctx.beginPath();    ctx.arc(this.x, this.y, this.radius, 0, Math.PI*2);    ctx.fillStyle = 'blue';    ctx.fill();  }}// 在动画循环中更新并绘制所有小球

3.4 数据可视化

Canvas 是绘制图表、地图等可视化内容的利器。可以封装一个简单的条形图组件:

class BarChart {  constructor(canvas, data) {    this.ctx = canvas.getContext('2d');    this.data = data;    this.width = canvas.width;    this.height = canvas.height;  }  draw() {    const max = Math.max(...this.data);    const barWidth = this.width / this.data.length;    this.data.forEach((value, i) => {      const barHeight = (value / max) * this.height * 0.8;      const x = i * barWidth;      const y = this.height - barHeight;      this.ctx.fillStyle = `hsl(${i * 30}, 70%, 50%)`;      this.ctx.fillRect(x, y, barWidth - 2, barHeight);    });  }}

3.5 游戏开发框架

利用 Canvas 可以构建游戏循环和实体组件系统。以下是一个简单的游戏循环模板:

class Game {  constructor(canvas) {    this.ctx = canvas.getContext('2d');    this.entities = [];    this.lastTime = 0;  }  start() {    this.gameLoop(performance.now());  }  gameLoop(now) {    const delta = (now - this.lastTime) / 1000;    this.lastTime = now;    this.update(delta);    this.render();    requestAnimationFrame((t) => this.gameLoop(t));  }  update(delta) {    this.entities.forEach(e => e.update(delta));  }  render() {    this.ctx.clearRect(00, canvas.width, canvas.height);    this.entities.forEach(e => e.draw(this.ctx));  }}

3.6 高级性能优化

离屏渲染(OffscreenCanvas)可以在 Worker 线程中执行绘图,避免阻塞主线程。浏览器支持 OffscreenCanvas 接口。

// 主线程const offscreen = canvas.transferControlToOffscreen();const worker new Worker('worker.js');worker.postMessage({ canvas: offscreen }, [offscreen]);
// worker.jsself.onmessage = (e) => {  const canvas = e.data.canvas;  const ctx = canvas.getContext('2d');  // 在 Worker 中绘制  ctx.fillStyle = 'red';  ctx.fillRect(00100100);};

Web Workers 处理像素数据:将耗时的图像处理任务交给 Worker,避免界面卡顿。

// 主线程const worker = new Worker('filter-worker.js');worker.postMessage(imageData);worker.onmessage = (e) => {  ctx.putImageData(e.data00);};
// filter-worker.jsself.onmessage = (e) => {  const imageData = e.data;  // 处理 imageData ...  self.postMessage(imageData);};

3.7 现代 Canvas 框架和库
  • Fabric.js:提供对象模型和交互能力,适合图形编辑器。

  • Konva.js:高性能 2D 绘图库,支持事件绑定和动画。

  • Paper.js:基于矢量图形的脚本框架,使用场景图。

  • PixiJS:2D WebGL 渲染引擎,性能卓越,适合游戏和交互应用。

  • Three.js:最流行的 3D 库,封装了 WebGL 细节。

这些库大大简化了复杂场景的开发,开发者可以根据需求选择合适的工具。

总结


Canvas 是 Web 图形开发的基石,从简单的矩形绘制到复杂的 3D 渲染,它提供了丰富的 API 和无限的扩展可能。本文从基础概念出发,涵盖了元素创建、上下文获取、基本绘图、样式、变换、动画、交互和性能优化,随后深入探讨了 WebGL、图像处理、物理引擎、数据可视化、游戏框架以及现代库的应用。

掌握这些知识后,您将能够自信地使用 Canvas 构建各种创意项目,无论是数据可视化、小游戏还是图像处理工具。未来,随着 WebGPU 等新技术的出现,Canvas 的能力还将进一步扩展,值得持续关注和学习。


阅读原文:原文链接


该文章在 2026/4/23 16:33:36 编辑过
关键字查询
相关文章
正在查询...
点晴ERP是一款针对中小制造业的专业生产管理软件系统,系统成熟度和易用性得到了国内大量中小企业的青睐。
点晴PMS码头管理系统主要针对港口码头集装箱与散货日常运作、调度、堆场、车队、财务费用、相关报表等业务管理,结合码头的业务特点,围绕调度、堆场作业而开发的。集技术的先进性、管理的有效性于一体,是物流码头及其他港口类企业的高效ERP管理信息系统。
点晴WMS仓储管理系统提供了货物产品管理,销售管理,采购管理,仓储管理,仓库管理,保质期管理,货位管理,库位管理,生产管理,WMS管理系统,标签打印,条形码,二维码管理,批号管理软件。
点晴免费OA是一款软件和通用服务都免费,不限功能、不限时间、不限用户的免费OA协同办公管理系统。
Copyright 2010-2026 ClickSun All Rights Reserved  粤ICP备13012886号-2  粤公网安备44030602007207号