Come posso limitare il panning nelle API di Google Maps V3?

In V2 c’era un modo per limitare il panning / trascinamento in modo che la mappa restasse entro certi limiti. Come è fatto in V3?

Diciamo che voglio che gli utenti guardino solo all’Europa. Ho già limitato lo zoom, ma se permetto il trascinamento (che devo in questo caso, per altri motivi), l’utente può scorrere oltre l’area che voglio mostrare.

Per favore fornisci un esempio di lavoro o uno snippet di codice: non sono un programmatore esperto …

Grazie!

Immagino di essere un po ‘in ritardo per la festa, ma visto che questo era esattamente ciò di cui avevo bisogno proprio ora E ho migliorato, ho pensato di pubblicare una risposta comunque.

Con entrambe le risposte di Daniel Vassallo e Brendo , l’utente può comunque utilizzare il controllo di pan (se triggersto) per allontanarsi dall’area desiderata. La cosa @ Yauhen.F menzionata in un commento.

Quindi, invece di usare l’evento dragend, uso l’evento center_changed. Questo viene continuamente triggersto durante il trascinamento e ogni volta che qualcuno usa il controllo di pan.

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

Salvando continuamente l’ultima posizione valida durante il trascinamento, il movimento si fermerà una volta fuori limite, invece di tornare indietro una volta terminato il trascinamento. ……

Il trucco è ascoltare l’evento dragend e se la mappa viene trascinata fuori dai limiti consentiti, dragend nuovamente all’interno. Se si definiscono i limiti consentiti come object LatLngBounds , è ansible utilizzare il metodo contains() , poiché restituisce true se l’argomento lat / lng specificato si trova all’interno dei limiti.

È anche importante limitare il livello di zoom, ma sembra che lo stiate già facendo.

Pertanto, potresti provare il seguente esempio:

     Google Maps JavaScript API v3 Example: Limit Panning    

Screenshot dall'esempio sopra. In questo caso, l'utente non sarà in grado di trascinare ulteriormente il sud o l'estremo oriente:

Google Maps JavaScript API v3 Esempio: limit Panning

La mia versione, basata su quella di @HenningJ, ma con alcune modifiche lastValidCenter per consentire un trascinamento uniforms lungo i bordi dei limiti.

          

Fiddle qui: http://jsfiddle.net/koenpunt/n7h6t/

Ecco una bella estensione a quanto sopra che ripristinerà il centro della mappa sull’ultima posizione valida ascoltando l’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); }); 

Il metodo migliore per restringere è impostare il livello di zoom e il punto centrale e disabilitare i controlli come zoom, scroll ecc. Come di seguito.

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

Ecco una soluzione che unisce la risposta di Tom Andersen e la risposta HenningJ attualmente accettata. I vantaggi di questo è che 1) consente uno scrolling più agevole lungo i bordi (con la soluzione di HenningJ apparentemente goffo), e 2) non ha alcun problema quando si esegue lo zoom fuori da un’area (anche in questo caso la risposta di HenningJ sembrava interrompersi quando si ingrandiva e fuori vicino ai confini).

La risposta di Tom era vicina a lavorare per me, tranne che posizionava l’area bloccata al centro dello schermo, il che non era accettabile per l’applicazione su cui stavo lavorando.

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

Ho provato la risposta di HenningJ e la mappa non smetteva di panning fino a quando il centro non si trovava in un angolo dei limiti che non era l’ideale. Ecco la mia soluzione:

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

Ecco una soluzione semplice che funziona su dispositivi mobili e desktop. Arresta la panoramica della mappa oltre la latitudine massima o minima del mondo e consente di impostare un livello minimo di zoom, che può aiutare a prevenire la visualizzazione di aree grigie con lo zoom troppo ampio (a seconda delle dimensioni impostate per la mappa):

(Raccomando caucanvas nell’usare l’evento center_changed come suggerito nella risposta accettata da HenningJ. Nel mio caso il numero di eventi che questo ha causato errori di overflow dello stack in Google Chrome, può essere utilizzato invece l’evento “dragend”, anche se questo consentirà l’utente deve trascinarsi fuori dalle aree e immediatamente “ricaccia” su un’area valida della mappa).

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

C’è un’altra discussione sull’argomento che è anche molto buona. Il problema che dovevo risolvere era che invece di impostare i limiti manualmente e controllare il contenimento del centro, volevo un set di limiti sul caricamento della pagina, quindi consentire il trascinamento verso il bordo se ingrandito.

