Google Maps v3 fitBounds() Zoom too close for single marker
Asked Answered
G

17

106

Is there a way to set a max zoom level for fitBounds()?

My problem is that when the map is only fed one location, it zooms in as far as it can go, which really takes the map out of context and renders it useless. Perhaps I am taking the wrong approach?

Guimar answered 26/7, 2010 at 12:23 Comment(1)
#4523523 is a much better solution. Particular @Nequins answerBobbette
S
147

I like mrt's solution (especially when you don't know how many points you will be mapping or adjusting for), except it throws the marker off so that it isn't in the center of the map anymore. I simply extended it by an additional point subtracting .01 from the lat and lng as well, so it keeps the marker in the center. Works great, thanks mrt!

// Pan & Zoom map to show all markers
function fitToMarkers(markers) {

    var bounds = new google.maps.LatLngBounds();

    // Create bounds from markers
    for( var index in markers ) {
        var latlng = markers[index].getPosition();
        bounds.extend(latlng);
    }

    // Don't zoom in too far on only one marker
    if (bounds.getNorthEast().equals(bounds.getSouthWest())) {
       var extendPoint1 = new google.maps.LatLng(bounds.getNorthEast().lat() + 0.01, bounds.getNorthEast().lng() + 0.01);
       var extendPoint2 = new google.maps.LatLng(bounds.getNorthEast().lat() - 0.01, bounds.getNorthEast().lng() - 0.01);
       bounds.extend(extendPoint1);
       bounds.extend(extendPoint2);
    }

    map.fitBounds(bounds);

    // Adjusting zoom here doesn't work :/

}
Sunsunbaked answered 17/3, 2011 at 21:49 Comment(5)
Good idea on keeping the original center. The reason the zoom level can not be reliably adjusted when using the fitBounds() method is because the zoom is occurring asynchronously: #2990358Desired
This worked great for me. I did have to pass the map reference into the function "function fitToMarkers(markers, map)" on V3, but it works like a charm after that!Belvabelvedere
Love that. Good one @ryan. Worked great for me, but .01 in my case zoomed out too far, .001 hit the sweet spot.Vatic
Thanks. Like @Vatic same case , 001 hit the spot.Unwieldy
I would recommend this solution #2438183Kamchatka
S
48

You can setup your map with maxZoom in the MapOptions (api-reference) like this:

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

This would keep the map from zooming any deeper when using fitBounds() and even removes the zoom levels from the zoom control.

Scapular answered 14/5, 2011 at 10:37 Comment(2)
@candlejack So exactly as described in my answer?Scapular
You can set the maxZoom before fitting the bounds and then unset it again using map.setOptions({ maxZoom: undefined }) on the idle event fired by changing the bounds. This prevents the zoom in, zoom out effect of instead resetting the zoom in the idle event.Anallese
B
30

Another solution is to expand bounds if you detect they are too small before you execute fitBounds():

var bounds = new google.maps.LatLngBounds();
// here you extend your bound as you like
// ...
if (bounds.getNorthEast().equals(bounds.getSouthWest())) {
   var extendPoint = new google.maps.LatLng(bounds.getNorthEast().lat() + 0.01, bounds.getNorthEast().lng() + 0.01);
   bounds.extend(extendPoint);
}
map.fitBounds(bounds);
Blackmarket answered 24/1, 2011 at 10:25 Comment(0)
V
23

Once you've added all of the real bounds add these lines

var offset = 0.002;     
var center = bounds.getCenter();                            
bounds.extend(new google.maps.LatLng(center.lat() + offset, center.lng() + offset));
bounds.extend(new google.maps.LatLng(center.lat() - offset, center.lng() - offset));

it get the center of the real bounds then adds two additional points one to the northeast and one to the southwest of you center

This effectively sets the minimum zoom, change the value of offset to increase or decrease the zoom

Vladikavkaz answered 21/5, 2015 at 14:19 Comment(1)
I don't fully grasp what this is doing, but it works sweet, thanksSpermophyte
F
19
var map = new google.maps.Map(document.getElementById("map"), { maxZoom: 10 });

Using the MaxZoom option works best for not zooming to close on to the marks you have.

Flagg answered 10/7, 2012 at 9:27 Comment(1)
Fantastic! Life saver!Sewing
G
13

