CSS3 transform 中的 matrix

CSS的transforn详解

位移,旋转,偏移,缩放分别使用translate/rotate/skew/scale的方式来控制元素变换,也可以使用matrix。

使用translate/rotate/skew/scale

.demo{
  transform:translate(10px, 20px) rotate(30deg) scale(1.5, 2); 
}

matrix

.demo{
  transform:matrix(0.75, 0.8, -0.8, 1.2, 10, 20)
}

Matrix的中文是矩阵,在计算机科学中,会用矩阵来对向量进行变换,在css3的transform属性中,可以使用矩阵对图像进行变换。

matrix与矩阵对应

css3里面可以用矩阵表示2D和3D转换

.demo{
  transform:matrix(a,b,c,d,e,f)
}
矩阵

2D的转换是由一个3*3的矩阵表示的,前两行代表转换的值,分别是 a b c d e f ,要注意是竖着排的,第一行代表的是X轴变化,第二行代表的是Y轴的变化,第三行代表的是Z轴的变化,2D不涉及到Z轴,这里使用 0 0 1

假设一个问题

创建一个宽高为200px的div ,div 里面有一个红色的点,位置是{x:181px y:50px}

矩阵

倘若将这个div向右平移20px,旋转37°,x轴缩放1.5倍,y轴缩放2倍

transform:tranlate(10px,20px) rotate(37deg) scale(1.5, 2)
矩阵

缩放scale(x,y)

缩放对应的是矩阵中的adx轴的缩放比例对应a,y轴的缩放比例对应d

transform:scale(x,y)
a = x
d = y

所以scale(1.5, 2)对应的矩阵是

matrix:(1.5,0,0,0,2,0)
(矩阵).png

如果元素没有被缩放,默认a = 1 d =1

平移 translate(10, 20)

平移对应的是矩阵中 ef,平移的xf分别对应 ef

transform:translate(10, 20)
e = 10
f = 20 

对应:transform: matrix(a, b, c, d ,10, 20);

结合缩放:transform: matrix(1.5 0, 0, 2, 10, 20)

旋转 rotate(0deg)

旋转影响的是a/b/c/d四个值,分别是什么呢?

transform: rotate(θdeg)

a=cosθ

b=sinθ

c=-sinθ

d=cosθ

如果要计算 30° 的sin值:

首先我们要将 30° 转换为弧度,传递给三角函数计算。用 JS 计算就是下面的样子了。

// 弧度和角度的转换公式:弧度=π/180×角度 
const radian = Math.PI / 180 * 30 // 算出弧度
const sin = Math.sin(radian) // 计算 sinθ
const cos = Math.cos(radian) // 计算 cosθ
console.log(sin, cos) // 输出 ≈ 0.5, 0.866
transform: rotate(30deg)

a=0.866

b=0.5

c=-0.5

d=0.866

transform: matrix(0.866, 0.5, -0.5, 0.866, 0, 0);
矩阵

偏移 skew(20deg, 30deg)

上面的题目中没有出现出现偏移值,偏移值也是由两个参数组成,x 轴和 y 轴,分别对应矩阵中的 c 和 b。是 x 对应 c,y 对应 b, 这个对应并不是相等,需要对 skew 的 x 值 和 y 值进行 tan 运算。

transform: skew(20deg, 30deg);

b=tan30°

c=tan20°

注意 y 对应的是 c,x 对应的是 b。
transform: matrix(a, tan(30deg), tan(20deg), d, e, f)

使用 JS 来算出 tan20 和 tan30

// 先创建一个方法,直接返回角度的tan值
function tan (deg) {
    const radian = Math.PI / 180 * deg
    return Math.tan(radian)
}
const b = tan(30)
const c = tan(20)
console.log(b, c) // 输出 ≈ 0.577, 0.364

b=0.577 c=0.364
transform: matrix(1, 0.577, 0.364, 1, 0, 0)

旋转+缩放+偏移+位移怎么办?

