jQuery fadeOut callback never fires - javascript

so I'm trying to create a really simple animation using jQuery but the callback for fadeOut doesn't ever happen.
Here is the code below:
var move = function(target, speed) {
$(target).delay(200).animate({bottom: "-=20"},
speed,
function() {
$(this).fadeOut(200, function() {
$(this).css("bottom", "+=20");
});
$(this).fadeIn(200);
}
);
move(target, speed);
};
move(".fa-arrow-down", 500);
I've tried several different things like checking it out in the console, setting various breakpoints (mainly right at $(this).css("bottom", "+=20");, right above this line, and right below this line).
I'm not really sure why it's not happening. Any help is appreciated and if you could please also explain what the issue actually is so I can learn too. Here's a fiddle.

You need to move the call to move(target, speed) to inside the complete function of the fadeIn.
DEMO
var move = function (target, speed) {
$(target).delay(200).animate({
bottom: "-=20"
},
speed,
function () {
$(this).fadeOut(200, function () {
$(this).css("bottom", "+=20");
});
$(this).fadeIn(200, function () {
move(target, speed);
});
});
};
move(".fa-arrow-down", 500);
But I can't take all the credit... cookie monster was first to see the recursion error. Just like he said, this works because it adds a delay to each time you call move()
As I just said, you're invoking move() immediately instead of waiting
for the callback. This means it invokes move() at a rate of frequency
equal to the time it takes to invoke .delay().animate(), but without
waiting for them to finish. In other words, move() will be invoked
tens of thousands of times even before the first .delay() is finished -- cookie monster

Related

onClick toggle class inside setInterval function

setInterval(function () {
$("#bound").click(function () {
$(".top").toggleClass("one");
$(".middle").toggleClass("two");
$(".bottom").toggleClass("three");
$(".nav-menu").toggleClass("menu-show");
});}, 450);
What is wrong with it?
Transition lags too much and sometimes stops workin.
Incase you want the latency after click event, you should put setInterval function inside click function:
$("#bound").click(function () {
setInterval(function () {
$(".top").toggleClass("one");
$(".middle").toggleClass("two");
$(".bottom").toggleClass("three");
$(".nav-menu").toggleClass("menu-show");
}, 450);
});
What is wrong with it?
The thing is you are binding so many click events at the interval of 450ms which will lead the browser to consume so much memory and browser will be unresponsive eventually.
Other noticeable thing is that you will get the "n" the number of bound events. So, as it is a continued process so at each iteration it will bind an event means if two iterations then two callbacks execution.
I guess you might instead do this:
$("#bound").click(function () {
setTimeout(function () { // <------change it to setTimeout if u don't make it infinite
$(".top").toggleClass("one");
$(".middle").toggleClass("two");
$(".bottom").toggleClass("three");
$(".nav-menu").toggleClass("menu-show");
}, 450);
});

Calling functions from within another - javascript

I'm relatively new to javascript and having a couple of issues that I'm hoping you can help with. I'm utilizing the fabric library with canvas to create an animation of sorts.
I have a function that is called when the relevant button is pressed:
//for starting the animation
startSim.onclick = function(){
//obtain speed value from the control panel.
var speed = 10000 / (new Number(speedControl.value));
//stuff
//animation process
object.animate('top', '+='+canvas.height,{
duration: speed,
abort: function(){
var returnedBool;
//Pause is pressed, simulation pauses
if(pause){
//stuff
}
//restart required
if(restart){
//stuff
}
//option here to save data?
return returnedBool;
},//end abort callback
onChange: canvas.renderAll.bind(canvas),
onComplete: function(){
//stuff
}
});//end animate callback
};
What I'd like to do is call certain other functions while the above animation is active.
I know how I'd like to do this using Java or C++ but I can't seem to call the function.
I have a display panel that should output various information - as the animation completes variables will change and I'd like them to be output on the screen and be updated as they change.
I'm testing with a simple function:
function updateInfoPanel(testSpeed){
var test = document.getElementById('currentSpeed');
test.innerHTML = test.innerHTML + testSpeed;
}
I think I need to call this in the main animate loop, if I call it before it's fine but obviously only displays the variable once. Could someone tell me where I'm going wrong please?
I also have a basic collision detection function that works but not within the animate loop and I think these problems are linked.
Many thanks for any help.
I removed the unnecessary parts of the code to save space.
So I've just tried to use a function as the result of onChange:
onChange: function(){
canvas.renderAll.bind(canvas);
updateInfoPanel(speed);
},
This doesn't present syntax errors but the animation no lingers runs although the speed variable does update in the info panel very quickly. :(
You need to call renderAll(), bind is actually returning a function to be used as a handler. Just try this code:
onChange: function(){
canvas.renderAll();//.bind(canvas);
updateInfoPanel(speed);
},
And let me know if it helped?