If it is for a single location, you can use setCenter() and setZoom() instead.

Goosy answered 26/7, 2010 at 17:1 Comment(1)
easiest solutionGentlemanfarmer
P
12

u can use

map.setOptions({
    maxZoom: [what u want],
    minZoom: [what u want]
});

this way u set the properties of the map after the map has been initialized .... u can set them as many times as u want ... but in ur case ... u can set them before fitBounds()

good luck, rarutu

Peele answered 6/4, 2013 at 19:42 Comment(0)
F
7

The way I prevent the map from zooming in to far is by adding this line of code:

var zoomOverride = map.getZoom();
        if(zoomOverride > 15) {
        zoomOverride = 15;
        }
      map.setZoom(zoomOverride);

Directly after this line:

map.setCenter(bounds.getCenter(), map.getBoundsZoomLevel(bounds));

Feel free to change the zoom level to whatever level you don’t want the map to zoom past.

If you have any problems or questions, just leave me a comment on the blog post I wrote about this at http://icode4you.net/creating-your-own-store-locator-map-how-to-prevent-the-map-from-zooming-in-too-close-on-a-single-marker

Furry answered 20/10, 2011 at 19:24 Comment(1)
I like this solution but insert the setzoom inside the if to not call it each time. There could also be a timing side effect that return 'undefined' from getzoom(). Solution: zoom = map.getZoom(); if (typeof zoom !== 'undefined' && zoom > 8) map.setZoom(8);Whomsoever
A
5

I really like mrt's solution and it works perfectly if you've always only have one point to work with. I did however find that if the bounding box was not based on one point, but the points were very close together, this could still cause the map to be zoomed in too far.

Here's a way to first check if the points are within a defined distance of each other, then if they are smaller than that minimum distance, extend the bounds by that minimum distance:

var bounds = new google.maps.LatLngBounds();
// here you extend your bound as you like

// ...

var minDistance = 0.002;
var sumA = bounds.getNorthEast().lng() - bounds.getSouthWest().lng();
var sumB = bounds.getNorthEast().lat() - bounds.getSouthWest().lat();

if((sumA < minDistance && sumA > -minDistance) 
&& (sumB < minDistance && sumB > -minDistance)){
var extendPoint1 = new google.maps.LatLng(bounds.getNorthEast().lat() + minDistance, bounds.getNorthEast().lng() + minDistance);
    var extendPoint2 = new google.maps.LatLng(bounds.getNorthEast().lat() - minDistance, bounds.getNorthEast().lng() - minDistance);
    bounds.extend(extendPoint1);
    bounds.extend(extendPoint2);
}

Hope this helps someone!

Acanthoid answered 2/4, 2012 at 4:9 Comment(0)
B
5

As for me guys i solve it by creating an idle event after fitBounds. Working perfectly. Guess that's one of the most clean solutions here

var locations = [['loc', lat, lng], ['loc', lat, lng]];
.....
for (i = 0; i < locations.length; i++) { 
  var map = new google.maps.Map(document.getElementById('map'), {
    zoom: 10
  });
  .... create markers, etc.
}
....
map.fitBounds(bounds);  
google.maps.event.addListenerOnce(map, 'idle', function() {
  if (locations.length == 1) {
    map.setZoom(11);
  }
});
Benumb answered 12/10, 2017 at 21:23 Comment(0)
P
3

This gives you a direct control upon max allowed zoom on bounds fitting.

var fitToMarkers = function(map, markers, maxZoom) {
    if (typeof maxZoom == 'undefined') maxZoom = 15;

    google.maps.event.addListenerOnce(map, 'bounds_changed', function(event) {
        if (this.getZoom() > maxZoom) {
            this.setZoom(maxZoom);
        }
    });

    var bounds = new google.maps.LatLngBounds();
    for (var m = 0; m < markers.length; m++) {
        var marker = markers[m];
        var latlng = marker.getPosition();
        bounds.extend(latlng);
    }

    map.fitBounds(bounds);
};
Pinnace answered 7/9, 2013 at 17:12 Comment(0)
S
2

I solved with this chunk, 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 (intial == true){
       if (map.getZoom() > 11) {
         map.setZoom(11);
         intial = false;
       }
    }
}); 

