
4.4 图形变形
本节将介绍如何对画布进行操作以及如何对画布中的图形进行变形,以便设计复杂图形。
4.4.1 保存和恢复状态

视频讲解
Canvas状态存储在栈中,一个绘画状态包括两部分。
当前应用的变形,如移动、旋转和缩放,包括的样式属性:strokeStyle、fillStyle、globalAlpha、lineWidth、lineCap、lineJoin、miterLimit、shadowOffsetX、shadowOffsetY、shadowBlur、shadowColor、globalCompositeOperation。
当前的裁切路径,参考4.5节介绍。
使用save()方法,可以将当前的状态推送到栈中保存,使用restore()方法可以将上一个保存的状态就从栈中弹出,恢复上一次所有的设置。
【示例】下面示例先绘制一个矩形,填充颜色为#ff00ff,轮廓颜色为蓝色,然后保存这个状态,再绘制另外一个矩形,填充颜色为#ff0000,轮廓颜色为绿色,最后恢复第一个矩形的状态,并绘制两个小的矩形,则其中一个矩形填充颜色必为#ff00ff,另外矩形轮廓颜色必为蓝色,因为此时已经恢复了原来保存的状态,所以会沿用最先设定的属性值,预览效果如图4.30所示。


图4.30 保存与恢复canvas状态
4.4.2 清除画布

视频讲解
使用clearRect()方法可以清除指定区域内的所有图形,显示画布背景,该方法用法如下。
context.clearRect(x,y,width,height);
参数说明如下:
x:要清除的矩形左上角的x坐标。
y:要清除的矩形左上角的y坐标。
width:要清除的矩形的宽度,以像素计。
height:要清除的矩形的高度,以像素计。
【示例】下面示例演示了如何使用clearRect()方法来擦除画布中的绘图。

在浏览器中的预览效果如图4.31所示,先是在画布上绘制一段弧线。如果单击“清空画布”按钮,则会清除这段弧线,如图4.32所示。

图4.31 绘制弧线

图4.32 清空画布
4.4.3 移动坐标

视频讲解
在默认状态下,画布以左上角(0,0)为原点作为绘图参考。使用translate()方法可以移动坐标原点,这样新绘制的图形就以新的坐标原点为参考进行绘制。其用法如下。
context.translate(dx, dy);
参数dx和dy分别为坐标原点沿水平和垂直两个方向的偏移量,如图4.33所示。
注意:在使用translate()方法之前,应该先使用save()方法保存画布的原始状态。当需要时可以使用restore()方法恢复原始状态,特别是在重复绘图时非常重要。
【示例】下面示例综合运用了save()、restore()、translate()方法来绘制一个伞状图形。

在浏览器中的预览效果如图4.34所示。可见,canvas中图形移动的实现,其实是通过改变画布的坐标原点来实现的,所谓的“移动图形”,只是“看上去”的样子,实际移动的是坐标空间。领会并掌握这种方法,对于随心所欲地绘制图形非常有帮助。

图4.33 坐标空间的偏移示意图

图4.34 移动坐标空间
4.4.4 旋转坐标

视频讲解
使用rotate()方法可以以原点为中心旋转canvas上下文对象的坐标空间,其用法如下。
context.rotate(angle);
rotate()方法只有一个参数,即旋转角度angle,旋转角度以顺时针方向为正方向,以弧度为单位,旋转中心为canvas的原点,如图4.35所示。

图4.35 以原点为中心旋转canvas
提示:如需将角度转换为弧度,可以使用degrees*Math.PI/180公式进行计算。例如,如果要旋转5°,可套用这样的公式:5*Math.PI/180。
【示例】在上节示例的基础上,下面示例设计在每次开始绘制图形之前,先将坐标空间旋转PI*(2/4+i/4),再将坐标空间沿y轴负方向移动100,然后开始绘制图形,从而实现使图形沿一中心点平均旋转分布。在浏览器中的预览效果如图4.36所示。


图4.36 旋转坐标空间
4.4.5 缩放图形

视频讲解
使用scale()方法可以增减canvas上下文对象的像素数目,从而实现图形的放大或缩小,其用法如下。
context.scale(x,y);
其中x为横轴的缩放因子,y轴为纵轴的缩放因子,值必须是正值。如果需要放大图形,则将参数值设置为大于1的数值,如果需要缩小图形,则将参数值设置为小于1的数值,当参数值等于1时则没有任何效果。
【示例】下面示例使用scale(0.95,0.95)来缩小图形到上次的0.95,共循环80次,同时移动和旋转坐标空间,从而实现图形呈螺旋状由大到小的变化,预览效果如图4.37所示。


图4.37 缩放图形
4.4.6 变换图形

视频讲解
transform()方法可以同时缩放、旋转、移动和倾斜当前的上下文环境,用法如下所示:
context.transform(a,b,c,d,e,f);
参数说明如下:
a:水平缩放绘图。
b:水平倾斜绘图。
c:垂直倾斜绘图。
d:垂直缩放绘图。
e:水平移动绘图。
f:垂直移动绘图。
提示:
translate(x,y)可以用下面的方法来代替:
context.transform(0,1,1,0,dx,dy);
或:
context.transform(1,0,0,1,dx,dy);
其中dx为原点沿x轴移动的数值,dy为原点沿y轴移动的数值。
scale(x,y)可以用下面的方法来代替:
context.transform(m11,0,0,m22,0,0);
或:
context.transform(0,m12,m21,0,0,0);
其中dx、dy都为0表示坐标原点不变。m11、m22或m12、m21为沿x、y轴放大的倍数。
rotate(angle)可以用下面的方法来代替:
context.transform(cosθ,sinθ,- sinθ, cosθ,0,0);
其中的θ为旋转角度的弧度值,dx、dy都为0表示坐标原点不变。
setTransform()方法用于将当前的变换矩阵进行重置为最初的矩阵,然后以相同的参数调用transform方法,用法如下所示。
context.setTransform(m11, m12, m21, m22, dx, dy);
【示例】下面示例使用setTransform()方法将前面已经发生变换的矩阵首先重置为最初的矩阵,即恢复最初的原点,然后再将坐标原点改为(10,10),并以新的坐标为基准绘制一个蓝色的矩形。

在浏览器中的预览效果如图4.38所示。在本例中,使用scale(0.95,0.95)来缩小图形到上次的0.95,共循环89次,同时移动和旋转坐标空间,从而实现图形呈螺旋状由大到小的变化。

图4.38 矩阵重置并变换