woshitom
woshitom

Reputation: 5129

lag between jquery animation and css animation

I'm stacking 5 images by attributing to all of them an absolute position with the same top and left coordinates and a different z-index.

My goal is to rotate, translate and turn to 0 the opacity of the image having the highest z-index and increasing by 1 the z-index of all the other images. I'm animating the image having the highest index with CSS transfomations and I change the z-index of the other images with jquery. My code is the following:

var i = 1;

function swypeStyle(){
  var imageLength = $('.my-image').length;

  $('.my-image').each(function(){
    $(this).removeClass('rotated');
  });

  $("#image"+i).addClass('rotated'); 

  setTimeout(function(){
    for(var j = 1; j <= imageLength; j++){

      var currentZindex = $('#image'+j).css('z-index');

      if(currentZindex == imageLength){
        currentZindex = 1;
      }else{
        currentZindex++;
      }

      $('#image'+j).css('z-index',currentZindex);
    }
  }, 1100);


  if(i == imageLength){
    i = 1;
  }else{
    i++;
  }
}

window.setInterval(function () {
	swypeStyle(); 
}, 3000);
.my-image{
  width: 144px;
	left: 0px;
  top: 0px;
  position: absolute;
}

.my-image.rotated {
	left: -150px;
	top: 25px; 
	-webkit-transform: rotate(-30deg);
	opacity: 0;
	-webkit-transition: all 1s ease-in-out;
}
<img src="https://www.otop.sg/retailer/images/image1.jpg" class="my-image" id="image1" style="z-index: 5;">
<img src="https://www.otop.sg/retailer/images/image2.jpg" class="my-image" id="image2" style="z-index: 4;">
<img src="https://www.otop.sg/retailer/images/image3.jpg" class="my-image" id="image3" style="z-index: 3;">
<img src="https://www.otop.sg/retailer/images/image4.jpg" class="my-image" id="image4" style="z-index: 2;">
<img src="https://www.otop.sg/retailer/images/image5.jpg" class="my-image" id="image5" style="z-index: 1;">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

My animation works well, the problem is when I switch and spend some time on an other chrome tab and when I go back on my script chrome tab there's a lag between my css animation and my jquery animation.

Upvotes: 0

Views: 104

Answers (3)

soulofmischief
soulofmischief

Reputation: 68

If you really can't give up your jQuery animations, you could try wrapping your animations in a requestAnimationFrame() loop. As MDN explains:

Like CSS transitions and animations, requestAnimationFrame() pauses when the current tab is pushed into the background.

Here is an example:

Usage:

// Get element.
const elem = document.querySelector( '#elementID' )
// Get current size.
const startSize = elem.width
// Set end size.
const endSize = startSize * 2 // Double the size of the element.
// Set animation duration.
const duration = 1000 // 1000ms -> 1s

animate( ratio => {
  setWidth( elem, lerp( startSize, endSize, ratio ))
}, duration )

Implementation:

// Resolves a promise once an animation is complete.
// Allows you to specify an animation duration, start and end values,
// and automatically handles frame interpolation.
function animate( callback, duration ) {
  return new Promise( resolve => {
    let
      // Amount of time in ms since last frame
      delta = 0,
      // Used to calculate delta
      lastTimestamp = 0,
      // Ratio for use in linear interpolation.
      // Passed through to the callback and incremented
      // with respect to duration.
      // The ratio determines how far along the start and end values we are.
      ratio = 0,
      // Speed is an inverse function of time, since ratio is normalized.
      speed = 1 / duration

    // Start the update loop
    update( performance.now())

    // Update loop
    function update( timestamp ) {
      if ( ratio < 1 ) {
        // Calculate frame delta and update last frame's timeStamp.
        // In the first frame, set lastFrame to this frame's timeStamp.
        delta = timestamp - ( lastTimestamp || timestamp )
        lastTimestamp = timestamp
        // Update ratio as a function of speed and frame delta
        ratio = clamp( ratio + ( speed * delta ))
        // Execute callback
        callback( ratio )
        // Request next frame
        requestAnimationFrame( update )
      }
      // Make good on the promise
      else resolve()
    }
  })
}

/** Linear interpolation between two scalars */
function lerp( min, max, t ) {
  /*
   * Get difference, multiply by `t` and add min.
   *
   * The ratio `t` represents the percentage of that distance
   * we add back to min, so that a fraction of 1 adds 100%
   * of the distance, which equals the max value.
   *
   * Precise form of linear interpolation,
   * ensures t=1 always equals max.
   */
  return ( 1 - t ) * min + t * max
}

// Set width of an element
function setWidth( element, width ) {
  element.style.width = `${ width }px` 
}

More about requestAnimationFrame()

Upvotes: 1

woshitom
woshitom

Reputation: 5129

I used css to do my animation because you can't animate rotation with the jQuery animate function.

Thanks to this post CSS rotation cross browser with jquery.animate() I found a work around and now my animation is 100% jQuery and there is no lag anymore.

var i = 1;

  function AnimateRotate(angle,elem) {
    $({deg: 0}).animate({deg: angle}, {
      duration: 700,
      step: function(now) {
        elem.css({
        transform: 'rotate(' + now + 'deg)'
      });
    }
    });
  }

function swypeStyle(){
  var imageLength = $('.my-image').length;

  $('.my-image').each(function(){
      $(this).css({
        "left": 0,
        "top": 0,
        "opacity": 1,
        WebkitTransform: 'rotate(0deg)',
        '-moz-transform': 'rotate(0deg)'
      })
    });

    AnimateRotate("-30",$("#image"+i));

    $("#image"+i).animate({
      "left": "-150px",
      "top": "25px",
      "opacity": 0
    },700); 

  setTimeout(function(){
    for(var j = 1; j <= imageLength; j++){

      var currentZindex = $('#image'+j).css('z-index');

      if(currentZindex == imageLength){
        currentZindex = 1;
      }else{
        currentZindex++;
      }

      $('#image'+j).css('z-index',currentZindex);
    }
  }, 1100);


  if(i == imageLength){
    i = 1;
  }else{
    i++;
  }
}

window.setInterval(function () {
	swypeStyle(); 
}, 3000);
.my-image{
	width: 144px;
	left: 0px;
	top: 0px;
	position: absolute;
}
<img src="https://www.otop.sg/retailer/images/image1.jpg" class="my-image" id="image1" style="z-index: 5;">
<img src="https://www.otop.sg/retailer/images/image2.jpg" class="my-image" id="image2" style="z-index: 4;">
<img src="https://www.otop.sg/retailer/images/image3.jpg" class="my-image" id="image3" style="z-index: 3;">
<img src="https://www.otop.sg/retailer/images/image4.jpg" class="my-image" id="image4" style="z-index: 2;">
<img src="https://www.otop.sg/retailer/images/image5.jpg" class="my-image" id="image5" style="z-index: 1;">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

Upvotes: 0

General_Twyckenham
General_Twyckenham

Reputation: 2261

The issue is that when your tab isn't active, Chrome will suspend items like animations, to reduce resource utilization.

My recommendation would be to do all of the transitions/animations in CSS only and use Javascript to only add/remove classes; this way the animations will remain synchronized.

Upvotes: 1

Related Questions