css - rotar - taquigrafía rotate3d
skew css (4)
Cómo combinar rotateX(50deg) rotateY(20deg) rotateZ(15deg)
en abreviatura rotate3d()
?
Depende de lo que trates de hacer, este ''truco'' podría ayudarte. Digamos que estás haciendo animación, y quieres agregar transformación tras transformación, y así sucesivamente, y no quieres que el CSS se vea como si estuviera haciendo cientos de transformaciones:
Esto funciona en chrome: 1. Aplica la transformación que quieras a un elemento. 2. La próxima vez que desee agregar una transformación, agréguela a la transformación calculada: "window.getComputedStyle (element) .transform" - pero asegúrese de poner la nueva transformación a la izquierda. 3. Ahora su transformación se vería como "rotateZ (30deg) matrix3d (......). 4. La próxima vez que quiera agregar otra transformación, repita el proceso: Chrome siempre reduce las transformaciones a la notación matrix3d.
TL; DR: aplique las transformaciones que desee y luego obtenga la transformación computada matrix3d.
Este truco también te permite rápidamente (es decir, sin hacer ninguna matemática por tu cuenta) crear una funcionalidad que rote un objeto con respecto a tu marco de referencia en cualquier dirección. Vea el ejemplo a continuación:
EDITAR : También he agregado traducciones xyz. Usando esto, sería muy fácil colocar objetos en ubicaciones específicas de 3D con orientaciones específicas en mente. O ... ¡imagina un cubo que rebota y cambia su eje de rotación con cada rebote según cómo aterrice!
var boxContainer = document.querySelector(''.translator''),
cube = document.getElementById(''cube''),
optionsContainer = document.getElementById(''options'');
var dims = [''x'', ''y'', ''z''];
var currentTransform;
var currentTranslate;
var init = function () {
optionsContainer.querySelector(''.xRotation input'')
.addEventListener(''input'', function (event) {
if (currentTransform != ''none'') {
var newTransform = ''rotateX('' + (360 - event.target.value) + ''deg) '' + currentTransform;
} else {
var newTransform = ''rotateX('' + (360 - event.target.value) + ''deg)'';
}
cube.style.transform = newTransform;
}, false);
optionsContainer.querySelector(''.yRotation input'')
.addEventListener(''input'', function (event) {
if (currentTransform != ''none'') {
var newTransform = ''rotateY('' + (360 - event.target.value) + ''deg) '' + currentTransform;
} else {
var newTransform = ''rotateY('' + (360 - event.target.value) + ''deg)'';
}
cube.style.transform = newTransform;
}, false);
optionsContainer.querySelector(''.zRotation input'')
.addEventListener(''input'', function (event) {
if (currentTransform != ''none'') {
var newTransform = ''rotateZ('' + (360 - event.target.value) + ''deg) '' + currentTransform;
} else {
var newTransform = ''rotateZ('' + (360 - event.target.value) + ''deg)'';
}
cube.style.transform = newTransform;
}, false);
optionsContainer.querySelector(''.xTranslation input'')
.addEventListener(''input'', function (event) {
if (currentTranslate != ''none'') {
var newTransform = ''translateX('' + (100 - event.target.value) + ''px) '' + currentTranslate;
} else {
var newTransform = ''translateX('' + (100 - event.target.value) + ''px)'';
}
boxContainer.style.transform = newTransform;
}, false);
optionsContainer.querySelector(''.yTranslation input'')
.addEventListener(''input'', function (event) {
if (currentTranslate != ''none'') {
var newTransform = ''translateY('' + (100 - event.target.value) + ''px) '' + currentTranslate;
} else {
var newTransform = ''translateY('' + (100 - event.target.value) + ''px)'';
}
boxContainer.style.transform = newTransform;
}, false);
optionsContainer.querySelector(''.zTranslation input'')
.addEventListener(''input'', function (event) {
if (currentTranslate != ''none'') {
var newTransform = ''translateZ('' + (500 - event.target.value) + ''px) '' + currentTranslate;
} else {
var newTransform = ''translateZ('' + (500 - event.target.value) + ''px)'';
}
boxContainer.style.transform = newTransform;
}, false);
reset();
};
function reset() {
currentTransform = window.getComputedStyle(cube).transform;
currentTranslate = window.getComputedStyle(boxContainer).transform;
optionsContainer.querySelector(''.xRotation input'').value = 360;
optionsContainer.querySelector(''.yRotation input'').value = 360;
optionsContainer.querySelector(''.zRotation input'').value = 360;
optionsContainer.querySelector(''.xTranslation input'').value = 100;
optionsContainer.querySelector(''.yTranslation input'').value = 100;
optionsContainer.querySelector(''.zTranslation input'').value = 500;
}
window.addEventListener(''DOMContentLoaded'', init, false);
document.addEventListener(''mouseup'', reset, false);
.translator
{
height: 200px;
position: absolute;
width: 200px;
transform-style: preserve-3d;
}
.threeSpace
{
height: 200px;
moz-perspective: 1200px;
o-perspective: 1200px;
perspective: 200px;
position: absolute;
transform-origin: 50px 50px 100px;
webkit-perspective: 1200px;
width: 100px;
perspective-origin: 100px 25px;
transform-style: preserve-3d;
}
#pointer{
position:relative;
height:2px;
width:2px;
top:25px;
left:100px;
background:blue;
z-index:9999;
}
#cube
{
height: 100%;
moz-transform-origin: 90px 110px 0px;
moz-transform-style: preserve-3d;
o-transform-origin: 90px 110px 0px;
o-transform-style: preserve-3d;
position: absolute;
transform-origin: 90px 110px 0px;
transform-style: preserve-3d;
webkit-transform-origin: 90px 110px 0px;
webkit-transform-style: preserve-3d;
width: 100%;
}
#cube .midPoint{
position:absolute;
top:48px;
left:48px;
height:1px;
width:1px;
background:green;
}
#cube figure
{
border: 2px solid black;
color: white;
display: block;
font-size: 60px;
font-weight: bold;
height: 96px;
line-height: 96px;
position: absolute;
text-align: center;
width: 96px;
/* transform-style: preserve-3d; */
}
#cube .front
{
background: hsl(0, 100%, 50%);
}
#cube .back
{
background: hsl(60, 100%, 50%);
}
#cube .right
{
background: hsl(120, 100%, 50%);
}
#cube .left
{
background: hsl(180, 100%, 50%);
}
#cube .top
{
background: hsl(240, 100%, 50%);
}
#cube .bottom
{
background: hsl(300, 100%, 50%);
}
#cube .front
{
moz-transform: translateZ(50px);
o-transform: translateZ(50px);
transform: translateZ(50px);
webkit-transform: translateZ(50px);
}
#cube .back
{
moz-transform: rotateX(-180deg) translateZ(50px);
o-transform: rotateX(-180deg) translateZ(50px);
transform: rotateX(-180deg) translateZ(50px);
webkit-transform: rotateX(-180deg) translateZ(50px);
}
#cube .right
{
moz-transform: rotateY(90deg) translateZ(50px);
o-transform: rotateY(90deg) translateZ(50px);
transform: rotateY(90deg) translateZ(50px);
webkit-transform: rotateY(90deg) translateZ(50px);
}
#cube .left
{
moz-transform: rotateY(-90deg) translateZ(50px);
o-transform: rotateY(-90deg) translateZ(50px);
transform: rotateY(-90deg) translateZ(50px);
webkit-transform: rotateY(-90deg) translateZ(50px);
}
#cube .top
{
moz-transform: rotateX(90deg) translateZ(50px);
o-transform: rotateX(90deg) translateZ(50px);
transform: rotateX(90deg) translateZ(50px);
webkit-transform: rotateX(90deg) translateZ(50px);
}
#cube .bottom
{
moz-transform: rotateX(-90deg) translateZ(50px);
o-transform: rotateX(-90deg) translateZ(50px);
transform: rotateX(-90deg) translateZ(50px);
webkit-transform: rotateX(-90deg) translateZ(50px);
}
#options{
position:absolute;
width:80%;
top:40%;
}
#options input
{
width: 60%;
}
<body>
<div class="threeSpace">
<div id="pointer"></div>
<div class="translator">
<div id="cube">
<figure class="front"><div class=''midPoint''></div></figure>
<figure class="back"></figure>
<figure class="right"></figure>
<figure class="left"></figure>
<figure class="top"></figure>
<figure class="bottom"></figure>
</div>
</div>
</div>
<section id="options">
<p class="xRotation">
<label>xRotation</label>
<input type="range" min="0" max="720" value="360" data-units="deg" />
</p>
<p class="yRotation">
<label>yRotation</label>
<input type="range" min="0" max="720" value="360" data-units="deg" />
</p>
<p class="zRotation">
<label>zRotation</label>
<input type="range" min="0" max="720" value="360" data-units="deg" />
</p>
<p class="xTranslation">
<label>xTranslation</label>
<input type="range" min="0" max="200" value="100" data-units="deg" />
</p>
<p class="yTranslation">
<label>yTranslation</label>
<input type="range" min="0" max="200" value="100" data-units="deg" />
</p>
<p class="zTranslation">
<label>zTranslation</label>
<input type="range" min="0" max="1000" value="500" data-units="deg" />
</p>
</section>
</body>
El valor exacto es rotate3d(133,32,58,58deg)
Ver el fiddle (Para Chrome y Safari, usando -webkit-transform)
Sintaxis:
rotate3d(x, y, z, a)
Valores:
-
x
Es un<number>
describe la coordenada x del vector que denota el eje de rotación. -
y
Es un<number>
describe la coordenada y del vector que denota el eje de rotación. -
z
Es un<number>
describe la coordenada z del vector que denota el eje de rotación. -
a
Es un<angle>
representa el ángulo de rotación. Un ángulo positivo denota una rotación en sentido horario, un ángulo negativo en sentido contrario a las agujas del reloj.
Como en :
.will-distort{
transform:rotate3d(10, 10, 10, 45deg);
}
rotateX(50deg)
es equivalente a rotate3d(1, 0, 0, 50deg)
rotateY(20deg)
es equivalente a rotate3d(0, 1, 0, 20deg)
rotateZ(15deg)
es equivalente a rotate3d(0, 0, 1, 15deg)
Asi que...
rotateX(50deg) rotateY(20deg) rotateZ(15deg)
es equivalente a
rotate3d(1, 0, 0, 50deg) rotate3d(0, 1, 0, 20deg) rotate3d(0, 0, 1, 15deg)
Para un genérico rotate3d(x, y, z, α)
, tienes la matriz
dónde
Ahora obtienes las matrices para cada una de las 3 transformadas rotate3d
y las multiplicas. Y la matriz resultante es la matriz correspondiente al single rotate3d
resultante. No estoy seguro de qué fácil es extraer los valores para rotate3d
, pero es fácil extraerlos para una sola matrix3d
.
En el primer caso ( rotateX(50deg)
( rotateX(50deg)
o rotate3d(1, 0, 0, 50deg)
), tienes:
x = 1
, y = 0
, z = 0
, α = 50deg
Entonces, la primera fila de la matriz en este caso es 1 0 0 0
.
El segundo es 0 cos(50deg) -sin(50deg) 0
.
El tercero 0 sin(50deg) cos(50deg) 0
.
Y el cuarto es obviamente 0 0 0 1
.
En el segundo caso, tiene x = 0
, y = 1
, z = 0
, α = 20deg
.
Primera fila: cos(20deg) 0 sin(20deg) 0
.
Segunda fila: 0 1 0 0
.
Tercera fila: -sin(20) 0 cos(20deg) 0
.
Cuarto: 0 0 0 1
En el tercer caso, tienes x = 0
, y = 0
, z = 1
, α = 15deg
.
Primera fila: cos(15deg) -sin(15deg) 0 0
.
Segunda fila sin(15deg) cos(15deg) 0 0
.
Y la tercera y la cuarta fila son 0 0 1 0
y 0 0 0 1
respectivamente.
Nota : es posible que haya notado que los signos de los valores de sin para la transformación rotateY son diferentes a los de las otras dos transformaciones. No es un error de cálculo. La razón de esto es que, para la pantalla, tiene el eje y apuntando hacia abajo, no hacia arriba.
Entonces, estas son las tres matrices 4x4
que necesitas multiplicar para obtener la matriz 4x4
para la transformación single rotate3d
resultante. Como ya he dicho, no estoy seguro de lo fácil que puede ser sacar los 4 valores, pero los 16 elementos en la matriz 4x4 son exactamente los 16 parámetros del equivalente matrix3d
de la transformación encadenada.
EDITAR :
En realidad, resulta que es bastante fácil ... Calcula la traza (suma de elementos diagonales) de la matriz para la matriz rotate3d
.
4 - 2*2*(1 - cos(α))/2 = 4 - 2*(1 - cos(α)) = 2 + 2*cos(α)
Luego calcula la traza para el producto de las tres matrices 4x4
, iguala el resultado con 2 + 2*cos(α)
extrae α
. Luego calcula x
, y
, z
.
En este caso particular, si calculé correctamente, el rastro de la matriz resultante del producto de las tres matrices 4x4
será:
T =
cos(20deg)*cos(15deg) +
cos(50deg)*cos(15deg) - sin(50deg)*sin(20deg)*cos(15deg) +
cos(50deg)*cos(20deg) +
1
Entonces cos(α) = (T - 2)/2 = T/2 - 1
, lo que significa que α = acos(T/2 - 1)
.