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
If I were going to implement this functionality, here's how I'd approach it:
Each rectangle should have its own handlers so the two important values, sideEntered and lastSideTouched, are encapsulated within the scope of its handler.
This is a simple solution, but the edges need improvements in mouseenter event.
In mouse enter event I gave it 5% differ in (0% & 0%) (100% & 100%) just for catching the cursor if it moves fast and this is the bug that needs a fix.
const div = document.querySelector('div');
const mouseLeave = (e) => {
e.preventDefault();
e = e || window.event;
// get box properties
let a = e.target.getBoundingClientRect();
let w = a.width;
let h = a.height;
// get x,y
const x = e.pageX - a.left;
const y = e.pageY - a.top;
//* detect mouse out
if (x >= w) console.log('out-right');
if (x <= 0) console.log('out-left');
if (y >= h) console.log('out-bottom');
if (y <= 0) console.log('out-top');
}
const mouseEnter = (e) => {
e.preventDefault();
e = e || window.event;
// get box properties
let a = e.target.getBoundingClientRect();
let w = a.width;
let h = a.height;
// get x,y
const x = e.pageX - a.left;
const y = e.pageY - a.top;
// get positions by percentage
const X = (x / w) * 100;
const Y = (y / h) * 100;
//* detect mouse in
if ((X >= 0 && X <= 100) && (Y >= 0 && Y <= 5)) console.log('in-top');
if ((X >= 0 && X <= 100) && (Y >= 95 && Y <= 100)) console.log('in-bottom');
if ((Y >= 0 && Y <= 100) && (X >= 95 && X <= 100)) console.log('in-right');
if ((Y >= 0 && Y <= 100) && (X >= 0 && X <= 5)) console.log('in-left');
}
div.addEventListener('mouseleave', mouseLeave, true);
div.addEventListener('mouseenter', mouseEnter, true);
div {
width: 300px;
height: 300px;
outline: 1px solid blue;
margin: 50px auto;
}
<div></div>
Fundamentally, mouse movement events happen as a sequence of dots not as a curved line as we perceive the movement on the screen. The faster you move the mouse the wider the spacing between the dots and the larger the objects the mouse can move over without touching. So ideally you need to know the direction of the last mouse position prior to landing on your object and from that calculate the direction from which it approached. i.e. You need to constantly track the mouse position on the whole page to be certain of getting your effect to work correctly every time.
Rather than surrounding the image with absolutely positioned divs, you might try doing this with an image map, attaching handlers to the defined areas. Just define the border areas to be thick enough that the mouse movement will be detected even if it's being moved rather quickly.
If you swipe your mouse rapidly from left to right so that it crosses 3 rectangles
[ 1 ] [ 2 ] [ 3 ]
the mouse will be entering rectangle #3 via its left border div immediately after it has exited rectangle #2 via its right border div. However, the assignment inClass="left" outClass="left" when rectangle #3 is entered via its left border div occurs BEFORE the outHandler for rectangle #2 has fired.
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.