Google Maps API V3:限制地图范围[重复]
Posted
技术标签:
【中文标题】Google Maps API V3:限制地图范围[重复]【英文标题】:Google Maps API V3: limit map bounds [duplicate] 【发布时间】: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 的解决方案是什么?
【问题讨论】:
【参考方案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
) 并限制 drag
和 zoom_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));
【讨论】:
以上是关于Google Maps API V3:限制地图范围[重复]的主要内容,如果未能解决你的问题,请参考以下文章
google maps js v3 api教程 -- 创建一个地图
在 Google Maps API v3 中缩放到 geojson 多边形边界
google maps js v3 api教程 -- 在地图上添加标记