Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Creating a div that knows where the mouse came from, including high mouse speed edge case

JSBin: http://jsbin.com/IwoDahe/1/edit?html,css,js,output

Context

I'm trying to create a "smart" div that knows where the mouse came from, and slides information from that side. Upon exit, it should slide information away in the exited direction.

This is fairly easy when the mouse moves slowly, as you can use .hover() and .slideToggle() to effectively capture and manipulate mouse movement.

However, when a user moves their mouse very fast, the slideToggle() function blocks the listener for mouseleave while it animates. (Which means the info ends up staying in the div even after mouseleave.) I've resorted to using the CSS :hover pseudoselector, but I'm still hitting an issue:

Issue

When the side of mouse entry is different from the side that the mouse last exited, the info slides in from the exited side, not the entered side. Check out the JSBin if what I'm saying sounds like total gibberish.

An idea I had was to, upon mouseenter, move the info div to the side that it's supposed to enter from, and then apply the pseudoselector. Problem is, CSS pseudoselectors fire faster than the JS.

Tests

Prepare: Widen your screen in JSBin so that the divs form a 4square.

It's Not Working When: enter div from top. info slides down. exit left. info slides left. enter from top. info will slide down from the left. Also, yes even initial entry is buggy.

It's Working When: enter div from left side. info slides in from left. exit top. info slides up. re-enter from left. info slides from left again.

like image 963
Salar Avatar asked Dec 12 '13 21:12

Salar


1 Answers

I would do it by checking whether or not the parent is hovered and changing the switch effect if so

switch (slideDirection) {
    case 'top':
        if (parent.is(':hover')) 
            info.css({
                'left': 0,
                'top': -200
            }).stop().animate({
                'left': 0,
                'top': 0
            })
        else 
            info.stop().animate({
                'left': 0,
                'top': -200
            })
        break;
    case 'right':
        if (parent.is(':hover')) 
            info.css({
                'left': 200,
                'top': 0
            }).stop().animate({
                'left': 0,
                'top': 0
            })
        else 
            info.stop().animate({
                'left': 200,
                'top': 0
            })
        break;
    case 'bottom':
        if (parent.is(':hover')) 
            info.css({
                'left': 0,
                'top': 200
            }).stop().animate({
                'left': 0,
                'top': 0
            })
        else 
            info.stop().animate({
                'left': 0,
                'top': 200
            })
        break;
    case 'left':
        if (parent.is(':hover')) 
            info.css({
                'top': 0,
                'left': -200
            }).stop().animate({
                'left': 0,
                'top': 0
            })
        else 
            info.stop().animate({
                'left': -200,
                'top': 0
            })
        break;
}

jsFiddle (Personal preference over jsBin). Sorry the code is a little messy, I'll clean it up when I have more time

EDIT

I came across some awesome alternatives to this approach:

  • This demo shows how jQuery can be combined with CSS transforms to achieve a very similar effect and perhaps more powerful effect
  • Here's a pure CSS version (awesome) but it does not leave the same direction as the mouse
like image 152
Zach Saucier Avatar answered Sep 28 '22 12:09

Zach Saucier