- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
给定 Leaflet 缩放级别 (0..22),我将如何计算 geoMercator 投影的 D3 缩放值?在 zoom=0 时,整个世界都在一个图 block (256x256) 中。在瓦片中,世界大小是 2^zoom x 2^zoom 瓦片。
最佳答案
与墨卡托 map 的 d3 比例进行比较:
墨卡托 map 使用以下公式:
var point = [x, Math.log(Math.tan(Math.PI / 4 + y / 2))];
d3 map 中的比例因子基本上应用以下变换:
point[0] = point[0] * k;
point[1] = -point[1] * k;
d3 墨卡托投影的默认 map 比例为 961/2π,即 961 像素 x 360 度。
墨卡托公式的一个怪癖是,“整个”世界的正方形 View 实际上将以南北 ±85.05113 度为上限。 Web Mercators 可以插入这一点,因为它们不是等角投影。 Leaflet 将“整个”世界的范围推至南北 ±89.15 度左右。
因此,d3 使用适当的墨卡托,Leaflet 使用网络墨卡托,这意味着比例值可能无法很好地啮合。 GIS.stackexchange 上的这个答案将提供有关两者之间差异的更多信息。
但是,您仍然可以将两者对齐(大多数情况下)。
如 Yurik 在下面的 comments 中所述,一种方法是使用缩放级别和图 block 大小来获取比例因子:
Web map 服务使用分 block 网格,其中增加缩放级别会使显示的分 block 数量增加四倍。在缩放级别 1 中,世界适合一个图 block ,在缩放级别 2 中,世界适合四个方形图 block 。瓷砖数量的一般公式是:
图 block 数 = 4^zoomLevel
最重要的是,每次我们放大时,穿过 map (一行)所需的图 block 数量都会翻倍。
以此为出发点,我们可以弄清楚如何匹配两者。
d3 geoMercator 使用 961/(2*Math.PI)
作为默认比例 - 这将赤道的 360 度(或 2 弧度)扩展到 961 像素。要将其设置为适用于基于图 block 的图层,我们只需要知道图 block 大小和缩放级别。
我们需要知道赤道分布了多少像素,我们使用:
tileSize * Math.pow(2,zoomLevel)
这为我们提供了环绕赤道的所有方 block 的宽度。然后我们可以将其除以 2Pi 得到我们的 d3 比例:
projection.scale(tileSize * Math.pow(2,zoomLevel)/(2 * Math.PI))
由于 d3 墨卡托和 web 墨卡托之间的差异,可能会出现失真问题,具体取决于您所在的位置和缩放的距离,但这在大多数情况下应该可以提供良好的对齐效果。
或者,我们可以使用传单 map 的实际角来确定合适的比例:
D3 的特点是允许投影将地理范围适合 svg 范围:projection.fitExtent()
。此方法采用 geojson 或几何图形。在这个答案中,我使用的是 geojson。
.getBounds()
将返回传单 map 范围,因此您可以相当轻松地创建一个 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);
使用稍微修改过的 leaflet example(更改中心点和缩放),整个事情看起来像这样:
var features = {
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"properties": {},
"geometry": {
"type": "Polygon",
"coordinates": [
[
[
-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.eyJ1IjoibWFwYm94IiwiYSI6ImNpejY4NXVycTA2emYycXBndHRqcmZ3N3gifQ.rJcFIG214AriISLbB6B5aw', {
maxZoom: 18,
attribution: 'Map data © <a href="http://openstreetmap.org">OpenStreetMap</a> contributors, ' +
'<a href="http://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>, ' +
'Imagery © <a href="http://mapbox.com">Mapbox</a>',
id: 'mapbox.streets'
}).addTo(mymap);
var svg = d3.select('#mapid')
.append('svg')
.attr('width',600)
.attr('height',400);
// Create a geojson bounding box:
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]
]
]
}
var projection = d3.geoMercator()
.fitSize([600, 400], bbox);
var path = d3.geoPath().projection(projection);
svg.append("path")
.datum(features)
.attr('d',path);
svg {
z-index: 10000;
position: relative;
}
<div id="mapid" style="width: 600px; height: 400px;"></div>
<link rel="shortcut icon" type="image/x-icon" href="docs/images/favicon.ico" />
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.0.3/dist/leaflet.css" integrity="sha512-07I2e+7D8p6he1SIM+1twR5TIrhUQn9+I6yjqD53JQjFiMf8EtC93ty0/5vJTZGF8aAocvHYNEDJajGdNx1IsQ==" crossorigin=""/>
<script src="https://unpkg.com/leaflet@1.0.3/dist/leaflet.js" integrity="sha512-A7vV8IFfih/D732iSSKi20u/ooOfj/AGehOKq0f4vLT1Zr2Y+RX7C+w8A1gaSasGtRUZpF/NZgzSAu4/Gc41Lg==" crossorigin=""></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.9.1/d3.js"></script>
我没有添加 map 更改时更新投影的代码,但这只是重新计算边界框并重新应用 fitSize 方法。
关于d3.js - 计算墨卡托 d3 缩放以匹配 Leaflet 缩放级别,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44612175/
我正在尝试实现类似于 Leaflet.buffer 的缓冲区在我的 map 上。然而,Leaflet.buffer 似乎只适用于 Leaflet.Draw。 我正在使用 Leaflet Editabl
我正试图摆脱 Google map ,因为我受够了他们现在的速度有多慢!我决定试一试 Leaflet,这似乎是个不错的选择。下面是我的代码: initMap(); function initMap()
在 Leaflet 中,是否可以使用 {clickable:false} 定义标记或折线,以便点击传递到下方的任何内容 - 无论是 map 还是可点击的几何对象? 目前我通过使标记/折线可点击并自己传
我正在结合 Leaflet 使用 HTML map 进行一些测试。 .服务器端我有一个 Ruby Sinatra 应用程序,它提供由 MySQL 表获取的 json 标记。使用 2k-5k 和可能更多
我无法使用Leaflet(0.7.7)/Leaflet.Draw(latest)将Layer属性转换为GEOJson对象的属性。我的工作流程是: 1创建 map :var map = L.map('#
我正在使用使用传单 api 的应用程序。 简介 我需要绘制不同类型的围栏,使用装饰器我可以在一定程度上为折线应用良好的视觉效果,但不多。 问题 我愿意显示双绞线而不是破折号、点或普通线,我知道双绞线将
我在我的应用程序中使用 WebView 来显示 Leaflet map 。 在 HTML 文件中,我有以下信用和链接: L.tileLayer('https://api.tiles.mapbox.co
我正在使用https://github.com/Leaflet/Leaflet.draw插件,并且试图检索已编辑图层的图层类型。 在draw:created事件中,我有layer和layerType,
我的左下角有缩放控件和比例尺。 我遇到的问题是,当我的 map 在移动设备上旋转时,它们与左上角的自定义控制面板重叠。 那么如何使比例尺水平位于缩放控件旁边? 最佳答案 您可以通过更改比例控件的 CS
我想计算标记的高度,但我在传单中没有找到任何解决方案。我找到了海拔插件,它允许在 map 上绘制海拔剖面图,但我不需要它。你知道如何计算高度吗?谢谢。 最佳答案 编辑:一个不错的选择 为任何可能需要它
我明白我可以使用通用Leaflet layer ,以及更高级的 map 框 featureLayer ,它提供了作为过滤器的有用功能。但是,我不明白两者之间的区别 marker = L.Marker
我正在尝试在 Render mapbox vector tiles inside react-leaflet? 中描述此实现工作,除了我使用的是 TypeScript。 所以我的文件看起来像这样: i
我正在尝试将我的点在 map 上的正确位置作为 Latlng: let point = L.point(0,0) // x=0,y=0 let latlng = map.unproject(point
我正在使用 Leaflet.VectorGrid用于在传单 map 上加载 pbf 矢量切片的插件。我检索矢量切片的 API 需要传递授权 header 。在 Mapbox GL js 中,这可以通过
我们有一张 map ,在某个缩放级别,我们开始对标记进行聚类。 现在我希望能够删除某些标记。我可以删除不参与集群的标记,但集群中的标记不会被删除,因为代码不会遍历它们。 我会发布代码,但它无处不在,而
我仅在同一位置的标记上进行聚类(即 maxClusterRadius = 0)。单击集群时,我希望它以特定的缩放级别(不是最大缩放)居中并放大,然后立即 spiderfy。使用以下代码,spiderf
使用 Leaflet javascript。我希望我的“清除按钮”能做两件事... 1) 取消选中所有 L.Control 层2) 从 map 中移除当前叠加层 我可以使用这段代码轻松完成第一个: v
我正在开发一个包含大量标记的应用程序,并希望将它们聚类。我找到了 Leaflet.markercluster,它做得很好。但是,我想自定义标记的聚类。具体来说,我想根据标记所在的国家/地区对我的标记进
有点奇怪,希望有人能帮忙。 在传单中,一旦用户输入了纬度/经度并向 map 添加了一个点,我希望能够在该点周围添加一个 10 公里的正方形。 我已经尝试四处寻找计算以找到 x 公里外的正方形的角,但没
我在 leaflet.js 中创建了一个具有多个图层的 map ,但无法弄清楚如何切换一个图层以最初显示在 map 上。 Here is the link 我确信它相当简单,但就是无法弄清楚。 最佳答
我是一名优秀的程序员,十分优秀!