如何使谷歌地图中的重叠 POI 可供访问

Dav*_*vid 8 javascript css google-maps google-maps-api-3

G 地图中的常见 POI 固定显示在图块上,但似乎可以通过重叠链接点击。当我制作透明地图叠加时,POI 链接仍然可见,但不再可单击。
通过屏幕截图,问题可能会变得更清楚,正确的 POI 我只能单击较暗覆盖层旁边的右上方区域:

在此输入图像描述

我已经尝试将覆盖层绑定到 z-index 最低的图层,但没有成功:

mapPane z-index:100
覆盖图层 z-index:101
浮动面板 z-index:102
标记图层 z-index:103
覆盖图像 z-index:104
浮动阴影 z-index:105
覆盖MouseTarget z-index:106
浮动面板 z-index:107

const panes = this.getPanes();
panes.mapPane.appendChild(this.div_);
Run Code Online (Sandbox Code Playgroud)

我知道,与标记相反,POI 的 API 支持是有限的,并且至少部分绑定到地点 API。尽管如此,我更喜欢使用 z-index 的方法或其他更通用的方法来处理 POI,这样我就不必使用额外的 API,并且该解决方案适用于所有显示的 POI。

对于标记,该方法setZIndex存在,但这似乎没有帮助:Marker API

我知道在更高分辨率上会显示更多 POI,但这对问题没有影响。
那么如何使 G 地图中叠加层下方的 POI 链接可点击呢?

编辑:
根据答案

我认为问题已经差不多解决了。由于@Brett Donald 的回答和评论,我在自己的 SVG 代码中发现了一些错误,并意识到标记并不完全由 g-map 创建,但 SVG 确实是由我自己创建/提供的。在单独的课程中,class USGSOverlay extends google.maps.OverlayView我可以选择添加所需的代码来实现我的目标。我也意识到这堂课对于解决问题至关重要。在一个链接答案中提到的示例中 ,并非覆盖层后面的所有单击事件都是可能的,因此可以通过单击 POI 打开窗口,但不能在图层后面再次关闭它们。

我将向那些可以通过关闭覆盖层后面的信息窗口的选项来丰富链接示例的人提供赏金。

Dav*_*vid 0

有关 Google 地图的基础知识

\n

谷歌地图(可能)由许多层组成,很难在浏览器控制台中验证。我在控制台中标记了外部地图层,并复制了编辑器中由 JavaScript 生成的整个 html,因此更容易验证和搜索标记或覆盖等预期元素。
\n尽管如此,调试诸如地图、标记或叠加层之类的对象可以通过console.log().

\n

关于具有 z-index 的层,就像问题中提到的那样,有一个清晰的结构。但是 z-index 以及每层的内容可以调整(或不使用),我怀疑在没有具体用例的情况下详细显示一般结构是否有用。因此,任何相关细节都与问题直接相关。

\n

叠加基础知识

\n

覆盖可以在许多级别上完成,还有一个特殊的类google.maps.GroundOverlay直接在地图上方排序。overlay要获得与覆盖相关的对象和方法的概述,一个好的开始就是在包含类和属性的列表中搜索单词。

\n

将叠加层绑定到窗格

\n

实现覆盖的常见方法是基于窗格创建定义google.maps.OverlayView并将覆盖绑定到窗格:

