Canvas入门基础(五):变形
在了解变形之前,我先介绍一下两个在你开始绘制复杂图形就必不可少的方法。
save 和 restore 方法是用来保存和恢复 canvas 状态的,都没有参数。Canvas 的状态就是当前画面应用的所有样式和变形的一个快照。save()
restore()
Canvas 状态是以堆(stack)的方式保存的,每一次调用 save 方法,当前的状态就会被推入堆中保存起来。这种状态包括:
1.当前应用的变形(即移动,旋转和缩放)
2.strokeStyle, fillStyle, globalAlpha, lineWidth, lineCap, lineJoin, miterLimit, shadowOffsetX, shadowOffsetY, shadowBlur, shadowColor, globalCompositeOperation 的值.
3.当前的裁切路径(clipping path)
你可以调用任意多次 save 方法。
每一次调用 restore 方法,上一个保存的状态就从堆中弹出,所有设定都恢复。
例子:
cxt.fillStyle="red"; cxt.fillRect(10,10,50,50); cxt.save(); cxt.fillStyle="blue"; cxt.fillRect(20,20,30,30); cxt.restore(); cxt.fillRect(30,30,10,10);

我们第一步先设置了填充色为红色,画了一个大正方形,然后保存状态;第二步将填充色设置为蓝色,画了一个小一点正方形;跟着调用restore()恢复状态,也就是恢复填充色为红色的状态,再画了一个更小的正方形。
到目前为止所做的动作和前面章节的都很类似。不过一旦我们调用 restore,状态堆中最后的状态会弹出,并恢复所有设置。如果不是之前用 save 保存了状态,那么我们就需要手动改变设置来回到前一个状态,这个对于两三个属性的时候还是适用的,一旦多了,我们的代码将会猛涨。
变形
在Canvas中,变形包括移动、旋转、缩放、变形,跟CSS3中的2D转换类似。(注意:原有内容不会受变形的影响,变形只是坐标变换,新绘制的图形就是在变换后的坐标轴里绘制的。)


下面我们来逐一的认识。


一、移动(translate)
canvas的移动是指移动 canvas 和它的原点到一个不同的位置。
translate 方法接受两个参数。x 是左右偏移量,y 是上下偏移量,如右图所示。translate(x, y)
例子:
cxt.fillRect(0,0,100,100); cxt.save(); cxt.translate(60,60); cxt.fillStyle="red"; cxt.fillRect(0,0,100,100); cxt.restore();

二、旋转(rotate)
用于以原点为中心旋转 canvas。
这个方法只接受一个参数:旋转的角度(angle),它是顺时针方向的,以弧度为单位的值。rotate(angle)
cxt.beginPath(); cxt.moveTo(0,50); cxt.lineTo(100,50); cxt.stroke(); cxt.save(); cxt.rotate(Math.PI/12); cxt.strokeStyle="red"; cxt.beginPath(); cxt.moveTo(0,50); cxt.lineTo(100,50); cxt.stroke(); cxt.restore();

三、缩放(scale)
scale 方法接受两个参数。x,y 分别是横轴和纵轴的缩放因子,它们都必须是正值。值比 1.0 小表示缩小,比 1.0 大则表示放大,值为 1.0 时什么效果都没有。scale(x, y)
例子:
cxt.fillRect(20,20,50,50); cxt.save(); cxt.scale(.5,.5); cxt.fillStyle="red"; cxt.fillRect(20,20,50,50);

四、变形
区别:
transform()方法的行为相对于由 rotate(),scale(), translate(), or transform() 完成的其他变换。例如:如果我们已经将绘图设置为放到两倍,则 transform() 方法会把绘图放大两倍,那么我们的绘图最终将放大四倍。这一点和之前的变换是一样的。
但是setTransform()不会相对于其他变换来发生行为。它的参数也是六个,context.setTransform(a,b,c,d,e,f),与transform()一样。
transform(m11, m12, m21, m22, dx, dy)
参数:
m11 水平缩放绘图。 默认值1
m12 水平倾斜绘图。 默认值0
m21 垂直倾斜绘图。 默认值0
m22 垂直缩放绘图。 默认值1
dx 水平移动绘图。 默认值0
dy 垂直移动绘图。 默认值0
这个方法必须将当前的变形矩阵乘上下面的矩阵:
m11 m21 dx m12 m22 dy 0 0 1
注意:该变换只会影响 transform() 方法调用之后的绘图。
setTransform(m11, m12, m21, m22, dx, dy)
参数:
m11 水平缩放绘图。 默认值1
m12 水平倾斜绘图。 默认值0
m21 垂直倾斜绘图。 默认值0
m22 垂直缩放绘图。 默认值1
dx 水平移动绘图。 默认值0
dy 垂直移动绘图。 默认值0
矩阵

五、transform和translate、scale、rotate
5.1 translate
cxt.translate(dx,dy)

cxt.transform (1,0,0,1,dx,dy)代替cxt.translate(dx,dy)。
也可以使用
cxt.transform(0,1,1,0.dx,dy)代替。
5.2 scale
cxt.scale(m11, m22):
也即是说可以使用
cxt.transform(m11,0,0,m22,0,0)代替cxt.scale(m11,m22);
也可以使用cxt.transform (0,m22,m11,0, 0,0);
5.3 rotate
rotate(θ)

也即是说可以用
cxt.transform(Math.cos(θ*Math.PI/180),Math.sin(θ*Math.PI/180),
-Math.sin(θ*Math.PI/180),Math.cos(θ*Math.PI/180),0,0)可以替代context.rotate(θ)。
也可以使用
cxt.transform(-Math.sin(θ*Math.PI/180),Math.cos(θ*Math.PI/180),
Math.cos(θ*Math.PI/180),Math.sin(θ*Math.PI/180), 0,0)替代。