API di Google Maps v3: posso impostareZoom dopo fitBounds?


201

Ho una serie di punti che voglio tracciare su una Google Map incorporata (API v3). Vorrei che i limiti accettassero tutti i punti a meno che il livello di zoom non sia troppo basso (cioè, ingrandito troppo). Il mio approccio è stato così:

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

// extend bounds with each point

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

Questo non funziona L'ultima riga "gmap.setZoom ()" non cambia il livello di zoom della mappa se chiamato direttamente dopo fitBounds.

C'è un modo per ottenere il livello di zoom di un limite senza applicarlo alla mappa? Altre idee per risolvere questo?


Risposte:


337

Modifica : vedi il commento di Matt Diamond di seguito.

Fatto! Prova questo:

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

Modifica in base alle tue esigenze.


76
Ottima soluzione, mi ha fatto risparmiare un sacco di problemi. Volevo solo aggiungere che potevi semplificarlo ulteriormente usando il metodo addListenerOnce ... in questo modo, non devi salvare l'ascoltatore e rimuoverlo manualmente, poiché il metodo si occuperà di quello per te.
Matt Diamond,

9
Questo ha il comportamento di vedere la mappa "saltare". Ascolta invece l'evento "zoom_change" e impostalo prima di chiamare fitBounds (). Vedi la mia risposta di seguito
Benjamin Sussman,

Grazie! google.maps.event.addListenerOnce (map, "idle", function () {} -> ha funzionato benissimo per il mio pacchetto di mappe per SugarCRM.
jjwdesign

L'ascoltatore non viene attivato per me. Ho provato questo in document.ready e window.load. Qualche idea? l'oggetto mappa è OK e ha provato anche addListener: `var map = $ (" # js-main-map-canvas "); var listener = google.maps.event.addListenerOnce (map, "idle", function () {alert ('hello');}); `
Henrik Erlandsson

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

68

Ho risolto un problema simile in una delle mie app. Ero un po 'confuso dalla tua descrizione del problema, ma penso che tu abbia lo stesso obiettivo che avevo ...

Nella mia app volevo tracciare uno o più marker e assicurarmi che la mappa li mostrasse tutti. Il problema era che, se mi fossi affidato esclusivamente al metodo fitBounds, il livello di zoom verrebbe raggiunto al massimo quando esisteva un singolo punto, il che non andava bene.

La soluzione era usare fitBounds quando c'erano molti punti e setCenter + setZoom quando c'era un solo punto.

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

5
La tua risposta ha risolto il mio problema con Google Maps V3. Grazie!
FR6,

1
Ho avuto lo stesso identico problema e la tua soluzione ha funzionato! Grazie!
manubkk,

Stavo provando lo stesso approccio da solo, ma non ha funzionato perché non ho invocato setCenter () prima di impostare lo zoom ... Mi chiedo ancora perché questo passaggio sia necessario, ma comunque ora funziona ... grazie a lotto Jim!
daveoncode

Map Center ha risolto il problema che stavo riscontrando! Bello uno +1
Piotr Kula il

1
Grazie per la tua buona risposta +1
Bharat Chodvadiya,

44

Sono venuto su questa pagina più volte per ottenere la risposta e, sebbene tutte le risposte esistenti siano state super utili, non hanno risolto esattamente il mio problema.

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

Fondamentalmente ho scoperto che l'evento 'zoom_changed' ha impedito all'interfaccia utente della mappa di "saltare" che è accaduto quando ho aspettato l'evento 'inattivo'.

Spero che questo aiuti qualcuno!


4
Eccellente, ho avuto anche il comportamento di "salto / zoom automatico". Proprio come una nota per gli altri lettori: assicurati di usare "addListenerOnce" come Benjamin fa sopra invece di "addListener", o spezza la testa sul perché il tuo browser si blocca continuamente ;-)
Geert-Jan

6
Si noti inoltre che l'ascoltatore deve essere aggiunto prima di chiamare fitBounds()se si utilizzazoom_changed
gapple il

1
Grazie per questo, sembra che v4 dovrebbe avere un fitBounds (limiti, minZoomLevel) :)
Richard

