javascript - icon - ¿Cómo limito el paneo en Google maps API V3?
google maps marker icon example (14)
Aquí hay una buena extensión a lo anterior que restablecerá el centro del mapa a la última posición válida al escuchar el evento dragstart.
// Limit panning
var lastCenter = map.getCenter();
google.maps.event.addListener(map, ''dragstart'', function() {
lastCenter = map.getCenter();
});
google.maps.event.addListener(map, ''dragend'', function() {
if(allowedBounds.contains(map.getCenter())) return;
map.setCenter(lastCenter);
});
En V2, había una manera de limitar el barrido / arrastre para que el mapa se mantenga dentro de ciertos límites. ¿Cómo se hace eso en V3?
Digamos que quiero que los usuarios solo miran a Europa. Ya he limitado el zoom, pero si permito arrastrar (lo que tengo que hacer en este caso, por otros motivos), el usuario puede desplazarse más allá del área que quiero mostrar.
Da un ejemplo de trabajo o un fragmento de código: no soy un codificador experto ...
¡Gracias!
Aquí hay una solución que es una combinación de la respuesta de Tom Andersen y la respuesta de HenningJ actualmente aceptada. Los beneficios de esto es que 1) permite un desplazamiento más suave a lo largo de los bordes (lo que la solución de HenningJ parecía torpe), y 2) no tiene ningún problema al acercar un área (la respuesta de HenningJ pareció romperse al acercarse) y fuera de los límites).
La respuesta de Tom estuvo cerca de funcionar para mí, excepto que colocó el área bloqueada en el centro de la pantalla, lo que no era aceptable para la aplicación en la que estaba trabajando.
// bounds of the desired area
var allowedBounds = new google.maps.LatLngBounds(
new google.maps.LatLng(70.33956792419954, 178.01171875),
new google.maps.LatLng(83.86483689701898, -88.033203125)
);
var lastValidCenter = map.getCenter();
google.maps.event.addListener(map, ''center_changed'', function() {
var mapBounds = map.getBounds();
var mapNe = mapBounds.getNorthEast();
var mapSw = mapBounds.getSouthWest();
var center = map.getCenter();
if( allowedBounds.contains(mapNe) && allowedBounds.contains(mapSw) ) {
//the user is scrolling within the bounds.
lastValidCenter = center;
return;
}
//the user has scrolled beyond the edge.
var mapWidth = mapNe.lng() - mapSw.lng();
var mapHeight = mapNe.lat() - mapSw.lat();
var x = center.lng();
var y = center.lat();
var maxX = allowedBounds.getNorthEast().lng();
var maxY = allowedBounds.getNorthEast().lat();
var minX = allowedBounds.getSouthWest().lng();
var minY = allowedBounds.getSouthWest().lat();
//shift the min and max dimensions by 1/2 of the screen size, so the bounds remain at the edge of the screen
maxX -= (mapWidth / 2);
minX += (mapWidth / 2);
maxY -= (mapHeight / 2);
minY += (mapHeight / 2);
if (x < minX) {
x = minX;
}
if (x > maxX) {
x = maxX;
}
if (y < minY){
y = minY;
}
if (y > maxY){
y = maxY;
}
map.panTo(new google.maps.LatLng(y, x));
});
Aquí hay una solución simple que funcionará en dispositivos móviles y computadoras de escritorio. Detiene el panorama del mapa más allá de la latitud máxima o mínima del mundo y permite establecer un nivel de zoom mínimo, lo que puede ayudar a evitar que las áreas grises se vuelvan visibles al alejarse demasiado (dependiendo del tamaño que establezca para su mapa):
(Recomiendo precaución al usar el evento center_changed como lo sugirió HenningJ en la respuesta aceptada. En mi caso, la cantidad de eventos que esto generó errores de desbordamiento de pila en Google Chrome. En su lugar, se puede usar el evento ''dragend'', aunque esto permitirá el usuario arrastra fuera de las áreas, y luego inmediatamente ''volverá'' a un área válida del mapa).
var lastValidCenter;
var minZoomLevel = 2;
setOutOfBoundsListener();
function setOutOfBoundsListener() {
google.maps.event.addListener(map, ''dragend'', function () {
checkLatitude(map);
});
google.maps.event.addListener(map, ''idle'', function () {
checkLatitude(map);
});
google.maps.event.addListener(map, ''zoom_changed'', function () {
checkLatitude(map);
});
};
function checkLatitude(map) {
if (this.minZoomLevel) {
if (map.getZoom() < minZoomLevel) {
map.setZoom(parseInt(minZoomLevel));
}
}
var bounds = map.getBounds();
var sLat = map.getBounds().getSouthWest().lat();
var nLat = map.getBounds().getNorthEast().lat();
if (sLat < -85 || nLat > 85) {
//the map has gone beyone the world''s max or min latitude - gray areas are visible
//return to a valid position
if (this.lastValidCenter) {
map.setCenter(this.lastValidCenter);
}
}
else {
this.lastValidCenter = map.getCenter();
}
}
Creo que llegué un poco tarde a la fiesta, pero como esto era exactamente lo que necesitaba justo ahora Y lo mejoré, pensé en publicar una respuesta de todos modos.
Con las respuestas de Daniel Vassallo y brendo , el usuario puede usar el control panorámico (si está activado) para alejarse del área deseada. La cosa @ Yauhen.F mencionada en un comentario.
Entonces, en lugar de usar el evento dragend, utilizo el evento center_changed. Esto se dispara continuamente durante el arrastre y cada vez que alguien usa el control de panoramización.
// bounds of the desired area
var allowedBounds = new google.maps.LatLngBounds(
new google.maps.LatLng(70.33956792419954, 178.01171875),
new google.maps.LatLng(83.86483689701898, -88.033203125)
);
var lastValidCenter = map.getCenter();
google.maps.event.addListener(map, ''center_changed'', function() {
if (allowedBounds.contains(map.getCenter())) {
// still within valid bounds, so save the last valid position
lastValidCenter = map.getCenter();
return;
}
// not valid anymore => return to last valid position
map.panTo(lastValidCenter);
});
Al guardar la última posición válida de forma continua durante el arrastre, el movimiento se detendrá una vez que esté fuera de límites, en lugar de perderse una vez que finalizó el arrastre. ......
Cuando uso drag o dragend o lo que sea, el mapa salta de vuelta a los límites permitidos en lugar de limitar el movimiento desbordante. Simplemente cambie el evento a ''center_changed'' para evitar que salte de esa manera.
Jsfiddle modificado: http://jsfiddle.net/Vjdde/1/
Editar: No estoy seguro de por qué el violín no produce un desbordamiento de la pila, pero debería hacerlo, ya que setCenter volverá a llamar a center_changed. Solo ten cuidado
El mejor método para restringir es establecer el nivel de zoom y el punto central y deshabilitar los controles como el zoom, desplazarse, etc., como se muestra a continuación.
var latlng = new google.maps.LatLng(18.283078,84.047556);
var myOptions = {
zoom: 12,
center: latlng,
zoomControl: false,
mapTypeId: google.maps.MapTypeId.ROADMAP,
scrollwheel: false,
navigationControl: false,
mapTypeControl: false,
scaleControl: false,
draggable: false,
disableDoubleClickZoom: true,
};
map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);
El truco es escuchar el evento dragend
, y si el mapa se arrastra fuera de los límites permitidos, dragend
nuevo adentro. Si define los límites permitidos como un objeto LatLngBounds
, puede usar el método contains()
, ya que devuelve verdadero si el argumento lat / lng dado está dentro de los límites.
También es importante limitar el nivel de zoom, pero parece que ya lo estás haciendo.
Por lo tanto, es posible que desee probar el siguiente ejemplo:
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8"/>
<title>Google Maps JavaScript API v3 Example: Limit Panning</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">
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 allowedBounds = 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 (allowedBounds.contains(map.getCenter())) return;
// Out of bounds - Move the map back within the bounds
var c = map.getCenter(),
x = c.lng(),
y = c.lat(),
maxX = allowedBounds.getNorthEast().lng(),
maxY = allowedBounds.getNorthEast().lat(),
minX = allowedBounds.getSouthWest().lng(),
minY = allowedBounds.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 hacia el sur o el lejano este en este caso:
Este es HenningJ, pero HenningJ en iOS usa LastValidCentre, que no es bueno, ya que es viejo, así que lo pinto, lo que lo hace mejor en iOS.
var mapObject = plugin_map.gmap3(''get'');
var allowedBounds = new google.maps.LatLngBounds(
new google.maps.LatLng(41.3957556, -88.4345472),
new google.maps.LatLng(49.4010417, -78.4286389)
);
google.maps.event.addListener(mapObject, ''center_changed'', function() {
if (allowedBounds.contains(mapObject.getCenter())) {
// still within valid bounds, so save the last valid position
return;
}
// not valid anymore => return to last valid position
var c = mapObject.getCenter(),
x = c.lng(),
y = c.lat(),
maxX = allowedBounds.getNorthEast().lng(),
maxY = allowedBounds.getNorthEast().lat(),
minX = allowedBounds.getSouthWest().lng(),
minY = allowedBounds.getSouthWest().lat();
if (x < minX) x = minX;
if (x > maxX) x = maxX;
if (y < minY) y = minY;
if (y > maxY) y = maxY;
//mapObject.setCenter(new google.maps.LatLng(y, x));
mapObject.panTo(new google.maps.LatLng(y, x));
});
Hay otro hilo sobre el tema que también es muy bueno. El problema que tuve que resolver fue que, en lugar de establecer límites manualmente y verificar la contención del centro, quería establecer un límite en la carga de la página, luego permitir el arrastre hacia el borde si se ampliaba.
Así que establecí límites de panoramización en la carga del mapa, una vez. Luego verifico si el mapa aún está en el zoom máximo y si es así, devuelvo el centro inicial. Si amplié mi imagen, quiero desplazarme hacia el BORDE de los límites iniciales, no solo comprobar si CENTER lo contiene, porque eso extendería la panorámica permitida a la mitad de la ventana gráfica.
Desafortunadamente, aunque esto hace el trabajo y funciona bien cuando se hace lentamente, es un poco brusco si se mueve rápidamente.
Si tienes sugerencias sobre cómo evitar esto, te lo agradecería.
map = new google.maps.Map( // defaults
document.getElementById("map22"),
{
disableDefaultUI : true,
zoomControl : true,
zoom : 7,
minZoom : 7,
maxZoom : 10,
center : new google.maps.LatLng(
64.99473104134819,
-19.22332763671875
),
mapTypeId : google.maps.MapTypeId.ROADMAP
}
);
function borders(){
return {
maxLat : map.getBounds().getNorthEast().lat(),
maxLng : map.getBounds().getNorthEast().lng(),
minLat : map.getBounds().getSouthWest().lat(),
minLng : map.getBounds().getSouthWest().lng(),
center : map.getCenter()
}
}
google.maps.event.addListenerOnce(map,''idle'',function() {
limit = borders();
});
google.maps.event.addListener(map,''drag'',function() {
if(map.getZoom() == 7) return map.setCenter(limit.center);
current = borders();
if( current.maxLng < limit.maxLng && current.minLng > limit.minLng ) activeCenterLng = current.center.lng();
if( current.maxLat < limit.maxLat && current.minLat > limit.minLat ) activeCenterLat = current.center.lat();
map.setCenter(
new google.maps.LatLng(
activeCenterLat,
activeCenterLng
)
);
});
Intenté la respuesta de HenningJ y el mapa no dejaría de panoramizar hasta que el centro estuviera en una esquina de los límites que no era ideal. Aquí está mi solución:
google.maps.event.addListener(map, ''center_changed'', function() {
var mapBounds = map.getBounds();
if(allowedBounds.contains(mapBounds.getNorthEast()) && allowedBounds.contains(mapBounds.getSouthWest())) {
lastCenter = map.getCenter();
return;
}
map.panTo(lastCenter);
}, this));
Las soluciones aquí me dejaron con 2 problemas. En primer lugar, si mantuvieras presionada la tecla de flecha para que comenzara a panoramizar rápidamente, cuando llegara al borde, no llegaría al borde porque debido a la aceleración de panoramización tomaba grandes "pasos", el siguiente " el paso "se habría salido de los límites, por lo que no se necesita ese último" paso ". Así que una vez que se detuvo, podía soltar la tecla de flecha y luego presionarla nuevamente, y se desplazaría un poco más. En segundo lugar, estas soluciones no contenían adecuadamente la panoramización después de un cambio de zoom. Pude resolver ambos y publiqué mi solución en otro hilo , pero pensé que lo vincularía aquí, ya que este fue el hilo que primero me ayudó a comenzar en la dirección correcta.
Mi versión, basada en la de @HenningJ, pero con algunas modificaciones del lastValidCenter
para permitir un arrastre suave a lo largo de los bordes de los límites.
<!DOCTYPE html>
<html>
<head>
<style type="text/css">
html { height: 100% }
body { height: 100%; margin: 0; padding: 0 }
#map-canvas { height: 100% }
</style>
<script type="text/javascript"
src="http://maps.google.com/maps/api/js?sensor=false"></script>
</script>
<script type="text/javascript">
function initialize() {
var mapOptions = {
center: new google.maps.LatLng(28.70, -127.50),
zoom: 4,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
var map = new google.maps.Map(document.getElementById("map-canvas"),
mapOptions);
// bounds of the desired area
var allowedBounds = new google.maps.LatLngBounds(
new google.maps.LatLng(28.70, -127.50),
new google.maps.LatLng(48.85, -55.90)
);
var boundLimits = {
maxLat : allowedBounds.getNorthEast().lat(),
maxLng : allowedBounds.getNorthEast().lng(),
minLat : allowedBounds.getSouthWest().lat(),
minLng : allowedBounds.getSouthWest().lng()
};
var lastValidCenter = map.getCenter();
var newLat, newLng;
google.maps.event.addListener(map, ''center_changed'', function() {
center = map.getCenter();
if (allowedBounds.contains(center)) {
// still within valid bounds, so save the last valid position
lastValidCenter = map.getCenter();
return;
}
newLat = lastValidCenter.lat();
newLng = lastValidCenter.lng();
if(center.lng() > boundLimits.minLng && center.lng() < boundLimits.maxLng){
newLng = center.lng();
}
if(center.lat() > boundLimits.minLat && center.lat() < boundLimits.maxLat){
newLat = center.lat();
}
map.panTo(new google.maps.LatLng(newLat, newLng));
});
}
google.maps.event.addDomListener(window, ''load'', initialize);
</script>
</head>
<body>
<div id="map-canvas"/>
</body>
</html>
Fiddle aquí: http://jsfiddle.net/koenpunt/n7h6t/
Sé que llegué un poco tarde a la fiesta, pero parece que a partir de mediados de 2016 , no hay forma oficial de restringir el área visible.
Hay algunas soluciones para restringir los límites (algunos de ellos en esta pregunta) pero para mí tienen un defecto, porque no restringen los límites exactamente para ajustarse a la vista del mapa, solo restringen que el centro del mapa esté dentro del límites especificados. Si desea restringir los límites a la superposición de imágenes como yo, esto puede dar como resultado un comportamiento como se ilustra a continuación, donde el mapa subyacente es visible debajo de nuestra superposición de imágenes:
Para abordar este problema, he creado una library , que restringe con éxito los límites, por lo que no puede salir de la superposición.
Sin embargo, como otras soluciones existentes, tiene un problema de "vibración". Cuando el usuario muestra el mapa con la fuerza suficiente, después de que suelta el botón izquierdo del mouse, el mapa continúa avanzando por su cuenta, desacelerándose gradualmente. Siempre devuelvo el mapa a los límites, pero eso da como resultado un tipo de vibración que se establece después de un momento. Este efecto de panoramización no puede detenerse con ningún medio provisto por la API Js en este momento. Parece que hasta que google agregue soporte para algo como map.stopPanningAnimation () no podremos crear una experiencia fluida.
Ejemplo de uso de la biblioteca mencionada, la experiencia de límites estrictos más fluidos 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:500px; width:1000px;"></div>
<script type="text/javascript"src="https://raw.githubusercontent.com/matej-pavla/StrictBoundsImage/master/StrictBoundsImage.js"></script>
</body>
Voy a publicar mi respuesta en caso de que alguien esté interesado porque no pude lograr lo que necesitaba con ninguna de las otras soluciones publicadas aquí.
Lo que necesitaba era restringir los límites verticales (latitud) del mapa para que el usuario no pudiera desplazarse más allá de los límites de latitud de la tierra (~ +/- 85 grados), pero cualquier otro límite funcionaría también.
Este enfoque usa el mismo evento center_changed
como se describe en otra parte y simplemente arregla el centro en caso de que se muestren partes de los límites prohibidos.
Este mecanismo solo funciona si se establece el zoom mínimo del mapa para que el alejamiento nunca muestre más área que la de los límites permitidos.
Ejemplo de trabajo: http://jsbin.com/vizihe
function initMap() {
// sample bounds, can be anything and goes hand in hand with minZoom
var northBoundary = 40
var southBoundary = -40
var map = new google.maps.Map(document.getElementById(''map''), {
center: {lat: 0, lng: 0},
zoom: 4,
// it''s important to set this to a large enough value
// so that zooming out does not show an area larger than allowed
minZoom: 4
})
map.addListener(''center_changed'', function () {
var bounds = map.getBounds();
var ne = bounds.getNorthEast()
var sw = bounds.getSouthWest()
var center = map.getCenter()
if(ne.lat() > northBoundary) {
map.setCenter({lat: center.lat() - (ne.lat() - northBoundary), lng: center.lng()})
}
if(sw.lat() < southBoundary) {
map.setCenter({lat: center.lat() - (sw.lat() - southBoundary), lng: center.lng()})
}
})
}
html, body, #map {
height: 100%;
margin: 0;
padding: 0;
}
<!DOCTYPE html>
<html>
<head>
<meta name="description" content="limit google map panning">
<title>Simple Map</title>
<meta name="viewport" content="initial-scale=1.0">
<meta charset="utf-8">
</head>
<body>
<div id="map"></div>
<script src="https://maps.googleapis.com/maps/api/js?callback=initMap"
async defer></script>
</body>
</html>