[javascript] Google지도 API V3-정확히 동일한 지점에 여러 마커

이것에 비트가 붙어 있습니다. JSON을 통해 지리적 좌표 목록을 검색하고 Google지도에 표시합니다. 정확히 같은 지점에 두 개 이상의 마커가있는 경우를 제외하고는 모두 잘 작동합니다. API는 맨 위의 마커 1 개만 표시합니다. 이것은 내가 생각하기에 충분히 공평하지만 어떻게 든 그들을 모두 표시하는 방법을 찾고 싶습니다.

Google을 검색하고 몇 가지 솔루션을 찾았지만 대부분 API의 V2 용이거나 그다지 좋지 않은 것 같습니다. 이상적으로는 일종의 그룹 마커를 클릭 한 다음 마커가 모두있는 지점 주변에 클러스터 된 마커를 표시하는 솔루션을 원합니다.

누구든지이 문제가 있거나 비슷한 문제가 있었고 해결책을 공유하고 싶습니까?



답변

OverlappingMarkerSpiderfier를 살펴보십시오 .
데모 페이지가 있지만 정확히 같은 지점에있는 마커는 표시되지 않고 서로 매우 가까운 마커 만 표시됩니다.

그러나 똑같은 지점에 마커가있는 실제 사례는 http://www.ejw.de/ejw-vor-ort/에서 볼 수 있습니다 (지도를 아래로 스크롤하고 몇 개의 마커를 클릭하여 거미 효과를 볼 수 있습니다. ).

그것은 당신의 문제에 대한 완벽한 해결책 인 것 같습니다.


답변

마커가 같은 건물에있는 경우 마커 오프셋은 실제 솔루션이 아닙니다. 원하는 것은 markerclusterer.js를 다음과 같이 수정하는 것입니다.

  1. MarkerClusterer 클래스에 프로토 타입 클릭 메소드를 다음과 같이 추가합니다. 나중에 map initialize () 함수에서이를 재정의합니다.

    MarkerClusterer.prototype.onClick = function() {
        return true;
    };
  2. 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. 그런 다음지도를 초기화하고 MarkerClusterer 객체를 선언하는 initialize () 함수에서 다음을 수행합니다.

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

    multiChoice ()는 선택할 수있는 옵션 목록이있는 InfoWindow를 팝업하는 (아직 작성되지 않은) 함수입니다. 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의 답변을 확장하여 좌표가 정확히 동일한 위치 ( lnglat속성이있는 객체) 목록이 주어지면 원래 위치에서 약간 이동 (객체를 제자리에서 수정)하는 기능을 구현했습니다. 그런 다음 중심점 주위에 멋진 원을 형성합니다.

위도 (북위 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에서 작동하도록 업데이트되었습니다.

  1. MarkerClusterer 클래스에 프로토 타입 클릭 메소드를 다음과 같이 추가합니다. 나중에 map initialize () 함수에서이를 재정의합니다.

    // BEGIN MODIFICATION (around line 715)
    MarkerClusterer.prototype.onClick = function() {
        return true;
    };
    // END MODIFICATION
  2. 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. 그런 다음지도를 초기화하고 MarkerClusterer 객체를 선언하는 initialize () 함수에서 다음을 수행합니다.

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

    multiChoice ()는 선택할 수있는 옵션 목록이있는 InfoWindow를 팝업하는 (아직 작성되지 않은) 함수입니다. markerClusterer 객체는 해당 클러스터에있는 마커 수를 확인하는 데 필요하므로 함수에 전달됩니다. 예를 들면 :

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

답변

위의 답변은 더 우아하지만 실제로 정말 믿을 수 없을 정도로 잘 작동하는 빠르고 더러운 방법을 찾았습니다. www.buildinglit.com 에서 실제로 확인할 수 있습니다.

내가 한 것은 위도와 경도에 임의의 오프셋을 내 genxml.php 페이지에 추가하여지도가 마커로 생성 될 때마다 오프셋과 함께 매번 약간 다른 결과를 반환합니다. 이것은 해킹처럼 들리지만 실제로는 마커가 겹치는 경우지도에서 클릭 할 수 있도록 임의의 방향으로 약간 이동하려면 마커 만 필요합니다. 그것은 실제로 정말 잘 작동합니다. 누가 그 복잡성을 다루고 모든 곳에서 봄을 원하기 때문에 거미 방법보다 더 잘 말할 것입니다. 마커를 선택할 수 있기를 원합니다. 무작위로 Nudging 완벽하게 작동합니다.

다음은 내 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);

위도 및 경도 아래에 + offset이 있습니다. 위의 두 변수에서. 나는 마커를 간신히 움직일 수있을 정도로 무작위로 작은 소수를 얻기 위해 random을 0,1000으로 10000000으로 나누어야했다. 필요에 더 정확한 변수를 얻으려면 해당 변수를 자유롭게 수정하십시오.


답변

같은 건물에 여러 서비스가있는 상황에서는 실제 지점에서 반경 내에서 마커를 약간 (예 : .001도) 오프셋 할 수 있습니다. 이것은 또한 멋진 시각 효과를 생성합니다.