FitBounds de Google Maps v3 () Zoom demasiado cerca para un solo marcador

92

¿Hay alguna forma de establecer un nivel de zoom máximo para fitBounds()? Mi problema es que cuando el mapa solo se alimenta en una ubicación, se acerca tanto como puede, lo que realmente saca el mapa de contexto y lo vuelve inútil. ¿Quizás estoy tomando el enfoque equivocado?

¡Gracias por adelantado!

Codey W
fuente
2
stackoverflow.com/questions/4523023/… es una solución mucho mejor. Respuesta particular de @Nequins
Kennet

Respuestas:

138

Me gusta la solución de mrt (especialmente cuando no sabe cuántos puntos mapeará o ajustará), excepto que arroja el marcador para que ya no esté en el centro del mapa. Simplemente lo extendí un punto adicional restando 0.01 de la latitud y la longitud también, por lo que mantiene el marcador en el centro. Funciona muy bien, gracias mrt!

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

}
Ryan
fuente
4
Buena idea para mantener el centro original. La razón por la que el nivel de zoom no se puede ajustar de manera confiable cuando se usa el fitBounds()método es porque el zoom se produce de forma asincrónica: stackoverflow.com/questions/2989858/…
Metro Smurf
1
Esto funciono muy bien para mi. Tuve que pasar la referencia del mapa a la función "función fitToMarkers (marcadores, mapa)" en V3, ¡pero funciona como un encanto después de eso!
Shane
4
Amo eso. Buen @ryan. Funcionó muy bien para mí, pero .01 en mi caso se alejó demasiado, .001 alcanzó el punto óptimo.
willdanceforfun
Gracias. Como en el mismo caso @willdanceforfun, 001 dio en el clavo.
Goran Jakovljevic
1
Recomendaría esta solución stackoverflow.com/questions/2437683/…
NinjaOnSafari
38

Usted puede configurar su mapa con maxZoomla MapOptions (API-referencia) así:

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

Esto evitaría que el mapa se acerque más al usarlo fitBounds()e incluso eliminaría los niveles de zoom del control de zoom.

Flygenring
fuente
@candlejack ¿Así que exactamente como se describe en mi respuesta?
Flygenring
6
Puede establecer el maxZoomantes de ajustar los límites y luego desarmarlo nuevamente usando map.setOptions({ maxZoom: undefined })el idleevento activado cambiando los límites. Esto evita que el efecto de acercar y alejar en lugar de restablecer el zoom en el idleevento.
El Yobo
29

Otra solución es expandir los límites si detecta que son demasiado pequeños antes de ejecutar 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);
mrt
fuente
19
var map = new google.maps.Map(document.getElementById("map"), { maxZoom: 10 });

Usar la opción MaxZoom funciona mejor para no acercar el zoom a las marcas que tiene.

Markvaneijk
fuente
¡Fantástico! Salvavidas!
Jaypee
18

Una vez que haya agregado todos los límites reales, agregue estas líneas

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

obtiene el centro de los límites reales y luego agrega dos puntos adicionales, uno al noreste y otro al suroeste de tu centro

Esto establece efectivamente el zoom mínimo, cambie el valor de compensación para aumentar o disminuir el zoom

PWHIT
fuente
12

Si es para una sola ubicación, puede usar setCenter () y setZoom () en su lugar.

CrazyEnigma
fuente
solución más fácil
Alberto M
11

puedes usar

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

de esta manera, establece las propiedades del mapa después de que se haya inicializado el mapa ... puede configurarlas tantas veces como desee ... pero en su caso ... puede establecerlas antes de fitBounds ()

buena suerte, rarutu

Wowzaaa
fuente
7

La forma en que evito que el mapa se acerque demasiado es agregando esta línea de código:

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

Directamente después de esta línea:

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

Siéntase libre de cambiar el nivel de zoom a cualquier nivel que no desee que el mapa pase.

Si tiene algún problema o pregunta, simplemente déjeme un comentario en la publicación del blog que escribí sobre esto en http://icode4you.net/creating-your-own-store-locator-map-how-to-prevent-the- map-from-zooming-in-too-close-on-a-single-marker

TheLibzter
fuente
1
Me gusta esta solución, pero inserto el setzoom dentro del if para no llamarlo cada vez. También podría haber un efecto secundario de sincronización que devuelva 'indefinido' de getzoom (). Solución: zoom = map.getZoom (); if (typeof zoom! == 'undefined' && zoom> 8) map.setZoom (8);
Le Droid
5

Me gusta mucho la solución de mrt y funciona perfectamente si siempre has tenido un solo punto con el que trabajar. Sin embargo, descubrí que si el cuadro delimitador no se basaba en un punto, pero los puntos estaban muy juntos, esto aún podría hacer que el mapa se acercara demasiado.

Aquí hay una forma de verificar primero si los puntos están dentro de una distancia definida entre sí, luego, si son más pequeños que esa distancia mínima, extienda los límites por esa distancia mínima:

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

¡Espero que esto ayude a alguien!

Pakage
fuente
3

Esto le da un control directo sobre el zoom máximo permitido en el ajuste de límites.

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);
};
clima
fuente
3

En cuanto a mí, lo resuelvo creando un evento inactivo después de fitBounds. Funcionando perfectamente. Supongo que es una de las soluciones más limpias aquí.

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);
  }
});
Vitali Protosovitski
fuente
2

Resolví con este fragmento, ya que Google Maps V3 está impulsado por eventos:

puede decirle a la API que vuelva a ajustar el zoom a una cantidad adecuada cuando se active el 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;
       }
    }
}); 

Utilicé inicialmente para que el mapa no se acercara demasiado al cargar cuando los eventuales fitBounds se perdieron, sin él, cualquier evento de zoom superior a 11 sería imposible para el usuario.

afinado
fuente
1

Después de llamar al fitBounds()método, intente configurar el nivel de zoom nuevamente. Obligará al mapa a estar en ese nivel de zoom mientras se centra en el lugar correcto.

moneshchary
fuente
0

Tengo una solución basada en limitar el zoom máximo al ajustar los límites. Funciona para mí (probado en 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);
    }
});
muffir
fuente
0

Y aqui esta otro.
La misma idea que mrt y Ryan, pero

  • también funciona si el tamaño de los límites no es exactamente cero (*)
  • evita la distorsión cerca de los polos
  • usa getCenter () en lugar de getNorthEast ()

(*) Nota: Si la caja ya es lo suficientemente grande, agregar esos dos puntos adicionales no debería tener ningún efecto. Así que no necesitamos más comprobaciones.

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

EDITAR: No estoy exactamente seguro de si mi cálculo de proporción es correcto, considerando que tenemos una proyección de Mercator. Podría volver a editar esto ...

Don Quijote
fuente
-1

Aquí está mi solución, que también funciona cuando dos marcadores están muy cerca. El nivel de zoom máximo efectivo es el mismo en ambas situaciones. Así no terminamos alejándonos innecesariamente, cuando hay más de un marcador

El efecto, nuevamente, es asegurar un zoom máximo, sin usar la opción maxZoom, que tiene el efecto probablemente no deseado de hacer imposible que el usuario haga zoom más allá del nivel maxZoom con el control de zoom

He calculado maxLat, minLat, maxLng y minLng de antemano ...

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,
});
rosell.dk
fuente