Google Maps API v3: ¿Puedo configurarZoom después de fitBounds?

201

Tengo un conjunto de puntos que quiero trazar en un mapa de Google incrustado (API v3). Me gustaría que los límites acomoden todos los puntos a menos que el nivel de zoom sea demasiado bajo (es decir, se haya alejado demasiado). Mi enfoque ha sido así:

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

// extend bounds with each point

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

Esto no funciona La última línea "gmap.setZoom ()" no cambia el nivel de zoom del mapa si se llama directamente después de fitBounds.

¿Hay alguna manera de obtener el nivel de zoom de un límite sin aplicarlo al mapa? ¿Otras ideas para resolver esto?

Chris
fuente
1
Vea stackoverflow.com/questions/4523023/using-setzoom-after-using-fitbounds-with-google-maps-api-v3
Mawg dice que reinstale a Monica el

Respuestas:

337

Editar : Vea el comentario de Matt Diamond a continuación.

¡Entendido! Prueba esto:

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

Modifique a sus necesidades.

LGT
fuente
76
Gran solución, me ahorró muchos problemas. Solo quería agregar que podría simplificarlo aún más utilizando el método addListenerOnce ... de esa manera, no tiene que guardar el oyente y eliminarlo manualmente, ya que el método se encargará de eso por usted.
Matt Diamond
9
Esto tiene el comportamiento de ver el mapa "saltar". En su lugar, escuche el evento "zoom_change" y configúrelo antes de llamar a fitBounds (). Vea mi respuesta a continuación
Benjamin Sussman
¡Gracias! google.maps.event.addListenerOnce (map, "idle", function () {} -> funcionó muy bien para mi paquete de mapas para SugarCRM.
jjwdesign
El oyente no se activa por mí. Intenté esto en document.ready y window.load. ¿Algunas ideas? El objeto map está bien y también probó addListener: `var map = $ (" # js-main-map-canvas "); var listener = google.maps.event.addListenerOnce (map, "idle", function () {alert ('hello');}); `
Henrik Erlandsson
Henrik, prueba $ ("# js-main-map-canvas") [0] o $ ("# js-main-map-canvas"). Get (0);
Rafael
68

Resolví un problema similar en una de mis aplicaciones. Estaba un poco confundido por tu descripción del problema, pero creo que tienes el mismo objetivo que yo tenía ...

En mi aplicación, quería trazar uno o más marcadores y asegurarme de que el mapa los mostrara a todos. El problema era que si confiaba únicamente en el método fitBounds, el nivel de zoom se maximizaría cuando hubiera un solo punto; eso no era bueno.

La solución fue usar fitBounds cuando había muchos puntos, y setCenter + setZoom cuando solo había un punto.

if (pointCount > 1) {
  map.fitBounds(mapBounds);
}
else if (pointCount == 1) {
  map.setCenter(mapBounds.getCenter());
  map.setZoom(14);
}
Jim Garvin
fuente
55
Su respuesta ha resuelto mi problema con Google Maps V3. ¡Gracias!
FR6
1
Tuve exactamente el mismo problema, ¡y su solución funcionó! ¡Gracias!
manubkk
Estaba probando el mismo enfoque por mí mismo, pero no funcionó porque no estaba invocando setCenter () antes de configurar el zoom ... Todavía me pregunto por qué es necesario este paso, pero de todos modos ahora funciona ... gracias mucho Jim!
daveoncode
¡Map Center resolvió el problema que tenía! Nice one +1
Piotr Kula
1
Gracias por su buena respuesta +1
Bharat Chodvadiya
44

He visitado esta página varias veces para obtener la respuesta, y aunque todas las respuestas existentes fueron muy útiles, no resolvieron mi problema exactamente.

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

Básicamente descubrí que el evento 'zoom_changed' evitó que la interfaz de usuario del mapa se "saltara", lo que sucedió cuando esperé el evento 'inactivo'.

Espero que esto ayude a alguien!

Benjamin Sussman
fuente
44
Excelente, también tuve el comportamiento de 'omisión / zoom automático'. Solo como una nota para otros lectores: asegúrese de usar "addListenerOnce" como lo hace Benjamin arriba en lugar de "addListener", o no pensar por qué su navegador se bloquea todo el tiempo ;-)
Geert-Jan
66
También tenga en cuenta que el oyente debe añadirse antes de llamar fitBounds()si se utilizazoom_changed
gapple
1
Gracias por esto, parece que v4 debería tener un fitBounds (límites, minZoomLevel) :)
Richard
3
Benjamin, creo que es mejor usarlo bounds_changed, porque zoom_changedno tiene que activarse en el caso cuando se fitBoundsmantiene el nivel de zoom. Mi intento jsfiddle.net/rHeMp/10 no lo confirma, pero no se debe confiar en un comportamiento indefinido.
TMS
10

