jQuery animate delay issues with self -queued looping of steps - javascript

I have a timeline definition which lists selectors and a list of delays and animations to apply to that object. You can specify that the steps for a particular object be looped.
Here is the function that's used to queue the animations:
function animateWithQueue(e, obj) {
if ($.queue(e[0]).length == 0) {
e.queue(function doNext(next) {
$.each(obj.steps, function(i, step) {
e.delay(step.pause).animate(step.anim, step.options);
});
if (obj.loop) {
e.queue(doNext);
}
next();
});
}
}​
Here is the timeline information
var timeline = {
'.square': {
loop: true,
steps: [
{ pause: 800, anim: { right: '+=200' }, options: { duration: 400} },
{ pause: 1000, anim: { right: '-=200' }, options: { duration: 400} }
]
},
'.circle': {
loop: true,
steps: [
{ pause: 1200, anim: { top: '+=200' }, options: { duration: 400} },
{ pause: 1200, anim: { top: '-=200' }, options: { duration: 400} }
]
}
};
And here is the function that puts the timeline into the above animate function:
$.each(timeline, function(selector, obj) {
animateWithQueue($(selector), obj);
});
Here is a full example. http://jsfiddle.net/sprintstar/Tdads/
This code appears to work fine, the animations loop and the stop button can be clicked to stop the animations, clear the queues etc. However the issue we're facing can be triggered by hitting stop and start over and over (say 10 times). Then notice that the delays are not functioning correctly any more, and the shapes move about much faster.
Why is this, and how can it be fixed?

