HTML 的 <canvas> 元素

1. 引言

<canvas> 是 HTML5 中引入的一个强大元素,它提供了一个可以通过 JavaScript 脚本绘制图形的"画布"。与使用 DOM 或 CSS 创建图形不同,<canvas> 提供了一套底层的、基于像素的 2D 绘图 API,让你能够动态生成图表、游戏画面、图像处理、动画等丰富内容。本文将带你从零开始,掌握 <canvas> 的核心概念与实战技巧。

2. 什么是 <canvas>

<canvas> 元素本身只是一个透明的矩形区域,它不具备任何绘图能力。真正的绘图工作是通过 JavaScript 获取其"渲染上下文"(Rendering Context)来完成的。最常用的是 2d 上下文,它提供了绘制形状、文本、图像和处理像素的方法。

2.1 基本结构

在 HTML 中插入一个 <canvas> 元素非常简单:

html 复制代码
<canvas id="myCanvas" width="400" height="300">
  您的浏览器不支持 Canvas 元素。
</canvas>
  • id:用于在 JavaScript 中定位元素。
  • widthheight:定义画布的尺寸(像素)。注意:通过 CSS 设置宽高会拉伸画布,而不会改变其实际分辨率。
  • 标签内的文本:当浏览器不支持 <canvas> 时显示的回退内容。

2.2 获取渲染上下文

要开始绘图,首先需要获取渲染上下文:

javascript 复制代码
const canvas = document.getElementById('myCanvas');
const ctx = canvas.getContext('2d');

ctx 对象就是你的"画笔",所有绘图方法都挂载在这个对象上。

3. 核心绘图 API

3.1 绘制矩形

矩形是 <canvas> 中唯一可以直接绘制的形状。其他形状(如圆形、多边形)需要通过路径(Path)来绘制。

javascript 复制代码
// 绘制一个填充的矩形
ctx.fillStyle = 'lightblue';
ctx.fillRect(10, 10, 150, 100); // (x, y, width, height)

// 绘制一个边框矩形
ctx.strokeStyle = 'red';
ctx.lineWidth = 3;
ctx.strokeRect(200, 10, 150, 100);

// 清除一个矩形区域(使其变透明)
ctx.clearRect(50, 50, 80, 60);

3.2 绘制路径(Path)

路径是绘制复杂图形的基础。基本步骤是:beginPath() -> 定义路径 -> closePath()(可选) -> fill()stroke()

javascript 复制代码
// 绘制一个圆形
ctx.beginPath();
ctx.arc(200, 200, 50, 0, Math.PI * 2); // (x, y, 半径, 起始角度, 结束角度)
ctx.fillStyle = 'green';
ctx.fill();

// 绘制一个三角形
ctx.beginPath();
ctx.moveTo(300, 300);   // 移动到起点
ctx.lineTo(350, 250);   // 画线到第二个点
ctx.lineTo(400, 300);   // 画线到第三个点
ctx.closePath();        // 闭合路径(回到起点)
ctx.strokeStyle = 'blue';
ctx.lineWidth = 2;
ctx.stroke();

3.3 样式与颜色

  • fillStyle:设置填充颜色(支持颜色名、十六进制、RGB、RGBA、渐变、图案)。
  • strokeStyle:设置描边颜色。
  • lineWidth:设置线条宽度。
  • globalAlpha:设置全局透明度(0.0 到 1.0)。
javascript 复制代码
// 使用半透明颜色
ctx.fillStyle = 'rgba(255, 0, 0, 0.5)';
ctx.fillRect(50, 50, 100, 100);

3.4 绘制文本

javascript 复制代码
ctx.font = '30px Arial';
ctx.fillStyle = 'black';
ctx.fillText('Hello Canvas!', 50, 150); // 填充文本

ctx.strokeStyle = 'red';
ctx.strokeText('Hello Canvas!', 50, 200); // 描边文本

3.5 绘制图像

可以将已有的 <img><video> 或其他 <canvas> 元素绘制到画布上。

javascript 复制代码
const img = new Image();
img.onload = function() {
  ctx.drawImage(img, 0, 0, 200, 150); // (图像, x, y, 宽, 高)
};
img.src = 'example.png';

注意 :图像加载是异步的,必须在 onload 回调中绘制。

4. 实战:绘制一个简单的柱状图

下面我们综合运用所学知识,绘制一个简单的柱状图。

html 复制代码
<!DOCTYPE html>
<html>
<head>
  <title>Canvas 柱状图</title>
</head>
<body>
  <canvas id="chartCanvas" width="500" height="300"></canvas>
  <script>
    const canvas = document.getElementById('chartCanvas');
    const ctx = canvas.getContext('2d');

    const data = [120, 200, 150, 80, 70, 110];
    const barWidth = 60;
    const gap = 20;
    const startX = 40;
    const chartHeight = 250;

    // 绘制背景
    ctx.fillStyle = '#f0f0f0';
    ctx.fillRect(0, 0, canvas.width, canvas.height);

    // 绘制柱子
    data.forEach((value, index) => {
      const barHeight = (value / Math.max(...data)) * chartHeight;
      const x = startX + index * (barWidth + gap);
      const y = canvas.height - 30 - barHeight;

      ctx.fillStyle = 'steelblue';
      ctx.fillRect(x, y, barWidth, barHeight);

      // 在柱子上方显示数值
      ctx.fillStyle = 'black';
      ctx.font = '14px Arial';
      ctx.textAlign = 'center';
      ctx.fillText(value, x + barWidth / 2, y - 5);
    });
  </script>
</body>
</html>

5. 动画与性能优化

5.1 创建动画循环

使用 requestAnimationFrame 创建流畅的动画。

javascript 复制代码
function draw() {
  // 清除画布
  ctx.clearRect(0, 0, canvas.width, canvas.height);

  // ... 绘制当前帧的内容 ...

  // 请求下一帧
  requestAnimationFrame(draw);
}

// 启动动画
requestAnimationFrame(draw);

5.2 性能优化建议

  • 避免频繁重绘:只在需要时更新画布。
  • 分层 Canvas :将静态背景和动态元素放在不同的 <canvas> 上,只重绘动态层。
  • 离屏渲染 :先在内存中的 <canvas> 上绘制复杂图形,再一次性 drawImage 到主画布。
  • 减少状态变更 :频繁修改 fillStylestrokeStyle 等属性会消耗性能,尽量批量绘制相同样式的图形。

6. 总结

<canvas> 元素为 Web 开发打开了图形和动画的大门。通过 JavaScript 的 2D 上下文,你可以实现从简单的图表到复杂的游戏引擎。掌握路径、样式、图像处理和动画循环是进阶的关键。希望本文能帮助你迈出 Canvas 编程的第一步,在实际项目中创造出令人惊叹的视觉效果。