Google Maps API v3: Can I setZoom after fitBounds?

耗尽温柔 提交于 2019-11-26 06:54:25

问题


I have a set of points I want to plot on an embedded Google Map (API v3). I\'d like the bounds to accommodate all points unless the zoom level is too low (i.e., zoomed out too much). My approach has been like this:

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

// extend bounds with each point

gmap.fitBounds(bounds); 
gmap.setZoom( Math.max(6, gmap.getZoom()) );

This doesn\'t work. The last line \"gmap.setZoom()\" doesn\'t change the zoom level of the map if called directly after fitBounds.

Is there a way to get the zoom level of a bounds without applying it to the map? Other ideas to solve this?


回答1:


Edit: See Matt Diamond's comment below.

Got it! Try this:

map.fitBounds(bounds);
var listener = google.maps.event.addListener(map, "idle", function() { 
  if (map.getZoom() > 16) map.setZoom(16); 
  google.maps.event.removeListener(listener); 
});

Modify to your needs.




回答2:


I solved a similar problem in one of my apps. I was a little confused by your description of the problem, but I think you have the same goal I had...

In my app I wanted to plot a one or more markers and ensure the map was showing them all. The problem was, if I relied solely on the fitBounds method, then the zoom-level would be maxed out when there was a single point - that was no good.

The solution was to use fitBounds when there was many points, and setCenter+setZoom when there was only one point.

if (pointCount > 1) {
  map.fitBounds(mapBounds);
}
else if (pointCount == 1) {
  map.setCenter(mapBounds.getCenter());
  map.setZoom(14);
}



回答3:


I have come to this page multiple times to get the answer, and while all the existing answers were super helpful, they did not solve my problem exactly.

google.maps.event.addListenerOnce(googleMap, 'zoom_changed', function() {
    var oldZoom = googleMap.getZoom();
    googleMap.setZoom(oldZoom - 1); //Or whatever
});

Basically I found that the 'zoom_changed' event prevented the UI of the map from "skipping" which happened when i waited for the 'idle' event.

Hope this helps somebody!




回答4:


I’ve just fixed this by setting maxZoom in advance, then removing it afterwards. For example:

map.setOptions({ maxZoom: 15 });
map.fitBounds(bounds);
map.setOptions({ maxZoom: null });



回答5:


