Table of Contents
背景情况
在对接客户过程中,客户不使用天地图作为地图服务,而要求使用他们发布好的 ArcGIS Server 离线瓦片地图,ArcGIS 离线地图的 z、x、y 规则与 leaflet 地图引擎的默认解析规则不一致,故需要扩展 leaflet 的 TileLayer。
使用 ArcGIS 瓦片地图
leaflet 解析规则
leaflet 的 TileLayer 通过内部的 getTileUrl 回调方法去获取瓦片路径,getTileUrl 会传入一个对象,对象中包含地图层级 z,瓦片横坐标 x,瓦片纵坐标 y。这些数据都为十进制数,与 ArcGIS 的瓦片解析规则不一致。
ArcGIS 瓦片路径
ArcGIS Server 切片后路径规则如下:
- __alllayers
- L00
- R00000000
- C00000000.png
- C0000000f.png
- R0000001f
- R00000000
- L21
- Conf.xml
- L00
可以看出 ArcGIS Server 切片规则:
- 最外层为__alllayers 文件夹;
- L 为地图层级文件夹,固定为 L 字母加两位十进制数,0-9 这种不足两位的层级,前面补 0;
- R 为瓦片纵坐标,固定为 R 字母加八位十六进制数,不足八位的,前面补 0;
- C 为瓦片横坐标,固定为 C 字母加八位十六进制数,不足八位的,前面补 0;
- Conf.xml 为配置文件,包含了瓦片的投影方式,原点坐标,分辨率等参数;
扩展 leaflet.TileLayer
了解了 leaflet 解析规则与 ArcGIS 瓦片规则的差别,就可以扩展 leaflet.TileLayer 类,自定义瓦片解析规则了。
// 瓦片加载扩展类const ArcGisServerTileLoad = L.TileLayer.extend({ // 扩展L.TileLayer类 getTileUrl: function (tilePoint) { // 地图层级 let zz = tilePoint.z.toString(); // 添加字母L并补0 zz = "L" + "00".slice(0, 2 - zz.length) + zz; // 初始8位16进制数 const initCR = "00000000"; // 瓦片横坐标,10进制转16进制 let xx = tilePoint.x.toString(16); // 添加字母并补0 xx = "C" + initCR.substring(0, 8 - xx.length) + xx; // 瓦片纵坐标,10进制转16进制 let yy = tilePoint.y.toString(16); // 添加字母并补0 yy = "R" + initCR.substring(0, 8 - yy.length) + yy; // 使用leaflet模板将各变量转换为路径字符串并返回 return L.Util.template( this._url, L.extend( { s: this._getSubdomain(tilePoint), z: zz, x: xx, y: yy, }, this.options, ), ); },});// 生成瓦片实例函数const arcGisServerTileLayer = (url: string, options?: L.TileLayerOptions) => { return new ArcGisServerTileLoad(url, options);};// 使用ArcGIS瓦片// 注意这里顺序为z、y、x,而不是z、x、y;map为leaflet的map实例arcGisServerTileLayer( "http://www.map-example.com/__alllayers/{z}/{y}/{x}.png",).addTo(map);坐标系投影
将瓦片解析规则调整为 ArcGIS 的解析规则后,发现瓦片地图仍然无法加载,排查原因后发现是瓦片的投影坐标系与 leaflet 地图引擎投影坐标系不同造成的。瓦片使用了 2000 国家大地坐标系,而 leaflet 默认只有 4326 与 3857 两种默认投影。
相关概念
-
EPSG:European Petroleum Survey Group,欧洲石油调查组织,最初由 EPSG 在 1985 年创建了地理参数数据集,并在 1993 年公开。2005 年 EPSG 并入国际油气生产者协会(IOGP),并入 IOGP 后,为避免混淆,数据集仍延用 EPSG 的名称,并由 IOGP 维护,后来 EPSG 就更多代指该数据集名称了。EPSG 编码介于 1024 至 32767 之间,每种地图投影都被分配了一个编码,该编码作为一种众所周知的机器可读的标准化文本存在,如
EPSG: 4326。EPSG 数据集可以通过网站https:epsg .io查看。 -
EPSG:4326 - WGS 84(world geodetic system 1984)即 世界大地测量系统 1984,广泛用于 GPS 定位等;
-
EPSG:3857 - Web Mercator Projection 网络墨卡托投影,常用于网络地图,如 Google Maps、OpenStreetMap;
-
EPSG:7789 - International Terrestrial Reference Frame 2014(ITRF2014)即 国际陆地参考系 2014;
-
EPSG:4490 - 2000 国家大地坐标系;
leaflet 使用 EPSG:4490 投影
- 安装并引入 proj4leaflet 插件;
npm install proj4leaflet;// 如果有引入leaflet库,引入proj4leaflet后,会自动挂载为L.Projimport "proj4leaflet";- 通过[https://epsg.io]网站查询 4490 投影定义配置,下滑页面至导出功能,复制 Proj4js 版本的 4490 定义配置;
proj4.defs("EPSG:4490", "+proj=longlat +ellps=GRS80 +no_defs");- 查看瓦片目录下的 Conf.xml 文件,找到投影坐标系、原点信息、分辨率等信息;
<!-- WKT标签表示了投影的坐标系,用于在epsg.io网站上查询对应的epsg编码,例如该WKT表示EPSG:4490 --><WKT>GEOGCS["CGCS_2000",DATUM["D_2000",SPHEROID["S_2000",6378137.0,298.2572221010041]],PRIMEM["Greenwich",0.0],UNIT["Degree",0.0174532925199433]]</WKT><!-- TileOrigin标签表示瓦片原点信息 --><TileOrigin xsi:type="typens:PointN"> <X>-180</X> <Y>90</Y></TileOrigin><!-- TileCols与TileRows标签表示瓦片大小 --><TileCols>256</TileCols><TileRows>256</TileRows><!-- LODInfo中代表每个地图层级的信息 --><LODInfo xsi:type="typens:LODInfo"> <!-- LevelID 地图层级 --> <LevelID>0</LevelID> <!-- Scale 缩放 --> <Scale>73957338.863641396</Scale> <!-- Resolution 分辨率 --> <Resolution>0.17597860392101103</Resolution></LODInfo>- 根据上述信息,并使用 proj4leaflet 创建新的投影
// 使用EPSG网站上复制出的4490配置const EPSG4490 = new L.Proj.CRS( "EPSG:4490", "+proj=longlat +ellps=GRS80 +no_defs", { // 使用Conf.xml中的resolution数据 resolutions: [ 0.17597860392101103, 0.087989301960505514, 0.043994650980252757, 0.021997325490126379, 0.010998662745063191, 0.0054993313725315955, 0.0027496656862657978, 0.0013748328431328989, 0.00068741642156644944, ], // 使用Conf.xml中的origin数据 origin: [-180, 90], },);
// 加载地图时,使用4490投影L.map("map", { crs: EPSG4490,});