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

Posted

技术标签:

【中文标题】Google Maps v3 - 限制可视区域和缩放级别【英文标题】:Google Maps v3 - limit viewable area and zoom level 【发布时间】:2011-04-18 14:18:09 【问题描述】:

是否可以将 Google 地图 v3 限制在某个区域?我想只允许显示某个区域(例如一个国家)并禁止用户在其他地方滑动。我也想限制缩放级别 - 例如仅在 6 级和 9 级之间。我想使用所有基本地图类型。

有什么方法可以实现吗?

我通过使用 StyledMap 在限制缩放级别方面取得了部分成功,但我仅在限制 ROADMAP 方面取得了成功,我无法通过这种方式限制其他基本类型的缩放。

感谢您的帮助

【问题讨论】:

【参考方案1】:

您可以收听dragend 事件,如果地图被拖到允许范围之外,请将其移回内部。您可以在 LatLngBounds 对象中定义允许的边界,然后使用 contains() 方法检查新的纬度/经度中心是否在边界内。

您还可以非常轻松地限制缩放级别。

考虑以下示例:Fiddle Demo

<!DOCTYPE html>
<html> 
<head> 
   <meta http-equiv="content-type" content="text/html; charset=UTF-8"/> 
   <title>Google Maps javascript API v3 Example: Limit Panning and Zoom</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"> 

   // This is the minimum zoom level that we'll allow
   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 strictBounds = 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 (strictBounds.contains(map.getCenter())) return;

     // We're out of bounds - Move the map back within the bounds

     var c = map.getCenter(),
         x = c.lng(),
         y = c.lat(),
         maxX = strictBounds.getNorthEast().lng(),
         maxY = strictBounds.getNorthEast().lat(),
         minX = strictBounds.getSouthWest().lng(),
         minY = strictBounds.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>

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

【讨论】:

这个决定看起来不太干净。为什么if (x &lt; minX) x = minX;if (x &gt; maxX) x = maxX; 不互相排斥?为什么将画布居中在 minX/maxX 和 maxX/maxY 坐标上,尽管它们不是中心坐标? 您可以在地图实例 (working example) 上使用 draggable: false 而不是 dragend 事件 这不是使用“zoom_changed”事件来限制用户的好方法。因为第一次它总是会超出最小级别,然后使用您的代码,您将再次设置最小缩放,这将在屏幕上闪烁。 检查zillow.com/homes/for_sale/days_sort/…他们以正确的方式完成了它,不知道如何。 如果我更改为 center_changed 事件而不是 dragend,这对我来说非常有效。【参考方案2】:

限制缩放级别的更好方法可能是使用minZoom/maxZoom 选项而不是对事件做出反应?

var opt =  minZoom: 6, maxZoom: 9 ;
map.setOptions(opt);

或者可以在地图初始化时指定选项,例如:

var map = new google.maps.Map(document.getElementById('map-canvas'), opt);

见:Google Maps JavaScript API V3 Reference

【讨论】:

现在这无疑是限制缩放级别的最佳方式。当我写这篇文章时,地图 API v3 中没有这个功能。值得庆幸的是,他们不断改进 API。 这很好用,这应该是缩放的最佳答案。 这应该被标记为那些只看所选答案的人的答案。 设置缩放级别对平移没有影响。 绝对是最好的方式【参考方案3】:

限制范围的更好方法...使用了上面海报中的包含逻辑。

var dragStartCenter;

google.maps.event.addListener(map, 'dragstart', function()
                                       dragStartCenter = map.getCenter();
                                         );

google.maps.event.addListener(this.googleMap, 'dragend', function()
                            if (mapBounds.contains(map.getCenter())) return;
                    map.setCenter(this.dragStart);
                           );

【讨论】:

为什么要为第二个听众添加this.googleMap 而不是mapdragStart 也不应该是 dragStartCenter 吗?最后mapBounds是什么? 所做的一切就是阻止用户在一次拖动中拖动到远处吗?他们仍然可以做很多小事并最终到任何地方,不是吗?【参考方案4】:

这是我解决可视区域限制问题的变体。

        google.maps.event.addListener(this.map, 'idle', function() 
            var minLat = strictBounds.getSouthWest().lat();
            var minLon = strictBounds.getSouthWest().lng();
            var maxLat = strictBounds.getNorthEast().lat();
            var maxLon = strictBounds.getNorthEast().lng();
            var cBounds  = self.map.getBounds();
            var cMinLat = cBounds.getSouthWest().lat();
            var cMinLon = cBounds.getSouthWest().lng();
            var cMaxLat = cBounds.getNorthEast().lat();
            var cMaxLon = cBounds.getNorthEast().lng();
            var centerLat = self.map.getCenter().lat();
            var centerLon = self.map.getCenter().lng();

            if((cMaxLat - cMinLat > maxLat - minLat) || (cMaxLon - cMinLon > maxLon - minLon))
               //We can't position the canvas to strict borders with a current zoom level
                self.map.setZoomLevel(self.map.getZoomLevel()+1);
                return;
            
            if(cMinLat < minLat)
                var newCenterLat = minLat + ((cMaxLat-cMinLat) / 2);
            else if(cMaxLat > maxLat)
                var newCenterLat = maxLat - ((cMaxLat-cMinLat) / 2);
            else
                var newCenterLat = centerLat;
            if(cMinLon < minLon)
                var newCenterLon = minLon + ((cMaxLon-cMinLon) / 2);
            else if(cMaxLon > maxLon)
                var newCenterLon = maxLon - ((cMaxLon-cMinLon) / 2);
            else
                var newCenterLon = centerLon;

            if(newCenterLat != centerLat || newCenterLon != centerLon)
                self.map.setCenter(new google.maps.LatLng(newCenterLat, newCenterLon));
        );

strictBoundsnew google.maps.LatLngBounds() 类型的对象。 self.gmap 存储一个 Google 地图对象 (new google.maps.Map())。

它确实有效,但如果你的界限覆盖它们,不要只忘记考虑跨越第 0 个经络和平行线的痔疮。

【讨论】:

已接受 Daniel Vassallo 的算法不适用于我。这里有几个主要区别。【参考方案5】:

由于某种原因

if (strictBounds.contains(map.getCenter())) return;

对我没用(可能是南半球问题)。我不得不将其更改为:

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

        if(x < minX || x > maxX || y < minY || y > maxY) 
            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));
        
    

希望对某人有所帮助。

【讨论】:

【参考方案6】:

这可能会有所帮助。

  var myOptions = 
      center: new google.maps.LatLng($lat,$lang),
      zoom: 7,
      disableDefaultUI: true,
      mapTypeId: google.maps.MapTypeId.ROADMAP
    ;

缩放级别可根据需要自定义。

【讨论】:

这并没有解决关于将缩放级别限制在e.g. only between levels 6 and 9 范围内的原始问题,它设置了 default 缩放级别并删除了默认 UI(即 @987654323 @/-) 这有点矫枉过正。【参考方案7】:

一个解决方案就像,如果你知道具体的纬度/经度。

google.maps.event.addListener(map, 'idle', function() 

    map.setCenter(new google.maps.LatLng(latitude, longitude));
    map.setZoom(8);

);

如果没有特定的纬度/经度

google.maps.event.addListener(map, 'idle', function() 

    map.setCenter(map.getCenter());
    map.setZoom(8);

);

google.maps.event.addListener(map, 'idle', function() 

    var bounds = new google.maps.LatLngBounds();
    map.setCenter(bounds.getCenter());
    map.setZoom(8);

);

【讨论】:

【参考方案8】:

在 v.3+ 上限制缩放。 在您的地图设置中添加默认缩放级别和 minZoom 或 maxZoom(或两者如果需要) 缩放级别为 0 到 19。 如果需要限制,您必须声明默认缩放级别。都区分大小写!

function initialize() 
   var mapOptions = 
      maxZoom:17,
      minZoom:15,
      zoom:15,
      ....

【讨论】:

【参考方案9】:

这可用于将地图重新​​居中到特定位置。这是我需要的。

    var MapBounds = new google.maps.LatLngBounds(
    new google.maps.LatLng(35.676263, 13.949096),
    new google.maps.LatLng(36.204391, 14.89038));

    google.maps.event.addListener(GoogleMap, 'dragend', function ()
    
        if (MapBounds.contains(GoogleMap.getCenter()))
        
            return;
        
        else
        
            GoogleMap.setCenter(new google.maps.LatLng(35.920242, 14.428825));
        
    );

【讨论】:

【参考方案10】:
myOptions = 
        center: myLatlng,
        minZoom: 6,
        maxZoom: 9,
        styles: customStyles,
        mapTypeId: google.maps.MapTypeId.ROADMAP
    ;

【讨论】:

这没有回答问题。【参考方案11】:

截至 2016 年年中,没有官方方法来限制可视区域。但是,大多数限制边界的临时解决方案都有一个缺陷,因为它们不会完全限制边界以适应地图视图,它们只会在地图中心超出指定边界时对其进行限制。如果您想像我一样将边界限制为叠加图像,这可能会导致如下所示的行为,其中底层地图在我们的图像叠加层下可见:

为了解决这个问题,我创建了一个library,它成功地限制了边界,所以你不能平移出覆盖层。

但是,与其他现有解决方案一样,它存在“振动”问题。当用户足够积极地平移地图时,释放鼠标左键后,地图仍会继续自行平移,逐渐变慢。我总是将地图返回到边界,但这会导致某种振动。目前无法通过 Js API 提供的任何方式停止这种平移效果。似乎在谷歌添加对诸如 map.stopPanningAnimation() 之类的支持之前,我们将无法创建流畅的体验。

使用上述库的示例,我能获得的最流畅的严格边界体验:

function initialise()
  
  var myOptions = 
     zoom: 5,
     center: new google.maps.LatLng(0,0),
     mapTypeId: google.maps.MapTypeId.ROADMAP,
  ;
  var map = new google.maps.Map(document.getElementById('map'), myOptions);
  
  addStrictBoundsImage(map);


function addStrictBoundsImage(map)
	var bounds = new google.maps.LatLngBounds(
		new google.maps.LatLng(62.281819, -150.287132),
		new google.maps.LatLng(62.400471, -150.005608));

	var image_src = 'https://developers.google.com/maps/documentation/' +
		'javascript/examples/full/images/talkeetna.png';

	var strict_bounds_image = new StrictBoundsImage(bounds, image_src, map);
<script type="text/javascript" src="http://www.google.com/jsapi"></script>
      <script type="text/javascript">
        google.load("maps", "3",other_params:"sensor=false");
      </script>
<body style="margin:0px; padding:0px;" onload="initialise()">
	 <div id="map" style="height:400px; width:500px;"></div>
     <script  type="text/javascript"src="https://raw.githubusercontent.com/matej-pavla/StrictBoundsImage/master/StrictBoundsImage.js"></script>
</body>

该库还能够自动计算最小缩放限制。然后它使用minZoom 地图的属性限制缩放级别。

希望这可以帮助那些想要一个完全尊重给定边界并且不想让他们摆脱它们的解决方案的人。

【讨论】:

【参考方案12】:

好消息。从 2019 年 2 月 14 日推出的 Maps JavaScript API 3.35 版开始,您可以使用新的restriction 选项来限制地图的视口。

根据文档

地图限制接口

可以应用于地图的限制。地图的视口不会超出这些限制。

来源:https://developers.google.com/maps/documentation/javascript/reference/map#MapRestriction

所以,现在您只需在地图初始化期间添加限制选项即可。请看以下将视口限制为瑞士的示例

var map;
function initMap() 
  map = new google.maps.Map(document.getElementById('map'), 
    center: lat: 46.818188, lng: 8.227512,
    minZoom: 7,
    maxZoom: 14,
    zoom: 7,
    restriction: 
      latLngBounds: 
        east: 10.49234,
        north: 47.808455,
        south: 45.81792,
        west: 5.95608
      ,
      strictBounds: true
    ,
  );
#map 
  height: 100%;

html, body 
  height: 100%;
  margin: 0;
  padding: 0;
<div id="map"></div>
<script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyDztlrk_3CnzGHo7CFvLFqE_2bUKEq1JEU&callback=initMap" async defer></script>

我希望这会有所帮助!

【讨论】:

链接失效。以下是关于该主题的新内容:示例:developers-dot-devsite-v2-prod.appspot.com/maps/documentation/… DOCS:developers-dot-devsite-v2-prod.appspot.com/maps/documentation/… 固定文档链接。 谢谢,这段代码有点用。也就是说,如果您使用 minZoom 和 maxZoom 将缩放限制为仅可能的 1 级。如果按预期工作,您似乎需要为每个缩放级别设置不同的南、西、北、东。为每个缩放级别设置不同的限制设置会很高兴。我选择了最大缩小级别并从那里定义了坐标,因此如果您放大然后平移,则可以平移出边界。

以上是关于Google Maps v3 - 限制可视区域和缩放级别的主要内容,如果未能解决你的问题,请参考以下文章

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

将 Google Maps V3 标记的拖动限制到折线

Google Maps API V3 使用限制是按网站访问者还是按 Web 服务器?

将 Google Maps API v3 搜索结果限制在某个国家/地区,同时将它们偏向某个位置

Google Maps api v3 工具:视觉扭曲?

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