簡體   English   中英

如何使谷歌地圖中的重疊 POI 可訪問

[英]How to make overlaid POIs in google maps accessible

g-maps 中的常見 POI 固定顯示在圖塊上,但似乎可以通過重疊鏈接點擊。 當我制作透明地圖覆蓋時,POI 鏈接仍然可見,但不再可點擊。
通過屏幕截圖,問題可能會更清楚,我只能在較暗覆蓋層旁邊的右上方區域單擊正確的 POI:

在此處輸入圖像描述

我已經嘗試將疊加層綁定到具有最低 z-index 的圖層,但沒有成功:

mapPane z-index:100
覆蓋層z-index:101
floatPane z-index:102
markerLayer z-index:103
疊加圖像 z-index:104
floatShadow z-index:105
覆蓋鼠標目標 z-index:106
floatPane z-index:107

const panes = this.getPanes();
panes.mapPane.appendChild(this.div_);

我知道與標記相反,對 POI 的 API 支持是有限的,並且至少部分綁定到位置 API。 盡管如此,我更喜歡關於 z-index 的方法或其他一些更通用的處理 POI 的方法,這樣我就不必使用額外的 API,並且該解決方案適用於所有顯示的 POI。

對於標記,存在setZIndex方法,但這在這里似乎沒有幫助: Marker API

我知道在更高分辨率上顯示更多 POI 的情況,但這對問題沒有影響。
那么如何使 g-maps 中覆蓋層下方的 POI 鏈接可點擊?

編輯:
根據答案

我認為問題幾乎解決了。 由於@Brett Donald 的回答和評論,我在自己的 SVG 代碼中發現了一些錯誤,並意識到標記並非完全由 g-map 創建,而是 SVG 確實是由我自己創建/提供的。 在單個類中class USGSOverlay extends google.maps.OverlayView我可以選擇添加所需的代碼來實現我的目標。 我也意識到這門課對於解決問題是必不可少的。 一個鏈接答案中提到的示例中,並非覆蓋層后面的所有單擊事件都是可能的,因此可以通過單擊 POI 打開窗口,但不能在圖層后面再次關閉它們。

我將獎勵那些可以通過關閉覆蓋層后面的信息窗口的選項來豐富鏈接示例的人。

您是否在疊加層上嘗試過此設置?

.my-overlay {
    pointer-events: none;
}

谷歌地圖基礎知識

谷歌地圖(可能)包含許多難以在瀏覽器控制台中驗證的層。 我在控制台中標記了外部地圖層,並在編輯器中復制了由 JavaScript 生成的整個 html,因此更容易驗證和搜索預期的元素,如標記或覆蓋。
盡管如此, console.log()可以很好地調試地圖、標記或覆蓋等對象。

關於具有 z-index 的層,就像問題中提到的那樣,有一個清晰的結構。 但是 z-index 以及每一層的內容都可以調整(或不使用),我懷疑在沒有具體用例的情況下詳細顯示一般結構是否有用。 因此,任何相應的細節都與問題直接相關。

覆蓋基礎

覆蓋可以在很多層面上完成,還有一個特殊的類google.maps.GroundOverlay直接在地圖上方排序。 要獲得有關與覆蓋相關的對象和方法的概述,一個好的開始就是在帶有類和屬性的列表中搜索overlay一詞。

將疊加層綁定到窗格

實現疊加層的常用方法是基於google.maps.OverlayView創建定義並將疊加層綁定到窗格:


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

此過程會將地圖綁定到一個預定義的窗格,該窗格通常具有問題中列出的 z-index(默認 z-index 的范圍從 100 到 107)。

直接綁定 Overlay 到地圖

也可以將獨立於窗格的疊加層綁定到地圖,如果沒有定義不同的 z-index,它將直接位於地圖上方。 此方法在鏈接示例中使用。 該示例使用原型,因此它有點復雜,但基本上是這樣完成的:

class MyOverlay extends google.maps.OverlayView {
 ...
 onAdd() {
     // NO binding like `panes.mapPane.appendChild(this.div_);`
 }
 ...
}
overlay = new MyOverlay(map);
overlay.setMap(map);

選擇使用哪種方法可能會影響地圖中生成的 html,但無論如何都會影響 z-index。 因此,無論任何操縱的目標超出此選擇范圍,都會對進一步的訴訟程序產生影響。

POI 和標記的基礎知識

谷歌地圖中的 POI(興趣點)的處理方式完全不同,並且在大多數情況下也具有不同的 z-index。 用戶的功能可能是相同的。

POI(興趣點)

POI 可以通過以下設置啟用或禁用:

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

POI 的圖像直接“打印”在只是 png 圖像的地圖圖塊上。 POI 不能移動,並且不能通過單擊功能打開信息窗口,它們通常在地圖上沒有直接功能(它們可能通過高級地圖選項連接)。
這是直接從 g-map 復制的圖像,包括 POI:

在此處輸入圖像描述

關於功能 POI 是 Image 和 HTML-Markup 的組合,它們都沒有直接組合在 HTML 源中,而是按地圖上的位置邏輯組合。

標記

標記可以有單獨的功能,單獨的設計,如果地圖支持,一些也可以拖動到其他位置。 它們具有不同的標准設計,並且可以具有與 POI 不同的 z-index,此外,它們具有自己的 API ,還允許更改 z-index。
這是一個標准標記:

在此處輸入圖像描述

雖然 POI 的圖像始終位於任何疊加層下方,但標記可以顯示在疊加層上方,相比之下,這也對處理 z-index 產生了一些影響。

到目前為止的結論

有許多層具有不同的 z 索引,並且可能很容易創建更多層。 谷歌地圖的許多挑戰都與 z-index 和 html 源代碼中的排序有關,因此將元素綁定到正確的圖層可能是許多情況下的解決方案。

挑戰

挑戰的主要部分是創建疊加層並在這些疊加層下方啟用對 POI 及其信息窗口的點擊。 在疊加層上方顯示信息窗口可能很重要。

挑戰的第二部分是在疊加層上方顯示標記及其信息窗口。 這似乎比第一部分容易得多。

存在哪些信息/經驗?

這個問題是如何在覆蓋層下方禁用鼠標事件,目前我的印象是它的答案很復雜,因為可以通過將覆蓋層綁定到窗格來提高覆蓋層的 z-index 以避免鼠標事件。 盡管如此,我對除了答案之外的問題感到非常高興,因為該網站揭示了幾個細節。
此外,這個簡短的示例對於查看實際情況和驗證一些細節非常有用。

挑戰細節

該示例顯示,與任何窗格相比,疊加層永遠不會阻止直接綁定到地圖的疊加層下方 POI 上的點擊事件。
然而,信息窗口不能關閉,因此信息窗口本身就是一個挑戰。
通過將標記綁定到窗格,將標記放置在覆蓋層的頂部應該很容易。
因此,覆蓋應直接綁定到地圖,標記綁定到窗格。
有關 POI 信息窗口的選項尚不清楚,它們應顯示在疊加層上方,或者至少是可關閉的。

如果覆蓋層是由 svg、html 標記或路徑(即使用多邊形選項)構建的,則可能仍需驗證覆蓋層的行為和相關的行為是否始終相同。

關於 jsfiddle.net 上示例的評論

jsfiddle.net 上的本地代碼和代碼的行為有點不同,並且在行為上不是 100% 一致的。 所以 jsfiddle.net 很適合展示正在運行的示例,但代碼可能必須更改,或者只是用於另一個變體。 如果 jsfiddle.net 上出現問題,請先在您自己的服務器上嘗試,然后再發表評論。

步驟1

由於鏈接的問題是關於阻止我想要實現的目標,因此首先必須停用示例/答案中的各個事件處理程序。
此外定義this._div.style.zIndex = 1000; 可以停用以獲得關閉打開的信息窗口的選項。 奇怪的是信息窗口並不總是被覆蓋,但有時在覆蓋的頂部,有時在下面。 這應該是一致的,最好在覆蓋層之上。 另一個問題是信息窗口並不總是可關閉的,但在大多數情況下,當我嘗試時(在 jsfiddle.net 上這不起作用)。

