Google Maps v3 fitBounds () Zoom troppo vicino per un singolo indicatore


92

C'è un modo per impostare un livello di zoom massimo per fitBounds()? Il mio problema è che quando la mappa è alimentata solo da una posizione, ingrandisce il più possibile, il che porta la mappa fuori contesto e la rende inutile. Forse sto prendendo l'approccio sbagliato?

Grazie in anticipo!


2
stackoverflow.com/questions/4523023/… è una soluzione molto migliore. Particolare @Nequins risposta
Kennet

Risposte:


138

Mi piace la soluzione di mrt (specialmente quando non sai per quanti punti mapperai o aggiusterai), tranne che getta via il marcatore in modo che non sia più al centro della mappa. L'ho semplicemente esteso di un punto aggiuntivo sottraendo .01 anche da lat e lng, in modo che mantenga il marker al centro. Funziona alla grande, grazie signor!

// Pan & Zoom map to show all markers
function fitToMarkers(markers) {

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

    // Create bounds from markers
    for( var index in markers ) {
        var latlng = markers[index].getPosition();
        bounds.extend(latlng);
    }

    // Don't zoom in too far on only one marker
    if (bounds.getNorthEast().equals(bounds.getSouthWest())) {
       var extendPoint1 = new google.maps.LatLng(bounds.getNorthEast().lat() + 0.01, bounds.getNorthEast().lng() + 0.01);
       var extendPoint2 = new google.maps.LatLng(bounds.getNorthEast().lat() - 0.01, bounds.getNorthEast().lng() - 0.01);
       bounds.extend(extendPoint1);
       bounds.extend(extendPoint2);
    }

    map.fitBounds(bounds);

    // Adjusting zoom here doesn't work :/

}

4
Buona idea su come mantenere il centro originale. Il motivo per cui il livello di zoom non può essere regolato in modo affidabile quando si utilizza il fitBounds()metodo è perché lo zoom avviene in modo asincrono: stackoverflow.com/questions/2989858/…
Metro Smurf

1
Questo ha funzionato benissimo per me. Ho dovuto passare il riferimento della mappa alla funzione "funzione fitToMarkers (marker, mappa)" su V3, ma dopo funziona a meraviglia!
Shane,

4
Amore che. Bravo @ryan. Ha funzionato alla grande per me, ma .01 nel mio caso ha ingrandito troppo, .001 ha colpito il punto giusto.
willdanceforfun

Grazie. Come nello stesso caso di @willdanceforfun, 001 ha centrato il punto.
Goran Jakovljevic

1
Vorrei raccomandare questa soluzione stackoverflow.com/questions/2437683/...
NinjaOnSafari

38

Puoi impostare la tua mappa con maxZoomin MapOptions (api-reference) in questo modo:

var map = new google.maps.Map(document.getElementById("map"), { maxZoom: 10 });

Ciò impedirebbe alla mappa di ingrandire ulteriormente quando si utilizza fitBounds()e persino rimuove i livelli di zoom dal controllo dello zoom.


@ Candlejack Quindi esattamente come descritto nella mia risposta?
Flygenring

6
È possibile impostare la maxZoomprima di montare i limiti e poi disinserire nuovamente utilizzando map.setOptions({ maxZoom: undefined })sul idleevento generato modificando i limiti. Ciò impedisce l'effetto zoom in, zoom out invece di reimpostare lo zoom idlenell'evento.
El Yobo

29

Un'altra soluzione è espandere i limiti se rilevi che sono troppo piccoli prima di eseguire fitBounds ():

var bounds = new google.maps.LatLngBounds();
// here you extend your bound as you like
// ...
if (bounds.getNorthEast().equals(bounds.getSouthWest())) {
   var extendPoint = new google.maps.LatLng(bounds.getNorthEast().lat() + 0.01, bounds.getNorthEast().lng() + 0.01);
   bounds.extend(extendPoint);
}
map.fitBounds(bounds);

19
var map = new google.maps.Map(document.getElementById("map"), { maxZoom: 10 });

L'uso dell'opzione MaxZoom funziona meglio per non zoomare per avvicinarsi ai segni che hai.


Fantastico! Salvavita!
Jaypee

18

Dopo aver aggiunto tutti i limiti reali, aggiungi queste linee

var offset = 0.002;     
var center = bounds.getCenter();                            
bounds.extend(new google.maps.LatLng(center.lat() + offset, center.lng() + offset));
bounds.extend(new google.maps.LatLng(center.lat() - offset, center.lng() - offset));

