Remove The Padding From The Google Map API v3 fitBounds() Method

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!

Comments (7) -

Sean Wohltman
Sean Wohltman United States
3/5/2015 10:42:44 PM #

Just an update, this is a great work around but there is a floating point error, it was also pointed out on the original Google groups thread but basically:

"you should replace the return value with:
return new google.maps.Point( Math.round(10000 * Math.abs(sw.y - ne.y)) / 10000, Math.round(10000 * Math.abs(sw.x - ne.x)) / 10000 );"

Reply

Chris
Chris United States
3/13/2015 2:17:01 AM #

Hi there -- I don't mean to sound desperate, but I am really wanting to use this code, I am a total javascript newbie, and I am looking for HTML examples of how you implemented it. I can not figure out how to make this work. Every time I replace map.fitBound(bounds) with the myFitBounds, I get an error that says "undefined is not a function (evaluating 'map.myFitBounds(map, bounds)'). I can not figure out how to make this work. Any help you can offer would be incredibly appreciated.

Reply

Chris
Chris United States
3/13/2015 2:18:01 AM #

Also, if you're looking for an example page, mine is at www.chrisrodkey.com/.../airportinfo2.cfm

Reply

Andris
Andris Hungary
5/8/2015 12:50:30 AM #

This seems to be a cleaner solution, with no tricks involved: stackoverflow.com/.../google-maps-v3-how-to-calculate-the-zoom-level-for-a-given-bounds

Reply

Nayru
Nayru Germany
9/16/2015 9:26:58 AM #

I'm using this! Thanks man, good work Smile

Reply

Martin Kirk
Martin Kirk Denmark
9/11/2017 10:28:43 AM #

This script works really good .... UNTIL you try fitting bounds in the pacific ocean, when the bounds cross or come close to the dateline (180 <-> -180 deg)

Reply

Roberto Junior
Roberto Junior Singapore
11/30/2017 10:43:32 AM #

Since June 2017, the method fitBounds has a second parameter that represents the size of the padding. For those who want to remove it, you just need to pass 0.

    Map.map.fitBounds(bounds, 0);


New method signature:
    
    fitBounds(bounds:LatLngBounds|LatLngBoundsLiteral, padding?:number)

Reply

Add comment

  Country flag

biuquote
  • Comment
  • Preview
Loading

About Oliver

shades-of-orange.com code blog logo I build web applications using ASP.NET and have a passion for javascript. Enjoy MVC 4 and Orchard CMS, and I do TDD whenever I can. I like clean code. Love to spend time with my wife and our children. My profile on Stack Exchange, a network of free, community-driven Q&A sites

About Anton

shades-of-orange.com code blog logo I'm a software developer at teamaton. I code in C# and work with MVC, Orchard, SpecFlow, Coypu and NHibernate. I enjoy beach volleyball, board games and Coke.