【问题标题】:Google Maps API V3: limit map bounds [duplicate]Google Maps API V3:限制地图范围[重复]
【发布时间】: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 的解决方案是什么?

【问题讨论】:

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


    【解决方案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));
                    } 
                }
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2012-10-14
              • 2013-10-03
              • 1970-01-01
              • 2014-04-21
              • 1970-01-01
              • 2011-04-01
              • 2011-12-25
              相关资源
              最近更新 更多