Javascript Google Maps V3:仅在视口中显示标记 - 清除标记问题
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2943474/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Google Maps V3: Only show markers in viewport - Clear markers issue
提问by Thijs
I like to create a map with Google Maps that can handle large amounts of markers (over 10.000). To not slow down the map I've created a XML-file that only outputs the markers that are inside the current viewport.
我喜欢使用可以处理大量标记(超过 10.000)的 Google Maps 创建地图。为了不减慢地图速度,我创建了一个 XML 文件,该文件仅输出当前视口内的标记。
First, I use initialize() to setup the map options:
首先,我使用 initialize() 来设置地图选项:
function initialize() {
var myLatlng = new google.maps.LatLng(51.25503952021694,3.27392578125);
var myOptions = {
zoom: 8,
center: myLatlng,
mapTypeId: google.maps.MapTypeId.ROADMAP
}
var map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);
google.maps.event.addListener(map, 'tilesloaded', function () {
loadMapFromCurrentBounds(map);
});
}
When the event 'tilesloaded' is finished, I use loadMapFromCurrentBounds(), this functions will get the current bounds and sends a request to the XML-file to show the markers that are inside the current viewport:
当事件 'tilesloaded' 完成时,我使用 loadMapFromCurrentBounds(),此函数将获取当前边界并向 XML 文件发送请求以显示当前视口内的标记:
function loadMapFromCurrentBounds(map) {
// First, determine the map bounds
var bounds = map.getBounds();
// Then the points
var swPoint = bounds.getSouthWest();
var nePoint = bounds.getNorthEast();
// Now, each individual coordinate
var swLat = swPoint.lat();
var swLng = swPoint.lng();
var neLat = nePoint.lat();
var neLng = nePoint.lng();
downloadUrl("mapsxml.php?swLat="+swLat+"&swLng="+swLng+"&neLat="+neLat+"&neLng="+neLng+"", function(data) {
var xml = parseXml(data);
var markers = xml.documentElement.getElementsByTagName("marker");
var infoWindow = new google.maps.InfoWindow;
for (var i = 0; i < markers.length; i++) {
var address = markers[i].getAttribute("address");
var type = markers[i].getAttribute("type");
var name = markers[i].getAttribute("name");
var point = new google.maps.LatLng(
parseFloat(markers[i].getAttribute("lat")),
parseFloat(markers[i].getAttribute("lng"))
);
var html = "<b>" + name + "</b> <br/>" + address;
var icon = customIcons[type] || {};
var marker = new google.maps.Marker({
map: map,
position: point,
icon: icon.icon,
shadow: icon.shadow});
bindInfoWindow(marker, map, infoWindow, html);
}
})
}
This is working great, however, the current code doesn't offload markers that aren't in de viewport anymore. Besides that, it loads markers again who are already loaded, that slows down the map really fast when moving the map a view times in the same area.
这很好用,但是,当前的代码不再卸载不在视口中的标记。除此之外,它会再次加载已经加载的标记,当在同一区域移动地图一个视图时间时,这会非常快地减慢地图速度。
So when the viewport changes, I like to clear the whole map first before loading new markers. What is the best way to do this?
所以当视口发生变化时,我喜欢在加载新标记之前先清除整个地图。做这个的最好方式是什么?
回答by Thijs
You need to add another Event Listener to the map:
您需要向地图添加另一个事件侦听器:
google.maps.event.addListener(map,'bounds_changed', removeMarkers);
See herefor more on removing all markers from a google map - unfortunately I dont think it can be done with one call. So you will have to write the removeMarkers or something similar which will have to iterate through all the markers on the map removing them individually like so:
有关从谷歌地图中删除所有标记的更多信息,请参见此处- 不幸的是,我认为一次调用无法完成。因此,您必须编写 removeMarkers 或类似的东西,它们必须遍历地图上的所有标记,将它们单独删除,如下所示:
markersArray[i].setMap(null);
I don't know whether it's quicker to check if the marker is in the viewport before removing by using:
我不知道在使用以下方法删除之前检查标记是否在视口中是否更快:
map.getBounds();
回答by CrazyEnigma
You may want to check out this thread. Daniel answered this quite nicely.
你可能想看看这个线程。丹尼尔很好地回答了这个问题。
What's the most efficient way to create routes on google maps from gps files?
Also, bounds_changed is the first opportunity to call your function. tilesloaded, will be called constantly. The viewport may contain more than one tile to fill the viewport.
此外, bounds_changed 是调用您的函数的第一个机会。tileloaded,将不断被调用。视口可能包含多个瓦片来填充视口。
Alternatively, you can also do a setVisible(false).
或者,您也可以执行 setVisible(false)。
In order to remove the marker, you may need to remove the listeners.
为了移除标记,您可能需要移除侦听器。
google.maps.event.clearInstanceListeners(marker);
marker.setMap(null);
markers.remove(marker);
delete marker;
回答by Konstantin Voronov
Due to the following explanation using 'tilesloaded' or 'bounds_changed' would be very wrong and cause unwilling continuous firings. Instead you would want to use 'idle' event which will fire once the user has stopped panning/zooming.
由于以下解释,使用 'tilesloaded' 或 'bounds_changed' 将是非常错误的并导致不情愿的连续射击。相反,您可能希望使用 'idle' 事件,一旦用户停止平移/缩放,该事件就会触发。
google.maps.event.addListener(map, 'idle', loadMapFromCurrentBounds);
google.maps.event.addListener(map, 'idle', loadMapFromCurrentBounds);
https://developers.google.com/maps/articles/toomanymarkers#viewportmarkermanagement
https://developers.google.com/maps/articles/toomanymarkers#viewportmarkermanagement
回答by webjunkie
This article goes through it pretty nicely: Dynamically loading thousands of markers in Google Maps
这篇文章很好地介绍了它: 在 Google 地图中动态加载数千个标记
- dynamically load markers until we reach a threshold
- keep a hashtable of markers that have already been added
- after the threshold has been reached, remove markers that aren't currently within the viewport
- remove all markers from the map when the user has zoomed out, and don't load any markers until the user zooms back to a reasonable level
- 动态加载标记,直到我们达到阈值
- 保留已添加标记的哈希表
- 达到阈值后,删除当前不在视口内的标记
- 当用户缩小时从地图中删除所有标记,并且在用户放大到合理水平之前不要加载任何标记
回答by tim
Your original function seems like a lot of code. I'd do something like this:
您的原始函数看起来像很多代码。我会做这样的事情:
if( map.getBounds().contains(markers[i].getPosition()) ) {
myMarkerDisplayFunction(markers[i]);
}

