使用 CSS3 Transform 的 Matrix 实现镜像翻转

274 阅读5分钟

几何意义

SVG 是一种矢量图形,放大可以不失真。

线性代数的 数值操作 和 几何直观

几何直观:更容易在不同场景中引入概念来解决问题。如:sinA

向量可以是任何东西,只要保证向量相加和数字和向量相乘有意义即可。

向量相加和向量数乘贯彻向量的始终。

向量是一个箭头(有方向,有距离),一个点,二维平面是一个坐标。

数乘就是向量的缩放,2*[2,3]

i 是 x 轴的基向量

j 是 y 轴的基向量

坐标【2,-3】是标量,将基向量拉长。[2,-3]相当于经过缩放的向量的和,2i+(-3)j

ac 是变换后的x基向量,bd是变换后y 的基向量。默认值i 是(1,0),j是(0,1)。因此matrix(a,b,c,d,e,f)中,a和 d的默认值是 1。

简单理解:某个点的位置为(2,3)。开始时在i(1,0)方向走两步,在j(0,1)方向走3 步。后来逆时针旋转 90 度,变成在 i 上走(0,1)上走 2 步,在 j(-1,,0)上走3 步。

matrix(0, -1, 1, 0, 0, 0); 是传递的基向量的坐标。

线性变换是指定变换后的基向量的坐标,然后根据坐标进行对应的数乘运算。

一个矩阵就是对空间的一种线性变换。

连续变换是矩阵相乘

矩阵应用

transform: translate(10px, 10px); => transform: matrix(1, 0, 0, 1, 10, 10);

transform: scale(1, 0.5); => transform: matrix(1, 0, 0, 0.5, 0, 0);

transform: rotate(45deg); => matrix(cos45,sin45,-sin45,cos45,0,0) => transform: matrix(0.866025,0.500000,-0.500000,0.866025,0,0);

transform: skew(30deg, 30deg); => matrix(1,tan(θy),tan(θx),1,0,0)
 => transform: matrix(1, 0.57735, 0.57735, 1, 0, 0);
变换类型变换方法matrix 写法
平移translate(translateX, translateY)matrix(1, 0, 0, 1, translateX, translateY)
缩放scale(scaleX, scaleY)matrix(scaleX, 0, 0, scaleY, 0, 0)
斜拉skew(angleX, angleY)matrix(1, tan(angleY), tan(angleX), 1, 0, 0)
旋转rotate(angle)matrix(cos(angle), sin(angle), -sin(angle), cos(angle), 0, 0)

matrix(scaleX(), skewY(), skewX(), scaleY(), translateX(), translateY())

旋转,拉伸,平移变换,本质上都是通过 Matrix() 方法实现的。CSS 提供 Transform:rotate这种方式是一种语法糖。方便写更容易维护的代码,并且操作简单。

线性变换

线性变换两个要求:直线依然是直线,原点保持固定不变。意思是:保持网格线平行且等距分布。缩放,旋转可以实现。也就是 a,b,c,d四个参数。但是平移需要移动坐标原点,所以引入了 e,f两个参数分别是坐标原点的变化。

仿射变换 = 线性变换 + 平移变换

仿射变换矩阵中:

基向量的变化:

坐标原点的变化:

平移计算

CSS3 transform matrix矩阵偏移分解实例页面

#mydiv{ 	transform: matrix(1, 0, 0, 1, 150, 150); 	}

相当于transform: translate(150px,150px)。点(220px,220px)的坐标

齐次坐标能区分是一个向量还是一个点

从普通坐标转换成齐次坐标时
如果(x,y,z)是个点,则变为(x,y,z,1);
如果(x,y,z)是个向量,则变为(x,y,z,0)

反之成立

使用场景

  1. 当使用 transform 不满足需求,没有提供对应的接口,需要使用更复杂的变换操作,可以使用 matrix。如:镜像对称效果。
  2. 当位移,变换操作较多,计算较复杂时,使用 tansform 不方便,可以新建一个 6 个参数的数组,所有操作计算结束后,将数组作为参数传递给 Matrix()。 【连续变换:矩阵相乘】

镜像对称

任意对称轴都可以用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)

通过 2 个方程

  1. 垂直的两条线斜率相乘等于-1 :(y - y') / (x - x') = -1 / k → ky - ky' = -x + x'
  2. 因为镜像,所以中点在轴线上: (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)

只需要知道对称轴的斜率 k ,就可以算出来matrix 中 a,b,c,d的值,如果对称轴不经过坐标轴原点,使用 e,f 进行平移。

踩了两个坑:

  1. 斜率的计算需要是y的变化量/x的变化量、符号不要搞错了:(y - y') / (x - x') 或者 (y'- y) / (x' - x)
  2. 数学中的y=x在web开发中需要注意y轴是向下的,和数学中的y轴相反

复合变换

复合变换是连续进行多个变换。

比如:放大 1.5 倍并旋转 45°。

transform: rotate(45deg) scale(1.5);

旋转矩阵表示为向量,[cos(a) sin(a) -sin(a) cos(a) 0 0]其中a是角度。为了缩放,我们需要使用矩阵[sx 0 0 sy 0 0]

transform: matrix(1.0606, 1.0606, -1.0606, 1.0606, 0, 1)

常用参数参考

参考

Understanding the CSS Transforms Matrix

理解CSS3 transform中的Matrix(矩阵)

仿射变换及其变换矩阵的理解

线性映射的矩阵的例子

详解 CSS 中的 matrix 和 matrix3d 变换原理