Delay animation until other animation is complete (sliding content( - javascript

I have this code which animates between divs sliding out. If an item is clicked, it's relevant content slides out. If another item is clicked, the current content slides back in and the new content slides out.
However,
var lastClicked = null;
var animateClasses = ['ale', 'bramling', 'bullet', 'miami-weisse'];
for (var i=0; i<animateClasses.length; i++) {
(function(animCls) {
$('.each-brew.'+animCls).toggle(function() {
if (lastClicked && lastClicked != this) {
// animate it back
$(lastClicked).trigger('click');
}
lastClicked = this;
$('.each-brew-content.'+animCls).show().animate({ left: '0' }, 1000).css('position','inherit');
}, function() {
$('.each-brew-content.'+animCls)
.animate({ left: '-33.3333%' }, 1000, function() { $(this).hide()}) // hide the element in the animation on-complete callback
.css('position','relative');
});
})(animateClasses[i]); // self calling anonymous function
}
However, the content sliding out once the already open content slides back is sliding out too quickly - it needs to wait until the content has fully slided back in before it slides out. Is this possible?
Here's a link to what I'm currently working on to get an idea (http://goo.gl/s8Tl6).
Cheers in advance,
R

Here's my take on it as a drop-in replacement with no markup changes. You want one of three things to happen when a menu item is clicked:
if the clicked item is currently showing, hide it
if something else is showing, hide it, then show the current item's content
if nothing is showing, show the current item's content
var lastClicked = null;
// here lastClicked points to the currently visible content
var animateClasses = ['ale', 'bramling', 'bullet', 'miami-weisse'];
for (var i=0; i<animateClasses.length; i++) {
(function(animCls) {
$('.each-brew.'+animCls).click(function(event){
if(lastClicked && lastClicked == animCls){
// if the lastClicked is `this` then just hide the content
$('.each-brew-content.'+animCls).animate(
{ left: '-33.3333%' }, 1000,
function() {
$(this).hide();
}).css('position','relative');
lastClicked = null;
}else{
if(lastClicked){
// if something else is lastClicked, hide it,
//then trigger a click on the new target
$('.each-brew-content.'+lastClicked).animate(
{ left: '-33.3333%' }, 1000,
function() {
$(this).hide();
$(event.target).trigger('click');
}).css('position','relative');
lastClicked = null;
}else{
// if there is no currently visible div,
// show our content
$('.each-brew-content.'+animCls).show()
.animate({ left: '0' }, 1000)
.css('position','relative');
lastClicked = animCls;
}
}
});
})(animateClasses[i]); // self calling anonymous function
}

Well, I'm pretty sure there are other more easy possibilities and I didn't have much time but here is a working jsfiddle: http://jsfiddle.net/uaNKz/
Basicly you use the callback function to wait until the animation is complete. In this special case it's the complete: function(){...}
$("document").ready(function(){
$('#ale').click(function(){
if ($('div').hasClass('toggled')){
$('.toggled').animate({ width: "toggle" }, { duration:250, complete: function(){
$('#alecont').animate({ width: "toggle" }, { duration:250 }).addClass('toggled');}
}).removeClass('toggled');
}else{
$('#alecont').animate({ width: "toggle" }, { duration:250 }).addClass('toggled');
}
});
$('#bramling').click(function(){
if ($('div').hasClass('toggled')){
$('.toggled').animate({ width: "toggle" }, { duration:250, complete: function(){
$('#bramcont').animate({ width: "toggle" }, { duration:250 }).addClass('toggled');}
}).removeClass('toggled');
}else{
$('#bramcont').animate({ width: "toggle" }, { duration:250 }).addClass('toggled');
}
});
});
I give a toggled class if a div is expanded. Since the animation on your page seems to be pretty much broken I think this would be a better way to do this. But remember: my code isn't really good. Just fast and it can be refactored. It's working tho..

Rather than using toggles, bind an on "click" handler to your ".each-brew" divs. In the handler, first hide content divs and then show the appropriate content when that animation completes. You can do that with either a promise or a callback. Something like this...
$(".each-brew").on("click", function (event) {
$(".each-brew-content").show().animate({ left: "0" }, 1000, function() {
// Get the brew name from the class list.
// This assumes that the brew is the second class in the list, as in your markup.
var brew = event.currentTarget.className.split(/\s+/)[1];
$(".each-brew-content." + brew).animate({ left: "-33.3333%" }, 1000, function() { $(this).hide(); });
});
});

I think an event and observer would do the trick for you.
set up the callback function on completion of your animation to fire an event.
the listener would first listen for any animation event and after that event is triggered listen for the completion event. when the completion event is fired execute the initial animation event.run method (or whatever you would want to call it)
Within the listener
on newanimationeventtriger(new_anim) wait for x seconds (to eliminate infinite loop poss) while if this lastevent triggers done == true{
new_anim.run();
}

Related

how do I stop the query animation que when a nav button is clicked

What I want: I created a sort of image gallery with a thumbnail slider and I want the thumbnails to scroll when a nav button is clicked but if the button is pushed again before the animation is completed it doesn't keep adding to the que, it clears the que and only completes the current animation.
What my problem is: When the button is clicked it puts the click animation in a que and completes all the clicks in order. Maybe someone can help we word this better.
What I have tried: I have tried adding .finish() and .stop(true, true) to my js file but I can't seem to get it working right. I'm probably putting it in the wrong spot or even using the wrong thing, I don't know and so I need some help.
Here is a functioning jsfiddle: http://jsfiddle.net/ma9j6o09/2/
Some of it is not working since my images are locally hosted but the slider part for the thumbnails is.
This is my function for animating the movement; what do I add to get the effect I need?
var clicks = 0;
$("#right").click(function() {
if ( clicks < 5 ) {
clicks++;
$("#thumbContainer").animate({
left: "-=128px"
}, 500, function() {
// Animation complete.
});
}
});
$("#left").click(function() {
if (clicks > 0) {
clicks--;
$("#thumbContainer").animate({
left: "+=128px"
}, 500, function() {
// Animation complete.
});
}
});
Try this out: http://jsfiddle.net/ma9j6o09/3/
In response to your question about .stop() you would use it like this:
$("#thumbContainer").stop(true, true).animate({
left: "+=128px"
}, 500, function() {
// Animation complete.
});
});
But this will indeed not achieve what you want as it means it will stop the animation and jump to the last frame straight away so you lose the animation you wanted.
Instead use the flag I used in the fiddle which makes it impossible to even try animate whilst an animation is in progress.
var clicks = 0,
animating = false;
$("#right").click(function() {
// Only animate if we are not already animating
if ( clicks < 5 && !animating ) {
animating = true;
clicks++;
$("#thumbContainer").animate({
left: "-=128px"
}, 500, function() {
animating = false; // No longer animating
// Animation complete.
});
}
});
$("#left").click(function() {
// Only animate if we are not already animating
if (clicks > 0 && !animating) {
animating = true;
clicks--;
$("#thumbContainer").animate({
left: "+=128px"
}, 500, function() {
animating = false; // No longer animating
// Animation complete.
});
}
});

jQuery velocity complete callback is being call but function no

I have a problem with this animation:
http://jsfiddle.net/pietrofxq/6kjnnkqx/
function hideIconPicture() {
self = $(this);
var p = self.find("p");
self.find("span").velocity("stop").velocity({
"opacity":0
},{
duration:100,
complete: function() {
p.velocity({"right":"0"}, {
duration:100,
delay:100
})
}
})
}
function showIconPicture() {
var self = $(this);
var p = self.find("p");
p.velocity({
"right":"60px",
}, {
duration:100,
complete: function() {
self.find("span").show().velocity({
"opacity":1
},100)
}
});
}
$(".uploadPicture .icon-container").hover(showIconPicture, hideIconPicture);
If you place your mouse above the middle of the black circle, and the mouse fast until below the black circle, the animation get bug: the icon goes back to its place, but the text remains with opacity:1.
How is that possible if in the code, i'm only setting the position of the icon to its original position AFTER the text get opacity:0?
First you must STOP current animations then start new animations.
add $('.icon-container>*').velocity("stop") to your show and hide functions.
See [ THIS ].
and it's not necessary to put the properties in quote. (use opacity, right instead of 'opacity', 'right')
and for changing your display value do this: (instead of show() hide() functions)
See the [ Documentation ]
$elm.velocity({
...
},{
display: 'none' //or 'block'
});
Whenever I use Velocity for hover effects, I use the data attribute to ensure that the animation is doing the right thing. The answer from #MeTe-30 didn't perform very well for me. This solution might be a little more useful for you: DEMO
var container = $('.icon-container');
var icon = container.find('p');
var text = container.find('span');
var group = icon.add(text);
container.data({animating:false}); // add data for animation queue purposes
function showIconPicture() {
/*
if the path is in the middle of an animation, stop it immediately and reverse the animation. This prevents many unwanted animations if the user hovers in and out quickly
*/
if (container.data('animating') === true){
icon.velocity("stop", true).velocity('reverse',{ duration:0});
container.data({animating:false});
} else { // begin default animation
icon.velocity({right :60, opacity: 1},{
duration:300,
begin: function(){
container.data({animating:true});
},
complete: function() {
text.velocity({ opacity:1 }, {duration: 300, delay: 0});
container.data({animating:false});
}
});
} // end of conditional statement
} // end of function
function hideIconPicture() {
/*
if the path is in the middle of an animation, stop it immediately and reverse the animation. This prevents many unwanted animations if the user hovers in and out quickly
*/
if (container.data('animating') === true){
icon.velocity("stop", true).velocity('reverse',{ duration:0});
container.data({animating:false});
} else { // begin default animation
icon.velocity({ right: 0, opacity:0 }, {
duration:200,
begin: function(){
container.data({animating:true});
},
complete: function(){
group.velocity({ opacity:0 },{ duration:200 });
container.data({animating:false});
}
});
} // end of conditional statement
} // end of function
$(".cover-profile").hover(showIconPicture, hideIconPicture);

Link click count for animation to run once

I answered a question earlier to run a jQuery animation when a link is clicked. Then the poster asked quite a valid question which stumped me.
"How do you only run the animation on the 1st click"...
I thought this would be pretty simple, so I tried something like this:
clicked = true;
$('#hotel').click(function(){
if (clicked){
$('#Hotelbody').animate({width:'toggle'},1000);
$('#Hotelbody').fadeIn();
$('#Mealsbody').hide();
clicked = false;
}
});
which, in all fairness, runs the animation only on the 1st click. But then if I clicked off that menu item and onto "Meals" for example, and return to click "Hotels" the animation doesn't run at all. I have spent the whole morning trying to figure this out, and I am getting frustrated now - haha
Essentially, what needs to happen is while the user is on "Hotels" menu item do not run the animation again if he / she clicks "Hotels" menu item. But if the user ventures to another menu item and returns to hotels, then run the animation.
Please see FIDDLE as an example.
Steps to follow:
1. Click Hotel --> (Animation runs)
2. Click Hotel again --> (Animation doesn't run)[so far, so good]
3. Click Meals --> Then Click Hotels again --> (Animation will not run again)
Please let me know if I need to explain myself further?
Thoughts:
- Have jQuery look at css class :active and animate from that?
Can't be that hard, just check if the one that's clicked is currently visible
$('#Hotel, #Meals').on('click', function(){
var el = $('#'+this.id+'body');
if ( el.is(':visible') ) return false;
el.animate({width:'toggle'},1000)
$('#Mealsbody, #Hotelbody').not(el).hide();
});
FIDDLE
Another way using classes http://jsfiddle.net/gMha8/17/
$('.tabs_bar').on('click', '#hotel:not(.now)', function () {
$(this).addClass('now');
$('#Meal').removeClass('now');
$('#Hotelbody').animate({
width: 'toggle'
}, 1000);
$('#Hotelbody').fadeIn();
$('#Mealsbody').hide();
});
$('.tabs_bar').on('click', '#Meal:not(.now)', function () {
$(this).addClass('now');
$('#hotel').removeClass('now');
$('#Mealsbody').animate({
width: 'toggle'
}, 1000);
$('#Mealsbody').fadeIn();
$('#Hotelbody').hide();
});
Here's a stupid way to do it http://jsfiddle.net/gMha8/14/
function meal() {
$('#Mealsbody').animate({
width: 'toggle'
}, 1000);
$('#Hotelbody').animate({
width: 'toggle'
}, 1000);
$('#Mealsbody').fadeIn();
$('#Hotelbody').hide();
$('#hotel').off().on('click', hotel);
$('#Meal').off('click', meal);
}
function hotel() {
$('#Hotelbody').animate({
width: 'toggle'
}, 1000);
$('#Mealsbody').animate({
width: 'toggle'
}, 1000);
$('#Hotelbody').fadeIn();
$('#Mealsbody').hide();
$('#Meal').off().on('click', meal);
$('#hotel').off('click', hotel);
}
$('#hotel').off().on('click', hotel);
$('#Meal').off().on('click', meal);
Try this:
var lastClicked = null;
$('#hotel').click(function(e){
if (lastClicked != e.target){
$('#Hotelbody').animate({width:'toggle'},1000);
$('#Hotelbody').fadeIn();
$('#Mealsbody').hide();
}
lastClicked = e.target;
});
$('#Meal').click(function(e){
if (lastClicked != e.target){$('#Mealsbody').animate({width:'toggle'},1000);
$('#Mealsbody').fadeIn();
$('#Hotelbody').hide();
}
lastClicked = e.target;
});
http://jsfiddle.net/gMha8/22/
Try this
$('#hotel').click(function(){
$('#Hotelbody').animate({width:'toggle'},1000);
$('#Mealsbody').animate({width:'toggle'},1000);
$('#Hotelbody').fadeIn();
$('#Mealsbody').hide();
});
$('#Meal').click(function(){
$('#Mealsbody').animate({width:'toggle'},1000);
$('#Hotelbody').animate({width:'toggle'},1000);
$('#Mealsbody').fadeIn();
$('#Hotelbody').hide();
});
Demo

jQuery Animations Control Sequence

I'm am attempting to build a homepage that has animations. I am having hard time controlling my animations though. All I need is to hide elements, and then show elements after a certain time. Loop through that sequence, and pause and show all elements when the someone hovers over the box. Example simple animation.
I have a long way to go. At first I tried using the .css() visibility property, now I'm using .show() and .hide().
I need a way to loop through my animations. I attempt to add another
setTimeout(clear1(), 3000);
to the end of my box1 function, but that wouldn't work for some reason.
I need a way to on a user hover over #box1, that all animations stop. I have tried using .clearQueue, but I couldn't get that to work.
First of all, set to your css:
.box {display: none;}
SHOW ALL BOXES ON HOVER See Demo
This will show all boxes on hover and then continue the animation from where it stopped (will hide the boxes that hadn't shown up during the animation). I think that is what you are after.
var index = 0; // To keep track of the last div showed during animation
var time_of_delay = 1000; // Set the time of delay
// Start the animation
$(document).ready(function () {
box1(time_of_delay);
});
// The hover states
$("#box1_1").hover(
function() {
box1(0);
}, function() {
box1(time_of_delay);
});
// The animation function
function box1 (delay_time) {
var time=delay_time;
if(time>0) {
$(".box").slice(index).each(function() {
$(this).hide().delay(time).show(0);
time=time+time_of_delay;
});
index=0;
} else {
$(".box:visible").each(function() {
index++;
});
$(".box").stop(true).show(0);
}
}
PAUSE ON HOVER See Demo
This will only pause the animation and continue from where it stopped.
var time_of_delay = 1000; // Set the time of delay
// Start the animation
$(document).ready(function () {
box1(time_of_delay);
});
// The hover states
$("#box1_1").hover(
function() {
box1(0);
}, function() {
box1(time_of_delay);
});
// The animation function
function box1 (delay_time) {
var time=delay_time;
if(time>0) {
$(".box:hidden").each(function() {
$(this).delay(time).show(0);
time=time+time_of_delay;
});
} else {
$(".box").stop(true);
}
}
I used setTimeout and clearTimeout and periodically call a function that increments (and resets) the box to display. Since I assign setTimout to boxt, I am able to call clearTimeout(boxt) on box1's hover event so that I can stop specifically that loop. Here's my jsfiddle. It might not be the exact effect you're trying to achieve, but it should be the right functionality and be easily adaptable with a few tweaks. Let me know if this works for you and if you have any questions about how it works :)
LIVE DEMO
var $box = $('#box1').find('.box'),
boxN = $box.length,
c = 0,
intv;
$box.eq(c).show(); // Show initially the '0' indexed .box (first one)
function loop(){
intv = setInterval(function(){
$box.eq(++c%boxN).fadeTo(400,1).siblings().fadeTo(400,0);
},1000);
}
loop(); // Start your loop
$('#box1').on('mouseenter mouseleave', function( e ){
return e.type=='mouseenter' ? (clearInterval(intv))($box.fadeTo(400,1)) : loop();
});
Where ++c%boxN will take care to loop your animation using the Modulo % (reminder) operator inside a setInterval. Than all you need to do is to register a mouseenter and mouseleave on the parent element to:
clear the Interval on mouseenter + fade all your elements
restart your loop function on mouseleave.
Here's one way to do it:
// hide all of the boxes
$('.box').hide();
// reference to each box, the current box in this list and a flag to stop the animation
var divs = box1.getElementsByClassName('box');
var i = 0;
var run = true;
// this will animate each box one after the other
function fade(){
if(i < divs.length && run){
$(divs[i++]).fadeIn(500, function(){
setTimeout(fade, 1000);
});
}
};
fade();
// stop the above function from running when the mouse enters `box1`
$('#box1').on('mouseenter', function(){console.log('enter');
run = false;
});
// start the function again from where we stopped it when the mouse leaves `box1`
$('#box1').on('mouseleave', function(){console.log('leave');
run = true;
fade();
});
Demo: http://jsfiddle.net/louisbros/dKcn5/

jquery clickling fast

I have this function, that adds 31px to my style bottom on ul.
It works fine, but if I click fast, it no longer adds 31px, but some weird number like 17.423px. I guess it's because the animation isn't done, and thereby by clicking fast it adds 31px to the current px amount. My thought is that I need to insert a stop(). But where?
$(function () {
$('.topTenTwocolumns .topTenTwocolumnsWrap .down').click(function () {
if ($("ul").css("bottom") !== '2728px') {
$(this).parents('.topTenTwocolumnsWrap').children('ul').stop().animate({
bottom: '+=31'
}, 200);
}
});
});
The animations are queued, but it might be that the values to animate are calculated before the animation is queued, and as you are using a relative value it would calculate the animation from it current position.
You already have a stop call in the code. I don't know if you added that afterwards, otherwise that could also explain the values. If you stop the animation halfways, the bottom value will naturally be changed halfways.
You could keep the current target value in a variable so that you can specify an absolute value for the animation:
$(function () {
var current = 0;
$('.topTenTwocolumns .topTenTwocolumnsWrap .down').click(function () {
if (current < 2728) {
current += 31;
$(this).parents('.topTenTwocolumnsWrap').children('ul').stop().animate({
bottom: current + 'px'
}, 200);
}
});
});
This way you can keep the stop call so that the new animation replaces the previous instead of being queued.
I would probably try to prevent the function from firing if one is already in flight. Something like this might work:
$(function () {
$('.topTenTwocolumns .topTenTwocolumnsWrap .down').click(function () {
if ($(this).data('in_flight') === true){
return false;
} else {
if ($("ul").css("bottom") !== '2728px') {
$(this).data('in_flight', true);
$(this).parents('.topTenTwocolumnsWrap').children('ul').stop().animate({
bottom: '+=31'
}, 200);
$(this).data('in_flight', false);
}
}
});
});
A more complicated approach would be to count the clicks and queue them (triggering the next one after the current running function completes). You could use similar code to do this.

Categories