Javascript 如何在 Google Maps API V3 中限制平移?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3125065/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 03:21:01  来源:igfitidea点击:

How do I limit panning in Google maps API V3?

javascriptgoogle-mapsgoogle-maps-api-3

提问by E. Tal

In V2 there was a way to limit panning/dragging so the map stays within certain bounds. How is that done in V3?

在 V2 中,有一种方法可以限制平移/拖动,以便地图保持在特定范围内。在 V3 中是如何做到的?

Let's say I want the users to only look at Europe. I've already limited the zoom, but if I allow dragging (which I have to in this case, for other reasons) then the user can pan beyond the area I want to show.

假设我希望用户只关注欧洲。我已经限制了缩放,但是如果我允许拖动(在这种情况下我必须这样做,因为其他原因)然后用户可以平移超出我想要显示的区域。

Please give working example or code snippet - I'm not an expert coder...

请给出工作示例或代码片段-我不是专家编码员...

回答by HenningJ

I guess I'm a little bit late to the party, but since this was exactly what I needed just now AND I improved on it, I thought I'd post an answer anyway.

我想我参加聚会有点晚了,但是由于这正是我刚才所需要的并且我对此有所改进,因此我想无论如何我都会发布答案。

With both the answers of Daniel Vassalloand brendo, the user can still use the pan-control (if it's activated) to move away from the wanted area. The thing @Yauhen.F mentioned in a comment.

有了Daniel Vassallobrendo的答案,用户仍然可以使用平移控件(如果它被激活)从想要的区域移开。@Yauhen.F 在评论中提到的事情。

So instead of using the dragend event, I use the center_changed event. This is continuously fired during dragging and every time someone uses the pan control.

因此,我没有使用 dragend 事件,而是使用 center_changed 事件。在拖动过程中以及每次有人使用平移控件时都会连续触发。

// bounds of the desired area
var allowedBounds = new google.maps.LatLngBounds(
     new google.maps.LatLng(70.33956792419954, 178.01171875), 
     new google.maps.LatLng(83.86483689701898, -88.033203125)
);
var lastValidCenter = map.getCenter();

google.maps.event.addListener(map, 'center_changed', function() {
    if (allowedBounds.contains(map.getCenter())) {
        // still within valid bounds, so save the last valid position
        lastValidCenter = map.getCenter();
        return; 
    }

    // not valid anymore => return to last valid position
    map.panTo(lastValidCenter);
});

By saving the last valid position continuously during the dragging, the movement will just stop once it's out of bounds, instead of yerking back once the dragging ended. ......

通过在拖动过程中连续保存最后一个有效位置,一旦超出范围,运动就会停止,而不是在拖动结束后立即返回。......

回答by Daniel Vassallo

The trick is to listen to the dragendevent, and if the map is dragged outside the allowed bounds, move it back inside. If you define your allowed bounds as a LatLngBoundsobject, you can use the contains()method, since it returns true if the given lat/lng argument is within the bounds.

诀窍是监听dragend事件,如果地图被拖到允许的范围之外,请将其移回内部。如果您将允许的边界定义为LatLngBounds对象,则可以使用该contains()方法,因为如果给定的 lat/lng 参数在边界内,它会返回 true。

It is also important to limit the zoom level, but it seems you are already doing this.

限制缩放级别也很重要,但您似乎已经在这样做了。

Therefore, you may want to try the following example:

因此,您可能想尝试以下示例:

<!DOCTYPE html>
<html> 
<head> 
   <meta http-equiv="content-type" content="text/html; charset=UTF-8"/> 
   <title>Google Maps JavaScript API v3 Example: Limit Panning</title> 
   <script type="text/javascript" 
           src="http://maps.google.com/maps/api/js?sensor=false"></script>
</head> 
<body> 
   <div id="map" style="width: 400px; height: 300px;"></div> 

   <script type="text/javascript"> 

   var minZoomLevel = 5;

   var map = new google.maps.Map(document.getElementById('map'), {
      zoom: minZoomLevel,
      center: new google.maps.LatLng(38.50, -90.50),
      mapTypeId: google.maps.MapTypeId.ROADMAP
   });

   // Bounds for North America
   var allowedBounds = new google.maps.LatLngBounds(
     new google.maps.LatLng(28.70, -127.50), 
     new google.maps.LatLng(48.85, -55.90));

   // Listen for the dragend event
   google.maps.event.addListener(map, 'dragend', function() {
     if (allowedBounds.contains(map.getCenter())) return;

     // Out of bounds - Move the map back within the bounds

     var c = map.getCenter(),
         x = c.lng(),
         y = c.lat(),
         maxX = allowedBounds.getNorthEast().lng(),
         maxY = allowedBounds.getNorthEast().lat(),
         minX = allowedBounds.getSouthWest().lng(),
         minY = allowedBounds.getSouthWest().lat();

     if (x < minX) x = minX;
     if (x > maxX) x = maxX;
     if (y < minY) y = minY;
     if (y > maxY) y = maxY;

     map.setCenter(new google.maps.LatLng(y, x));
   });

   // Limit the zoom level
   google.maps.event.addListener(map, 'zoom_changed', function() {
     if (map.getZoom() < minZoomLevel) map.setZoom(minZoomLevel);
   });

   </script> 
</body> 
</html>

Screenshot from the above example. The user will not be able to drag further south or far east in this case:

上面例子的截图。在这种情况下,用户将无法进一步向南或向东拖动:

Google Maps JavaScript API v3 Example: Limit Panning

Google Maps JavaScript API v3 示例:限制平移

回答by Koen.

My version, based on the one from @HenningJ, but with some modification of the lastValidCenterto allow smooth draggingalong the edges of the bounds.

我的版本基于@HenningJ 的版本,但对 进行了一些修改lastValidCenter以允许沿边界边缘平滑拖动

<!DOCTYPE html>
<html>
    <head>
        <style type="text/css">
            html { height: 100% }
            body { height: 100%; margin: 0; padding: 0 }
            #map-canvas { height: 100% }
        </style>
        <script type="text/javascript"
            src="http://maps.google.com/maps/api/js?sensor=false"></script>
        </script>
        <script type="text/javascript">
            function initialize() {
                var mapOptions = {
                    center: new google.maps.LatLng(28.70, -127.50),
                    zoom: 4,
                    mapTypeId: google.maps.MapTypeId.ROADMAP
                };
                var map = new google.maps.Map(document.getElementById("map-canvas"),
                        mapOptions);

                // bounds of the desired area
                var allowedBounds = new google.maps.LatLngBounds(
                  new google.maps.LatLng(28.70, -127.50),
                  new google.maps.LatLng(48.85, -55.90)
                );
                var boundLimits = {
                    maxLat : allowedBounds.getNorthEast().lat(),
                    maxLng : allowedBounds.getNorthEast().lng(),
                    minLat : allowedBounds.getSouthWest().lat(),
                    minLng : allowedBounds.getSouthWest().lng()
                };

                var lastValidCenter = map.getCenter();
                var newLat, newLng;
                google.maps.event.addListener(map, 'center_changed', function() {
                    center = map.getCenter();
                    if (allowedBounds.contains(center)) {
                        // still within valid bounds, so save the last valid position
                        lastValidCenter = map.getCenter();
                        return;
                    }
                    newLat = lastValidCenter.lat();
                    newLng = lastValidCenter.lng();
                    if(center.lng() > boundLimits.minLng && center.lng() < boundLimits.maxLng){
                        newLng = center.lng();
                    }
                    if(center.lat() > boundLimits.minLat && center.lat() < boundLimits.maxLat){
                        newLat = center.lat();
                    }
                    map.panTo(new google.maps.LatLng(newLat, newLng));
                });
            }
            google.maps.event.addDomListener(window, 'load', initialize);
        </script>
    </head>
    <body>
        <div id="map-canvas"/>
    </body>
</html>

Fiddle here: http://jsfiddle.net/koenpunt/n7h6t/

在这里小提琴:http: //jsfiddle.net/koenpunt/n7h6t/

回答by AjayR

The best method to restrict is, set the zoom level and center point and disable the controls like zoom, scroll etc like below.

限制的最佳方法是,设置缩放级别和中心点并禁用缩放、滚动等控件,如下所示。

 var latlng = new google.maps.LatLng(18.283078,84.047556);
     var myOptions = {
          zoom: 12,

          center: latlng,
          zoomControl: false,
          mapTypeId: google.maps.MapTypeId.ROADMAP,
          scrollwheel: false,
        navigationControl: false,
        mapTypeControl: false,
        scaleControl: false,
        draggable: false,
        disableDoubleClickZoom: true,
        };
        map = new google.maps.Map(document.getElementById("map_canvas"),   myOptions);

回答by brendo

Here is a nice extension to the abovethat will reset the Map's center to the last valid position by listening to the dragstart event.

这是对上述内容的一个很好的扩展,它将通过侦听 dragstart 事件将地图的中心重置为最后一个有效位置。

// Limit panning
var lastCenter = map.getCenter();

google.maps.event.addListener(map, 'dragstart', function() {
    lastCenter = map.getCenter();
});

google.maps.event.addListener(map, 'dragend', function() {
    if(allowedBounds.contains(map.getCenter())) return;

    map.setCenter(lastCenter);
});

回答by George Huber

Here's a solution which is a merge together of Tom Andersen's answer and the currently accepted HenningJ answer. The benefits of this is it 1) allows for smoother scrolling along edges (which HenningJ's solution seemed clunky with), and 2) doesn't have any issues when zooming in an out of an area (again HenningJ's answer seemed to break when zooming in and out near the boundaries).

这是一个解决方案,它是 Tom Andersen 的答案和当前接受的 HenningJ 答案的合并。这样做的好处是 1) 允许沿边缘更平滑的滚动(HenningJ 的解决方案似乎很笨拙),并且 2)在放大区域时没有任何问题(再次,HenningJ 的答案在放大时似乎会中断)并在边界附近)。

