简体   繁体   中英

google maps fitBounds callback

I know there is a bounds_changed event that is triggered if the bounds have changed, however I need to know when fitBounds has completed (when bounds have changed or bounds have stayed the same).

Google has some sort of tolerance where if the bounds have changed very little it will not actually change the bounds / call bounds_changed. I need to know when this happens.

I have done this successfully with timeouts but it seems hacky and possibly prone to some errors when bounds_changed take more than 100ms to trigger.

See example: http://jsbin.com/sosurexuke/1/edit?js,console,output

Any better solutions?

Edit: If you think just checking if the map.getBounds() is the same as what you are sending fitBounds() then you'll be disappointed to know that the result of fitting to bounds is typically not even close to the bounds you send. I wrote this function thinking this might be possible

function boundsAreIdentical(bounds1, bounds2) {
        if (!bounds1 || !bounds2) return false;

        var tolerance = 0.00001;
        console.log(bounds1.getNorthEast().lat(), bounds2.getNorthEast().lat());
        console.log(bounds1.getNorthEast().lng(), bounds2.getNorthEast().lng());
        console.log(bounds1.getSouthWest().lat(), bounds2.getSouthWest().lat());
        console.log(bounds1.getSouthWest().lng(), bounds2.getSouthWest().lng());
        if (
            (Math.abs(bounds1.getNorthEast().lat() - bounds2.getNorthEast().lat()) <= tolerance) &&
            (Math.abs(bounds1.getNorthEast().lng() - bounds2.getNorthEast().lng()) <= tolerance) &&
            (Math.abs(bounds1.getSouthWest().lat() - bounds2.getSouthWest().lat()) <= tolerance) &&
            (Math.abs(bounds1.getSouthWest().lng() - bounds2.getSouthWest().lng()) <= tolerance)) {
            return true;
        }
        return false;
    }

Edit 2 years later:

It seems that in the latest experimental version of google maps (3.32) bounds_changed is fired even when the bounds are identical to current bounds.

I updated the original example to be version 3.31 which still shows the original issue.

The easiest way to solve the first part of this question (knowing when the bounds have finished changing) is to use the idle event listener .

How ever you are changing the bounds, set this event just before you are about to change them. That way, when the bounds are all settled, the map will register as idle and the idle event fires, inside which you can do your shiz. To prevent events piling on top of each other, clear it at the same time too.

You may have to fiddle a little with it. Speaking of fiddling, here's a fiddle. In this fiddle I just set the alert to happen every time:

https://jsbin.com/kapimov/edit?js,output Click the "Change Bounds" and you'll see it happen over and over:)

EDIT: To check for if fitBounds() fired when it fails , compare center before and after firing fitBounds().

Even when trying to set the bounds to the same coordinates twice, the centre appears to change and can be compared. The centre check seems to happen before the actual movement of the map for the bounds, but always changes on calling that function.

Hit the "Fit Current Bounds" button twice to see it in action; the first time 'bounds_changed' fires, the second it doesn't but centre still checks correctly. Comment out the fitBounds() function to see how centre doesn't change without it.

As denoted in the edit to the question. If you can use 3.32, then just use that. Otherwise if you need a solution that works pre-3.32 then you can simply pan the map by 1 pixel right before fitting bounds. The visual change doesnt trigger a refresh and forces the bounds to always change.

Demo: http://jsbin.com/bipekaxosa/1/edit?js,console,output

function pan(map, newCenterLatLng, offsetx, offsety, callback) {
    if (!map.getProjection()) {
        if (callback) {
            return setTimeout(pan, 1, map, newCenterLatLng, offsetx, offsety, callback);
        }
        throw new Error("You must wait until map.getProjection() is ready. Try using the callback instead");
    }

    var newCenterLatLngPixels = map.getProjection().fromLatLngToPoint(newCenterLatLng);

    var offset = new google.maps.Point(
        ((typeof (offsetx) == "number" ? offsetx : 0) / Math.pow(2, map.getZoom())) || 0,
        ((typeof (offsety) == "number" ? offsety : 0) / Math.pow(2, map.getZoom())) || 0
    );

    map.setCenter(map.getProjection().fromPointToLatLng(new google.maps.Point(
        newCenterLatLngPixels.x - offset.x,
        newCenterLatLngPixels.y + offset.y
    )));

    if (callback) {
        return callback();
    }
}

function fitBoundsAndCallback(map, bounds, callback) {
    google.maps.event.addListenerOnce(map, "bounds_changed", function() {
        if (callback) {
            callback();
        }
    });

    // Pan the map 1 pixel up so that bounds will always change
    // even in the event you are fitting to the same bounds as before
    // Remove this once the move to gmaps 3.32 as bounds_changed works always
    this.pan(map, map.getCenter(), 0, 1, function(){
      map.fitBounds(bounds);
    });
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM