simPod
simPod

Reputation: 13446

jQuery hover animation - how to stop properly on mouseout

My problem is that when I move mouse quickly over square element and then go out with my cursor it sometimes doesn't finish the "mouseout" part of hover function

My HTML:

<div id="wrapper">
    <div id="o1" class="square"></div>
    <div id="o2" class="square"></div>
</div>

CSS

#wrapper {
    width: 100px;
    height: 100px;
    position: relative;
}
.square {
    width: 100px;
    height: 100px;
    position: absolute;
}
#o1 {
    background: red;
}
#o2 {
    background: blue;
    display:none;
}

Javascript:

$(function(){
    var o1 = $("#o1");
    var o2 = $("#o2");
    $('#wrapper').hover(function() {
        o1.fadeOut(400,function () {
            o2.fadeIn(400);
        });
    }, function() {
        o2.fadeOut(400,function () {
            o1.fadeIn(400);
        });
    });
});

jsFiddle: http://jsfiddle.net/TQ37t/

I have tried using stop() with different parameter on different places in my code but without success. Thanks

Upvotes: 0

Views: 1883

Answers (4)

slashingweapon
slashingweapon

Reputation: 11307

The easiest solution I came up with was to make sure all the queues were stopped before adding any new animations:

var o1 = $("#o1");
var o2 = $("#o2");
$('#wrapper').hover(function() {
    o2.stop(true, true);
    o1.stop(true, true);
    o1.fadeOut(400,function () {
        o2.fadeIn(400);
    });
}, function() {
    o1.stop(true, true);
    o2.stop(true, true);
    o2.fadeOut(400,function () {
        o1.fadeIn(400);
    });
});

Note that order matters when stopping the queues. Consider the following sequence:

    o1.fadeOut(400,function () {
        o2.fadeIn(400);
    });
    o2.stop(true, true); // at this point, o1 can still queue a new animation onto o2
        // at this point, o1 might finish fadeOut() and begin o2.fadeIn()
    o1.stop(true, true); // We should have stopped this one first

Upvotes: 2

slashingweapon
slashingweapon

Reputation: 11307

Because there are two different queues running at the same time, getting them to stop was a problem. One solution I came up with was to create a single queue that could be controlled, stopped, etc.. The Javascript looks like this:

var o1 = $("#o1");
var o2 = $("#o2");
var wrapper = $('#wrapper');

function funcToFadeInOutDequeue(jq, isIn) {
    if (isIn) {
        return function() {
            jq.fadeIn(400, function() {
                wrapper.dequeue();
            });
        };
    } else {
        return function() {
            jq.fadeOut(400, function() {
                wrapper.dequeue();
            });
        };
    }
}

wrapper.hover(function() {
    wrapper.stop(true);
    wrapper.queue( funcToFadeInOutDequeue(o1, false) );
    wrapper.queue( funcToFadeInOutDequeue(o2, true) );
}, function() {
    wrapper.stop(true);
    wrapper.queue( funcToFadeInOutDequeue(o2, false) );
    wrapper.queue( funcToFadeInOutDequeue(o1, true) );
});

See the fiddle...

Upvotes: 1

Adam
Adam

Reputation: 3518

Stop actually takes care of the problem (if this is the effect you are after):

$(function(){
var o1 = $("#o1");
var o2 = $("#o2");
$('#wrapper').hover(function() {
    o1.fadeOut(400,function () {
        o2.fadeIn(400);
    });
}, function() {
    o1.stop();
    o2.fadeOut(400,function () {
        o1.fadeIn(400);
    });
});

}); ​

http://jsfiddle.net/adam_gajzlerowicz/TQ37t/3/

Upvotes: 0

LukeGT
LukeGT

Reputation: 2352

Let's assume that o1 is visible and o2 is hidden. If we quickly hover in and out, the following happens:

  • o1 begins to fade out
  • o2 begins to fade out - finishes instantly, already hidden
  • o1 is told to fade in, as a result of o2 fading out
  • o2 is told to fade in, as a result of o1 fading out

What you get is both shapes being visible at the same time. This then causes further inconsistencies later.

What you need to do is have a flag which you set on mouseover/mouseout, which defines whether the mouse is over the #wrapper or not. You also have similar fadeIn/fadeOut instructions, just like you have now. But for the callback, run a function that reads the flag and determines which object needs to be faded in.

$(function(){
    var o1 = $("#o1");
    var o2 = $("#o2");
    var over = false;
    choose = function() {
        if (over) {
            o2.fadeIn(400);
        } else {
            o1.fadeIn(400);
        }
    }
    $('#wrapper').hover(function() {
        over = true;
        o1.fadeOut(400,choose);
    }, function() {
        over = false;
        o2.fadeOut(400,choose);
    });
});

JSFiddle: http://jsfiddle.net/TQ37t/2/

Upvotes: 1

Related Questions