Estoy trabajando en la creación de una rotación compatible con varios navegadores (ie9 +) y tengo el siguiente código en un jsfiddle
$(document).ready(function () {
DoRotate(30);
AnimateRotate(30);
});
function DoRotate(d) {
$("#MyDiv1").css({
'-moz-transform':'rotate('+d+'deg)',
'-webkit-transform':'rotate('+d+'deg)',
'-o-transform':'rotate('+d+'deg)',
'-ms-transform':'rotate('+d+'deg)',
'transform': 'rotate('+d+'deg)'
});
}
function AnimateRotate(d) {
$("#MyDiv2").animate({
'-moz-transform':'rotate('+d+'deg)',
'-webkit-transform':'rotate('+d+'deg)',
'-o-transform':'rotate('+d+'deg)',
'-ms-transform':'rotate('+d+'deg)',
'transform':'rotate('+d+'deg)'
}, 1000);
}
El CSS y HTML son realmente simples y solo para demostración:
.SomeDiv{
width:50px;
height:50px;
margin:50px 50px;
background-color: red;}
<div id="MyDiv1" class="SomeDiv">test</div>
<div id="MyDiv2" class="SomeDiv">test</div>
La rotación funciona cuando se usa .css()
pero no cuando se usa .animate()
; ¿Por qué es así y hay alguna manera de solucionarlo?
Gracias.
jquery
css
rotation
jquery-animate
Frenchie
fuente
fuente
step
devolución de llamada), pero la parte de "por qué es eso" es bastante clara.Respuestas:
Las transformaciones CSS no son posibles de animar con jQuery, todavía. Puedes hacer algo como esto:
function AnimateRotate(angle) { // caching the object for performance reasons var $elem = $('#MyDiv2'); // we use a pseudo object for the animation // (starts from `0` to `angle`), you can name it as you want $({deg: 0}).animate({deg: angle}, { duration: 2000, step: function(now) { // in the step-callback (that is fired each step of the animation), // you can use the `now` paramter which contains the current // animation-position (`0` up to `angle`) $elem.css({ transform: 'rotate(' + now + 'deg)' }); } }); }
Puede leer más sobre la devolución de llamada por pasos aquí: http://api.jquery.com/animate/#step
http://jsfiddle.net/UB2XR/23/
Y, por cierto: no necesita prefijar las transformaciones css3 con jQuery 1.7+
Actualizar
Puede envolver esto en un jQuery-plugin para hacer su vida un poco más fácil:
$.fn.animateRotate = function(angle, duration, easing, complete) { return this.each(function() { var $elem = $(this); $({deg: 0}).animate({deg: angle}, { duration: duration, easing: easing, step: function(now) { $elem.css({ transform: 'rotate(' + now + 'deg)' }); }, complete: complete || $.noop }); }); }; $('#MyDiv2').animateRotate(90);
http://jsbin.com/ofagog/2/edit
Actualización2
Optimicé un poco para hacer que el orden de
easing
,duration
ycomplete
insignificante.$.fn.animateRotate = function(angle, duration, easing, complete) { var args = $.speed(duration, easing, complete); var step = args.step; return this.each(function(i, e) { args.complete = $.proxy(args.complete, e); args.step = function(now) { $.style(e, 'transform', 'rotate(' + now + 'deg)'); if (step) return step.apply(e, arguments); }; $({deg: 0}).animate({deg: angle}, args); }); };
Actualización 2.1
Gracias a matteo que notó un problema con el
this
-contexto en el completo-callback
. Si se soluciona vinculando la devolución de llamada conjQuery.proxy
en cada nodo.He agregado la edición al código antes de la Actualización 2 .
Actualización 2.2
Esta es una posible modificación si desea hacer algo como alternar la rotación hacia adelante y hacia atrás. Simplemente agregué un parámetro de inicio a la función y reemplacé esta línea:
$({deg: start}).animate({deg: angle}, args);
Si alguien sabe cómo hacer que esto sea más genérico para todos los casos de uso, ya sea que desee establecer un grado de inicio o no, realice la edición adecuada.
El uso ... ¡es bastante simple!
Básicamente, tiene dos formas de alcanzar el resultado deseado. Pero al principio, echemos un vistazo a los argumentos:
jQuery.fn.animateRotate(angle, duration, easing, complete)
Excepto por "ángulo", todos son opcionales y recurren a las
jQuery.fn.animate
propiedades predeterminadas :duration: 400 easing: "swing" complete: function () {}
Primero
Esta es la forma corta, pero parece un poco confusa cuantos más argumentos pasamos.
$(node).animateRotate(90); $(node).animateRotate(90, function () {}); $(node).animateRotate(90, 1337, 'linear', function () {});
2do
Prefiero usar objetos si hay más de tres argumentos, por lo que esta sintaxis es mi favorita:
$(node).animateRotate(90, { duration: 1337, easing: 'linear', complete: function () {}, step: function () {} });
fuente
this
que no se refiere a un objeto DOM es porque el contexto se establece en el objeto al queanimate()
se llamó, en este caso{deg: 0}
se establece en el contexto. Puede solucionar esto cambiando el contexto de cada función de devolución de llamada conapply()
/call()
o$.proxy()
(como ha mostrado @yckart). Aquí está mi solución para arreglar TODAS las devoluciones de llamada y permitir la rotación 3d: jsfiddle.net/TrevinAvery/P5J4V/440
grados cada vez no conducirá al comportamiento esperado, por lo que debe inicializar con el valor de rotación actual. Cómo hacerlo se explica aquí: stackoverflow.com/a/11840120/61818¡Gracias yckart! Gran aporte. Desarrollé un poco más tu complemento. Se agregó startAngle para un control total y CSS entre navegadores.
$.fn.animateRotate = function(startAngle, endAngle, duration, easing, complete){ return this.each(function(){ var elem = $(this); $({deg: startAngle}).animate({deg: endAngle}, { duration: duration, easing: easing, step: function(now){ elem.css({ '-moz-transform':'rotate('+now+'deg)', '-webkit-transform':'rotate('+now+'deg)', '-o-transform':'rotate('+now+'deg)', '-ms-transform':'rotate('+now+'deg)', 'transform':'rotate('+now+'deg)' }); }, complete: complete || $.noop }); }); };
fuente
jquery-1.8+
!El tránsito de jQuery probablemente hará su vida más fácil si está tratando con animaciones CSS3 a través de jQuery.
EDITAR Marzo de 2014 (porque mi consejo ha sido votado constantemente desde que lo publiqué)
Permítanme explicar por qué inicialmente estaba insinuando el complemento anterior:
Actualizar
DOM
en cada paso (es decir$.animate
) no es ideal en términos de rendimiento. Funciona, pero probablemente sea más lento que las transiciones CSS3 puras o las animaciones CSS3 .Esto se debe principalmente a que el navegador tiene la oportunidad de pensar en el futuro si usted indica cómo se verá la transición de principio a fin.
Para hacerlo, puede, por ejemplo, crear una clase CSS para cada estado de la transición y solo usar jQuery para alternar el estado de la animación.
Esto generalmente es bastante bueno, ya que puede modificar sus animaciones junto con el resto de su CSS en lugar de mezclarlo con su lógica comercial:
// initial state .eye { -webkit-transform: rotate(45deg); -moz-transform: rotate(45deg); transform: rotate(45deg); // etc. // transition settings -webkit-transition: -webkit-transform 1s linear 0.2s; -moz-transition: -moz-transform 1s linear 0.2s; transition: transform 1s linear 0.2s; // etc. } // open state .eye.open { transform: rotate(90deg); } // Javascript $('.eye').on('click', function () { $(this).addClass('open'); });
Si alguno de los parámetros de transformación es dinámico, por supuesto, puede usar el atributo de estilo en su lugar:
$('.eye').on('click', function () { $(this).css({ -webkit-transition: '-webkit-transform 1s ease-in', -moz-transition: '-moz-transform 1s ease-in', // ... // note that jQuery will vendor prefix the transform property automatically transform: 'rotate(' + (Math.random()*45+45).toFixed(3) + 'deg)' }); });
Mucha más información detallada sobre las transiciones CSS3 en MDN .
SIN EMBARGO, hay algunas otras cosas a tener en cuenta y todo esto puede volverse un poco complicado si tiene animaciones complejas, encadenamiento, etc. y jQuery Transit solo hace todas las partes complicadas debajo del capó:
$('.eye').transit({ rotate: '90deg'}); // easy huh ?
fuente
Para hacer este navegador cruzado, incluido IE7 +, deberá expandir el complemento con una matriz de transformación. Dado que el prefijo del proveedor se realiza en jQuery desde jquery-1.8 +, dejaré eso para la
transform
propiedad.$.fn.animateRotate = function(endAngle, options, startAngle) { return this.each(function() { var elem = $(this), rad, costheta, sintheta, matrixValues, noTransform = !('transform' in this.style || 'webkitTransform' in this.style || 'msTransform' in this.style || 'mozTransform' in this.style || 'oTransform' in this.style), anims = {}, animsEnd = {}; if(typeof options !== 'object') { options = {}; } else if(typeof options.extra === 'object') { anims = options.extra; animsEnd = options.extra; } anims.deg = startAngle; animsEnd.deg = endAngle; options.step = function(now, fx) { if(fx.prop === 'deg') { if(noTransform) { rad = now * (Math.PI * 2 / 360); costheta = Math.cos(rad); sintheta = Math.sin(rad); matrixValues = 'M11=' + costheta + ', M12=-'+ sintheta +', M21='+ sintheta +', M22='+ costheta; $('body').append('Test ' + matrixValues + '<br />'); elem.css({ 'filter': 'progid:DXImageTransform.Microsoft.Matrix(sizingMethod=\'auto expand\','+matrixValues+')', '-ms-filter': 'progid:DXImageTransform.Microsoft.Matrix(sizingMethod=\'auto expand\','+matrixValues+')' }); } else { elem.css({ //webkitTransform: 'rotate('+now+'deg)', //mozTransform: 'rotate('+now+'deg)', //msTransform: 'rotate('+now+'deg)', //oTransform: 'rotate('+now+'deg)', transform: 'rotate('+now+'deg)' }); } } }; if(startAngle) { $(anims).animate(animsEnd, options); } else { elem.animate(animsEnd, options); } }); };
Nota: Los parámetros
options
ystartAngle
son opcionales, si solo necesita configurarstartAngle
use{}
onull
foroptions
.Uso de ejemplo:
var obj = $(document.createElement('div')); obj.on("click", function(){ obj.stop().animateRotate(180, { duration: 250, complete: function() { obj.animateRotate(0, { duration: 250 }); } }); }); obj.text('Click me!'); obj.css({cursor: 'pointer', position: 'absolute'}); $('body').append(obj);
Vea también este jsfiddle para una demostración.
Actualización : ahora también puede pasar
extra: {}
las opciones. Esto le permitirá ejecutar otras animaciones simultáneamente. Por ejemplo:obj.animateRotate(90, {extra: {marginLeft: '100px', opacity: 0.5}});
Esto rotará el elemento 90 grados y lo moverá hacia la derecha con 100px y lo hará semitransparente todo al mismo tiempo durante la animación.
fuente
ms
,o
,webkit
,moz
para garantizar una detección correcta. El violín también se actualiza a v12.esta es mi solución:
var matrixRegex = /(?:matrix\(|\s*,\s*)([-+]?[0-9]*\.?[0-9]+(?:[e][-+]?[0-9]+)?)/gi; var getMatches = function(string, regex) { regex || (regex = matrixRegex); var matches = []; var match; while (match = regex.exec(string)) { matches.push(match[1]); } return matches; }; $.cssHooks['rotation'] = { get: function(elem) { var $elem = $(elem); var matrix = getMatches($elem.css('transform')); if (matrix.length != 6) { return 0; } return Math.atan2(parseFloat(matrix[1]), parseFloat(matrix[0])) * (180/Math.PI); }, set: function(elem, val){ var $elem = $(elem); var deg = parseFloat(val); if (!isNaN(deg)) { $elem.css({ transform: 'rotate(' + deg + 'deg)' }); } } }; $.cssNumber.rotation = true; $.fx.step.rotation = function(fx) { $.cssHooks.rotation.set(fx.elem, fx.now + fx.unit); };
entonces puedes usarlo en el fkt animado predeterminado:
//rotate to 90 deg cw $('selector').animate({ rotation: 90 }); //rotate to -90 deg ccw $('selector').animate({ rotation: -90 }); //rotate 90 deg cw from current rotation $('selector').animate({ rotation: '+=90' }); //rotate 90 deg ccw from current rotation $('selector').animate({ rotation: '-=90' });
fuente
Otra respuesta, porque jQuery.transit no es compatible con jQuery.easing. Esta solución viene como una extensión de jQuery. Es más genérico, la rotación es un caso específico:
$.fn.extend({ animateStep: function(options) { return this.each(function() { var elementOptions = $.extend({}, options, {step: options.step.bind($(this))}); $({x: options.from}).animate({x: options.to}, elementOptions); }); }, rotate: function(value) { return this.css("transform", "rotate(" + value + "deg)"); } });
El uso es tan simple como:
$(element).animateStep({from: 0, to: 90, step: $.fn.rotate});
fuente
Sin plugin de navegador cruzado con setInterval:
function rotatePic() { jQuery({deg: 0}).animate( {deg: 360}, {duration: 3000, easing : 'linear', step: function(now, fx){ jQuery("#id").css({ '-moz-transform':'rotate('+now+'deg)', '-webkit-transform':'rotate('+now+'deg)', '-o-transform':'rotate('+now+'deg)', '-ms-transform':'rotate('+now+'deg)', 'transform':'rotate('+now+'deg)' }); } }); } var sec = 3; rotatePic(); var timerInterval = setInterval(function() { rotatePic(); sec+=3; if (sec > 30) { clearInterval(timerInterval); } }, 3000);
fuente