前排提示:本篇为该系列第二篇,内容相对于第一篇来说比较简单,各位可当休闲读物来看。

《前端 · 深入理解 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​=⎝⎛​a1​b1​0​c1​d1​0​e1​f1​1​⎠⎞​⋅⎝⎛​a2​b2​0​c2​d2​0​e2​f2​1​⎠⎞​=⎝⎛​a1​∗a2​+c1​∗b2​+e1​∗0b1​∗a2​+d1​∗b2​+f1​∗00∗a2​+0∗b2​+1∗0​a1​∗c2​+c1​∗d2​+e1​∗0b1​∗c2​+d1​∗d2​+f1​∗00∗c2​+0∗d2​+1∗0​a1​∗e2​+c1​∗f2​+e1​∗1b1​∗e2​+d1​∗f2​+f1​∗10∗e2​+0∗f2​+1∗1​⎠⎞​=⎝⎛​a1​∗a2​+c1​∗b2​b1​∗a2​+d1​∗b2​0​a1​∗c2​+c1​∗d2​b1​∗c2​+d1​∗d2​0​a1​∗e2​+c1​∗f2​+e1​b1​∗e2​+d1​∗f2​+f1​1​⎠⎞​​

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 函数的计算原理 ②相关推荐

  1. 前端 · 深入理解 transform 函数的计算原理 ①

    在涉及到前端图形学的时候,几乎避免不了 transform 属性的应用. 而 transform 一共内置了五种不同大类的函数(矩阵变形.平移.缩放.旋转.倾斜,具体细节有九个),开发者经常容易被不同 ...

  2. 前端移动端的rem适配计算原理

    rem是什么? rem(font size of the root element)是指相对于根元素的字体大小的单位.简单的说它就是一个相对单位.看到rem大家一定会想起em单位,em(font si ...

  3. python agg函数_个人对Pandas中agg、apply和transform函数的理解

    个人对Pandas中agg.apply和transform函数的理解 学习<利用Python进行数据分析>一书,关于pandas的这三个函数,个人理解如下. agg agg方法可以被gro ...

  4. 通过简单的计算理解sumproduct函数(图文)

    目录 前言 1.功能 2.验证过程 2.1 数值型数据 2.2 非数值型数据 2.2.1 布尔类型进行四则运算 2.2.2 文本型四则运算 3. 注意事项 前言 本文主要从函数的计算过程来讲解,从自己 ...

  5. 前端面试 vue生命周期钩子是如何实现的?理解vue中模板编译原理?

    生命周期钩子在内部会被vue维护成一个数组(vue 内部有一个方法mergeOption)和全局的生命周期合并最终转换成数组,当执行到具体流程时会执行钩子(发布订阅模式),callHook来实现调用. ...

  6. crc16的c语言函数 计算ccitt_CCITT CRC-16计算原理与实现

    计算原理与实现 CRC 的全称为 Cyclic Redundancy Check ,中文名称为循环冗余校验.它是一类 重要的线性分组码, 编码和解码方法简单, 检错和纠错能力强, 在通信领域广泛 地用 ...

  7. crc16的c语言函数 计算ccitt_CCITT CRC-16计算原理与实现CRC-ITU

    CCITT CRC-16 计算原理与实现 时间: 201 1 -08-28 22:37 :20 来源: 作者: CRC 的全称为 Cy clic Redundancy Check ,中文名称为循环冗余 ...

  8. 文本相似度php,分析php计算文本字符串相似度函数similar_text()的原理

    PHP有个计算两个文本字符串相似度的函数similar_text(),可以得出一个百分比来表示两个字符串的相似程度.效果如下: similar_text('aaaa', 'aaaa', $percen ...

  9. Direct3D Draw函数 异步调用原理解析

    概述 在D3D10中,一个基本的渲染流程可分为以下步骤: 清理帧缓存: 执行若干次的绘制: 通过Device API创建所需Buffer: 通过Map/Unmap填充数据到Buffer中: 将Buff ...

最新文章

  1. Action 中 Response already committed 解决办法
  2. ArrayMap java.lang.ArrayIndexOutOfBoundsException
  3. Javascript之学习笔记每日更新
  4. 镗孔指令g76格式_钻孔、镗孔、攻丝,11个固定循环详解!
  5. EasyMock教程–入门
  6. 乘方取模计算(模幂计算)
  7. 《Nature》颠覆性发现!第四种热传递方式找到了
  8. C语言 assert 函数 - C语言零基础入门教程
  9. hihocoder编程练习赛91:相邻字符串
  10. 使用JavaScript下进行iframe的DOM操作(考虑浏览器兼容性)
  11. 用RDA方式同步SQLCE与SQL SERVER数据库
  12. light动名词_2015年12月英语六级语法知识:动名词
  13. 地铁的建设主要用什么计算机知识,地铁知识竞答--选择题填空题
  14. 浅析NDI 5(一)基于NDI 5如何打造全球NDI演播室?
  15. ESP8266 Blinker 小爱同学 本地控制 手机配网 四路开关 物联网 arduino编程详细注释
  16. php中如何插入图片,php如何添加图片
  17. Mac电脑打不开app store,打开网页提示连接不到服务器,图片不能加载提示证书问题
  18. 基于Hadoop豆瓣电影数据分析(综合实验)
  19. 太多人问Protobuf的问题了,我只好把这个重新搬出来!
  20. Android 使用shape实现虚线或者虚线框

热门文章

  1. 中国联通携号转网已上线,需输入手机号申请,即可换成39元套餐
  2. 英语话题 Health
  3. Linux主备网卡检测脚本,检测linux eth0网卡带宽的脚本
  4. DevC++ 报错[Error] Id returned 1 exit status
  5. 微信小程序登录code been used或者invalid code错误解决方案
  6. 启动monitor白屏
  7. 激活函数、损失函数和优化函数的比较
  8. 23种设计模式(白话篇章 )
  9. 三极管和MOS管开关速度谁快呀
  10. `Algorithm-Solution` `LeetCode` 6305. 二进制矩阵中翻转最多一次使路径不连通