评论

矩阵在前端中的应用

在前端中应用矩阵的场景最为常见的就是:CSS3 中的矩阵、canvas中的矩阵、svg中的矩阵、图像处理...等等一些场景;

一、矩阵的应用

矩阵的应用场景主要在图像处理、线性变换及对称、量子态的线性组合、简正模式、几何光电和电子学。

而我们在前端中应用矩阵的场景最为常见的就是:CSS3 中的矩阵、canvas中的矩阵、svg中的矩阵、图像处理…等等一些场景;

二、CSS3中的矩阵

CSS3中的矩阵指的是一个方法,书写为matrix() 和 matrix3d(),前者是元素2D平面的移动变换(transform),后者则是3D变换。2D变换矩阵为 3x3,3D变换则是 4x4 的矩阵。

大家都知道transform有斜拉(skew),缩放(scale),旋转(rotate)以及位移(translate)这几个属性方法

transform: skew(35deg);
transform: scale(1, 0.5);
transform: rotate(45deg);
transform: translate(10px, 20px);

那大家有没有想过,这些属性方法其后面运作的机理是什么呢?


无论是旋转还是拉伸什么的,本质上都是应用的matrix()方法实现的。

三、transform与坐标系统

transform旋转其默认是绕着中心点旋转的,而这个中心点就是transform-origin属性对应的点,也是所有矩阵计算的一个重要依据点。

transform-origin: x-axis y-axis z-axis;

x-axis:
left
center
right
length
%

y-axis:
top
center
bottom
length
%

z-axis:
length


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

因为这个会影响矩阵的计算所以也顺带提一下!

1.transform的matrix()

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

实际上,这6个参数,对应的矩阵就是:

注意书写方向是竖着的。
其运算过程为:

其中,x, y表示转换元素的所有坐标(变量)。
那 ax + cy + e 的意义是什么? ax + cy + e 为变换后的水平坐标,bx + dy + f 表示变换后的垂直位置。

2.偏移(translate)

举一个简单例子:

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 = 1 * 0 + 0 * 0 + 30 = 30, y坐标就是 bx + dy + f = 0 * 0 + 1 * 0 + 30 = 30。

中心点坐标从(0, 0)变成了 → (30, 30)。好好想象下,原来(0,0)的位置,移到了(30, 30)处,怎么样,是不是往右下方同时偏移了30像素。

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

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

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

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

还不能理解的可以参考下张鑫旭大神的小demo:懵逼请点击

3.缩放(scale)

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

transform: matrix(1, 0, 0, 1, 30, 30);

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 = s * x + 0 * y + 0 = s * x;
y' = bx + dy + f = 0 * x + s * y + 0 = s * y;

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

4.旋转(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θ

CS-SC的结构这样比较好记:

rotate的旋转30度

transform:rotate(30deg);

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

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

5.拉伸(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轴,两者并无关联。

以上就是斜拉(skew),缩放(scale),旋转(rotate)以及位移(translate)这些属性的实现原理;

问题来了,有这么简便的方法为啥还需要用matrix?

确实,对于一般地交互应用,transform属性默认提供的些方法是足够了,但是,一些其他的效果,如果transform属性没有提供接口方法,那我们只能通过矩阵计算自己实现呀。

要知道,matrix矩阵是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 - y') / (x - x') = -1 / k → ky - ky' = -x + x'

二是中心点在轴线上:
(x + x') / 2 * k = (y + y') / 2 → kx + kx' = y + y'

把x'和y'提出来,就有:
x' = (1 - k * k) / (k* k + 1) * x + 2k / (k * k + 1) * y
y' = 2k / (k * k + 1) * x + (k * k - 1) / (k * k + 1) * y

再结合矩阵公式:
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)

两条垂直的线段的斜率相乘等于-1,大家都还记得吧?
不记得可以点击详情请点击这里!

四、3D变换中的矩阵

本质上很多东西都与2D一致的,只是复杂度不一样而已。只是从 3 x 3 的矩阵变成 4 x 4 的矩阵,而且参数从6个参数,变成16个参数。

transform: matrix3d(x, 0, 0, 0, 0, y, 0, 0, 0, 0, z, 0, 0, 0, 0, 1)

这个就由大家自己发挥了。

五、其他

其实不仅是CSS3的transform是这样,其实canvas和svg的也是同理,所以我在这里也不再一一列举了,有兴趣的同学就自己去探索吧,网上也很多大神的文章可以去了解下。

最后一次编辑于  2020-02-12  
点赞 2
收藏
评论
登录 后发表内容