如果我们既要旋转又要缩放又要偏移,我们需要将旋转和缩放和偏移和位移多个矩阵相乘,要按照transform里面rotate/scale/skew/translate所写的顺序相乘。
这里我们先考虑旋转和缩放,需要将旋转的矩阵和缩放的矩阵相乘

实在是用语言解释不清楚如何去乘,用一张图解释吧:

这里我用小写字母代表第一个矩阵中的值,大写字母代表第二个矩阵里的值


1.png

将我们的已经得到的矩阵带入到公式


2.png

得出:

transform: rotate(30) scale(1.5 2);

转换为 matrix 表示为:

transform: matrix(1.299, 0.75, -1, 1.732, 0, 0);

找到这次转换的矩阵

div 的 transform 值如下

transform: translate(10px, 20px) rotate(37deg) scale(1.5, 2);

#### translate(10px, 20px)

x 平移 10px,y 平移 20px,所以 e=10,f=20。


(矩阵

rotate(37deg)

sin37° ≈ 0.6

cos37° ≈ 0.8

根据 a 对应 cos b,对应 sin,c 对应 -sin,d 对应 cos 的值

得到:

a=0.8,b=0.6,c=-0.6,d=0.8
1.png

scale(1.5, 2)

x 轴缩放 1.5,y 轴缩放 2,所以 a=1.5,d=2

1.png

结合

transform: translate(10px, 20px) rotate(37deg) scale(1.5, 2);

我们使用 位移矩阵 旋转矩阵 缩放矩阵(根据transform中的变换类型书写的顺序)

可以使用矩阵计算器进行计算

从左往右依次计算

10.png

所以最终得到矩阵


11.png
matrix(1.2, 0.9, -1.2 1.6, 10, 20)

验证一下

transform: matrix(1.2, 0.9, -1.2 1.6, 10, 20)

transform: translate(10px, 20px) rotate(37deg) scale(1.5, 2);

效果是一样的

如何对一个坐标进行矩阵变换

我们已经知道了这个矩阵,如何通过矩阵对一个坐标进行变化,找到这个坐标变化后的位置呢?

我们用之前得出的变换矩阵去乘以这一个坐标组成的3*1(三排一列)矩阵。


2.png

上面已经介绍过如何进行矩阵乘法了,这里在介绍一遍

3.png

上图中左右两个矩阵颜色相同的位置相乘后相加,每一行都进行这样的计算:

4.png

得到一个3*1的矩阵,第一行是转换后的 x 值,第二行是转换后的 y 值,第三行是转换后的 z 值(2d不考虑z值)。

前面讲到,矩阵的第一行影响 x,第二行影响 y,也体现在这个地方。

假设我们的坐标是(50, 80),这里还没有针对我们提出的问题上面的点进行计算。

我们把坐标写成矩阵的形式,设置 z 轴是1:

5.png

然后进行乘法计算:


6.png

通过我们计算出来的矩阵变换得到新的位置(46, 172)

继续刚刚问题

坐标是需要基于一个坐标系存在的,我们需要找到正确的坐标系才能算出准确的坐标。 在 CSS transform 中,有个属性是 transform-origin,来设置变换所基于的点,默认是transform-origin: 50% 50%,基于中间元素的中心点。我们需要以这个点建立坐标系。

在网页中,坐标系是 x 轴向右,y 轴向下。

转换前:


7 (1).png

转换后:


8.1.png

根据题目我们知道,这个点相对于绿色div左上角的坐标是(181, 50) 绿色div的宽高为200 基于绿色div中心点建立的坐标系,这个点的坐标是(81, -50)

将坐标代入公式进行计算:


9.png

得到坐标约为(167, 13)

再将这个坐标转换成页面坐标系(267,113)

最终我们得到了这个点在经过转换后的坐标

参考文章: https://fanmingfei.com/post/CSS3_Transform_Matrix_Intro.html

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,311评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,339评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,671评论 0 342
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,252评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,253评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,031评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,340评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,973评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,466评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,937评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,039评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,701评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,254评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,259评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,485评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,497评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,786评论 2 345

推荐阅读更多精彩内容