Google Maps API v3: Kann ich Zoom nach fitBounds einstellen?


201

Ich habe eine Reihe von Punkten, die ich auf einer eingebetteten Google Map (API v3) zeichnen möchte. Ich möchte, dass die Grenzen alle Punkte berücksichtigen, es sei denn, die Zoomstufe ist zu niedrig (dh zu stark herausgezoomt). Mein Ansatz war wie folgt:

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

// extend bounds with each point

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

Das funktioniert nicht. Die letzte Zeile "gmap.setZoom ()" ändert die Zoomstufe der Karte nicht, wenn sie direkt nach fitBounds aufgerufen wird.

Gibt es eine Möglichkeit, die Zoomstufe einer Grenze zu ermitteln, ohne sie auf die Karte anzuwenden? Andere Ideen, um dies zu lösen?


1
Siehe stackoverflow.com/questions/4523023/using-setzoom-after-using-fitbounds-with-google-maps-api-v3
Mawg sagt, Monica am

Antworten:


337

Bearbeiten : Siehe Matt Diamonds Kommentar unten.

Verstanden! Versuche dies:

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

Passen Sie an Ihre Bedürfnisse an.


76
Tolle Lösung, hat mir total viel Ärger erspart. Ich wollte nur hinzufügen, dass Sie es mithilfe der addListenerOnce-Methode weiter vereinfachen können. Auf diese Weise müssen Sie den Listener nicht speichern und manuell entfernen, da die Methode dies für Sie erledigt.
Matt Diamond

9
Dies hat das Verhalten, dass die Karte "übersprungen" wird. Warten Sie stattdessen auf das Ereignis "zoom_change" und richten Sie es ein, bevor Sie fitBounds () aufrufen. Siehe meine Antwort unten
Benjamin Sussman

Vielen Dank! google.maps.event.addListenerOnce (map, "idle", function () {} -> funktionierte hervorragend für mein
Kartenpaket

Der Hörer wird für mich nicht ausgelöst. Ich habe dies in document.ready und window.load versucht. Irgendwelche Ideen? Das Kartenobjekt ist in Ordnung und hat auch versucht, addListener zu verwenden: `var map = $ (" # js-main-map-canvas "); var listener = google.maps.event.addListenerOnce (map, "idle", function () {alert ('hallo');}); `
Henrik Erlandsson

Henrik, versuche $ ("# js-main-map-canvas") [0] oder $ ("# js-main-map-canvas"). Get (0);
Rafael

68

Ich habe ein ähnliches Problem in einer meiner Apps gelöst. Ich war ein wenig verwirrt über Ihre Beschreibung des Problems, aber ich denke, Sie haben das gleiche Ziel, das ich hatte ...

In meiner App wollte ich eine oder mehrere Markierungen zeichnen und sicherstellen, dass auf der Karte alle angezeigt werden. Das Problem war, wenn ich mich ausschließlich auf die fitBounds-Methode verlassen würde, würde die Zoomstufe maximal sein, wenn es einen einzelnen Punkt gäbe - das war nicht gut.

Die Lösung bestand darin, fitBounds zu verwenden, wenn viele Punkte vorhanden waren, und setCenter + setZoom, wenn nur ein Punkt vorhanden war.

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

5
Ihre Antwort hat mein Problem mit Google Maps V3 gelöst. Vielen Dank!
FR6

1
Ich hatte genau das gleiche Problem und Ihre Lösung hat funktioniert! Vielen Dank!
Manubkk

Ich habe den gleichen Ansatz selbst versucht, aber er hat nicht funktioniert, weil ich setCenter () vor dem Einstellen des Zooms nicht aufgerufen habe ... Ich frage mich immer noch, warum dieser Schritt erforderlich ist, aber jetzt funktioniert er trotzdem ... danke a viel Jim!
Daveoncode

Map Center hat das Problem gelöst, das ich hatte! Netter +1
Piotr Kula

1
Vielen Dank für Ihre gute Antwort +1
Bharat Chodvadiya

44

Ich bin mehrmals auf diese Seite gekommen, um die Antwort zu erhalten, und obwohl alle vorhandenen Antworten sehr hilfreich waren, haben sie mein Problem nicht genau gelöst.

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

Grundsätzlich stellte ich fest, dass das Ereignis 'zoom_changed' die Benutzeroberfläche der Karte daran hinderte, zu "überspringen", was passierte, als ich auf das Ereignis "idle" wartete.

Hoffe das hilft jemandem!


4
Ausgezeichnet, ich hatte auch das Verhalten "Überspringen / automatisches Zoomen". Nur als Hinweis für andere Leser: Verwenden Sie "addListenerOnce" wie oben von Benjamin anstelle von "addListener" oder brechen Sie sich den Kopf, warum Ihr Browser ständig abstürzt ;-)
Geert-Jan

