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...
请给出工作示例或代码片段——我不是专业的程序员……
Thanks!
谢谢!
14 个解决方案
#1
87
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 Vassallo and 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 Vassallo和brendo的回答中,用户仍然可以使用泛控制(如果它被激活)离开需要的区域。@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事件。这是在拖拽和每次有人使用pan控件时持续触发的。
// 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. ......
通过在拖拽过程中持续保存最后一个有效位置,当拖拽结束时,移动将停止,而不是向后移动
#2
20
The trick is to listen to the dragend
event, and if the map is dragged outside the allowed bounds, move it back inside. If you define your allowed bounds as a LatLngBounds
object, 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:
上面示例的截图。在这种情况下,用户将不能拖往更远的南部或远东:
#3
9
My version, based on the one from @HenningJ, but with some modification of the lastValidCenter
to allow smooth dragging along 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/
#4
3
Here is a nice extension to the above that 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);
});
#5
3
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);
#6
2
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)可以更流畅地沿着边滚动(亨宁杰的解决方案似乎有点笨拙);2)在缩放一个区域时没有任何问题(同样,亨宁杰的答案似乎在缩放到边界附近时被打破)。
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));
});
#7
1
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:
我尝试了亨宁杰的答案,直到地图的中心在边界的一个不理想的角落里,地图才会停止平移。这是我的解决方案:
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));
#8
1
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).
(我建议在使用center_changed事件时要谨慎,正如HenningJ所建议的那样。在我的例子中,它创建的事件的数量在谷歌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();
}
}
#9
0
There is another thread on 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.
所以我在地图装载上设置了平移边界一次。然后我检查映射是否仍然在最大缩放,如果是,返回初始中心。如果放大,我希望平移到初始边界的边缘,而不是检查是否包含中心,因为这会将允许的平移扩展到viewport的一半。
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
)
);
});
#10
0
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.
当我使用拖拽或拖拽等工具时,映射会跳转回允许的边界,而不是简单地限制溢出移动。只需将事件更改为“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
编辑:不知道为什么fiddle不产生堆栈溢出,但是它应该产生,因为setCenter将再次调用center_changed .。只是小心
#11
0
The solutions here left me with 2 issues. First of all, if you held down the arrow key so that it started panning rapidly, when it hit the edge, it wouldn't go all the way to the edge because due to the panning acceleration taking large "steps", the next "step" would have gone outside the bounds, so it doesn't take that last "step". So once it stopped, you could release the arrow key and then press it again, and it would pan just a little bit further. Second, these solutions didn't properly contain the panning after a zoom change. I managed to solve both, and posted my solution in another thread, but I thought I'd link it here, since this was the thread that first got me started in the right direction.
这里的解决方案留给我两个问题。首先,如果你持有下箭头键,开始快速平移,撞到边缘的时候,它不会一直到边缘,因为由于平移加速度大的“步骤”,下一个“步骤”会在范围之外,所以它不需要最后一步”。一旦它停止,你就可以释放箭头键然后再按一下,它就会再向前平移一点点。其次,这些解决方案没有适当地包含缩放后的平移。我设法解决了这两个问题,并在另一个线程中发布了我的解决方案,但是我想我应该在这里链接它,因为这是第一个让我开始正确方向的线程。
#12
0
This is HenningJ - but HenningJ on ios uses lastValidCentre - which is not good, as its old, so I clamp, which makes it better on iOS.
这是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));
});
#13
0
I'll post my answer in case anyone's interested because I couldn't achieve what I needed with any of the other solutions posted here.
我将发布我的答案,以防有人感兴趣,因为我无法实现我需要的任何其他解决方案张贴在这里。
What I needed was to restrict the vertical bounds (latitude) of the map so that the user would not be able to pan beyond the latitude bounds of the earth (~ +/-85 degrees), but any other bounds would work too.
我需要的是限制地图的垂直边界(纬度),这样用户就不能越过地球的纬度边界(~ +/-85度),但是其他的边界也可以。
This approach uses the same center_changed
event as described elsewhere and simply fixes the center in case parts of the prohibited bounds are shown.
此方法使用与其他地方描述的center_changed事件相同的方法,并在显示禁止边界的部分时简单地修复中心。
This mechanism only works if the minimum zoom of the map is set so that zooming out can never show more area than that within the allowed bounds.
此机制仅在设置映射的最小缩放比例时才有效,这样缩放比例在允许的范围内不能显示比该范围更多的区域。
Working example: http://jsbin.com/vizihe
工作示例: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>
#14
0
I know I am little late to the party, but it seems that as of middle 2016, there is no official way to restrict viewable area.
我知道我参加派对的时间并不晚,但从2016年中期开始,似乎没有官方的方式来限制可观看区域。
There are some solutions to restrict the bounds (some of them in this question) but for me they have a flaw though, because they don't restrict the bounds exactly to fit the map view, they only restrict the map center be contained within the specified bounds. If you want to restrict the bounds to overlaying image like me, this can result in a behavior like illustrated below, where the underlaying map is visible under our image overlay:
有一些解决方案可以限制边界(在这个问题中有一些),但是对我来说,它们有一个缺陷,因为它们没有精确地限制边界以适应映射视图,它们只限制映射中心包含在指定的边界内。如果你想限制像我这样的叠加图像的界限,这可能导致如下所示的行为,在我们的图像叠加下可以看到下面的叠加映射:
To tackle this issue, I have created a library, which successfully restrict the bounds so you cannot pan out of the overlay.
为了解决这个问题,我创建了一个库,它成功地限制了边界,所以您不能超出覆盖层。
However, as other existing solutions, it has a "vibrating" issue. When the user pans the map aggressively enough, after they release the left mouse button, the map still continues panning by itself, gradually slowing. I always return the map back to the bounds, but that results in kind of vibrating, which settles after a moment. This panning effect cannot be stopped with any means provided by the Js API at the moment. It seems that until google adds support for something like map.stopPanningAnimation() we won't be able to create a smooth experience.
然而,作为其他现有的解决方案,它有一个“振动”的问题。当用户移动地图的力度足够大时,当他们释放鼠标左键后,地图仍然会继续自己移动,逐渐变慢。我总是把地图返回到边界,但这导致了震动,过了一会儿就平息了。目前Js API提供的任何方法都无法阻止这种平移效果。似乎直到谷歌添加对map.stopPanningAnimation()之类的东西的支持之后,我们才能创建一个流畅的体验。
Example using the mentioned library, the smoothest strict bounds experience I was able to get:
例如使用上面提到的库,我能得到的最平滑、最严格的边界体验:
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>
#1
87
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 Vassallo and 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 Vassallo和brendo的回答中,用户仍然可以使用泛控制(如果它被激活)离开需要的区域。@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事件。这是在拖拽和每次有人使用pan控件时持续触发的。
// 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. ......
通过在拖拽过程中持续保存最后一个有效位置,当拖拽结束时,移动将停止,而不是向后移动
#2
20
The trick is to listen to the dragend
event, and if the map is dragged outside the allowed bounds, move it back inside. If you define your allowed bounds as a LatLngBounds
object, 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:
上面示例的截图。在这种情况下,用户将不能拖往更远的南部或远东:
#3
9
My version, based on the one from @HenningJ, but with some modification of the lastValidCenter
to allow smooth dragging along 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/
#4
3
Here is a nice extension to the above that 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);
});
#5
3
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);
#6
2
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)可以更流畅地沿着边滚动(亨宁杰的解决方案似乎有点笨拙);2)在缩放一个区域时没有任何问题(同样,亨宁杰的答案似乎在缩放到边界附近时被打破)。
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));
});
#7
1
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:
我尝试了亨宁杰的答案,直到地图的中心在边界的一个不理想的角落里,地图才会停止平移。这是我的解决方案:
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));
#8
1
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).
(我建议在使用center_changed事件时要谨慎,正如HenningJ所建议的那样。在我的例子中,它创建的事件的数量在谷歌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();
}
}
#9
0
There is another thread on 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.
所以我在地图装载上设置了平移边界一次。然后我检查映射是否仍然在最大缩放,如果是,返回初始中心。如果放大,我希望平移到初始边界的边缘,而不是检查是否包含中心,因为这会将允许的平移扩展到viewport的一半。
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
)
);
});
#10
0
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.
当我使用拖拽或拖拽等工具时,映射会跳转回允许的边界,而不是简单地限制溢出移动。只需将事件更改为“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
编辑:不知道为什么fiddle不产生堆栈溢出,但是它应该产生,因为setCenter将再次调用center_changed .。只是小心
#11
0
The solutions here left me with 2 issues. First of all, if you held down the arrow key so that it started panning rapidly, when it hit the edge, it wouldn't go all the way to the edge because due to the panning acceleration taking large "steps", the next "step" would have gone outside the bounds, so it doesn't take that last "step". So once it stopped, you could release the arrow key and then press it again, and it would pan just a little bit further. Second, these solutions didn't properly contain the panning after a zoom change. I managed to solve both, and posted my solution in another thread, but I thought I'd link it here, since this was the thread that first got me started in the right direction.
这里的解决方案留给我两个问题。首先,如果你持有下箭头键,开始快速平移,撞到边缘的时候,它不会一直到边缘,因为由于平移加速度大的“步骤”,下一个“步骤”会在范围之外,所以它不需要最后一步”。一旦它停止,你就可以释放箭头键然后再按一下,它就会再向前平移一点点。其次,这些解决方案没有适当地包含缩放后的平移。我设法解决了这两个问题,并在另一个线程中发布了我的解决方案,但是我想我应该在这里链接它,因为这是第一个让我开始正确方向的线程。
#12
0
This is HenningJ - but HenningJ on ios uses lastValidCentre - which is not good, as its old, so I clamp, which makes it better on iOS.
这是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));
});
#13
0
I'll post my answer in case anyone's interested because I couldn't achieve what I needed with any of the other solutions posted here.
我将发布我的答案,以防有人感兴趣,因为我无法实现我需要的任何其他解决方案张贴在这里。
What I needed was to restrict the vertical bounds (latitude) of the map so that the user would not be able to pan beyond the latitude bounds of the earth (~ +/-85 degrees), but any other bounds would work too.
我需要的是限制地图的垂直边界(纬度),这样用户就不能越过地球的纬度边界(~ +/-85度),但是其他的边界也可以。
This approach uses the same center_changed
event as described elsewhere and simply fixes the center in case parts of the prohibited bounds are shown.
此方法使用与其他地方描述的center_changed事件相同的方法,并在显示禁止边界的部分时简单地修复中心。
This mechanism only works if the minimum zoom of the map is set so that zooming out can never show more area than that within the allowed bounds.
此机制仅在设置映射的最小缩放比例时才有效,这样缩放比例在允许的范围内不能显示比该范围更多的区域。
Working example: http://jsbin.com/vizihe
工作示例: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>
#14
0
I know I am little late to the party, but it seems that as of middle 2016, there is no official way to restrict viewable area.
我知道我参加派对的时间并不晚,但从2016年中期开始,似乎没有官方的方式来限制可观看区域。
There are some solutions to restrict the bounds (some of them in this question) but for me they have a flaw though, because they don't restrict the bounds exactly to fit the map view, they only restrict the map center be contained within the specified bounds. If you want to restrict the bounds to overlaying image like me, this can result in a behavior like illustrated below, where the underlaying map is visible under our image overlay:
有一些解决方案可以限制边界(在这个问题中有一些),但是对我来说,它们有一个缺陷,因为它们没有精确地限制边界以适应映射视图,它们只限制映射中心包含在指定的边界内。如果你想限制像我这样的叠加图像的界限,这可能导致如下所示的行为,在我们的图像叠加下可以看到下面的叠加映射:
To tackle this issue, I have created a library, which successfully restrict the bounds so you cannot pan out of the overlay.
为了解决这个问题,我创建了一个库,它成功地限制了边界,所以您不能超出覆盖层。
However, as other existing solutions, it has a "vibrating" issue. When the user pans the map aggressively enough, after they release the left mouse button, the map still continues panning by itself, gradually slowing. I always return the map back to the bounds, but that results in kind of vibrating, which settles after a moment. This panning effect cannot be stopped with any means provided by the Js API at the moment. It seems that until google adds support for something like map.stopPanningAnimation() we won't be able to create a smooth experience.
然而,作为其他现有的解决方案,它有一个“振动”的问题。当用户移动地图的力度足够大时,当他们释放鼠标左键后,地图仍然会继续自己移动,逐渐变慢。我总是把地图返回到边界,但这导致了震动,过了一会儿就平息了。目前Js API提供的任何方法都无法阻止这种平移效果。似乎直到谷歌添加对map.stopPanningAnimation()之类的东西的支持之后,我们才能创建一个流畅的体验。
Example using the mentioned library, the smoothest strict bounds experience I was able to get:
例如使用上面提到的库,我能得到的最平滑、最严格的边界体验:
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>