通过 JavaScript 获取 CSS 旋转值

Avatar of Chris Coyier
Chris Coyier

DigitalOcean 为您的旅程的每个阶段提供云产品。 立即开始使用 价值 200 美元的免费积分!

来自 aditya 的 评论

有没有办法 [通过 JavaScript] 获取元素旋转的角度?

这似乎是一个合理的要求。 因此我们有一些 HTML

<div id="i-am-rotated">text</div>

它通过 CSS 旋转

#i-am-rotated {
  -webkit-transform: rotate(30deg); 
  -moz-transform:    rotate(30deg); 
  -ms-transform:     rotate(30deg); 
  -o-transform:      rotate(30deg);  
}

我们的目标是通过 JavaScript 从该元素中获取数字“30”。 从元素访问样式信息的现代方法是 getComputedStyle()(在所有现代浏览器和 IE 9+ 中支持,较旧的 IE 支持 currentStyle())。 让我们尝试使用 getComputedStyle() 获取它

var el = document.getElementById("i-am-rotated");

var st = window.getComputedStyle(el, null);

var tr = st.getPropertyValue("-webkit-transform") ||
         st.getPropertyValue("-moz-transform") ||
         st.getPropertyValue("-ms-transform") ||
         st.getPropertyValue("-o-transform") ||
         st.getPropertyValue("transform") ||
         "Either no transform set, or browser doesn't do getComputedStyle";

您可能认为返回值将是“rotate(30deg)”,我们可以在其上运行 parseInt() 并获得“30”。 但不幸的是,这行不通。 我们实际获得的值如下

console.log(tr);
// matrix(0.8660254037844387, 0.49999999999999994, -0.49999999999999994, 0.8660254037844387, 0, 0)

浏览器将 CSS 旋转转换转换为矩阵转换。 我想它是这样做的,以简化对单个元素的多个转换成为一个值。 那么我们该怎么办呢?

Nicolas Gallager 研究 了旋转转换的矩阵转换。 从本质上讲就是 这个

rotate(Xdeg) = matrix(cos(X), sin(X), -sin(X), cos(X), 0, 0);

我们实际上只需要其中之一来进行快速计算。 我们需要获取这些值的反正弦(正弦的倒数,sin-1),确保以弧度获取。

首先,我们将获取单独的矩阵值

// UPDATE: below was causing errors sometimes...
// var values = tr.split('(')[1].split(')')[0].split(',');
// Replace with... (thanks Thierry)
var values = tr.split('(')[1],
    values = values.split(')')[0],
    values = values.split(',');

var a = values[0]; // 0.866025
var b = values[1]; // 0.5
var c = values[2]; // -0.5
var d = values[3]; // 0.866025

然后我们知道 sin(X) == 0.5 所以 asin(0.5) == radians 并且 degrees == radians * 180/π

所以

var angle = Math.round(Math.asin(b) * (180/Math.PI));
console.log(angle);
// 30

太好了!

Nicolas 通过考虑比例进一步进行了研究。 使用以下完整代码,可以提取旋转值,无论应用了多少其他转换。

#complex-transform {
  -webkit-transform: rotate(30deg) scale(1.2) skew(10deg) translate(5px, 5px); 
  -moz-transform:    rotate(30deg) scale(1.2) skew(10deg) translate(5px, 5px); 
  -ms-transform:     rotate(30deg) scale(1.2) skew(10deg) translate(5px, 5px); 
  -o-transform:      rotate(30deg) scale(1.2) skew(10deg) translate(5px, 5px);  
}
var el = document.getElementById("complex-transform");
var st = window.getComputedStyle(el, null);
var tr = st.getPropertyValue("-webkit-transform") ||
         st.getPropertyValue("-moz-transform") ||
         st.getPropertyValue("-ms-transform") ||
         st.getPropertyValue("-o-transform") ||
         st.getPropertyValue("transform") ||
         "fail...";

// With rotate(30deg)...
// matrix(0.866025, 0.5, -0.5, 0.866025, 0px, 0px)
console.log('Matrix: ' + tr);

// rotation matrix - http://en.wikipedia.org/wiki/Rotation_matrix

var values = tr.split('(')[1];
    values = values.split(')')[0];
    values = values.split(',');
var a = values[0];
var b = values[1];
var c = values[2];
var d = values[3];

var scale = Math.sqrt(a*a + b*b);

// arc sin, convert from radians to degrees, round
// DO NOT USE: see update below
var sin = b/scale;
var angle = Math.round(Math.asin(sin) * (180/Math.PI));

// works!
console.log('Rotate: ' + angle + 'deg');

更新:事实证明,此行对于计算角度更可靠

var angle = Math.round(Math.atan2(b, a) * (180/Math.PI));

感谢 NicolasDivyaOli 的幕后帮助。