ottiene il centro dei limiti reali, quindi aggiunge due punti aggiuntivi uno a nord-est e uno a sud-ovest del centro

Questo imposta efficacemente lo zoom minimo, cambia il valore di offset per aumentare o diminuire lo zoom


12

Se è per una singola posizione, è possibile utilizzare invece setCenter () e setZoom ().


soluzione più semplice
Alberto M

11

puoi usare

map.setOptions({
    maxZoom: [what u want],
    minZoom: [what u want]
});

in questo modo puoi impostare le proprietà della mappa dopo che la mappa è stata inizializzata .... puoi impostarle tutte le volte che vuoi ... ma nel tuo caso ... puoi impostarle prima di fitBounds ()

buona fortuna, rarutu


7

Il modo in cui evito che la mappa si ingrandisca troppo è aggiungendo questa riga di codice:

var zoomOverride = map.getZoom();
        if(zoomOverride > 15) {
        zoomOverride = 15;
        }
      map.setZoom(zoomOverride);

Subito dopo questa riga:

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

Sentiti libero di cambiare il livello di zoom a qualsiasi livello non desideri che la mappa venga ingrandita.

Se hai problemi o domande, lasciami un commento sul post del blog che ho scritto su questo su http://icode4you.net/creating-your-own-store-locator-map-how-to-prevent-the- mappa-da-zoom-in-troppo-vicino-su-un-singolo-marker


1
Mi piace questa soluzione ma inserisco il setzoom all'interno del if per non richiamarlo ogni volta. Potrebbe anche esserci un effetto collaterale del tempo che restituisce "undefined" da getzoom (). Soluzione: zoom = map.getZoom (); if (typeof zoom! == 'undefined' && zoom> 8) map.setZoom (8);
Le Droid

5

Mi piace molto la soluzione di mrt e funziona perfettamente se hai sempre un solo punto su cui lavorare. Tuttavia, ho riscontrato che se il riquadro di delimitazione non si basava su un punto, ma i punti erano molto vicini tra loro, ciò potrebbe comunque causare uno zoom eccessivo della mappa.

Ecco un modo per verificare prima se i punti si trovano a una distanza definita l'uno dall'altro, quindi se sono inferiori a quella distanza minima, estendi i limiti di quella distanza minima:

var bounds = new google.maps.LatLngBounds();
// here you extend your bound as you like

// ...

var minDistance = 0.002;
var sumA = bounds.getNorthEast().lng() - bounds.getSouthWest().lng();
var sumB = bounds.getNorthEast().lat() - bounds.getSouthWest().lat();

if((sumA < minDistance && sumA > -minDistance) 
&& (sumB < minDistance && sumB > -minDistance)){
var extendPoint1 = new google.maps.LatLng(bounds.getNorthEast().lat() + minDistance, bounds.getNorthEast().lng() + minDistance);
    var extendPoint2 = new google.maps.LatLng(bounds.getNorthEast().lat() - minDistance, bounds.getNorthEast().lng() - minDistance);
    bounds.extend(extendPoint1);
    bounds.extend(extendPoint2);
}

Spero che questo aiuti qualcuno!


3

Questo ti dà un controllo diretto sullo zoom massimo consentito sull'adattamento dei limiti.

var fitToMarkers = function(map, markers, maxZoom) {
    if (typeof maxZoom == 'undefined') maxZoom = 15;

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

    var bounds = new google.maps.LatLngBounds();
    for (var m = 0; m < markers.length; m++) {
        var marker = markers[m];
        var latlng = marker.getPosition();
        bounds.extend(latlng);
    }

    map.fitBounds(bounds);
};

3

Per quanto mi riguarda ragazzi, lo risolvo creando un evento di inattività dopo fitBounds. Funziona perfettamente. Immagino che sia una delle soluzioni più pulite qui

var locations = [['loc', lat, lng], ['loc', lat, lng]];
.....
for (i = 0; i < locations.length; i++) { 
  var map = new google.maps.Map(document.getElementById('map'), {
    zoom: 10
  });
  .... create markers, etc.
}
....
map.fitBounds(bounds);  
google.maps.event.addListenerOnce(map, 'idle', function() {
  if (locations.length == 1) {
    map.setZoom(11);
  }
});

2

Ho risolto con questo pezzo, poiché Google Maps V3 è guidato dagli eventi:

puoi dire all'API di riportare lo zoom su un valore adeguato quando si attiva l'evento zoom_changed :

