我一直在寻找方法,将上下文菜单n我的谷歌Map应用程序.不幸的是,我的搜索发现的许多例子是旧的,许多链接不再有效.这是真实的这个链接Google maps marker custom context menu
我确实找到了一个示例example,我可以开始工作,但使它可用可能会有点混乱:这是工作的html示例(我的APIKEY被遮住了)。
<!DOCTYPE html>
<html>
<script src="https://maps.googleapis.com/maps/api/js?key=MYAPIKEY&callback=initialize"></script>
<script type="text/javascript" src="http://code.jquery.com/jquery-1.4.2.min.js"></script>
<script type="text/javascript">
var map;
function initialize() {
var latlng = new google.maps.LatLng(51.47,-0.025956);
var myOptions = {
zoom: 12,
center: latlng,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);
google.maps.event.addListener(map, "rightclick",function(event){showContextMenu(event.latLng);});
google.maps.event.addListener(map, "click",function(event){closeContextMenu();});
}
function getCanvasXY(caurrentLatLng){
var scale = Math.pow(2, map.getZoom());
var nw = new google.maps.LatLng(
map.getBounds().getNorthEast().lat(),
map.getBounds().getSouthWest().lng()
);
var worldCoordinateNW = map.getProjection().fromLatLngToPoint(nw);
var worldCoordinate = map.getProjection().fromLatLngToPoint(caurrentLatLng);
var caurrentLatLngOffset = new google.maps.Point(
Math.floor((worldCoordinate.x - worldCoordinateNW.x) * scale),
Math.floor((worldCoordinate.y - worldCoordinateNW.y) * scale)
);
return caurrentLatLngOffset;
}
function setMenuXY(caurrentLatLng){
var mapWidth = $('#map_canvas').width();
var mapHeight = $('#map_canvas').height();
var menuWidth = $('.contextmenu').width();
var menuHeight = $('.contextmenu').height();
var clickedPosition = getCanvasXY(caurrentLatLng);
var x = clickedPosition.x ;
var y = clickedPosition.y ;
if((mapWidth - x ) < menuWidth)
x = x - menuWidth;
if((mapHeight - y ) < menuHeight)
y = y - menuHeight;
$('.contextmenu').css('left',x );
$('.contextmenu').css('top',y );
};
function showContextMenu(caurrentLatLng ) {
var projection;
var contextmenuDir;
projection = map.getProjection() ;
$('.contextmenu').remove();
contextmenuDir = document.createElement("div");
contextmenuDir.className = 'contextmenu';
contextmenuDir.innerHTML = "<a id='menu1'><div class=context onclick=click1()>menu item 1<\/div><\/a><a id='menu2'><div class=context onclick=click2()>menu item 2<\/div><\/a>";
$(map.getDiv()).append(contextmenuDir);
setMenuXY(caurrentLatLng);
contextmenuDir.style.visibility = "visible";
}
function closeContextMenu()
{
$('.contextmenu').remove();
}
function click1()
{
alert("click 1");
}
function click2()
{
alert("click 2");
}
$(document).ready(function(){
initialize();
});
</script>
<style type="text/css">
html { height: 100%; }
body { height: 100%; margin: 0; padding: 0 }
#map_canvas{
height: 100%;
}
.contextmenu{
visibility:hidden;
background:#ffffff;
border:1px solid #8888FF;
z-index: 10;
position: relative;
width: 140px;
}
.contextmenu div{
padding-left: 5px
}
</style>
Rightclick below to show context menu.
<div class="formDiv" id="map_canvas"></div>
</html>
字符串
在'contextmenuDir.innerHTML ='行变得混乱。我决定进一步搜索,而不是扩展如何动态提供菜单项。我在github中找到了一个项目,似乎是我正在寻找的。然而,该项目是另一个项目的分支,结果不再有效。因此,没有关于html要求的细节。所以,我创建了一个html文件,并下载了contextmenu.js文件和其余的示例JavaScript代码,并尝试了一下。示例引用了一个apikey.js文件,看起来像这样:
var apikey2 = "..........................."; // API key 3
console.log("api keys loaded");
型
我的test4.htm文件:
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="initial-scale=1.0" user-scalable="yes" />
<style type="text/css">
html { height: 100%; }
body { height: 100%; margin: 0; padding: 0 }
#map { height: 100%; }
.menu {
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: 2px;
}
</style>
<title>Simple Map</title>
<script src="https://polyfill.io/v3/polyfill.min.js?features=default"></script>
<!-- playground-hide -->
<script src="apikey.js"> </script>
<!--script>
const process = { env: {} };
process.env.GOOGLE_MAPS_API_KEY =
apikey2;
</script-->
<!-- playground-hide-end -->
<!--link rel="stylesheet" type="text/css" href="./style.css" /-->
</head>
<body>
<div id="map"></div>
<div id="menu"></div>
<!-- prettier-ignore -->
<script>(g=>{var h,a,k,p="The Google Maps JavaScript API",c="google",l="importLibrary",q="__ib__",m=document,b=window;b=b[c]||(b[c]={});var d=b.maps||(b.maps={}),r=new Set,e=new URLSearchParams,u=()=>h||(h=new Promise(async(f,n)=>{await (a=m.createElement("script"));e.set("libraries",[...r]+"");for(k in g)e.set(k.replace(/[A-Z]/g,t=>"_"+t[0].toLowerCase()),g[k]);e.set("callback",c+".maps."+q);a.src=`https://maps.${c}apis.com/maps/api/js?`+e;d[q]=f;a.onerror=()=>h=n(Error(p+" could not load."));a.nonce=m.querySelector("script[nonce]")?.nonce||"";m.head.append(a)}));d[l]?console.warn(p+" only loads once. Ignoring:",g):d[l]=(f,...n)=>r.add(f)&&u().then(()=>d[l](f,...n))})
({key: apikey2, v: "weekly"});</script>
<script src = "./test4.js"></script>
<!--script src="./contextmenu.js"></script-->
</body>
</html>
型
以及包含JavaScript代码的test4.js文件。
var map; //google.maps.Map;
//$(document).ready(function() {
// initMap();
//});
async function initMap() {
const { Map } = await google.maps.importLibrary("maps");
console.log("initMap start");
map = new google.maps.Map(document.getElementById("map"), {
center: { lat: -34.397, lng: 150.644 },
zoom: 8,
});
/*
google.maps.ContextMenu v1.0
A context menu for Google Maps API v3
http://code.martinpearman.co.uk/googlemapsapi/google.maps.ContextMenu/
Copyright Martin Pearman
Last updated 21st November 2011
[email protected]
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
google.maps.ContextMenu = function(map, options, callback) {
options = options || {};
this.setMap(map);
this.classNames_ = options.classNames || {};
this.map_ = map;
this.id = options.id;
this.mapDiv_ = map.getDiv();
this.menuItems_ = options.menuItems || [];
this.pixelOffset = options.pixelOffset || new google.maps.Point(10, -5);
this.callback = callback || null;
this.eventName = options.eventName || 'menu_item_selected';
/**
* [createMenuItem description]
* @param {Object} itemOptions An object with a label (required), a className (optional) and an id (optional)
* @param {Boolean} before when True, the menuitem is prepended to the menu instead of appended.
*/
this.createMenuItem = function(itemOptions, before) {
var self = this;
if (!self.menu_) {
console.log('No menu');
return;
}
itemOptions = itemOptions || {};
var menuItem = document.createElement('div');
menuItem.innerHTML = itemOptions.label;
menuItem.className = itemOptions.className || self.classNames_.menuItem;
menuItem.eventName = itemOptions.eventName || self.eventName;
if (itemOptions.id) {
menuItem.id = itemOptions.id;
}
menuItem.style.cssText = 'cursor:pointer; white-space:nowrap';
menuItem.onclick = function() {
google.maps.event.trigger(self, menuItem.eventName, self.position_, itemOptions.eventName);
};
if (before) {
self.menu_.insertBefore(menuItem, self.menu_.firstChild);
} else if (itemOptions.container_id) {
document.getElementById(itemOptions.container_id).appendChild(menuItem);
} else {
self.menu_.appendChild(menuItem);
}
};
/**
* [createMenuGroup description]
* @param {Boolean} before when True, the menugroup is prepended to the menu instead of appended.
*/
this.createMenuGroup = function(itemOptions, before) {
var self = this;
if (!self.menu_) {
console.log('No menu');
return;
}
itemOptions = itemOptions || {};
var menuGroup = document.createElement('span');
if (itemOptions.id) {
menuGroup.id = itemOptions.id;
}
if (before) {
self.menu_.insertBefore(menuGroup, self.menu_.firstChild);
} else {
self.menu_.appendChild(menuGroup);
}
};
/**
* [createMenuSeparator description]
* @param {Boolean} before when True, the menuitem is prepended to the menu instead of appended.
*/
this.createMenuSeparator = function(itemOptions, before) {
var self = this;
if (!self.menu_) {
console.log('No menu');
return;
}
itemOptions = itemOptions || {};
var menuSeparator = document.createElement('div');
if (self.classNames_.menuSeparator) {
menuSeparator.className = self.classNames_.menuSeparator;
}
if (itemOptions.id) {
menuSeparator.id = itemOptions.id;
}
if (before) {
self.menu_.insertBefore(menuSeparator, self.menu_.firstChild);
} else if (itemOptions.container_id) {
document.getElementById(itemOptions.container_id).appendChild(menuSeparator);
} else {
self.menu_.appendChild(menuSeparator);
}
};
};
google.maps.ContextMenu.prototype = new google.maps.OverlayView();
google.maps.ContextMenu.prototype.draw = function() {
if (this.isVisible_) {
var mapSize = new google.maps.Size(this.mapDiv_.offsetWidth, this.mapDiv_.offsetHeight);
var menuSize = new google.maps.Size(this.menu_.offsetWidth, this.menu_.offsetHeight);
var mousePosition = this.getProjection().fromLatLngToDivPixel(this.position_);
var left = mousePosition.x;
var top = mousePosition.y;
if (mousePosition.x > mapSize.width - menuSize.width - this.pixelOffset.x) {
left = left - menuSize.width - this.pixelOffset.x;
} else {
left += this.pixelOffset.x;
}
if (mousePosition.y > mapSize.height - menuSize.height - this.pixelOffset.y) {
top = top - menuSize.height - this.pixelOffset.y;
} else {
top += this.pixelOffset.y;
}
this.menu_.style.left = left + 'px';
this.menu_.style.top = top + 'px';
}
};
google.maps.ContextMenu.prototype.getVisible = function() {
return this.isVisible_;
};
google.maps.ContextMenu.prototype.hide = function() {
if (this.isVisible_) {
this.menu_.style.display = 'none';
this.isVisible_ = false;
}
};
google.maps.ContextMenu.prototype.onAdd = function() {
var $this = this; // used for closures
var menu = document.createElement('div');
if (this.classNames_.menu) {
menu.className = this.classNames_.menu;
}
if (this.id) {
menu.id = this.id;
}
menu.style.cssText = 'display:none; position:absolute;z-index:250;';
$this.menu_ = menu;
for (var i = 0, j = this.menuItems_.length; i < j; i++) {
if (this.menuItems_[i].label) {
this.createMenuItem(this.menuItems_[i]);
} else {
this.createMenuSeparator();
}
}
menu.onmouseover = function() {
$this.map_.inmenu = true;
//console.log('Mouseover Menu');
};
menu.onmouseout = function() {
$this.map_.inmenu = false;
//console.log('mouseout Menu');
};
//delete this.classNames_;
delete this.menuItems_;
this.isVisible_ = false;
this.position_ = new google.maps.LatLng(0, 0);
google.maps.event.addListener(this.map_, 'click', function(mouseEvent) {
$this.hide();
});
this.getPanes().floatPane.parentNode.parentNode.appendChild(menu);
if (this.callback) this.callback();
};
google.maps.ContextMenu.prototype.onRemove = function() {
this.getPanes().floatPane.appendChild(this.menu);
this.menu_.parentNode.removeChild(this.menu_);
delete this.mapDiv_;
delete this.menu_;
delete this.position_;
};
google.maps.ContextMenu.prototype.show = function(latLng) {
if (!this.isVisible_) {
this.menu_.style.display = 'block';
this.isVisible_ = true;
}
this.position_ = latLng;
this.draw();
};
var menuStyle = {
menu: 'context_menu',
menuSeparator: 'context_menu_separator',
menuItem: 'context_menu_item'
};
var contextMenuOptions = {
id: "map_rightclick",
eventName: "menu_item_selected",
classNames: menuStyle,
menuItems:
[
{label:'option1', id:'menu_option1'},
{label:'option2', id:'menu_option2'},
]
};
var contextMenu = new google.maps.ContextMenu(map, contextMenuOptions, function() {
console.log('optional callback');
});
google.maps.event.addListener(map, 'contextmenu', function(mouseEvent) {
console.log("contextmenu clicked");
contextMenu.show(mouseEvent.latLng);
});
console.log("initMap done");
}
initMap();
//export {};
型
然而,在我的浏览器中加载test5.htm文件会创建一个谷歌Map,但没有上下文菜单。我认为它不起作用,因为html文件缺少一个div和/或一些样式信息。我认为div sgold有一个被称为'container_id'的类名,但我不知道它在找什么。我需要有人谁理解这一切,以帮助我找出解决办法。
1条答案
按热度按时间qgelzfjb1#
在添加新函数“getCanvasXY”并修改“draw”函数后,上下文菜单的位置现在可以正常工作,如下所示:
字符串
仍然没有解决的是如何调用函数来响应菜单项上的单击。