今年实验室几个 web 项目都用到了百度地图服务,但部署环境无法访问外网,必须要对百度地图进行离线化处理。百度地图没有官方的 web 端离线方案,只能自己动手,丰衣足食。地图离线化不仅包含普通地图的瓦片图,还要求包括卫星图 + 路网,绘制图形等独立的 Library。
看了一下百度地图 js 压缩处理后的源码,可以说是非常不友好了,为了快速实现这个需求,尽可能少的修改百度 js 代码,方便以后升级或者禁用离线版,一个简单的思路是修改原始瓦片图请求为本地的离线地图库。
背景知识
电子地图主要是基于图层叠加进行绘制,从真实世界的物理建模到路网、建筑,再到服务标注。目前大多数互联网地图服务提供商都使用瓦片图的拼接来实现地理信息展示,每个缩放层级分辨率都不同,即不同的缩放层级,会把图层分成大小相同、数量不等的瓦片图。
地理位置信息使用经纬度坐标来描述,原理是对椭球型的地球进行墨卡托投影,这种投影是将三维地球空间映射到二维空间,且能保持任意两点间的夹角不变。
经纬度坐标
国际标准的经纬度坐标是 WGS84
,国内提供地理位置信息服务的公司使用的坐标体系都不尽相同。网上都存在不同坐标体系之间的相互转化,如 GoogleMap -> BaiduMap 等。
核心库源码分析
Web 端百度地图的核心代码在 BaiduApi_2.0.js
中,主要实现了将 BMap 挂在 window 下,并添加一系列方法,和 AMD 模块加载。
绘图的核心代码在 DrawingManager_1.4.js
,主要实现了绘制多边形、区域选择等功能。
离线化
可选方案:
- leaflet + 百度/高德数据源
- 浏览器缓存
- 劫持请求到本地,缓存瓦片图【选用方案】
其中 leaflet 方案需要较高的开发成本,而浏览器缓存在无网络的环境下又不可行,所以选用了劫持百度核心库请求的方案。
瓦片图离线化
瓦片图下载工具在 fork 仓库的基础上加了下载卫星图和多线程模式,修改了下载路径和文件名等,为了和劫持的请求进行适配。
百度的瓦片图存储在多个 CDN 上,在核心代码里有一个简单的负载均衡策略,统一劫持改为离线模式。
百度地图模块离线化
百度地图除核心库外,还有很多以模块化加载的代码,放在 try-catch 里进行 eval。包括版本声明、InfoWidnow、Marker 等等。
这部分直接下载相应模块代码保存在 getmodules。
其中有一个点是百度设计的模块会并行加载,如有时候是 mapclick,marker...
加载,有时候是单个文件加载,而且顺序不定。这里我用了一个对象保存下载时的模块名称,然后进行匹配当时的模块请求,发现只要包括一项就加载多模块文件,缺少的再单独加载。