jQuery animation for a hover with 'mouse direction'

user191766 picture user191766 · Sep 2, 2010 · Viewed 11.4k times · Source

I'm trying to simulate the effect where I hover on an image an overlayed semi-transparent image will fade in from the direction where your mouse came from. Vice versa when your mouse leaves the image (fadeout + moves away)

I've prepared a test page for this. Go ahead and check it out, it will clarify what the desired effect is.

I have defined a HTML structure for this:

    <div class="overlayLink">
        <img src="assets/work/thumbnails/kreatude.jpg" alt="Kreatude" />
        <div class="overlayLink_overlay_bg">&nbsp;</div>
        <div class="overlayLink_overlay_fg">
            <span class="overlayLink_overlay_link"><a href="#">View Case Study</a></span>
            <div class="top">&nbsp;</div>
            <div class="left">&nbsp;</div>
            <div class="right">&nbsp;</div>
            <div class="bottom">&nbsp;</div>
        </div>
     </div>

and the following JS (I'm using jQuery):

jQuery(document).ready(function () {
    ourWork();
});

function ourWork(){
    var inHandler = function(){
        var blue_bg = jQuery(this).find('.overlayLink_overlay_bg');
        var divClass = inClass;

        blue_bg.stop(true,true).fadeIn();
        var ml,mt;
        if(divClass == 'left'){
            ml = -260;
            mt = 0;
        }
        else if(divClass == 'right'){
            ml = 260;
            mt = 0;
        }
        else if(divClass == 'top'){
            ml = 0;
            mt = -140;
        }
        else if(divClass == 'bottom'){
            ml = 0;
            mt = 140;
        }       

        //positioning
        jQuery(this).find('a').css({
            'marginLeft': ml + 'px',
            'marginTop' : mt + 'px'
        });


        //animation
        jQuery(this).find('a').stop(true,true).animate({
            "marginLeft": "0px",
            "marginTop": "0px"
        }, "slow");
    }
    var outHandler = function(){
        var blue_bg = jQuery(this).find('.overlayLink_overlay_bg');
        var divClass = outClass;

        blue_bg.stop(true,true).fadeOut();
        var ml,mt;
        if(divClass == 'left'){
            ml = -260;
            mt = 0;
        }
        else if(divClass == 'right'){
            ml = 260;
            mt = 0;
        }
        else if(divClass == 'top'){
            ml = 0;
            mt = -140;
        }
        else if(divClass == 'bottom'){
            ml = 0;
            mt = 140;
        }        

        //animation
        jQuery(this).find('a').stop(true,true).animate({
            "marginLeft": ml + "px",
            "marginTop": mt + "px"
        }, "slow");

    }

    var inClass, outClass;
    jQuery('.overlayLink_overlay_fg div').hover(function(){        
        inClass = jQuery(this).attr('class');
    },function(){       
        outClass = jQuery(this).attr('class');
    });

    jQuery('.overlayLink').mouseenter(inHandler).mouseleave(outHandler);
}

explanation:

Basically I have four absolute positioned divs on top of the image to know the direction (left,top,bottom,right) when I hover on one of those 4 div's (.overlayLink_overlay_fg div) I put the class name of the hovered div in a variable (var inClass and var outclass)

Once I hover over the div who covers the area of the image (.overlayLink) I request the direction from the inClass or outClass variable and perform the animation (inHandler,outHandler)

however this all seems to work, it's a little glitchy when you move your mouse really fast, now I'm asking what the problem is (that's causing the glitches) and how it could be fixed with my current code.

Thanks in advance

Answer

Caspar Kleijne picture Caspar Kleijne · Sep 5, 2010

Perhaps you shoud consider not to use the divs as "hotspots" but use some Math and Javascript to find the point where the mouse enters and leaves a div. This avoids overlapping/gaps problems. The code below basicaly divides a div in 4 triangled zones. Each zone returns a number when the mouse moves over it. The code needs some finetuning, and you have to decide for yourself where to bind and unbind the events. But I think it takes away most of your flickering problems.

$(".overlayLink").bind("mouseenter mouseleave",function(e){

/** the width and height of the current div **/
var w = $(this).width();
var h = $(this).height();

/** calculate the x and y to get an angle to the center of the div from that x and y. **/
/** gets the x value relative to the center of the DIV and "normalize" it **/
var x = (e.pageX - this.offset().left - (w/2)) * ( w > h ? (h/w) : 1 );
var y = (e.pageY - this.offset().top  - (h/2)) * ( h > w ? (w/h) : 1 );

/** the angle and the direction from where the mouse came in/went out clockwise (TRBL=0123);**/
/** first calculate the angle of the point, 
 add 180 deg to get rid of the negative values
 divide by 90 to get the quadrant
 add 3 and do a modulo by 4  to shift the quadrants to a proper clockwise TRBL (top/right/bottom/left) **/
var direction = Math.round((((Math.atan2(y, x) * (180 / Math.PI)) + 180 ) / 90 ) + 3 )  % 4;


/** do your animations here **/ 
switch(direction) {
 case 0:
  /** animations from the TOP **/
 break;
 case 1:
  /** animations from the RIGHT **/
 break;
 case 2:
  /** animations from the BOTTOM **/
 break;
 case 3:
  /** animations from the LEFT **/
 break;
}});

of course the short notation to get the direction should be:

var direction =  Math.round( Math.atan2(y, x) / 1.57079633 + 5 ) % 4

where 1.57... is Math.PI / 2 This is much more efiicient bit harder for me to explain since it skips the degrees conversion.