Something is not working quite right with delay...
As a work around, I've replaced it with doTimeout in this fiddle, so the following:
e.delay(step.pause).animate(step.anim, step.options);
Becomes:
var timerName = e[0].className + $.now();
timeouts.push(timerName);
e.queue(function(next) {
e.doTimeout(timerName, step.pause, function() {
this.animate(step.anim, step.options);
next();
});
});
timeouts is an array of unique timeout ids - each of which is cleared when the stop button is pressed.
As I've said, more of a workaround than a fix, as you'll also need to reset the position of the elements on stop too. (notice I've removed the += and -= from the top/right definitions)

looking at your stop handler i woudl suspect the .stop() to be miss placed.
i would target it on .circle and .square instead of the holding div.
Had an issue once with animate, as the element was moving faster and faster and faster and cam to the conclusion that animate was stacking up on himself.
api.jquery.com/clearQueue/ and http://api.jquery.com/stop/ might be usefull

Related

Smoothstate.js - removeClass not working onReady function

I'm using Smoothstate.js to add page transitions to my website and I'm trying to show a loading page between each page transition using the onStart, onProgress and onReady functions.
The code I have works, but every now and again it get's stuck on the loading page and the container div isn't removing the class 'is-loading'. However, it is removing the is-exiting class even though they're with the same removeClass line?
I'm so confused as to why It's not removing. Can anyone help please?
// Photoswipe
$(function(){
'use strict';
var options = {
prefetch: true,
debug:true,
cacheLength: 0,
repeatDelay: 500,
onStart: {
duration: 0, // Duration of our animation
render: function ($container) {
// Add your CSS animation reversing class
$container.addClass('is-exiting');
// Restart your animation
smoothState.restartCSSAnimations();
}
},
onProgress: {
// How long this animation takes
duration: 0,
// A function that dictates the animations that take place
render: function ($container) {
setTimeout(function() {
$container.addClass('is-loading');
$('#progressBar').append('<div id="bar"></div>');
var progress = '100%';
$('#bar').animate({
width: progress
}, 400);
}, 500);
}
},
onReady: {
duration: 0,
render: function ($container, $newContent) {
$container.removeClass('is-loading is-exiting');
// Inject the new content
$container.html($newContent);
},
},
onAfter: function() {
navbarAnimate();
closeMenu();
ImageSliders();
initPhotoSwipeFromDOM('.gallery');
ImageOverlay();
}
},
smoothState = $('#main').smoothState(options).data('smoothState');
});
Just a hint:
you add is-loading, 500ms after the loading process started. So may it be possible that onReady gets fired before your 500ms timeout? And therefore is-loading will be added as class again, after your removeClass call?
tl;dr: the problem is most likely the timeout here
setTimeout(function() {
$container.addClass('is-loading');
$('#progressBar').append('<div id="bar"></div>');
var progress = '100%';
$('#bar').animate({
width: progress
}, 400);
}, 500);

Stop/reverse animation on mouse off (baraja jquery plugin)

I've implemented the baraja jquery plugin for a section on a 'web app' that I need to create.
Rather than the plugin spreading the cards on the click of a button, I've opted to alter the script and spread out the cards on hover. On the face of it this works but if you hover over the cards and back off quickly before the animation is finished the cards will stay open. And then when you hover over the 'deck' they close. I've created a codepen below to show this:
http://codepen.io/moy/pen/OPyGgw
I've tried using .stop(); but it doesn't seem to have an impact on the result. Can anyone help me with this?
Additionally I'd like the deck to be open on page load, then close after a second or 2. I tried this with $( document ).ready() including the baraja.fan call but that didn't trigger it - any ideas?
this one really tickled me ;) tried several things, but - as already told - the plugin doesn't expect to get the close animation call faster, then the opening animation will run.
so finally i build you the following.
- opening the fan, right at document ready
- created a timeout for the mouseleave, to wait for the opening animation duration, before closing it - you will have a 400ms delay when mouseleave the element, but it will close, even when you've been to fast...
$(document).ready(function () {
if ($("#baraja-el").length) {
var $el = $('#baraja-el');
baraja = $el.baraja();
}
//initial open
baraja.fan({
speed: 400,
easing: 'ease-in-out',
range: 80,
direction: 'right',
origin: {
x: 0,
y: 0
},
center: true
});
$('.baraja-container').addClass('open');
// navigation
$('#baraja-prev').on('click', function (event) {
baraja.previous();
$('.baraja-container li').each(function () {
if ($(this).css('z-index') === "1000") {
$(this).addClass('visited');
}
});
});
$('#baraja-next').on('click', function (event) {
baraja.next();
$('.baraja-container li').each(function () {
if ($(this).css('z-index') === "1010") {
$(this).addClass('visited');
}
});
});
$('.baraja-container').hover(function (event) {
if(!$(this).hasClass('open'))
{
$(this).addClass('open');
baraja.fan({
speed: 400,
easing: 'ease-in-out',
range: 80,
direction: 'right',
origin: {
x: 0,
y: 0
},
center: true
});
}
}, function (event) {
curBarCon = $(this);
setTimeout(function(){
curBarCon.removeClass('open');
baraja.close();
}, 400);
});
$('.baraja-container li').click(function () {
$(this).addClass('visited');
});
});
since i fiddled in your codepen, you should have the working version here: http://codepen.io/moy/pen/OPyGgw
but... it's really no perfect solution. i'd suggest to get another plugin or rework baraja to get callback functions, which would test if the animation is currently running and dequeue them if needed.
rgrds,
E

jQuery animation setup callback throws error

