canvas 的使用

一、canvas 简介

Canvas 是 HTML5 规范中的一个元素,它允许您使用 JavaScript 在网页上绘制图形、图像以及其他视觉元素。通过 Canvas,您可以在浏览器中创建动态的图表、图像编辑器、游戏以及其他交互式的视觉效果。

Canvas 元素本身是一个矩形区域,可以通过 JavaScript 的 Canvas API 来操作。在 Canvas 上绘制的内容是由 JavaScript 代码生成的,包括图形、图像和文本。

以下是 Canvas 的基本使用步骤:

  1. 创建 Canvas 元素: 在 HTML 中,使用<canvas>标签来创建 Canvas 元素,指定其宽度和高度。

    <canvas id="myCanvas" width="400" height="200"></canvas>
    
  2. 获取上下文: 使用 JavaScript 获取 Canvas 的绘图上下文,通常是 2D 上下文。

    var canvas = document.getElementById("myCanvas");
    var ctx = canvas.getContext("2d");
    
  3. 绘制图形: 使用绘图上下文的方法来绘制各种图形、图像和文本。例如,使用fillRect()方法绘制矩形。

    ctx.fillStyle = "rgb(200, 0, 0)";
    ctx.fillRect(10, 10, 100, 100);
    
  4. 绘制图像: 使用drawImage()方法将图像绘制到 Canvas 上。

    var img = new Image();
    img.src = "image.jpg";
    img.onload = function () {
      ctx.drawImage(img, 0, 0);
    };
    
  5. 动画和交互: 结合定时器和事件处理程序,您可以在 Canvas 上创建动画和交互式内容。

Canvas API 提供了许多方法来控制绘图、颜色、变换、文本等方面的操作。您可以在 Canvas 上绘制线条、矩形、圆形、路径,以及使用渐变、阴影等增加图形的复杂性。

需要注意的是,虽然 Canvas 非常强大,但它是基于 JavaScript 的,因此在处理复杂的图形和动画时可能需要处理性能和优化的问题。

二、canvas 示例

2.1 坐标轴-栅格

在我们开始画图之前,我们需要了解一下画布栅格(canvas grid)以及坐标空间。

如图所示,canvas 元素默认被网格所覆盖。

Alt text

  • 通常来说网格中的一个单元相当于 canvas 元素中的一像素。

  • 栅格的起点为左上角(坐标为(0,0))。所有元素的位置都相对于原点定位。所以图中蓝色方形左上角的坐标为距离左边(X 轴)x 像素,距离上边(Y 轴)y 像素(坐标为(x,y))。最后我们会平移原点到不同的坐标上,旋转网格以及缩放。现在我们还是使用原来的设置。

2.2 绘制矩形

不同于 SVG,<canvas>只支持两种形式的图形绘制:矩形和路径(由一系列点连成的线段)。所有其他类型的图形都是通过一条或者多条路径组合而成的。不过,我们拥有众多路径生成的方法让复杂图形的绘制成为了可能。

首先,我们回到矩形的绘制中。canvas 提供了三种方法绘制矩形:

  • fillRect(x, y, width, height)

绘制一个填充的矩形

  • strokeRect(x, y, width, height)

绘制一个矩形的边框

  • clearRect(x, y, width, height)

清除指定矩形区域,让清除部分完全透明。

上面提供的方法之中每一个都包含了相同的参数。x 与 y 指定了在 canvas 画布上所绘制的矩形的左上角(相对于原点)的坐标。width 和 height 设置矩形的尺寸。

2.2.1 绘制示例 1

实际效果

Alt text

const canvas = document.getElementById("canvas-container");

// 获取一个2D绘图上下文,该上下文将用于在Canvas上进行绘制
const ctx = canvas.getContext("2d");

// 设置了绘图上下文的填充颜色。
ctx.fillStyle = "rgb(200,0,0)";

/* fillRect() 是一个绘图上下文的方法,
  它接受四个参数:矩形的左上角 x 坐标、左上角 y 坐标、矩形的宽度和矩形的高度。
  在这个例子中,矩形的左上角位于坐标 (10, 10),宽度是 55,高度是 50。
*/
ctx.fillRect(10, 10, 55, 50);

// 绘制第二个
ctx.fillStyle = "rgba(0, 0, 200, 0.5)";
ctx.fillRect(30, 30, 55, 50);

2.2.2 绘制示例 2

实际效果

Alt text

const canvas = document.getElementById("canvas-container");

// 获取一个2D绘图上下文,该上下文将用于在Canvas上进行绘制
const ctx = canvas.getContext("2d");

// 绘制矩形,矩形的左上角位于坐标 (25, 25),宽度是 100,高度是 100。
ctx.fillRect(25, 25, 100, 100);

// 清除指定矩形区域,让清除部分完全透明,清除从坐标 (25, 25),宽度是 60,高度是60的矩形
ctx.clearRect(45, 45, 60, 60);

// 绘制边框:一个从坐标 (50, 50),宽度是 50,高度是50的矩形的边框
ctx.strokeRect(50, 50, 50, 50);

2.3 绘制路径

图形的基本元素是路径。路径是通过不同颜色和宽度的线段或曲线相连形成的不同形状的点的集合。一个路径,甚至一个子路径,都是闭合的。使用路径绘制图形需要一些额外的步骤。

  • 首先,你需要创建路径起始点。
  • 然后你使用画图命令去画出路径。
  • 之后你把路径封闭。
  • 一旦路径生成,你就能通过描边或填充路径区域来渲染图形。

以下是所要用到的函数:

beginPath() 新建一条路径,生成之后,图形绘制命令被指向到路径上生成路径。

moveTo(x, y) 将笔触移动到指定的坐标 x 以及 y 上。当 canvas 初始化或者 beginPath()调用后,你通常会使用 moveTo()函数设置起点。 我们也能够使用 moveTo()绘制一些不连续的路径

closePath() 闭合路径之后图形绘制命令又重新指向到上下文中。

stroke() 通过线条来绘制图形轮廓。

fill() 通过填充路径的内容区域生成实心的图形。

lineTo(x, y) 绘制一条从当前位置到指定 x 以及 y 位置的直线。

生成路径的第一步叫做 beginPath()。本质上,路径是由很多子路径构成,这些子路径都是在一个列表中,所有的子路径(线、弧形、等等)构成图形。而每次这个方法调用之后,列表清空重置,然后我们就可以重新绘制新的图形。

备注: 当前路径为空,即调用 beginPath() 之后,或者 canvas 刚建的时候,第一条路径构造命令通常被视为是 moveTo(),无论实际上是什么。出于这个原因,你几乎总是要在设置路径之后专门指定你的起始位置。

第二步就是调用函数指定绘制路径,本文稍后我们就能看到了。

第三,就是闭合路径 closePath(),不是必需的。这个方法会通过绘制一条从当前点到开始点的直线来闭合图形。如果图形是已经闭合了的,即当前点为开始点,该函数什么也不做。

2.3.1 绘制三角形

实际效果

Alt text

function draw() {
  const canvas = document.getElementById("canvas-container");
  if (canvas.getContext) {
    const ctx = canvas.getContext("2d");

    // 新建一条路径,生成之后,图形绘制命令被指向到路径上生成路径
    ctx.beginPath();

    // 设置起始位置75,50
    ctx.moveTo(75, 50);

    // 绘制直线到100,75
    ctx.lineTo(100, 75);

    // 绘制直线到100,25
    ctx.lineTo(100, 25);

    //  通过填充路径的内容区域生成实心的图形。
    ctx.fill();
  }
}

2.3.2 绘制圆-emoji 表情

实际效果

Alt text

arc(x, y, radius, startAngle, endAngle, anticlockwise)

arc(开始横坐标x,开始纵坐标y,半径radius, 开始角度startAngle, 结束角度endAngle, 顺时针或者逆时针(默认为顺时针)anticlockwise)

画一个以(x,y)为圆心的以 radius 为半径的圆弧(圆),从 startAngle 开始到 endAngle 结束,按照 anticlockwise 给定的方向(默认为顺时针)来生成。

arcTo(x1, y1, x2, y2, radius)

根据给定的控制点和半径画一段圆弧,再以直线连接两个控制点。

stroke()

通过线条来绘制图形轮廓。

const canvas = document.getElementById("canvas-container");

if (canvas.getContext) {
  const ctx = canvas.getContext("2d");

  // 新建一条路径,生成之后,图形绘制命令被指向到路径上生成路径
  ctx.beginPath();

  //画一个以(75,75)坐标为圆心的以 50px 为半径的圆弧(圆),从 0 开始到 Math.PI * 2(2π为一个圆) 结束,
  // 按照顺时针给定的方向(默认为顺时针)来生成。
  ctx.arc(75, 75, 50, 0, Math.PI * 2, true); // 绘制

  // 移动到110,75坐标
  ctx.moveTo(110, 75);

  //画一个以(75,75)坐标为圆心的以 35px 为半径的圆弧(圆),从 0 开始到 Math.PI(π为半个圆) 结束,
  // 按照逆时针来生成。
  ctx.arc(75, 75, 35, 0, Math.PI, false); // 口 (顺时针)

  // 移动到65, 65坐标
  ctx.moveTo(65, 65);

  //画一个以(60,65)坐标为圆心的以 5px 为半径的圆弧(圆),从 0 开始到 Math.PI*2(2π为一个圆) 结束,
  // 按照顺时针来生成。
  ctx.arc(60, 65, 5, 0, Math.PI * 2, true); // 左眼

  // 移动到95, 65坐标
  ctx.moveTo(95, 65);

  //画一个以(60,65)坐标为圆心的以 5px 为半径的圆弧(圆),从 0 开始到 Math.PI*2(2π为一个圆) 结束,
  // 按照顺时针来生成。
  ctx.arc(90, 65, 5, 0, Math.PI * 2, true); // 右眼

  // 通过线条来绘制图形轮廓。
  ctx.stroke();
}
Contributors: masecho