如何用Canvas绘制多种图形

作者&投稿:张钞 (若有异议请与网页底部的电邮联系)
如何用Canvas绘制多种图形~

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

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



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

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

画布的最左上角是 (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 的坐标系中,角的一边是以圆心为中心的水平向右的直线。角度单位均为弧度。例如下图,确定了圆心、起始角度(图中标明的锐角)和终止角度(图中标明的钝角),方向为逆时针,于是就有了这么一个弧。如果方向为顺时针,那么就会是一个跟它互补的、非常非常大的弧……

所以如果转了 2π 圈之后,弧就成了圆形,因此也可以使用绘制弧的方式来绘制圆形:
ctx.beginPath();
ctx.arc(圆心 x 坐标, 圆心 y 坐标, 半径, 0, Math.PI * 2, true);
ctx.closePath();


最后一个参数随便填(当然也可以不填),因为不管是顺时针还是逆时针,转了 2π 圈之后都是一个圆。
矩形
如果只是想绘制一个横平竖直的矩形,可以使用下面的两个方法:
// 只描边
ctx.strokeRect(左上角 x 坐标, 左上角 y 坐标, 宽度, 高度);
// 只填充
ctx.fillRect(左上角 x 坐标, 左上角 y 坐标, 宽度, 高度);


线条样式 / 填充样式
之前绘制的所有图形都是黑色的,但是 Canvas 肯定不止这么一种颜色(不然标准的制定者会被喷的很惨)。事实上,Canvas 可以单独设置线条样式和填充样式,分别使用的是 strokeStyle 和 fillStyle。可能的值有三种:纯色、渐变、图像。既然线条样式与填充样式的使用方法相同,那么下面统一以填充样式为例。如果想设置线条样式,直接将所有的 fillStyle改成 strokeStyle 即可,里面的参数都不变。
/* 纯色填充 */
// 普通的颜色
ctx.fillStyle = '#0000ff';
// 带有透明度的颜色
ctx.fillStyle = 'rgba(64, 0, 127, 0.5)';

/* 渐变填充 */
// 设置渐变的尺寸(参数分别为起始点的 x 和 y、终止点的 x 和 y)
var gradient = ctx.createLinearGradient(0, 0, 170, 0);
// 设置过渡色,第一个参数是渐变的位置,第二个参数是颜色
gradient.addColorStop(0, 'magenta');
gradient.addColorStop(0.5, 'blue');
gradient.addColorStop(1.0, 'red');
// 设置填充样式
ctx.fillStyle = gradient;

/* 图片填充 */
// 创建图片
var image = new Image;
image.src = '/path/to/image.png';
// 创建图片笔触,可以指定图片的平铺方式,这里是横向平铺
var pattern = ctx.createPattern(image, 'repeat-x');
// 设置笔触填充
ctx.fillStyle = pattern;


关于渐变,除了代码中提到的线性渐变以外,还有 createRadialGradient,也就是径向渐变。
设置完填充样式之后,就可以使用 fill 来填充啦!如果设置的是线条样式,那么就可以使用 stroke 来描边。
当然,对于线条样式,还有个额外的方法叫 lineWidth 可以用来控制线条的宽度。
文字
要想在画布上画文字,首先需要知道所使用的字体和字号:
ctx.font = '30px Verdana';


然后就可以通过 strokeText 或者 fillText 来对字体描边或者填充字体。
ctx.strokeText("Hello Coding!", 23, 33);
ctx.fillText("Hello Coding!", 23, 66);


图片
在 Canvas 中绘制图片有三种方法:
// 指定绘制位置
ctx.drawImage(image, x, y);
// 指定绘制位置和图像宽高
ctx.drawImage(image, x, y, width, height);
// 指定剪裁区域、绘制位置和图像宽高
ctx.drawImage(image, sx, sy, swidth, sheight, x, y, width, height);


参数的含义依次如下:
image: 要使用的 Image、Canvas 或 Video
sx: 可选,开始剪切的 x 坐标
sy: 可选,开始剪切的 y 坐标
swidth: 可选,被剪切图像的宽度
sheight: 可选,被剪切图像的高度
x: 在画布上放置图像的 x 坐标
y: 在画布上放置图像的 y 坐标
width: 可选,要使用的图像的宽度
height: 可选,要使用的图像的高度


画布设置
细心的同学可能会发现,刚才有些属性是直接对 ctx 变量做设置,例如 ctx.lineWidth,只要设置了它,那么后续画出来的线条全都是这么个宽度。
其实,Canvas 的设置项还有许多,例如我们可以直接移动画布、旋转画布、设置全局的绘制透明度等等。这些设置还可以随时保存和恢复。
要注意的一点是,所有已经画在画布上的东西,是已经定死了的,不管之后再次进行任何设置都不会再改变。这个很像 Windows 下的画图程序。
废话不多说,直接上代码:
// 移动画布,其实就是移动坐标系
ctx.translate(往右移动的量, 往下移动的量);
// 旋转画布,旋转中心为坐标系原点
ctx.rotate(顺时针旋转的角度);
// 以坐标系原点为中心缩放画布
ctx.scale(横向放大倍数, 纵向放大倍数);
// 设置绘制透明度,如果 fillStyle 等属性设置了透明度则会叠加
ctx.globalAlpha(零到一的小数);
// 设置全局组合操作
ctx.globalCompositeOperation = 'lighter';
// 保存当前设置
ctx.save();
// 恢复上次保存的设置
ctx.restore();


移动、旋转、缩放其实就是在控制绘图的坐标系,如果你在调用这三个方法的时候,脑子里时刻有一个带刻度的坐标系,效果会非常好。
事实上,Canvas 的坐标变换遵循计算机图形学的知识:变换矩阵。简单来说,一个坐标可以看成是一个矩阵,坐标所对应的矩阵乘上变换矩阵就可以实现对坐标的变换。为了提升计算的效率,可以先计算出几种变换复合之后的变换矩阵,然后直接通过 transform 函数对当前坐标系进行变换,或者通过 setTransform 函数将坐标系重置为初始状态后再进行变换。至于变换矩阵的内容,对于本文来说就有些超纲了。
全局组合操作有点像 PhotoShop 里面的“混合选项”,具体的实现方式还没有完全确定,目前常见浏览器都统一了的实现方式有:source-over、source-atop、destination-over、destination-out、lighter、xor。具体的行为可以看 Mozilla 官方文档,但是由于标准还未完全确定,因此其它浏览器不保证所有的行为都跟 Mozilla 的标准一致。一般来说,比较常见的是 source-over 和 lighter 两种,这两种的标准在浏览器界也算是无可争议的。
至于保存和恢复设置就有点好玩了,首先需要了解一个叫“栈”的东西。
栈是一个一维数组,规定只能从一个方向操作。栈一开始是空的,我们可以从这个方向往数组 push 元素,也只能从这个方向把最后一个元素(栈顶元素)pop 出来,除此以外没有任何多余的操作。当然,pop 的次数不能多于 push 的次数,因为 pop 到栈底的时候栈里就已经没有元素了,此时再 pop 是没有意义的。栈的用处有很多,例如括号匹配、表达式求值、深度优先搜索,甚至绝大部分语言的函数调用都要用到栈。
每次我们调用 save 函数,实际上是将当前的全局设置 push 到了一个专门栈上,每次调用 restore 函数的时候将最后一次保存的内容 pop 出来并用它覆盖当前的全局设置,这样栈顶就是最近一次保存的内容了。保存和恢复在某些情况下很好用,例如我需要画一个歪着的图形,然后继续画正着的图形,这样就可以先调用 save,然后调用 rotate,画完图形之后再 restore 回来,继续画其它的图形。
其实 Canvas 还有许多方法,例如 toDataURL 直接将当前画布上的内容转换为十六进制的 data-url,getImageData直接将图像转换为 RGBA 数组以供图像处理算法使用,putImageData 将 RGBA 数组转换为图片显示在画布上等等。如果配上 JavaScript 的定时更新(最好用 requestAnimationFrame 而不是 setInterval),则可以产生动画效果。网上还有许多 Canvas 的库,可以让程序员更简便地基于 Canvas 编写属于自己的特效或功能。在这儿我想说一句话:大家的脑洞有多大,Canvas 的能力就有多强~

对第2个绘制,试试一下延时setTimeOut

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

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 的坐标系是计算机中常见的坐标系,它长这样:

画布的最左上角是 (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 的坐标系中,角的一边是以圆心为中心的水平向右的直线。角度单位均为弧度。例如下图,确定了圆心、起始角度(图中标明的锐角)和终止角度(图中标明的钝角),方向为逆时针,于是就有了这么一个弧。如果方向为顺时针,那么就会是一个跟它互补的、非常非常大的弧……

所以如果转了 2π 圈之后,弧就成了圆形,因此也可以使用绘制弧的方式来绘制圆形:
ctx.beginPath();
ctx.arc(圆心 x 坐标, 圆心 y 坐标, 半径, 0, Math.PI * 2, true);
ctx.closePath();

最后一个参数随便填(当然也可以不填),因为不管是顺时针还是逆时针,转了 2π 圈之后都是一个圆。
矩形
如果只是想绘制一个横平竖直的矩形,可以使用下面的两个方法:
// 只描边
ctx.strokeRect(左上角 x 坐标, 左上角 y 坐标, 宽度, 高度);
// 只填充
ctx.fillRect(左上角 x 坐标, 左上角 y 坐标, 宽度, 高度);

线条样式 / 填充样式
之前绘制的所有图形都是黑色的,但是 Canvas 肯定不止这么一种颜色(不然标准的制定者会被喷的很惨)。事实上,Canvas 可以单独设置线条样式和填充样式,分别使用的是 strokeStyle 和 fillStyle。可能的值有三种:纯色、渐变、图像。既然线条样式与填充样式的使用方法相同,那么下面统一以填充样式为例。如果想设置线条样式,直接将所有的 fillStyle改成 strokeStyle 即可,里面的参数都不变。
/* 纯色填充 */
// 普通的颜色
ctx.fillStyle = '#0000ff';
// 带有透明度的颜色
ctx.fillStyle = 'rgba(64, 0, 127, 0.5)';

/* 渐变填充 */
// 设置渐变的尺寸(参数分别为起始点的 x 和 y、终止点的 x 和 y)
var gradient = ctx.createLinearGradient(0, 0, 170, 0);
// 设置过渡色,第一个参数是渐变的位置,第二个参数是颜色
gradient.addColorStop(0, 'magenta');
gradient.addColorStop(0.5, 'blue');
gradient.addColorStop(1.0, 'red');
// 设置填充样式
ctx.fillStyle = gradient;

/* 图片填充 */
// 创建图片
var image = new Image;
image.src = '/path/to/image.png';
// 创建图片笔触,可以指定图片的平铺方式,这里是横向平铺
var pattern = ctx.createPattern(image, 'repeat-x');
// 设置笔触填充
ctx.fillStyle = pattern;

关于渐变,除了代码中提到的线性渐变以外,还有 createRadialGradient,也就是径向渐变。
设置完填充样式之后,就可以使用 fill 来填充啦!如果设置的是线条样式,那么就可以使用 stroke 来描边。
当然,对于线条样式,还有个额外的方法叫 lineWidth 可以用来控制线条的宽度。
文字
要想在画布上画文字,首先需要知道所使用的字体和字号:
ctx.font = '30px Verdana';

然后就可以通过 strokeText 或者 fillText 来对字体描边或者填充字体。
ctx.strokeText("Hello Coding!", 23, 33);
ctx.fillText("Hello Coding!", 23, 66);

图片
在 Canvas 中绘制图片有三种方法:
// 指定绘制位置
ctx.drawImage(image, x, y);
// 指定绘制位置和图像宽高
ctx.drawImage(image, x, y, width, height);
// 指定剪裁区域、绘制位置和图像宽高
ctx.drawImage(image, sx, sy, swidth, sheight, x, y, width, height);

参数的含义依次如下:
image: 要使用的 Image、Canvas 或 Video
sx: 可选,开始剪切的 x 坐标
sy: 可选,开始剪切的 y 坐标
swidth: 可选,被剪切图像的宽度
sheight: 可选,被剪切图像的高度
x: 在画布上放置图像的 x 坐标
y: 在画布上放置图像的 y 坐标
width: 可选,要使用的图像的宽度
height: 可选,要使用的图像的高度

画布设置
细心的同学可能会发现,刚才有些属性是直接对 ctx 变量做设置,例如 ctx.lineWidth,只要设置了它,那么后续画出来的线条全都是这么个宽度。
其实,Canvas 的设置项还有许多,例如我们可以直接移动画布、旋转画布、设置全局的绘制透明度等等。这些设置还可以随时保存和恢复。
要注意的一点是,所有已经画在画布上的东西,是已经定死了的,不管之后再次进行任何设置都不会再改变。这个很像 Windows 下的画图程序。
废话不多说,直接上代码:
// 移动画布,其实就是移动坐标系
ctx.translate(往右移动的量, 往下移动的量);
// 旋转画布,旋转中心为坐标系原点
ctx.rotate(顺时针旋转的角度);
// 以坐标系原点为中心缩放画布
ctx.scale(横向放大倍数, 纵向放大倍数);
// 设置绘制透明度,如果 fillStyle 等属性设置了透明度则会叠加
ctx.globalAlpha(零到一的小数);
// 设置全局组合操作
ctx.globalCompositeOperation = 'lighter';
// 保存当前设置
ctx.save();
// 恢复上次保存的设置
ctx.restore();

移动、旋转、缩放其实就是在控制绘图的坐标系,如果你在调用这三个方法的时候,脑子里时刻有一个带刻度的坐标系,效果会非常好。
事实上,Canvas 的坐标变换遵循计算机图形学的知识:变换矩阵。简单来说,一个坐标可以看成是一个矩阵,坐标所对应的矩阵乘上变换矩阵就可以实现对坐标的变换。为了提升计算的效率,可以先计算出几种变换复合之后的变换矩阵,然后直接通过 transform 函数对当前坐标系进行变换,或者通过 setTransform 函数将坐标系重置为初始状态后再进行变换。至于变换矩阵的内容,对于本文来说就有些超纲了。
全局组合操作有点像 PhotoShop 里面的“混合选项”,具体的实现方式还没有完全确定,目前常见浏览器都统一了的实现方式有:source-over、source-atop、destination-over、destination-out、lighter、xor。具体的行为可以看 Mozilla 官方文档,但是由于标准还未完全确定,因此其它浏览器不保证所有的行为都跟 Mozilla 的标准一致。一般来说,比较常见的是 source-over 和 lighter 两种,这两种的标准在浏览器界也算是无可争议的。
至于保存和恢复设置就有点好玩了,首先需要了解一个叫“栈”的东西。
栈是一个一维数组,规定只能从一个方向操作。栈一开始是空的,我们可以从这个方向往数组 push 元素,也只能从这个方向把最后一个元素(栈顶元素)pop 出来,除此以外没有任何多余的操作。当然,pop 的次数不能多于 push 的次数,因为 pop 到栈底的时候栈里就已经没有元素了,此时再 pop 是没有意义的。栈的用处有很多,例如括号匹配、表达式求值、深度优先搜索,甚至绝大部分语言的函数调用都要用到栈。
每次我们调用 save 函数,实际上是将当前的全局设置 push 到了一个专门栈上,每次调用 restore 函数的时候将最后一次保存的内容 pop 出来并用它覆盖当前的全局设置,这样栈顶就是最近一次保存的内容了。保存和恢复在某些情况下很好用,例如我需要画一个歪着的图形,然后继续画正着的图形,这样就可以先调用 save,然后调用 rotate,画完图形之后再 restore 回来,继续画其它的图形。
其实 Canvas 还有许多方法,例如 toDataURL 直接将当前画布上的内容转换为十六进制的 data-url,getImageData直接将图像转换为 RGBA 数组以供图像处理算法使用,putImageData 将 RGBA 数组转换为图片显示在画布上等等。如果配上 JavaScript 的定时更新(最好用 requestAnimationFrame 而不是 setInterval),则可以产生动画效果。网上还有许多 Canvas 的库,可以让程序员更简便地基于 Canvas 编写属于自己的特效或功能。在这儿我想说一句话:大家的脑洞有多大,Canvas 的能力就有多强~


3-利用Canvas绘制柱状图(原理-绘制矩形)
通过id获取canvas元素 利用canvas.getContext("2d")获取Context上下文 使用ctx.rect(x,y,w,h)绘制宽度与高度分别为w、h,左上角顶点在(x,y)的矩形 设置内部填充颜色为"blue"并调用ctx.fillrect(x,y,w,h)填充矩形 调用ctx.fillStyle="blue"设置填充颜色为蓝色 使用ctx.rect(x,y,w,h)绘制矩形...

canvas-绘制矩形及弧形
在HTML5的Canvas API中,矩形是最基本的图形元素,可以直接通过三种方法进行绘制:fillRect(), strokeRect() 和 clearRect()。这些方法需要四个参数:矩形的x坐标、y坐标、宽度和高度。绘制灰色实心矩形和透明实心矩形 fillRect()方法用于填充颜色,通过fillStyle属性设定颜色,使用时输入坐标(x, y, 宽度...

JavaScript全解析——canvas 绘制形状(上)
在JavaScript的Canvas API中,我们已经对基本线条和填充有所了解,现在我们将深入学习绘制各种形状。首先,我们来看如何通过canvas的工具箱来创建矩形。绘制矩形是基础操作,通过rect(x, y, width, height)命令,从坐标(x, y)开始画出宽度和高度为给定值的矩形。然而,单纯地使用这个方法,矩形并不会立即...

HTML 5 Canvas绘制
HTML5 Canvas是一个在网页上进行图形绘制的强大工具,但其本身不具备绘图功能,所有的图形绘制操作都需要在JavaScript中进行。首先,你需要在HTML中定义一个canvas元素,如:然后,利用JavaScript通过其id找到这个canvas元素:javascript var canvas = document.getElementById("myCanvas");接着,创建一个名为...

如何用HTML5 CANVAS绘制文字
我们可以在HTML5 canvas上绘制绘制文字,并且可以设置文字的字体,大小和颜色。绘制文字的字体由2D上下文的font属性来控制。如果你需要使用颜色来填充文字或制作描边文字,可以使用2D上下文的fillStyle和strokeStyle属性来完成。要在canvas上绘制文字,可以通过2D上下文的fillText()函数或strokeText()函数来完成。下...

怎样使用canvas绘制一个矩形
1、首先需要新建文件并创建画布。2、接下来开始定义函数获取画布。3、然后可以获取上下文。、4、接着需要设置填充矩形的颜色。5、接下来开始设置边框颜色和边框宽度。6、最后开始绘制填充矩形和边框矩形。7、最后输出完成图,可以看到绘制一个矩形。

canvas海报制作-用canvas画布绘制动画作为网站的banner
1.首先一样,获取Canvas对象:2.获取像素比,将Canvas宽高进行放大,放大比例为:devicePixelRatio\/webkitBackingStorePixelRatio,我们写了一个兼容的方法。3.按实际渲染倍率来缩放canvas。注意基础知识点:要设置canvas的画布大小,使用的是和;要设置画布的实际渲染大小,使用的style属性或CSS设置的width和height,...

如何用HTML5 CANVAS绘制阴影和填充模式
绘制阴影我们可以在HTML5 canvas上绘制出图形或文字的阴影效果。canvas的阴影效果非常简单,通过一些简单的设置,就可以自动在图片或文字下面生成相应的阴影。下面是一个简单的例子:在canvas中,图形的阴影由2D上下文的4个属性来控制:shadowOffsetXshadowOffsetYshadowBlurshadowColorshadowOffsetX和shadowOffsetY...

如何使用HTML5 CANVAS绘制渐变色
我们可以通过2D上下文的createLinearGradient()方法来创建一个线性渐变。下面是一个例子:var canvas = document.getElementById(ex1);var context = canvas.getContext(2d);var x1 = 0;var y1 = 0;var x2 = 100;var y2 = 0;var linearGradient1 = context.createLinearGradient(x1,y1,x2,y2...

微信小程序内使用canvas绘制自定义折线图表
无需赘言,下面展示最终的自定义折线图表在微信小程序canvas中的实现效果:遇到的主要挑战:这个项目基于mpvue开发的小程序,因此代码采用了Vue的编程风格,适合微信小程序环境。对于不熟悉的部分,代码中留有注释,如有疑问,欢迎随时提问。如果对示例有任何疑问,欢迎留言交流。作者:smallStone ...

宁城县13966479300: 如何用Canvas绘制多种图形 -
充差一干: HTML5 的标准已经出来好久了,但是似乎其中的 Canvas 现在并没有在太多的地方用到.一个很重要的原因是,Canvas 的标准还没有完全确定,不适合大规模用在生产环境.但是,Canvas 的优点也是很明显的,例如在绘制含有大量元素的图...

宁城县13966479300: 怎样用canvas在网页上绘制图形 -
充差一干: 我们可以获取canvas对象为var c=document.getElementById("myCanvas");其应有js属性方法如下列举: 1:绘制渲染对象,c.getContext("2d"),获取2d绘图对象,无论我们调用多少次获取的对象都将是相同的对象. 2:绘制方法:clecrRect...

宁城县13966479300: 如何使用 Canvas 创建 3D 图形 -
充差一干: 画布是一个矩形区域,您可以控制其每一像素.canvas 拥有多种绘制路径、矩形、圆形、字符以及添加图像的方法.创建 Canvas 元素 向 HTML5 页面添加 canvas 元素.规定元素的 id、宽度和高度:<canvas id="myCanvas" width="200" ...

宁城县13966479300: 如何使用canvas里绘制一个三角形 -
充差一干: <canvas id="canvas" width="500" height="500" style="background-color: yellow;"></canvas> 代码如下:var canvas=document.getElementById("canvas"); var cxt=canvas.getContext("2d"); cxt.beginPath(); cxt.moveTo(250,50); cxt....

宁城县13966479300: canvas绘图时怎么实现同时缓慢绘制多个图形? -
充差一干: 对第2个绘制,试试一下延时setTimeOut

宁城县13966479300: 如何使用HTML5 Canvas动态的绘制拓扑图 -
充差一干: <canvas>动态的绘制拓扑图1.添加引用\r\n右击项目-添加引用-浏览 找到本地的dll文件\r\n2.using 该dll文件里面代码的名称空间 \r\n然后就可以调用dll文件里面的类和方法<canvas>定义和用法:Canvas 对象表示一个 HTML 画布元素 -<canvas>....

宁城县13966479300: mental canvas 怎么画图 -
充差一干: 画布 用canvas作画,首先,你需要有一块“画布”.如果你的书架里面没有画布,你可以买一卷回来放进去.当然,在网页里面我们不需要花钱买,直接写一个canvas即可,类似: 复制代码 代码如下: 你的浏览器不支持canvas 其中标签里面的文字是给不支.

宁城县13966479300: Android 如何在 Canvas里 放多张图片 -
充差一干: 方案只有一种: 1、图片转换为Bitmap对象 2、通过canvas的drawBitmap方法绘制图片对象 示例: 1、图片转换成Bitmap对象1)资源文件转换 Bitmap bmp=BitmapFactory.decodeResource(r, R.drawable.icon);//读取drawable下的icon图片,...

宁城县13966479300: html5 canvas 画圆形用什么方法 -
充差一干: HTML5中canvas元素,绘制圆形需要使用路径,开始时要取得图形上下文,首先使用路径来勾勒图形的轮廓,然后设置颜色,进行绘制.arc(cx,cy,radius,start_angle,end_angle,direction);cx 水平坐标cy 垂直坐标radius 圆心start-angel 圆周...

宁城县13966479300: 简述HTML5中canvas使用路径绘制图形的一般步骤 -
充差一干: beginPath() //图形 closePath()

本站内容来自于网友发表,不代表本站立场,仅表示其个人看法,不对其真实性、正确性、有效性作任何的担保
相关事宜请发邮件给我们
© 星空见康网