6
Beachten Sie auch, dass der Listener vor dem Aufruf hinzugefügt werden sollte, fitBounds()wenn Siezoom_changed
gapple

1
Vielen Dank dafür, scheint wie v4 sollte ein fitBounds (Grenzen, minZoomLevel) haben :)
Richard

3
Benjamin, ich denke es ist besser zu verwenden bounds_changed, da zoom_changedes nicht ausgelöst werden muss, wenn fitBoundsdie Zoomstufe beibehalten wird. Mein Versuch jsfiddle.net/rHeMp/10 bestätigt das nicht, aber man sollte sich nicht auf undefiniertes Verhalten verlassen.
TMS

10

Ich habe dies gerade behoben, indem ich maxZoom im Voraus eingestellt und anschließend entfernt habe. Beispielsweise:

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

Die mit Abstand beste Lösung, um ein zu starkes Vergrößern zu verhindern. Einfach und intuitiv. Kein Zeichnen und erneutes Zeichnen der Karte.
user2605793

Dies ist in der Tat der bisher beste Rundgang.
Downhillski

2
Ich habe festgestellt, dass dies nicht funktioniert, wenn Sie maxZoom unmittelbar nach dem Aufruf von fitBounds zurücksetzen, da der Zoom asynchron erfolgt (sodass maxZoom zum Zeitpunkt des Vergrößerns wieder auf null zurückgesetzt ist). Warten, bis "Leerlauf" zurückgesetzt wird, würde dies beheben, obwohl ich denke.
user987356

4

Wenn ich mich nicht irre, gehe ich davon aus, dass alle Ihre Punkte auf der Karte mit der höchstmöglichen Zoomstufe sichtbar sein sollen. Ich habe dies erreicht, indem ich die Zoomstufe der Karte auf 16 initialisiert habe (nicht sicher, ob es die höchstmögliche Zoomstufe in V3 ist).

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

Danach habe ich die Grenzen gesetzt:

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);

Ergebnis: Erfolg!


3

Ich benutze:

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

Dies verwendet die kleinere von 24 und die erforderliche Zoomstufe gemäß Ihrem Code, ändert jedoch wahrscheinlich den Zoom trotzdem und kümmert sich nicht darum, wie viel Sie herausgezoomt haben.


Ich hasse es, das zu sagen, aber so seltsam diese Antwort auch aussah, es ist das einzige, was bisher funktioniert hat, und ich habe innerhalb von 3 Tagen nach 4-5 Stunden gesucht. Wird aber immer noch nach einer besseren Lösung suchen.
Allov

3

Bitte versuchen Sie dies:

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);

2

Ich hatte das gleiche Problem und konnte es mit dem folgenden Code lösen. Dieses listener ( google.maps.addListenerOnce()) -Ereignis wird nur einmal ausgelöst, unmittelbar nachdem map.fitBounds()es ausgeführt wurde. Es besteht also keine Notwendigkeit

  1. Verfolgen Sie den Listener und entfernen Sie ihn manuell, oder
  2. Warten Sie, bis die Karte ist idle.

