非地球
有时,地图并不代表地球表面的事物,因此没有地理纬度和经度的概念。大多数情况下,这指的是大型扫描图像,例如游戏地图。
在本教程中,我们选取了来自《星际控制 II》的游戏地图,该游戏现在已作为开源项目 The Ur-Quan Masters提供。这些地图使用读取游戏开源数据文件的工具制作(网页似乎已下线,请参阅存档版本),如下所示
该游戏内置了一个方形坐标系,如角落所示。这将使我们能够建立一个坐标系。
CRS.Simple
CRS 代表坐标参考系统,地理学家用它来解释坐标向量中的坐标含义。例如,[15, 60]
表示地球上使用经纬度时的印度洋中的一个点,或者我们星图中的太阳系 Krueger-Z。
Leaflet 地图只有一个 CRS(而且只有一个 CRS),可以在创建地图时更改。对于我们的游戏地图,我们将使用CRS.Simple
,它表示一个方形网格
var map = L.map('map', {
crs: L.CRS.Simple
});
然后,我们只需添加一个带有星图图像及其近似边界的L.ImageOverlay
var bounds = [[0,0], [1000,1000]];
var image = L.imageOverlay('uqm_map_full.png', bounds).addTo(map);
并显示整个地图
map.fitBounds(bounds);
查看此独立示例。 |
此示例无法正常工作,因为在执行fitBounds()
后,我们无法看到整个地图。
CRS.Simple 地图中的常见错误
在 Leaflet 的默认 CRS CRS.Earth
中,360 度经度映射到 256 个水平像素(在缩放级别 0 时),大约 170 度纬度映射到 256 个垂直像素(在缩放级别 0 时)。
在 CRS.Simple
中,一个水平地图单位映射到一个水平像素,同理垂直方向也一样。这意味着整个地图大约有 1000x1000 像素大小,无法容纳在我们的 HTML 容器中。幸运的是,我们可以将minZoom
设置为小于零的值
var map = L.map('map', {
crs: L.CRS.Simple,
minZoom: -5
});
像素与地图单位
使用 CRS.Simple
时,一个常见的错误是假设地图单位等于图像像素。在这种情况下,地图覆盖了 1000x1000 个单位,但图像大小为 2315x2315 像素。不同的情况会要求一个像素 = 一个地图单位,或者 64 个像素 = 一个地图单位,或者任何值。以地图单位思考,然后根据需要添加图层(L.ImageOverlay
、L.Marker
等)。
事实上,我们使用的图像覆盖了超过 1000 个地图单位 - 存在一个相当大的边距。测量 0 和 1000 坐标之间有多少个像素,并推算,我们可以获得此图像的正确坐标边界
var bounds = [[-26.5,-25], [1021.5,1023]];
var image = L.imageOverlay('uqm_map_full.png', bounds).addTo(map);
趁此机会,让我们添加一些标记
var sol = L.latLng([ 145, 175.2 ]);
L.marker(sol).addTo(map);
map.setView( [70, 120], 1);
查看此独立示例。 |
这不是你想要的 LatLng
你会注意到 Sol 的坐标是 [145,175]
而不是 [175,145]
,地图中心也是如此。 CRS.Simple
中的坐标采用 [y, x]
而不是 [x, y]
的形式,就像 Leaflet 使用 [lat, lng]
而不是 [lng, lat]
一样。
(从技术角度讲,Leaflet 倾向于使用[northing, easting]
而不是 [easting, northing]
- 坐标对中的第一个坐标指向“北”,第二个坐标指向“东”)
关于 [lng, lat]
或 [lat, lng]
或 [y, x]
或 [x, y]
的争论由来已久,并没有明确的共识。由于缺乏共识,Leaflet 才会有一个名为 L.LatLng
的类,而不是更易造成混淆的 L.Coordinate
。
如果你觉得使用名为 L.LatLng
的 [y, x]
坐标没有意义,可以轻松地为它们创建包装器
var yx = L.latLng;
var xy = function(x, y) {
if (Array.isArray(x)) { // When doing xy([x, y]);
return yx(x[1], x[0]);
}
return yx(y, x); // When doing xy(x, y);
};
现在,我们可以添加一些恒星,甚至可以使用 [x, y]
坐标添加一条航线
var sol = xy(175.2, 145.0);
var mizar = xy( 41.6, 130.1);
var kruegerZ = xy( 13.4, 56.5);
var deneb = xy(218.7, 8.3);
L.marker( sol).addTo(map).bindPopup( 'Sol');
L.marker( mizar).addTo(map).bindPopup( 'Mizar');
L.marker(kruegerZ).addTo(map).bindPopup('Krueger-Z');
L.marker( deneb).addTo(map).bindPopup( 'Deneb');
var travel = L.polyline([sol, deneb]).addTo(map);
地图看起来基本相同,但代码更易读
查看此独立示例。 |