Google Maps API V3:限制地图边界

时间:2010-10-10 18:34:02

标签: google-maps google-maps-api-3

我正在尝试设置界限,您可以使用Google Maps API V3拖动地图 以下是适用于V2 http://econym.org.uk/gmap/example_range.htm的解决方案。

然而,使用API​​ V3并不是那么好:当你使用相同的checkbounds()函数时,当你到达边界时地图会抽搐,而map.setCenter()会改变地图的中心。

如何解决? API V3的解决方案是什么?

7 个答案:

答案 0 :(得分:19)

我遇到了同样的问题,但这应该排除它(它是相同的功能,听的事件从'move'或'drag'改为'center_changed',就像一个魅力!:< / p>

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

答案 1 :(得分:6)

如果地图调整大小或放大/缩小,您可能还需要考虑环绕坐标,曲线扭曲和居中到边界尺寸。如果您的边界占据整个地图的很大一部分(例如像大陆一样),则尤其需要这样做。

checkBounds()的一个问题是,它没有考虑到接近北极/南极的纬度值,它们具有非线性失真,这使得限制界限准确(我使用)近似魔术数乘数,不适用于所有情况)。通过右边,您应该首先将边界转换为线性2d世界坐标,以查看它在世界坐标方面离边界的距离,而不是将世界坐标中的实际目标中心点映射到目标实际纬度位置。对于经度值,这似乎不是很多问题,线性剪切方法似乎足够准确,主要问题是经度坐标的包装,在下面的代码中(稍微)解释。

// 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对于checkBounds(),要从地图中心获取正确的2d世界坐标,给定2个lat / lng值,请使用map.getProjection()。fromLatLngToPoint()。比较2个点,找到它们之间的线性差异,并使用map.getProjection()。fromPointToLatLng()将世界坐标的差异映射回lat / lng。这将以lat / lng为单位为您提供精确的剪辑偏移。

答案 2 :(得分:4)

此脚本获取初始边界(allowedBounds)并限制dragzoom_changed上的边界。此外,缩放受限于&lt; 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));
 }
}

答案 3 :(得分:1)

谢谢@sairafi。你的回答让我非常接近。我得到一个错误,其中getBounds未定义,因此我将其包装在另一个侦听器中,以确保首先完全加载地图。

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

答案 4 :(得分: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);
                    }
             }

答案 5 :(得分:0)

请检查此Google Maps API v3: Can I setZoom after fitBounds?

map.fitBounds(mapBounds);

答案 6 :(得分:0)

@sairafi和@devin

感谢您的回答。我可以让它在Chrome / Windows 7中运行,因为.comtains()检查一旦你到达边界就会逐渐变为真和假。

所以我将底部的setCenter()更改为panTo()

第二个问题是如果你在初始加载时建立边界,你必须使用google.maps.event.addListenerOnce(map,'idle'...)事件,否则它会继续将边界重置为当前可见的地图。

最后,我确实将拖动事件用于跟踪中心,因为某些原因可以更顺利地进行。

结果代码如下:

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