Zunächst wird die entsprechende Zoomstufe festgelegt, und der Benutzer kann über die anfängliche Zoomstufe hinaus vergrößern und verkleinern, da der Ereignis-Listener abgelaufen ist. Wenn beispielsweise nur google.maps.addListener()aufgerufen wurde, kann der Benutzer die angegebene Zoomstufe (in dem Fall 4) niemals überschreiten. Seit der Implementierung google.maps.addListenerOnce()kann der Benutzer auf jede von ihm gewählte Stufe zoomen.

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) 
   }
});

2

Hatte das gleiche Problem, musste viele Markierungen auf die Karte passen. Dies löste meinen Fall:

  1. Grenzen deklarieren
  2. Verwenden Sie das von koderoid bereitgestellte Schema (für jeden Markierungssatz bounds.extend(objLatLng)).
  3. Fitbounds ausführen, nachdem die Karte abgeschlossen ist:

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

2

Ich habe eine Lösung gefunden, die die Prüfung vor dem Anruf durchführt, fitBoundsdamit Sie nicht hinein- und plötzlich herauszoomen

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);
}

Sie müssen ein wenig mit der Variablen minLatSpan herumspielen, um sie an die gewünschte Stelle zu bringen. Dies hängt sowohl von der Zoomstufe als auch von den Abmessungen des Kartenbereichs ab.

Sie können auch den Längengrad anstelle des Breitengrads verwenden


Funktioniert für mich, aber ich verwende minLatSpan nicht - ich muss den Zoom nur einstellen, wenn sich 1 Marker in der Karte befindet. Daher überprüfe ich nur, ob es mehr als 1 Marker gibt.
Micer

2

Ich habe viele falsche oder zu komplizierte Lösungen gesehen und mich daher entschlossen, eine funktionierende, elegante Lösung zu veröffentlichen .

Der Grund, warum Sie setZoom()nicht wie erwartet funktionieren, ist, dass fitBounds()es asynchron ist. Es gibt also keine Garantie dafür, dass der Zoom sofort aktualisiert wird, aber Ihr Aufruf, setZoom()sich darauf zu verlassen.

Was Sie in Betracht ziehen könnten, ist das Festlegen der minZoomKartenoption vor dem Aufrufen fitBounds()und das anschließende Löschen nach Abschluss des Vorgangs (damit Benutzer bei Bedarf weiterhin manuell herauszoomen können):

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);

Wenn Sie außerdem den maximalen Zoom einschränken möchten, können Sie denselben Trick mit der maxZoomEigenschaft anwenden .

Siehe die MapOptions-Dokumente .


1

Ich verwende dies, um sicherzustellen, dass die Zoomstufe eine festgelegte Stufe nicht überschreitet, damit ich weiß, dass Satellitenbilder verfügbar sind.

Fügen Sie dem zoom_changedEreignis einen Listener hinzu . Dies hat den zusätzlichen Vorteil, dass die Zoomsteuerung auch auf der Benutzeroberfläche gesteuert wird.

Nur ausführen, setZoomwenn Sie müssen, daher ist eine ifAnweisung gegenüber Math.maxoder vorzuziehenMath.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);

So verhindern Sie, dass Sie zu weit herauszoomen:

   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);

1

In dieser Funktion müssen Sie Metadaten dynamisch hinzufügen, um den Geometrietyp nur zu speichern, da die Funktion eine beliebige Geometrie akzeptiert.

"fitGeometries" ist eine JSON-Funktion, die ein Kartenobjekt erweitert.

"geometries" ist ein generisches Javascript-Array, kein 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);
},

Alternativ habe ich die ganze Arbeit erledigt, ohne zu wissen, dass das LatLngBounds-Objekt eine expand () -Methode enthält. Das wäre viel einfacher.
CrazyEnigma

1

