1

I have an animation linked to scroll position. Whenever the the user scrolls up or down, an animation is triggered for that position to move an element within the view window. If the user scrolls farther, these animations need to queue so that the element moves smoothly along the path.

var target = getAnimation();
var props = {
    left: [target.x, target.easing],
    top: target.y
};

$("#ball").animate(props, 400, "easeInOutQuad");

The problem with this is that when multiple animations get queued, the ball slows and speeds up in a bad way. What I'd like to do is something like this:

var target = getAnimation();
var props = {
    left: [target.x, target.easing],
    top: target.y
};

var ball = $("#ball"), queue = ball.queue();

if(ball.queue().length) {
    for(var i = 1, len = queue.length; i < len; i++) {
        //modify all the other queued animations to use linear easing
    }
    ball.animate(props, 400, "easeOutQuad");
}
else {
    ball.animate(props, 400, "easeInQuad");
}

By starting with an easeIn function, using linear in the middle, and easeOut at the end, I get a much smoother animation. Is there anyway I can access and modify the animations in the queue?

Edit:

Here is a fiddle to demonstrate what I'm trying to achieve: https://jsfiddle.net/reesewill/mtepvguw/

In the fiddle, I am using linear easing, but I'd really like the general affect to be more like easeInOutQuad. However, because I allow queueing, I can't just apply that easing function without it messing up the whole effect (change the linear to easeInOutQuad and click queue a few times quickly to see). Thus, I need something like the above to create the general impression of easeInOutQuad.

5
  • Do you have any fiddle to recreate the problem? Commented Mar 18, 2015 at 4:03
  • why not just stop() ? jsfiddle.net/mtepvguw/4 Commented Mar 18, 2015 at 5:08
  • Stop changes the flight trajectory. In my real world application, this is unacceptable. Commented Mar 18, 2015 at 5:13
  • I think you can add new animation to the queue using animate() and just replace needed element with last one in array returned by queue(), than remove last element, something like: box.animate(newArgs); var queue=box.queue(); queue[2]=queue.pop(); Commented Mar 18, 2015 at 5:19
  • You are right, this manipulating the queue this way can get me what I want, but it adds a huge layer of complexity to figure out what's in the queue and rebuild it all from scratch. I'd prefer to modify the data, not just discard it. Commented Mar 19, 2015 at 8:16

2 Answers 2

0
+50

Note , $(selector).queue() returns a reference to the animation queue, an Array. This reference can be modified with standard array methods. See also .dequeue() .

Try utilizing

Array.prototype.splice()

Summary

The splice() method changes the content of an array by removing existing elements and/or adding new elements.

Syntax

array.splice(start, deleteCount[, item1[, item2[, ...]]]) Parameters

start

Index at which to start changing the array. If greater than the length of the array, actual starting index will be set to the length of the array. If negative, will begin that many elements from the end.

deleteCount

An integer indicating the number of old array elements to remove. If deleteCount is 0, no elements are removed. In this case, you should specify at least one new element. If deleteCount is greater than the number of elements left in the array starting at start, then all of the elements through the end of the array will be deleted.

itemN

The element to add to the array. If you don't specify any elements, splice() will only remove elements from the array.

Returns

An array containing the deleted elements. If only one element is removed, an array of one element is returned. If no elements are removed, an empty array is returned.

See also Array.prototype.concat()


var elem = $("body")
, msg = function() {
    return "<br />" 
           + "queue length:" 
           + $(this).queue("abc").length
  };

elem.queue("abc", [
  function(next) {
    $(this).append(msg.call(this));
    next()
  },
  function(next) {
    $(this).append(msg.call(this));
    next()
  },
  function(next) {
    $(this).append(msg.call(this));
    next()
  }
]);

elem.append(msg.call(elem));

// do stuff, 
// replace `function` within `abc` queue,
// change `easing` options within replacement function 
elem.queue("abc").splice(1, 1, function(next) {
  $(this).append("<br />" 
                 + "`function` at index `1` within `abc` queue " 
                 + "replaced with new `function`" 
                 + msg.call(this));
  next()
});

elem.append("<br />" 
            + "after `.splice()` , before `.concat()`" 
            + msg.call(elem));
// do stuff,
// `concat` functions onto `abc` queue`
var arr = elem.queue("abc").concat(
  function(next) {
    $(this).append(msg.call(this));
    next()
  }, function(next) {
    $(this).append(msg.call(this));
    next()
  }, function() {
    $(this).append(msg.call(this) 
                   + "<br />" 
                   + "done");
  }
);

elem.queue("abc", arr);

elem.append("<br />" 
            + "after `.concat()`"
            + msg.call(elem));

elem.dequeue("abc");
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js">
</script>

Sign up to request clarification or add additional context in comments.

Comments

0

i tried, you can do it with create new (re-ordered) queue

download source http://api.jquery.com/queue/
Example: Set a queue array to delete the queue.

and replace start event with my, its worked.

But functions in queue are stored in array of functions. You need to know order of original queue of animations which you want to changed :( Or you can create new optimalized queue.

$( "#start" ).click(function() {
  $( "div" )
    .show( "slow" )
    .animate({ left: "+=50" }, 5000 )
    .animate({ top: "+=50" }, 5000 )
    .queue(function() {
      $( this ).addClass( "newcolor" ).dequeue();
    })
    .animate({ left: '-=50' }, 1500 )
    .queue(function() {
      $( this ).removeClass( "newcolor" ).dequeue();
    })
    .slideUp();


    // get current queue
    var currQueue = $( "div" ).queue( "fx");

    // create new queue and change order or add/remove animations
    var newQueue = [];
      newQueue.push(currQueue[1]);
      newQueue.push(currQueue[3]); // changed
      newQueue.push(currQueue[2]); // changed
      newQueue.push(currQueue[5]);

    // set new queue to element
    $("div").queue("fx", newQueue);

    console.log($("div").queue("fx"));
}); 

more info found in jquery documentation

.queue( [queueName ], newQueue )
Description: Manipulate the queue of functions to be executed, once for each matched element.

important is second parameter newQueue

i hope it helps

3 Comments

Changing the order of the queue isn't really that useful if you are moving an object along a path. I need to change the easing function for currQueue[3], currQueue[2], etc.
@Will Reese i think it is easy. You can setup new functions into new array like in documentation example with .queue(function(....
see my comment on the original question. I'd prefer to not discard all the information in the queue.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.