开发者

Google Map V3 context menu

开发者 https://www.devze.com 2023-03-30 11:40 出处:网络
I am looking for a Google Map V3 context menu library. I have found some code examples here Gizzmo\'s blog

I am looking for a Google Map V3 context menu library. I have found some code examples here

  1. Gizzmo's blog
  2. Google API tips
  3. GMap3
  4. How I got ..

Stack overflow question Google maps v3 - Contextual menu available? of April also just came up with the above examples. So did Gmap3 adding a simple contex开发者_开发百科t menu .

But maybe somebody has encapsulated the examples in a reusable library or found something in the meantime. Obviously there was something for V2.

-- Updated 2012-05-31 --

I have found another one http://googlemapsmania.blogspot.de/2012/04/create-google-maps-context-menu.html , but did not have the time to test it yet.


I don't think you need a library for this. I'd start by trying:

var contextMenu = google.maps.event.addListener(
        map,
        "rightclick",
        function( event ) {
            // use JS Dom methods to create the menu
            // use event.pixel.x and event.pixel.y 
            // to position menu at mouse position
            console.log( event );
        }
    );

This assumes your map was created with:

var map = new google.maps.map( { [map options] } );

The event object inside the callback has 4 properties

  1. latLng
  2. ma
  3. pixel

where pixel.x and pixel.y are the offset where your click event triggered - counted from the upper left corner of the canvas holding the map object.


I have created a working JS Fiddle for showing context menu as well as the ability to have clickable items on this context menu.

It shows a clickable Context Menu when a marker is right clicked on Google map. Basically it makes use of an OverlayView on map. BTW its just a demo.

var loc, map, marker, contextMenu;

ContextMenu.prototype = new google.maps.OverlayView();

/**
  * onAdd is called when the map's panes are ready and the overlay has been
  * added to the map.
  */
ContextMenu.prototype.onAdd = function() {

    $("<div id='cMenu' class='context-menu-marker'></div>").appendTo(document.body);
    var divOuter = $("#cMenu").get(0);

    for(var i=0;i < this.menuItems.length;i++) {
        var mItem = this.menuItems[i];
        $('<div id="' + mItem.id + '" class="options-marker">' +
          mItem.label + '</div>').appendTo(divOuter);
    }

    this.div_ = divOuter;

    // Add the element to the "overlayLayer" pane.
    var panes = this.getPanes();
    //panes.overlayLayer.appendChild();
    panes.overlayMouseTarget.appendChild(this.div_);

    var me = this;

    for(var i=0;i < this.menuItems.length;i++) {
        var mItem = this.menuItems[i];

        var func = function() {
           me.clickedItem = this.id;
           google.maps.event.trigger(me, 'click');
        };

        google.maps.event.addDomListener($("#" + mItem.id).get(0), 'click', $.proxy(func, mItem));
    }


    google.maps.event.addListener(me, 'click', function() {
       alert(me.clickedItem); 
    });

};

ContextMenu.prototype.draw = function() {
    var div = this.div_;
    div.style.left = '0px';
    div.style.top = '0px';
    div.style.width = '100px';
    div.style.height = '50px';
};

// The onRemove() method will be called automatically from the API if
// we ever set the overlay's map property to 'null'.
ContextMenu.prototype.onRemove = function() {
    this.div_.parentNode.removeChild(this.div_);
    this.div_ = null;
};

// Set the visibility to 'hidden' or 'visible'.
ContextMenu.prototype.hide = function() {
  if (this.div_) {
    // The visibility property must be a string enclosed in quotes.
    this.div_.style.visibility = 'hidden';
  }
};

ContextMenu.prototype.show = function(cpx) {
  if (this.div_) {
    var div = this.div_;
    div.style.left = cpx.x + 'px';
    div.style.top = cpx.y + 'px';

    this.div_.style.visibility = 'visible';
  }
};

function ContextMenu(map,options) {
    options = options || {}; //in case no options are passed to the constructor
    this.setMap(map); //tells the overlay which map it needs to draw on
    this.mapDiv = map.getDiv(); //Div container that the map exists in
    this.menuItems = options.menuItems || {}; //specific to context menus
    this.isVisible = false; //used to hide or show the context menu
}

function initialize() {

    loc = new google.maps.LatLng(62.323907, -150.109291);

    var options = {};
    var menuItems=[];

    menuItems.push({id:"zoomIn", className:'context_menu_item', eventName:'zoom_in_click', label:'Zoom in'});
    menuItems.push({id:"zoomOut", className:'context_menu_item', eventName:'zoom_out_click', label:'Zoom out'});


    options.menuItems = menuItems;
    //=========================================

    map = new google.maps.Map(document.getElementById("map"), {
        zoom: 12,
        center: loc,
        mapTypeId: google.maps.MapTypeId.ROADMAP
    });

    marker = new google.maps.Marker({
        map: map,
        position: loc,
        visible: true
    });

    contextMenu = new ContextMenu(map, options);

    google.maps.event.addListener(marker, 'rightclick', function(mouseEvent){
        contextMenu.hide();
        this.clickedMarker_ = this;
        var overlayProjection = contextMenu.getProjection();
        var cpx = overlayProjection.fromLatLngToContainerPixel(mouseEvent.latLng);
        contextMenu.show(cpx);

        map.setOptions({ draggableCursor: 'pointer' });
    });

    // Hide context menu on several events
    google.maps.event.addListener(map,'click', function(){
        map.setOptions({ draggableCursor: 'grab' });
        contextMenu.hide();
    });

}