Tom's answer was close to working for me, except it positioned the locked off area into the center of the screen, which wasn't acceptable for the application I was working on.

Tom 的回答几乎对我有用,只是它将锁定区域定位在屏幕中央,这对于我正在处理的应用程序来说是不可接受的。

// bounds of the desired area
var allowedBounds = new google.maps.LatLngBounds(
     new google.maps.LatLng(70.33956792419954, 178.01171875), 
     new google.maps.LatLng(83.86483689701898, -88.033203125)
);
var lastValidCenter = map.getCenter();

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

    var mapBounds = map.getBounds();
    var mapNe = mapBounds.getNorthEast();
    var mapSw = mapBounds.getSouthWest();
    var center = map.getCenter();

    if( allowedBounds.contains(mapNe) && allowedBounds.contains(mapSw) ) {
        //the user is scrolling within the bounds.
        lastValidCenter = center;
        return;
    }

    //the user has scrolled beyond the edge.

    var mapWidth = mapNe.lng() - mapSw.lng();
    var mapHeight = mapNe.lat() - mapSw.lat();

    var x = center.lng();
    var y = center.lat();

    var maxX = allowedBounds.getNorthEast().lng();
    var maxY = allowedBounds.getNorthEast().lat();
    var minX = allowedBounds.getSouthWest().lng();
    var minY = allowedBounds.getSouthWest().lat();

    //shift the min and max dimensions by 1/2 of the screen size, so the bounds remain at the edge of the screen

    maxX -= (mapWidth / 2);
    minX += (mapWidth / 2);

    maxY -= (mapHeight / 2);
    minY += (mapHeight / 2);


    if (x < minX) {
        x = minX;
    }
    if (x > maxX) {
        x = maxX;
    }
    if (y < minY){
        y = minY;
    }
    if (y > maxY){
        y = maxY;
    }

    map.panTo(new google.maps.LatLng(y, x));

});

