【问题标题】:Using custom popups instead of info windows on Google Maps with multiple markers在具有多个标记的 Google 地图上使用自定义弹出窗口而不是信息窗口
【发布时间】:2020-04-12 01:38:55
【问题描述】:

在 Google 地图上自定义信息窗口存在局限性/风险,因为 Google 将来可能会改变他们实施信息窗口 CSS 的方式。如果您想显着更改设计,推荐的方法是使用自定义弹出窗口。

但是,Google 自己的使用自定义弹出窗口的文档并没有说明如何做一些我认为大多数用户都想知道的关键事情。

1) 如何使用带有多个标记的自定义弹出窗口?

2) 如何切换/隐藏/显示与特定标记关联的自定义弹出窗口?

这是我正在处理的创建自定义弹出窗口的文档: https://developers-dot-devsite-v2-prod.appspot.com/maps/documentation/javascript/examples/overlay-popup

非常感谢任何帮助。

编辑 - 添加代码示例和图像:

<!DOCTYPE html>
<html>
  <head>
    <meta name="viewport" content="initial-scale=1.0, user-scalable=no">
    <meta charset="utf-8">
    <title>Custom Popups</title>
    <style>
      /* Always set the map height explicitly to define the size of the div
       * element that contains the map. */
      #map {
        height: 100%;
      }
      /* Optional: Makes the sample page fill the window. */
      html, body {
        height: 100%;
        margin: 0;
        padding: 0;
      }

      /* The popup bubble styling. */
      .popup-bubble {
        /* Position the bubble centred-above its parent. */
        display: none;
        position: absolute;
        top: 0;
        left: 0;
        transform: translate(-50%, -100%);
        /* Style the bubble. */
        background-color: white;
        /* padding: 5px; */
        border-radius: 5px;
        font-family: sans-serif;
        overflow-y: auto;
        /* height: 250px; */
        /* width: 250px; */
        box-shadow: 0px 2px 10px 1px rgba(0,0,0,0.5);
      }
      /* The parent of the bubble. A zero-height div at the top of the tip. */
      .popup-bubble-anchor {
        /* Position the div a fixed distance above the tip. */
        position: absolute;
        width: 100%;
        bottom: /* TIP_HEIGHT= */ 8px;
        left: 0;
      }
      /* This element draws the tip. */
      .popup-bubble-anchor::after {
        content: "";
        position: absolute;
        top: 0;
        left: 0;
        /* Center the tip horizontally. */
        transform: translate(-50%, 0);
        /* The tip is a https://css-tricks.com/snippets/css/css-triangle/ */
        width: 0;
        height: 0;
        /* The tip is 8px high, and 12px wide. */
        border-left: 6px solid transparent;
        border-right: 6px solid transparent;
        border-top: /* TIP_HEIGHT= */ 8px solid white;
      }
      /* JavaScript will position this div at the bottom of the popup tip. */
      .popup-container {
        cursor: auto;
        height: 0;
        position: absolute;
        /* The max width of the info window. */
        width: 200px;
      }
      .info-window-img {
        height: 170px;
        width: 250px;
      }
      .info-window-text {
        padding: 5px;
      }
      .info-window h1 {
        font-size: 18px;
        text-align: left;
        margin: 0px;
      }
      .info-window a {
        color: #E85A71;
        decoration: none;
      }
    </style>
  </head>
  <body>
    <div id="map"></div>