小的變化可以在這里看到。

這是在自己的服務器上測試的完整代碼,在文件底部的變量“googleApiKey”中添加您自己的 API 密鑰:

<!doctype html>
<html>
<head>
    <title>Example for clickevents</title>
    <style>
      html, body {height: 100%;margin: 0;padding: 0;}
      #googleMap {height: 70%; width:100%}
    </style>
    <script src="https://polyfill.io/v3/polyfill.min.js?features=default"></script>
<script
    type="application/javascript"
    src="//code.jquery.com/jquery-2.1.3.js"
></script>
</head>
<body>
<div id="googleMap"></div>
<div id="message"></div>

<script>
    let map;

    function log(msg) {
        //console.log(msg); 
        document.getElementById('message').innerHTML += msg + '<br>';
    }

    function initMap() {
        var mapProp = {
            center: new google.maps.LatLng(51.508742, -0.120850),
            zoom: 15,
            mapTypeId: google.maps.MapTypeId.ROADMAP
        };
        var map = new google.maps.Map(document.getElementById("googleMap"), mapProp);

        let myMarkers = [];
        myMarkers['marker1'] = new google.maps.Marker({
            position: new google.maps.LatLng(51.506742, -0.120850),
            map: map,
            title: "MARKER 1",
        });
        myMarkers['marker2'] = new google.maps.Marker({
            position: new google.maps.LatLng(51.510742, -0.120850),
            map: map,
            title: "MARKER 2",
        });
        for (currentMarker in myMarkers) {
          var marker = new google.maps.Marker({
            position: myMarkers[currentMarker].position,
            map: map,
            title: myMarkers[currentMarker].title,
            // icon: icon,
          });
        }

        var infowindow = new google.maps.InfoWindow({
          content: 'Welcome to Google! Thanks for using our products and services (“Services”). The Services are provided by Google Inc. (“Google”), 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.'
        });
        
        myMarkers['marker1'].addListener('click', function () { infowindow.open(map, myMarkers['marker1']); });
        myMarkers['marker2'].addListener('click', function () { log('marker2 clicked'); });

        MyOverlay.prototype = new google.maps.OverlayView; //extends google.maps.OverlayView {
        function MyOverlay(map) {
          this._div = document.createElement('div');
          this._div.style.background = 'rgba(0, 0, 60, 0.2)';
          this._div.style.position   = 'absolute';
          // this._div.style.zIndex     = 1000;
          this._div.style.width      = '100%';
          this._div.style.height     = '200px';
          this.listeners = [];
          this.setMap(map);
        }
        const overlay = new MyOverlay(map);
        // const overlay = new MyOverlay;

        MyOverlay.events = [
          'mousedown', 'mousemove', 'mouseover', 
          'mouseout', 'mouseup', 'mousewheel', 
          'DOMMouseScroll', 'touchstart', 'touchend', 
          'touchmove', 'dblclick', 'contextmenu'
        ];
        MyOverlay.prototype.onAdd = function () {
            var self = this;
            this.getPanes().floatPane.appendChild(this._div);
            this.listeners = MyOverlay.events.map(function (event) {
                console.log({map:map,event:event});
                myMarkers['marker1'].addListener('mousedown', function () { log('marker1 clicked'); });
            });
        };
        MyOverlay.prototype.onRemove = function () {
            this.getPanes().floatPane.removeChild(this._div);
        };
        MyOverlay.prototype.draw = function () {
                myMarkers['marker1'].addListener('mousedown', function () { log('marker1 clicked'); });
        };
        overlay.setMap(map);
        console.log(overlay);
    }
    window.initMap = initMap;
    
    
    googleApiKey = '';
</script>
<script
  src="https://maps.googleapis.com/maps/api/js?key=" + googleApiKey + "&callback=initMap&v=weekly&channel=2&region=DE&language=de"
  async defer
></script>
</body>
</html>

所以實際上我自己最初的問題如何使 POI 可訪問得到了回答,我將通過擴展這個答案來回答我在“挑戰”中提到的更多細節。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM