ChatGPT解决这个技术问题 Extra ChatGPT

Using setZoom() after using fitBounds() with Google Maps API V3

I'm using fitBounds() to set the zoom level on my map too include all the markers currently displayed. However, when I have only one marker visible, the zoom level is 100% (... which zoom level 20 I think...). However, I don't want it to be that far zoomed in so the user can adjust the position of the marker without having to zoom out.

I have the following code:

var marker = this.map.createMarker(view.latlng, this.markerNumber);
this.map.bounds.extend(view.latlng);
this.map.map.setCenter(this.map.bounds.getCenter());
this.map.map.fitBounds(this.map.bounds);
if (this.markerNumber === 1) {
  this.map.map.setZoom(16);
}
this.markerNumber++;

where this.map.bounds was previously defined as:

this.map.bounds = new google.maps.LatLngBounds();

However, the problem I am having is that the line this.map.map.setZoom(16); doesn't work if I use this.map.map.fitBounds(this.map.bounds);, however, I know that line of code is correct because when I comment out the fitBound() line, the setZoom() magically starts functioning.

Any ideas how I resolve this? I'm thinking of setting a maxZoom level as an alternative if I can't get this working.

The .map.map is on purpose there or is a mistake?If possible upload a test page and provide a linkso we can see the problem with more ease.
I'm having the same problem. Would love to know a fix.
.map.map was there on purpose. The first referred to my map object and the second one to the google map object. I've since cleaned this issue from my code.

H
Herman Schaaf

Alright, I've figured it out. Apparently, the fitbounds() happens asynchronously, so you have to wait for a bounds_changed event before setting zoom works.

map = this.map.map;

map.fitBounds(this.map.bounds);
zoomChangeBoundsListener = 
    google.maps.event.addListenerOnce(map, 'bounds_changed', function(event) {
        if (this.getZoom()){
            this.setZoom(16);
        }
});
setTimeout(function(){google.maps.event.removeListener(zoomChangeBoundsListener)}, 2000);

Update: See @Nequin's answer using addListenerOnce for a better solution that doesn't require a timeout.


Nice solution, worked for me as well. Although you could have done addListenerOnce() which would do away with the removeListener() call.
In addition to using addListenerOnce, I would advise using setTimeout to remove the listener. I had a case where the bounds did not change because the markers were in close proximity to each other. With this code, the user would be unable to zoom (at least once).
@MikePurcell & h0tw1r3: I edited the code to add your suggestions, thanks! Didn't test it, so hope I didn't introduce any silly mistakes.
@Herman.....thnx herman i have stuck on this problem for about 3 hours...thnx again...
I had to put the removeListener inside the addListener callback function. Otherwise the execution would remove the listener even before calling it.
M
Mathias Bynens
google.maps.event.addListenerOnce(yourMap, 'bounds_changed', function(event) {
  if (this.getZoom() > 15) {
    this.setZoom(15);
  }
});

This solution works better… instead of waiting on timeout to remove listener. Call this directly before using fitBounds (I believe calling after will work as well).


Good solution. Could make it better by using google.maps.event.addListenerOnce instead of adding and then removing the listener.
I’ve taken the liberty to edit the answer to use addListenerOnce.
That solution doesn't work for me. this.getZoom() always is undefined in the callback and this.setZoom() has no effect.
Perfect, best answer
Remember the problems using this I would instead use the reference to the map passed to the event handler, like this: if (yourMap.getZoom() > 15) { ... }. It sounds that @horace had problems with it and probably this refers to the current class where the implementation is being done or the google.maps.event instance. Avoid using this if you simply want to use the passed-in reference to your map.
E
Emery Lapinski

I found the additional zoom to be a little jarring. If you set the maxZoom option before calling fitBounds (and then unset it in the callback) you can avoid it:

map.setOptions({
    maxZoom: 10
});

map.setCenter(new google.maps.LatLng(-89, -179)); // make sure it changes so the idle listener gets called back

map.fitBounds(bounds);

var listener = google.maps.event.addListenerOnce(map, "idle", function()
{
    map.setOptions({
        maxZoom: 999
    });
});

much better solution, because setting the zoom after bounds changed (as the other answers suggested) won't be smooth, will be very ugly actually.
V
Vishwanath

I have simple and dirty solution. Use If else ...

var marker = this.map.createMarker(view.latlng, this.markerNumber);
this.map.bounds.extend(view.latlng);
this.map.map.setCenter(this.map.bounds.getCenter()); 
if (this.markerNumber === 1) {
  this.map.map.setZoom(16);
} else {
   this.map.map.fitBounds(this.map.bounds);
}       
this.markerNumber++;

But do you know why the two don't work together? I don't see why these are incompatible when called serially.
M
Mike G

I just added one line to the function addBounds(position) and it fixed it, as the following shows:

    addBounds: function(position) {
        this.get('bounds', new google.maps.LatLngBounds()).extend(this._latLng(position));
        this.get('map').fitBounds(this.get('bounds'));
        this.get('map').setZoom(16);//line added
        return this;
    },

h
horace

All the solutions with event listeners didn't work for me (this.getZoom() always is undefined in the callback and this.setZoom() has no effect).

I came up with this solution which worked nicely:

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