谷歌Maps Api相当新。我有一个数据数组,我想循环遍历并在地图上绘制。看似相当简单,但我发现的所有多标记教程都相当复杂。

让我们以谷歌网站的数据数组为例:

var locations = [
  ['Bondi Beach', -33.890542, 151.274856, 4],
  ['Coogee Beach', -33.923036, 151.259052, 5],
  ['Cronulla Beach', -34.028249, 151.157507, 3],
  ['Manly Beach', -33.80010128657071, 151.28747820854187, 2],
  ['Maroubra Beach', -33.950198, 151.259302, 1]
];

我只是想绘制所有这些点,并在单击时弹出一个infoWindow来显示名称。


当前回答

根据Daniel Vassallo的回答,下面是一个以更简单的方式处理闭包问题的版本。

因为所有的标记都有一个单独的InfoWindow,而且JavaScript并不关心你是否给对象添加了额外的属性,你所需要做的就是给标记的属性添加一个InfoWindow,然后调用InfoWindow本身的.open() !

编辑:有了足够的数据,页面加载可能会花费很多时间,因此与其使用标记构造InfoWindow,不如只在需要时进行构造。注意,用于构造InfoWindow的任何数据都必须作为属性(data)追加到Marker。还要注意,在第一次单击事件之后,infoWindow将作为它的标记的属性持久化,因此浏览器不需要不断地重构。

var locations = [
  ['Bondi Beach', -33.890542, 151.274856, 4],
  ['Coogee Beach', -33.923036, 151.259052, 5],
  ['Cronulla Beach', -34.028249, 151.157507, 3],
  ['Manly Beach', -33.80010128657071, 151.28747820854187, 2],
  ['Maroubra Beach', -33.950198, 151.259302, 1]
];

var map = new google.maps.Map(document.getElementById('map'), {
  center: new google.maps.LatLng(-33.92, 151.25)
});

for (i = 0; i < locations.length; i++) {  
  marker = new google.maps.Marker({
    position: new google.maps.LatLng(locations[i][1], locations[i][2]),
    map: map,
    data: {
      name: locations[i][0]
    }
  });
  marker.addListener('click', function() {
    if(!this.infoWindow) {
      this.infoWindow = new google.maps.InfoWindow({
        content: this.data.name;
      });
    }
    this.infoWindow.open(map,this);
  })
}

其他回答

当前地图标记和聚类算法修改后的最新最简单算法:

修改地址:https://developers.google.com/maps/documentation/javascript/marker-clustering

<!DOCTYPE Html>
<html>
<head>
<meta Content-Security-Policy="default-src  'self'; script-src 'self' 'unsafe-eval' https://*/;">
<link type="text/css" href="http://www.mapsmarker.com/wp-content/uploads/leaflet-maps-marker-icons/bar_coktail.png">
<link rel="icon" href="data:,">
<title>App</title>
</head>
<style type="text/css">
   #map {
    height: 500
}
</style>

<body>
<div id='map' style="width:100%; height:400px"></div>
<script type='text/javascript'>
    function initMap() {
        maps = new google.maps.Map(document.getElementById('map'), {
            center: new google.maps.LatLng(12.9824855, 77.637094),
            zoom: 5,
            disableDefaultUI: false,
            mapTypeId: google.maps.MapTypeId.HYBRID
        });
        var labels='ABCDEFGHIJKLMNOPQRSTUVWXYZ';
        var markerImage = 'http://www.mapsmarker.com/wp-content/uploads/leaflet-maps-marker-icons/bar_coktail.png';
        marker = locations.map(function (location, i) {
            return new google.maps.Marker({
                position: new google.maps.LatLng(location.lat, location.lng),
                map: maps,
                title: "Map",
                label: labels[i % labels.length],
                icon: markerImage
            });
        });

        var markerCluster = new MarkerClusterer(maps, marker, {
            imagePath: 'https://developers.google.com/maps/documentation/javascript/examples/markerclusterer/m'
        });
    }
    var locations = [
            { lat: 12.9824855, lng: 77.637094},
            { lat: 11.9824855, lng: 77.154312 },
            { lat: 12.8824855, lng: 77.637094},
            { lat: 10.8824855, lng: 77.054312 },
            { lat: 12.9824855, lng: 77.637094},
            { lat: 11.9824855, lng: 77.154312 },
            { lat: 12.8824855, lng: 77.637094},
            { lat: 13.8824855, lng: 77.054312 },
            { lat: 14.9824855, lng: 54.637094},
            { lat: 15.9824855, lng: 54.154312 },
            { lat: 16.8824855, lng: 53.637094},
            { lat: 17.8824855, lng: 52.054312 },
            { lat: 18.9824855, lng: 51.637094},
            { lat: 19.9824855, lng: 69.154312 },
            { lat: 20.8824855, lng: 68.637094},
            { lat: 21.8824855, lng: 67.054312 },
            { lat: 12.9824855, lng: 76.637094},
            { lat: 11.9824855, lng: 75.154312 },
            { lat: 12.8824855, lng: 74.637094},
            { lat: 10.8824855, lng: 74.054312 },
            { lat: 12.9824855, lng: 73.637094},
            { lat: 3.9824855, lng: 72.154312 },
            { lat: 2.8824855, lng: 71.637094},
            { lat: 1.8824855, lng: 70.054312 }
        ];

