前端 · 深入理解 transform 函数的计算原理 ②
前排提示:本篇为该系列第二篇,内容相对于第一篇来说比较简单,各位可当休闲读物来看。
《前端 · 深入理解 transform 函数的计算原理 ①》
接上回书讲到,我们知道了 transform 函数中的四大类共九个计算函数的工作原理。
既然除去 matrix 以外的八个具体形变函数,都可以用 matrix 来表达,那么这样是否意味着,只要有具体的参数,就可以用 matrix 来替代其他所有计算函数。也就是说,其实只用 matrix 就可以玩转 transform。
那么怎么玩?
在本篇,我们要做的目标只有一个:代码压缩。
展开来讲,是针对 transform 函数的代码压缩。
首先,为什么要做这件事情呢?
原因有二:
第一,transform 函数支持函数接续使用,所以经常可以看到开发者在代码中写入非常长的函数链条,诸如:
transform="rotate(-10 50 100) translate(-36,45.5) matrix(1,2,3,4,5,6) skewX(40) scale(1 0.5)"
其实这一长串要做的事情只有一个,那就是把一个元素,从状态 A,变成状态 B。
当元素数量上来以后,这种冗长的代码写法,无异于对加载和渲染产生额外消耗。而且代码阅读起来也十分不美观。
上一篇讲过,transform 中的多函数工作原理为矩阵乘法,所以这么长一串,其实只需要一个 matrix 就可以解决(这里保留了两位小数):
transform="matrix(1.33,1.80,2.38,2.46,-38.19,66.30)"
是不是看起来舒服多了?
交给浏览器的运算步骤减少了,前端代码文件体积降低了,视觉上看起来也规整很多,一举多得。
第二,显式的 transform 函数序列很容易让很多不喜欢动脑的“致敬者”轻易获取到变换逻辑。而由于矩阵乘法运算难以倒推出结果,这种隐式的压缩写法,等同于加密处理。
综上,我们要做的,其实就是完成矩阵乘法。
方法很简单:
① 将各个变化函数转化为对应的 matrix 形式
② 将各个 matrix 按顺序连乘,得到最终结果
最后这个有且仅有一个的变化矩阵,就是我们用来替换“函数链”的那个唯一的 matrix() 。
第一步就不多说了,上一篇讲地非常细。关键在于第二步,不过矩阵乘法本身,对于理工科学生来说,大学一年级甚至高中三年级都学过,其实也不难。
这里给广大读者展开列一下公式,直接套用即可:
Mresult=M1⋅M2=(a1c1e1b1d1f1001)⋅(a2c2e2b2d2f2001)=(a1∗a2+c1∗b2+e1∗0a1∗c2+c1∗d2+e1∗0a1∗e2+c1∗f2+e1∗1b1∗a2+d1∗b2+f1∗0b1∗c2+d1∗d2+f1∗0b1∗e2+d1∗f2+f1∗10∗a2+0∗b2+1∗00∗c2+0∗d2+1∗00∗e2+0∗f2+1∗1)=(a1∗a2+c1∗b2a1∗c2+c1∗d2a1∗e2+c1∗f2+e1b1∗a2+d1∗b2b1∗c2+d1∗d2b1∗e2+d1∗f2+f1001)\begin{aligned} M_{result} &= M_{1}·M_{2} \\ &= \begin{pmatrix} a_{1} & c_{1} & e_{1} \\ b_{1} & d_{1} & f_{1} \\ 0 & 0 & 1 \\ \end{pmatrix} ·\begin{pmatrix} a_{2} & c_{2} & e_{2} \\ b_{2} & d_{2} & f_{2} \\ 0 & 0 & 1 \\ \end{pmatrix} \\ &= \begin{pmatrix} a_{1}*a_{2}+c_{1}*b_{2}+e_{1}*0 & a_{1}*c_{2}+c_{1}*d_{2}+e_{1}*0 & a_{1}*e_{2}+c_{1}*f_{2}+e_{1}*1 \\ b_{1}*a_{2}+d_{1}*b_{2}+f_{1}*0 & b_{1}*c_{2}+d_{1}*d_{2}+f_{1}*0 & b_{1}*e_{2}+d_{1}*f_{2}+f_{1}*1 \\ 0*a_{2}+0*b_{2}+1*0 & 0*c_{2}+0*d_{2}+1*0 & 0*e_{2}+0*f_{2}+1*1 \\ \end{pmatrix} \\ &= \begin{pmatrix} a_{1}*a_{2}+c_{1}*b_{2} & a_{1}*c_{2}+c_{1}*d_{2} & a_{1}*e_{2}+c_{1}*f_{2}+e_{1} \\ b_{1}*a_{2}+d_{1}*b_{2} & b_{1}*c_{2}+d_{1}*d_{2} & b_{1}*e_{2}+d_{1}*f_{2}+f_{1} \\ 0 & 0 & 1 \\ \end{pmatrix} \\ \end{aligned} Mresult=M1⋅M2=⎝⎛a1b10c1d10e1f11⎠⎞⋅⎝⎛a2b20c2d20e2f21⎠⎞=⎝⎛a1∗a2+c1∗b2+e1∗0b1∗a2+d1∗b2+f1∗00∗a2+0∗b2+1∗0a1∗c2+c1∗d2+e1∗0b1∗c2+d1∗d2+f1∗00∗c2+0∗d2+1∗0a1∗e2+c1∗f2+e1∗1b1∗e2+d1∗f2+f1∗10∗e2+0∗f2+1∗1⎠⎞=⎝⎛a1∗a2+c1∗b2b1∗a2+d1∗b20a1∗c2+c1∗d2b1∗c2+d1∗d20a1∗e2+c1∗f2+e1b1∗e2+d1∗f2+f11⎠⎞
用 python 写,核心就是这一行:
m_result = {'a': m1['a'] * m2['a'] + m1['c'] * m2['b'], 'b': m1['b'] * m2['a'] + m1['d'] * m2['b'],'c': m1['a'] * m2['c'] + m1['c'] * m2['d'], 'd': m1['b'] * m2['c'] + m1['d'] * m2['d'],'e': m1['a'] * m2['e'] + m1['c'] * m2['f'] + m1['e'],'f': m1['b'] * m2['e'] + m1['d'] * m2['f'] + m1['f']}
初始默认为 matrix(1, 0, 0, 1, 0, 0) ,只要将每个函数接续连乘,就可以最终计算出结果。
实测结果如下,各位可自行验证:
<svg width="100%" height="100%"><circle cx="100" cy="100" r="10" fill="red" transform="rotate(-10 50 100) translate(-36,45.5) matrix(1,2,3,4,5,6) skewX(40) scale(1 0.5)"></circle><circle cx="100" cy="100" r="10" fill="green" transform="matrix(1.33,1.80,2.38,2.46,-38.19,66.30)"></circle>
</svg>
其实代码压缩在前端领域非常常见,不同语言也有不同的压缩方式。出于一个比较重要的细节处理,撰写此文跟大家分享。
好啦,本篇完。
前端 · 深入理解 transform 函数的计算原理 ②相关推荐
- 前端 · 深入理解 transform 函数的计算原理 ①
在涉及到前端图形学的时候,几乎避免不了 transform 属性的应用. 而 transform 一共内置了五种不同大类的函数(矩阵变形.平移.缩放.旋转.倾斜,具体细节有九个),开发者经常容易被不同 ...
- 前端移动端的rem适配计算原理
rem是什么? rem(font size of the root element)是指相对于根元素的字体大小的单位.简单的说它就是一个相对单位.看到rem大家一定会想起em单位,em(font si ...
- python agg函数_个人对Pandas中agg、apply和transform函数的理解
个人对Pandas中agg.apply和transform函数的理解 学习<利用Python进行数据分析>一书,关于pandas的这三个函数,个人理解如下. agg agg方法可以被gro ...
- 通过简单的计算理解sumproduct函数(图文)
目录 前言 1.功能 2.验证过程 2.1 数值型数据 2.2 非数值型数据 2.2.1 布尔类型进行四则运算 2.2.2 文本型四则运算 3. 注意事项 前言 本文主要从函数的计算过程来讲解,从自己 ...
- 前端面试 vue生命周期钩子是如何实现的?理解vue中模板编译原理?
生命周期钩子在内部会被vue维护成一个数组(vue 内部有一个方法mergeOption)和全局的生命周期合并最终转换成数组,当执行到具体流程时会执行钩子(发布订阅模式),callHook来实现调用. ...
- crc16的c语言函数 计算ccitt_CCITT CRC-16计算原理与实现
计算原理与实现 CRC 的全称为 Cyclic Redundancy Check ,中文名称为循环冗余校验.它是一类 重要的线性分组码, 编码和解码方法简单, 检错和纠错能力强, 在通信领域广泛 地用 ...
- crc16的c语言函数 计算ccitt_CCITT CRC-16计算原理与实现CRC-ITU
CCITT CRC-16 计算原理与实现 时间: 201 1 -08-28 22:37 :20 来源: 作者: CRC 的全称为 Cy clic Redundancy Check ,中文名称为循环冗余 ...
- 文本相似度php,分析php计算文本字符串相似度函数similar_text()的原理
PHP有个计算两个文本字符串相似度的函数similar_text(),可以得出一个百分比来表示两个字符串的相似程度.效果如下: similar_text('aaaa', 'aaaa', $percen ...
- Direct3D Draw函数 异步调用原理解析
概述 在D3D10中,一个基本的渲染流程可分为以下步骤: 清理帧缓存: 执行若干次的绘制: 通过Device API创建所需Buffer: 通过Map/Unmap填充数据到Buffer中: 将Buff ...
最新文章
- Action 中 Response already committed 解决办法
- ArrayMap java.lang.ArrayIndexOutOfBoundsException
- Javascript之学习笔记每日更新
- 镗孔指令g76格式_钻孔、镗孔、攻丝,11个固定循环详解!
- EasyMock教程–入门
- 乘方取模计算(模幂计算)
- 《Nature》颠覆性发现!第四种热传递方式找到了
- C语言 assert 函数 - C语言零基础入门教程
- hihocoder编程练习赛91:相邻字符串
- 使用JavaScript下进行iframe的DOM操作(考虑浏览器兼容性)
- 用RDA方式同步SQLCE与SQL SERVER数据库
- light动名词_2015年12月英语六级语法知识:动名词
- 地铁的建设主要用什么计算机知识,地铁知识竞答--选择题填空题
- 浅析NDI 5(一)基于NDI 5如何打造全球NDI演播室?
- ESP8266 Blinker 小爱同学 本地控制 手机配网 四路开关 物联网 arduino编程详细注释
- php中如何插入图片,php如何添加图片
- Mac电脑打不开app store,打开网页提示连接不到服务器,图片不能加载提示证书问题
- 基于Hadoop豆瓣电影数据分析(综合实验)
- 太多人问Protobuf的问题了,我只好把这个重新搬出来!
- Android 使用shape实现虚线或者虚线框
热门文章
- 中国联通携号转网已上线,需输入手机号申请,即可换成39元套餐
- 英语话题 Health
- Linux主备网卡检测脚本,检测linux eth0网卡带宽的脚本
- DevC++ 报错[Error] Id returned 1 exit status
- 微信小程序登录code been used或者invalid code错误解决方案
- 启动monitor白屏
- 激活函数、损失函数和优化函数的比较
- 23种设计模式(白话篇章 )
- 三极管和MOS管开关速度谁快呀
- `Algorithm-Solution` `LeetCode` 6305. 二进制矩阵中翻转最多一次使路径不连通