Canvas 入门

发布时间 2023-03-23 11:53:24作者: thby

为什么要使用 Canvas

可能你有同样的疑惑,那不妨先问自己一个问题:当你需要在网页上展示一些形状的时候,你会怎样做?
面对一些简单的形状(点、直线、矩形、直角三角形等)且在仅用于展示的情况下,其实用 HTML 配合 CSS 就可以完成。
对于 CSS 有一定了解的话,你会发现复杂的图形也不过是简单图形的拼接,同样可以用如上的方式来完成。
但是,一旦需要图形和图形之间产生动态联系,HTML 和 CSS 的弊端就暴露了出来:需要同时兼顾页面结构与样式,创作成本增加
举一个例子:使用 HTML 和 CSS 来展示一个角为30°的直角三角形

涉及到角度的话,很自然地可以想到 CSS 中的 transform: rotate() 属性,所以在这个例子中我选择增加一个“遮罩层”,颜色与背景保持一致。
这样一来,根据 \(90°-遮罩层旋转的角度=30°\) 就得到了遮罩层旋转的角度,就得到了图中的效果。
使用 CSS 中的 clip-path 也可以实现多边形的展示(通过设定显示的部分和隐藏的部分),但是想要再对图形进行变换,还需要引入 JavaScript 来实现动态效果,这无疑增加了工作量。
而上面这些内容就是使用 Canvas 的理由:更直接地达成目的。

同样的三角形,使用 canvas 制作还可以调整三角形的大小。在这个过程中仅使用了 HTML 和 JavaScript,而在 HTML 中不用担心页面样式,只专注于 JavaScript 的绘图即可。

Canvas 的由来

提起 Canvas 的由来,MDN 上的说法再一次让我感受到了 Apple 也就是苹果公司的牛犇之处:

<canvas> 最早由 Apple 引入 WebKit,用于 Mac OS X 的 Dashboard,随后被各个浏览器实现。如今,所有主流的浏览器都支持它。
为了自己的产品和品牌无尽地整活就完事了。

Canvas的使用

第一次接触 Canvas

说到 Canvas 的使用,最早接触是在大学一年级。当时有一门课叫做《网页设计与制作》,在那个里面我知道了原来 Canvas 就是一个标签 <canvas></canvas>,在页面结构里包含 <canvas>...</canvas> 不就是 Canvas 的使用了嘛。
而当时的例子也就是用 Canvas 画了一个矩形,我就觉得这跟用具有长度、宽度、背景的 <div> 没有任何区别,于是乎在那之后的很长一段时间里,我觉得 HTML5 并没有什么了不起。

展示 canvas

上面的第一次接触其实也提到了在页面中使用 Canvas 的方式,即 以标签的形式呈现在 HTML 文档中即可。

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
  </head>
  <body>
    <canvas></canvas>
  </body>
</html>

这个时候打开页面发现还是一片空白,但是在开发者模式下可以看到 <canvas> 标签对应与页面中有一个宽度为 300 像素和高度为 150 像素的矩形,而这个就是我们的 canvas 即画布的大小,之后的绘图都会在上面进行。
可以通过 widthheight 两个标签对 canvas 的宽度和高度进行设置,默认情况下宽度和高度如上。

...
    <canvas width="300" height="200"></canvas>
    <!-- 此时宽度为 300px, 高度为 200px -->
...

改变 canvas 内容

不同于以往接触的大部分 HTML 标签,在 <canvas></canvas> 的开始标签和闭合标签内部写入的一切内容(包括文本和其他标签)都会被视为替代内容,即只有在当前浏览器不支持 Canvas 的情况下才会显示出来的内容(类比 <img> 中的 alt 属性应用场景)
那么如何改变 canvas 即画布上的内容就需要用到一开始提到的 JavaScript 来动态绘制内容。
作为 HTML 中的一个标签元素,我们在对 canvas 中的内容进行改变的之前,首先就要获得这个元素

获得 canvas

let canvas = document.getElementsByTagName("canvas")[0];

获取上下文

Canvas 发展至今,除了本文主要关注的 2d 图形以外,还可以对 3d 图形进行绘制。由此,获得 <canvas> 元素后,还需要明确它的适用场景(以 2d 为例)

let canvas = document.getElementsByTagName("canvas")[0];
let canvasContext = canvas.getContext("2d");

现在,canvasContext 就是画布的 2d 对象了,通过调用该对象的方法,就可以描绘一个图形所需要的点、线(直线、曲线)、面(多边形、圆)。

开始绘制

不同于真正地在画布上进行创作,使用 Canvas 绘制图形首先需要我们了解其绘图的原理。
此时可以回想在初中阶段学习到的平面直角坐标系,其将数与形结合起来的特质在今天也应用地相当广泛,而 Canvas 就是其中一个例子。
画布中的坐标系,以左上的画布顶点为公共点,即原点;水平向左为横轴正方向,垂直向下为纵轴正方向。区别于以往了解到的平面直角坐标系

比如 \((100, 100)\) 指的就是画布上,横向看在原点左方 100 像素;纵向看在原点下方 100 像素的点。
知道如何明确点的位置,接下就是路径,也就是一个点如何到另外一个点。
路径的设置就涉及到内置函数 lineToarcTo ,前者绘制直线,后者绘制曲线

let canvas = document.getElementsByTagName("canvas")[0];
let convasContext = canvas.getContext("2d");
// 移动到 (100, 100)
convasContext.moveTo(100, 100);
// 画直线到 (150, 150)
convasContext.lineTo(150, 150);
// 描边
convasContext.stroke();


上段代码中最后的 stroke() 决定了绘图的展示形式,即描边,除此以外还有 fill() 也就是填充。需要注意,填充需要满足绘制的形状为闭合图形。

后续

了解 Canvas 对象的具体用途后,接下来就是根据个人需求结合 Canvas 文档和丰富的第三方库开始进行自己的创作,在这个过程中提升自己的数学功底