[英]How do I limit panning in Google maps API V3?
在V2中有一种限制平移/拖动的方法,因此地图保持在特定范围内。 怎么在V3中完成?
假设我希望用户只看欧洲。 我已经限制了缩放,但是如果我允许拖动(在这种情况下我必须出于其他原因),那么用户可以超出我想要显示的区域。
请给出工作示例或代码片段 - 我不是专家编码器......
我想我参加派对有点晚了,但因为这正是我现在所需要的,而且我对此有所改进,我想我还是会发一个答案。
通过Daniel Vassallo和brendo的答案,用户仍然可以使用平移控制(如果它被激活)远离想要的区域。 @ Yauhen.F在评论中提到的东西。
因此,我使用了center_changed事件,而不是使用dragend事件。 在拖动期间以及每次有人使用平移控件时都会持续触发。
// 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);
});
通过在拖动过程中连续保存最后一个有效位置,一旦超出界限,移动就会停止,而不是在拖动结束后退回。 ......
诀窍是收听dragend
事件,如果地图被拖到允许的边界之外,则将其移回内部。 如果将允许的边界定义为LatLngBounds
对象,则可以使用contains()
方法,因为如果给定的lat / lng参数在边界内,则返回true。
限制缩放级别也很重要,但似乎你已经这样做了。
因此,您可能需要尝试以下示例:
<!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>
以上示例的屏幕截图。 在这种情况下,用户将无法再向南或远东拖动:
我的版本基于@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>
在这里小提琴: http : //jsfiddle.net/koenpunt/n7h6t/
限制的最佳方法是,设置缩放级别和中心点,并禁用像缩放,滚动等控件,如下所示。
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);
这里是一个很好的扩展到上面 ,将通过听取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);
});
这是一个解决方案,它将Tom Andersen的答案与目前公认的HenningJ答案合并在一起。 这样做的好处是:1)允许沿着边缘更平滑地滚动(HenningJ的解决方案看起来很笨拙),以及2)当放大一个区域时没有任何问题(当放大时HenningJ的答案似乎再次破裂)并且靠近边界)。
汤姆的答案接近为我工作,除了它将锁定的区域定位到屏幕的中心,这对我正在处理的应用程序来说是不可接受的。
// 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));
});
我尝试了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));
这是一个适用于移动和桌面的简单解决方案。 它将停止地图平移超出世界的最大或最小纬度,并允许设置最小缩放级别,这有助于防止灰色区域通过缩放太远而变得可见(取决于您为地图设置的大小):
(我建议在使用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();
}
}
关于这个主题的另一个主题也非常好。 我必须解决的问题是,不是手动设置边界和检查中心包含,我想在页面加载上设置边界,然后允许在放大时拖动到边缘。
所以我在地图加载上设置了一次平移边界。 然后我检查地图是否仍处于最大缩放状态,如果是,则返回初始中心。 如果放大,我想平移到初始边界的边缘,而不仅仅是检查是否包含CENTER,因为这会将允许的平移延长视口的一半。
不幸的是,虽然这可以完成工作并且在慢慢地翘起时工作正常但如果你快速平移会有点不稳定。
如果你有关于如何避免这种情况的建议,我将不胜感激。
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
)
);
});
当我使用拖动或拖拽或其他任何东西时,地图会跳回到允许的边界而不是简单地限制溢出的移动。 只需将事件更改为“center_changed”即可阻止其跳转。
修改过的jsfiddle: http : //jsfiddle.net/Vjdde/1/
编辑:不知道为什么小提琴不会产生堆栈溢出,但它应该,因为setCenter将再次调用center_changed ..请注意
这里的解决方案给我留下了两个问题。 首先,如果按住箭头键使其快速开始平移,当它到达边缘时,它将不会一直到边缘,因为由于平移加速度需要大的“步骤”,下一个“步骤“将超出界限,所以它不会采取最后的”步骤“。 因此,一旦它停止,您可以释放箭头键然后再次按下它,它会稍微平移一点。 其次,这些解决方案在缩放变化后没有正确包含平移。 我设法解决了这两个问题,并在另一个线程中发布了我的解决方案,但我想我会把它链接到这里,因为这是第一个让我开始正确方向的线程。
这是HenningJ - 但ios上的HenningJ使用了lastValidCentre - 这不是很好,因为它很旧,所以我钳制,这使它在iOS上更好。
var mapObject = plugin_map.gmap3('get');
var allowedBounds = new google.maps.LatLngBounds(
new google.maps.LatLng(41.3957556, -88.4345472),
new google.maps.LatLng(49.4010417, -78.4286389)
);
google.maps.event.addListener(mapObject, 'center_changed', function() {
if (allowedBounds.contains(mapObject.getCenter())) {
// still within valid bounds, so save the last valid position
return;
}
// not valid anymore => return to last valid position
var c = mapObject.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;
//mapObject.setCenter(new google.maps.LatLng(y, x));
mapObject.panTo(new google.maps.LatLng(y, x));
});
如果有人感兴趣,我会发布我的答案,因为我无法通过此处发布的任何其他解决方案实现我所需要的。
我需要的是限制地图的垂直边界(纬度),以便用户无法平移超出地球的纬度界限(〜+/- 85度),但任何其他界限也会起作用。
此方法使用与其他地方描述的相同的center_changed
事件,并且仅在显示禁止边界的部分时简单地修复中心。
此机制仅在设置了地图的最小缩放时才有效,因此缩小时不能显示比允许范围内的区域更多的区域。
工作示例: http : //jsbin.com/vizihe
function initMap() {
// sample bounds, can be anything and goes hand in hand with minZoom
var northBoundary = 40
var southBoundary = -40
var map = new google.maps.Map(document.getElementById('map'), {
center: {lat: 0, lng: 0},
zoom: 4,
// it's important to set this to a large enough value
// so that zooming out does not show an area larger than allowed
minZoom: 4
})
map.addListener('center_changed', function () {
var bounds = map.getBounds();
var ne = bounds.getNorthEast()
var sw = bounds.getSouthWest()
var center = map.getCenter()
if(ne.lat() > northBoundary) {
map.setCenter({lat: center.lat() - (ne.lat() - northBoundary), lng: center.lng()})
}
if(sw.lat() < southBoundary) {
map.setCenter({lat: center.lat() - (sw.lat() - southBoundary), lng: center.lng()})
}
})
}
html, body, #map {
height: 100%;
margin: 0;
padding: 0;
}
<!DOCTYPE html>
<html>
<head>
<meta name="description" content="limit google map panning">
<title>Simple Map</title>
<meta name="viewport" content="initial-scale=1.0">
<meta charset="utf-8">
</head>
<body>
<div id="map"></div>
<script src="https://maps.googleapis.com/maps/api/js?callback=initMap"
async defer></script>
</body>
</html>
我知道我对派对来说已经迟到了,但似乎截至2016年中期 ,没有官方的方法来限制可见区域。
有一些限制边界的解决方案(在这个问题中有一些),但对我来说它们有一个缺陷,因为它们并没有完全限制边界以适应地图视图,它们只限制地图中心包含在指定的边界。 如果你想限制像我一样覆盖图像的边界,这可能会导致如下图所示的行为,其中底层地图在我们的图像叠加下可见:
为了解决这个问题,我创建了一个库 ,它成功地限制了边界,因此您无法平移覆盖。
然而,作为其他现有解决方案,它具有“振动”问题。 当用户足够积极地平移地图时,在他们释放鼠标左键后,地图仍然会自动继续平移,逐渐减慢。 我总是将地图返回到界限,但这会产生一种振动,一会儿就会结束。 此刻平移效果无法通过Js API提供的任何方式停止。 似乎在Google添加对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:500px; width:1000px;"></div> <script type="text/javascript"src="https://raw.githubusercontent.com/matej-pavla/StrictBoundsImage/master/StrictBoundsImage.js"></script> </body>
谷歌地图API的新版本现在提供了限制边界的方法。 只需在初始化地图时指定限制边界即可。 例如,如果您只想将边界限制为Newzeland,则执行以下操作:
<body>
<div id="map"></div>
<script>
var map;
var NEW_ZEALAND_BOUNDS = {
north: -34.36,
south: -47.35,
west: 166.28,
east: -175.81,
};
var AUCKLAND = {lat: -37.06, lng: 174.58};
function initMap() {
map = new google.maps.Map(document.getElementById('map'), {
center: AUCKLAND,
restriction: {
latLngBounds: NEW_ZEALAND_BOUNDS,
strictBounds: false,
},
zoom: 7,
});
}
</script>
<script async defer
src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&callback=initMap">
</script>
</body>
仅供参考:要限制整个世界的地图,您可以使用以下范围。 这里棘手的部分是使用strictBounds:true
。 这将确保用户无法缩小世界视图:
map = new google.maps.Map(document.getElementById('map'), {
restriction: {
latLngBounds: {
north: 85,
south: -85,
west: -180,
east: 180
},
strictBounds: true,
},
zoom: 7,
});
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.