Skip to content

HTML5 - Canvas

HTML <canvas> 元素提供了一种强大而灵活的方式,用于直接在网页中使用 JavaScript 绘制图形、制作动画和处理图像。它充当图形的容器;实际的绘图是通过 Canvas API 或 WebGL 等相关 API 完成的。

Canvas API 主要专注于 2D 图形(即 ‘2d’ 上下文)。对于 3D 图形,你通常会使用 WebGL API 并结合 <canvas> 元素。

Canvas 被广泛用于数据可视化、创建游戏、照片处理、实时图形渲染以及生成动态图形元素。

首先,你在 HTML 中添加一个 <canvas> 元素。它需要 width 和 height 属性来定义绘图表面的尺寸(以 CSS 像素为单位)。开始标签和结束标签之间放置的任何内容都用作备用(fallback)内容,适用于不支持 canvas 的浏览器。

<!DOCTYPE html>
<html>
<head>
<title>Canvas Example</title>
<style>
/* Add a border to visualize the canvas area */
#myDrawingCanvas {
border: 1px solid black;
background-color: #f0f0f0; /* Optional background */
}
</style>
</head>
<body>
<h1>My Canvas Drawing</h1>
<canvas id="myDrawingCanvas" width="400" height="300">
Your browser does not support the HTML5 canvas element.
<!-- Fallback content goes here -->
</canvas>
<script src="drawing.js"></script>
</body>
</html>

<canvas> 元素本身只是一个空白位图。要在其上绘图,你需要获取其渲染上下文。最常见的上下文是 '2d',它提供了 2D 绘图功能。

使用 JavaScript 中的 getContext() 方法获取上下文:

// drawing.js
const canvas = document.getElementById('myDrawingCanvas');
// Check if canvas and getContext are supported
if (canvas.getContext) {
// Get the 2D rendering context
const ctx = canvas.getContext('2d');
console.log('Canvas context obtained:', ctx);
// --- 绘图代码在这里 ---
// Example: Draw a simple filled rectangle
ctx.fillStyle = 'red'; // 设置填充颜色
ctx.fillRect(10, 10, 150, 75); // 绘制矩形 (x, y, 宽度, 高度)
// Example: Draw outlined text
ctx.strokeStyle = 'blue';
ctx.lineWidth = 2;
ctx.font = '30px Arial';
ctx.strokeText('Hello Canvas!', 50, 150); // 绘制文本 (文本, x, y)
} else {
console.error('Canvas not supported by this browser.');
// Handle lack of canvas support (e.g., display message from fallback content)
}

所有绘图操作都在 ctx(上下文)对象上执行。

canvas 使用网格系统。canvas 的左上角是坐标 (0, 0)。X 值向右增加,Y 值向下增加。

2D 上下文提供了绘制各种形状、线条、文本和图像的方法。

  • ctx.fillRect(x, y, width, height): 绘制一个填充矩形。
  • ctx.strokeRect(x, y, width, height): 绘制矩形的轮廓。
  • ctx.clearRect(x, y, width, height): 清除指定的矩形区域,使其透明。

路径(线条、曲线、自定义形状)

Section titled “路径(线条、曲线、自定义形状)”

路径用于创建复杂的形状、线条和曲线。过程通常包括:

  1. ctx.beginPath(): 开始一个新的路径。
  2. 使用 moveTo(x, y)、lineTo(x, y)、arc(x, y, radius, startAngle, endAngle)、quadraticCurveTo(cp1x, cp1y, x, y)、bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y) 等路径方法来定义形状。
  3. ctx.closePath()(可选): 通过绘制一条线回到起始点来闭合路径。
  4. ctx.fill(): 使用当前的 fillStyle 填充当前路径。
  5. ctx.stroke(): 使用当前的 strokeStyle 和线条样式绘制当前路径的轮廓。
// Example: Draw a triangle
ctx.beginPath();
ctx.moveTo(75, 50); // 起始点
ctx.lineTo(100, 75); // 画线到底部右侧
ctx.lineTo(100, 25); // 画线到顶部右侧
ctx.closePath(); // 画线回到起始点
ctx.fillStyle = 'green';
ctx.fill(); // 填充三角形
ctx.strokeStyle = 'darkgreen';
ctx.stroke(); // 绘制三角形轮廓
  • ctx.font = '值': 设置字体属性(例如,'bold 48px serif')。
  • ctx.fillText(text, x, y, [maxWidth]): 绘制填充文本。
  • ctx.strokeText(text, x, y, [maxWidth]): 绘制轮廓文本。
  • ctx.textAlign = '值': 设置文本对齐方式(start、end、left、right、center)。
  • ctx.textBaseline = '值': 设置基线对齐方式(top、hanging、middle、alphabetic、ideographic、bottom)。
  • ctx.fillStyle = color | gradient | pattern: 设置用于填充形状的样式。
  • ctx.strokeStyle = color | gradient | pattern: 设置用于形状轮廓(描边)的样式。
  • ctx.lineWidth = value: 设置线条宽度。
  • ctx.lineCap = 'butt' | 'round' | 'square': 设置线条末端的外观。
  • ctx.lineJoin = 'round' | 'bevel' | 'miter': 设置线条交汇处角点的外观。
  • ctx.globalAlpha = value: 设置透明度(0.0 = 透明,1.0 = 不透明)。
  • 渐变 (Gradients): ctx.createLinearGradient()(创建线性渐变)、ctx.createRadialGradient()(创建径向渐变)。
  • 图案 (Patterns): ctx.createPattern(image, repetition)(创建图案)。
  • ctx.drawImage(image, dx, dy): 在 canvas 上绘制图像(来自 <img>、<video> 或另一个 <canvas>)到 (dx, dy) 坐标。
  • ctx.drawImage(image, dx, dy, dWidth, dHeight): 绘制并缩放图像。
  • ctx.drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight): 将图像的一部分(源 sx, sy, 源宽度, 源高度)绘制到 canvas 上(目标 dx, dy, 目标宽度, 目标高度)。

上下文允许你对坐标系统进行变换:

  • ctx.translate(x, y): 将原点 (0,0) 移动到 (x, y)。
  • ctx.rotate(angle): 围绕当前原点顺时针旋转 canvas(角度以弧度为单位)。
  • ctx.scale(x, y): 将 canvas 在水平方向按 x 比例缩放,垂直方向按 y 比例缩放。
  • ctx.transform(a, b, c, d, e, f) / ctx.setTransform(...): 直接修改变换矩阵。
  • ctx.save(): 保存当前的绘图状态(样式、变换)。
  • ctx.restore(): 恢复最近保存的绘图状态。

Canvas 动画通常使用 JavaScript 的定时函数(setInterval、setTimeout)创建,或者更常用的是 requestAnimationFrame()。基本循环包括:

  1. 清除 canvas(例如,ctx.clearRect(0, 0, canvas.width, canvas.height))。
  2. 更新动画变量(位置、大小等)。
  3. 在新状态下绘制场景。
  4. 使用 requestAnimationFrame(你的绘图函数) 请求下一帧。

Canvas 2D API 得到所有现代桌面和移动浏览器的普遍支持。像 Internet Explorer 8 及以下的老旧浏览器不原生支持它。

对于复杂的图形或游戏,可以考虑使用专门的 JavaScript 库(例如 Fabric.js、Konva.js、p5.js 用于 2D,或 Three.js、Babylon.js 用于 WebGL/3D),它们基于 Canvas API 构建并简化了许多常见任务。