简体   繁体   English

谷歌地图 API V3 - 完全相同的位置上的多个标记

[英]Google maps API V3 - multiple markers on exact same spot

Bit stuck on this one.有点卡在这个上。 I am retrieving a list of geo coords via JSON and popping them onto a google map.我正在通过 JSON 检索地理坐标列表并将它们弹出到谷歌地图上。 All is working well except in the instance when I have two or more markers on the exact same spot.除了在完全相同的位置上有两个或更多标记的情况外,一切都运行良好。 The API only displays 1 marker - the top one. API 仅显示 1 个标记 - 顶部的标记。 This is fair enough I suppose but would like to find a way to display them all somehow.我想这很公平,但想找到一种方法以某种方式显示它们。

I've searched google and found a few solutions but they mostly seem to be for V2 of the API or just not that great.我搜索了谷歌并找到了一些解决方案,但它们似乎大多适用于 API 的 V2,或者不是那么好。 Ideally I'd like a solution where you click some sort of group marker and that then shows the markers clustered around the spot they are all in.理想情况下,我想要一个解决方案,您可以单击某种组标记,然后显示标记聚集在它们所在的位置周围。

Anybody had this problem or similar and would care to share a solution?有人遇到这个问题或类似问题,愿意分享解决方案吗?

Take a look at OverlappingMarkerSpiderfier .看看OverlappingMarkerSpiderfier
There's a demo page, but they don't show markers which are exactly on the same spot, only some which are very close together.有一个演示页面,但它们没有显示完全相同的标记,只有一些非常接近的标记。

But a real life example with markers on the exact same spot can be seen on http://www.ejw.de/ejw-vor-ort/ (scroll down for the map and click on a few markers to see the spider-effect).但是可以在http://www.ejw.de/ejw-vor-ort/上看到一个在完全相同的位置带有标记的真实示例(向下滚动查看地图并单击一些标记以查看蜘蛛效果)。

That seems to be the perfect solution for your problem.这似乎是您问题的完美解决方案。

Offsetting the markers isn't a real solution if they're located in the same building.如果标记位于同一建筑物中,则偏移标记不是真正的解决方案。 What you might want to do is modify the markerclusterer.js like so:您可能想要做的是像这样修改markerclusterer.js:

  1. Add a prototype click method in the MarkerClusterer class, like so - we will override this later in the map initialize() function:在 MarkerClusterer 类中添加一个原型 click 方法,如下所示 - 我们稍后将在 map initialize() 函数中覆盖它:

     MarkerClusterer.prototype.onClick = function() { return true; };
  2. In the ClusterIcon class, add the following code AFTER the clusterclick trigger:在 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); }
  3. Then, in your initialize() function where you initialize the map and declare your MarkerClusterer object:然后,在初始化地图并声明 MarkerClusterer 对象的 initialize() 函数中:

     markerCluster = new MarkerClusterer(map, markers); // onClickZoom OVERRIDE markerCluster.onClickZoom = function() { return multiChoice(markerCluster); }

    Where multiChoice() is YOUR (yet to be written) function to popup an InfoWindow with a list of options to select from.其中 multiChoice() 是您的(尚未编写的)函数,用于弹出一个 InfoWindow,其中包含可供选择的选项列表。 Note that the markerClusterer object is passed to your function, because you will need this to determine how many markers there are in that cluster.请注意,markerClusterer 对象被传递给您的函数,因为您将需要它来确定该集群中有多少标记。 For example:例如:

     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; }

I used this alongside jQuery and it does the job:我将它与 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);

Expanding on Chaoley's answer , I implemented a function that, given a list of locations (objects with lng and lat properties) whose coordinates are exactly the same, moves them away from their original location a little bit (modifying objects in place).扩展Chaoley 的答案,我实现了一个函数,给定坐标完全相同的位置列表(具有lnglat属性的对象),将它们从原始位置移开一点(就地修改对象)。 They then form a nice circle around the center point.然后它们围绕中心点形成一个漂亮的圆圈。

