有点卡在这个上。我正在通过 JSON 检索地理坐标列表并将它们弹出到谷歌地图上。除了在完全相同的位置有两个或更多标记的情况外,一切都运行良好。API 仅显示 1 个标记 - 最上面的标记。我想这很公平,但想找到一种方法来以某种方式显示它们。
我在谷歌上搜索并找到了一些解决方案,但它们似乎大多适用于 API 的 V2 或者不是那么好。理想情况下,我想要一个解决方案,您可以单击某种组标记,然后显示聚集在它们所在位置周围的标记。
任何人都有这个问题或类似的问题,并愿意分享解决方案?
有点卡在这个上。我正在通过 JSON 检索地理坐标列表并将它们弹出到谷歌地图上。除了在完全相同的位置有两个或更多标记的情况外,一切都运行良好。API 仅显示 1 个标记 - 最上面的标记。我想这很公平,但想找到一种方法来以某种方式显示它们。
我在谷歌上搜索并找到了一些解决方案,但它们似乎大多适用于 API 的 V2 或者不是那么好。理想情况下,我想要一个解决方案,您可以单击某种组标记,然后显示聚集在它们所在位置周围的标记。
任何人都有这个问题或类似的问题,并愿意分享解决方案?
看看OverlappingMarkerSpiderfier。
有一个演示页面,但它们没有显示完全在同一位置的标记,只有一些非常靠近。  
但是在http://www.ejw.de/ejw-vor-ort/上可以看到一个真实的例子,在完全相同的地方有标记(向下滚动地图并点击几个标记以查看蜘蛛效果)。
这似乎是您问题的完美解决方案。
如果标记位于同一建筑物中,则偏移标记并不是真正的解决方案。您可能想要做的是像这样修改markerclusterer.js:
在 MarkerClusterer 类中添加一个原型 click 方法,就像这样 - 我们稍后将在 map initialize() 函数中覆盖它:
MarkerClusterer.prototype.onClick = function() { 
    return true; 
};
在 ClusterIcon 类中,在 clusterclick 触发器之后添加以下代码:
// Trigger the clusterclick event.
google.maps.event.trigger(markerClusterer, 'clusterclick', this.cluster_);
var zoom = this.map_.getZoom();
var maxZoom = markerClusterer.getMaxZoom();
// if we have reached the maxZoom and there is more than 1 marker in this cluster
// use our onClick method to popup a list of options
if (zoom >= maxZoom && this.cluster_.markers_.length > 1) {
   return markerClusterer.onClickZoom(this);
}
然后,在您初始化地图并声明您的 MarkerClusterer 对象的 initialize() 函数中:
markerCluster = new MarkerClusterer(map, markers);
// onClickZoom OVERRIDE
markerCluster.onClickZoom = function() { return multiChoice(markerCluster); }
multiChoice() 是您的(尚未编写)函数,用于弹出一个带有可供选择的选项列表的信息窗口。请注意,markerClusterer 对象会传递给您的函数,因为您将需要它来确定该集群中有多少个标记。例如:
function multiChoice(mc) {
     var cluster = mc.clusters_;
     // if more than 1 point shares the same lat/long
     // the size of the cluster array will be 1 AND
     // the number of markers in the cluster will be > 1
     // REMEMBER: maxZoom was already reached and we can't zoom in anymore
     if (cluster.length == 1 && cluster[0].markers_.length > 1)
     {
          var markers = cluster[0].markers_;
          for (var i=0; i < markers.length; i++)
          {
              // you'll probably want to generate your list of options here...
          }
          return false;
     }
     return true;
}
我将它与 jQuery 一起使用,它完成了这项工作:
var map;
var markers = [];
var infoWindow;
function initialize() {
    var center = new google.maps.LatLng(-29.6833300, 152.9333300);
    var mapOptions = {
        zoom: 5,
        center: center,
        panControl: false,
        zoomControl: false,
        mapTypeControl: false,
        scaleControl: false,
        streetViewControl: false,
        overviewMapControl: false,
        mapTypeId: google.maps.MapTypeId.ROADMAP
      }
    map = new google.maps.Map(document.getElementById('map-canvas'), mapOptions);
    $.getJSON('jsonbackend.php', function(data) {
        infoWindow = new google.maps.InfoWindow();
        $.each(data, function(key, val) {
            if(val['LATITUDE']!='' && val['LONGITUDE']!='')
            {                
                // Set the coordonates of the new point
                var latLng = new google.maps.LatLng(val['LATITUDE'],val['LONGITUDE']);
                //Check Markers array for duplicate position and offset a little
                if(markers.length != 0) {
                    for (i=0; i < markers.length; i++) {
                        var existingMarker = markers[i];
                        var pos = existingMarker.getPosition();
                        if (latLng.equals(pos)) {
                            var a = 360.0 / markers.length;
                            var newLat = pos.lat() + -.00004 * Math.cos((+a*i) / 180 * Math.PI);  //x
                            var newLng = pos.lng() + -.00004 * Math.sin((+a*i) / 180 * Math.PI);  //Y
                            var latLng = new google.maps.LatLng(newLat,newLng);
                        }
                    }
                }
                // Initialize the new marker
                var marker = new google.maps.Marker({map: map, position: latLng, title: val['TITLE']});
                // The HTML that is shown in the window of each item (when the icon it's clicked)
                var html = "<div id='iwcontent'><h3>"+val['TITLE']+"</h3>"+
                "<strong>Address: </strong>"+val['ADDRESS']+", "+val['SUBURB']+", "+val['STATE']+", "+val['POSTCODE']+"<br>"+
                "</div>";
                // Binds the infoWindow to the point
                bindInfoWindow(marker, map, infoWindow, html);
                // Add the marker to the array
                markers.push(marker);
            }
        });
        // Make a cluster with the markers from the array
        var markerCluster = new MarkerClusterer(map, markers, { zoomOnClick: true, maxZoom: 15, gridSize: 20 });
    });
}
function markerOpen(markerid) {
    map.setZoom(22);
    map.panTo(markers[markerid].getPosition());
    google.maps.event.trigger(markers[markerid],'click');
    switchView('map');
}
google.maps.event.addDomListener(window, 'load', initialize);
扩展Chaoley 的答案,我实现了一个函数,在给定坐标完全相同的位置列表(具有lng和lat属性的对象)的情况下,将它们从原始位置移开一点(修改对象到位)。然后它们围绕中心点形成一个漂亮的圆圈。
我发现,对于我的纬度(北纬 52 度),0.0003 度的圆半径效果最好,并且当转换为公里时,您必须弥补纬度和经度之间的差异。您可以在此处找到您所在纬度的近似换算。
var correctLocList = function (loclist) {
    var lng_radius = 0.0003,         // degrees of longitude separation
        lat_to_lng = 111.23 / 71.7,  // lat to long proportion in Warsaw
        angle = 0.5,                 // starting angle, in radians
        loclen = loclist.length,
        step = 2 * Math.PI / loclen,
        i,
        loc,
        lat_radius = lng_radius / lat_to_lng;
    for (i = 0; i < loclen; ++i) {
        loc = loclist[i];
        loc.lng = loc.lng + (Math.cos(angle) * lng_radius);
        loc.lat = loc.lat + (Math.sin(angle) * lat_radius);
        angle += step;
    }
};
@Ignatius 最优秀的答案,已更新以与 MarkerClustererPlus 的 v2.0.7 一起使用。
在 MarkerClusterer 类中添加一个原型 click 方法,就像这样 - 我们稍后将在 map initialize() 函数中覆盖它:
// BEGIN MODIFICATION (around line 715)
MarkerClusterer.prototype.onClick = function() { 
    return true; 
};
// END MODIFICATION
在 ClusterIcon 类中,在 click/clusterclick 触发器之后添加以下代码:
// EXISTING CODE (around line 143)
google.maps.event.trigger(mc, "click", cClusterIcon.cluster_);
google.maps.event.trigger(mc, "clusterclick", cClusterIcon.cluster_); // deprecated name
// BEGIN MODIFICATION
var zoom = mc.getMap().getZoom();
// Trying to pull this dynamically made the more zoomed in clusters not render
// when then kind of made this useless. -NNC @ BNB
// var maxZoom = mc.getMaxZoom();
var maxZoom = 15;
// if we have reached the maxZoom and there is more than 1 marker in this cluster
// use our onClick method to popup a list of options
if (zoom >= maxZoom && cClusterIcon.cluster_.markers_.length > 1) {
    return mc.onClick(cClusterIcon);
}
// END MODIFICATION
然后,在您初始化地图并声明您的 MarkerClusterer 对象的 initialize() 函数中:
markerCluster = new MarkerClusterer(map, markers);
// onClick OVERRIDE
markerCluster.onClick = function(clickedClusterIcon) { 
  return multiChoice(clickedClusterIcon.cluster_); 
}
multiChoice() 是您的(尚未编写)函数,用于弹出一个带有可供选择的选项列表的信息窗口。请注意,markerClusterer 对象会传递给您的函数,因为您将需要它来确定该集群中有多少个标记。例如:
function multiChoice(clickedCluster) {
  if (clickedCluster.getMarkers().length > 1)
  {
    // var markers = clickedCluster.getMarkers();
    // do something creative!
    return false;
  }
  return true;
};