Acabo de arreglar esto configurando maxZoom por adelantado y luego eliminándolo. Por ejemplo:

map.setOptions({ maxZoom: 15 });
map.fitBounds(bounds);
map.setOptions({ maxZoom: null });
Robin Whittleton
fuente
La mejor solución para evitar el acercamiento demasiado. Simple e intuitivo. Sin dibujar y volver a dibujar el mapa.
user2605793
Este es de hecho el mejor recorrido hasta ahora.
Downhillski
2
Descubrí que esto no funciona si restableces maxZoom inmediatamente después de llamar a fitBounds, porque el zoom ocurre de forma asincrónica (por lo que maxZoom vuelve a ser nulo cuando se acerca). Esperar hasta que esté "inactivo" para restablecerlo solucionaría esto, aunque supongo.
user987356
4

Si no me equivoco, supongo que desea que todos sus puntos sean visibles en el mapa con el nivel de zoom más alto posible. Logré esto inicializando el nivel de zoom del mapa a 16 (no estoy seguro si es el nivel de zoom más alto posible en V3).

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

Luego, después de eso, hice los límites:

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

Resultado: ¡Éxito!

Lester S
fuente
3

Yo suelo:

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

Esto usará el menor de 24 y el nivel de zoom necesario de acuerdo con su código, sin embargo, probablemente cambia el zoom de todos modos y no le importa cuánto haya alejado.

ytg
fuente
Odio decir esto, pero por extraño que parezca esta respuesta, es lo único que funcionó hasta ahora y he estado buscando durante 4-5 horas en un lapso de 3 días. Sin embargo, seguirá buscando una solución mejor.
Allov
3

Por favor intente esto:

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);
Atif Tariq
fuente
2

Tuve el mismo problema y pude resolverlo usando el siguiente código. Este google.maps.addListenerOnce()evento listener ( ) solo se activará una vez, justo después de que map.fitBounds()se ejecute. Entonces, no hay necesidad de

  1. Realizar un seguimiento y eliminar manualmente el oyente, o
  2. Espera hasta que el mapa esté idle.

Establece el nivel de zoom apropiado inicialmente y permite al usuario acercar y alejar más allá del nivel de zoom inicial porque el detector de eventos ha expirado. Por ejemplo, si solo google.maps.addListener()se llamó, entonces el usuario nunca podrá hacer zoom más allá del nivel de zoom establecido (en el caso, 4). Desde que implementamos google.maps.addListenerOnce(), el usuario podrá hacer zoom a cualquier nivel que elija.

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) 
   }
});
9 monos
fuente
2

Tenía el mismo problema, necesitaba colocar muchos marcadores en el mapa. Esto resolvió mi caso:

  1. Declarar límites
  2. Utilice el esquema proporcionado por koderoid (para cada conjunto de marcadores bounds.extend(objLatLng))
  3. Ejecutar fitbounds DESPUÉS de completar el mapa:

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

He encontrado una solución que hace la comprobación antes de llamar fitBoundspara que no se acerque y se aleje repentinamente

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

Tendrás que jugar un poco con la variable minLatSpan para llegar a donde quieras. Varía según el nivel de zoom y las dimensiones del lienzo del mapa.

También puedes usar longitud en lugar de latitud

CheapSteaks
fuente
Funciona para mí, pero no estoy usando minLatSpan: necesito establecer el zoom solo cuando hay 1 marcador en el mapa. Por lo tanto, solo estoy verificando si hay más de 1 marcadores.
Micer
2

Vi muchas soluciones incorrectas o demasiado complicadas, así que decidí publicar una solución elegante y funcional .

La razón por la setZoom()que no funciona como espera es que fitBounds()es asincrónica, por lo que no garantiza que actualizará el zoom de inmediato, pero su llamado a setZoom()confiar en eso.

Lo que puede considerar es configurar la minZoomopción de mapa antes de llamar fitBounds()y luego borrarla después de que se complete (para que los usuarios puedan alejarse manualmente si lo desean):

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

Además, si desea limitar también el zoom máximo, puede aplicar el mismo truco con el maxZoom propiedad.

Vea los documentos de MapOptions .

Svilen Marchev
fuente
1

Lo uso para asegurarme de que el nivel de zoom no exceda un nivel establecido, de modo que sé que las imágenes satelitales estarán disponibles.

Agregue un oyente al zoom_changedevento. Esto tiene la ventaja adicional de controlar el control de zoom en la interfaz de usuario también.

