Google Maps v3: limitar el área visible y el nivel de zoom

97

¿Es posible limitar el mapa de Google v3 a un área determinada? Quiero permitir que se muestre solo un área (por ejemplo, un país) y no permitir que el usuario se deslice en otra parte. También quiero restringir el nivel de zoom, por ejemplo, solo entre los niveles 6 y 9. Y quiero usar todos los tipos de mapas base.

¿Hay alguna forma de lograrlo?

Tuve un éxito parcial al limitar el nivel de zoom al usar StyledMap, pero solo logré restringir ROADMAP, no pude limitar el zoom en otros tipos básicos de esta manera.

Gracias por cualquier ayuda

Tomik
fuente

Respuestas:

119

Puede escuchar el dragendevento y, si el mapa se arrastra fuera de los límites permitidos, vuelva a moverlo hacia adentro. Puede definir sus límites permitidos en un LatLngBoundsobjeto y luego usar el contains()método para verificar si el nuevo centro lat / lng está dentro de los límites.

También puede limitar el nivel de zoom muy fácilmente.

Considere el siguiente ejemplo: Fiddle Demo

<!DOCTYPE html>
<html> 
<head> 
   <meta http-equiv="content-type" content="text/html; charset=UTF-8"/> 
   <title>Google Maps JavaScript API v3 Example: Limit Panning and Zoom</title> 
   <script type="text/javascript" 
           src="http://maps.google.com/maps/api/js?sensor=false"></script>
</head> 
<body> 
   <div id="map" style="width: 400px; height: 300px;"></div> 

   <script type="text/javascript"> 

   // This is the minimum zoom level that we'll allow
   var minZoomLevel = 5;

   var map = new google.maps.Map(document.getElementById('map'), {
      zoom: minZoomLevel,
      center: new google.maps.LatLng(38.50, -90.50),
      mapTypeId: google.maps.MapTypeId.ROADMAP
   });

   // Bounds for North America
   var strictBounds = new google.maps.LatLngBounds(
     new google.maps.LatLng(28.70, -127.50), 
     new google.maps.LatLng(48.85, -55.90)
   );

   // Listen for the dragend event
   google.maps.event.addListener(map, 'dragend', function() {
     if (strictBounds.contains(map.getCenter())) return;

     // We're out of bounds - Move the map back within the bounds

     var c = map.getCenter(),
         x = c.lng(),
         y = c.lat(),
         maxX = strictBounds.getNorthEast().lng(),
         maxY = strictBounds.getNorthEast().lat(),
         minX = strictBounds.getSouthWest().lng(),
         minY = strictBounds.getSouthWest().lat();

     if (x < minX) x = minX;
     if (x > maxX) x = maxX;
     if (y < minY) y = minY;
     if (y > maxY) y = maxY;

     map.setCenter(new google.maps.LatLng(y, x));
   });

   // Limit the zoom level
   google.maps.event.addListener(map, 'zoom_changed', function() {
     if (map.getZoom() < minZoomLevel) map.setZoom(minZoomLevel);
   });

   </script> 
</body> 
</html>

Captura de pantalla del ejemplo anterior. El usuario no podrá arrastrar más al sur o al este en este caso:

Ejemplo de la versión 3 de la API de JavaScript de Google Maps: Forzar la detención del arrastre del mapa

Daniel Vassallo
fuente
2
La decisión no parece limpia. ¿Por qué if (x < minX) x = minX;y if (x > maxX) x = maxX;no excluirse? ¿Por qué centra el lienzo en las coordenadas minX / maxX y maxX / maxY aunque no son coordenadas del centro?
Alexander Palamarchuk
1
En lugar del dragendevento que podría usar draggable: falseen la instancia del mapa ( ejemplo de trabajo )
machineaddict
Esta no es una buena técnica para usar el evento "zoom_changed" para restringir al usuario. Debido a que la primera vez siempre va más allá del nivel mínimo y luego, usando su código, está configurando el zoom mínimo nuevamente, lo que flikr en la pantalla.
Jitendra Pancholi
visite zillow.com/homes/for_sale/days_sort/… Lo han hecho de la manera correcta, no estoy seguro de cómo.
Jitendra Pancholi
1
Esto funcionó perfectamente para mí si cambiaba al center_changedevento en lugar de dragend.
Johan B
182