google.maps.event.addDomListener(window, 'load', initialize);

Fiddle link:

http://jsfiddle.net/jEhJ3/3409/


You can add context menu very easily in google map by following these steps:

  1. Add a custom control of google maps, hide that control on page load.
  2. Add a right click event handler on map.
  3. Show that custom control on right click at correct position using pixel property of right click event parameter.

Moreover, Following is working snippet, open it in full page (use you own key to avoid that google billing error):

var map;
var karachi = {
  lat: 24.8567575,
  lng: 66.9701725
};

$(document).ready(function() {
  initMap();
});

function initMap() {
  map = new google.maps.Map(document.getElementById('map'), {
    zoom: 13.5,
    center: karachi
  });

  let contextMenu = document.getElementById('contextMenu');
  map.controls[google.maps.ControlPosition.TOP_CENTER].push(contextMenu);
  hideContextMenu();

  google.maps.event.addListener(map, "rightclick", function(event) {
    showContextMenu(event);
  });
  google.maps.event.addListener(map, "click", function(event) {
    hideContextMenu();
  });
}

function showContextMenu(event) {
  $('#contextMenu').css("display", "block");
  $('#contextMenu').css({
    left: event.pixel.x,
    top: event.pixel.y
  })
}

function hideContextMenu() {
  $('#contextMenu').css("display", "none");
}
#map {
  height: 100%;
}
html,
body {
  height: 100%;
  margin: 0;
  padding: 0;
}

.contextMenu {
  background-color: rgb(255, 255, 255);
  border: 2px solid rgb(255, 255, 255);
  border-radius: 3px;
  box-shadow: rgba(0, 0, 0, 0.3) 0px 2px 6px;
  cursor: pointer;
  font-size: 1rem;
  text-align: center;
  color: #0d1f49;
  width: 20vw;
  margin: 1px;/*Please note that this margin is necessary otherwise browser will open its own context menu*/
}
<script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyAGlM3LLIL2j4Wm-WQ9qUz7I7ZpBsUx1X8">
</script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="map"></div>
<div id="contextMenu" class="contextMenu">
  <div onclick="alert('On click of item 1 is called')">
    Item 1
  </div>
</div>


Go to this demo-purpose website: http://easysublease.org/mapcoverjs/

For context menu, I do not suggest implementing one subclass of the overlayView Class provided by Google Maps API. First, one instance of subclass of overlayView should be added to the five panes provided by Google. More possibly one should add this instance to pane overlayMouseTarget . But, this instance is "shadowed" by other dom over it. So normal original browser event such mouseover, mouseout cannot reach this instance.

One must use Google Maps API method: addDomListener to handle it(why?). It requires lots of JavaScript code to implement different event handlers, do lots of css class adding and deleting just to realize some visual effects, which could be done using several lines of CSS code if this instance is outside the map container.

So actually converting one external dom outside google map container into one context menu has merit that it can receive original DOM events from browser. Also using some external library can make the target behave better. As context menu, it should not only be able to handle original events, but also those events from Map.

-----------see implementations below------------------------

At the map part HTML, this is the code:

<div id="mapcover">
  <div id="mapcover-map"></div> <!-- this is map container-->
  <div id="demoControlPanel" class="mc-static2mapcontainer panel">I am map UI control button's container, I think one can use jQuery UI to make me look better<br><br>
    <div id="zoom-in-control" class="text-center">zoomIn</div>
    <div id="zoom-out-control" class="text-center">zoomOut</div>
  </div>
  <div id="demoContextPanel" class="mc-ascontextmenu panel">

    I am map context menu container, you can sytle me and add logic to me, just as normal DOM nodes.
    since I am not in Map Container at all! 
    <div class="text-center">
      <div role="group" aria-label="..." class="btn-group">
        <button id="place-marker1" type="button" class="btn btn-default">Marker1</button>
        <button id="place-marker2" type="button" class="btn btn-default">Marker2</button>
      </div>
    </div>
    <div class="form-group">
      <label for="content-marker1">Content of next Marker1</label>
      <input id="content-marker1" type="text" placeholder="New of Marker1!" class="form-control">
    </div>
  </div>
</div>

It shows how one developer can convert one external DOM (id=demoContextPanel) into one map context menu by just adding one css class ".mc-ascontextmenu"! That pages uses mapcover.js, which helps developer to manage some key components of Map such as Map control UIs, context menu, and customized markers. Then Developers have full freedom to style its map UIs.

If you need more, you can go to its Github see readme.md: https://github.com/bovetliu/mapcover

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号