如何获取 DOM 元素的变换矩阵?

Jia*_*ang 8 html javascript canvas web

如何获取 DOM 元素的变换矩阵?就像画布上下文一样,我们在 DOM 上有 getTransform() 方法吗?

ibr*_*cin 3

getComputedStyle($el).transform如果有任何 2d 变换,则应返回 2 x 3 变换矩阵;如果 z 轴上也有变换,则应返回 4 x 4 矩阵 3d。请参阅我的答案,了解如何操作以防万一。

\n

对于嵌套元素,结果矩阵是从父级到子级的矩阵相乘:

\n
<parent>\n  <firstChild>\n    <grandChild>\n    </grandChild>\n  </firstChild>\n</parent>\n
Run Code Online (Sandbox Code Playgroud)\n

上面生成的 DOMMatrix 将是:

\n

\xe2\x9c\x9d M父代\xe2\x80\xa2 M第一个子代\xe2\x80\xa2 M孙代

\n

上面的 svg 等价于变换属性将是:

\n

变换=“变换父级变换firstChild变换grandChild

\n

因此,变换在逻辑上RIGHTLEFT应用(孙子的变换首先应用于自身),其数学投影是将矩阵从LEFTRIGHT相乘,如上面的\xe2\x9c\x9d所示。

\n

但有一个问题,在 SVG 中,所有转换都是相对于 viewBox 的绝对 0,0 原点(左上角),无论元素在哪里/是什么。因此,我们需要一些特殊条件:

\n

1-用途transform-origin: 0px 0px;

\n
\n

在 CSS 中,一些变换(例如旋转)是相对于元素的中心进行的,以使人们更容易操作。然而,这会产生“旋转(Xdeg)”相对于元素宽度/高度的问题(默认CSS旋转约为50% 50%)。边长为 100px 的正方形上的默认 css“旋转(40deg)”不会产生与边长为 300px 的正方形相同的矩阵。为了不合并元素的可变宽度/高度,我们可以做的一件事是确保元素使用transform-origin: 0px 0px;.

\n
\n

2-仅使用CSS定位transform,不使用CSS定位:

\n
\n

确保相对/绝对定位元素不包含修改元素位置的值,因为left, top, bot, right ...这些值不会被捕获在元素的转换矩阵中,除非您el.getBoundingClientRect()自己手动调用并派生矩阵条目

\n
\n

如果满足这些条件,下面的示例(也是小提琴)应该可以正常工作。目标是计算红色(父)+蓝色(子)方块的组合矩阵,并将洋红色/黄色与蓝色方块叠加。洋红色的矩阵是通过将红色和蓝色矩阵从左到右相乘、黄色矩阵从右到左相乘来计算的:

\n

\r\n
\r\n
/*THIS EXAMPLE WORKS IF THE MECHANISM OF TRANSFORMATION MATRICES \nIN CSS DOM IS CLOSE ENOUGH TO SVG, \nWHICH MEANS LIKE IN SVG, ROTATE SHOULD NOT \nBE AROUND AN ELEMENTS CENTER (default) BUT TO \nTHE TOP LEFT CORNER OF THE ELEMENT. \nIN SVG, ALL TRANFORMATIONS ARE RELATIVE TO THE TOP LEFT \nCORNER OF THE VIEWBOX WHICH CANNOT \nBE 100% TRANSPORTED TO CSS. \nTHE CLOSEST I COULD FIND WAS TO \nSET TRANSFORM-ORIGIN: 0px 0px WHICH SEEMS TO WORK */\n\n/*There is red parent square and blue child square \ninside which both have cascading transformations. \nThe goal is to combine their transformation matrices \nand make yellow (W) and magenta (U) squares \nsuperimpose with the blue square*/\n\n//get all the elements in variables\nconst [elX, elY, elU, elW] = [...document.getElementsByTagName("div")];\n//make a regexp to extract the entries of the matrix, with match, it returns [a, b, c, d, e, f]\nconst rgx = /(-?[0-9]+(?:\\.[0-9]+)?)/gi;\n//DOMMatrices expect an array of 6 numbers for 2D transformations\n//get the matrix of big red parent square\nconst matrix_elX = new DOMMatrix(getComputedStyle(elX).transform.match(rgx));\n//get the matrix of the small blue child square\nconst matrix_elY = new DOMMatrix(getComputedStyle(elY).transform.match(rgx));\n/*\n\'result\' is MX * MY and \'result2\' is MY * MX\nmagenta square U uses result,\nyellow square W uses result2,\nmagenta square U correctly superimposes with blue square,\nbut yellow square W does NOT,\ntherefore MX * MY and MY * MX are not the same, as you can expect that matrice multiplication is NOT commutative\nBelow uses DOMMatrix.fromMatrix is create clones of the matrices because operations does mutate the matrix itself.\n*/\nlet result = DOMMatrix.fromMatrix(matrix_elY).preMultiplySelf(DOMMatrix.fromMatrix(matrix_elX)),\n        result2 = DOMMatrix.fromMatrix(matrix_elX).preMultiplySelf(DOMMatrix.fromMatrix(matrix_elY));\nelU.style.transform = result;\nelW.style.transform = result2;
Run Code Online (Sandbox Code Playgroud)\r\n
* {\n  margin: 0px;\n  box-sizing: border-box;\n  transform-origin: 0px 0px;\n}\n\n#x {\n  position: relative;\n  background: red;\n  width: 300px;\n  height: 300px;\n  transform: translate(-20px, -20px) rotate(-30deg) translate(150px, 100px) rotate(20deg);\n}\n\n#y {\n  position: relative;\n  background: blue;\n  width: 100px;\n  height: 100px;\n  transform: rotate(-5deg) rotate(10deg) translate(200px, 50px) rotate(75deg) translate(35px, 10px) rotate(-25deg);\n}\n\n#u {\n  position: absolute;\n  top: 0px;\n  width: 100px;\n  height: 100px;\n  background: magenta;\n  opacity: 0.5;\n}\n\n#w {\n  position: absolute;\n  top: 0px;\n  width: 100px;\n  height: 100px;\n  background: yellow;\n  opacity: 0.5;\n}
Run Code Online (Sandbox Code Playgroud)\r\n
<div id="x">\n  <div id="y">\n    \n  </div>\n</div>\n\n<div id="u">U</div>\n<div id="w">W</div>
Run Code Online (Sandbox Code Playgroud)\r\n
\r\n
\r\n

\n