2010-10-10 16 views
11

Sto cercando di impostare i limiti in cui è possibile trascinare la mappa utilizzando l'API di Google Maps V3 Ecco la soluzione per V2 http://econym.org.uk/gmap/example_range.htm che funziona piuttosto bene.API di Google Maps V3: limiti mappa limite

Tuttavia con API V3 non è così buono: quando si utilizza la stessa funzione checkbounds(), la mappa si contrae quando si raggiunge il limite mentre map.setCenter() cambia il centro della mappa.

Come ripararlo? Qual è la soluzione per API V3?

risposta

19

Ho avuto lo stesso problema, ma questo dovrebbe risolverlo (è la stessa funzione, l'evento da ascoltare è cambiato da "sposta" o "trascina" a "center_changed", funziona come un incantesimo!

google.maps.event.addListener(map,'center_changed',function() { checkBounds(); }); 

function checkBounds() {  
    if(! allowedBounds.contains(map.getCenter())) { 
     var C = map.getCenter(); 
     var X = C.lng(); 
     var Y = C.lat(); 

     var AmaxX = allowedBounds.getNorthEast().lng(); 
     var AmaxY = allowedBounds.getNorthEast().lat(); 
     var AminX = allowedBounds.getSouthWest().lng(); 
     var AminY = allowedBounds.getSouthWest().lat(); 

     if (X < AminX) {X = AminX;} 
     if (X > AmaxX) {X = AmaxX;} 
     if (Y < AminY) {Y = AminY;} 
     if (Y > AmaxY) {Y = AmaxY;} 

     map.setCenter(new google.maps.LatLng(Y,X)); 
    } 
} 
+0

Ho usato questo e funziona fantastico. Saluti! –

+5

a cosa è impostato 'allowedBounds'? – travis

+1

allowedBounds è un [oggetto LatLngBounds] (https://developers.google.com/maps/documentation/javascript/reference#LatLngBounds) (in pratica una coppia di latitudini/longitudini). Questo funziona davvero bene BTW, fa esattamente quello che dovrebbe per me! – strikernl

4

Questo script ottiene i limiti iniziali (allowedBounds) e limitare i limiti sulla drag e zoom_changed. anche lo zoom è limitata < 7.

var allowedBounds = false; 

google.maps.event.addListener(map, 'idle', function() { 
if (!allowedBounds) { 
    allowedBounds = map.getBounds(); 
} 
}); 

google.maps.event.addListener(map, 'drag', checkBounds); 
google.maps.event.addListener(map, 'zoom_changed', checkBounds); 

function checkBounds() { 

if (map.getZoom() < 7) map.setZoom(7); 

if (allowedBounds) { 

    var allowed_ne_lng = allowedBounds.getNorthEast().lng(); 
    var allowed_ne_lat = allowedBounds.getNorthEast().lat(); 
    var allowed_sw_lng = allowedBounds.getSouthWest().lng(); 
    var allowed_sw_lat = allowedBounds.getSouthWest().lat(); 

    var currentBounds = map.getBounds(); 
    var current_ne_lng = currentBounds.getNorthEast().lng(); 
    var current_ne_lat = currentBounds.getNorthEast().lat(); 
    var current_sw_lng = currentBounds.getSouthWest().lng(); 
    var current_sw_lat = currentBounds.getSouthWest().lat(); 

    var currentCenter = map.getCenter(); 
    var centerX = currentCenter.lng(); 
    var centerY = currentCenter.lat(); 

    if (current_ne_lng > allowed_ne_lng) centerX = centerX-(current_ne_lng-allowed_ne_lng); 
    if (current_ne_lat > allowed_ne_lat) centerY = centerY-(current_ne_lat-allowed_ne_lat); 
    if (current_sw_lng < allowed_sw_lng) centerX = centerX+(allowed_sw_lng-current_sw_lng); 
    if (current_sw_lat < allowed_sw_lat) centerY = centerY+(allowed_sw_lat-current_sw_lat); 

    map.setCenter(new google.maps.LatLng(centerY,centerX)); 
} 
} 
+0

Questa è l'unica risposta che ho trovato che prende in considerazione i limiti esterni e non solo il centro. Affidarsi al solo centro consente di eseguire una panoramica ben al di fuori dell'area desiderata a seconda del livello di zoom. – James

1

Grazie @sairafi. la tua risposta mi ha fatto molto chiudi, ero getti ng un errore in cui getBounds non era definito, quindi l'ho spostato in un altro listener per assicurarmi che la mappa fosse stata caricata per prima.

google.maps.event.addListenerOnce(map, 'tilesloaded', function() { 
    allowedBounds = map.getBounds(); 
    google.maps.event.addListener(map,'center_changed',function() { checkBounds(allowedBounds); }); 
}); 

// Limit map area 
function checkBounds(allowedBounds) { 

if(!allowedBounds.contains(map.getCenter())) { 
    var C = map.getCenter(); 
    var X = C.lng(); 
    var Y = C.lat(); 

    var AmaxX = allowedBounds.getNorthEast().lng(); 
    var AmaxY = allowedBounds.getNorthEast().lat(); 
    var AminX = allowedBounds.getSouthWest().lng(); 
    var AminY = allowedBounds.getSouthWest().lat(); 

    if (X < AminX) {X = AminX;} 
    if (X > AmaxX) {X = AmaxX;} 
    if (Y < AminY) {Y = AminY;} 
    if (Y > AmaxY) {Y = AmaxY;} 

    map.setCenter(new google.maps.LatLng(Y,X)); 
} 
} 
0
southWest = new google.maps.LatLng(48.59475380744011,22.247364044189453); 
      northEast = new google.maps.LatLng(48.655344320891444,22.352420806884766); 
      var limBound = new google.maps.LatLngBounds(southWest,northEast); 
      var lastCenter; 

      var option = {zoom:15, 
      center: limBound.getCenter(), 
      mapTypeId: google.maps.MapTypeId.ROADMAP}; 
      var map = new google.maps.Map(document.getElementById('divMap'),option); 
      google.maps.event.addListener(map,'zoom_changed', function() { 
       minZoom(15); 
       }); 
      google.maps.event.addListener(map,'drag',function(e){ 
       limitBound(limBound); 
       }); 

     function minZoom(minZoom){ 
       if (map.getZoom()<minZoom) 
       {map.setZoom(minZoom);} 
      };  

     function limitBound(bound) 
     { 
      if (bound.getNorthEast().lat() > map.getBounds().getNorthEast().lat() 
       && bound.getNorthEast().lng() > map.getBounds().getNorthEast().lng() 
       && bound.getSouthWest().lat() < map.getBounds().getSouthWest().lat() 
       && bound.getSouthWest().lng() < map.getBounds().getSouthWest().lng()) 
       { 
        lastCenter=map.getCenter(); 
        $('#divText').text(lastCenter.toString()); 
        } 
       if (bound.contains(map.getCenter())) 
       { 
        map.setCenter(lastCenter); 
        } 
      } 
0

@sairafi e @devin

grazie per entrambe le risposte. Potrei non far funzionare questo in Chrome/Windows 7 perché il controllo di .comtains() si è verificato su true e false non appena si raggiunge il limite.

Così ho cambiato il setCenter() in basso a Panto()

Il secondo problema era che se si stabilisce i confini del carico iniziale, è necessario utilizzare il google.maps.event.addListenerOnce (mappa, 'inattivo' ...) evento altrimenti continua a reimpostare i limiti della mappa attualmente visualizzabile.

Infine, utilizzo l'evento di trascinamento per i centri di tracciamento, per qualche motivo che ha funzionato in modo più fluido.

Il codice risultante è questo:

google.maps.event.addListenerOnce(map,'idle',function() { 
     allowedBounds = map.getBounds(); 
    }); 
    google.maps.event.addListener(map,'drag',function() { 
     checkBounds(); 
    }); 
    function checkBounds() {  
     if(! allowedBounds.contains(map.getCenter())) 
     { 
      var C = map.getCenter(); 
      var X = C.lng(); 
      var Y = C.lat(); 
      var AmaxX = allowedBounds.getNorthEast().lng(); 
      var AmaxY = allowedBounds.getNorthEast().lat(); 
      var AminX = allowedBounds.getSouthWest().lng(); 
      var AminY = allowedBounds.getSouthWest().lat(); 
      if (X < AminX) {X = AminX;} 
      if (X > AmaxX) {X = AmaxX;} 
      if (Y < AminY) {Y = AminY;} 
      if (Y > AmaxY) {Y = AmaxY;} 
      map.panTo(new google.maps.LatLng(Y,X)); 
     } 
    } 
6

Si potrebbe anche prendere in considerazione incarto coordinate, distorsione curva e centerizing alle dimensioni rilegati se la mappa ridimensiona o zoom in/out. Questo è particolarmente necessario se i tuoi limiti occupano una grande percentuale dell'intera mappa (ad esempio, come un continente).

Uno dei problemi con checkBounds() è che non tiene conto dei valori di latitudine vicini ai poli nord/sud, che hanno una distorsione non lineare che limita i limiti in accuratezza (I utilizzare moltiplicatori di numeri magici approssimativi che non funzioneranno in tutte le situazioni). A destra, dovresti prima convertire i limiti in coordinate del mondo 2d lineari per vedere quanto è lontano dai confini in termini di coordinate del mondo, piuttosto che mappare il vero punto centrale del bersaglio in coordinate mondiali con la posizione attuale di latitudine bersaglio.Per i valori di longitudine, questo non sembra molto problema e l'approccio di clipping lineare sembra abbastanza accurato, il problema principale è con l'avvolgimento delle coordinate di longitudine che è rappresentato (in qualche modo) nel codice sottostante.

// Persitant variables 
var allowedBounds; // assign something here 
var lastValidCenter; // initialize this using map.getCenter() 

function checkBounds() { // when bounds changes due to resizing or zooming in/out 

    var currentBounds = map.getBounds(); 
    if (currentBounds == null) return; 

     var allowed_ne_lng = allowedBounds.getNorthEast().lng(); 
     var allowed_ne_lat = allowedBounds.getNorthEast().lat(); 
     var allowed_sw_lng = allowedBounds.getSouthWest().lng(); 
     var allowed_sw_lat = allowedBounds.getSouthWest().lat(); 

    var wrap; 
    var cc = map.getCenter(); 
    var centerH = false; 
    var centerV = false; 

    // Check horizontal wraps and offsets 
    if (currentBounds.toSpan().lng() > allowedBounds.toSpan().lng()) { 
     centerH = true; 
    } 
    else { // test positive and negative wrap respectively 
     wrap = currentBounds.getNorthEast().lng() < cc.lng(); 
     var current_ne_lng = !wrap ? currentBounds.getNorthEast().lng() : allowed_ne_lng +(currentBounds.getNorthEast().lng() + 180) + (180 - allowed_ne_lng); 
     wrap = currentBounds.getSouthWest().lng() > cc.lng(); 
     var current_sw_lng = !wrap ? currentBounds.getSouthWest().lng() : allowed_sw_lng - (180-currentBounds.getSouthWest().lng()) - (allowed_sw_lng+180); 
    } 


    // Check vertical wraps and offsets 
    if (currentBounds.toSpan().lat() > allowedBounds.toSpan().lat()) { 
     centerV = true; 
    } 
    else { // test positive and negative wrap respectively 
    wrap = currentBounds.getNorthEast().lat() < cc.lat(); if (wrap) { alert("WRAp detected top") } // else alert("no wrap:"+currentBounds); wrap = false; 
     var current_ne_lat = !wrap ? currentBounds.getNorthEast().lat() : allowed_ne_lat + (currentBounds.getNorthEast().lat() +90) + (90 - allowed_ne_lat); 
     wrap = currentBounds.getSouthWest().lat() > cc.lat(); if (wrap) { alert("WRAp detected btm") } //alert("no wrap:"+currentBounds); 
     var current_sw_lat = !wrap ? currentBounds.getSouthWest().lat() : allowed_sw_lat - (90-currentBounds.getSouthWest().lat()) - (allowed_sw_lat+90); 
    } 


     // Finalise positions 
     var centerX = cc.lng(); 
     var centerY = cc.lat(); 
    if (!centerH) { 
     if (current_ne_lng > allowed_ne_lng) centerX -= current_ne_lng-allowed_ne_lng; 
     if (current_sw_lng < allowed_sw_lng) centerX += allowed_sw_lng-current_sw_lng; 
    } 
    else { 
     centerX = allowedBounds.getCenter().lng(); 
    } 

    if (!centerV) { 
     if (current_ne_lat > allowed_ne_lat) { 
      centerY -= (current_ne_lat-allowed_ne_lat) * 3; // approximation magic numbeer. Adjust as u see fit, or use a more accruate pixel measurement. 
     } 
     if (current_sw_lat < allowed_sw_lat) { 
      centerY += (allowed_sw_lat-current_sw_lat)*2.8; // approximation magic number 
     } 
    } 
    else { 
     centerY = allowedBounds.getCenter().lat(); 
    } 
    map.setCenter(lastValidCenter = new google.maps.LatLng(centerY,centerX)); 
} 



function limitBound(bound) // Occurs during dragging, pass allowedBounds to this function in most cases. Requires persistant 'lastValidCenter=map.getCenter()' var reference. 
    { 
     var mapBounds = map.getBounds(); 

     if ( mapBounds.getNorthEast().lng() >= mapBounds.getSouthWest().lng() && mapBounds.getNorthEast().lat() >= mapBounds.getSouthWest().lat() // ensure no left/right, top/bottom wrapping 
      && bound.getNorthEast().lat() > mapBounds.getNorthEast().lat() // top 
      && bound.getNorthEast().lng() > mapBounds.getNorthEast().lng() // right 
      && bound.getSouthWest().lat() < mapBounds.getSouthWest().lat() // bottom 
      && bound.getSouthWest().lng() < mapBounds.getSouthWest().lng()) // left 
      { 
       lastValidCenter=map.getCenter(); // valid case, set up new valid center location 
      } 

     // if (bound.contains(map.getCenter())) 
     // { 
       map.panTo(lastValidCenter); 
      // } 

     } 



// Google map listeners 

google.maps.event.addListener(map, 'zoom_changed', function() { 
    //var zoom = map.getZoom(); 
    checkBounds(); 
}); 

google.maps.event.addListener(map, "bounds_changed", function() { 

    checkBounds(); 
}); 

google.maps.event.addListener(map, 'center_changed', function() { 
     limitBound(allowedBounds); 
}); 

P.S Per checkBounds(), per ottenere una corretta coordinare mondo 2d dal centro della mappa, data 2 valori LAT/LNG, utilizzare map.getProjection(). FromLatLngToPoint(). Confrontate i 2 punti, individuate la differenza lineare tra di loro e mappate la differenza delle coordinate del mondo a lat/lng usando map.getProjection(). FromPointToLatLng(). Ciò ti fornirà offset di clip accurati in unità lat/lng.

Problemi correlati