2010-10-10 6 views
11

J'essaie de définir des limites où vous pouvez faire glisser la carte en utilisant Google Maps API V3 Voici la solution pour V2 http://econym.org.uk/gmap/example_range.htm qui fonctionne plutôt bien. Cependant, avec l'API V3, ce n'est pas très bon: lorsque vous utilisez la même fonction checkbounds(), la carte ticse quand vous atteignez la borne tandis que map.setCenter() change le centre de la carte.Google Maps API V3: limite les limites de la carte

Comment le réparer? Quelle est la solution pour API V3?

Répondre

19

J'ai eu le même problème, mais cela devrait trier (c'est la même fonction, l'événement à écouter est changé de 'déplacer' ou 'glisser' en 'centre_changed', fonctionne comme un charme!

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

J'ai utilisé ceci et cela fonctionne génial. À votre santé! –

+5

Que définit 'allowedBounds'? – travis

+1

allowedBounds est un [objet LatLngBounds] (https://developers.google.com/maps/documentation/javascript/reference#LatLngBounds) (essentiellement une paire de latitudes/longitudes). Cela fonctionne très bien BTW, fait exactement ce qu'il devrait pour moi! – strikernl

4

Ce script obtient les limites initiales (allowedBounds) et limiter les limites sur drag et zoom_changed. de plus, le zoom est limité sur < 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

C'est la seule réponse que j'ai trouvée qui prend en compte les limites extérieures et pas seulement le centre. S'appuyer uniquement sur le centre vous permet de toujours effectuer un panoramique à l'extérieur d'une zone prévue en fonction du niveau de zoom. – James

1

Merci @sairafi. Votre réponse m'a très fermer, j'étais getti ng une erreur où getBounds n'était pas défini, donc je l'ai enveloppé dans un autre écouteur pour m'assurer que la carte était entièrement chargée en premier.

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 et @devin

merci pour vos deux réponses. Je pourrais faire fonctionner cela dans Chrome/Windows 7 parce que le chèque de .comtains() a évlauated à la fois vrai et faux dès que vous frappez la limite.

donc j'ai changé le setCenter() en bas à panTo()

Le deuxième problème est que si vous établissez des limites de la charge initiale, vous devez utiliser le google.maps.event.addListenerOnce (carte, 'idle' ...) sinon il continue à réinitialiser les limites de la carte actuellement visible.

Enfin, j'utilise l'événement glisser pour les centres de suivi, pour une raison qui a fonctionné plus facilement.

Le code résultant est la suivante:

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

Vous pourriez aussi prendre en compte les coordonnées d'emballage, déformation de la courbe, et centerizing aux dimensions liées si la carte redimensionne ou effectuer un zoom avant/arrière. Ceci est particulièrement nécessaire si vos limites occupent un grand pourcentage de la carte entière (par exemple, comme un continent). L'un des problèmes avec checkBounds() est qu'il ne prend pas en compte les valeurs de latitude proches des pôles nord/sud, qui ont une distorsion non linéaire qui limite les limites in-justes (I (0)). utiliser des multiplicateurs de nombres magiques approximatifs qui ne fonctionneront pas dans toutes les situations). De droite, vous devez d'abord convertir les bornes en coordonnées linéaires 2D pour voir à quelle distance elles sont en termes de coordonnées du monde, que de mapper le point central réel en coordonnées du monde à la position de latitude réelle cible.Pour les valeurs de longitude, cela ne semble pas très problématique et l'approche de l'écrêtage linéaire semble assez précise, le problème principal est avec l'enroulement des coordonnées de longitude qui est pris en compte (un peu) dans le code ci-dessous.

// 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 Pour CheckBounds(), pour obtenir une bonne monde 2d coordonnées du centre de la carte, étant donné 2 lat/valeurs lng, utilisez map.getProjection(). FromLatLngToPoint(). Comparez les 2 points, trouvez la différence linéaire entre eux et mappez la différence entre les coordonnées du monde et lat/lng en utilisant map.getProjection(). FromPointToLatLng(). Cela vous donnera des décalages de clip précis dans les unités lat/lng.

Questions connexes