</script>
<script src="https://unpkg.com/@google/markerclustererplus@4.0.1/dist/markerclustererplus.min.js">
</script>
<script src="https:maps.googleapis.com/maps/api/js?key=AIzaSyDWu6_Io9xA1oerfOxE77YAv31etN4u3Dw&callback=initMap">
</script>
<script type='text/javascript'></script>

我想我将把这个放在这里,因为它似乎是那些开始使用谷歌地图API的一个流行的着陆点。在客户端呈现多个标记可能是许多映射应用程序性能下降的原因。很难进行基准测试、修复,在某些情况下甚至很难确定存在问题(由于浏览器实现的差异、客户端可用的硬件、移动设备等等)。

开始解决这个问题的最简单方法是使用标记集群解决方案。其基本思想是将地理上相似的位置分组,并显示点的数量。当用户放大地图时,这些组会展开,显示出下面的单个标记。

也许最简单的实现是markerclusterer库。基本实现如下(在库导入之后):

<script type="text/javascript">
  function initialize() {
    var center = new google.maps.LatLng(37.4419, -122.1419);

    var map = new google.maps.Map(document.getElementById('map'), {
      zoom: 3,
      center: center,
      mapTypeId: google.maps.MapTypeId.ROADMAP
    });

    var markers = [];
    for (var i = 0; i < 100; i++) {
      var location = yourData.location[i];
      var latLng = new google.maps.LatLng(location.latitude,
          location.longitude);
      var marker = new google.maps.Marker({
        position: latLng
      });
      markers.push(marker);
    }
    var markerCluster = new MarkerClusterer({map, markers});
  }
  google.maps.event.addDomListener(window, 'load', initialize);
</script>

标记不是直接添加到映射中,而是添加到数组中。然后将该数组传递给为您处理复杂计算的库,并将其附加到映射。

这些实现不仅极大地提高了客户端性能,而且在许多情况下,它们还会导致更简单、更整洁的UI,更容易在更大范围内消化数据。

谷歌提供了其他实现。

希望这能帮助到那些刚接触映射的人。

下面是另一个使用唯一标题和infoWindow文本加载多个标记的示例。使用最新的谷歌映射API V3.11进行测试。

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
    <title>Multiple Markers Google Maps</title>
    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.0/jquery.min.js"></script>
    <script
      src="https://maps.googleapis.com/maps/api/js?v=3.11&sensor=false"
      type="text/javascript"
    ></script>
    <script type="text/javascript">
      // check DOM Ready
      $(document).ready(function () {
        // execute
        (function () {
          // map options
          var options = {
            zoom: 5,
            center: new google.maps.LatLng(39.909736, -98.522109), // centered US
            mapTypeId: google.maps.MapTypeId.TERRAIN,
            mapTypeControl: false,
          };

          // init map
          var map = new google.maps.Map(
            document.getElementById('map_canvas'),
            options
          );

          // NY and CA sample Lat / Lng
          var southWest = new google.maps.LatLng(40.744656, -74.005966);
          var northEast = new google.maps.LatLng(34.052234, -118.243685);
          var lngSpan = northEast.lng() - southWest.lng();
          var latSpan = northEast.lat() - southWest.lat();

          // set multiple marker
          for (var i = 0; i < 250; i++) {
            // init markers
            var marker = new google.maps.Marker({
              position: new google.maps.LatLng(
                southWest.lat() + latSpan * Math.random(),
                southWest.lng() + lngSpan * Math.random()
              ),
              map: map,
              title: 'Click Me ' + i,
            });

            // process multiple info windows
            (function (marker, i) {
              // add click event
              google.maps.event.addListener(marker, 'click', function () {
                infowindow = new google.maps.InfoWindow({
                  content: 'Hello, World!!',
                });
                infowindow.open(map, marker);
              });
            })(marker, i);
          }
        })();
      });
    </script>
  </head>
  <body>
    <div id="map_canvas" style="width: 800px; height: 500px"></div>
  </body>
</html>

250个标记的截图:

