leaflet加载不同投影的瓦片地图

3,835 阅读3分钟

需求

由于项目使用矢量数据统一为大地2000坐标系(ESPG:4490),而遥感影像数据采用了多种坐标系,根据需求,需要在同一个地图控件上面显示不同坐标系的底图,每次切换底图后需要自动正确缩放到切换前地图显示范围。

坐标系wkid描述
China Geodetic Coordinate System 200044902000国家大地坐标系
CGCS2000 / 3-degree Gauss-Kruger zone 3745252000国家大地坐标系 高斯-克吕格投影 3度带分带 第37号分带
CGCS2000 / 3-degree Gauss-Kruger zone 3845262000国家大地坐标系 高斯-克吕格投影 3度带分带 第38号分带
CGCS2000 / 3-degree Gauss-Kruger zone 3945272000国家大地坐标系 高斯-克吕格投影 3度带分带 第39号分带
WGS 84 -- WGS84 - World Geodetic System 198443261984世界大地坐标系
WGS 84 / Pseudo-Mercator -- Spherical Mercator38571984世界大地坐标系 墨卡托投影

参考资料

change the crs property of map dynamically #2553 动态改变地图的CRS属性 #2553

问题

leaflet 本身不提供针对不同底图设置CRS的设置,所以切换底图后,由于切片范围计算参数没有更改,对于不同坐标系的底图没有显示到正确的位置。

解决思路

  1. 查看源代码,发现leaflet内置的所有矢量坐标都是转换为wgs84世界大地坐标系进行渲染显示,同时,切片计算方式则是依据map.crs对象的投影参数。矢量数据和切片数据的显示位置计算不会互相影响,所以当切片发生偏移,只需要更改map.crs对象的投影参数。
  2. 针对每个坐标系的投影参数创建crs对象。
  3. 当地图底图切换时,自动更新map.crs为对应坐标系的crs对象。

解决方案

  1. 使用Proj4Leaflet,创建CRS对象(leaflet自带wkid为4326和3857的CRS对象定义)
import L from 'leaflet'
import 'proj4leaflet'
const  resolutions = []  // 特别重要,从地图服务定义上面获取
L.CRS.EPSG4525 = new L.Proj.CRS('EPSG:4525',
      '+proj=tmerc +lat_0=0 +lon_0=111 +k=1 +x_0=37500000 +y_0=0 +ellps=GRS80 +units=m +no_defs',
      {
        resolutions: resolutions,
        origin:[] // 特别重要,从地图服务定义上面获取
      }
);
L.CRS.EPSG4526 = new L.Proj.CRS('EPSG:4526',
      '+proj=tmerc +lat_0=0 +lon_0=114 +k=1 +x_0=38500000 +y_0=0 +ellps=GRS80 +units=m +no_defs',
      {
        resolutions: resolutions,
        origin:[] // 特别重要,从地图服务定义上面获取
      }
);
L.CRS.EPSG4527 = new L.Proj.CRS('EPSG:4527',
      '+proj=tmerc +lat_0=0 +lon_0=117 +k=1 +x_0=39500000 +y_0=0 +ellps=GRS80 +units=m +no_defs',
      {
        resolutions: resolutions,
        origin:[] // 特别重要,从地图服务定义上面获取
      }
);
  1. 切换图层的同时切换crs
map.on('baselayerchange', function(layer) {
        let center = map.getCenter();
        let zoom = map.getZoom();

        map.options.crs = L.CRS.EPSG4525; // 根据图层坐标系设置
        map._resetView(center, zoom, true);
})

注意

由于wgs84和大地2000坐标系定义接近,并且4490的矢量数据传入leaflet中渲染并不会产生什么偏移,所以矢量数据不需要投影。