canvas 快速入门

2022-10-24 19:05:41 浏览数 (1)

canvas 快速入门

在本文中,我们将学习Canvas的特性,包括如何在HTML文档中引入Canvas以及在Canvas上绘制图形和各种对象。我们也将学习如何修改绘制在Canvas上的图形和对象,以及如何擦除它们。最后,将通过一个例子来学习如何将Canvas,尺寸设置为浏览器窗口的大小。

1. 认识 canvas 元素

videoaudio类似,canvas元素完全不需要任何外部插件就能够运行。你只需要使用 HTML 并使用2D谊染上下文API(2D rendering context API)编写一些JavaScript代码。即使你现在还不了解什么是2D渲染上下文API,也不用担心一你很快就会熟悉这方面知识。

canvas元素的用法很简单——我想说的是非常简单。开始只需要添加下面的代码:

代码语言:javascript复制
<canvas width="500"height="500">
<!--在此插入后备内客-->
</canvas>

我想我应该坦诚地告诉你,这段代码实际上并没有实现什么特殊的效果。它仅仅创建了一个新的空白 canvas 元素,还无法看到任何内容,因为还没有使用2D渲染上下文执行任何操作。我们很快就会在canvas 上绘制一些图形,而绘制这些图形也是很简单的。

目前,在创建 canvas 元素时,需要特别注意的是widthheight属性。这两个属性明确地定义了canvas 元素的尺寸,从而相应地定义了2D渲染上下文的尺寸。如果不使用这些属性定义canvas元素的尺寸,那么2D渲染上下文会被设置为使用默认宽度和高度,分别是300150像素。在本文后面的内容中,我们将学习如何创建一个能够动态修改尺寸并填充整个浏览器窗口的canvas元素。

大多数现代浏览器都支持 canvas 元素及其主要特性,但是毫无疑问,IE还不支持这些,至少在IE9之前的版本是不支持的。如果你接受这个现实,那么可以在 canvas 元素的后备内容中添加一条友好的消息,告诉使用IE的用户应该升级他们的浏览器。另外的方法是使用强大的 ExplorerCanvas 脚本,它是由Google的一些研究人员开发的。这个方法的好处在于只需要在网页上添加一个脚本,然后canvas元素就能够在IE9之前的版本上正常运行了。

如果对此感兴趣,可以从ExplorerCanvas网站下载这个脚本,然后按照说明进行安装。

2. 2D 渲染上下文

canvas元素并非Canvas中最强大的部分,真正的关键部分是「2D 渲染上下文」,这是你真正绘制图形的地方。canvas元素的用途只是作为2D渲染上下文的包装器,它包含绘图和图形操作所需要的全部方法和丰富功能。理解这一点是很重要的,所以我再强调一下:「绘图是在2D渲染上下文中进行的,而不是在canvas元素中进行。」可以通过canvas元素访问和显示2D渲染上下文。

2.1 坐标系统

2D 渲染上下文是一种基于屏幕的标准绘图平台。与其他的2D平台类似,它采用平面的「笛卡儿坐标系统」,左上角为原点(0, 0)。向右移动时,x坐标值会增加,向下移动时,y坐标值会增加。如果你想把图形绘制到正确的位置上,一定要理解这个坐标系统。

坐标系统的1个单位通常相当于屏幕的1个像素,所以位置(24, 30)是向右24像素和向下30像素的位置。有时候坐标系统的1个单位相当于2个像素(例如,在一些高分辨率显示器中),但是一般的经验法则是1个坐标单位等于1个屏幕像素。

2.2 访问 2D 渲染上下文

暂时不解释这个概念,先来使用一下。我们先创建一个空白canvas元素:

代码语言:javascript复制
<canvas id="myCanvas" width="500" height="500">
  <!--Insert fallback content here -->
</canvas>

如果现在运行,你不会看到任何内容,因此我们要访问2D渲染上下文,这样就可以开始绘图了。

代码语言:javascript复制
const canvas = document.getElementById("myCanvas");
const context = canvas.getContext ("2d");

在这个例子中,我们将这个canvas元素赋值给一个变量,然后再通过调用getContext方法将得到的2D渲染上下文赋给另一个变量。

有了包含2D渲染上下文的变量之后,就可以开始绘制图形了。最令人激动的时刻到来了!在上下文变量声明语句之后添加下面这行代码:

代码语言:javascript复制
context.fillRect(40, 40, 100, 100);

刷新页面,你会看到一些令人惊奇的变化,页面上出现一个黑色的矩形,这个矩形是黑色的,因为Canvas所绘制元素的默认颜色是黑色。我们将在本文后面学习如何使用其他颜色。

image-20220608105903974

3. 绘制基本图形和线条

正如你所看到的,绘制一个正方形是非常简单的。只需要使用一行代码,即调用fillRect方法:

代码语言:javascript复制
context.fillRect(40, 40, 100, 100);

需要注意的一点是,调用的方法是fillRect,而不是fillSquare

创建一个矩形需要输入4个参数。前两个参数是正方形原点(左上角)的(x, y)坐标值,其余两个参数是矩形的「宽度」「高度」。矩形宽度是(x, y)位置向右绘制的距离,而矩形高度是(x, y)位置向下绘制的距离。你现在就能明白,为什么理解坐标系统很重要,否则你可能会误认为高度是指 从(x, y)位置向上绘制的距离。fillRect方法可以重写为以下形式,从而方便对参数的理解:

代码语言:javascript复制
context.fillRect (x,y,width,height);

如果要在不同的位置绘制矩形呢?很简单,只需要修改(x, y)位置值。例如,将x坐标修改为200y坐标修改为300

这正是Canvas的美妙之处。操作你所绘制的对象是非常简单的,只需要修改一些参数值。

❝注意有一个问题可能不太明显,如果你绘制的图形原点位于canvas元素之外,那么它将无法显示在屏幕上。只有当图形的原点或者某些部分位于canvas元素之内时,它才是可见的。 ❞

fillRect相对应的方法是strokeRectfillRect绘制一个矩形并给它填充颜色(在我们的例子中是黑色),strokeRect则绘制一个矩形并给它绘制边框,也就是用线条绘制出矩形的轮廓。如果将使用fillRect的例子修改为使用strokeRect,那么你就会明白我所说的意思了。

image-20220608122748832

矩形现在加上了轮廓线,它实际上变成了中空的。由此可见,绘图是很有意思的,但是如何绘制一些更高级的图形呢,例如粗线条?没问题。

3.1 线条

绘制线条与绘制图形有一些区别。它们实际上称为路径。要绘制一个简单的路径,首先必须在 2D 渲染上下文中调用beginPath方法,意思实际上就是说:“准备,要开始画路径了。”下一个调用的方法是moveTo,它会设置要绘制路径的原点坐标(x, y)。然后调用lineTo方法设置线条的终点坐标(x, y),再调用closePath完成路径的绘制。最后,调用stroke绘制它的轮廓,显示线条。将全部步骤放到一起,就得到了下面的代码:

代码语言:javascript复制
context.beginPath(); // 开始路径
context.moveTo(40, 40); // 设置路径原点
context.lineTo(340, 40); // 设置路径终点
context.closePath(); // 结束路径
context.stroke(); // 绘出路径轮赤

最后,我们得到一条直线。

image-20220608123316666

但是,直线并不一定是水平或垂直的,通过修改lineTo方法的坐标(x, y)参数,就能够绘制出斜线:

代码语言:javascript复制
context.lineTo(340, 340);

结果如下。

image-20220608123548861

直线本身并没有什么特别的,但是通过组合,它们能够产生复杂且令人惊奇的图形。接下来我们来看看如何画一个圆形?

3.2 圆形

要理解圆形与矩形之间存在很大区别并不难。然而,认识这一点能够说明为什么在Canvas中绘制圆形与矩形也有很大区别。圆形是一个非常复杂的形状,因此Canvas实际上并没有专门绘制圆形的方法。但是有一个方法可以绘制圆弧,圆弧实际上是圆形的组成部分一首尾相连的圆弧就是圆形。

这有点难懂,所以我们暂且不去解释,先在Canvas中创建一个圆形:

代码语言:javascript复制
context.beginPath(); // 开始路径
context.arc(230, 90, 50, 0, Math.PI*2, false); // 绘制一个周形
context.closePath(); // 结来路径
context.fill(); // 填充路径

image-20220608125635852

你现在已经理解第一行及最后两行代码了,它们负责开始和结束路径(即圆弧),然后在它们完成时填充路径(fill是与stroke类似的方法)。最关键的是第二行代码,它包含绘制圆形所需要的全部信息。这似乎有些复杂,所以让我们来分析一下。

创建一个圆弧需要使用6个参数:「圆弧原点的(x, y)坐标值」(也是我们例子中的圆心)、「圆弧半径」「开始角度」「结束角度」和一个「布尔值」,如果圆弧按逆时针方向绘制,那么它为tue,否则它为false。方法arc可以重写为下面更具可读性的形式:

代码语言:javascript复制
context.arc(x, y, radius, startAngle, endAngle, anticlockwise);

前面三个参数都很简单,这里不过多解释。开始角度和结束角度参数表面上很简单,但是需要适当解释才能够很好地理解它们的使用方法。

一定要注意,Canvas中的角度是以弧度而不是角度为单位的。简单地说,360度(一个完整的圆)是pi的2倍)弧度。

那么,现在你对角度在Canvas中的用法有所了解了。让我们把注意力转移回画圆形的例子。在那个例子中,我们所画弧线的开始角度是0,结束角度是Math.PI*2,它们就是圆的开始和结束角度。如果你还不确定,请对照上图。

❝注意:要在JavaScript中使用pi的值,你需要使用Math对象,它是一个特殊对象,允许你完成各种强大的数学计算。我们还会在其他一些任务中使用这个对象,如生成随机数。 ❞

那么,如果想要画一个半圆,应该如何设置结束角度呢?没错,非常简单,其JavaScript代码如下:

代码语言:javascript复制
context.arc(230, 90, 50, 0, Math.PI, false); // 给制一个半圆

如果一切正常,应该会在浏览器上看到一个半圆。

image-20220608125934485

❝注意:虽然arc方法的第6个参数是可选的,但是如果不传入这个参数,Firefox会抛出一个错误。因此,最好保留这个参数,以便明确地指定孤线的绘制方向。 ❞

你还可以对角度进行任意调整,以创建1/4圆和任意饼形。然而,如果你想要了解这些图形的绘制方法,请另找时间进行尝试。我们需要继续关注更重要的方面,例如,修改图形的颜色!

4. 样式

黑色太单调了,要是有一种方法能够修改图形和线条颜色该多好,有办法吗?这个方法容易吗?也是用一行代码就能实现吗?完全正确!我绝对没有说谎。让我们马上修改本文开头所创建的正方形的颜色。

代码语言:javascript复制
context.fillStyle = "rgb(255, 0, 0)";
context.fillRect(40, 40, 100, 100);