I want to implement a jQuery animation callback method progress or step,
but in either case I'm getting the following error:
NS_ERROR_IN_PROGRESS: Component returned failure code: 0x804b000f (NS_ERROR_IN_PROGRESS) [nsICacheEntry.dataSize]
I searched a lot but not able to find anything in context, I am kind of stuck here, please suggest what could cause this error?
In fiddle i tried with step and progress and its working there , but not able to get it worked in my code, I am just looking, has some one faced such kind of error in jquery animation?
The sample code is:
this.taskHandle.find('img').stop(true, true).animate({
//todo//
top: vtop, // this.taskHandle.outerHeight(),
//'top': 0 - $('.target.upper').height(),
width: 0,
opacity: 0
}, {
duration: 2000,
step: function(){
console.log('I am called');
}
},
$.proxy(function() {
// some css clearing method
}, {
// some further actions after animation completes
})
);
You have some semantic errors going on here. I'm going to repost your code, formatted for easier reading:
this.taskHandle.find('img')
.stop(true, true)
.animate(
{
//todo//
top: vtop , // this.taskHandle.outerHeight(),
//'top' : 0 - $('.target.upper').height(),
width : 0,
opacity : 0
},
{
duration:2000,
step: function() {
console.log('I am called');
}
},
$.proxy(
function() {
// some css clearing method
},
{
// some further actions after animation completes
}
)
);
First: animate() doesn't accept 3 parameters (at least not those 3 parameters). I'm not sure what you are trying to do with your css clearing method, but anything you wan't to happen after the animation is complete should be in the complete method that you add right next to the step method.
Second: $.proxy() needs to have the context in which you want it to run as the second parameter, not some other"complete"-function.
So here is a slightly modified example which works. You can try it yourself in this fiddle.
var vtop = 100;
$('div')
.stop(true, true)
.animate(
{
top: vtop,
width: 0,
opacity : 0
},
{
duration: 2000,
step: function() {
console.log('I am called');
},
complete: function () {
alert('complete');// some further actions after animation completes
}
}
);
You could use Julian Shapiro's Velocity.js, which animations are (arguable) faster than jQuery and CSS (read this for more)
It allows you to use callbacks such as :
begin
progress
complete
like :
var vtop = 100;
jQuery(document).ready(function ($) {
$('div').find("img").velocity({
top: vtop,
width: 0,
opacity: 0
}, {
duration: 2000,
begin: function (elements) {
console.log('begin');
},
progress: function (elements, percentComplete, timeRemaining, timeStart) {
$("#log").html("<p>Progress: " + (percentComplete * 100) + "% - " + timeRemaining + "ms remaining!</p>");
},
complete: function (elements) {
// some further actions after animation completes
console.log('completed');
$.proxy( ... ); // some css clearing method
}
});
}); // ready
Notice that you just need to replace .animate() by .velocity()
See JSFIDDLE

Animated arrow(s)

I'm using the following code to animate a div class arrow;
function animUp() {
$(".arrow").animate({
top: "0"
}, "slow", "swing", animDown);
}
function animDown() {
$(".arrow").animate({
top: "40px"
}, "slow", "swing", animUp);
}
$(document).ready(function() {
animUp();
});
Which works great and animates the arrow as intended. I've then added the class 'arrow' to another div with an arrow in to animate and they both stop animate down, long pause, animate up, long pause, animate down etc. Rather than the smooth animation of one arrow.
I've also tried having arrow and arrow2 and combining them in the script like this;
function animUp() {
$(".arrow, .arrow2").animate({
top: "0"
}, "slow", "swing", animDown);
}
function animDown() {
$(".arrow, .arrow2").animate({
top: "40px"
}, "slow", "swing", animUp);
}
$(document).ready(function() {
animUp();
});
With the same result as above. What else can I try to get them both animating smoothly?
jsFiddle - My html structure is using bootstrap
animations are added to a queue by default in jQuery to avoid queueing you should do the following:
function animUp() {
$(".arrow, .arrow2").animate({
top: "0"
}, {
duration: "slow",
queue: false,
easing: "swing",
complete: animDown
});
}
function animDown() {
$(".arrow, .arrow2").animate({
top: "40px"
}, {
duration: "slow",
queue: false,
easing: "swing",
complete: animDown
});
}
notice how instead of just passing in "slow" we now use an object
the following is from the jQuery site :: http://api.jquery.com/animate/
queue (default: true)
Type: Boolean or String
A Boolean indicating whether to place the animation in the effects queue. If false, the animation will begin immediately. As of jQuery 1.7, the queue option can also accept a string, in which case the animation is added to the queue represented by that string. When a custom queue name is used the animation does not automatically start; you must call .dequeue("queuename") to start it.

How to run two jQuery animations simultaneously?