Sólo ejecutar setZoomsi es necesario, por lo que una ifafirmación es preferible Math.maxoaMath.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);

Para evitar alejarse demasiado:

   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);
Mantis
fuente
1

En esta función, debe agregar dinámicamente metadatos para almacenar el tipo de geometría solo porque la función acepta cualquier geometría.

"fitGeometries" es una función JSON que extiende un objeto de mapa.

"geometrías" es una matriz genérica de JavaScript, no 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);
},
CrazyEnigma
fuente
Alternativamente, hice todo el trabajo sin saber que hay un método extend () en el objeto LatLngBounds. Esto sería mucho más fácil.
CrazyEnigma
1

este trabajo es para mí con API v3 pero con configuración de zoom fijo:

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

gmap.setCenter(bounds.getCenter()); 
gmap.setZoom( 6 );
Pedro Blaszczak
fuente
1

Como yo, si no está dispuesto a jugar con los oyentes, esta es una solución simple que se me ocurrió: agregue un método en el mapa que funcione estrictamente de acuerdo con sus requisitos como este:

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

entonces puede llamar en map.fitLmtdBounds(bounds)lugar de map.fitBounds(bounds)establecer los límites bajo el rango de zoom definido ... o map.fitLmtdBounds(bounds,3,5)anular el rango de zoom ...

Kanak Singhal
fuente
0

Por favor intente esto.

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

Si esto te será útil.

Todo lo mejor

Kanak Vaghela
fuente
0

Después del cálculo de los límites, puede verificar la distancia entre la esquina superior izquierda y la esquina inferior derecha; entonces puede comprender el nivel de zoom probando la distancia (si la distancia es demasiado alta, el nivel de zoom sería bajo), entonces puede seleccionar el tiempo usando el método setbound o setZoom.

Orhun Alp Oral
fuente
0

No me gusta sugerirlo, pero si debe intentarlo, primero llame

gmap.fitBounds(bounds);

Luego cree un nuevo Thread / AsyncTask, hágalo dormir durante 20-50 ms aproximadamente y luego llame

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

desde el hilo de la interfaz de usuario (use un controlador o el onPostExecutemétodo para AsyncTask).

No sé si funciona, solo una sugerencia. Aparte de eso, tendría que calcular de alguna manera el nivel de zoom a partir de sus puntos, verificar si es demasiado bajo, corregirlo y luego simplemente llamargmap.setZoom(correctedZoom)

Joseph Earl
fuente
0

Si 'limits_changed' no está disparando correctamente (a veces Google no parece aceptar las coordenadas perfectamente), entonces considere usar 'center_changed' en su lugar.

El evento 'center_changed' se activa cada vez que se llama a fitBounds (), aunque se ejecuta inmediatamente y no necesariamente después de que el mapa se haya movido.

En casos normales, 'inactivo' sigue siendo el mejor oyente de eventos, pero esto puede ayudar a un par de personas a encontrarse con problemas extraños con sus llamadas fitBounds ().

Ver devolución de llamada de Google Maps fitBounds

tempranova
fuente
0

Para intervenir con otra solución, descubrí que el enfoque "escuchar eventos limit_changed y luego establecer nuevo zoom" no funcionó de manera confiable para mí. Creo que a veces estaba llamando fitBoundsantes de que el mapa se hubiera inicializado por completo, y la inicialización estaba causando un evento con fitBoundslímites cambiados que agotaría al oyente, antes de cambiar los límites y el nivel de zoom. Terminé con este código, que parece funcionar hasta ahora:

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

Para mí, la solución más fácil fue esta:

map.fitBounds(bounds);

function set_zoom() {
    if(map.getZoom()) {map.setZoom(map.getZoom() - 1);}
    else {setTimeout(set_zoom, 5);}
}
setTimeout(set_zoom, 5);
horace
fuente
-1
google.maps.event.addListener(marker, 'dblclick', function () {
    var oldZoom = map.getZoom(); 
    map.setCenter(this.getPosition());
    map.setZoom(parseInt(oldZoom) + 1);
});
chetan
fuente
-3

Todo lo que hice es:

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

Y funciona en la API V3.

Petr Svoboda
fuente
map.setCenter acepta solo un atributo, latlng, y el mapa no tiene ninguna función como getBoundsZoomLevel
Viktor
Pensé que hay una función como getBoundsZoomLevel después de ver esta publicación, y estoy decepcionado después de darme cuenta de que no la hay.
sedran
Creo que getBoundsZoomLevel () estaba disponible en la API V2 de Google Maps y no en la API V3
Kush