回答by Chris Halcrow

Here's a simple solution that will work across mobile and desktop. It will stop the map panning beyond the world's maximum or minimum latitude, and allows a minimum zoom level to be set, which can help to prevent grey areas becoming visible through zooming too far out (depending on the size you set for your map):

这是一个适用于移动设备和桌面设备的简单解决方案。它将停止地图平移超出世界的最大或最小纬度,并允许设置最小缩放级别,这有助于防止灰色区域因放大太远而变得可见(取决于您为地图设置的大小):

(I recommend caution in using the center_changed event as suggested in the accepted answer by HenningJ. In my case the number of events this creates caused stack overflow errors in Google Chrome. Instead, the 'dragend' event can be used - although this will allow the user to drag outside of the areas, and will then immediately 'snap back' to a valid area of the map).

(我建议在使用 HenningJ 接受的答案中建议的 center_changed 事件时要谨慎。在我的情况下,这造成的事件数量会导致 Google Chrome 中的堆栈溢出错误。相反,可以使用 'dragend' 事件 - 尽管这将允许用户拖动到区域之外,然后将立即“回弹”到地图的有效区域)。

var lastValidCenter;
var minZoomLevel = 2;

setOutOfBoundsListener();

function setOutOfBoundsListener() {
        google.maps.event.addListener(map, 'dragend', function () {
            checkLatitude(map);
        });
        google.maps.event.addListener(map, 'idle', function () {
            checkLatitude(map);
        });
        google.maps.event.addListener(map, 'zoom_changed', function () {
            checkLatitude(map);
        });
};