¿Una mejor manera de restringir el nivel de zoom podría ser usar las opciones minZoom/ en maxZoomlugar de reaccionar a los eventos?

var opt = { minZoom: 6, maxZoom: 9 };
map.setOptions(opt);

O las opciones se pueden especificar durante la inicialización del mapa, por ejemplo:

var map = new google.maps.Map(document.getElementById('map-canvas'), opt);

Consulte: Referencia de la versión 3 de la API de JavaScript de Google Maps

ChrisV
fuente
3
Ahora bien, esta es seguramente la mejor manera de restringir el nivel de zoom. Cuando estaba escribiendo la publicación, la función no estaba presente en Maps API v3. Afortunadamente, siguen mejorando la API.
Tomik
2
Esto funciona perfectamente, esta debería ser la mejor respuesta para el zoom.
paullb
3
Esto debe marcarse como la respuesta para aquellos que solo miran la respuesta elegida.
ErJab
9
establecer el nivel de zoom no tiene ningún efecto sobre la panorámica.
Simpatico
1
Definitivamente la mejor manera de hacerlo
ChrisRich
16

Buenas noticias. A partir de la versión 3.35 de la API de JavaScript de Maps, que se lanzó el 14 de febrero de 2019, puede usar una nueva restrictionopción para limitar la ventana gráfica del mapa.

Según la documentación

Interfaz MapRestriction

Una restricción que se puede aplicar al mapa. La ventana gráfica del mapa no excederá estas restricciones.

fuente: https://developers.google.com/maps/documentation/javascript/reference/map#MapRestriction

Entonces, ahora solo agrega la opción de restricción durante la inicialización de un mapa y eso. Eche un vistazo al siguiente ejemplo que limita la ventana gráfica a Suiza

var map;
function initMap() {
  map = new google.maps.Map(document.getElementById('map'), {
    center: {lat: 46.818188, lng: 8.227512},
    minZoom: 7,
    maxZoom: 14,
    zoom: 7,
    restriction: {
      latLngBounds: {
        east: 10.49234,
        north: 47.808455,
        south: 45.81792,
        west: 5.95608
      },
      strictBounds: true
    },
  });
}
#map {
  height: 100%;
}
html, body {
  height: 100%;
  margin: 0;
  padding: 0;
}
<div id="map"></div>
<script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyDztlrk_3CnzGHo7CFvLFqE_2bUKEq1JEU&callback=initMap" async defer></script>

¡Espero que esto ayude!

xomena
fuente
El enlace no funciona. Aquí hay algunos nuevos sobre este tema: EJEMPLO: developers-dot-devsite-v2-prod.appspot.com/maps/documentation/… DOCS: developers-dot-devsite-v2-prod.appspot.com/maps/documentation/ …
Adam
1
Enlace de documentación fijo.
xomena
Gracias, este código funcionó. Es decir, si limita el zoom a solo 1 nivel posible con minZoom y maxZoom. Parece que debe establecer un sur, oeste, noth, este diferente para cada nivel de zoom si esto funciona como se espera. Sería maravilloso tener una configuración de restricción diferente para cada nivel de zoom. Fui a mi nivel máximo de alejamiento y definí las coordenadas desde allí, lo que hace posible desplazarme fuera de los límites si acercas y luego desplazas.
Kim Steinhaug
6

Para limitar el zoom en v.3 +. en la configuración de su mapa agregue el nivel de zoom predeterminado y los niveles de zoom minZoom o maxZoom (o ambos si es necesario) son de 0 a 19. Debe declarar un nivel de zoom sordo si se requiere limitación. ¡todos distinguen entre mayúsculas y minúsculas!