3
Benjamin, penso che sia meglio usarlo bounds_changed, perché zoom_changednon deve essere attivato nel caso in cui si fitBoundsmantenga il livello di zoom. Il mio tentativo jsfiddle.net/rHeMp/10 non lo conferma, ma non si dovrebbe fare affidamento su un comportamento indefinito.
TMS

10

Ho appena risolto impostando maxZoom in anticipo, quindi rimuovendolo in seguito. Per esempio:

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

La migliore soluzione di gran lunga per prevenire lo zoom troppo. Semplice ed intuitivo Nessun disegno e ri-disegno della mappa.
user2605793,

Questo è davvero il miglior walkaround finora.
Downhillski,

2
Ho scoperto che questo non funziona se si reimposta maxZoom immediatamente dopo aver chiamato fitBounds, perché lo zoom avviene in modo asincrono (quindi maxZoom torna a null al momento dello zoom). Aspettare fino a quando "inattivo" per resettarlo risolverà questo, anche se credo.
user987356,

4

Se non sbaglio, presumo che tu voglia che tutti i tuoi punti siano visibili sulla mappa con il livello di zoom più alto possibile. Ho raggiunto questo obiettivo inizializzando il livello di zoom della mappa su 16 (non sono sicuro che sia il livello di zoom più alto possibile su V3).

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

Poi ho fatto le cose al limite:

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

Risultato: successo!


3

Io uso:

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

Questo utilizzerà il minore di 24 e il livello di zoom necessario in base al codice, tuttavia probabilmente cambia comunque lo zoom e non si preoccupa di quanto hai ingrandito.


Odio dirlo, ma per quanto strana sembrasse questa risposta, è l'unica cosa che ha funzionato finora e ho cercato 4-5 ore in un arco di 3 giorni. Sarà comunque alla ricerca di una soluzione migliore.
Allov,

3

Per favore prova questo:

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

Ho avuto lo stesso problema e sono stato in grado di risolverlo utilizzando il seguente codice. Questo google.maps.addListenerOnce()evento listener ( ) verrà generato solo una volta, subito dopo l' map.fitBounds()esecuzione. Quindi, non è necessario

  1. Tenere traccia di e rimuovere manualmente l'ascoltatore o
  2. Aspetta che la mappa sia idle.

Imposta inizialmente il livello di zoom appropriato e consente all'utente di ingrandire e rimpicciolire oltre il livello di zoom iniziale poiché il listener di eventi è scaduto. Ad esempio, se solo google.maps.addListener()fosse chiamato, l'utente non sarebbe mai in grado di ingrandire oltre il livello di zoom indicato (nel caso, 4). Da quando abbiamo implementato google.maps.addListenerOnce(), l'utente sarà in grado di ingrandire a qualsiasi livello scelga.

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

Aveva lo stesso problema, necessario per adattarsi a molti indicatori sulla mappa. Questo ha risolto il mio caso:

  1. Dichiarare limiti
  2. Usa lo schema fornito da koderoid (per ogni set di marker bounds.extend(objLatLng))
  3. Esegui fitbound DOPO che la mappa è stata completata:

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

2

Ho trovato una soluzione che effettua il controllo prima di chiamare in fitBoundsmodo da non ingrandire e rimpicciolire improvvisamente

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

Dovrai giocare un po 'con la variabile minLatSpan per portarla dove vuoi. Varia in base al livello di zoom e alle dimensioni dell'area di disegno della mappa.

Puoi anche usare la longitudine invece della latitudine


Funziona per me, ma non sto usando minLatSpan - Ho bisogno di impostare lo zoom solo quando 1 marker è sulla mappa. Pertanto sto solo verificando se ci sono più di 1 marcatori.
Micer,

2

Ho visto molte soluzioni errate o troppo complicate, quindi ho deciso di pubblicare una soluzione funzionante ed elegante .

Il motivo setZoom()non funziona come previsto è che fitBounds()è asincrono, quindi non garantisce che aggiornerà immediatamente lo zoom, ma la tua chiamata setZoom()si affida a questo.

Ciò che potresti prendere in considerazione è impostare l' minZoomopzione della mappa prima di chiamare fitBounds()e quindi cancellarla al termine (in modo che gli utenti possano comunque eseguire lo zoom indietro manualmente se lo desiderano):

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

Inoltre, se si desidera limitare anche lo zoom massimo, è possibile applicare lo stesso trucco con la maxZoomproprietà.