I found that, for my latitude (52deg North), 0.0003 degrees of circle radius work best, and that you have to make up for the difference between latitude and longitude degrees when converted to kilometres.我发现,对于我的纬度(北 52 度),0.0003 度的圆半径效果最好,并且当转换为公里时,您必须弥补纬度和经度之间的差异。 You can find approximate conversions for your latitude here .您可以在此处找到适合您纬度的近似换算。

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 most excellent answer, updated to work with v2.0.7 of MarkerClustererPlus. @Ignatius 最出色的答案,已更新为与 MarkerClusterPlus 的 v2.0.7 一起使用。

  1. Add a prototype click method in the MarkerClusterer class, like so - we will override this later in the map initialize() function:在 MarkerClusterer 类中添加一个原型 click 方法,如下所示 - 我们稍后将在 map initialize() 函数中覆盖它:

     // BEGIN MODIFICATION (around line 715) MarkerClusterer.prototype.onClick = function() { return true; }; // END MODIFICATION
  2. In the ClusterIcon class, add the following code AFTER the click/clusterclick trigger:在 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
  3. Then, in your initialize() function where you initialize the map and declare your MarkerClusterer object:然后,在初始化地图并声明 MarkerClusterer 对象的 initialize() 函数中:

     markerCluster = new MarkerClusterer(map, markers); // onClick OVERRIDE markerCluster.onClick = function(clickedClusterIcon) { return multiChoice(clickedClusterIcon.cluster_); }

    Where multiChoice() is YOUR (yet to be written) function to popup an InfoWindow with a list of options to select from.其中 multiChoice() 是您的(尚未编写的)函数,用于弹出一个 InfoWindow,其中包含可供选择的选项列表。 Note that the markerClusterer object is passed to your function, because you will need this to determine how many markers there are in that cluster.请注意,markerClusterer 对象被传递给您的函数,因为您将需要它来确定该集群中有多少标记。 For example:例如:

     function multiChoice(clickedCluster) { if (clickedCluster.getMarkers().length > 1) { // var markers = clickedCluster.getMarkers(); // do something creative! return false; } return true; };

This is more of a stopgap 'quick and dirty' solution similar to the one Matthew Fox suggests, this time using JavaScript.这更像是一种权宜之计的“快速而肮脏”的解决方案,类似于 Matthew Fox 建议的解决方案,这次使用的是 JavaScript。

In JavaScript you can just offset the lat and long of all of your locations by adding a small random offset to both eg在 JavaScript 中,您可以通过向两者添加一个小的随机偏移量来偏移所有位置的纬度和经度,例如

myLocation[i].Latitude+ = (Math.random() / 25000)

(I found that dividing by 25000 gives enough separation but doesn't move the marker significantly from the exact location eg a specific address) (我发现除以25000可以提供足够的分离度,但不会将标记从确切位置显着移动,例如特定地址)

This makes a reasonably good job of offsetting them from one another, but only after you've zoomed in closely.这可以很好地将它们彼此抵消,但前提是您必须仔细放大。 When zoomed out, it still won't be clear that there are multiple options for the location.缩小时,仍然不清楚该位置有多个选项。

The answers above are more elegant, but I found a quick and dirty way that actually works really really incredibly well.上面的答案更优雅,但我发现了一种快速而肮脏的方法,实际上效果非常好。 You can see it in action at www.buildinglit.com您可以在www.buildinglit.com上看到它的实际效果

All I did was add a random offset to the latitude and longditude to my genxml.php page so it returns slightly different results each time with offset each time the map is created with markers.我所做的只是在我的 genxml.php 页面的纬度和经度上添加一个随机偏移量,因此每次使用标记创建地图时,它每次返回的结果都略有不同。 This sounds like a hack, but in reality you only need the markers to move a slight nudge in a random direction for them to be clickable on the map if they are overlapping.这听起来像是一个 hack,但实际上您只需要标记在随机方向上轻微移动,如果它们重叠,它们就可以在地图上点击。 It actually works really well, I would say better than the spider method because who wants to deal with that complexity and have them spring everywhere.它实际上工作得很好,我会说比蜘蛛方法更好,因为谁想要处理这种复杂性并让它们无处不在。 You just want to be able to select the marker.您只想能够选择标记。 Nudging it randomly works perfect.随机轻推它非常完美。

Here is an example of the while statement iteration node creation in my php_genxml.php这是在我的 php_genxml.php 中创建 while 语句迭代节点的示例

while ($row = @mysql_fetch_assoc($result)){ $offset = rand(0,1000)/10000000;
$offset2 = rand(0, 1000)/10000000;
$node = $dom->createElement("marker");
$newnode = $parnode->appendChild($node);
$newnode->setAttribute("name", $row['name']);
$newnode->setAttribute("address", $row['address']);
$newnode->setAttribute("lat", $row['lat'] + $offset);
$newnode->setAttribute("lng", $row['lng'] + $offset2);
$newnode->setAttribute("distance", $row['distance']);
$newnode->setAttribute("type", $row['type']);
$newnode->setAttribute("date", $row['date']);
$newnode->setAttribute("service", $row['service']);
$newnode->setAttribute("cost", $row['cost']);
$newnode->setAttribute("company", $company);

Notice under lat and long there is the +offset.请注意,在 lat 和 long 下有 + 偏移量。 from the 2 variables above.从上面的2个变量。 I had to divide random by 0,1000 by 10000000 in order to get a decimal that was randomly small enough to just barely move the markers around.我必须将随机数除以 0,1000 除以 10000000 以获得随机小到足以勉强移动标记的小数。 Feel free to tinker with that variable to get one that is more precise for your needs.随意修改该变量以获得更精确的变量以满足您的需求。

I like simple solutions so here's mine.我喜欢简单的解决方案,所以这是我的。 Instead of modifying the lib, which would make it harder to mantain.而不是修改库,这将使其更难维护。 you can simply watch the event like this您可以像这样简单地观看活动

google.maps.event.addListener(mc, "clusterclick", onClusterClick);

then you can manage it on然后你可以管理它

function onClusterClick(cluster){
    var ms = cluster.getMarkers();

i, ie, used bootstrap to show a panel with a list. i,即,使用引导程序显示带有列表的面板。 which i find much more confortable and usable than spiderfying on "crowded" places.我发现这比在“拥挤”的地方做蜘蛛更舒适和有用。 (if you are using a clusterer chances are you will end up with collisions once you spiderfy). (如果您使用的是clusterer,那么一旦您进行spiderfy,您最终会发生碰撞)。 you can check the zoom there too.你也可以在那里检查缩放。

btw.顺便提一句。 i just found leaflet and it seems to work much better, the cluster AND spiderfy works very fluidly http://leaflet.github.io/Leaflet.markercluster/example/marker-clustering-realworld.10000.html and it's open-source.我刚刚找到了传单,它似乎工作得更好,集群和 spiderfy 工作非常流畅http://leaflet.github.io/Leaflet.markercluster/example/marker-clustering-realworld.10000.html它是开源的。

For situations where there are multiple services in the same building you could offset the markers just a little, (say by .001 degree), in a radius from the actual point.对于同一建筑物中有多个服务的情况,您可以在距离实际点的半径范围内稍微偏移标记(例如 0.001 度)。 This should also produce a nice visual effect.这也应该产生一个很好的视觉效果。

Updated to work with MarkerClustererPlus.更新为与 MarkerClustererPlus 一起使用。

  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) {
    var markers = cClusterIcon.cluster_.markers_;
    var a = 360.0 / markers.length;
    for (var i=0; i < markers.length; i++)
    {
        var pos = markers[i].getPosition();
        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 finalLatLng = new google.maps.LatLng(newLat,newLng);
        markers[i].setPosition(finalLatLng);
        markers[i].setMap(cClusterIcon.cluster_.map_);
    }
    cClusterIcon.hide();
    return ;
  }
  // END MODIFICATION

Check out Marker Clusterer for V3 - this library clusters nearby points into a group marker.查看 V3 的Marker Clusterer - 这个库将附近的点聚集成一个组标记。 The map zooms in when the clusters are clicked.单击集群时地图会放大。 I'd imagine when zoomed right in you'd still have the same problem with markers on the same spot though.我想当你放大时,你仍然会在同一个地方遇到同样的问题。

I used markerclustererplus, and for me this works:我使用了markerclustererplus,对我来说这很有效:

//Code
google.maps.event.addListener(cMarkerClusterer, "clusterclick", function (c) {
            var markers = c.getMarkers();
            
            //Check Markers array for duplicate position and offset a little
            if (markers .length > 1) {
                //Check if all markers are in the same position (with 4 significant digits)
                if (markers .every((val, index, arr) => (val.getPosition().lat().toFixed(4) == arr[0].getPosition().lat().toFixed(4)) && (val.getPosition().lng().toFixed(4) == arr[0].getPosition().lng().toFixed(4)))) { /
                    //Don't modify first element
                    for (i = 1; i < markers.length; i++) {
                        var existingMarker = markers[i];
                        var pos = existingMarker.getPosition();                        
                        var quot = 360.0 / markers.length;
                        var newLat = pos.lat() + -.00008 * Math.cos(+quot * i); //+ -.00008 * Math.cos((+quot * i) / 180 * Math.PI);  //x                        
                        var newLng = pos.lng() + -.00008 * Math.sin(+quot * i);  //+ -.0008 * Math.sin((+quot * i) / 180 * Math.PI);  //Y
                        existingMarker.setPosition(new google.maps.LatLng(newLat, newLng));                        
                    }
                    let cZoom = map.getZoom();
                    map.setZoom(cZoom-1);
                    map.setZoom(cZoom+1);
                } 
            }            
        });

Check this: https://github.com/plank/MarkerClusterer检查这个: https ://github.com/plank/MarkerClusterer

This is the MarkerCluster modified to have a infoWindow in a cluster marker, when you have several markers in the same position.当您在同一位置有多个标记时,这是修改为在群集标记中有一个 infoWindow 的 MarkerCluster。

You can see how it works here: http://culturedays.ca/en/2013-activities你可以在这里看到它是如何工作的:http: //culturedays.ca/en/2013-activities

Giving offset will make the markers faraway when the user zoom in to max.当用户放大到最大时,给予偏移将使标记远离。 So i found a way to achieve that.所以我找到了实现这一目标的方法。 this may not be a proper way but it worked very well.这可能不是正确的方法,但效果很好。

// This code is in swift
for loop markers
{
//create marker
let mapMarker = GMSMarker()
mapMarker.groundAnchor = CGPosition(0.5, 0.5)
mapMarker.position = //set the CLLocation
//instead of setting marker.icon set the iconView
let image:UIIMage = UIIMage:init(named:"filename")
let imageView:UIImageView = UIImageView.init(frame:rect(0,0, ((image.width/2 * markerIndex) + image.width), image.height))
imageView.contentMode = .Right
imageView.image = image
mapMarker.iconView = imageView
mapMarker.map = mapView
}

set the zIndex of the marker so that you will see the marker icon which you want to see on top, otherwise it will animate the markers like auto swapping.设置标记的 zIndex 以便您可以在顶部看到要在顶部看到的标记图标,否则它将像自动交换一样为标记设置动画。 when the user tap the marker handle the zIndex to bring the marker on top using zIndex Swap.当用户点击标记时,处理 zIndex 以使用 zIndex Swap 将标记置于顶部。

How to get away with it.. [Swift]如何摆脱它.. [斯威夫特]

    var clusterArray = [String]()
    var pinOffSet : Double = 0
    var pinLat = yourLat
    var pinLong = yourLong
    var location = pinLat + pinLong

A new marker is about to be created?即将创建一个新的标记? check clusterArray and manipulate it's offset检查clusterArray并操作它的偏移量

 if(!clusterArray.contains(location)){
        clusterArray.append(location)
    } else {

        pinOffSet += 1
        let offWithIt = 0.00025 // reasonable offset with zoomLvl(14-16)
        switch pinOffSet {
        case 1 : pinLong = pinLong + offWithIt ; pinLat = pinLat + offWithIt
        case 2 : pinLong = pinLong + offWithIt ; pinLat = pinLat - offWithIt
        case 3 : pinLong = pinLong - offWithIt ; pinLat = pinLat - offWithIt
        case 4 : pinLong = pinLong - offWithIt ; pinLat = pinLat + offWithIt
        default : print(1)
        }


    }

result结果

在此处输入图像描述

Adding to Matthew Fox's sneaky genius answer, I have added a small random offset to each lat and lng when setting the marker object.添加到 Matthew Fox 鬼鬼祟祟的天才答案中,我在设置标记对象时为每个 lat 和 lng 添加了一个小的随机偏移量。 For example:例如:

new LatLng(getLat()+getMarkerOffset(), getLng()+getMarkerOffset()),

private static double getMarkerOffset(){
    //add tiny random offset to keep markers from dropping on top of themselves
    double offset =Math.random()/4000;
    boolean isEven = ((int)(offset *400000)) %2 ==0;
    if (isEven) return  offset;
    else        return -offset;
}

I used this http://leaflet.github.io/Leaflet.markercluster/ and perfectly works for me.我使用了这个http://leaflet.github.io/Leaflet.markercluster/并且非常适合我。 added full solution.添加了完整的解决方案。

<html lang="en">
  <head>
    <script src="https://code.jquery.com/jquery-3.2.1.js" integrity="sha256-DZAnKJ/6XZ9si04Hgrsxu/8s717jcIzLy3oi35EouyE=" crossorigin="anonymous"></script>
     <script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.0.3/leaflet.js"></script>
     <script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet.markercluster/1.0.4/leaflet.markercluster.js"></script>
     <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.0.3/leaflet.css" />
     <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/leaflet.markercluster/1.0.4/MarkerCluster.Default.css" />
 </head>
<body>
   <div id="map"></div>

    <script>
        var addressData = [
            {id: 9, name: "Ankita", title: "Manager", latitude: "33.1128019", longitude: "-96.6958939"},
            {id: 1, name: "Aarti", title: "CEO", latitude: "33.1128019", longitude: "-96.6958939"},
            {id: 2, name: "Payal", title: "Employee", latitude: "33.0460488", longitude: "-96.9983386"}];

        var addressPoints = [];
        for (i = 0; i < addressData.length; i++) {
            var marker = {
                latitude: addressData[i].latitude,
                longitude: addressData[i].longitude,
                coverage: addressData[i]
            };
            addressPoints.push(marker);
        }
        var map = L.map('map').setView(["32.9602172", "-96.7036844"], 5);
        var basemap = L.tileLayer('http://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}.png', {attribution: '&copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a> &copy; <a href="http://cartodb.com/attributions">CartoDB</a>', subdomains: 'abcd'});
        basemap.addTo(map);
        
        var markers = L.markerClusterGroup();
        for (var i = 0; i < addressPoints.length; i++) {
           // var icon1 = "app/common_assest/images/pin/redPin.png"; // set ehere you own marker pin whatever you want to set
            var currentMarker = addressPoints[i];
            console.log(currentMarker);
            var contentString = '<div class="mapinfoWindowContent">' +
                    '<div class="mapInfoTitle">Name: ' + currentMarker.coverage.name + '</div>' +
                    '<div class="mapInfoSubText">Licence: ' + currentMarker.coverage.title + '</div>' +
                    '</div>';
   // var myIcon = L.icon({// set ehere you own marker pin whatever you want to set
     // iconUrl: icon1,
    //  iconRetinaUrl: icon1,
   //                });
            var marker = L.marker(new L.LatLng(currentMarker['latitude'], currentMarker['longitude']), {
                title: currentMarker.coverage.name
            });
            marker.bindPopup(contentString);
            markers.addLayer(marker);
        }
        markers.addTo(map);
    </script>
</body>

Hope fully it will help to you easily.完全希望它对您有帮助。

The solution I've used is pretty simple.我使用的解决方案非常简单。 Just use @googlemaps/markerclusterer library in combination with the Maps JavaScript API.只需将@googlemaps/markerclusterer库与 Maps JavaScript API 结合使用即可。

Than you will need just one line after the map is filled out with your markers:在地图上填满标记后,您只需要一行:

new MarkerClusterer({ map, markers });

All information can be found here https://developers.google.com/maps/documentation/javascript/marker-clustering所有信息都可以在这里找到https://developers.google.com/maps/documentation/javascript/marker-clustering

I'm using Android's Map Cluster.我正在使用 Android 的地图集群。 These are the libs I'm using:这些是我正在使用的库:

implementation 'com.google.android.gms:play-services-places:16.0.0'   
 
implementation 'com.google.android.gms:play-services-maps:16.0.0'
 
implementation 'com.google.android.gms:play-services-location:16.0.0'
 
implementation 'com.google.maps.android:android-maps-utils:2.0.1'

The problem I was running into is that the Cluster Markers don't separate if two items have the exact same Latitude and Longitudinal points.我遇到的问题是,如果两个项目具有完全相同的纬度和经度点,则集群标记不会分开。 My fix is to scan through my array of items and if two positions match, I move their positions slightly.我的解决方法是扫描我的项目数组,如果两个位置匹配,我会稍微移动它们的位置。 Here's my code:这是我的代码:

Field Variables:字段变量:

private ArrayList<Tool> esTools;

When you're done initializing the ArrayList of Tools.当您完成初始化工具的 ArrayList 时。 From your parsing method, call this:从你的解析方法,调用这个:

loopThroughToolsListAndFixOnesThatHaveSameGeoPoint_FixStackingIssue();

Where the magic happens:奇迹发生的地方:

private void loopThroughToolsListAndFixOnesThatHaveSameGeoPoint_FixStackingIssue() { 
    DecimalFormat decimalFormatTool = new DecimalFormat("000.0000");
    decimalFormatTool.setRoundingMode(RoundingMode.DOWN);

    for(int backPointer=0; backPointer <= (esTools.size()-1); backPointer++){
        Map<String, Double> compareA = esTools.get(backPointer).getUserChosenGeopoint();
        Double compareA_Latitude = compareA.get("_latitude");
        compareA_Latitude= Double.valueOf(decimalFormatTool.format(compareA_Latitude));
        Double compareA_Longitude = compareA.get("_longitude");
        compareA_Longitude= Double.valueOf(decimalFormatTool.format(compareA_Longitude));
        System.out.println("compareA_Lat= "+ compareA_Latitude+ ", compareA_Long= "+ compareA_Longitude);
        for(int frontPointer=0; frontPointer <= (esTools.size()-1); frontPointer++){
            if(backPointer==frontPointer){
                continue;
            }
            Map<String, Double> compareB = esTools.get(frontPointer).getUserChosenGeopoint();
            Double compareB_Latitude = compareB.get("_latitude");
            compareB_Latitude= Double.valueOf(decimalFormatTool.format(compareB_Latitude));
            Double compareB_Longitude = compareB.get("_longitude");
            compareB_Longitude= Double.valueOf(decimalFormatTool.format(compareB_Longitude));

            if((compareB_Latitude.equals(compareA_Latitude)) && (compareB_Longitude.equals(compareA_Longitude))) {
                System.out.println("these tools match");

                Random randomGen = new Random();
                Double randomNumLat  = randomGen.nextDouble() * 0.00015;
                int addOrSubtractLatitude= ( randomGen.nextBoolean() ? 1 : -1 );
                randomNumLat = randomNumLat*addOrSubtractLatitude;

                Double randomNumLong = randomGen.nextDouble() * 0.00015;
                int addOrSubtractLongitude= ( randomGen.nextBoolean() ? 1 : -1 );
                randomNumLong = randomNumLong*addOrSubtractLongitude;
                System.out.println("Adding Random Latitude="+ randomNumLat + ", Longitude= "+ randomNumLong);

                System.out.println("\n");
                Map<String, Double> latitudeLongitude = new HashMap<>();
                latitudeLongitude.put("_latitude", (compareB_Latitude+ randomNumLat));
                latitudeLongitude.put("_longitude", (compareB_Longitude+ randomNumLong));
                esTools.get(frontPointer).setUserChosenGeopoint(latitudeLongitude);

            }
        }
    }
}

So what the above method does is scan through my ArrayList and see if there are any two Tools have matching points.所以上面的方法所做的就是扫描我的ArrayList,看看是否有两个Tools有匹配点。 If the Lat Long points match, move one slightly.如果 Lat Long 点匹配,则稍微移动一个。

扩展上面给出的答案,只需确保在初始化地图对象时设置 maxZoom 选项。

Adding to above answers but offering an alternative quick solution in php and wordpress.添加到上述答案,但在 php 和 wordpress 中提供了另一种快速解决方案。 For this example I am storing the location field via ACF and looping through the posts to grab that data.在本例中,我通过 ACF 存储位置字段并遍历帖子以获取该数据。

I found that storing the lat / lng in an array and check the value of that array to see if the loop matches, we can then update the value within that array with the amount we want to shift our pips by.我发现将 lat / lng 存储在一个数组中并检查该数组的值以查看循环是否匹配,然后我们可以使用我们想要移动点的数量更新该数组中的值。

//This is the value to shift the pips by. I found this worked best with markerClusterer
$add_to_latlng = 0.00003;

while ($query->have_posts()) {
    $query->the_post();
    $meta = get_post_meta(get_the_ID(), "postcode", true); //uses an acf field to store location
    $lat = $meta["lat"];
    $lng = $meta["lng"];

    if(in_array($meta["lat"],$lat_checker)){ //check if this meta matches
        
        //if matches then update the array to a new value (current value + shift value)
        // This is using the lng value for a horizontal line of pips, use lat for vertical, or both for a diagonal
        if(isset($latlng_storer[$meta["lng"]])){
            $latlng_storer[$meta["lng"]] = $latlng_storer[$meta["lng"]] + $add_to_latlng;
            $lng = $latlng_storer[$meta["lng"]];
        } else {
            $latlng_storer[$meta["lng"]] = $meta["lng"];
            $lng = $latlng_storer[$meta["lng"]];
        }

    } else {
        $lat_checker[] = $meta["lat"]; //just for simple checking of data
        $latlng_storer[$meta["lat"]] = floatval($meta["lat"]);
        $latlng_storer[$meta["lng"]] =  floatval($meta["lng"]);
    }

    $entry[] = [
        "lat" => $lat,
        "lng" => $lng,
    //...Add all the other post data here and use this array for the pips
    ];
} // end query

Once I've grabbed these locations I json encode the $entry variable and use that within my JS.一旦我抓住了这些位置,我就会对 $entry 变量进行 json 编码并在我的 JS 中使用它。

let locations = <?=json_encode($entry)?>;

I know this is a rather specific situation but I hope this helps someone along the line!我知道这是一个相当具体的情况,但我希望这有助于沿线的人!

扩展上面的答案,当你得到连接的字符串,而不是添加/减去位置(例如“37.12340-0.00069”)时,将你的原始纬度/经度转换为浮点数,例如使用 parseFloat(),然后添加或减去更正。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM