初学 Canvas <第一篇-基础篇>

时间:2023-03-08 18:01:46

本文摘自:兴趣部落大神(为你一生画眉)-讲一讲canvas究竟是个啥?

HTML5 的标准已经出来好久了,但是似乎其中的 Canvas 现在并没有在太多的地方用到。一个很重要的原因是,Canvas 的标准还没有完全确定,不适合大规模用在生产环境。但是,Canvas 的优点也是很明显的,例如在绘制含有大量元素的图表的时候,SVG 往往因为性能问题而无法胜任,例如我见过的一次技术分享会的抽奖环节,虽然效果比较炫,但因为每个头像都是 DOM,利用 CSS3 控制的动画,导致了性能非常低下。此外,随着硬件性能的提高,视频截图、图像处理等功能也逐渐可以在网页上实现了,大多数网站用的是 Flash,但是 Flash 在 Mac 电脑上性能不高,还需要学一些额外的知识。Canvas 则是直接使用 JavaScript 来进行绘图,对 Mac 友好,所以不失为 Flash 的一个继承者。

使用 Canvas

说了这么多,Canvas 究竟是个啥?

英文中 Canvas 的意思是“画布”,不过这里说的 Canvas 是 HTML5 中新出的一个元素,开发者可以在上面绘制一系列图形。Canvas 在 HTML 文件中的写法很简单:

<canvas id="canvas" width="宽度" height="高度"></canvas>

其中 id 属性是所有 HTML 元素都可以用的,Canvas 自带的属性只有后面两个(分别控制宽度、高度),没有其它的了。至于兼容性,CanIUse 上面写了,基础的功能目前用户使用的 90% 的浏览器都支持,所以大部分情况下还是可以放心使用的。

初学 Canvas <第一篇-基础篇>

注意,一定要使用 Canvas 自带的 width 和 height 属性,不要使用 CSS 来控制,因为 CSS 控制会导致 Canvas 变形。可以试着与 PhptpShop 对比一下,后者是改变“图像大小”,前者才是正确的改变“画布大小”。例如下图是三张图片的横向拼接:最左边的黑框中是大小为 50px * 50px 的原图;中间是改变了图像大小为 100px * 100px 的效果,图像变得模糊,但是对于图像本身来说坐标范围并没有变大;最右边才是正确的 100px * 100px 的 Canvas。

aaarticlea/jpeg;base64,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" alt="" />

Canvas 绝大部分的绘图方法都与 <canvas> 标签无关,需要使用 JavaScript 对其进行操作,这就是所谓的 Canvas API。

我们首先获取到这个元素:

var canvas = document.getElementById('canvas');

然后通过一个方法来获取可以调用一切 Canvas API 的入口:

var ctx = canvas.getContext('2d');

看到 2d 是不是很激动地联想到有没有 3d 呢?没有 3d 的写法,不过如果想要开启 3D 世界的大门,则可以写 canvas.getContext('webgl')。然而 WebGL 是基于 OpenGL ES 2.0 的一套标准,与本文是彻彻底底的两条路,因此这里就不讨论了。

Canvas 中的基本概念

坐标

与数学上常见的笛卡尔坐标系不太相同,Canvas 的坐标系是计算机中常见的坐标系,它长这样:

aaarticlea/jpeg;base64,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" alt="" />

画布的最左上角是 (0,0),往右 x 增大,往下 y 增大,而且 x 和 y 都是整数(就算在计算过程中不是整数,在绘制的时候也会当作整数处理),单位是像素。

绘图

带大家怀旧一下。不知道有多少同学小时候玩过 logo 语言,在里面你可以控制一只小海龟在一块板子上行走、画画、提笔、落笔。Canvas 中也一样,你需要控制一只画笔的移动和绘制。然而 Canvas 更高级一些,你可以直接利用一些函数来画图,不用去控制那只画笔的位置。

Canvas 中的基本图形

通过上文定义的 ctx 变量可以干许多有意思的事情,我们先看看如何绘制一些基本图形。

线条

我们指定画笔移动到某一点,然后告诉画笔需要从当前这一点画到另一点。我们可以让画笔多次移动、绘制,最后统一输出到屏幕上。例子如下:

ctx.moveTo(10, 10);
ctx.lineTo(150, 50);
ctx.lineTo(10, 50);
ctx.moveTo(10, 20);
ctx.lineTo(40, 70);
ctx.stroke();

上面的代码中,lineTo 是产生线条用的函数,执行完之后画笔就移到了线条的终点。需要注意的是,线条此时并没有显示在屏幕上,必须调用 stroke 才会显示。这样设计是有道理的,因为向屏幕上输出内容需要耗费大量的资源,我们完全可以先攒够一波 lineTo,最后用 stroke 放一个大的。

路径

绘制路径非常简单,只需要先告诉 ctx 一声“我要开始画路径了”,然后通过各种方法(例如 lineTo)绘制路径。如果需要画一个封闭路径,那就最后告诉 ctx一声:“我画完了,你把它封闭起来吧。”当然,不要忘记利用 stroke 输出到屏幕上。

一个简单的例子:

ctx.beginPath();
ctx.moveTo(10, 10);
ctx.lineTo(150, 50);
ctx.lineTo(10, 50);
ctx.closePath();
ctx.stroke();

如果我不想只描绘路径线条,而是想填充整个路径呢?可以将最后一行的 stroke 改成 fill,这样就跟使用了画图中的油漆桶一样,封闭路径里面的内容就都被填充上颜色了:

ctx.fill();

弧 / 圆形

绘制弧的函数参数比较多:

ctx.arc(圆心 x 坐标, 圆心 y 坐标, 半径, 起始角度, 终止角度, 是否为逆时针);

注意,在 Canvas 的坐标系中,角的一边是以圆心为中心的水平向右的直线。角度单位均为弧度。例如下图,确定了圆心、起始角度(图中标明的锐角)和终止角度(图中标明的钝角),方向为逆时针,于是就有了这么一个弧。如果方向为顺时针,那么就会是一个跟它互补的、非常非常大的弧……

aaarticlea/jpeg;base64,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" alt="" />

所以如果转了 2π 圈之后,弧就成了圆形,因此也可以使用绘制弧的方式来绘制圆形:

ctx.beginPath();
ctx.arc(圆心 x 坐标, 圆心 y 坐标, 半径, 0, Math.PI * 2, true);
ctx.closePath();

最后一个参数随便填(当然也可以不填),因为不管是顺时针还是逆时针,转了 2π 圈之后都是一个圆。