2d与3d矩阵变换公式
CSS3中的2d矩阵变换
- CSS3中的
transform: translate(tx, ty)
等价于transform: matrix(1,0,0,1,tx,ty)
- CSS3中的
transform:rotate(θ)
等价于transform: matrix(cosθ,sinθ,-sinθ,cosθ,0,0)
- CSS3中的
transform: scale(Sx, Sy)
等价于transform: matrix(Sx,0,0,Sy,0,0)
- CSS 3中的
transform: skew(θx,θy)
等价于transform:matrix(tan(θx),0,0,tan(θy),0,0)
CSS3中的3d矩阵变换
给个简单的demo,利用CSS3动画库 bounce.js 通过设置元素属性 transform:matrix3d
(1-16位参数值) 让元素偏移 200px。 从matrix三阶矩阵到matrix3d四阶矩阵,本质上很多东西都与2D大同小异,只是复杂度不一样而已。
<!--dom--> <div class="animation-target"></div> <!--css代码--> .animation-target { background-color: #333; height: 100px; width: 100px; } <!--js代码--> let bounce = new Bounce(); bounce.translate({ from: { x: 0 }, to: { x: 200 } }) bounce.applyTo(document.querySelector('.animation-target')) /* bounce.js 其余scale、rotate、skew等api最终都是通过transform:matrix3d(1-16位参数值)来实现元素的动画效果 */
效果图如下:matrix3d对应的矩阵运算细节可参考 bounce.js
svg中的矩阵变换
svg中的变换原理和css3中的类似,但是在svg中没有相关的属性来设置变换的中心点,只能通过translate来模拟。如下设置transform-origin是不生效的
<!--dom--> <svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="100" height="190"> <rect id="SvgjsRect1008" width="100" height="100" transform-origin="0% 0%" transform="translate(100, 0)"></rect> </svg> /* transform-origin="0% 0%" 设置是不生效的 */
下面结合SVG.js 这个开源库来看下svg中的矩阵变换应用
<!--dom 作为SVG.js的挂载节点--> <div id="drawing"></div> <!--js--> let draw = SVG('drawing').size(300, 300) let rect = draw.rect(100, 100) rect.rotate(45) // 旋转45度
如图:
那么rect.rotate(45)
是怎么变成 上图中的 matrix
的呢? 如下:
<!--SVG.js 中的关键代码截取--> rect.rotate(45) => rotate: function(d, cx, cy) { return this.transform({ rotation: d, cx: cx, cy: cy }) } transform: function(o, relative) { var target = this, matrix; // this 通过SVG.js new 出的一个react实例对象 matrix = new SVG.Matrix(target) // 获取当前元素的transform: matrix矩阵值,具体实现可以查阅SVG.js源码 ... 此处省略部分代码 ensureCentre(o, target) // 通过svg原生api, element.node.getBBox()来计算元素的中心点o // 应用矩阵 matrix = relative ? // relative matrix.rotate(o.rotation, o.cx, o.cy) : // absolute matrix.rotate(o.rotation - matrix.extract().rotation, o.cx, o.cy) } rotate: function(r, cx, cy) { // convert degrees to radians r = SVG.utils.radians(r) // 计算对应的旋转矩阵, 对应a,b,c,d,e,f值如下 return this.around(cx, cy, new SVG.Matrix(Math.cos(r), Math.sin(r), -Math.sin(r), Math.cos(r), 0, 0)) } // Transform around a center point 以中心点来进行旋转 around: function(cx, cy, matrix) { //这里很重要:svg以某个参考点变换时 => 通过先平移translate(cx,cy), 然后transform目标matrix值, 再进行反平移translate(-cx,-cy) return this .multiply(new SVG.Matrix(1, 0, 0, 1, cx || 0, cy || 0)) .multiply(matrix) .multiply(new SVG.Matrix(1, 0, 0, 1, -cx || 0, -cy || 0)) } multiply: function(matrix) { // 这里是把元素当前的transform: matrix属性值与目标矩阵相乘 return new SVG.Matrix(this.native().multiply(parseMatrix(matrix).native())) } native: function() { // SVG.js 中的矩阵相乘, 利用的是svg元素的原生api, createSVGMatrix()来实现 // create new matrix var matrix = SVG.parser.native.createSVGMatrix() // update with current values for (var i = abcdef.length - 1; i >= 0; i--) matrix[abcdef[i]] = this[abcdef[i]] return matrix } //最后把最终计算的matrix变换值设置到react元素上就完成了 this.attr('transform', matrix)