How I got a context menu onto my Google Maps API V3

Tuesday, 9 February 2010 09:34 by ebenroux

I have a jquery context menu plug-in that I have been using for a while.  As things go the context menu is attached to the relevant element (my map div) like so:

$('#map-canvas').contextMenu('context-menu', {options});

This is all good-and-well except that when the map is rendered all kinds of magic happens that basically means my context menu is never displayed.  This is in all likelihood because the Google Maps populates the map canvas div with elements that obvious do not have my context menu attached.

So the approach I took was to somehow tell the context menu to pop up where I need it.  But then I couldn't find a context menu that had a simple Show or Display or PopUp method (maybe I just missed it).  So the next step was to trigger the 'contexmenu' event on the map-canvas div.

First I needed to add an event listener for the rightclick event on the map that would call the openContextMenu function.  However, the event object passed to the function by Google Maps is a MouseEvent class.  This only has a latLng property specifying the latitude and longitude.  From this I needed to get the XY pixel coordinates.  Fortunately there is a MapCanvasProjection object that can return a Point from the fromLatLngToContainerPixel method.  Unfortunately the MapCanvasProjection object cannot be returned from the map but rather from an overlay.  So after some googling I found a bit of code on StackOverflow that does just that.

If anyone has a more elegant way to achieve the same thing please let me know.

Here is the complete code:

var map;
var mapOverlay;
var contextMenuEvent;

$(document).ready(function() {
    var sw = new google.maps.LatLng(-34.80, 16.43);
    var ne = new google.maps.LatLng(-22.06, 32.75);
    var bounds = new google.maps.LatLngBounds(sw, ne);

    map = new google.maps.Map($("#map-canvas").get(0), { mapTypeId: google.maps.MapTypeId.ROADMAP });

    map.setCenter(bounds.getCenter());
    map.fitBounds(bounds);
    map.enableKeyDragZoom();

    mapOverlay = new MapOverlay(map);

    google.maps.event.addListener(map, "rightclick", openContextMenu);

    $.contextMenu.defaults(
      {
          menuStyle:
         {
             width: '200px'
         }
      });

    $('#map-canvas').contextMenu('context-menu', {
        bindings:
      {
          'context-menu-zoom-in': function(trigger) {
              map.setZoom(map.getZoom() + 1);
          },
          'context-menu-zoom-out': function(trigger) {
              map.setZoom(map.getZoom() - 1);
          },
          'context-menu-center-map': function(trigger) {
              map.setCenter(contextMenuEvent.latLng);
          }
      }
    });
});

function openContextMenu(e) {
    var ev = new jQuery.Event('contextmenu');

    var p = mapOverlay.getProjection().fromLatLngToContainerPixel(e.latLng);

    ev.pageX = p.x;
    ev.pageY = p.y;
   
    contextMenuEvent = e;

    $('#map-canvas').trigger(ev, [e.latLng]);
}

MapOverlay.prototype = new google.maps.OverlayView();
MapOverlay.prototype.onAdd = function() { }
MapOverlay.prototype.onRemove = function() { }
MapOverlay.prototype.draw = function() { }

function MapOverlay(map) { this.setMap(map); }

Tags:   ,
Categories:   Google Maps | jQuery
Actions:   E-mail | Permalink | Comments (0) | Comment RSSRSS comment feed
Comments are closed