function checkLatitude(map) {
    if (this.minZoomLevel) {
        if (map.getZoom() < minZoomLevel) {
            map.setZoom(parseInt(minZoomLevel));
        }
    }

    var bounds = map.getBounds();
    var sLat = map.getBounds().getSouthWest().lat();
    var nLat = map.getBounds().getNorthEast().lat();
    if (sLat < -85 || nLat > 85) {
        //the map has gone beyone the world's max or min latitude - gray areas are visible
        //return to a valid position
        if (this.lastValidCenter) {
            map.setCenter(this.lastValidCenter);
        }
    }
    else {
        this.lastValidCenter = map.getCenter();
    }
}

回答by Brandon Peters

I tried the answer from HenningJ and the map wouldn't stop panning until the center was in a corner of the bounds which was not ideal. Here is my solution:

我尝试了 HenningJ 的答案,直到中心位于不理想的边界角落时,地图才会停止平移。这是我的解决方案:

google.maps.event.addListener(map, 'center_changed', function() {
    var mapBounds = map.getBounds();
    if(allowedBounds.contains(mapBounds.getNorthEast()) && allowedBounds.contains(mapBounds.getSouthWest())) {
        lastCenter = map.getCenter();
        return;
    }

    map.panTo(lastCenter);
}, this));

回答by tim

There is another threadon the subject that is also very good. The problem I had to solve was that instead of setting boundaries manually and checking center containment, I wanted a boundary set on page load, then allow dragging to the edge if zoomed in.

还有另一个线程关于这个问题,这也是很不错的。我必须解决的问题是,我希望在页面加载时设置边界,而不是手动设置边界和检查中心包含情况,然后在放大时允许拖动到边缘。

So I set panning boundaries on map load, once. Then I check if map is still at max zoom and if so, return the initial center. If zoomed in, I want to pan to the EDGE of initial boundaries, not just check if CENTER contained, because that would extend the allowed panning by half the viewport.

所以我在地图加载时设置了平移边界,一次。然后我检查地图是否仍处于最大缩放,如果是,则返回初始中心。如果放大,我想平移到初始边界的 EDGE,而不仅仅是检查 CENTER 是否包含,因为这会将允许的平移扩展到视口的一半。

Unfortunately, although this gets the job done and works fine when paning slowly, it's a bit jerky if you pan quickly.

不幸的是,虽然这可以完成工作并且在缓慢平移时工作正常,但如果你快速平移,它会有点生涩。

If you have suggestions on how this can be avoided, I'd be grateful.

如果您有关于如何避免这种情况的建议,我将不胜感激。

    map = new google.maps.Map( // defaults
        document.getElementById("map22"),
        {
            disableDefaultUI        : true,
            zoomControl             : true,
            zoom                    : 7,
            minZoom                 : 7,
            maxZoom                 : 10,
            center                  : new google.maps.LatLng(
                64.99473104134819,
                -19.22332763671875
            ),
            mapTypeId               : google.maps.MapTypeId.ROADMAP
        }
    );



    function borders(){
        return {
            maxLat : map.getBounds().getNorthEast().lat(),
            maxLng : map.getBounds().getNorthEast().lng(),
            minLat : map.getBounds().getSouthWest().lat(),
            minLng : map.getBounds().getSouthWest().lng(),
            center : map.getCenter()
        }
    }

    google.maps.event.addListenerOnce(map,'idle',function() {
        limit = borders();
    });

    google.maps.event.addListener(map,'drag',function() {
        if(map.getZoom() == 7) return map.setCenter(limit.center);
        current = borders();
        if( current.maxLng < limit.maxLng && current.minLng > limit.minLng ) activeCenterLng = current.center.lng();
        if( current.maxLat < limit.maxLat && current.minLat > limit.minLat ) activeCenterLat = current.center.lat();
        map.setCenter(
            new google.maps.LatLng(
                activeCenterLat,
                activeCenterLng
            )
        );
    });

回答by johanj

When I'm using drag or dragend or whatever, the map jumps back into allowed bounds instead of simply restricting overflowing movement. Just change the event to 'center_changed' to stop it from jumping around like that.

当我使用 drag 或 dragend 或其他什么时,地图会跳回到允许的范围内,而不是简单地限制溢出的运动。只需将事件更改为 'center_changed' 即可阻止它像那样跳来跳去。

Modified jsfiddle: http://jsfiddle.net/Vjdde/1/

修改后的jsfiddle:http: //jsfiddle.net/Vjdde/1/

Edit: Not sure why the fiddle doesn't produce a stack overflow but it should, since setCenter will call center_changed again.. Just watch out

编辑:不知道为什么小提琴不会产生堆栈溢出,但它应该,因为 setCenter 会再次调用 center_changed .. 注意