var initial = true
google.maps.event.addListener(map, "zoom_changed", function() {
    if (intial == true){
       if (map.getZoom() > 11) {
         map.setZoom(11);
         intial = false;
       }
    }
}); 

Ho usato intial per fare in modo che la mappa non ingrandisse troppo caricando quando l'eventuale fitBounds è penetrato, senza di esso qualsiasi evento di zoom oltre 11 sarebbe impossibile per l'utente.


1

Dopo aver chiamato il fitBounds()metodo, prova a impostare nuovamente il livello di zoom. Forzerà la mappa ad essere a quel livello di zoom pur essendo centrata nel punto giusto.


0

Ho un'animazione basata sulla limitazione dello zoom massimo quando si adattano i limiti. Funziona per me (testato su Win 7 - IE 9, FF 13, Chrome 19):

// When fitting bounds:
var bounds = new google.maps.LatLngBounds();
// ...
// extend bounds as you like
// ..

// now set global variable when fitting bounds
window.fittingBounds = true;
map.fitBounds(bounds);
window.fittingBounds = false;


// attach this event listener after map init
google.maps.event.addListener(map, 'zoom_changed', function() {
    // set max zoom only when fitting bounds
    if (window.fittingBounds && map.getZoom() > 16) {
        this.setZoom(16);
    }
});

0

E ... eccone un altro.
Stessa idea di Mrt e Ryan, ma

  • funziona anche se la dimensione dei limiti non è esattamente zero (*)
  • previene la distorsione vicino ai poli
  • usa getCenter () invece di getNorthEast ()

(*) Nota: se la scatola è già abbastanza grande, l'aggiunta di questi due punti extra non dovrebbe avere alcun effetto. Quindi non abbiamo bisogno di ulteriori controlli.

function calcBounds(markers) {
  // bounds that contain all markers
  var bounds = new google.maps.LatLngBounds();
  // Using an underscore _.each(). Feel free to replace with standard for()
  _.each(markers, function(marker) {
    bounds.extend(marker.getPosition());
  });
  // prevent lat/lng distortion at the poles
  var lng0 = bounds.getNorthEast().lng();
  var lng1 = bounds.getSouthWest().lng();
  if (lng0 * lng1 < 0) {
    // Take the cos at the equator.
    var cos = 1;
  }
  else {
    var cos0 = Math.cos(lng0);
    var cos1 = Math.cos(lng1);
    // Prevent division by zero if the marker is exactly at the pole.
    var cos_safe = Math.max(cos0, cos1, 0.0001);
  }
  var cos0 = Math.cos(bounds.getNorthEast.lng() * Math.PI / 180);
  var cos1 = Math.cos(bounds.getSouthWest.lng() * Math.PI / 180);
  // "radius" in either direction.
  // 0.0006 seems to be an ok value for a typical city.
  // Feel free to make this value a function argument.
  var rLat = 0.0006;
  var rLng = rLat / cos_safe;
  // expand the bounds to a minimum width and height
  var center = bounds.getCenter();
  var p0 = new google.maps.LatLng(center.lat() - rLat, center.lng() - rLng);
  var p1 = new google.maps.LatLng(lat.center() + rLat, center.lng() + rLng);
  bounds.extend(p0);
  bounds.extend(p1);
  return bounds;
}

EDIT: Non sono esattamente sicuro che il mio calcolo del rapporto sia corretto, considerando che abbiamo una proiezione di Mercatore. Potrei modificare di nuovo questo ..



-1

Ecco la mia soluzione, che funziona anche quando due marker sono molto vicini. Il livello di zoom massimo effettivo è lo stesso in entrambe le situazioni. Quindi non finiamo per ridurre lo zoom inutilmente, quando ci sono più di un marker

L'effetto, ancora una volta, è garantire uno zoom massimo, senza utilizzare l'opzione maxZoom, che ha l'effetto probabilmente indesiderato di rendere impossibile all'utente di ingrandire oltre il livello maxZoom con il controllo dello zoom

Ho calcolato maxLat, minLat, maxLng e minLng in anticipo ...

var minLatSpan = 0.002;
if (maxLat - minLat < minLatSpan) {
  // ensures that we do not zoom in too much
  var delta = (minLatSpan - (maxLat - minLat)) / 2;
  maxLat += delta;
  minLat -= delta;
}

map.fitBounds({
  east: maxLng,
  west: minLng,
  north: maxLat,
  south: minLat,
});
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.