1
votes

( JSFIDDLE provided.. )

GOAL :

  • Rotate an element constantly for 3 seconds and then stop
  • Once the rotation has stopped, rotate the element to 175 degrees. Animate the rotation starting from its current angle (whatever that angle was when the constant rotation was stopped)

PROBLEM #1

On Chrome, after the constant rotation has been stopped, the element is rotated to 175 degrees but without any animation. I'm trying to reset the animation (that I paused in order to stop the constant rotation) but nothing seems to be working.

PROBLEM #2

On Safari, after the constant rotation has been stopped, the element's angle is reset to 0 degrees (by itself) and then it's rotated to 175 degrees with animation.

So in both cases, the sequence of events does not work as expected. Can you see what I'm doing wrong ?

Do you have a cross-browser checked solution that includes IE10+ ?

Please check this JSFIDDLE to see the below code in action

CSS :

span {
   position:absolute;
   top: 10px;
   left: 10px; 
}

div {
    position:absolute;
    top: 100px;
    left: 100px;
    height: 100px;
    width: 100px;
    background-color: black;
    border-top: 10px solid blue;
    border-bottom: 10px solid red;
    border-left: 10px solid green;
    border-right: 10px solid yellow;
}

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

HTML :

<span></span>
<div></div>

JAVASCRIPT :

/* This function returns the element's current degrees at any given time */
var currentDegreesFor = function($element) {
    var matrix = $element.css("-webkit-transform") ||
        $element.css("-moz-transform") ||
        $element.css("-ms-transform") ||
        $element.css("-o-transform") ||
        $element.css("transform");

    if (matrix !== 'none') {
        var values = matrix.split('(')[1].split(')')[0].split(',');
        var a = values[0];
        var b = values[1];
        var angle = Math.round(Math.atan2(b, a) * (180 / Math.PI));
    } else {
        var angle = 0;
    }

    return (angle < 0) ? angle += 360 : angle;
};

var $element = $('div');

// INITIALIZING CONSTANT ROTATION
$('span').text('rotating constantly');
$element.css({
    "-webkit-animation": "constantrotate infinite 5s linear",
    "animation": "constantrotate infinite 5s linear"
});

// AFTER 3 SECONDS
setTimeout(function() {
    // STOP CONTSTANT ROTATION
    $element.css({
        'animation-play-state': 'paused',
        '-webkit-animation-play-state': 'paused'
    });

    // get element's current degrees
    var degrees = currentDegreesFor($element);

    $('span').text('constant rotation stopped at ' + degrees +
        ' degrees');

    // AFTER 3 SECONDS
    setTimeout(function() {
        /* This animation has now stopped at X degrees
        However the element's current rotation isn't 
        set to X degrees explicitly with a CSS rule.
        Apparently, I need to add that rule myself if I want to 
        further rotate the element */
        $element.css({
            'transform': 'rotate(' + degrees + 'deg)',
            '-webkit-transform': 'rotate(' + degrees + 'deg)'
        });

        $('span').text('CSS tranform: rotate() set to ' + degrees +
            ' degrees');

        // AFTER 3 SECONDS
        setTimeout(function() {
            $('span').text('rotating to 175 degrees with animation');

            /* I'm now resetting the animation from 
            "constantrotate" to "transition". The element is
            rotated but with no animation (at least none on Chrome - on Safari the element's angle 
            is set back to 0 before this animation begins). What am I doing wrong ?
            */
            $element.css({
                '-webkit-animation': '-webkit-transition',
                'animation': 'transition',
                'transition': 'transform 10s ease-in',
                '-webkit-transition': '-webkit-transform 10s ease-in',
                'transform': 'rotate(175deg)',
                '-webkit-transform': 'rotate(175deg)'
            });
        }, 3000);
    }, 3000);
}, 4000);
1
Could you please elaborate a bit more ? You can try your suggestion on the JSFiddle I've provided (Chrome & Safari if you like) to see if it works actually. - Sprout Coder
by itself it wont work. You will need to: 1. after pausing animation and knowing the stoping angle, set the css to animation:none, transition:transform 5s, and transform: rotate( currentAngle deg) 2. then wait a bit and set transform: rotate(175deg) - Tiago Coelho
Why do I need to "wait a bit" ? I think that must be the source of the problem for both browsers actually. It seems that when it comes to animations the CSS styles are not applied immediately. Why is that? This would make sense (taking a while for a new animation-related style to be applied) if the element was already being animated at the moment a new animate style is being applied to it (a conflict could possibly be generated in that case). However, in my case I'm waiting for the current animation (the constant one) to be completed before applying the new one (rotate to 175deg). - Sprout Coder
the waiting a bit in this case is needed because you need to have transition set, before changing the property that transition animates(transform in this case) - Tiago Coelho

1 Answers

-1
votes

A better Approach:

Mixing keyframed animation and transitions is unreliable and behaves differently across browsers... so I suggest using

requestAnimationFrame

see it working here: http://jsfiddle.net/mc3v6xsw/5/

and check the documentation here: https://developer.mozilla.org/en-US/docs/Web/API/window.requestAnimationFrame

this works in chrome,safari,firefox and ie10

function constantRotation(timestamp){
    if(startTime==null)
        startTime=timestamp;
    var delta = timestamp-startTime;
    degrees = (360/fullRotationTime)*delta;
    $element.css({
             'transform': 'rotate(' + degrees + 'deg)',
             '-webkit-transform': 'rotate(' + degrees + 'deg)'        
    });
    rotationAnimation=window.requestAnimationFrame(constantRotation);
}
var rotationAnimation=window.requestAnimationFrame(constantRotation);

and you can stop it with

cancelAnimationFrame(rotationAnimation);

First attempt:

this works on chrome: http://jsfiddle.net/p08L6ndo/

What i did: after pausing:

 $element.css({
     'transform': 'rotate(' + degrees + 'deg)',
     '-webkit-transform': 'rotate(' + degrees + 'deg)',
     'animation':'none',
     'transition':'transform 2s'
 });

and after another 3 seconds:

 $element.css({
     '-webkit-transform': 'rotate(175deg)',
     'transform':'rotate(175deg)'
 });