Consulta i documenti di MapOptions .


1

Lo uso per garantire che il livello di zoom non superi un livello impostato in modo da sapere che le immagini satellitari saranno disponibili.

Aggiungi un ascoltatore zoom_changedall'evento. Ciò ha l'ulteriore vantaggio di controllare anche il controllo dello zoom sull'interfaccia utente.

Eseguire solo setZoomse necessario, quindi ifun'istruzione è preferibile Math.maxao aMath.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);

Per evitare lo zoom indietro troppo lontano:

   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 questa funzione, è necessario aggiungere dinamicamente metadati per memorizzare il tipo di geometria solo perché la funzione accetta qualsiasi geometria.

"fitGeometries" è una funzione JSON che estende un oggetto mappa.

"geometries" è un array javascript generico non un 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);
},

In alternativa, ho fatto tutto il lavoro senza sapere che esiste un metodo ext () sull'oggetto LatLngBounds. Questo sarebbe molto più semplice.
CrazyEnigma,

1

questo lavoro è per me con API v3 ma con impostazione dello zoom fisso:

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

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

1

Come me, se non sei disposto a giocare con gli ascoltatori, questa è una soluzione semplice che mi è venuta in mente: aggiungi un metodo sulla mappa che funzioni rigorosamente in base alle tue esigenze come questa:

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

quindi è possibile chiamare map.fitLmtdBounds(bounds)invece di map.fitBounds(bounds)impostare i limiti nell'ambito dell'intervallo di zoom definito ... o map.fitLmtdBounds(bounds,3,5)di ignorare l'intervallo di zoom ..


0

Per favore, prova questo.

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

Se questo ti sarà utile.

Ti auguro il meglio


0

Dopo il calcolo dei confini è possibile verificare la distanza tra l'angolo superiore sinistro e quello inferiore destro; quindi è possibile comprendere il livello di zoom testando la distanza (se la distanza è troppo elevata, il livello di zoom sarebbe basso) quindi è possibile selezionare se utilizzare il metodo di rilegatura o setZoom ..


0

Non mi piace suggerirlo, ma se devi provare - prima chiamata

gmap.fitBounds(bounds);

Quindi crea un nuovo Thread / AsyncTask, fallo dormire per 20-50ms circa e poi chiama

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

dal thread dell'interfaccia utente (utilizzare un gestore o il onPostExecutemetodo per AsyncTask).

Non so se funziona, solo un suggerimento. A parte questo, dovresti in qualche modo calcolare tu stesso il livello di zoom dai tuoi punti, controllare se è troppo basso, correggerlo e quindi chiamaregmap.setZoom(correctedZoom)


0

Se "bounds_changed" non si attiva correttamente (a volte Google non sembra accettare le coordinate perfettamente), considera invece l'uso di "center_changed".

L'evento 'center_changed' viene generato ogni volta che viene chiamato fitBounds (), sebbene venga eseguito immediatamente e non necessariamente dopo lo spostamento della mappa.

In casi normali, "inattivo" è ancora il miglior ascoltatore di eventi, ma ciò può aiutare un paio di persone che incontrano strani problemi con le loro chiamate fitBounds ().

Vedi callback fitBounds di Google Maps


0

Per entrare in contatto con un'altra soluzione, ho scoperto che l'approccio "ascolta l'evento bounds_changed e quindi imposta il nuovo zoom" non ha funzionato in modo affidabile per me. Penso che a volte stavo chiamandofitBounds prima che la mappa fosse stata completamente inizializzata e l'inizializzazione stava causando un evento bounds_changed che avrebbe utilizzato l'ascoltatore, prima di fitBoundsmodificare i confini e il livello di zoom. Ho finito con questo codice, che sembra funzionare finora:

// 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

Per me la soluzione più semplice era questa:

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

Tutto quello che ho fatto è:

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

E funziona su API V3.


map.setCenter accetta solo un attributo, latlng e map non ha funzioni come getBoundsZoomLevel
Viktor

Ho pensato che ci fosse una funzione come getBoundsZoomLevel dopo aver visto questo post, e sono deluso dopo aver realizzato che non lo è.
Sedran,

penso che getBoundsZoomLevel () fosse disponibile nell'API V2 di Google Maps e non nell'API V3
Kush,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.