GoogleMaps v3: 在使用 fitBound 时强制最小缩放级别

我正在地图上绘制一系列标记(使用地图 api 的 v3)。

在 v2中,我有以下代码:

  bounds = new GLatLngBounds();


... loop thru and put markers on map ...
bounds.extend(point);
... end looping


map.setCenter(bounds.getCenter());
var level = map.getBoundsZoomLevel(bounds);
if ( level == 1 )
level = 5;
map.setZoom(level > 6 ? 6 : level);

这样可以很好地确保在地图上总是有一个合适的细节层次。

我试图在 v3中复制这个功能,但 setZoom 和 fitBound 似乎不合作:

... loop thru and put markers on the map
var ll = new google.maps.LatLng(p.lat,p.lng);
bounds.extend(ll);
... end loop


var zoom = map.getZoom();
map.setZoom(zoom > 6 ? 6 : zoom);
map.fitBounds(bounds);

我尝试了不同的排列(例如,在 setZoom 之前移动 fitBound) ,但是我对 setZoom 所做的任何操作似乎都不会影响地图。我错过了什么吗?有办法吗?

91168 次浏览

At this discussion on Google Groups I discovered that basically when you do a fitBounds, the zoom happens asynchronously so you need to capture the zoom and bounds change event. The code in the final post worked for me with a small modification... as it stands it stops you zooming greater than 15 completely, so used the idea from the fourth post to have a flag set to only do it the first time.

// Do other stuff to set up map
var map = new google.maps.Map(mapElement, myOptions);
// This is needed to set the zoom after fitbounds,
google.maps.event.addListener(map, 'zoom_changed', function() {
zoomChangeBoundsListener =
google.maps.event.addListener(map, 'bounds_changed', function(event) {
if (this.getZoom() > 15 && this.initialZoom == true) {
// Change max/min zoom here
this.setZoom(15);
this.initialZoom = false;
}
google.maps.event.removeListener(zoomChangeBoundsListener);
});
});
map.initialZoom = true;
map.fitBounds(bounds);

Hope that helps,

Anthony.

Without trying it, I'd say you should be able to do it just by having fitBounds() before you get the zoom level, i.e.

map.fitBounds(bounds);
var zoom = map.getZoom();
map.setZoom(zoom > 6 ? 6 : zoom);

If you did try that and it didn't work, you can setup your map with minZoom in the MapOptions (api-reference) like this:

var map = new google.maps.Map(document.getElementById("map"), { minZoom: 6 });

This would keep the map from zooming any further out when using fitBounds().

Anthony's solution is very nice. I only needed to fix the zoom for the inital page load (ensuring that you weren't too far zoomed in to start with) and this did the trick for me:

var zoomChangeBoundsListener =
google.maps.event.addListener(map, 'bounds_changed', function(event) {
google.maps.event.removeListener(zoomChangeBoundsListener);
map.setZoom( Math.min( 15, map.getZoom() ) );
});




map.fitBounds( zoomBounds );

In my case, I simply wanted to set the zoom level to one less than what google maps chose for me during fitBounds. The purpose was to use fitBounds, but also ensure no markers were under any map tools, etc.

My map is created early and then a number of other dynamic components of the page have an opportunity to add markers, calling fitBounds after each addition.

This is in the initial block where the map object is originally created...

var mapZoom = null;

Then this is added to each block where a marker is added, right before the map.fitBounds is called...

google.maps.event.addListenerOnce(map, 'bounds_changed', function() {
if (mapZoom != map.getZoom()) {
mapZoom = (map.getZoom() - 1);
map.setZoom(mapZoom);
}
});

When using 'bounds_changed' without the check in place, the map zoomed out once for every marker regardless of whether it needed it or not. Conversely, when I used 'zoom_changed', I would sometimes have markers under map tools because the zoom didn't actually change. Now it is always triggered, but the check ensures that it only zooms out once and only when needed.

Hope this helps.

When you call map.fitBounds() on one item - the map may zoom in too closely. To fix this, simply add 'maxZoom' to mapOptions...

var mapOptions = {
maxZoom: 15
};

Since Google Maps V3 is event driven, you can tell the API to set back the zoom to a proper amount when the zoom_changed event triggers:

var initial = true
google.maps.event.addListener(map, "zoom_changed", function() {
if (initial == true){
if (map.getZoom() > 11) {
map.setZoom(11);
initial = false;
}
}
});

I used initial to make the map not zooming too much when the eventual fitBounds is permorfed, but to let the user zoom as much as he/she wants. Without the condition any zoom event over 11 would be possible for the user.

You can also set the maxZoom option just before calling fitBounds() and reset the value afterwards:

if(!bounds.isEmpty()) {
var originalMaxZoom = map.maxZoom;
map.setOptions({maxZoom: 18});
map.fitBounds(bounds);
map.setOptions({maxZoom: originalMaxZoom});
}

I found the following to work quite nicely. It is a variant on Ryan's answer to https://stackoverflow.com/questions/3334729/.... It guarantees to show an area of at least two times the value of offset in degrees.

const center = bounds.getCenter()
const offset = 0.01
const northEast = new google.maps.LatLng(
center.lat() + offset,
center.lng() + offset
)
const southWest = new google.maps.LatLng(
center.lat() - offset,
center.lng() - offset
)
const minBounds = new google.maps.LatLngBounds(southWest, northEast)
map.fitBounds(bounds.union(minBounds))

I just had the same task to solve and used a simple function to solve it.

it doesn't care how many Markers are in the bounds - if there are a lot and the zoom is already far away, this zooms a little bit out, but when there is only one marker (or a lot very close to each other), then the zoomout is significant (customizable with the extendBy variable):

var extendBounds = function() {
// Extends the Bounds so that the Zoom Level on fitBounds() is a bit farer away
var extendBy = 0.005;
var point1 = new google.maps.LatLng(
bounds.getNorthEast().lat() + extendBy,
bounds.getNorthEast().lng() + extendBy
)
var point2 = new google.maps.LatLng(
bounds.getSouthWest().lat() - extendBy,
bounds.getSouthWest().lng() - extendBy
)
bounds.extend(point1);
bounds.extend(point2);
}

To use it, I use an own function to do the fitBounds():
map is my GoogleMap Object

var refreshBounds = function() {
extendBounds();
map.fitBounds(bounds);
}