Così ho impostato una volta i limiti di panning sul caricamento della mappa. Quindi controllo se la mappa è ancora allo zoom massimo e in tal caso, restituire il centro iniziale. Se ingrandito, voglio eseguire una panoramica sull’EDGE dei limiti iniziali, non solo per controllare se CENTER è contenuto, perché ciò estenderebbe il panning consentito della metà del viewport.

Sfortunatamente, anche se questo ha portato a termine il lavoro e funziona bene quando il paning lentamente, è un po ‘a scatti se si esegue una panoramica veloce.

Se hai suggerimenti su come questo può essere evitato, te ne sarei grato.

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

Quando utilizzo drag o dragend o qualsiasi altra cosa, la mappa torna ai limiti consentiti invece di limitarsi a limitare i movimenti di overflow. Basta cambiare l’evento in “center_changed” per impedirgli di saltare in giro in quel modo.

Modificato jsfiddle: http://jsfiddle.net/Vjdde/1/

Modifica: Non sono sicuro del motivo per cui il violino non produce un sovraccarico di stack, ma dovrebbe, dal momento che setCenter chiamerà di nuovo center_changed .. Basta fare attenzione

Le soluzioni qui mi hanno lasciato con 2 numeri. Prima di tutto, se tenete premuto il tasto freccia in modo che abbia iniziato a scorrere rapidamente, quando ha colpito il bordo, non sarebbe andato fino al limite perché a causa dell’accelerazione del panning, prendendo “passi” di grandi dimensioni, il prossimo ” passo “sarebbe andato fuori dai limiti, quindi non ci vuole l’ultimo” passo “. Quindi, una volta fermato, è ansible rilasciare il tasto freccia e quindi premerlo di nuovo, e potrebbe scorrere un po ‘di più. In secondo luogo, queste soluzioni non contenevano correttamente il panning dopo un cambio di zoom. Sono riuscito a risolvere entrambi e ho postato la mia soluzione in un’altra discussione , ma ho pensato di collegarla qui, poiché questo è stato il thread che mi ha fatto iniziare nella giusta direzione.

Questo è HenningJ – ma HenningJ su ios usa lastValidCentre – che non è buono, come il suo vecchio, quindi lo morsetto, che lo rende migliore su 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)); }); 

Pubblicherò la mia risposta nel caso in cui qualcuno fosse interessato perché non sono riuscito a ottenere ciò di cui avevo bisogno con le altre soluzioni pubblicate qui.

Quello di cui avevo bisogno era di limitare i limiti verticali (latitudine) della mappa in modo che l’utente non fosse in grado di eseguire una panoramica oltre i limiti di latitudine della terra (~ +/- 85 gradi), ma qualsiasi altro limite avrebbe funzionato.

Questo approccio utilizza lo stesso evento center_changed come descritto altrove e semplicemente corregge il centro nel caso in cui vengano mostrate parti dei limiti proibiti.

Questo meccanismo funziona solo se lo zoom minimo della mappa è impostato in modo tale che lo zoom in uscita non possa mai mostrare un’area maggiore di quella entro i limiti consentiti.

Esempio di lavoro: 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; } 
     Simple Map     

So di essere in ritardo per la festa, ma sembra che a metà 2016 non ci sia un modo ufficiale per limitare l’area visibile.

Ci sono alcune soluzioni per limitare i limiti (alcuni di essi in questa domanda) ma per me hanno comunque un difetto, perché non limitano i limiti esattamente per adattarsi alla vista della mappa, limitano solo il centro della mappa che deve essere contenuto all’interno del limiti specificati. Se vuoi limitare i limiti di sovrapposizione di un’immagine come me, questo può comportare un comportamento come illustrato di seguito, in cui la mappa sottostante è visibile sotto la sovrapposizione di immagini:

inserisci la descrizione dell'immagine qui

Per affrontare questo problema, ho creato una libreria , che limita con successo i limiti in modo che non sia ansible eseguire la panoramica dall’overlay.

Tuttavia, come altre soluzioni esistenti, ha un problema “vibrante”. Quando l’utente esegue il panning della mappa in modo abbastanza aggressivo, dopo aver rilasciato il pulsante sinistro del mouse, la mappa continua a eseguire il panning da sola, rallentando gradualmente. Ritorna sempre indietro alla mappa, ma questo si traduce in una sorta di vibrazione, che si risolve dopo un momento. Questo effetto panning non può essere interrotto con i mezzi forniti dall’API Js al momento. Sembra che fino a quando Google aggiungerà il supporto per qualcosa come map.stopPanningAnimation () non saremo in grado di creare un’esperienza fluida.

Esempio utilizzando la libreria citata, l’esperienza dei limiti rigorosi più fluidi che sono riuscito a ottenere:

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