变换矩阵
之前三节所说的坐标变换的三种方式——平移translate()
,缩放scale()
,以及旋转rotate()
都可以通过transform()
做到。
在介绍矩阵变换transform()
前,我们来说一说什么是变换矩阵。
以上是Canvas中transform()
方法所对应的变换矩阵。而此方法正是传入图中所示的六个参数,具体为context.transform(a,b,c,d,e,f)
。
各参数意义对应如下表:
参数 | 意义 |
---|---|
a | 水平缩放(1) |
b | 水平倾斜(0) |
c | 垂直倾斜(0) |
d | 垂直缩放(1) |
e | 水平位移(0) |
f | 垂直位移(0) |
当我们把对应的0或1代入进矩阵,可以发现这是一个单位矩阵(水平和垂直缩放默认值是1,代表缩放1倍,即不缩放)。该方法使用一个新的变化矩阵与当前变换矩阵进行乘法运算,然后得到各种变化的效果。
这里简单说一下,当我们想对一个图形进行变换的时候,只要对变换矩阵相应的参数进行操作,操作之后,对图形的各个定点的坐标分别乘以这个矩阵,就能得到新的定点的坐标。
而Canvas绘图中,就给咱们提供了一个函数来改变这个变换矩阵,那就是transform()
。
矩阵变换transform()
注:以下三个变换的转换结论转自张雯的博客,童鞋们可以戳进去看看详情。
平移变换
如上图所示:x’ = x + dx
,y’ = y + dy
。
也即是说可以使用context.transform (1,0,0,1,dx,dy)
代替context.translate(dx,dy)
。
也可以使用context.transform(0,1,1,0,dx,dy)
代替。
缩放变换
同理可以使用context.transform(sx,0,0,sy,0,0)
代替context.scale(sx, sy)
;
也可以使用context.transform(0,sy,sx,0,0,0)
;
旋转变换
如上图图所示:
B点是通过A点逆时针旋转θ得到,x = r * cosa
,y = r * sina
即x’=r*cos(a+θ)=x*cosθ-y*sinθ
,y’=r*sin(a+θ)=x*sinθ+y*cosθ
也即是
综上:context.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(θ)
。
也可以使用context.transform(-Math.sin(θ*Math.PI/180),Math.cos(θ*Math.PI/180), Math.cos(θ*Math.PI/180),Math.sin(θ*Math.PI/180),0,0)
替代。
以上结论引自张雯的博客,很好的说明了矩阵变换的过程,但是结论过于复杂,建议使用transform()
的时候,可以在如下几个情况下使用:
- 使用
context.transform (1,0,0,1,dx,dy)
代替context.translate(dx,dy)
- 使用
context.transform(sx,0,0,sy,0,0)
代替context.scale(sx, sy)
- 使用
context.transform(0,b,c,0,0,0)
来实现倾斜效果(最实用)。
不用再使用它去实现旋转了,另外也没有也不用全记这些结论,直接记下abcdef六个参数的意义,效果是一样的。
下面我们看一个代码,熟悉一下:
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<title>矩阵变换</title>
<style>
body { background: url("./images/bg3.jpg") repeat; }
#canvas { border: 1px solid #aaaaaa; display: block; margin: 50px auto; }
</style>
</head>
<body>
<div id="canvas-warp">
<canvas id="canvas">
你的浏览器居然不支持Canvas?!赶快换一个吧!!
</canvas>
</div>
<script>
window.onload = function(){
var canvas = document.getElementById("canvas");
canvas.width = 800;
canvas.height = 600;
var context = canvas.getContext("2d");
context.fillStyle = "#FFF";
context.fillRect(0,0,800,600);
context.fillStyle = "yellow";
context.strokeStyle = "#00AAAA";
context.lineWidth = 5;
context.save();
//平移至(300,200)
context.transform(1,0,0,1,300,200);
//水平方向放大2倍,垂直方向放大1.5倍
context.transform(2,0,0,1.5,0,0);
//水平方向向右倾斜宽度10%的距离,垂直方向向上倾斜高度10%的距离
context.transform(1,-0.1,0.1,1,0,0);
context.fillRect(0,0,200,200);
context.strokeRect(0,0,200,200);
context.restore();
};
</script>
</body>
</html>
运行结果:
setTransform()
方法
transform()
方法的行为相对于由 rotate()
,scale()
, translate()
, or transform()
完成的其他变换。例如:如果我们已经将绘图设置为放到两倍,则 transform()
方法会把绘图放大两倍,那么我们的绘图最终将放大四倍。这一点和之前的变换是一样的。
但是setTransform()
不会相对于其他变换来发生行为。它的参数也是六个,context.setTransform(a,b,c,d,e,f)
,与transform()
一样。
这里我们通过一个例子来说明:
绘制一个矩形,通过 setTransform()
重置并创建新的变换矩阵,再次绘制矩形,重置并创建新的变换矩阵,然后再次绘制矩形。
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<title>矩阵变换</title>
<style>
body { background: url("./images/bg3.jpg") repeat; }
#canvas { border: 1px solid #aaaaaa; display: block; margin: 50px auto; }
</style>
</head>
<body>
<div id="canvas-warp">
<canvas id="canvas">
你的浏览器居然不支持Canvas?!赶快换一个吧!!
</canvas>
</div>
<script>
window.onload = function(){
var canvas = document.getElementById("canvas");
canvas.width = 800;
canvas.height = 600;
var context = canvas.getContext("2d");
context.fillStyle = "#FFF";
context.fillRect(0,0,800,600);
context.fillStyle="yellow";
context.fillRect(200,100,250,100)
context.setTransform(1,0.5,-0.5,1,30,10);
context.fillStyle="red";
context.fillRect(200,100,250,100);
context.setTransform(1,0.5,-0.5,1,30,10);
context.fillStyle="blue";
context.fillRect(200,100,250,100);
};
</script>
</body>
</html>
运行结果:
解释一下过程:每当我们调用 setTransform()
时,它都会重置前一个变换矩阵然后构建新的矩阵,因此在下面的例子中,不会显示红色矩形,因为它在蓝色矩形下面。
这一节的内容有些难和多,但是除了倾斜其他并不实用,所以童鞋们尽量了解一下就好,能够掌握就更好啦!至此,所有的图形变换我们已经上完了,基本的三大变化——平移变换、旋转变换、缩放变换,以及万能的矩阵变换。大家都以及完全掌握了吗?如果不熟练,要回头多看看,并且多加练习。稍作休息,下一节开始,就是新的航程!我们继续前进!😋