Wert der CSS-Rotation über JavaScript ermitteln

Avatar of Chris Coyier
Chris Coyier am

DigitalOcean bietet Cloud-Produkte für jede Phase Ihrer Reise. Starten Sie mit 200 $ kostenlosem Guthaben!

Ein Kommentar von aditya

Gibt es eine Möglichkeit, über JavaScript den Winkel zu ermitteln, um den ein Element gedreht ist?

Scheint eine vernünftige Anfrage zu sein. Also haben wir etwas HTML

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

Und es ist durch CSS gedreht

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

Unser Ziel ist es, die Zahl "30" aus diesem Element über JavaScript zu erhalten. Die moderne Methode zum Abrufen von Stilinformationen aus einem Element ist getComputedStyle() (Unterstützt in allen modernen Browsern und IE 9+, ältere IE-Versionen unterstützten currentStyle()). Versuchen wir, es mit getComputedStyle() zu bekommen.

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";

Man könnte denken, der zurückgegebene Wert wäre "rotate(30deg)" und wir könnten parseInt() darauf anwenden und "30" erhalten. Aber leider funktioniert das nicht. Der tatsächliche Wert, den wir zurückbekommen, ist dieser

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

Der Browser wandelt die CSS-Rotations-Transformation in eine Matrix-Transformation um. Ich stelle mir vor, er tut dies, um mehrere Transformationen auf dem einzelnen Element zu einem einzigen Wert zu vereinfachen. Was also tun wir?

Nicolas Gallager recherchierte die Matrix-Transformation für Rotations-Transformationen. Die im Wesentlichen dies ist

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

Wir brauchen wirklich nur eine davon, um eine schnelle Gleichung zu erstellen. Wir müssen den Arkussinus (Umkehrung von Sinus, sin-1) der Werte ermitteln, wobei wir sicherstellen müssen, dass wir ihn in **Radiant** erhalten.

Zuerst legen wir die einzelnen Matrixwerte getrennt in die Hand

// 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

Dann wissen wir sin(X) == 0,5, also asin(0,5) == Radiant und Grad == Radiant * 180/π.

Also

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

Juhu!

Nicolas ging noch weiter, indem er auch die Skalierung berücksichtigte. Mit dem vollständigen Code unten kann der Rotationswert extrahiert werden, wenn beliebige andere Transformationen angewendet werden.

#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');

**UPDATE:** Es stellt sich heraus, dass diese Zeile zur Berechnung des Winkels viel zuverlässiger ist

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

Vielen Dank an Nicolas, Divya und Oli für die Hilfe hinter den Kulissen.