Is it possible to run two animations on two different elements simultaneously? I need the opposite of this question Jquery queueing animations.
I need to do something like this...
$('#first').animate({ width: 200 }, 200);
$('#second').animate({ width: 600 }, 200);
but to run those two at the same time. The only thing I could think of would be using setTimeout once for each animation, but I don't think it is the best solution.
yes there is!
$(function () {
$("#first").animate({
width: '200px'
}, { duration: 200, queue: false });
$("#second").animate({
width: '600px'
}, { duration: 200, queue: false });
});
That would run simultaneously yes.
what if you wanted to run two animations on the same element simultaneously ?
$(function () {
$('#first').animate({ width: '200px' }, 200);
$('#first').animate({ marginTop: '50px' }, 200);
});
This ends up queuing the animations.
to get to run them simultaneously you would use only one line.
$(function () {
$('#first').animate({ width: '200px', marginTop:'50px' }, 200);
});
Is there any other way to run two different animation on the same element simultaneously ?
I believe I found the solution in the jQuery documentation:
Animates all paragraph to a left style
of 50 and opacity of 1 (opaque,
visible), completing the animation
within 500 milliseconds. It also will
do it outside the queue, meaning it
will automatically start without
waiting for its turn.
$( "p" ).animate({
left: "50px", opacity: 1
}, { duration: 500, queue: false });
simply add: queue: false.
If you run the above as they are, they will appear to run simultaenously.
Here's some test code:
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
<script>
$(function () {
$('#first').animate({ width: 200 }, 200);
$('#second').animate({ width: 600 }, 200);
});
</script>
<div id="first" style="border:1px solid black; height:50px; width:50px"></div>
<div id="second" style="border:1px solid black; height:50px; width:50px"></div>
While it's true that consecutive calls to animate will give the appearance they are running at the same time, the underlying truth is they're distinct animations running very close to parallel.
To insure the animations are indeed running at the same time use:
$(function() {
$('#first').animate({..., queue: 'my-animation'});
$('#second').animate({..., queue: 'my-animation'});
$('#first,#second').dequeue('my-animation');
});
Further animations can be added to the 'my-animation' queue and all can be initiated provided the last animation dequeue's them.
Cheers,
Anthony
See this brilliant blog post about animating values in objects.. you can then use the values to animate whatever you like, 100% simultaneously!
http://www.josscrowcroft.com/2011/code/jquery-animate-increment-decrement-numeric-text-elements-value/
I've used it like this to slide in/out:
slide : function(id, prop, from, to) {
if (from < to) {
// Sliding out
var fromvals = { add: from, subtract: 0 };
var tovals = { add: to, subtract: 0 };
} else {
// Sliding back in
var fromvals = { add: from, subtract: to };
var tovals = { add: from, subtract: from };
}
$(fromvals).animate(tovals, {
duration: 200,
easing: 'swing', // can be anything
step: function () { // called on every step
// Slide using the entire -ms-grid-columns setting
$(id).css(prop, (this.add - this.subtract) + 'px 1.5fr 0.3fr 8fr 3fr 5fr 0.5fr');
}
});
}
Posting my answer to help someone, the top rated answer didn't solve my qualm.
When I implemented the following [from the top answer], my vertical scroll animation just jittered back and forth:
$(function () {
$("#first").animate({
width: '200px'
}, { duration: 200, queue: false });
$("#second").animate({
width: '600px'
}, { duration: 200, queue: false });
});
I referred to: W3 Schools Set Interval and it solved my issue, namely the 'Syntax' section:
setInterval(function, milliseconds, param1, param2, ...)
Having my parameters of the form { duration: 200, queue: false } forced a duration of zero and it only looked at the parameters for guidance.
The long and short, here's my code, if you want to understand why it works, read the link or analyse the interval expected parameters:
var $scrollDiv = '#mytestdiv';
var $scrollSpeed = 1000;
var $interval = 800;
function configureRepeats() {
window.setInterval(function () {
autoScroll($scrollDiv, $scrollSpeed);
}, $interval, { queue: false });
};
Where 'autoScroll' is:
$($scrollDiv).animate({
scrollTop: $($scrollDiv).get(0).scrollHeight
}, { duration: $scrollSpeed });
//Scroll to top immediately
$($scrollDiv).animate({
scrollTop: 0
}, 0);
Happy coding!

Categories

Resources