If I'm not mistaken, I'm assuming you want all your points to be visible on the map with the highest possible zoom level. I accomplished this by initializing the zoom level of the map to 16(not sure if it's the highest possible zoom level on V3).

var map = new google.maps.Map(document.getElementById('map_canvas'), {
  zoom: 16,
  center: marker_point,
  mapTypeId: google.maps.MapTypeId.ROADMAP
});

Then after that I did the bounds stuff:

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

// You can have a loop here of all you marker points
// Begin loop
bounds.extend(marker_point);
// End loop

map.fitBounds(bounds);

Result: Success!




回答6:


I use:

gmap.setZoom(24); //this looks a high enough zoom value
gmap.fitBounds(bounds); //now the fitBounds should make the zoom value only less

This will use the smaller of 24 and the necessary zoom level according to your code, however it probably changes the zoom anyway and doesn't care about how much you zoomed out.




回答7:


I had the same issue and I was able to solve it using the following code. This listener (google.maps.addListenerOnce()) event will only get fired once, right after map.fitBounds() is executed. So, there is no need to

  1. Keep track of and manually remove the listener, or
  2. Wait until the map is idle.

It sets the appropriate zoom level initially and allows the user to zoom in and out past the initial zoom level because the event listener has expired. For example, if only google.maps.addListener() was called, then the user would never be able to zoom-in past the stated zoom level (in the case, 4). Since we implemented google.maps.addListenerOnce(), the user will be able to zoom to any level he/she chooses.

map.fitBounds(bounds);

var zoom_level_for_one_marker = 4;

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



回答8:


Had the same problem, needed to fit many markers on the map. This solved my case:

  1. Declare bounds
  2. Use scheme provided by koderoid (for each marker set bounds.extend(objLatLng))
  3. Execute fitbounds AFTER map is completed:

    google.maps.event.addListenerOnce(map, 'idle', function() { 
        map.fitBounds( bounds );
    });
    



回答9:


I've found a solution that does the check before calling fitBounds so you don't zoom in and suddenly zoom out

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

// extend bounds with each point

var minLatSpan = 0.001;
if (bounds.toSpan().lat() > minLatSpan) {
    gmap.fitBounds(bounds); 
} else {
    gmap.setCenter(bounds.getCenter());
    gmap.setZoom(16);
}

You'll have to play around with the minLatSpan variable a bit to get it where you want. It will vary based on both zoom-level and the dimensions of the map canvas.

You could also use longitude instead of latitude




回答10:


Please try this:

map.fitBounds(bounds);

// CHANGE ZOOM LEVEL AFTER FITBOUNDS
zoomChangeBoundsListener = google.maps.event.addListenerOnce(map, 'bounds_changed', function(event) {
  if (this.getZoom()){
    this.setZoom(15);
  }
});
setTimeout(function(){
  google.maps.event.removeListener(zoomChangeBoundsListener)
}, 2000);



回答11:


I saw many incorrect or too complicated solutions, so decided to post a working, elegant solution.

The reason setZoom() doesn't work as you expect is that fitBounds() is asynchronous, so it gives no guarantee that it would immediately update the zoom, but your call to setZoom() relies on that.

What you might consider is setting the minZoom map option before calling fitBounds() and then clearing it after it completes (so that users can still zoom out manually if they want to):

var bounds = new google.maps.LatLngBounds();
// ... (extend bounds with all points you want to fit)

// Ensure the map does not get too zoomed out when fitting the bounds.
gmap.setOptions({minZoom: 6});
// Clear the minZoom only after the map fits the bounds (note that
// fitBounds() is asynchronous). The 'idle' event fires when the map
// becomes idle after panning or zooming.
google.maps.event.addListenerOnce(gmap, 'idle', function() {
  gmap.setOptions({minZoom: null});
});

gmap.fitBounds(bounds);

In addition, if you want to also limit the max zoom, you can apply the same trick with the maxZoom property.

See the MapOptions docs.




回答12:


I use this to ensure the zoom level does not exceed a set level so that I know satellite images will be available.

Add a listener to the zoom_changed event. This has the added benefit of controlling the zoom control on the UI also.

Only execute setZoom if you need to, so an if statement is preferable to Math.max or to Math.min

   google.maps.event.addListener(map, 'zoom_changed', function() { 
      if ( map.getZoom() > 19 ) { 
        map.setZoom(19); 
      } 
    });
    bounds = new google.maps.LatLngBounds( ... your bounds ... )
    map.fitBounds(bounds);

To prevent zooming out too far:

   google.maps.event.addListener(map, 'zoom_changed', function() { 
      if ( map.getZoom() < 6 ) { 
        map.setZoom(6); 
      } 
    });
    bounds = new google.maps.LatLngBounds( ... your bounds ... )
    map.fitBounds(bounds);



回答13:


In this function, you need to dynamically add metadata to store the geometry type only because the function accepts any geometry.

"fitGeometries" is a JSON function extending a map object.

"geometries" is an generic javascript array not an MVCArray().

geometry.metadata = { type: "point" };
var geometries = [geometry];

fitGeometries: function (geometries) {
    // go and determine the latLngBounds...
    var bounds = new google.maps.LatLngBounds();
    for (var i = 0; i < geometries.length; i++) {
        var geometry = geometries[i];
        switch (geometry.metadata.type)
        {
            case "point":
                var point = geometry.getPosition();
                bounds.extend(point);
                break;
            case "polyline":
            case "polygon": // Will only get first path
                var path = geometry.getPath();
                for (var j = 0; j < path.getLength(); j++) {
                    var point = path.getAt(j);
                    bounds.extend(point);
                }
                break;
        }
    }
    this.getMap().fitBounds(bounds);
},



回答14:


this work's for me with API v3 but with setting fixed zoom:

var bounds = new google.maps.LatLngBounds();
// extend bounds with each point

gmap.setCenter(bounds.getCenter()); 
gmap.setZoom( 6 );



回答15:


Like me, if you are not willing to play with listeners, this is a simple solution i came up with: Add a method on map which works strictly according to your requirements like this one :

    map.fitLmtdBounds = function(bounds, min, max){
        if(bounds.isEmpty()) return;
        if(typeof min == "undefined") min = 5;
        if(typeof max == "undefined") max = 15;

        var tMin = this.minZoom, tMax = this.maxZoom;
        this.setOptions({minZoom:min, maxZoom:max});
        this.fitBounds(bounds);
        this.setOptions({minZoom:tMin, maxZoom:tMax});
    }

then you may call map.fitLmtdBounds(bounds) instead of map.fitBounds(bounds) to set the bounds under defined zoom range... or map.fitLmtdBounds(bounds,3,5) to override the zoom range..




回答16:


Please try this.

// Find out what the map's zoom level is
zoom = map.getZoom();
if (zoom == 1) {
  // If the zoom level is that low, means it's looking around the
world.
  // Swap the sw and ne coords
  viewportBounds = new
google.maps.LatLngBounds(results[0].geometry.location, initialLatLng);
  map.fitBounds(viewportBounds);
}

If this will helpful to you.

All the best




回答17:


After calculation of the boundries you can check the distance between upper left and down right corner; then you can understand the zoom level by testing the distance (if distance is too far zoom level would be low) then you can select wheter using setbound method or setZoom..




回答18:


I don't like to suggest it, but if you must try - first call

gmap.fitBounds(bounds);

Then create a new Thread/AsyncTask, have it sleep for 20-50ms or so and then call

gmap.setZoom( Math.max(6, gmap.getZoom()) );

from the UI thread (use a handler or the onPostExecute method for AsyncTask).

I don't know if it works, just a suggestion. Other than that you'd have to somehow calculate the zoom level from your points yourself, check if it's too low, correct it and then just call gmap.setZoom(correctedZoom)




回答19:


If 'bounds_changed' is not firing correctly (sometimes Google doesn't seem to accept coordinates perfectly), then consider using 'center_changed' instead.

The 'center_changed' event fires every time fitBounds() is called, although it runs immediately and not necessarily after the map has moved.

In normal cases, 'idle' is still the best event listener, but this may help a couple people running into weird issues with their fitBounds() calls.

See google maps fitBounds callback




回答20:


To chime in with another solution - I found that the "listen for bounds_changed event and then set new zoom" approach didn't work reliably for me. I think that I was sometimes calling fitBounds before the map had been fully initialized, and the initialization was causing a bounds_changed event that would use up the listener, before fitBounds changed the boundaries and zoom level. I ended up with this code, which seems to work so far:

// If there's only one marker, or if the markers are all super close together,
// `fitBounds` can zoom in too far. We want to limit the maximum zoom it can
// use.
//
// `fitBounds` is asynchronous, so we need to wait until the bounds have
// changed before we know what the new zoom is, using an event handler.
//
// Sometimes this handler gets triggered by a different event, before
// `fitBounds` takes effect; that particularly seems to happen if the map
// hasn't been fully initialized yet. So we don't immediately remove the
// listener; instead, we wait until the 'idle' event, and remove it then.
//
// But 'idle' might happen before 'bounds_changed', so we can't set up the
// removal handler immediately. Set it up in the first event handler.

var removeListener = null;
var listener = google.maps.event.addListener(map, 'bounds_changed', () => {
  console.log(map.getZoom());
  if (map.getZoom() > 15) {
    map.setZoom(15);
  }

  if (!removeListener) {
    removeListener = google.maps.event.addListenerOnce(map, 'idle', () => {
      console.log('remove');
      google.maps.event.removeListener(listener);
    });
  }
});



回答21:


For me the easiest solution was this:

map.fitBounds(bounds);

function set_zoom() {
    if(map.getZoom()) {map.setZoom(map.getZoom() - 1);}
    else {setTimeout(set_zoom, 5);}
}
setTimeout(set_zoom, 5);



回答22:


google.maps.event.addListener(marker, 'dblclick', function () {
    var oldZoom = map.getZoom(); 
    map.setCenter(this.getPosition());
    map.setZoom(parseInt(oldZoom) + 1);
});



回答23:


All I did is:

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

And it works on V3 API.



来源:https://stackoverflow.com/questions/2437683/google-maps-api-v3-can-i-setzoom-after-fitbounds

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!