通过设置2D渲染上下文的fillSty1e属性,你就能够修改形状和路径的填充颜色。在前一个例子中,我们赋值了一个“rgb(红、绿、蓝)”颜色值,但是你也可以使用任何有效的 CSS 颜色值,如十六进制码(例如,#FF0000)或单词“red”。在这个例子中,颜色值设置为红色(纯红色,没有绿色和蓝色),最后正方形应该如下图所示。

image-20220608130428957

但是先不要太高兴,因为它还有一个问题,那就是在设置fillSty1e属性之后,你所绘制的所有图形都会采用这个颜色。如果你接受这个结果,它就不是问题。但是如果你只希望修改一个对象的颜色,那么你一定要注意。有一个方法可以解决这个问题,就是当你在Canvas上绘制对象时,将fillStyle属性设置回黑色(或其他颜色),例如:

代码语言:javascript复制
context.fillStyle = "rgb(255, 0, 0)";
context.fillRect(40, 40, 100, 100); // 红色正方形
context.fillRect(180, 40, 100, 100); // 红色正方形
context.fillStyle = "rgb(0, 0, 0)";
context.fillRect(320, 40, 100, 100); // 黑色正方形

结果如下图所示。

image-20220608130952785

还可以在描边图形和路径上使用strokeStyle属性实现变色效果。例如,下面的代码与前一个例子相同,唯一区别是它使用笔画描边而不是填充:

代码语言:javascript复制
context.strokeStyle = "rgb(255, 0, 0)";
context.strokeRect(40, 40, 100, 100); // 红色正方形
context.strokeRect(180, 40, 100, 100); // 红色正方形
context.strokeStyle = "rgb(0, 0, 0)";
context.strokeRect(320, 40, 100, 100); // 黑色正方形

结果如下图所示。

image-20220608131240199

❝注意:完全可以同时使用fillSty1estrokeStyle为图形设置不同的填充和描边颜色。 ❞

这其中并没有什么复杂的地方,所有代码都非常简单。修改线条的颜色也是非常简单的:

代码语言:javascript复制
context.strokeStyle = "rgb(255, 0, 0)";
context.beginPath();
context.moveTo(40, 180);
context.lineTo(420, 180); // 红色线条
context.closePath();
context.stroke();
context.strokeStyle = "rgb(0, 0, 0)";
context.beginPath();
context.moveTo(40, 220);
context.lineTo(420, 220); // 黑色线条
context.closePath();
context.stroke();

结果如下图所示。

image-20220608131610028

以上就是在Canvas中修改颜色的所有方法。

「修改线宽」

修改颜色很有意思,但是我们例子中的线条还有些细。Canvas有一个方法可以增加线宽,即 2D 渲染上下文的lineWidth属性。lineWidth,属性的默认值为1,但是可以将它修改为任意值。例如,修改红线和黑线的宽度:

代码语言:javascript复制
context.lineWidth = 5; //加粗线条
context.strokeStyle = "rgb(255, 0, 0)";
context.beginPath();
context.moveTo(40, 180);
context.lineTo(420, 180); //红线
context.closePath();
context.stroke();
context.lineWidth = 20; //进-步加瓶线条
context.strokeStyle = "rgb(0, 0, 0)";
context.beginPath();
context.moveTo(40, 220);
context.lineTo(420, 220); //黑线
context.closePath();
context.stroke()

其结果是得到一条稍粗的红线和一条非常粗的黑线。

image-20220608134345598

lineWidth属性也会影响图形:

代码语言:javascript复制
context.lineWidth = 5; // 加瓶线条
context.strokeStyle = "rgb(255, 0, 0)";
context.strokeRect(40, 40, 100, 100); // 红色正方形
context.strokeRect(180, 40, 100, 100); // 红色正方形
context.lineWidth = 20; // 进一步加粗线条
context.strokeStyle = "rgb(0, 0, 0)";
context.strokeRect(320, 40, 100, 100); // 黑色正方形

你可能已经猜到,最终得到两个边框稍粗的红色正方形和一个边框非常粗的黑色正方形。

image-20220608134713819

你现在已经掌握了基本的绘图方法,但是在继续学习真正强大的特性之前,我们还需要学习其他一些特性。

5. 绘制文本

Canvas 不仅能绘制图形,还能够显示文本。老实说,与使用传统的HTML元素(如p元素)创建文本相比,使用Canvas绘制文本通常并不是好方法,原因如下。

Canvas 中的文本是以图像形式绘制的,这意味着它无法像HTML文档中的普通文字一样用鼠标指针选取一它实际上不是文本,只是像文本而已。如果你以前使用过微软画图程序,那么就会理解我的意思。一旦文字绘制之后,它就无法编辑,除非先擦除文字,再重新绘制。在 Canvas中绘制文本的好处是你可以利用 Canvas 支持的强大转换和其他绘图功能。然而,我必须提醒你,除非你有充分理由不使用普通的HTML元素,否则一定不要在 Canvas 中创建文本。相反,你应该使用普通的HTML元素来创建文本,然后使用CSS定位到Canvas,之上。关键是使用HTML来处理文本(内容),而使用Canvas来处理像素和图形。

下面是我想要介绍的 Canvas 绘制文本的方法,其实很简单:

代码语言:javascript复制
const text = "Hello,World!"
context.fillText(text, 40, 40);

这就是你绘制文本所需要的代码。2D渲染上下文的fillText方法可接受4个参数(其中一个是可选的,所以我们现在省略了)。第一个参数是准备绘制的文本,第二个和第三个参数是文本原点(左下角)的(x, y)坐标值。我都说过很简单了。

由于字号太小无法看清楚,我现在还不准备展示输出效果,这是因为 Canvas的默认文本设置是10px sans-serif(非常小)。所以现在让我们修改字号,同时也会介绍修改字体的方法。要实现这个操作,你需要设置2D渲染上下文的font属性,如下所示:

代码语言:javascript复制
const text = "Hello, World!";
context.font = "30px serif"; //修改字号和学体
context.fillText(text, 40, 40);

属性font可接受与 CSS 的font属性完全相同的字符串值。在前一个例子中,我们指定了字体的像素大小,然后是希望使用的字体。设置为serif表示计算机的默认字体是serif字体。所有代码组合在一起将得到下图所示的结果。

image-20220608141727711

这样显示效果会好一些,能看清了。如果愿意,甚至可以将文本设置为斜体:

代码语言:javascript复制
const text = "Hello,World!";
context.font = "italic 30px serif";
context.fillText(text, 40, 40);

这里所做的唯一修改就是将单词italic添加到font属性中,这样就得到如下图所示的结果。

image-20220608142216599

除了font属性,还可以使用许多设置,如行高和备用字体系列。本文不会介绍这方面内容,但是如果你对在 Canvas 中使用文本感兴趣,建议你自己去了解详细内容。

在继续之前,先让我们介绍如何创建「描边文本」这也是很有用的:

代码语言:javascript复制
const text = "Hello,World!";
context.font = "italic 40px serif";
context.strokeText(text, 40, 40);

这次使用的是strokeText方法,它的参数与fillText完全相同。字号过小会让文本难以辨别,所以在这个例子中,我们加大了字号,而原点也稍微向下移,所以文本不会超出屏幕顶部。最终得到的结果如下图所示。

image-20220608142630759

我们并不常用描边文本,但是它在一些项目中是必不可少的。如果遇到这种情况,建议你尽量使用这个功能。

6. 擦除 canvas

在 Canvas 上绘制确实是很有趣的事情,但是当你画错了或者想要清除画布和绘制其他图形时,应该如何做呢?有两个方法可以使用:clearRect方法以及「宽度」「高度」技巧。我们首先学习2D渲染上下文的clearRect方法。

假设你在 Canvas上只画了一个正方形和圆形:

代码语言:javascript复制
context.fillRect(40, 40, 100, 100);
context.beginPath();
context.arc(230, 90, 50, 0, Math.PI * 2, false);
context.closePath();
context.fill();

image-20220608143419733

然后,可以随时清除 Canvas。要执行这个操作,只需要使用 Canvas 的原点坐标(x, y)「宽度」「高度」调用clearRect。如果Canvas宽500像素高500像素,那么可以按照以下方式调用clearRect

代码语言:javascript复制
context.clearRect (0, 0, 500, 500);

当运行时,它在浏览器上不会显示任何内容,因为刚刚清除了Canvas的所有内容。甚至,即使不知道Canvas尺寸,也可以使用dom元素获取widthheight来调用clearRect

但是,并不一定要清除整个Canvas,可以只清除 Canvas 的一个特定区域。例如,如果我们只想清除例子中的正方形,可以按以下方式调用clearRect

代码语言:javascript复制
context.clearRect(40, 40, 100, 100);

这样就剩下一个圆形。

image-20220608143347123

这种方法是通过修改clearRect的参数来清除一个特定区域。在我们的例子中,我们将准备擦除的区域的原点(左上角)移动到正方形的左上角(40, 40),并将准备擦除的区域的宽度和高度设置为正方形的宽度和高度(100)。其结果是只将正方形所在的特定区域清除。按照以下方式修改clearRect的参数,就能够将圆形清除:

代码语言:javascript复制
context.clearRect(180, 40, 100, 100);

记住,弧形的原点是它的中心,所以为了获得clearRect方法所需要的正确原点,我们需要用原点的xy坐标减去它的半径。

Canvas中的对象是可以被部分擦除的,虽然你可能并不需要这样做:

代码语言:javascript复制
context.fillRect(40, 40, 100, 100);
context.beginPath();
context.arc(230, 90, 50, 0, Math.PI * 2, false);
context.closePath();
context.fill();
context.clearRect(230, 90, 50, 50);

这个例子会切掉圆形的一部分。

image-20220608143820443

我们可以先绘制一个基本形状,然后再去掉一部分,从而快速方便地绘制出一些复杂的形状。

「宽度/高度技巧」

如果只是想要擦除 Canvas 上的所有内容,并从零开始绘图,那么你可能要考虑使用「宽度/高度技巧」。老实说,这实际上并不是一种技巧,而是一种将Canvas重置为默认新状态的方法,但是关于它的文档很少。其依据是每当重新设置一个canvas元素的widthheight属性时,Canvas都会自动清除内容并返回其原始状态。这种方法也有一些缺点,所以先看一个例子:

代码语言:javascript复制
context.fillStyle = "rgb(255, 0, 0)";
context.fillRect(40, 40, 100, 100);
context.beginPath();
context.arc(230, 90, 50, 0, Math.PI * 2, false);
context.closePath();
context.fill();

上面的代码仅仅是在Canvas上绘制出一个红色正方形和一个圆形。现在让我们来重置这个Canvas:

代码语言:javascript复制
canvas.width = canvas.width;
canvas.height = canvas.height;

相信你现在已经知道操作的结果是什么了。如果一切正确,你会看到一个空白的 Canvas。

现在,将下面这行代码添加到使用「宽度/高度」技巧清除Canvas内容的代码之后:

代码语言:javascript复制
context.fillRect(40, 40, 100, 100);

这肯定会绘制出一个红色正方形,对吗?(记住:之前设置了fillSty1e属性。)那么,为什么它实际上绘制出了一个黑色正方形呢?

image-20220608145541626

「宽度/高度技巧」的缺点是,它会完全重置 Canvas 上的所有内容,包括「样式」「颜色」。所以,只有准备完全重置 Canvas,而不仅仅是清除内容时,你才能使用这种方法。

7. 使 canvas 填满浏览器窗口

到现在为止,我们使用的 canvas 元素一直采用固定的500像素的宽度和高度。这个尺寸没有问题,但是如果我们想要将它填满整个浏览器窗口,又该如何做呢?对于普通的HTML元素,可以将widthheight属性设置为100%,然后一切就都满足要求了。然而,canvas元素并不支持这种方法,它会忽略百分比,将100%解释为100像素,200%解释为200像素,以此类推。因此,我们需要使用另一种方法。

最简单的方法是将 canvas 元素的宽度和高度精确设置为浏览器窗口的宽度和高度。可以使用window浏览器对象获取窗口的宽度和高度:

代码语言:javascript复制
const canvas = document.getElementById("myCanvas");
const context = canvas.getContext("2d");
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
context.fillRect(0, 0, canvas.width, canvas.height);

你会发现这种方法实际上并非完全正确,因为canvas 元素和浏览器窗口旁边还会有一个白色空隙。

要解决这个问题,我们需要使用一些CSS。

代码语言:javascript复制
* { margin: 0; padding: 0 }
html, body { height: 1008; width: 1008; }

canvas {
  display: block;
}

第一行代码将所有HTML元素的marginpadding重置为0,从而删除所显示的白色边框,这一般称为CSS重置。还有其他更好的方法可以实现CSS重置,但是现在使用的这种方法已经满足我们的需要了。第二行代码并不是必需的,但是它可以保证htmlbody元素使用整个浏览器窗口的宽度和高度。最后一行代码将canvas元素从inline修改为block,这样我们才能够正确地设置宽度和高度,从而使之能够使用整个浏览器窗口的宽度和高度,而不会出现滚动条。

但是,还有问题要解决。如果你调整浏览器窗口大小,canvas元素仍然会保持原来的尺寸,这样,如果窗口缩小过多就会显示滚动条。

为了解决这个问题,需要在调整浏览器窗口大小的同时调整canvas元素的大小。

代码语言:javascript复制
window.onresize = function() {
  const canvas = document.getElementById("myCanvas");
  const context = canvas.getContext("2d");
  canvas.width = window.innerWidth;
  canvas.height = window.innerHeight;
  console.log(window.innerWidth, window.innerHeight);
  context.fillRect(0, 0, canvas.width, canvas.height);
}

0 人点赞