如何计算给定边界的缩放级别
我正在寻找一种方法来使用Google Maps V3 API计算给定边界的缩放级别,类似于V2 API中的getBoundsZoomLevel()。
这是我想要做的:
// These are exact bounds previously captured from the map object
var sw = new google.maps.LatLng(42.763479, -84.338918);
var ne = new google.maps.LatLng(42.679488, -84.524313);
var bounds = new google.maps.LatLngBounds(sw, ne);
var zoom = // do some magic to calculate the zoom level
// Set the map to these exact bounds
map.setCenter(bounds.getCenter());
map.setZoom(zoom);
// NOTE: fitBounds() will not work
不幸的是,我无法为我的特殊用例使用fitBounds()方法。 它适用于在地图上绘制标记,但对于设置确切的边界并不适用。 这里是我不能使用fitBounds()方法的一个例子。
map.fitBounds(map.getBounds()); // not what you expect
Google小组提出了一个类似的问题:http://groups.google.com/group/google-maps-js-api-v3/browse_thread/thread/e6448fc197c3c892
缩放级别是离散的,每一步的缩放倍数。 所以一般来说,你不能完全符合你想要的边界(除非你对特定的地图大小感到非常幸运)。
另一个问题是边长之间的比例,例如,你无法准确地将边界与方形地图内的细长矩形进行拟合。
对于如何拟合确切的范围没有简单的答案,因为即使您愿意更改地图div的大小,您也必须选择更改的大小和相应的缩放级别(粗略地说,您是将它放大还是缩小比它目前是?)。
如果你真的需要计算缩放,而不是存储它,这应该做的伎俩:
墨卡托投影翘曲纬度,但经度的任何差异总是表示地图宽度的相同分数(以度/ 360度表示的角度差)。 在缩放零点时,整个世界地图是256x256像素,每个级别的缩放倍数都是宽度和高度。 因此,在一个小代数之后,我们可以按如下方式计算缩放比例,前提是我们知道地图的像素宽度。 请注意,由于经度环绕,我们必须确保角度为正值。
var GLOBE_WIDTH = 256; // a constant in Google's map projection
var west = sw.lng();
var east = ne.lng();
var angle = east - west;
if (angle < 0) {
angle += 360;
}
var zoom = Math.round(Math.log(pixelWidth * 360 / angle / GLOBE_WIDTH) / Math.LN2);
感谢Giles Gardam的回答,但它只涉及经度而不是纬度。 一个完整的解决方案应该计算纬度所需的缩放级别和经度所需的缩放级别,然后取两个中较小(更远的)。
这是一个同时使用经度和纬度的函数:
function getBoundsZoomLevel(bounds, mapDim) {
var WORLD_DIM = { height: 256, width: 256 };
var ZOOM_MAX = 21;
function latRad(lat) {
var sin = Math.sin(lat * Math.PI / 180);
var radX2 = Math.log((1 + sin) / (1 - sin)) / 2;
return Math.max(Math.min(radX2, Math.PI), -Math.PI) / 2;
}
function zoom(mapPx, worldPx, fraction) {
return Math.floor(Math.log(mapPx / worldPx / fraction) / Math.LN2);
}
var ne = bounds.getNorthEast();
var sw = bounds.getSouthWest();
var latFraction = (latRad(ne.lat()) - latRad(sw.lat())) / Math.PI;
var lngDiff = ne.lng() - sw.lng();
var lngFraction = ((lngDiff < 0) ? (lngDiff + 360) : lngDiff) / 360;
var latZoom = zoom(mapDim.height, WORLD_DIM.height, latFraction);
var lngZoom = zoom(mapDim.width, WORLD_DIM.width, lngFraction);
return Math.min(latZoom, lngZoom, ZOOM_MAX);
}
在jsfiddle上演示
参数:
“bounds”参数值应该是一个google.maps.LatLngBounds
对象。
“mapDim”参数值应该是具有“height”和“width”属性的对象,它们表示显示地图的DOM元素的高度和宽度。 如果你想确保填充,你可能想减少这些值。 也就是说,您可能不希望边界内的地图标记太靠近地图边缘。
如果您正在使用jQuery库,则可以按如下方式获取mapDim
值:
var $mapDiv = $('#mapElementId');
var mapDim = { height: $mapDiv.height(), width: $mapDiv.width() };
如果您正在使用Prototype库,则可以按如下方式获取mapDim值:
var mapDim = $('mapElementId').getDimensions();
返回值:
返回值是仍将显示整个界限的最大缩放级别。 该值将介于0
和最大缩放级别之间,包括在内。
最大缩放级别为21.(我相信Google Maps API v2只有19级。)
说明:
Google地图使用墨卡托投影。 在墨卡托投影中,经线是等距的,但纬线不是。 纬线之间的距离随着从赤道到极点而增加。 事实上,当它到达极点时,距离趋于无穷大。 但是,Google Maps地图不会显示北纬约85度以上或南纬约-85度以下的纬度。 (参考)(我计算+/- 85.05112877980658度的实际截止点。)
这使得边界分数的计算在纬度上比在经度上更复杂。 我使用维基百科的公式计算纬度分数。 我认为这与Google地图使用的投影相符。 毕竟,我链接到上面的Google Maps文档页面包含指向同一维基百科页面的链接。
其他说明:
对于API的第3版,这很简单并且可以工作:
var latlngList = [];
latlngList.push(new google.maps.LatLng (lat,lng));
var bounds = new google.maps.LatLngBounds();
latlngList.each(function(n){
bounds.extend(n);
});
map.setCenter(bounds.getCenter()); //or use custom center
map.fitBounds(bounds);
和一些可选的技巧:
//remove one zoom level to ensure no marker is on the edge.
map.setZoom(map.getZoom()-1);
// set a minimum zoom
// if you got only 1 marker or all markers are on the same address map will be zoomed too much.
if(map.getZoom()> 15){
map.setZoom(15);
}
链接地址: http://www.djcxy.com/p/14309.html