views:

163

answers:

3

I'm trying to setup a function in JavaScript to fade in or fade out some elements on my page. The fade themselves work fine, but my problem occurs when one of them tries to cancel the actions of the other one.

//I know this is ugly, I'm just learning JavaScript again and plan to recode it after I learn some more...
var fadeOut = false

//set out to true to fade out, false to fade in
function fade(out) {
    var steps = 1
    var outSpeed = 100
    var inSpeed = 10
    var timer = 0

    if (out) {
            //fade out
            fadeOut = true
            for ( var i=100; i>=0; i-=steps ) {
                    if ( fadeOut ) {
                            setTimeout("set_el_opacity(" + (i / 100) + ")",
                            timer+=steps
                    } else {
                            break;
                    }
            }
    } else {
            //fade in
            fadeOut = false
            for ( var i=0; i<=100; i+=steps ) {
                    if( !fadeOut ) {
                            setTimeout("set_el_opacity(" + (i / 100) + ")",
                            timer+=steps
                    } else {
                            break;
                    }
            }
    }
}

Now, the fade out is set to run slower than the fade in. I want the user to see it fade out slowly so they know it's on purpose, and then fade back in quickly if the elements are needed (removing some clutter from the screen when it's not needed).

fade(true) works fine, fade(false) works fine and is faster. My problem occurs when I call fade(true) followed shortly by fade(false). The fades fight with each other and then, since the fade(true) call runs faster it finishes first and the fade(false) call proceeds to fade it all out fully.

My question is: what can I do to make the fade(false) call cancel the loop of the fade(true) call?

+7  A: 

When you set the timer:

mytime = setTimeout('function()', 1000);

you can cancel it by using clearTimeout:

clearTimeout(mytime);
Seb
Thanks, that answers my question. The comment on setInterval below let me know that I should re-work the code to run differently and more efficiently.
Geek42
A: 

You should cancel the active timeout whenever fade() is called, using the clearTimeout() function. For more information on timeouts, check out this article. Here is a brief example based on the code you provided.

var timeoutId = null;

function fade(out) {
    // ...
    // Your variable declarations
    // ...

    // Cancel the active timeout, if any.
    clearTimeout(timeoutId);

    // Record the timeout ID inside your if-else blocks
    if (out) {
        // ...
        timeoutId = setTimeout( ... );
        // ...
    } else {
        // ...
        timeoutId = setTimeout( ... );
        // ...
    }
}
William Brendel
`clearTimeout`, not `cancelTimeout`: https://developer.mozilla.org/en/DOM/window.clearTimeout
NickFitz
oops, thanks for the correction
William Brendel
A: 

To start with, it's not a good idea to fire many many timers in a loop. You should instead use setInterval or fire off a new timer from your setTimeout handler.

Another approach is to have a single timer which fires off at fixed intervals and manages all pending effects. You can decide on a frame rate and let your timer (a "timer stack") run indefinitely, "ticking" at every frame -- you can optionally start/stop the ticking when there are no pending effects.

Ates Goral
This is what I needed to realize. I was adapting some code I found online and did not realize that the setTimeout function returns immediatly. So basically this loop is setting up about 100 timers of longer intervals and then letting them trigger. I could assign those to an array and cancel them all, or better yet, re-work the code to properly look.Thanks
Geek42