by Oliver
4. July 2014 21:56
In our customizable web portal platform discoverize we offer searching for results using a Google Map. In a recent iteration, we were trying to improve the overall map usage experience, and one thing we wanted to do was to zoom into the map as far as possible for all results to still appear on the map.
map.fitBounds(map.getBounds());
– does not do what you would like it to
The natural choice to achieve that would be to use the fitBounds method on the Map object with the bounding rectangle for the coordinates of all results. Unfortunately, though, Google chose to add a non-configurable 45px margin around that bounding box so that in a lot of cases the map appears to be zoomed out too far for what would be possible. That's why map.fitBounds(map.getBounds()); will zoom the map out!
Zoom in if you can
After a bit of searching I found a workaround on this Google Groups thread: map.fitBounds(map.getBounds()) zooms out map. The idea behind the solution provided there is to check whether the bounds to fit on the map wouldn't still fit using a higher zoom level and if yes, apply that zoom level. Since I had some problems with the code from the thread I reworked it slightly and now have this:
function myFitBounds(myMap, bounds) {
myMap.fitBounds(bounds); // calling fitBounds() here to center the map for the bounds
var overlayHelper = new google.maps.OverlayView();
overlayHelper.draw = function () {
if (!this.ready) {
var extraZoom = getExtraZoom(this.getProjection(), bounds, myMap.getBounds());
if (extraZoom > 0) {
myMap.setZoom(myMap.getZoom() + extraZoom);
}
this.ready = true;
google.maps.event.trigger(this, 'ready');
}
};
overlayHelper.setMap(myMap);
}
function getExtraZoom(projection, expectedBounds, actualBounds) {
// in: LatLngBounds bounds -> out: height and width as a Point
function getSizeInPixels(bounds) {
var sw = projection.fromLatLngToContainerPixel(bounds.getSouthWest());
var ne = projection.fromLatLngToContainerPixel(bounds.getNorthEast());
return new google.maps.Point(Math.abs(sw.y - ne.y), Math.abs(sw.x - ne.x));
}
var expectedSize = getSizeInPixels(expectedBounds),
actualSize = getSizeInPixels(actualBounds);
if (Math.floor(expectedSize.x) == 0 || Math.floor(expectedSize.y) == 0) {
return 0;
}
var qx = actualSize.x / expectedSize.x;
var qy = actualSize.y / expectedSize.y;
var min = Math.min(qx, qy);
if (min < 1) {
return 0;
}
return Math.floor(Math.log(min) / Math.LN2 /* = log2(min) */);
}
Replace map.fitBounds(bounds) with myFitBounds(map, bounds)
That's all you have to do to zoom in as far as possible while keeping your bounds on the map.
Happy coding!