Google Maps API V3:限制地图范围[重复]

Posted

技术标签:

【中文标题】Google Maps API V3:限制地图范围[重复]【英文标题】:Google Maps API V3: limit map bounds [duplicate] 【发布时间】:2011-04-23 12:43:44 【问题描述】:

我正在尝试设置可以使用 Google Maps API V3 拖动地图的范围 这是 V2 http://econym.org.uk/gmap/example_range.htm 的解决方案,效果很好。

但是使用 API V3 就不是很好了:当您使用相同的 checkbounds() 函数时,当您到达边界时地图会抽搐,而 map.setCenter() 会更改地图的中心。

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

【问题讨论】:

【参考方案1】:

我遇到了同样的问题,但这应该解决它(它是相同的功能,要听的事件从'move'或'drag'更改为'center_changed',就像一个魅力!:

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

【讨论】:

我用过这个,效果很好。干杯! allowedBounds 设置为什么? allowedBounds 是LatLngBounds object(基本上是一对纬度/经度)。顺便说一句,这真的很好用,完全符合我的要求! 这不考虑缩放级别,因此您仍然可以在预期区域之外很好地进行操作。【参考方案2】:

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

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 个纬度/经度值,请使用 map.getProjection().fromLatLngToPoint()。比较 2 个点,找到它们之间的线性差异,然后使用 map.getProjection().fromPointToLatLng() 将世界坐标的差异映射回 lat/lng。这将为您提供以 lat/lng 为单位的准确剪辑偏移。

【讨论】:

【参考方案3】:

此脚本获取初始边界 (allowedBounds) 并限制 dragzoom_changed 的边界。缩放也限制在

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

【讨论】:

这是我发现的唯一一个考虑到外部边界而不仅仅是中心的答案。仅依靠中心,您仍然可以根据缩放级别在预期区域之外进行平移。【参考方案4】:

感谢@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));


【讨论】:

【参考方案5】:
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);
                    
             

【讨论】:

【参考方案6】:

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

map.fitBounds(mapBounds);

【讨论】:

【参考方案7】:

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

【讨论】:

以上是关于Google Maps API V3:限制地图范围[重复]的主要内容,如果未能解决你的问题,请参考以下文章

google maps js v3 api教程 -- 创建一个地图

在 Google Maps API v3 中缩放到 geojson 多边形边界

google maps js v3 api教程 -- 在地图上添加标记

如何限制 Google 地图 API V3 中的平移?

Google Maps API v3 将地图重新​​定位到标记

Google Maps v3 - 限制可视区域和缩放级别