何为矩阵?

在这里插入图片描述

CSS3中的矩阵指的是一个方法,书写为matrix()matrix3d(),前者是元素2D平面的移动变换(transform),后者则是3D变换。2D变换矩阵为3*3, 如上面矩阵示意图;3D变换则是4*4的矩阵。

transform中有这么几个属性方法:斜拉(skew),缩放(scale),旋转(rotate)以及位移(translate)。

为什么transform:rotate(45deg);会让元素旋转45°, 其后面运作的机理是什么呢?

下面这张图可以解释上面的疑问:
在这里插入图片描述
无论是旋转还是拉伸什么的,本质上都是应用的matrix()方法实现的(修改matrix()方法固定几个值),只是类似于transform:rotate这种表现形式,我们更容易理解,记忆与上手。

在CSS3以及HTML5的世界里,这玩意还是涉猎蛮广的,如SVG以及canvas。

transform与坐标系统

用过transform旋转的人可以发现了,其默认是绕着中心点旋转的,而这个中心点就是transform-origin属性对应的点,也是所有矩阵计算的一个重要依据点(下图参考自https://dev.opera.com/)。
在这里插入图片描述

当我们通过transform-origin属性进行设置的时候,矩阵相关计算也随之发生改变。反应到实际图形效果上就是,旋转拉伸的中心点变了!

举例来说,如果我们设置:

transform-origin: bottom left;

则,坐标中心点就是左下角位置。于是动画(例如图片收缩)就是基于图片的左下角这一点了。

我们如果这样设置:

transform-origin: 50px 70px;

则,中心点位置由中间移到了距离左侧50像素,顶部70像素的地方(参见下图),而此时的(30, 30)的坐标为白点所示的位置(这个位置后面会用到)。
在这里插入图片描述

matrix translate(偏移)

CSS3 transform的matrix()方法写法如下:

transform: matrix(a,b,c,d,e,f);

这6参数,对应的矩阵如下,注意书写方向是竖着的。
在这里插入图片描述
矩阵转换公式:
在这里插入图片描述
其中,x, y表示转换元素的所有坐标(变量)了。那后面的ax+cy+e怎么来的呢?

很简单,3*3矩阵每一行的第1个值与后面1*3的第1个值相乘,第2个值与第2个相乘,第3个与第3个,然后相加,如下图同色标注:

在这里插入图片描述

那ax+cy+e的意义是什么?
记住了,ax+cy+e为变换后的水平坐标,bx+dy+f表示变换后的垂直位置。

一个简单例子就明白了,假设矩阵参数如下:

transform: matrix(1, 0, 0, 1, 30, 30); /* a=1, b=0, c=0, d=1, e=30, f=30 */

现在,我们根据这个矩阵偏移元素的中心点,假设是(0, 0),即x=0, y=0。

于是,变换后的x坐标就是ax+cy+e = 10+00+30 =30, y坐标就是bx+dy+f = 00+10+30 =30.

于是,中心点坐标从(0, 0)变成了→(30, 30)。对照上面有个(30, 30)的白点图,好好想象下,原来(0,0)的位置,移到了白点的(30, 30)处,怎么样,是不是往右下方同时偏移了30像素哈!!

实际上transform: matrix(1, 0, 0, 1, 30, 30);就等同于transform: translate(30px, 30px);.

注意:translate, rotate等方法都是需要单位的,而matrix方法e, f参数的单位可以省略。

总结:matrix表现偏移就是

transform: matrix(与我无关, 哪位, 怎么不去高考, 打麻将去吧, 水平偏移距离, 垂直偏移距离);

你只要关心后面两个参数就可以了,至于前面4个参数,是牛是马,是男是女都没有关系的。

matrix矩阵与缩放,旋转以及拉伸

偏移是matrix效果中最简单,最容易理解的,因此,上面很详尽地对此进行展开说明。下面,为了进一步加深对matrix的理解,会简单讲下matrix矩阵与缩放,旋转以及拉伸效果。

缩放(scale)

上面的偏移只要关心最后两个参数,这个缩放也是只要关心两个参数。哪两个呢?

发现没,matrix(1, 0, 0, 1, 30, 30) 的元素比例与原来一样,1:1, 而这几个参数中,有两个1。没错,这两个1就是缩放相关的参数。

其中,第一个缩放x轴,第二个缩放y轴。

用公式就很明白了,假设比例是s,则有matrix(s, 0, 0, s, 0, 0);,于是,套用公式,就有:
x’ = ax+cy+e = sx+0y+0 = sx;
y’ = bx+dy+f = 0
x+sy+0 = sy;

也就是matrix(sx, 0, 0, sy, 0, 0);,等同于scale(sx, sy);

旋转(rotate)

旋转相比前面两个要更高级些,要用到三角函数。

方法以及参数使用如下(假设角度为θ):

matrix(cosθ,sinθ,-sinθ,cosθ,0,0)

结合矩阵公式,就有:

x' = x*cosθ-y*sinθ+0 = x*cosθ-y*sinθ
y' = x*sinθ+y*cosθ+0 = x*sinθ+y*cosθ

就旋转而言,rotate(θdeg)这种书写形式要比matrix简单多了,首先记忆简单,其次,无需计算。例如,旋转30°,前者直接:

transform:rotate(30deg);

而使用matrix表示则还要计算cos, sin值:

transform: matrix(0.866025,0.500000,-0.500000,0.866025,0,0);

拉伸(skew)

拉伸也用到了三角函数,不过是tanθ,而且,其至于b, c两个参数相关,书写如下(注意y轴倾斜角度在前):

matrix(1,tan(θy),tan(θx),1,0,0)

套用矩阵公式计算结果为:

x' = x+y*tan(θx)+0 = x+y*tan(θx) 
y' = x*tan(θy)+y+0 = x*tan(θy)+y

对应于skew(θx + “deg”,θy+ “deg”)这种写法。

其中,θx表示x轴倾斜的角度,θy表示y轴,两者并无关联。

matrix处理镜像对称效果

对于一般地交互应用,transform属性默认提供的些方法是足够了,但是,一些其他的效果,如果transform属性没有提供接口方法,那你又该怎么办呢?比方说,“镜像对称效果”!

在镜像对称的时候轴是看不见的。轴围绕的那个点就是CSS3中transform变换的中心点,自然,镜像对称也不例外。因为该轴永远经过原点,因此,任意对称轴都可以用y = k * x表示。则matrix表示就是:

matrix((1-k*k) / (1+k*k), 2k / (1 + k*k), 2k / (1 + k*k), (k*k - 1) / (1+k*k), 0, 0)

这个如何得到的呢?如下图,已经y=kx,并且知道点(x, y)坐标,求其对称点(x’, y’)的坐标?
在这里插入图片描述

很简单,一是垂直,二是中心点在轴线上,因此有:

(y‘-y) / (x’ - x) = -1/ k → ky’-ky = x-x’
((y + y’)/2)/((x + x’) / 2) = k → y+y’ = kx+kx’

再通过因数消除法,把x’和y’提出来,就有:

x’ = ((1-k*k)*x + 2k*y)/(k*k+1);
y’ = (2k*x + ((k*k-1)*y))/(k*k+1);

再结合矩阵公式:
x’ = ax+cy+e;
y’ = bx+dy+f;

我们就可以得到:
a = (1-k*k)/(k*k+1);
b = 2k/(k*k+1);
c = 2k/(k*k+1);
d = (k*k-1)/(k*k+1);

也就是上面matrix方法中的参数值

3D变换中的矩阵

3D变换虽然只比2D多了一个D,但是复杂程度不只多了一个。从二维到三维,是从4到9;而在矩阵里头是从3*3变成4*4, 9到16了。

其实,本质上很多东西都与2D一致的,只是复杂度不一样而已。这里就举一个简单的3D缩放变换的例子。

对于3D缩放效果,其矩阵如下:
在这里插入图片描述
代码表示就是:

transform: matrix3d(sx, 0, 0, 0, 0, sy, 0, 0, 0, 0, sz, 0, 0, 0, 0, 1)
Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