setTimeout not changing external variable [duplicate]

This is my code:
var b;
while(!b){
setTimeout(function(){
alert('sss')
b=1;
}, 500);
}
and it will not alert 'sss'
What can i do?
Updated:
I want to get bounds on google maps v3:
function get_bounds(){
var bounds_;
while(!bounds_){
setTimeout(function(){
bounds_=map.getBounds();
if(bounds_){
var leftBottom=[bounds_.getSouthWest().lat(),bounds_.getSouthWest().lng()]
var rightTop=[bounds_.getNorthEast().lat(),bounds_.getNorthEast().lng()]
return [leftBottom,rightTop];
}
}, 500);
}
}
updated2:
hi patrick dw, i don't know why , but your code doesn't work:
var b;
function waitForB() {
setTimeout(function(){
if(!b)
waitForB();
else
alert('sss');
}, 500);
}
waitForB()
updated3:
it is ok now :
var b;
function waitForB() {
setTimeout(function(){
if(!b){
waitForB();
b='ss';
}
else{
alert('sss')
}
}, 500);
}
waitForB()
JavaScript in web browsers is run in a single thread. When you call setTimeout(), it won't spawn a new thread. This means that setTimeout() will not execute until all of your main code has finished executing.
For this reason, you will end up with an infinite loop, because your loop condition is dependant on the execution of the setTimeout() callback.
Here's an interesting article on how JavaScript timers work:
How JavaScript Timers Work by John Resig
UPDATE:
Further to the updated question, you may want to listen to the bounds_changed event instead. I am not sure how you are planning to use your get_bounds() function, but you may want to refactor your logic to use an event listener instead:
google.maps.event.addListener(map,'bounds_changed', function () {
// The code here is triggered when the bounds change
});
That code is going to burn CPU time and memory by scheduling timeouts to happen. Think about it: you're loop condition is "b" becoming truthy. How is that going to happen? Only when a timer event fires. Will that happen? No, because you're eating the whole machine scheduling zillions more timeouts.
This sort of situation has as a tell-tale sign the effect of warming up the room you're sitting in.
I don't know what effect you're trying to get. Why not start by just the setTimeout() call and see how that goes. Maybe you could describe more about what it is you're trying to do.
Maybe you will want to use setInterval instead of setTimeout.
When b is changed, alert shows up.
var b = false;
(function () {
var intervalId;
function wait() {
if (b) {
clearInterval(intervalId);
alert('sss');
}
}
intervalId = setInterval(wait, 500);
})();
It is more intuitive and it doesn't mess with global variables too much.
HINT: Put semicolon after every statement if you are not sure where to omit safely.
This problem can now be solved correctly using the idle rather than the bounds_changed event listener:
google.maps.event.addListener(map, 'idle', function() {
updateStuff();
});
This event is fired when the map becomes idle after panning or zooming.
http://code.google.com/apis/maps/documentation/javascript/reference.html
It also fires after the map is first rendered, so this is probably the only event listener you need on your map in order to keep it up to date.

Loop kinetic javascript transitions one after other instead of all at once

I want to to queue several transitions one after the other in html5 canvas.
Looping the transition function calls all the transitions at once. I dont know if callback will be do this if the iterations are more than 100.
I want to do something like this:--
for(i=0;i<10;i++)
{
move(circle,Math.floor(Math.random()*1000),400);
}
move is my defined function which makes some transitions.its working perfectly fine.
Here, i want the circle to change its postion with every iteration but its changing its position only once.
You could do this:
var i=10;
var interval = window.setInterval(function(){
move(circle,Math.floor(Math.random()*1000), 400);
console.log(i);
if(!--i) {
window.clearInterval(interval);
}
}, 400); // wait 400 msecs between calls
Or, if your move function was willing to invoke a callback function once the transition was complete :
var i=10;
var callback = function(){
if(i--){
move(circle,Math.floor(Math.random()*1000),400, callback);
}
}
callback();
Yeah ofcource. Its not exactly the solution to the problem but sort of a trick.i first stored the instructions in a separate array (transitionsequence) and used a recursive callback to Callback (the callback defined in kinetic). its not very efficient method but i dont care as long as it solves the problem. :)
`function move2( i , limit) {
var obj = transitionsequence[i].object;
obj.transitionTo({
y:100,
duration: 0.3,
callback : function()
{
obj.transitionTo({
x:transitionsequence[i].x,
duration:0.3,
callback: function()
{
obj.transitionTo({
y:transitionsequence[i].y,
duration:0.3,
callback: function()
{
if(i < limit)
move2(i+1 , limit);
}
});
}
});
}
});
};`
The reason why your approach doesn't work is because the browser doesn't get an opportunity to repaint the canvas between your painting steps. Traditionally this was solved by rendering a single step (frame) and then waiting a small amount of time, but there's a new feature available in recent browsers: requestAnimationFrame, which is solving that exact problem.
Check Animating with javascript: from setInterval to requestAnimationFrame and requestAnimationFrame for Smart Animating (they also show how to create a shim for animating in browsers that don't support requestAnimationFrame).
(I don't know kinetic.js, but there might even be direct support for such a shim in it).

Loop Through jQuery Function Inifitly

I have a jQuery Animation which I want to loop infinitely, I have the current code but it just returns nothing.
$(document).ready(function() {
var i = 0;
document.write(i);
function runTest(){
$('#page_effect').fadeIn(1500).delay(3500).fadeOut(1500);
$('#page_effect2').delay(7000).fadeIn(1500).delay(3500).fadeOut(1500);
$('#page_effect3').delay(13900).fadeIn(1500).delay(3500).fadeOut(1500);
$('#page_effect4').delay(21000).fadeIn(1500).delay(3500).fadeOut(1500);
i++;
runTest();
}
if(i === 0){
runTest();
}
});
Many Thanks! :)
You could wrap them all in a function and re-call the function after the last animation has finished:
function run(){
$('#page_effect').fadeIn(1500).delay(3500).fadeOut(1500);
$('#page_effect2').delay(7000).fadeIn(1500).delay(3500).fadeOut(1500);
$('#page_effect3').delay(13900).fadeIn(1500).delay(3500).fadeOut(1500);
$('#page_effect4').delay(21000).fadeIn(1500).delay(3500).fadeOut(1500,run);
}
run();
Live example: http://jsfiddle.net/nCs6N/
First off, you shouldn't chain animations like this, use callbacks:
$("#page_effect").fadeIn(1500, function() {
$(this).delay(3500).fadeOut(1500);
});
This will wait for 3500ms to fadeOut, but only after the 1500ms fadeIn is complete.
This way using callbacks, you can call the function again from the last callback:
function runTest(){
...
$('#page_effect4').delay(21000).fadeIn(1500, function() {
$(this).delay(3500).fadeOut(1500, function() {
runTest();
// this will be called only after the fadeout completes
});
});
}
You're queueing the animations, but never "yielding" execution back to the browser, because you just call the function again immediately.
The browser never gets to enter its event loop, and the animations won't start.
To fix this, you'll need to make the browser wait until all of the animations have completed, and then queue them again:
$(function() {
(function animate() {
$('#page_effect').fadeIn(1500).delay(3500).fadeOut(1500);
$('#page_effect2').delay(7000).fadeIn(1500).delay(3500).fadeOut(1500);
$('#page_effect3').delay(13900).fadeIn(1500).delay(3500).fadeOut(1500);
$('#page_effect4').delay(21000).fadeIn(1500).delay(3500).fadeOut(1500);
// using deferred objects, ask for a promise that will be resolved
// when all animations on the specified elements have been completed,
// and when done, call myself to start all over again
$('#page_effect,#page_effect2,#page_effect3,#page_effect4')
.promise().done(animate);
})(); // invoke immediately
});
I note that your four separate effects are probably supposed to run in series, but the .promise() based solution above will also work if they were all running in parallel.
See http://jsfiddle.net/alnitak/ZKevs/
Note that if you are intending to run those effects in series you shouldn't really just queue them up all together - there's no timing guarantee and it's possible that the next element might start animation before the previous one finished.
The traditional solution to this was to add an "animation complete" callback in the last animation, but with four separate animations as you have here that would end up being horribly nested.
jQuery deferred objects can help here, too - note how this eliminates the additional calculated .delay() calls:
$('#page_effect').fadeIn(1500).delay(3500).fadeOut(1500);
$('#page_effect').promise().done(function() {
$('#page_effect2').fadeIn(1500).delay(3500).fadeOut(1500);
});
$('#page_effect2').promise().done(function() {
$('#page_effect3').fadeIn(1500).delay(3500).fadeOut(1500);
});
$('#page_effect4').promise().done(function() {
$('#page_effect4').fadeIn(1500).delay(3500).fadeOut(1500);
});
$('#page_effect4').promise.done(animate);
At which point you can see that every animation chain is identical and can be refactored:
function cycle($els) {
var i = 0, n = $els.length;
(function next() {
var $this = $els.eq(i);
i = (i + 1) % n;
$this.fadeIn(1500).delay(3500).fadeOut(1500).promise().done(next);
})();
});
cycle($('#page_effect,#page_effect2,#page_effect3,#page_effect4'));
Don't call runTest() recursively like that, you'll exhaust the function stack.
Instead use setTimeout(runTest, 0);

Categories