D3.js 计算墨卡托d3缩放以匹配传单缩放级别

D3.js 计算墨卡托d3缩放以匹配传单缩放级别,d3.js,leaflet,map-projections,mercator,D3.js,Leaflet,Map Projections,Mercator,给定传单缩放级别(0..22),如何计算geoMercator投影的D3缩放值?当zoom=0时,整个世界都可以放在一块瓷砖(256x256)中。在平铺中,世界大小为2^缩放x 2^缩放平铺。与墨卡托地图的d3比例相比: 墨卡托地图使用以下公式: var point = [x, Math.log(Math.tan(Math.PI / 4 + y / 2))]; d3贴图中的比例因子基本上应用以下变换: point[0] = point[0] * k; point[1] =

给定传单缩放级别(0..22),如何计算geoMercator投影的D3缩放值?当zoom=0时,整个世界都可以放在一块瓷砖(256x256)中。在平铺中,世界大小为2^缩放x 2^缩放平铺。

与墨卡托地图的d3比例相比:

墨卡托地图使用以下公式:

var point =  [x, Math.log(Math.tan(Math.PI / 4 + y / 2))];  
d3贴图中的比例因子基本上应用以下变换:

   point[0] =  point[0] * k;
   point[1] =  -point[1] * k;
d3墨卡托投影的默认地图比例为961/2π,或961像素乘以360度

墨卡托公式的一个怪癖是,“整个”世界的方形视图实际上将覆盖在南北±85.05113度。网络墨卡托人可以推动这一点,因为他们不是保形投影。传单将“整个”世界的范围推至±89.15度左右的南北方向

因此,d3使用适当的墨卡托和传单使用web墨卡托意味着比例值可能无法很好地匹配。关于的回答将提供更多关于两者之间差异的信息

但是,您仍然可以将两者对齐(大多数情况下)


Yurik在下面提到的一种方法是使用缩放级别和平铺大小来获得比例因子:

Web地图服务使用平铺网格,其中增加缩放级别可使显示的平铺数量增加四倍。在缩放级别1时,世界可以放在一个平铺中;在缩放级别2时,世界可以放在四个方形平铺中。瓷砖数量的一般公式为:

瓷砖数量=4^zoomLevel

最重要的是,每次放大时,穿过地图(一行)所需的平铺数量都会翻倍

以此为起点,我们可以找出如何匹配这两者

d3 geoMercator使用
961/(2*Math.PI)
作为默认比例-这将赤道的360度(或2弧度)扩展到961像素。要将其设置为适用于基于平铺的层,我们只需要知道平铺大小和缩放级别

我们需要知道赤道分布了多少像素,才能得到我们使用的:

tileSize*Math.pow(2,zoomLevel)

这给了我们所有环绕赤道的瓷砖的宽度。然后我们可以除以2Pi得到我们的d3标度:

projection.scale(tileSize*Math.pow(2,zoomLevel)/(2*Math.PI))

由于d3墨卡托和web墨卡托之间的差异,可能会出现失真问题,这取决于您所在的位置和缩放距离,但在大多数情况下,这应该提供良好的对齐


或者,我们可以使用传单地图的实际角落来确定适当的比例:

D3提供了一种方法,允许投影将地理范围与svg范围相匹配:
projection.fitExtent()
。此方法采用geojson或几何体。在这个答案中,我使用的是geojson

.getBounds()
将返回leaftlet映射范围,因此您可以非常轻松地创建geojson边界框:

var bbox = {
    "type": "Polygon",
    "coordinates": [
        [
            [mymap.getBounds()._northEast.lng, mymap.getBounds()._northEast.lat], 
            [mymap.getBounds()._northEast.lng, mymap.getBounds()._southWest.lat], 
            [mymap.getBounds()._southWest.lng, mymap.getBounds()._southWest.lat], 
            [mymap.getBounds()._southWest.lng, mymap.getBounds()._northEast.lat],
            [mymap.getBounds()._northEast.lng, mymap.getBounds()._northEast.lat]
        ]
    ]
}
请注意,绕组顺序在d3中实际上很重要-外圈为逆时针方向

然后,您只需将投影设置为适合该范围:

var projection = d3.geoMercator()
   .fitSize([600, 400], bbox);
使用稍微修改的(更改了中心点和缩放),整个过程如下所示:

var功能={
“类型”:“FeatureCollection”,
“特点”:[
{
“类型”:“功能”,
“属性”:{},
“几何学”:{
“类型”:“多边形”,
“坐标”:[
[
[
-0.17565250396728513,
51.510118018740904
],
[
-0.17586708068847653,
51.509744084227556
],
[
-0.17584562301635742,
51.50871574849058
],
[
-0.17359256744384766,
51.50613812964363
],
[
-0.17204761505126953,
51.50552375337273
],
[
-0.16966581344604492,
51.50481587478995
],
[
-0.16599655151367188,
51.50454874793857
],
[
-0.1624774932861328,
51.504001132997686
],
[
-0.16058921813964844,
51.5039744199054
],
[
-0.16033172607421875,
51.50426826305929
],
[
-0.16013860702514648,
51.5043884710761
],
[
-0.16016006469726562,
51.50465559886706
],
[
-0.15996694564819336,
51.50510971251776
],
[
-0.16282081604003906,
51.505737450406535
],
[
-0.16466617584228516,
51.5058710105437
],
[
-0.16835689544677734,
51.50588436653591
],
[
-0.1705455780029297,
51.506098061878475
],
[
-0.17273426055908203,
51.506672363145654
],
[
-0.17282009124755857,
51.50681927626061
],
[
-0.17468690872192383,
51.508729103648925
],
[
-0.17511606216430664,
51.50999782583918
],
[
-0.17526626586914062,
51.510144728231545
],
[
-0.17565250396728513,
51.510118018740904
]
]
]
}
}
]
};
var mymap=L.map('mapid').setView([51.5,-0.171],14);
L.tileLayer('https://api.tiles.mapbox.com/v4/{id}/{z}/{x}/{y}.png?access_token=pk.eyj1ijoibwfwym94iiwiysi6imnpey4nxvycta2emycxbndhrqcmz3n3gifq.rjcfig214ariislb6b5a