[jquery] jQuery: how do I animate a div rotation?

I can rotate a div with css, and jquery .rotate, but i don't know how to animate it.

This question is related to jquery

The answer is


If you're designing for an iOS device or just webkit, you can do it with no JS whatsoever:

CSS:

@-webkit-keyframes spin {  
from {  
    -webkit-transform: rotate(0deg);  
}  
to {  
    -webkit-transform: rotate(360deg);  
    } 
}

.wheel {
    width:40px;
    height:40px;
    background:url(wheel.png);
    -webkit-animation-name: spin; 
    -webkit-animation-iteration-count: infinite; 
    -webkit-animation-timing-function: linear;
    -webkit-animation-duration: 3s; 
}

This would trigger the animation on load. If you wanted to trigger it on hover, it might look like this:

.wheel {
    width:40px;
    height:40px;
    background:url(wheel.png);
}

.wheel:hover {
    -webkit-animation-name: spin; 
    -webkit-animation-iteration-count: infinite; 
    -webkit-animation-timing-function: ease-in-out;
    -webkit-animation-duration: 3s; 
}

I've been using

_x000D_
_x000D_
$.fn.rotate = function(degrees, step, current) {_x000D_
    var self = $(this);_x000D_
    current = current || 0;_x000D_
    step = step || 5;_x000D_
    current += step;_x000D_
    self.css({_x000D_
        '-webkit-transform' : 'rotate(' + current + 'deg)',_x000D_
        '-moz-transform' : 'rotate(' + current + 'deg)',_x000D_
        '-ms-transform' : 'rotate(' + current + 'deg)',_x000D_
        'transform' : 'rotate(' + current + 'deg)'_x000D_
    });_x000D_
    if (current != degrees) {_x000D_
        setTimeout(function() {_x000D_
            self.rotate(degrees, step, current);_x000D_
        }, 5);_x000D_
    }_x000D_
};_x000D_
_x000D_
$(".r90").click(function() { $("span").rotate(90) });_x000D_
$(".r0").click(function() { $("span").rotate(0, -5, 90) });
_x000D_
span { display: inline-block }
_x000D_
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>_x000D_
<span>potato</span>_x000D_
_x000D_
<button class="r90">90 degrees</button>_x000D_
<button class="r0">0 degrees</button>
_x000D_
_x000D_
_x000D_


This works for me:

function animateRotate (object,fromDeg,toDeg,duration){
    var dummy = $('<span style="margin-left:'+fromDeg+'px;">')
    $(dummy).animate({
        "margin-left":toDeg+"px"
    },{
        duration:duration,
        step: function(now,fx){
            $(object).css('transform','rotate(' + now + 'deg)');
        }
    });
};

Based on Peter Ajtai answer, here is a small jquery plugin that may help others. I didn't test on Opera and IE9 but is should work on these browsers too.

$.fn.rotate = function(until, step, initial, elt) {
    var _until = (!until)?360:until;
    var _step = (!step)?1:step;
    var _initial = (!initial)?0:initial;
    var _elt = (!elt)?$(this):elt;

    var deg = _initial + _step;

    var browser_prefixes = ['-webkit', '-moz', '-o', '-ms'];
    for (var i=0, l=browser_prefixes.length; i<l; i++) {
      var pfx = browser_prefixes[i]; 
      _elt.css(pfx+'-transform', 'rotate('+deg+'deg)');
    }

    if (deg < _until) {
      setTimeout(function() {
          $(this).rotate(_until, _step, deg, _elt); //recursive call
      }, 5);
    }
};

$('.my-elt').rotate()

I needed to rotate an object but have a call back function. Inspired by John Kern's answer I created this.

function animateRotate (object,fromDeg,toDeg,duration,callback){
        var dummy = $('<span style="margin-left:'+fromDeg+'px;">')
        $(dummy).animate({
            "margin-left":toDeg+"px"
        },
        {
            duration:duration,
            step: function(now,fx){
                $(object).css('transform','rotate(' + now + 'deg)');
                if(now == toDeg){
                    if(typeof callback == "function"){
                        callback();
                    }
                }
            }
        }
    )};

Doing this you can simply call the rotate on the object like so... (in my case I'm doing it on a disclosure triangle icon that has already been rotated by default to 270 degress and I'm rotating it another 90 degrees to 360 degrees at 1000 milliseconds. The final argument is the callback after the animation has finished.

animateRotate($(".disclosure_icon"),270,360,1000,function(){
                alert('finished rotate');
            });

If you want just a jQuery option, this will work:

$(el).stop().animate(
  {rotation: 360},
  {
    duration: 500,
    step: function(now, fx) {
      $(this).css({"transform": "rotate("+now+"deg)"});
    }
  }
);

This works with jQuery 1.8, which takes care of CSS prefixing automatically. jQuery doesn't animate rotation so I'm putting the transform:rotate() in the custom step function. It might only work starting from 0.

Demo: http://jsfiddle.net/forresto/ShUgD/

IE9 and Mobile Safari 4 support CSS transforms but not CSS transitions, so I came up with this simple shim, using Modernizr feature testing:

if (Modernizr.csstransitions) {
  $(el).css({
    "transition": "all 500ms ease-in-out"
  });
}

$(el).click(function(){
  var rotateTo = 360;
  if (Modernizr.csstransitions) {
    $(el).css({"transform": "rotate("+rotateTo+"deg)"});
  } else {
    $(el).stop().animate(
      {rotation: rotateTo},
      {
        duration: 500,
        step: function(now, fx) {
          $(this).css({"transform": "rotate("+now+"deg)"});
        }
      }
    );
  }
});

The above will use CSS transitions when available.


As of now you still can't animate rotations with jQuery, but you can with CSS3 animations, then simply add and remove the class with jQuery to make the animation occur.

JSFiddle demo


HTML

<img src="http://puu.sh/csDxF/2246d616d8.png" width="30" height="30"/>

CSS3

img {
-webkit-transform: rotate(-90deg);
-moz-transform: rotate(-90deg);
-o-transform: rotate(-90deg);
-ms-transform: rotate(-90deg);
transform: rotate(-90deg);
transition-duration:0.4s;
}

.rotate {
-webkit-transform: rotate(0deg);
-moz-transform: rotate(0deg);
-o-transform: rotate(0deg);
-ms-transform: rotate(0deg);
transform: rotate(0deg);
transition-duration:0.4s;
}

jQuery

$(document).ready(function() {
    $("img").mouseenter(function() {
        $(this).addClass("rotate");
    });
    $("img").mouseleave(function() {
        $(this).removeClass("rotate");
    });
});