javascript GoogleMap上下文菜单示例不起作用

t3psigkw  于 12个月前  发布在  Java
关注(0)|答案(1)|浏览(73)

我一直在寻找方法,将上下文菜单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'的类名,但我不知道它在找什么。我需要有人谁理解这一切,以帮助我找出解决办法。

qgelzfjb

qgelzfjb1#

在添加新函数“getCanvasXY”并修改“draw”函数后,上下文菜单的位置现在可以正常工作,如下所示:

function getCanvasXY(currentLatLng) {
        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(currentLatLng);
       var currentLatLngOffset = new google.maps.Point(
           Math.floor((worldCoordinate.x - worldCoordinateNW.x) * scale),
           Math.floor((worldCoordinate.y - worldCoordinateNW.y) * scale)
       );
       return currentLatLngOffset;
    }

    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 clickedPosition = getCanvasXY(this.position_);
            var left = clickedPosition.x ;
            var top = clickedPosition.y ;

            if((mapSize.width - left ) < menuSize.width)
                left = left - menuSize.width;

            if((mapSize.height - top ) < menuSize.height)
                top = top - menuSize.height;

            this.menu_.style.left = left + 'px';
            this.menu_.style.top = top + 'px';
        }
    };

字符串
仍然没有解决的是如何调用函数来响应菜单项上的单击。

相关问题