I used intial make the map not zooming too much loading when the eventual fitBounds permorfed, without it any zoom event over 11 would be impossible for the user.

Showcase answered 20/10, 2013 at 17:51 Comment(0)
C
1

After calling fitBounds() method, try to setup zoom level again. It will force the map to be at that zoom level whilst being centered at the right place.

Christoforo answered 25/8, 2016 at 5:9 Comment(0)
M
0

I have soulution based on limiting max zoom when fitting bounds. Works for me (tested on Win 7 - IE 9, FF 13, Chrome 19):

// When fitting bounds:
var bounds = new google.maps.LatLngBounds();
// ...
// extend bounds as you like
// ..

// now set global variable when fitting bounds
window.fittingBounds = true;
map.fitBounds(bounds);
window.fittingBounds = false;


// attach this event listener after map init
google.maps.event.addListener(map, 'zoom_changed', function() {
    // set max zoom only when fitting bounds
    if (window.fittingBounds && map.getZoom() > 16) {
        this.setZoom(16);
    }
});
Michaella answered 22/6, 2012 at 8:50 Comment(0)
B
0

And .. here is another one.
Same idea as mrt and Ryan, but

  • also works if bounds size is not exactly zero (*)
  • prevents distortion near the poles
  • uses getCenter() instead of getNorthEast()

(*) Note: If the box is already big enough, then adding those two extra points should have no effect. So we don't need any further checking.

function calcBounds(markers) {
  // bounds that contain all markers
  var bounds = new google.maps.LatLngBounds();
  // Using an underscore _.each(). Feel free to replace with standard for()
  _.each(markers, function(marker) {
    bounds.extend(marker.getPosition());
  });
  // prevent lat/lng distortion at the poles
  var lng0 = bounds.getNorthEast().lng();
  var lng1 = bounds.getSouthWest().lng();
  if (lng0 * lng1 < 0) {
    // Take the cos at the equator.
    var cos = 1;
  }
  else {
    var cos0 = Math.cos(lng0);
    var cos1 = Math.cos(lng1);
    // Prevent division by zero if the marker is exactly at the pole.
    var cos_safe = Math.max(cos0, cos1, 0.0001);
  }
  var cos0 = Math.cos(bounds.getNorthEast.lng() * Math.PI / 180);
  var cos1 = Math.cos(bounds.getSouthWest.lng() * Math.PI / 180);
  // "radius" in either direction.
  // 0.0006 seems to be an ok value for a typical city.
  // Feel free to make this value a function argument.
  var rLat = 0.0006;
  var rLng = rLat / cos_safe;
  // expand the bounds to a minimum width and height
  var center = bounds.getCenter();
  var p0 = new google.maps.LatLng(center.lat() - rLat, center.lng() - rLng);
  var p1 = new google.maps.LatLng(lat.center() + rLat, center.lng() + rLng);
  bounds.extend(p0);
  bounds.extend(p1);
  return bounds;
}

EDIT: I am not exactly sure if my ratio calculation correctly, considering we have a Mercator projection. I might re-edit this..

Bultman answered 4/1, 2013 at 17:45 Comment(0)
V
0

Its already answered here Google Maps v3: Enforcing min. zoom level when using fitBounds it works as expected :) so now if after fit bounds zoom is less then lets say 13 then you can set new zoom which you preffer

Villain answered 7/12, 2013 at 13:49 Comment(0)
D
-1

Here is my go at a solution, which also works when two markers are very close. The effective maximum zoom level is the same in both situations. So we do not end up zooming unneccesarily out, when there are more than one marker

The effect, again is ensuring a maximum zoom, without using the maxZoom option, which has the probably unwanted effect of making it impossible for the user to zoom further than the maxZoom level with the zoom control

I have calculated maxLat, minLat, maxLng and minLng beforehand...

var minLatSpan = 0.002;
if (maxLat - minLat < minLatSpan) {
  // ensures that we do not zoom in too much
  var delta = (minLatSpan - (maxLat - minLat)) / 2;
  maxLat += delta;
  minLat -= delta;
}

map.fitBounds({
  east: maxLng,
  west: minLng,
  north: maxLat,
  south: minLat,
});
Dasie answered 22/6, 2018 at 6:56 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.