canvas中transform函数

http://m.2cto.com/?src=http%3A%2F%2Fbook.2cto.com%2F201304%2F19772.html

上面分别讲了缩放、平移以及旋转的实现方法。其实所有这些变形都是可以通过变形矩阵transform来实现的。先来看看transform函数的定义。
transform函数的原型如下:
transform (a,b,c,d,e,f);
该函数的各个变量对应以下变换矩阵中相应位置的参数。
 
 1 /*
 2 * context.transform(a, b, c, d, e, f) - 按指定的矩阵转换当前的用户坐标系
 3 * 相当于:context.transform(M11, M12, M21, M22, OffsetX, OffsetY)
 4 *
 5 * 关于仿射矩阵参考:http://www.cnblogs.com/webabcd/archive/2008/11/03/1325150.html
 6 *
 7 * |X| |M11(默认值 1) M21(默认值 0) 0|
 8 * |Y| = |x y 1| * |M12(默认值 0) M22(默认值 1) 0|
 9 * |1| |OffsetX(默认值 0) OffsetY(默认值 0) 1|
10 *
11 * X = x * M11 + y * M12 + OffsetX
12 * Y = x * M21 + y * M22 + OffsetY
13 
14 * 旋转(默认为0度)
15 * 旋转对应的矩阵公式如下
16 * |X| |cos(θ)(默认值 1) -sin(θ)(默认值 0) 0|
17 * |Y| = |x y 1| * |sin(θ)(默认值 0) cos(θ)(默认值 1) 0|
18 * |1| |OffsetX(默认值 0) OffsetY(默认值 0) 1|
19 */

 

 
下面来说明如何使用这个变换矩阵来实现上面的各种变形。
1. 缩放
假设原始坐标为(x,y),缩放后的坐标为(x1,y1),缩放的倍数分别为a和d,那么就有下列公式:
x1=a*x
y1=d*y
因此,我们得到了如下矩阵公式。
 
这样就可以用transform (a,0,0,d,0,0)来替换scale(a,d)了,如代码清单3-7所示。
代码清单 3-7
<script type="text/javascript">
var c=document.getElementById("myCanvas");
var ctx=c.getContext("2d");
ctx.beginPath();
ctx.strokeStyle = "#000000";
ctx.strokeRect(10,10,150,100);
ctx.transform(3,0,0,3,0,0);
ctx.beginPath();
ctx.strokeStyle = "#cccccc";
ctx.strokeRect(10,10,150,100);
</script>
运行效果如图3-7所示。
 
可以看到,这里用代码清单3-7实现了和代码清单3-1一样的功能。
2. 平移
同样,假设原始坐标为(x,y),平移后的坐标为(x1,y1),在x轴和y轴的平移量分别为e和f,那么就有下列公式:
x1=x+e
y1=y+f
因此,我们得到如下矩阵公式。
 
这样就可以用transform (1,0,0,1,e,f)来替换translate (e,f)了,如代码清单3-8所示。
代码清单 3-8
<script type="text/javascript">
var c=document.getElementById("myCanvas");
var ctx=c.getContext("2d");
ctx.beginPath();
ctx.strokeStyle = "#000000";
ctx.strokeRect(10,10,150,100);
ctx.transform (1,0,0,1,50,100);
ctx.beginPath();
ctx.strokeStyle = "#cccccc";
ctx.strokeRect(10,10,150,100);
</script>
运行效果如图3-8所示。
 
可以看到,这里用代码清单3-8实现了和代码清单3-4一样的功能。
3. 旋转
旋转对应的矩阵公式如下。
 
现在可以用transform (cos , sin , –sin , cos ,0,0)来替换rotate ()了,如代码清单3-9所示。
代码清单 3-9
<script type="text/javascript">
var c=document.getElementById("myCanvas");
var ctx=c.getContext("2d");
ctx.beginPath();
ctx.strokeStyle = "#000000";
ctx.strokeRect(200,50,100,50);
ctx.transform (Math.cos(45*Math.PI/180),
 Math.sin(45*Math.PI/180),
 -Math.sin(45*Math.PI/180),
 Math.cos(45*Math.PI/180),0,0);
ctx.beginPath();
ctx.strokeStyle = "#cccccc";
ctx.strokeRect(200,50,100,50);
</script>
</body>
运行效果如图3-9所示。
 
可以看到,这里用代码清单3-9实现了和代码清单3-5一样的功能。
这样,我们就用transform完成了所有变形。另外,变换矩阵也可以通过setTransform函数来实现,setTransform的参数与transform一样,不同的是,setTransform函数是先消去之前的transform变换,然后重新进行变换的。为了区分transform和setTransform,我们看看下面的例子,如代码清单3-10所示。
代码清单 3-10
<script type="text/javascript">
var c=document.getElementById("myCanvas");
var ctx=c.getContext("2d");
ctx.beginPath();
ctx.strokeStyle = "#000000";
ctx.strokeRect(200,50,100,50);
ctx.transform (Math.cos(5*Math.PI/180),
 Math.sin(5*Math.PI/180),
 -Math.sin(5*Math.PI/180),
 Math.cos(5*Math.PI/180),0,0);
ctx.beginPath();
ctx.strokeStyle = "#cccccc";
ctx.strokeRect(200,50,100,50);
ctx.transform (Math.cos(10*Math.PI/180),
 Math.sin(10*Math.PI/180),
 -Math.sin(10*Math.PI/180),
 Math.cos(10*Math.PI/180),0,0);
ctx.beginPath();
ctx.strokeStyle = "#999999";
ctx.strokeRect(200,50,100,50);
</script>
运行效果如图3-10所示。
 
在代码清单3-10中,首先旋转5度,然后再旋转10度,所以第二次旋转相当于旋转了15度。
下面再看看代码清单3-11中setTransform的使用方法。
代码清单 3-11
<script type="text/javascript">
var c=document.getElementById("myCanvas");
var ctx=c.getContext("2d");
ctx.beginPath();
ctx.strokeStyle = "#000000";
ctx.strokeRect(200,50,100,50);
ctx.transform (Math.cos(5*Math.PI/180),
 Math.sin(5*Math.PI/180),
 -Math.sin(5*Math.PI/180),
 Math.cos(5*Math.PI/180),0,0);
ctx.beginPath();
ctx.strokeStyle = "#cccccc";
ctx.strokeRect(200,50,100,50);
ctx.setTransform (Math.cos(10*Math.PI/180),
 Math.sin(10*Math.PI/180),
 -Math.sin(10*Math.PI/180),
 Math.cos(10*Math.PI/180),0,0);
ctx.beginPath();
ctx.strokeStyle = "#999999";
ctx.strokeRect(200,50,100,50);
</script>
运行效果如图3-11所示。
可以看到,第二次的旋转没有在第一次旋转的基础上进行,因为用setTransform实现旋转效果的时候,已经清除了上一个transform,所以只旋转了10度。
4. 倾斜
接着来看一下如何实现图像的倾斜效果。首先看图3-12。
 
图中的3个点p0、p1、p2遵循以下矩形公式。 
将上面的矩形公式带入setTransform函数中,如代码清单3-12所示。
代码清单 3-12
<script type="text/javascript">
var c=document.getElementById('myCanvas'); 
var ctx=c.getContext('2d');
ctx.setTransform(1,10/150,-40/100,1,40,10); 
ctx.rect(50,50,150,100); 
ctx.stroke();
</script>
运行效果如图3-13所示。
上述倾斜效果也可以根据另外3个点来实现,看图3-14。
图中的3个点p1、p2、p3遵循以下矩形公式。
 
将上面的矩形公式代入setTransform函数中,如代码清单3-13所示。
代码清单 3-13
<script type="text/javascript">
var c=document.getElementById('myCanvas'); 
var ctx=c.getContext('2d');
ctx.setTransform(130/150,-20/150,-20/100,80/100,0,0);
ctx.rect(50,50,150,100); 
ctx.stroke();
</script>
运行效果如图3-15所示。
 
5. 图片的扭曲效果
根据以上所介绍的内容,已经可以做到倾斜、旋转、平移和缩放4种基本变形,如图3-16所示。
 
但是,对于非上述4种基本变形的特殊变形,就无法直接实现了。比如图3-17中的扭曲变形效果。
这时候,就需要通过多种变形组合来实现。先对图3-17进行分解,如图3-18所示。
此时分解出的两个图形可分别看作是两个基本变形的一部分,如图3-19所示。
 
这样一来就简单了,只需要实现两个倾斜的变形,然后利用clip函数将图片的一部分绘制出来,就可以完成图3-17中的效果了,如代码清单3-14所示。
代码清单 3-14
<script type="text/javascript">
var c=document.getElementById('myCanvas');
var ctx=c.getContext('2d');
var img = new Image();
img.src="face.jpg";
img.onload = function(){
 ctx.save();
 ctx.beginPath();
 ctx.moveTo(80,0);
 ctx.lineTo(320,40);
 ctx.lineTo(0,200);
 ctx.closePath();
 ctx.clip();
 ctx.setTransform((320-80)/240,40/240,-80/240,200/240,80,0);
 ctx.drawImage(img,0,0);
 ctx.restore();
 
 ctx.save();
 ctx.beginPath();
 ctx.moveTo(320,40);
 ctx.lineTo(0,200);
 ctx.lineTo(200,150);
 ctx.closePath();
 ctx.clip();
 ctx.setTransform(200/240,(150-200)/240,(200-320)/240,(150-40)/240,0,200);
 ctx.drawImage(img,0,0-240);
 ctx.restore();
};
</script>
运行上面的代码,就可以得到图3-17的效果了。
解释一下代码清单3-14。首先看一下左半边图形的绘制。
ctx.beginPath();
ctx.moveTo(80,0);
ctx.lineTo(320,40);
ctx.lineTo(0,200);
ctx.closePath();
ctx.clip();
上面这段代码是以(80,0)、(320,40)和(0,200) 3个点为顶点绘制一个三角形,然后利用clip函数将这个三角形作为绘图的可视区域。
ctx.setTransform(200/240,(150-200)/240,(200-320)/240,(150-40)/240,0,200);
上面的代码是以刚才的三角形的3个顶点来进行倾斜变形的,这个变形的原理已经在代码清单3-12中讲过了。
ctx.drawImage(img,0,0);
上面的代码是绘制图片,因为绘图的可视区域只是一个三角形,所以绘制完的图片只有一部分。
右半边图形的绘制思路和左半边是一样的。同时,两次绘图都加上了save()函数和restore()函数,这是为了让两次变形和绘图互不干涉。
posted @ 2016-01-29 10:37  南极山  阅读(918)  评论(0)    收藏  举报