它将自动随机化Lat/Lng,使其独一无二。如果你想测试500、1000、xxx标记和性能,这个例子将非常有用。

根据Daniel Vassallo的回答,下面是一个以更简单的方式处理闭包问题的版本。

因为所有的标记都有一个单独的InfoWindow,而且JavaScript并不关心你是否给对象添加了额外的属性,你所需要做的就是给标记的属性添加一个InfoWindow,然后调用InfoWindow本身的.open() !

编辑:有了足够的数据,页面加载可能会花费很多时间,因此与其使用标记构造InfoWindow,不如只在需要时进行构造。注意,用于构造InfoWindow的任何数据都必须作为属性(data)追加到Marker。还要注意,在第一次单击事件之后,infoWindow将作为它的标记的属性持久化,因此浏览器不需要不断地重构。

var locations = [
  ['Bondi Beach', -33.890542, 151.274856, 4],
  ['Coogee Beach', -33.923036, 151.259052, 5],
  ['Cronulla Beach', -34.028249, 151.157507, 3],
  ['Manly Beach', -33.80010128657071, 151.28747820854187, 2],
  ['Maroubra Beach', -33.950198, 151.259302, 1]
];

var map = new google.maps.Map(document.getElementById('map'), {
  center: new google.maps.LatLng(-33.92, 151.25)
});

for (i = 0; i < locations.length; i++) {  
  marker = new google.maps.Marker({
    position: new google.maps.LatLng(locations[i][1], locations[i][2]),
    map: map,
    data: {
      name: locations[i][0]
    }
  });
  marker.addListener('click', function() {
    if(!this.infoWindow) {
      this.infoWindow = new google.maps.InfoWindow({
        content: this.data.name;
      });
    }
    this.infoWindow.open(map,this);
  })
}

这是我写的另一个版本来节省地图的空间,它将infowindow指针放在标记的实际纬度和长度上,而在显示infowindow时暂时隐藏标记。

它还取消了标准的“标记”分配,并加快了速度 通过直接将新标记分配给标记创建中的标记数组进行处理。但是请注意,标记和信息窗口都添加了额外的属性,所以这种方法有点不合常规……但那是我!

在这些信息窗口问题中从未提到,标准的信息窗口不是放在标记点的lat和lng上,而是放在标记图像的顶部。标记可见性必须隐藏,否则Maps API将再次将信息窗口锚推回标记图像的顶部。

对“标记”数组中的标记的引用在标记声明后立即创建,用于以后可能需要的任何额外处理任务(隐藏/显示,抓取坐标等)。这样就省去了将标记对象赋值给'marker'的额外步骤,然后将'marker'推到标记数组中…在我的书里有很多不必要的处理。

不管怎样,对信息窗口有不同的看法,希望它能帮助你了解和激励你。

    var locations = [
      ['Bondi Beach', -33.890542, 151.274856, 4],
      ['Coogee Beach', -33.923036, 151.259052, 5],
      ['Cronulla Beach', -34.028249, 151.157507, 3],
      ['Manly Beach', -33.80010128657071, 151.28747820854187, 2],
      ['Maroubra Beach', -33.950198, 151.259302, 1]
    ];
    var map;
    var markers = [];

    function init(){
      map = new google.maps.Map(document.getElementById('map_canvas'), {
        zoom: 10,
        center: new google.maps.LatLng(-33.92, 151.25),
        mapTypeId: google.maps.MapTypeId.ROADMAP
      });

      var num_markers = locations.length;
      for (var i = 0; i < num_markers; i++) {  
        markers[i] = new google.maps.Marker({
          position: {lat:locations[i][1], lng:locations[i][2]},
          map: map,
          html: locations[i][0],
          id: i,
        });

        google.maps.event.addListener(markers[i], 'click', function(){
          var infowindow = new google.maps.InfoWindow({
            id: this.id,
            content:this.html,
            position:this.getPosition()
          });
          google.maps.event.addListenerOnce(infowindow, 'closeclick', function(){
            markers[this.id].setVisible(true);
          });
          this.setVisible(false);
          infowindow.open(map);
        });
      }
    }

google.maps.event.addDomListener(window, 'load', init);

这是一个工作的JSFiddle

额外的注意 您将注意到在给定的谷歌示例数据中,'locations'数组中的第四个位置是一个数字。在这个例子中,你也可以使用这个值作为标记id来代替当前循环的值,这样…

var num_markers = locations.length;
for (var i = 0; i < num_markers; i++) {  
  markers[i] = new google.maps.Marker({
    position: {lat:locations[i][1], lng:locations[i][2]},
    map: map,
    html: locations[i][0],
    id: locations[i][3],
  });
};