最近在实现小程序的一个关于canvas多次变换需求,由于之前不是很了解矩阵,但在我的老大的帮助下,啃下了这根硬骨头,那么canvas中的矩阵变换,用到的setTransform就是基于CSS3中的矩阵这一概念实现的,在此记录一下,日后忘记也能再翻一翻,后续也会更新关于3D Matrix的相关知识点,话不多说,开干!
一、矩阵是什么?
当你第一次听说这个名词的时候,肯定和我一样被他吓到了,其实矩阵就可以理解为我们平时看到的站队方阵,矩阵中的数字就好比每行每排的人,而矩阵间的运算就是方阵之间的队伍互冲厮杀
[ ] [ ]
1,2,3 1,3,5
4,5,6 x 7,9,2
7,8,9 4,6,8
[ ] [ ]
那么css中的矩阵可以理解为一个方法,matrix()
或者3D的 matrix3d()
,前者是元素2D平面移动,变换或旋转、后者就是3D变换,2D变换矩阵为3x3,3D的则为4x4矩阵。
二、从基本属性来理解矩阵
我们常用css变换的小伙伴应该知道,transform,那么transform就有几个属性可以设置,比如缩放(scale)、旋转(rotate)、位移(translate)及斜拉(skew)
.transformSkew { transform: skew(45deg); }
.transformScale { transform:scale(0.8, 0.6); }
.transformRotate { transform:rotate(60deg); }
.transformTranslate { transform:translate(30px, 20px); }
三、transform与坐标原点
transform旋转其实是围绕着中心点旋转的,而这个中心点就是transform-origin属性的对应点,如果我们设置如下:
transform-origin: bottom left;
那么坐标中心点就位于左下角位置,那么包括缩放,旋转就都会基于左下角进行,如果想要旋转缩放基于中心点,就需要设置为:center center
,表示横纵坐标 X、Y基于元素中点操作,这就是坐标原点。
当然,这个值也可以是像素,如果设置为 :60px 100px
,那就会往x轴右侧偏移60像素、往y轴下方偏移100像素,仔细想想是不是就是那么回事呢。
四、矩阵应用场景
CSS3 transform
的矩阵 matrix()
方法有几个参数,具体写法:
transform:matrix(a,b,c,d,e,f)
当我第一次见到这些的时候还是有点懵的,六个参数,没有太大的规律,对应矩阵其实是这样的:
[ a c e ]
b d f
[ 0 0 1 ]
书写形式是竖着的,上面提过矩阵可以想象成的士兵方阵,要让其发生变化,就是矩阵变换,就让他们互冲,下面列一个矩阵和向量相乘的公式:
[ a c e ] [ x ] [ ax + cy + e ]
b d f x y = bx + dy + f
[ 0 0 1 ] [ 1 ] [ 0 + 0 + 1 ]
那么应用场景就是,如果坐标系有若干个点,我需要把它们按矩阵去变换,就将点和矩阵相乘,他们的乘积就是变换后的点,如果还需要变换,可以把操作记录成矩阵,让矩阵和矩阵相乘,就是新的存档,是不是很神奇。
如果还想深入了解其原理,有个官方demo,感兴趣可以看看!
五、Matrix的计算
计算
获取当前元素的所有像素点坐标并计算
x’ = ax+cy+e
y’ = bx+dy+f
简单例子
偏移(translate)
坐标公式应该为:x’ = x + 偏移量; y‘ = y + 偏移量
套用上面的公式那么应该:a = 1; b = 0;c = 0;d = 1; e = x偏移量;f = y偏移量
matrix(1, 0, 0, 1, x偏移量, y偏移量)
缩放(scale)
x’ = xx缩放倍数 ; y’ = yy缩放倍数
a = x缩放倍数 ; b = 0; c = 0; d = y缩放倍数 ; e = 0; f = 0
matrix(x缩放倍数, 0, 0, y缩放倍数, 0, 0);
如:缩小一半, matirx(0.5,0,0,0.5,0,0);
垂直旋转(rotate)
x’ = ax + cy ; y’ = bx +dy
a = cosθ; b = sinθ; c = sinθ; d = cosθ; e = 0; f = 0;
matrix(cosθ, sinθ, sinθ, cosθ, 0, 0);
如:要水平旋转30度,只需计算出cos30°和sin30°的值,作为参数a和c的值 matrix(0.866,0,0.5,1,0,0);
垂直旋转同理;
垂直旋转(rotate)
只需:水平旋转角度 = -垂直旋转角度
如:要顺时针旋转30度, matrix(0.866,0.5,-0.5,0.866,0,0);
上面的都可以用CSS3 transform提供的translate() rotate() scale() 方法实现,但有些效果不能实现。(如:镜像)
水平镜像:(y坐标不变,x坐标变负)
所以:a=-1; b=0; c=0; d=1; e=0; f=0;简化得:
x’ = -x;
y’ = y
拉伸(skew)
各像素新坐标需要为
x1=x+tan(ax)*y,y1=tan(ay)*x+y,
因此等价于matrix(1,tan(ay),tan(ax),1,0,0);。例如skew(45deg);等价于matrix(1, 0, 1, 1, 0, 0);(tan(45)=1)
六、总结
我们通常使用的CSS3 transform中提供了像skew
, rotate
, …
等简单易理解的方法,为什么还要用矩阵 Matrix
或3DMatrix
呢。
对于一般地交互应用,transform
属性默认提供的些方法是足够了,但是,一些其他的效果,如果transform
属性没有提供接口方法,那你又该怎么办呢?比方说,“镜像对称效果”!
这时,就只能靠matrix
矩阵了。要知道,matrix矩阵是transform
变换的基础,可以应付很多高端的效果,算是一种高级应用技巧。
回见!