Google Maps v3: Enforcing min. zoom level when using fitBounds

88,283

Solution 1

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.

Solution 2

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().

Solution 3

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

Solution 4

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

Solution 5

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
};
Share:
88,283

Related videos on Youtube

chris
Author by

chris

Updated on January 06, 2021

Comments

  • chris
    chris over 3 years

    I'm drawing a series of markers on a map (using v3 of the maps api).

    In v2, I had the following code:

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

    And that work fine to ensure that there was always an appropriate level of detail displayed on the map.

    I'm trying to duplicate this functionality in v3, but the setZoom and fitBounds don't seem to be cooperating:

    ... 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);
    

    I've tried different permutation (moving the fitBounds before the setZoom, for example) but nothing I do with setZoom seems to affect the map. Am I missing something? Is there a way to do this?

  • chris
    chris almost 14 years
    Thank you! I've been fighting with that for a couple of hours! It does seem like a bug, though.
  • Metro Smurf
    Metro Smurf over 12 years
    This is a good method. Another method is to check the current bounds and extend the bounds, i.e., stackoverflow.com/questions/3334729/… . Though the linked answer here is only expanding the bounds by a fraction, you can use the same method to expand the bounds by a larger number; I've found that adding 7 to all corners does a good job.
  • Andrew
    Andrew over 12 years
    This is a cool solution. I noticed, however, that it works fine for me in chrome, ie, and firefox without using map.initialZoom.
  • Jan Aagaard
    Jan Aagaard over 12 years
    I don't think map.initialZoom is needed, since the event removes itself once it fires. A great solution, nevertheless.
  • Andrew
    Andrew over 12 years
    I'd like to correct my previous comment. I think that setting the initialZoom property might be needed. I had some trouble zooming in real close on IE 9 after leaving out that part of the code... Cool solution!
  • pstadler
    pstadler over 11 years
    Use google.maps.event.addListenerOnce(), so you don't have to manually remove the listener afterwards.
  • Falantar014
    Falantar014 about 11 years
    nice simple and elegant solution!
  • Izazael
    Izazael over 10 years
    Setting the minZoom and maxZoom values restricts the user from zooming beyond those values, so it doesn't help if all you want to do is set the initial zoom to something reasonable (which is what I think the OP was talking about)
  • Flygenring
    Flygenring over 10 years
    So basically pretty much exactly as I wrote in my answer?
  • Selwyn
    Selwyn over 9 years
    the variable zoomChangeBoundsListener throws an execption as its undefined and hence the map is stuck. Is this the correct code snippet
  • Derek
    Derek over 9 years
    Instead of removing the listener you can use addListenerOnce, but I am using this solution.
  • sba
    sba almost 9 years
    Because I've been looking at this the third time, here's the golfed version. Thanks @pstadler. google.maps.event.addListenerOnce(map, 'bounds_changed', function() { this.setZoom(Math.min(15, this.getZoom())); });
  • Flygenring
    Flygenring over 7 years
    This seems to be the only answer that should actually use addListener instead of repeating (and relying on remembering) to addListenerOnce before every single map.fitBounds()
  • Milk Man
    Milk Man almost 7 years
    When using addLIstenerOnce you can simply listen zoom_changed. I'm using zoom_changed just before map.fitBounds(bounds); and seems to work great on Chrome.
  • Rich Court
    Rich Court over 5 years
    @Izazael makes a good point, that isn't covered in the answer. This is great at stopping fitBounds() from zooming too far, but it also restricts the user's interaction with the map's zoom buttons. The accepted answer is the better option if you prefer that the user have full control.
  • Flygenring
    Flygenring over 5 years
    I'm not really sure how it's not covered by my answer, as I mention the second technique stating: "This would keep the map from zooming any further"
  • RubbelDeCatc
    RubbelDeCatc over 4 years
    Might not work because wit new versions. fitBounds() works asynchronous!
  • Greg
    Greg over 4 years
    I like this option because it does not cause the zoom_changed event to fire twice like many of the other options
  • Alexey Domanski
    Alexey Domanski about 4 years
    Awesome solution when max object has maxZoom option defined.