Diese Arbeit ist für mich mit API v3, aber mit festem Zoom:

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

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

1

Wie ich, wenn Sie nicht bereit sind, mit Zuhörern zu spielen, ist dies eine einfache Lösung, die ich mir ausgedacht habe: Fügen Sie eine Methode auf der Karte hinzu, die genau Ihren Anforderungen entspricht, wie diese:

    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});
    }

Dann können Sie anrufen, map.fitLmtdBounds(bounds)anstatt map.fitBounds(bounds)die Grenzen unter dem definierten Zoombereich festzulegen ... oder map.fitLmtdBounds(bounds,3,5)den Zoombereich zu überschreiben.


0

Bitte versuchen Sie dies.

// 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);
}

Wenn dies für Sie hilfreich sein wird.

Alles Gute


0

Nach der Berechnung der Grenzen können Sie den Abstand zwischen der oberen linken und der unteren rechten Ecke überprüfen. Dann können Sie die Zoomstufe verstehen, indem Sie die Entfernung testen (wenn die Entfernung zu weit ist, wäre die Zoomstufe niedrig). Dann können Sie auswählen, ob Sie die Setbound-Methode oder setZoom verwenden möchten.


0

Ich schlage es nicht gerne vor, aber wenn Sie es versuchen müssen - rufen Sie zuerst an

gmap.fitBounds(bounds);

Erstellen Sie dann einen neuen Thread / eine neue AsyncTask, lassen Sie ihn etwa 20-50 ms lang schlafen und rufen Sie dann auf

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

aus dem UI-Thread (verwenden Sie einen Handler oder den onPostExecute Methode für AsyncTask).

Ich weiß nicht, ob es funktioniert, nur ein Vorschlag. Ansonsten müssten Sie die Zoomstufe aus Ihren Punkten selbst berechnen, prüfen, ob sie zu niedrig ist, sie korrigieren und dann einfach anrufengmap.setZoom(correctedZoom)


0

Wenn 'bounds_changed' nicht richtig ausgelöst wird (manchmal scheint Google die Koordinaten nicht perfekt zu akzeptieren), sollten Sie stattdessen 'center_changed' verwenden.

Das Ereignis 'center_changed' wird bei jedem Aufruf von fitBounds () ausgelöst, obwohl es sofort und nicht unbedingt nach dem Verschieben der Karte ausgeführt wird.

Im Normalfall ist 'idle' immer noch der beste Ereignis-Listener, aber dies kann einigen Leuten helfen, die mit ihren fitBounds () -Aufrufen auf seltsame Probleme stoßen.

Siehe Google Maps FitBounds Callback


0

Um eine andere Lösung zu finden, stellte ich fest, dass der Ansatz "Auf bounds_changed-Ereignis warten und dann neuen Zoom festlegen" für mich nicht zuverlässig funktionierte. Ich glaube, ich habe manchmal angerufen, fitBoundsbevor die Karte vollständig initialisiert wurde, und die Initialisierung verursachte ein Ereignis bounds_changed, das den Listener verbrauchte, bevor fitBoundsdie Grenzen und die Zoomstufe geändert wurden. Am Ende hatte ich diesen Code, der bisher zu funktionieren scheint:

// 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);
    });
  }
});

0

Für mich war die einfachste Lösung:

map.fitBounds(bounds);

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

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

-3

Alles was ich getan habe ist:

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

Und es funktioniert mit der V3-API.


map.setCenter akzeptiert nur ein Attribut, latlng, und map hat keine Funktion wie getBoundsZoomLevel
Viktor

Ich dachte, es gibt eine Funktion wie getBoundsZoomLevel, nachdem ich diesen Beitrag gesehen habe, und ich bin enttäuscht, nachdem ich festgestellt habe, dass es keine gibt.
Sedran

Ich denke, getBoundsZoomLevel () war in Google Maps V2 API und nicht in V3 API verfügbar
Kush
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.