Can I implement a callback with each animation step in jQuery?

不问归期 提交于 2019-12-03 21:05:50

look at this article: http://james.padolsey.com/javascript/fun-with-jquerys-animate/

very clear, very easy!

All timers in JavaScript are based on the native plain old school JavaScript function setInterval() or setTimeout(). Even jQuery uses this internally.

The trick to synchronize timers, is making sure there is only one setInterval() is invoked, so build something ourselves.

An animation can be designed with:

  • have 10 steps, each with an interval of 30ms.
  • The total animation takes 300ms.
  • At each step, the current progress/percentage can be calculated:

    var percentage = ( currentStep / totalSteps );

Now, each time your function is called by setInterval(), you can set all DOM elements at once to the correct positions. To find out where an element should be at each animation frame, you use the:

var diff       = ( to - from );
var stepValue  = from + diff * percentage;

The jQuery easing functions can be called directly, and the final statement becomes:

var stepValue  = jQuery.easing[ easingMethod ]( percentage, 0, from, diff );

I've turned this into a class:

/**
 * Animation timeline, with a callback.
 */
function AnimationTimeline( params, onstep )
{
  // Copy values.

  // Required:
  this.from     = params.from || 0;         // e.g. 0%
  this.to       = params.to   || 1;         // e.g. 100%
  this.onstep   = onstep || params.onstep;  // pass the callback.

  // Optional
  this.steps    = params.steps    || 10;
  this.duration = params.duration || 300;
  this.easing   = params.easing   || "linear";

  // Internal
  this._diff  = 0;
  this._step  = 1;
  this._timer = 0;
}

jQuery.extend( AnimationTimeline.prototype, {

  start: function()
  {
    if( this.from == this.to )
      return;

    if( this._timer > 0 )
    {
      self.console && console.error("DOUBLE START!");
      return;
    }

    var myself  = this;    
    this._diff  = ( this.to - this.from );
    this._timer = setInterval( function() { myself.doStep() }, this.duration / this.steps );
  }

, stop: function()
  {
    clearInterval( this._timer );
    this._timer = -1;
    this._queue = [];
  }

, doStep: function()
  {
    // jQuery version of: stepValue = from + diff * percentage;
    var percentage = ( this._step / this.steps );
    var stepValue  = jQuery.easing[ this.easing ]( percentage, 0, this.from, this._diff );

    // Next step
    var props = { animationId: this._timer + 10
                , percentage: percentage
                , from: this.from, to: this.to
                , step: this._step, steps: this.steps
                };
    if( ++this._step > this.steps )
    {
      stepValue = this.to;  // avoid rounding errors.
      this.stop();
    }

    // Callback
    if( this.onstep( stepValue, props ) === false ) {
      this.stop();
    }
  }
});

And now you can use:

var el1 = $("#element1");
var el2 = $("#element2");

var animation = new AnimationTimeline( {
    easing: "swing"
  , onstep: function( stepValue, animprops )
    {
      // This is called for every animation frame. Set the elements:
      el1.css( { left: ..., top: ... } );
      el2.css( { left: ..., top: ... } );
    }
  });

// And start it.
animation.start();

Adding a pause/resume is an exercise for the reader.

A simple answer to do it. Maybe someone will search it as i did.

We can user the "step" attribute in the animation function.

$(obj).animate(
    {
        left: 0
    },
    {
        duration: 50,
        step: function( currentLeft ){
            console.log( "Left: ", currentLeft );
        }
    }
 );

So for each step, this will log the current left position

did you check jquery queue?

You can queue your animations and set a callback on each of them, I think if you play little bit with it you can achieve what you want.

Hope it helps, Sinan.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!