views:

47

answers:

2

The site I'm working on has a collection of navigation elements across the top ("Products", "Company", etc.). When you mouse over the Products link, an overlay appears that shows a list of products with links to each. There's a small link at the top of the container that, when clicked, closes the container. All of this works as advertised.

The client has asked that, once a user's mouse pointer is a sufficient distance from the overlay element, the overlay element would close (without them having to click the 'close' link). This element appears on multiple pages that have disparate content, so I'm afraid it won't be as simple as adding a mouseover listener to another single element within the page and have it work everywhere. My question, I suppose, is this: is there a relatively easy way to know when the mouse cursor is x pixels away from this container and trigger an event when this occurs?

My other thought is that I could just find several elements on the page that fit this criteria and add mouseover listeners to each, but I'm assuming there's a more elegant way of handling this.

Thanks in advance - and please let me know if more detail is needed.

+3  A: 

Here's one example.

http://jsfiddle.net/CsgFk/

Calculate the bounds you want around the overlay, and set up a mousemove hanlder on the document, which tests to see if the mouse is outside the bounds.

EDIT: It may be worthwhile to unbind the mousemove from the document when the overlay is hidden, and rebind it when revealed so that the mousemove isn't constantly firing for no reason. Or at the very least, have the mousemove handler check to see if the overlay is already hidden before hiding it.

HTML

<div id='overlay'></div>​

CSS

#overlay {
    width: 200px;
    height: 200px;
    background: orange;
    position: relative;
    top: 123px;
    left:23px;
}​

jQuery

var $ovl = $('#overlay');
var offset = $ovl.offset();
var height = $ovl.height();
var width = $ovl.width();

var bounds = {top: offset.top - 100,
              bottom: offset.top + height + 100,
              left: offset.left - 100,
              right: offset.left + width + 100
             }

$ovl.mouseenter(function() {
    $ovl.stop().animate({opacity:1});
});

    $(document).mousemove(function(e) {
    if(e.pageX < bounds.left ||
       e.pageX > bounds.right ||
       e.pageY < bounds.top ||
       e.pageY > bounds.bottom) {
           $ovl.stop().animate({opacity:.3});
    }
});​

EDIT:

Here's another idea (although it is heavily dependent on your layout). Place the overlay inside a container that has a large padding and remove the overlay when the pointer performs a mouseleave on the container. Again, this may not be feasible in your layout.


EDIT:

One other idea would be to set a delay on the code used to remove the overlay. Its not as precise, but may yield a sufficiently desirable effect.

patrick dw
I like the second idea
colinmarc
@colinmarc - I agree, as long as the layout allows it. By far the simplest, while achieving the desired result.
patrick dw
+1  A: 

Why not use a mouseout event with a timer?

var zGbl_OverlayCloseTimer      = '';

OverlayElement.addEventListener ("mouseout",  CloseOverlayWithDelay, false);


function CloseOverlayWithDelay (zEvent)
{
    if (typeof zGbl_OverlayCloseTimer == "number")
    {
        clearTimeout (zGbl_OverlayCloseTimer);
        zGbl_OverlayCloseTimer  = '';
    }

    zGbl_OverlayCloseTimer      = setTimeout (function() { CloseOverlay (); }, 333);
}


function CloseOverlay ()
{
    ...
}
Brock Adams
@Brock - That is effectively the last solution I gave. :o) Less precise though, since if you move the mouse 1px off the overly and stop, it will still fire after the timeout. May not be what the OP wanted.
patrick dw
@patrick I confess that I did not read your most recent edit as it appeared that your answer was unrelated to mine. As for the timed mouseout it works extremely well in practice. The user never leaves the pointer in such a dubious position. Rather you guard against "bumps" and unwanted overlay activations (requires about a 0.2 second delay on the overlay's activation).
Brock Adams
@Brock - No problem. :o) Dubious? Certainly `1px` was a mere example. Could be `30px`. My only point is that the OP specifically requested a distance based solution as an auto-close so the user doesn't need to click the close button. A small mouse movement off the overlay, followed by a pause would trigger the close, which may be partly what the OP is trying to avoid.
patrick dw