function initialize() {
   var mapOptions = {
      maxZoom:17,
      minZoom:15,
      zoom:15,
      ....
PLATA PROFUNDA
fuente
3

Una forma mucho mejor de limitar el rango ... usó la lógica de contenido del póster de arriba.

var dragStartCenter;

google.maps.event.addListener(map, 'dragstart', function(){
                                       dragStartCenter = map.getCenter();
                                         });

google.maps.event.addListener(this.googleMap, 'dragend', function(){
                            if (mapBounds.contains(map.getCenter())) return;
                    map.setCenter(this.dragStart);
                           });
Palmadita
fuente
¿Por qué agrega en this.googleMaplugar de mappara el segundo oyente? ¿No debería dragStartserlo también dragStartCenter? Por último, ¿qué es mapBounds?
hobbes3
2
Seguramente todo lo que hace es evitar que el usuario arrastre demasiado en un movimiento de arrastre. Todavía podrían hacer muchos pequeños arrastres y terminar en cualquier lugar, ¿no?
James
1

Esto se puede utilizar para volver a centrar el mapa en una ubicación específica. Que es lo que necesitaba.

    var MapBounds = new google.maps.LatLngBounds(
    new google.maps.LatLng(35.676263, 13.949096),
    new google.maps.LatLng(36.204391, 14.89038));

    google.maps.event.addListener(GoogleMap, 'dragend', function ()
    {
        if (MapBounds.contains(GoogleMap.getCenter()))
        {
            return;
        }
        else
        {
            GoogleMap.setCenter(new google.maps.LatLng(35.920242, 14.428825));
        }
    });
Jonathan Busuttil
fuente
1
myOptions = {
        center: myLatlng,
        minZoom: 6,
        maxZoom: 9,
        styles: customStyles,
        mapTypeId: google.maps.MapTypeId.ROADMAP
    };
Anup
fuente
1
Esto no responde a la pregunta.
Kit Sunde
0

Aquí está mi variante para resolver el problema de la limitación del área visible.

        google.maps.event.addListener(this.map, 'idle', function() {
            var minLat = strictBounds.getSouthWest().lat();
            var minLon = strictBounds.getSouthWest().lng();
            var maxLat = strictBounds.getNorthEast().lat();
            var maxLon = strictBounds.getNorthEast().lng();
            var cBounds  = self.map.getBounds();
            var cMinLat = cBounds.getSouthWest().lat();
            var cMinLon = cBounds.getSouthWest().lng();
            var cMaxLat = cBounds.getNorthEast().lat();
            var cMaxLon = cBounds.getNorthEast().lng();
            var centerLat = self.map.getCenter().lat();
            var centerLon = self.map.getCenter().lng();

            if((cMaxLat - cMinLat > maxLat - minLat) || (cMaxLon - cMinLon > maxLon - minLon))
            {   //We can't position the canvas to strict borders with a current zoom level
                self.map.setZoomLevel(self.map.getZoomLevel()+1);
                return;
            }
            if(cMinLat < minLat)
                var newCenterLat = minLat + ((cMaxLat-cMinLat) / 2);
            else if(cMaxLat > maxLat)
                var newCenterLat = maxLat - ((cMaxLat-cMinLat) / 2);
            else
                var newCenterLat = centerLat;
            if(cMinLon < minLon)
                var newCenterLon = minLon + ((cMaxLon-cMinLon) / 2);
            else if(cMaxLon > maxLon)
                var newCenterLon = maxLon - ((cMaxLon-cMinLon) / 2);
            else
                var newCenterLon = centerLon;

            if(newCenterLat != centerLat || newCenterLon != centerLon)
                self.map.setCenter(new google.maps.LatLng(newCenterLat, newCenterLon));
        });

strictBoundses un objeto de new google.maps.LatLngBounds()tipo. self.gmapalmacena un objeto de Google Map ( new google.maps.Map()).

Realmente funciona, pero no solo olvide tener en cuenta las hemorroides con cruce de meridianos 0 y paralelos si sus límites los cubren.

Alexander Palamarchuk
fuente
Aceptado, el algoritmo de Daniel Vassallo no funciona correctamente para mí. Hay varias diferencias principales aquí.
Alexander Palamarchuk
0

Por alguna razón

if (strictBounds.contains(map.getCenter())) return;

no funcionó para mí (tal vez un problema del hemisferio sur). Tuve que cambiarlo a:

    function checkBounds() {
        var c = map.getCenter(),
            x = c.lng(),
            y = c.lat(),
            maxX = strictBounds.getNorthEast().lng(),
            maxY = strictBounds.getNorthEast().lat(),
            minX = strictBounds.getSouthWest().lng(),
            minY = strictBounds.getSouthWest().lat();

        if(x < minX || x > maxX || y < minY || y > maxY) {
            if (x < minX) x = minX;
            if (x > maxX) x = maxX;
            if (y < minY) y = minY;
            if (y > maxY) y = maxY;
            map.setCenter(new google.maps.LatLng(y, x));
        }
    }

Espero que ayude a alguien.

Mayko
fuente
0

Una solución es como, si conoce el lat / lng específico.

google.maps.event.addListener(map, 'idle', function() {

    map.setCenter(new google.maps.LatLng(latitude, longitude));
    map.setZoom(8);

});

Si no tiene lat / lng específico

google.maps.event.addListener(map, 'idle', function() {

    map.setCenter(map.getCenter());
    map.setZoom(8);

});

o

google.maps.event.addListener(map, 'idle', function() {

    var bounds = new google.maps.LatLngBounds();
    map.setCenter(bounds.getCenter());
    map.setZoom(8);

});
Jaison
fuente
0

A mediados de 2016 , no existe una forma oficial de restringir el área visible. Sin embargo, la mayoría de las soluciones ad-hoc para restringir los límites tienen un defecto, ya que no restringen los límites exactamente para ajustarse a la vista del mapa, solo lo restringen si el centro del mapa está fuera de los límites especificados. Si desea restringir los límites a una imagen superpuesta como yo, esto puede resultar en un comportamiento como el que se ilustra a continuación, donde el mapa subyacente es visible debajo de nuestra superposición de imágenes:

ingrese la descripción de la imagen aquí

Para abordar este problema, he creado una biblioteca , que restringe con éxito los límites para que no pueda salir de la superposición.

Sin embargo, como otras soluciones existentes, tiene un problema de "vibración". Cuando el usuario desplaza el mapa de forma suficientemente agresiva, después de soltar el botón izquierdo del ratón, el mapa sigue desplazándose por sí mismo, ralentizándose gradualmente. Siempre devuelvo el mapa a los límites, pero eso resulta en una especie de vibración. Este efecto de panorámica no se puede detener con ningún medio proporcionado por la API de Js en este momento. Parece que hasta que Google agregue soporte para algo como map.stopPanningAnimation () no podremos crear una experiencia fluida.

Ejemplo usando la biblioteca mencionada, la experiencia de límites estrictos más suave que pude obtener:

function initialise(){
  
  var myOptions = {
     zoom: 5,
     center: new google.maps.LatLng(0,0),
     mapTypeId: google.maps.MapTypeId.ROADMAP,
  };
  var map = new google.maps.Map(document.getElementById('map'), myOptions);
  
  addStrictBoundsImage(map);
}

function addStrictBoundsImage(map){
	var bounds = new google.maps.LatLngBounds(
		new google.maps.LatLng(62.281819, -150.287132),
		new google.maps.LatLng(62.400471, -150.005608));

	var image_src = 'https://developers.google.com/maps/documentation/' +
		'javascript/examples/full/images/talkeetna.png';

	var strict_bounds_image = new StrictBoundsImage(bounds, image_src, map);
}
<script type="text/javascript" src="http://www.google.com/jsapi"></script>
      <script type="text/javascript">
        google.load("maps", "3",{other_params:"sensor=false"});
      </script>
<body style="margin:0px; padding:0px;" onload="initialise()">
	 <div id="map" style="height:400px; width:500px;"></div>
     <script  type="text/javascript"src="https://raw.githubusercontent.com/matej-pavla/StrictBoundsImage/master/StrictBoundsImage.js"></script>
</body>

La biblioteca también puede calcular la restricción mínima de zoom automáticamente. Luego restringe el nivel de zoom usando minZoomel atributo del mapa.

Con suerte, esto ayudará a alguien que quiera una solución que respete plenamente los límites establecidos y no quiera permitir que se salga de ellos.

Matej P.
fuente
-4

Esto puede resultar útil.

  var myOptions = {
      center: new google.maps.LatLng($lat,$lang),
      zoom: 7,
      disableDefaultUI: true,
      mapTypeId: google.maps.MapTypeId.ROADMAP
    };

El nivel de Zoom se puede personalizar según los requisitos.

Samir Dash
fuente
Esto no aborda la pregunta original acerca de restringir el nivel de zoom a un rango e.g. only between levels 6 and 9, establece el nivel de zoom predeterminado y elimina la interfaz de usuario predeterminada (es decir, +/ -) que es un poco exagerada.
Alastair