<script>
  var stories = [
    {
      "name": "First place",
      "url": "www.example.com",
      "category": "first category",
      "lat": 53.3498,
      "lng": 6.2603
    },
    {
      "name": "Second place",
      "url": "www.example2.com",
      "category": "second category",
      "lat": 53.0,
      "lng": 6.2603
    }
  ];
  var map, popup, Popup;
  var popups = [];

  function addMarkerInfo() {
    var bounds = new google.maps.LatLngBounds();
    var markers = []
    var clusterStyles = [
    {
      textColor: 'white',
      url: `{{ url_for('static', filename='images/') }}` + 'clusterimage.png',
      height: 50,
      width: 50
    }
    ];
    var mcOptions = {
      styles: clusterStyles,
    }
      for (var i = 0; i < stories.length; i++) {
          var story = stories[i]
          var url = story.url;
          var storyname = story.name;
          var storycategory = story.category;
          var contentString =`
            <h1><a href="${url}">${storyname}</a></h1>
            <p>${storycategory}</p>`;
          const marker = new google.maps.Marker({
              position: {lat: story.lat, lng: story.lng},
              map: map
          });
          markers.push(marker)
          bounds.extend(marker.position);
          map.fitBounds(bounds, 50);
          var opt = {
            maxZoom: 17,
            mapTypeControl: false,
            streetViewControl: false
           };
          map.setOptions(opt);
          // POPUP STARTS HERE
          Popup = createPopupClass();
          popup = new Popup(
              new google.maps.LatLng(story.lat, story.lng),
              contentString
              );
          popup.setMap(map);
          // popup.draw();
          popups[0] = popup;
          console.log(popup.containerDiv);

          marker.addListener('click', function () {

          });
          // POPUP ENDS HERE
      }
      var markerCluster = new MarkerClusterer(map, markers, mcOptions);
  }

  /** Initializes the map and the custom popup. */
  function initMap() {
    map = new google.maps.Map(document.getElementById('map'), {
    });

    addMarkerInfo();
  }

  /**
   * Returns the Popup class.
   *
   * Unfortunately, the Popup class can only be defined after
   * google.maps.OverlayView is defined, when the Maps API is loaded.
   * This function should be called by initMap.
   */
  function createPopupClass() {
    /**
     * A customized popup on the map.
     * @param {!google.maps.LatLng} position
     * @param {!Element} content The bubble div.
     * @constructor
     * @extends {google.maps.OverlayView}
     */
    function Popup(position, string) {
      this.position = position;
      var content = document.createElement('div');
      content.classList.add('popup-bubble');
      content.classList.add('info-window');
      content.innerHTML = string;

      // This zero-height div is positioned at the bottom of the bubble.
      var bubbleAnchor = document.createElement('div');
      bubbleAnchor.classList.add('popup-bubble-anchor');
      bubbleAnchor.appendChild(content);

      // This zero-height div is positioned at the bottom of the tip.
      this.containerDiv = document.createElement('div');
      this.containerDiv.classList.add('popup-container');
      this.containerDiv.appendChild(bubbleAnchor);

      // Optionally stop clicks, etc., from bubbling up to the map.
      google.maps.OverlayView.preventMapHitsAndGesturesFrom(this.containerDiv);
    }
    // ES5 magic to extend google.maps.OverlayView.
    Popup.prototype = Object.create(google.maps.OverlayView.prototype);

    /** Called when the popup is added to the map. */
    Popup.prototype.onAdd = function() {
      this.getPanes().floatPane.appendChild(this.containerDiv);
    };

    /** Called when the popup is removed from the map. */
    Popup.prototype.onRemove = function() {
      if (this.containerDiv.parentElement) {
        this.containerDiv.parentElement.removeChild(this.containerDiv);
      }
    };

    /** Called each frame when the popup needs to draw itself. */
    Popup.prototype.draw = function() {
      var divPosition = this.getProjection().fromLatLngToDivPixel(this.position);

      // Hide the popup when it is far out of view.
      var display =
          Math.abs(divPosition.x) < 4000 && Math.abs(divPosition.y) < 4000 ?
          'block' :
          'none';

      if (display === 'block') {
        this.containerDiv.style.left = divPosition.x + 'px';
        this.containerDiv.style.top = divPosition.y + 'px';
      }
      if (this.containerDiv.style.display !== display) {
        this.containerDiv.style.display = display;
      }
    };

    return Popup;
  }
    </script>
    <script src="https://developers.google.com/maps/documentation/javascript/examples/markerclusterer/markerclusterer.js">
    </script>
    <script async defer
    src="https://maps.googleapis.com/maps/api/js?key={{GOOGLE_KEY}}&callback=initMap">
    </script>
  </body>
</html>

map image with markers and popup

【问题讨论】:

  • 请向我们展示您的代码。到目前为止你做了什么?预期的结果是什么?
  • 我添加了一个我正在处理的代码示例和我希望看到的图像。目前标记显示,但我正在努力弄清楚如何创建弹出窗口,然后根据用户按下标记打开它们。

标签: javascript google-maps google-maps-markers


【解决方案1】:

您好,我希望 2 年后给出答案还为时不晚... 我为这个限制所做的是

创建标记时,除了传递位置和地图之外,我还传递了一个名为 targetID 的自定义属性,此 ID 的值将以某种方式与您要显示的信息相关联。在我的情况下,它是一个房屋 ID:

const marker = new google.maps.Marker({
                position: {lat: markerLat, lng: markerLong},
                map,
                targetId: houseId
            })

在创建 Popup 类时,我添加了名为 popupID 的第三个参数,并在添加该类 popup-container 后将此 popupID 作为 id 添加到 this.containerDiv:

function Popup(position, string, popupId) {
  this.position = position;
  .
  .
  .
  this.containerDiv.setAttribute('id', popupId)

并且在创建弹出窗口的新实例时,我只需传递与标记相同的 id 作为第三个参数:

popup = new Popup(
          new google.maps.LatLng(story.lat, story.lng),
          contentString,
          houseId
          )

由于 this.ContainerDiv 现在将 houseId 作为 Id 并且每个标记在自定义属性中都有 houseId,现在我可以创建一个函数,将一个侦听器附加到每个标记(在我的情况下,我想要一个悬停效果)并且这个侦听器可以通过Id获取元素并修改该元素的样式:

function attachListeners (someMarker){    
someMarker.addListener("mouseover", () => {
    let myPopup =  document.getElementById(someMarker.targetId)
    myPopup.style.display = "block";
    myPopup.onmouseout = () => {
        myPopup.style.display = "none"
    }
})

}

在此之后,在将标记推送到标记数组之前,您只需要调用函数并传递标记

.
.
.
attachListener(marker);
markers.push(marker)

我希望你理解我的解决方案并且它对你有用

【讨论】:

    猜你喜欢
    • 2018-04-03
    • 2017-04-17
    • 1970-01-01
    • 2013-08-19
    • 2013-08-15
    • 2021-01-01
    • 2021-12-15
    • 1970-01-01
    • 2019-06-03
    相关资源
    最近更新 更多