1

I have recently posted about a hover effect with hover.

It now works ok, but I was wondering if there is a way to prioritise the effect. For example, if the user goes through a sequence of image rollovers quickly it takes a while for the animation to catch up. I don't mind the animations continuing, but I would like the item that is currently being hovered over to fadein immediately.

Here is my code at the moment:

<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.5.0/jquery.min.js" type="text/javascript"></script>
<title>Robs Test</title>
<style>
body{background:gray;}
div{position:relative;}
.box{
    position:relative;
    width:150px;
    height:150px;
    float:left;
    display:block;
    background:black;
    margin-right:20px;
}
.boxover{
    position:absolute;
    top:10px;
    left:0px;
    width:100%;
    height:20px;
    z-index:100;
    background:white;
    display:none;
}
</style>
<script type="text/javascript">
    $(function(){
        $('.box').hover(over, out);
    });


    function over(event){
        var over_id = '#box_over_' + $(this).attr('id').replace('over_','');

        $(over_id).fadeIn(400);
        $(over_id).css("display","normal");

    }
    function out(event) {
        var over_id = '#box_over_' + $(this).attr('id').replace('over_','');

        $(over_id).fadeOut(400);

    }

</script>

</head>

<body>
<a href="#" class="box" id="over_1"><img src="pier.jpg" alt="test" width="150" height="150" /><div id="box_over_1" class="boxover">hello</div></a>
<a href="#" class="box" id="over_2"><img src="pier.jpg" alt="test" width="150" height="150" /><div id="box_over_2" class="boxover">there</div></a>
<a href="#" class="box" id="over_3"><img src="pier.jpg" alt="test" width="150" height="150" /><div id="box_over_3" class="boxover">rob</div></a>


</body>

</html>

Is there something I can do to make the div that's being hovered over prioristise over the others? So I don't have to wait till the animation completes.

Cheers

Rob

4 Answers4

1

You can use stop function in jQuery to make it better. It will stop the animation in progress.

function over(event){
    var over_id = '#box_over_' + $(this).attr('id').replace('over_','');

    $(over_id).stop(true, true).fadeIn(400);
    $(over_id).css("display","normal");

}
function out(event) {
    var over_id = '#box_over_' + $(this).attr('id').replace('over_','');

    $(over_id).stop(true, true).fadeOut(400);

}
Diode
  • 24,570
  • 8
  • 40
  • 51
0

If you want to go whole ham, you can build your own priority queue system for objects using jquery animations. Then whenever a new animation is started, you can check the queue to see if there is an existing animation that needs to be stopped (if its priority is lower), or if the new animation should not start (due to a higher priority animation already running in the queue). Just wrote this in the last 10 mins so, check for bugs lol

Animations = {
    active : [],
    remove(anim){
        this.active.splice(this.active.indexOf(anim),1);
    },
    test(){
        this.$testObj1 = $('<div id="animTest" style="position:absolute;left:100;width:20px;height:20px;border:2px solid purple;">hi1</div>');
        this.$testObj2 = $('<div id="animTest" style="position:absolute;left:200;width:20px;height:20px;border:2px solid red;">hi2</div>');
        this.$testObj3 = $('<div id="animTest" style="position:absolute;left:300;width:20px;height:20px;border:2px solid blue;">hi3</div>');
        $('html').append(this.$testObj1).append(this.$testObj2).append(this.$testObj3);
        let testAnim1 = new Animation(
            'one',
            this.$testObj1,
            {top:100},
            1000,
            1 );
        let testAnim2 = new Animation(
            'two',
            this.$testObj2,
            {top:200},
            1000,
            2 );
        let testAnim3 = new Animation(
            'three',
            this.$testObj3,
            {top:300},
            1000,
            3 );
        setTimeout(function(){testAnim3.Animate();},1000) // lowest priority
        setTimeout(function(){testAnim2.Animate();},3000)
        setTimeout(function(){testAnim1.Animate();},2000) // highest priority
        setTimeout(function(){testAnim2.Animate();},6000)
    }
}
class Animation {
    constructor(name,$el,animationList,duration,priority,callback=null){
        this.name = name;
        this.$el = $el;
        this.animationList = animationList;
        this.priority = priority;
        this.duration = duration;
        this.callback = callback;
    }

    Animate(){
        let toRemove = [];
        console.log('animating : '+this.name);
        Animations.active.filter(x => x.priority > this.priority).forEach(x => {
            console.log('toRemPush :'+x.name);
            toRemove.push(x)
        });
        toRemove.forEach(x => {
            console.log('stopping and removing '+x.name+', priority '+x.priority+', due to '+this.name+' with priority '+this.priority);
            x.$el.stop(); 
            Animations.remove(x);
        });
        if (Animations.active.filter(x => x.priority < this.priority).length > 0){
            console.log('fail to start '+this.name+' due to higher priority anims running.');
            return;
        }
        this.$el.animate(
            this.animationList,
            this.duration,
            function(e){
                Animations.remove(this);
                if (this.callback != null && this.callback instanceof Function) {
                    this.callback(e);
                }
            });

       Animations.active.push(this);
    }
}
vannorman
  • 144
  • 1
  • 12
0

I would only trigger the animations (especially if they are long) if the user hovers over the image for set threshold amount of time (not on every rollover).

See related post on implementing controlled hover.

Community
  • 1
  • 1
SliverNinja - MSFT
  • 31,051
  • 11
  • 110
  • 173
0

Related to what @SliverNinja linked to, specifically for your scenario:

function over(event) {
    var $this = $(this);
    $this.data('hoverTimer', setTimeout(function(){
        timer = null;
        var over_id = '#box_over_' + $this.attr('id').replace('over_', '');

        $(over_id).fadeIn(400);
        $(over_id).css("display", "normal");
    }, 200));
}

function out(event) {
    var timer = $(this).data('hoverTimer');

    if (timer !== null) {
        clearTimeout(timer);   
    }
    var over_id = '#box_over_' + $(this).attr('id').replace('over_', '');

    $(over_id).fadeOut(400);
}

Here's the fiddle: http://jsfiddle.net/9RR93/

Alex Heyd
  • 1,323
  • 1
  • 10
  • 17