5
votes

I'm mucking around with v3 of the Google Maps API and using the InfoBox plugin (part of the http://google-maps-utility-library-v3.googlecode.com/ suite) in conjunction to make some nicely styled info windows that react to marker interactions.

For this particular experiment, I've attempted to get the InfoBox window pop-up when the marker has been hovered over and out, however I've struggled to resolve the issue with the event system regarding mouseover/mouseout on the InfoBox window. What happens is that I can locate the DIV and use a google.maps.event.addDomListener to attach a mouseover and mouseout event to the InfoBox, except it's too fiddly -- when I mouseover a child node within the InfoBox, it counts as a mouseout on the parent node and fires the event.

Is this somehow related to propagation? I know InfoBox has a enableEventPropagation switch when you create a new InfoBox, but I'm not quite sure how and why it would be used.

The aim of the experiment is to create an info window with related links inside that appears on mouseover of the marker. You can then move the mouse inside the info window and interact and when you mouse out it will close the info window. I've tried another method where the mouseover on the marker triggers an external function that creates an external info window element that's positioned and has its own event handling. That works fine, but the layering of the custom info window on top of the map means that when you mouse over another marker in close proximity (under the custom info window) it can't register the mouseover for the marker.

This was my attempt at the InfoBox method:

 <!DOCTYPE html>
 <html>
 <head>
 <style type="text/css">
 <!--
    #map {
        width:                  800px;
        height:                 600px;
        margin:                 50px auto;
    }

    .map-popup {
        overflow:               visible;
        display:                block;
    }

    .map-popup .map-popup-window {
        background:             #fff;
        width:                  300px;
        height:                 140px;
        position:               absolute;
        left:                   -150px;
        bottom:                 20px;
    }

    .map-popup .map-popup-content {
        padding:                20px;
        text-align:             center;
        color:                  #000;
        font-family:            'Georgia', 'Times New Roman', serif;
    }
 -->
 </style>
 <script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false"></script>
 <script type="text/javascript" src="http://google-maps-utility-library-v3.googlecode.com/svn/trunk/infobox/src/infobox_packed.js"></script>
 <script type="text/javascript">

    var gmap, gpoints = [];

    function initialize() {
        gmap = new google.maps.Map(document.getElementById('map'), {
            zoom:               9,
            streetViewControl:  false,
            scaleControl:       false,
            center:             new google.maps.LatLng(-38.3000000,144.9629796),
            mapTypeId:          google.maps.MapTypeId.ROADMAP
        });

        for ( var i=0; i<5; i++ ) {
            gpoints.push( new point(gmap) );
        }
    }

    function popup(_point) {
        _point.popup = new InfoBox({
            content:            _point.content,
            pane:               'floatPane',
            closeBoxURL:        '',
            alignBottom:        1
        });

        _point.popup.open(_point.marker.map, _point.marker);

        google.maps.event.addListener(_point.popup, 'domready', function() {
            // Have to put this within the domready or else it can't find the div element (it's null until the InfoBox is opened)
            google.maps.event.addDomListener(_point.popup.div_, 'mouseout', function() {
                _point.popup.close();
            });
        });
    }

    function point(_map) {
        this.marker = new google.maps.Marker({
            position:           new google.maps.LatLng(-37.8131869 - (1 * Math.random()),144.9629796  + (1 * Math.random())),
            map:                _map
        });

        this.content = '<div class="map-popup"><div class="map-popup-window"><div class="map-popup-content"><a href="http://www.google.com/">Just try to click me!</a><br/>Hovering over this text will result in a <code>mouseout</code> event firing on the <code>map-popup</code> element and this will disappear.</div></div>';

        // Scope
        var gpoint = this;

        // Events
        google.maps.event.addListener(gpoint.marker, 'mouseover', function() {
            popup(gpoint);
        });
    }

 </script>
 </head>
 <body onload="initialize()">
    <div id="map"></div>
 </body>
 </html>

So I guess if anyone knows how to make this work and respond properly (or provide relevant tips/tricks) then that would be great!

2
Did you ever find a good solution for this? The jQuery example below looks like it targets the popup itself and not the marker. I'm having trouble seeing how to implement it that way using InfoBox. By upgrading to the latest dev version of InfoBox and turning on event propagation, I was able to get the popup to not jump to any underlying markers below the popup.Jeremy Hicks

2 Answers

11
votes

I have had the same problem. Just as you say the issue is that mouseout is triggered when moving to one of the child elements. The solution is to instead use mouseenter and mouseleave (jQuery needed), see this post for more information: Hover, mouseover and mouse out

In this case it is not possible to use the google maps event listener (it does not support mouseenter). Instead you can attach a normal jQuery event, or use the hover function as shown in the following code:

google.maps.event.addListener(_point.popup, 'domready', function() {
//Have to put this within the domready or else it can't find the div element (it's null until the InfoBox is opened)

    $(_point.popup.div_).hover(
        function() {
            //This is called when the mouse enters the element
        },
        function() {
            //This is called when the mouse leaves the element
            _point.popup.close();
        }
    );
});    
2
votes

What happens is that I can locate the DIV and use a google.maps.event.addDomListener to attach a mouseover and mouseout event to the InfoBox, except it's too fiddly -- when I mouseover a child node within the InfoBox, it counts as a mouseout on the parent node and fires the event.

A naive approach to overcome this could be to traverse the element tree up in your mouseout handler and to check whether you find the DIV or end up at the document root. If you find the DIV, the mouse is still within the popup and you don't need to close it.

jQuery solves this problem nicely by introducing a second event, mouseleave, which behaves as you would expect it and is implemented in a similar manner as explained above. The jQuery sourcecode has a special closure withinElement for this case which may be worth looking at.