画布的基本用法

让我们从查看 <canvas> HTML 元素本身开始本教程。在本页末尾,您将了解如何设置画布 2D 上下文并在浏览器中绘制第一个示例。

<canvas> 元素

html
<canvas id="tutorial" width="150" height="150"></canvas>

乍一看,<canvas> 看起来像 <img> 元素,唯一的明显区别是它没有 srcalt 属性。实际上,<canvas> 元素只有两个属性,widthheight。这两个属性都是可选的,也可以使用 DOM 属性 设置。当未指定 widthheight 属性时,画布的初始宽度将为 300 像素,高度为 150 像素。该元素可以通过 CSS 随意调整大小,但在渲染期间,图像会按比例缩放以适应其布局大小:如果 CSS 大小不符合初始画布的比例,则图像会显得扭曲。

注意:如果您的渲染结果出现扭曲,请尝试在 <canvas> 属性中显式指定 widthheight 属性,而不要使用 CSS。

id 属性不是 <canvas> 元素特有的,而是可以应用于任何 HTML 元素的 全局 HTML 属性 之一(例如,class)。始终提供 id 都是一个好主意,因为它使在脚本中识别它变得更加容易。

<canvas> 元素可以像任何普通图像一样进行样式设置(marginborderbackground 等)。但是,这些规则不会影响画布上的实际绘制。我们将在本教程的 专门章节 中看到如何实现这一点。当未对画布应用任何样式规则时,它最初将是完全透明的。

无障碍内容

<canvas> 元素与 <img><video><audio><picture> 元素一样,必须通过提供备用文本来实现无障碍访问,以便在媒体无法加载或用户无法按预期体验它时显示。您应始终提供备用内容、字幕和替代文本,以便适合媒体类型。

提供备用内容非常简单:只需将备用内容插入 <canvas> 元素中,即可供屏幕阅读器、蜘蛛和其他自动化机器人访问。默认情况下,浏览器会忽略容器内的内容,正常渲染画布,除非不支持 <canvas>

例如,我们可以提供画布内容的文本描述,或提供动态渲染内容的静态图像。这可能看起来像这样

html
<canvas id="stockGraph" width="150" height="150">
  current stock price: $3.15 + 0.15
</canvas>

<canvas id="clock" width="150" height="150">
  <img src="images/clock.png" width="150" height="150" alt="A clock" />
</canvas>

告诉用户使用支持画布的不同浏览器并不能帮助那些根本无法阅读画布的用户。提供有用的备用文本或子 DOM 会为原本无法访问的元素添加无障碍功能。

必需的 </canvas> 标签

由于提供备用内容的方式,与 <img> 元素不同,<canvas> 元素 要求 结束标签 (</canvas>)。如果没有此标签,文档的其余部分将被视为备用内容,并且不会显示。

如果不需要备用内容,简单的 <canvas id="foo" role="presentation" …></canvas> 与所有支持画布的浏览器完全兼容。这仅应在画布纯粹用于展示时使用。

渲染上下文

<canvas> 元素创建一个固定大小的绘图表面,该表面公开了一个或多个 渲染上下文,这些上下文用于创建和操作显示的内容。在本教程中,我们将重点关注 2D 渲染上下文。其他上下文可能会提供不同类型的渲染;例如,WebGL 使用基于 OpenGL ES 的 3D 上下文。

画布最初是空白的。要显示内容,脚本首先需要访问渲染上下文并在其上绘制。<canvas> 元素有一个名为 getContext() 的方法,用于获取渲染上下文及其绘制函数。getContext() 接受一个参数,即上下文的类型。对于本教程涵盖的 2D 图形,您指定 "2d" 以获取 CanvasRenderingContext2D

js
const canvas = document.getElementById("tutorial");
const ctx = canvas.getContext("2d");

脚本中的第一行通过调用 document.getElementById() 方法来检索 DOM 中表示 <canvas> 元素的节点。获得元素节点后,您可以使用其 getContext() 方法访问绘图上下文。

检查支持情况

备用内容在不支持 <canvas> 的浏览器中显示。脚本还可以通过测试 getContext() 方法的存在来以编程方式检查支持情况。我们上面的代码片段变成了这样

js
const canvas = document.getElementById("tutorial");

if (canvas.getContext) {
  const ctx = canvas.getContext("2d");
  // drawing code here
} else {
  // canvas-unsupported code here
}

基本模板

这是一个最小的模板,我们将把它用作以后示例的起点。

注意:将脚本嵌入 HTML 中不是一个好习惯。我们在这里这样做是为了使示例保持简洁。

html
<!doctype html>
<html lang="en-US">
  <head>
    <meta charset="utf-8" />
    <title>Canvas tutorial</title>
    <style>
      canvas {
        border: 1px solid black;
      }
    </style>
  </head>
  <body>
    <canvas id="tutorial" width="150" height="150"></canvas>
    <script>
      function draw() {
        const canvas = document.getElementById("tutorial");
        if (canvas.getContext) {
          const ctx = canvas.getContext("2d");
        }
      }
      window.addEventListener("load", draw);
    </script>
  </body>
</html>

脚本包含一个名为 draw() 的函数,该函数在页面加载完成后执行;这是通过监听文档上的 load 事件来实现的。此函数或类似的函数也可以使用 setTimeout()setInterval() 或任何其他事件处理程序来调用,只要页面已首先加载即可。

下面是一个模板在行动中的样子。如这里所示,它最初是空白的。

一个简单的示例

首先,让我们看一下绘制两个相交矩形的简单示例,其中一个矩形具有 alpha 透明度。我们将在后面的示例中更详细地探讨其工作原理。

html
<!doctype html>
<html lang="en-US">
  <head>
    <meta charset="UTF-8" />
    <title>Canvas experiment</title>
  </head>
  <body>
    <canvas id="canvas" width="150" height="150"></canvas>
    <script type="application/javascript">
      function draw() {
        const canvas = document.getElementById("canvas");
        if (canvas.getContext) {
          const ctx = canvas.getContext("2d");

          ctx.fillStyle = "rgb(200 0 0)";
          ctx.fillRect(10, 10, 50, 50);

          ctx.fillStyle = "rgb(0 0 200 / 50%)";
          ctx.fillRect(30, 30, 50, 50);
        }
      }
      draw();
    </script>
  </body>
</html>

此示例看起来像这样