\n
\n  class USGSOverlay extends google.maps.OverlayView {\n        bounds_;\n        image_;\n        div_;\n        constructor(bounds, image) { ... }\n        onAdd() {\n            this._div = document.createElement(\'div\');\n            ...\n            const panes = this.getPanes();\n            // inding overlay to a pane,\n            // `mapPane` can be exchanged by a different existing pane:\n            panes.mapPane.appendChild(this.div_); \n            ...\n        }\n        draw() { ... }\n        onRemove() { ... }\n  }\n  overlay = new USGSOverlay(map);\n  overlay.setMap(map);\n
Run Code Online (Sandbox Code Playgroud)\n

此过程会将地图绑定到预定义窗格,该窗格通常具有问题中列出的 z 索引(默认 z 索引范围从 100 到 107)。

\n

将 Overlay 直接绑定到地图

\n

还可以将独立于窗格的叠加层绑定到地图,然后如果没有定义不同的 z-index,它将位于地图的正上方。此方法在链接的示例中使用。\n该示例使用原型,因此有点复杂,但本质上是这样完成的:

\n
class MyOverlay extends google.maps.OverlayView {\n ...\n onAdd() {\n     // NO binding like `panes.mapPane.appendChild(this.div_);`\n }\n ...\n}\noverlay = new MyOverlay(map);\noverlay.setMap(map);\n
Run Code Online (Sandbox Code Playgroud)\n
\n

选择使用哪种方法可能会影响地图中生成的 html,但无论如何都会影响 z-index。因此,无论任何操纵的目标超出了这个选择,它都会影响进一步的程序。

\n

POI 和标记的基础知识

\n

谷歌地图中的 POI(兴趣点)的处理方式完全不同,并且在大多数情况下也具有不同的 z 索引。不过,用户的功能可能是相同的。

\n

POI(兴趣点)

\n

POI 可以通过以下设置启用或禁用:

\n
        const styles = {\n          default: [],\n          hide: [\n            {featureType: "poi.attraction", stylers: [{ visibility: "off" }]},\n            {featureType: "poi.business", stylers: [{ visibility: "off" }]},\n            {featureType: "poi.government", stylers: [{ visibility: "off" }]},\n            {featureType: "poi.medical",stylers: [{ visibility: "off" }]},\n            {featureType: "poi.park",stylers: [{ visibility: "off" }]},\n            {featureType: "poi.place_of_worship", stylers: [{ visibility: "off" }]},\n            {featureType: "poi.school", stylers: [{ visibility: "off" }]},\n            {featureType: "poi.sports_complex", stylers: [{ visibility: "off" }]},\n          ],\n        };\n        map.setOptions({ styles: styles["hide"] });\n
Run Code Online (Sandbox Code Playgroud)\n

POI 的图像直接“打印”在地图图块上,这些图块只是 png 图像。POI 无法移动,除了点击功能即可打开信息窗口之外,它们通常在地图上没有直接功能(尽管它们可能通过高级地图选项进行连接)。
\n这是直接从 g-map 复制的图像,包括 POI:

\n

在此输入图像描述

\n

关于功能 POI 是图像和 HTML 标记的组合,它们不是直接组合在 HTML 源中,而是按地图上的位置逻辑组合。

\n

标记

\n

标记可以具有单独的功能、单独的设计,如果地图支持,有些标记还可以拖动到其他位置。它们具有不同的标准设计,并且可以具有与 POI 不同的 z 索引,此外它们还有自己的 API,也允许更改 z 索引。
\n这是一个标准标记:

\n

在此输入图像描述

\n

虽然 POI 图像始终位于任何叠加层下方,但标记可以显示在叠加层上方,相比之下,这对使用 z 索引也有一定影响。

\n

到目前为止的结论

\n

有许多具有不同 z 索引的层,并且可以轻松创建更多层。有关 google 地图的许多挑战都与 z-index 和 html 源中的排序有关,因此将元素绑定到正确的层可能是许多情况下的解决方案。

\n

挑战

\n

挑战的主要部分是创建叠加层并启用对 POI 及其叠加层下方的信息窗口的点击。在覆盖层上方显示信息窗口可能会很重要。

\n

挑战的第二部分是在覆盖层上方显示标记及其信息窗口。这似乎比第一部分容易得多。

\n

存在哪些信息/经验?

\n

这个问题是如何禁用覆盖层下方的鼠标事件,目前我的印象是它的答案非常复杂,因为只需提高覆盖层的 z-index 即可通过绑定它来避免鼠标事件到一个窗格。尽管如此,我还是很高兴看到答案之外的问题,因为该网站揭示了一些细节。
\n还有简短的例子对于查看实际情况并验证一些细节非常有用。

\n

细节上的挑战

\n

该示例表明,与任何窗格相比,覆盖层永远不会阻止覆盖层下方 POI 上的单击事件,这些覆盖层直接绑定到地图。
\n尽管如此,信息窗口无法关闭,因此信息窗口本身就是一个挑战。
\n通过将标记绑定到窗格,可以轻松地将标记放置在覆盖层顶部。
\n因此,覆盖层应直接绑定到地图,标记应直接绑定到窗格。
\n有关 POI 信息窗口的选项尚不清楚,它们应显示在覆盖层上方,或者至少是可关闭的。

\n

如果覆盖层是由 svg、html 标记或路径(即带有多边形选项)构建的,则可能仍需要验证覆盖层的行为以及与覆盖层相关的行为是否始终相同。

\n

有关 jsfiddle.net 上示例的评论

\n

本地代码和 jsfiddle.net 上的代码的行为有点不同,并且行为并非 100% 一致。因此,jsfiddle.net 很好地展示了正在运行的示例,但代码可能需要更改,或者只是在其他变体中使用。\n如果某些内容在 jsfiddle.net 上不起作用,请先在您自己的服务器上尝试,然后再发表评论。

\n

步骤1

\n

由于链接的问题是关于阻止我想要实现的目标,因此首先必须停用示例/答案中的各个事件处理程序。
\n进一步定义this._div.style.zIndex = 1000;以获得关闭打开的信息窗口的选项。\n奇怪的是,信息窗口并不总是被覆盖,但有时在覆盖层的顶部,有时在下面。这应该是一致的,最多在覆盖层之上。另一个问题是信息窗口并不总是可关闭的,但在大多数情况下,当我尝试时(在 jsfiddle.net 上这不起作用)。

\n

在这里可以看到微小的变化

\n

以下是在自己的服务器上测试的完整代码,在文件底部的变量“googleApiKey”中添加您自己的 API 密钥:

\n
<!doctype html>\n<html>\n<head>\n    <title>Example for clickevents</title>\n    <style>\n      html, body {height: 100%;margin: 0;padding: 0;}\n      #googleMap {height: 70%; width:100%}\n    </style>\n    <script src="https://polyfill.io/v3/polyfill.min.js?features=default"></script>\n<script\n    type="application/javascript"\n    src="//code.jquery.com/jquery-2.1.3.js"\n></script>\n</head>\n<body>\n<div id="googleMap"></div>\n<div id="message"></div>\n\n<script>\n    let map;\n\n    function log(msg) {\n        //console.log(msg); \n        document.getElementById(\'message\').innerHTML += msg + \'<br>\';\n    }\n\n    function initMap() {\n        var mapProp = {\n            center: new google.maps.LatLng(51.508742, -0.120850),\n            zoom: 15,\n            mapTypeId: google.maps.MapTypeId.ROADMAP\n        };\n        var map = new google.maps.Map(document.getElementById("googleMap"), mapProp);\n\n        let myMarkers = [];\n        myMarkers[\'marker1\'] = new google.maps.Marker({\n            position: new google.maps.LatLng(51.506742, -0.120850),\n            map: map,\n            title: "MARKER 1",\n        });\n        myMarkers[\'marker2\'] = new google.maps.Marker({\n            position: new google.maps.LatLng(51.510742, -0.120850),\n            map: map,\n            title: "MARKER 2",\n        });\n        for (currentMarker in myMarkers) {\n          var marker = new google.maps.Marker({\n            position: myMarkers[currentMarker].position,\n            map: map,\n            title: myMarkers[currentMarker].title,\n            // icon: icon,\n          });\n        }\n\n        var infowindow = new google.maps.InfoWindow({\n          content: \'Welcome to Google! Thanks for using our products and services (\xe2\x80\x9cServices\xe2\x80\x9d). The Services are provided by Google Inc. (\xe2\x80\x9cGoogle\xe2\x80\x9d), located at 1600 Amphitheatre Parkway, Mountain View, CA 94043, United States.By using our Services, you are agreeing to these terms. Please read them carefully.Our Services are very diverse, so sometimes additional terms or product requirements (including age requirements) may apply. Additional terms will be available with the relevant Services, and those additional terms become part of your agreement with us if you use those Services.\'\n        });\n        \n        myMarkers[\'marker1\'].addListener(\'click\', function () { infowindow.open(map, myMarkers[\'marker1\']); });\n        myMarkers[\'marker2\'].addListener(\'click\', function () { log(\'marker2 clicked\'); });\n\n        MyOverlay.prototype = new google.maps.OverlayView; //extends google.maps.OverlayView {\n        function MyOverlay(map) {\n          this._div = document.createElement(\'div\');\n          this._div.style.background = \'rgba(0, 0, 60, 0.2)\';\n          this._div.style.position   = \'absolute\';\n          // this._div.style.zIndex     = 1000;\n          this._div.style.width      = \'100%\';\n          this._div.style.height     = \'200px\';\n          this.listeners = [];\n          this.setMap(map);\n        }\n        const overlay = new MyOverlay(map);\n        // const overlay = new MyOverlay;\n\n        MyOverlay.events = [\n          \'mousedown\', \'mousemove\', \'mouseover\', \n          \'mouseout\', \'mouseup\', \'mousewheel\', \n          \'DOMMouseScroll\', \'touchstart\', \'touchend\', \n          \'touchmove\', \'dblclick\', \'contextmenu\'\n        ];\n        MyOverlay.prototype.onAdd = function () {\n            var self = this;\n            this.getPanes().floatPane.appendChild(this._div);\n            this.listeners = MyOverlay.events.map(function (event) {\n                console.log({map:map,event:event});\n                myMarkers[\'marker1\'].addListener(\'mousedown\', function () { log(\'marker1 clicked\'); });\n            });\n        };\n        MyOverlay.prototype.onRemove = function () {\n            this.getPanes().floatPane.removeChild(this._div);\n        };\n        MyOverlay.prototype.draw = function () {\n                myMarkers[\'marker1\'].addListener(\'mousedown\', function () { log(\'marker1 clicked\'); });\n        };\n        overlay.setMap(map);\n        console.log(overlay);\n    }\n    window.initMap = initMap;\n    \n    \n    googleApiKey = \'\';\n</script>\n<script\n  src="https://maps.googleapis.com/maps/api/js?key=" + googleApiKey + "&callback=initMap&v=weekly&channel=2&region=DE&language=de"\n  async defer\n></script>\n</body>\n</html>\n
Run Code Online (Sandbox Code Playgroud)\n

所以实际上我自己最初的问题如何使 POI 可访问已经得到解答,我将通过扩展这个答案来回答上面“挑战”中提到的更多细节。

\n