彻底理解Leaflet之 L.CRS + 搞定Leaflet多坐标系拓展

一、抛砖引玉

对于Leaflet创建map。总有一个很重要头疼的属性–crs:

  this.map = L.map("view-map", {
       zoomControl: false,
       attributionControl: false,
       crs: L.CRS.EPSG3857,
       minZoom: 1,
       maxZoom: 20,
   }).setView([38.00315, 114.28898], 4);

对。就是这么一个简单的属性,却是整个leaflet瓦片加载的核心算法必然依赖项。当然,对于leaflet官档,自然而然的给出了一句忠告:
在这里插入图片描述

Don’t change this if you’re not sure what it means.

嘿嘿。你这给了一个不要轻易去动,然后给死了一个坐标系L.CRS.EPSG3857。这怎么可能满足我等的需求嘛?如果我要支持地方坐标系呢?咋办?

二、进入主题

好奇的我们打开了leaflet的源码。发现对于CRS的定义就几个函数:
在这里插入图片描述
没错。你看出来了,其实这玩意就是提供了wgs84坐标系与目标坐标系之间转换的一种算法。因为leaflet内部都是用经纬度坐标系表达的坐标,所以leaflet内部表达所用的坐标系都是wgs84,也就是EPSG:4326。所以啊。不管是计算瓦片行列号,计算瓦片最终在地图上的位置,都需要对应的坐标系的定义进行转换。L.CRS就是定义了这样的一种转换算法。我们来看一下L.CRS.latLngToPoint内部实现:
在这里插入图片描述
没错。调用了this.projection.project()这个函数。那this.projection的定义呢?没错。单独使用L.CRS这个是无法实现坐标转换的。这只是一个模板,是一个壳,真正做转换的其实是this.projection做的事情。于是我们往下看,Leaflet到底在这个L.CRS里做了什么文章:

在这里插入图片描述
弄了一个Earth对象,继承了CRS的所有属性,新增了distance方法,用来计算两个经纬度之间的距离。这个我们过。

在这里插入图片描述

吼吼?EPSG3857的定义不就出来了?果然在继承的对象中添加了projection对象。并将SphericalMercator赋值给了它。自然而然,我们就找到了EPSG:3857坐标系的投影算法:
在这里插入图片描述
到这里想必大家看明白了。为了验证我们的想法,马上去看了一下L.。、CRS提供的4326的算法。果然:结果如我们想象的一样:
在这里插入图片描述
在这里插入图片描述
自己转自己,当然就是随意赋值给自己拉。

三、拓展坐标系

可惜。leaflet只提供了这2种坐标系。那如果我需要其他多种坐标系呢?给大家看看我们公司影像服务器要求支持的坐标系列表:
在这里插入图片描述
没错。有好几百个。。。实际存在的坐标系可能更多。那我们该如何拓展坐标系呢。看到这里,自然而然的我们就想到了gis神库:proj4.jsproj4.js是一个开源的,专门用来进行坐标定义和坐标转换的工具。官档只有一个api:

proj4(fromProj, toProj, coord) 

demo也很简单:

 //2437自定义-->4326
var proj1 = '+proj=tmerc +lat_0=0 +lon_0=120 +k=1 +x_0=502000 +y_0=2000 +ellps=krass +towgs84=15.8,-154.4,-82.3,0,0,0,0 +units=m +no_defs'; 
var proj2 = '+proj=longlat +datum=WGS84 +no_defs';
var projPoint = proj4(proj1, proj2, [x, y]);

上面的那个奇怪的字符串就是该坐标系的算法定义。全国比较常用的,官档都有。你要说生僻的,那只能自己定义。关于里面的各个参数的意义,你让我说,我也没办法都给你说出来。反正在我看来,他就是一个字符串。巧了,服务器给我的坐标系数据里正好就有
在这里插入图片描述
现在算法有了。就是封装的过程。

我们的目的很明确,就是弄一个crs对象传递给map的初始化的crs属性。我这个crs对象得有一个projection子对象,这个子对象要有projectunproject函数,在这个函数里去调用proj4进行坐标转换。当然网上已经有不少做好了拓展封装。proj4leaflet.js就是一个。文末附上下载链接。简要摘出部分代码:

在这里插入图片描述
拓展自原生的L.CRS,初始化了projection对象。咋样?是不是和我说的一样?
在这里插入图片描述
在初始化函数里用proj4定义了一个Proj4对象。然后在project和unproject里调用函数进行转换。
调用方法:

 const crs = new L.Proj.CRS(name,desc,{})
 
 this.map = L.map("view-map", {
       zoomControl: false,
       attributionControl: false,
       crs: crs,
       minZoom: 1,
       maxZoom: 20,
   }).setView([38.00315, 114.28898], 4);

在第三个参数这里还可以配置原点和bounds。即该坐标系的原点和bbox。这些参数我们服务器都有,网上也都有。

结语

本人分析的比较浅,对于深层次的proj4的算法。表示真心看不懂。不得不说leaflet的设计还是相当灵活的。拓展性很强。网上很多插件都是基于leaflet做的拓展。如果有什么不明白的也欢迎留言~

proj4leaflet以及proj4下载地址

猜你喜欢

转载自blog.csdn.net/qq_29722281/article/details/102635604
今日推荐