How to affect the "grace margin" of map.fitBounds()
Asked Answered
D

2

18

In Google maps API v2, map of our country was nicely fitted to 700x400px map with the following:

map.getBoundsZoomLevel(<bounds of our country>)

But in API v3, the map.fitBounds() method doesn't fit it at that zoom level to 700x400 - it zooms out one level.

This means that map.fitBounds() counts with some "grace margin" or something.

How can I affect the size of this margin?

Damalus answered 23/3, 2012 at 17:24 Comment(10)
Could the "grace margin" be a percentage of your desired bounds? If this margin is fixed, you could input an even smaller, measured, bounds to fitBounds(), so that the end of the grace margin matched your originally desired bounds. Hope this made sense.Enounce
@HeitorChang, this would be really hacky and clumsy solution, but anyway without knowing how exactly the "grace margin" is computed by fitBounds(), you cannot do that.Damalus
After hacking around, I concluded that v3 fitBounds() will zoom in only if there's at least a 45 pixel padding (to both sides of the rectangle defined by your bounds) on the long dimension, at that zoom level. Supposing it's a close call, the map will stay zoomed out, leaving a big margin. I hope this may be useful to you.Enounce
After reading this: #6049475 I'm afraid there's no other solution besides writing my own fitBounds. Shitty api v3, yet another flaw!Damalus
Do you know a workaround to get bounds of that "grace margin"?Rutland
@Damalus did you find an answer to your question? I am also interested in this margin, and especially how it's calculated. Or, in other words, how to transform the result of getBounds() to be used for fitBounds() and have no zoom effect after. Thanks!Inclinable
No, I don't know the answer. If I knew it I would post it here.Damalus
In many cases, you could replace your map bounds by a reference to the map center coordinates and the zoom level.Haya
@Tomas, how do you get your country bounds? Did you define them manually or do you get them from the API?Haya
@MrUpsidown: manually.Damalus
S
2

Here's a solution that will zoom into the map as far as possible without a custom margin. You should be able to adapt it to account for some margin if you want to.

My solution is based on this comment in a Google Groups thread. Unfortunately, the call to helper.getProjection() always returned undefined, so I adapted the above answer a bit and came up with this working code.

Just replace your existing calls to map.fitBounds(bounds) with myFitBounds(map, bounds):

function myFitBounds(myMap, bounds) {
    myMap.fitBounds(bounds);

    var overlayHelper = new google.maps.OverlayView();
    overlayHelper.draw = function () {
        if (!this.ready) {
            var projection = this.getProjection(),
                zoom = getExtraZoom(projection, bounds, myMap.getBounds());
            if (zoom > 0) {
                myMap.setZoom(myMap.getZoom() + zoom);
            }
            this.ready = true;
            google.maps.event.trigger(this, 'ready');
        }
    };
    overlayHelper.setMap(myMap);
}

// LatLngBounds b1, b2 -> zoom increment
function getExtraZoom(projection, expectedBounds, actualBounds) {
    var expectedSize = getSizeInPixels(projection, expectedBounds),
        actualSize = getSizeInPixels(projection, 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.log(2) /* = log2(min) */);
}

// LatLngBounds bnds -> height and width as a Point
function getSizeInPixels(projection, 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));
}
Soucy answered 30/6, 2014 at 13:0 Comment(1)
This worked well for me, but I had to modify one line to deal with a floating point rounding error when expectedSize is exactly double actualSize. Changed the return statement of getSizeInPixels to: 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 );Oldster
G
0

Now, 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)
Glue answered 30/11, 2017 at 9:35 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.