話很少說,先上效果圖html
之前在作項目時,常常會聽到客戶說,大家這個地圖是哪來的,太醜了,能不能換成百度地圖……高德也行……git
你們生活中,基本上都已經習慣了使用百度地圖和高德地圖,而在作項目時,用這兩個地圖作爲底圖,也基本成爲了標配。但在開發中使用這兩個地圖,會遇到一個攔路虎,座標偏移問題。github
全球如今用的最多的座標,是wgs84座標,專業GPS設備和手機GPS定位獲得的座標,一般都是這個座標。咱們國家爲了保密須要,要求在國內發佈的互聯網地圖,必需要在這個基礎上進行加密偏移。加密後的座標叫作國測局座標,俗稱火星座標。高德地圖、騰訊地圖、國內的谷歌地圖都是這個座標。百度地圖則是在火星座標的基礎上再次加密,造成了百度座標。算法
leaflet有一個加載互聯網地圖的插件leaflet.ChineseTmsProviders,能夠輕鬆實現加載高德、百度、天地圖、谷歌等在線地圖瓦片,但並無去解決它們的偏移問題。高德和百度地圖卻是提供了wgs84座標轉成本身座標的在線接口,但僅支持單向轉入,不支持反向再轉回來,這會致使地圖拾取座標等功能沒法獲得wgs84座標。微信
網上流傳着一份wgs84座標、火星座標和百度座標之間相互轉換的算法。在多個項目中使用後發現,基本很準,偶爾有偏差,但很小,也就幾米之內,平時用時基本感受不到。ide
兩種思路:加密
第一種,把糾偏算法封裝成一個接口,相似上面提到的百度、高德地圖的座標轉換接口,在向地圖加載數據前,先調用這個接口完成座標的轉換再添加到地圖上。等因而把本身的數據偏移到互聯網地圖座標上。這種是最多見的。spa
第二種,百度、高德的地圖都是瓦片地圖,每一張瓦片在加載時都會去計算它的經緯度位置,咱們能夠在計算經緯度位置時加入糾偏算法,把瓦片的座標位置糾偏回來。當全部瓦片的位置正確了,整個地圖也就不存在偏移了。等因而把火星座標或百度座標的瓦片糾偏回wgs84座標。插件
兩種方案進行比較,第一種明顯是被百度、高德的座標轉換接口帶節奏了。leaflet是開源的,咱們能夠經過研究源碼實現對瓦片的糾偏,從而真正實現對地圖的糾偏,而不是每次去調用座標轉換接口,讓數據將錯就錯。3d
第二種方案還能夠進一步延伸,把對瓦片的糾偏封裝成插件,最終目標是引入這個插件之後實現對地圖的自動糾偏。
對瓦片糾偏,先要找到加載瓦片、計算瓦片位置的代碼在哪。
上文中提到的,加載互聯網地圖的插件leaflet.ChineseTmsProviders本質是一個圖層,它繼承了TileLayer
TileLayer繼承了GridLayer
加載瓦片的代碼主要是在GridLayer中寫的。
計算瓦片位置的代碼在 _getTiledPixelBounds 方法和 _setZoomTransform 方法中。
瓦片糾偏分三步:
第一步:準備座標轉換的算法
第二步:根據互聯網地圖名稱獲取座標類型
第三步:在獲取瓦片和地圖縮放的方法中,調用糾偏算法
有個問題,既然要封裝成插件,就要作到耦合,不能直接修改leaflet的源碼。這裏能夠參考leaflet的源碼,使用 include 方式對方法進行重寫來作到修改源碼。
include方式經過例子瞭解一下:好比leaflet源碼中 Polygon.toGeoJSON() 方法不是在 Polygon.js 文件中寫的,而是用 include 方式寫在了GeoJSON.js文件中。Polygon類原本是沒有toGeoJSON()方法的,這樣就增長了這個方法。若是Polygon類中已經有了toGeoJSON()方法,這樣寫會根據執行的順序,後執行的會把先加載的重寫。
最後,咱們把上面的代碼封裝成一個js插件,你們引用這個插件,就能實現了對地圖的糾偏,不須要寫一行js代碼,這纔是我心目中真正的優雅。
下圖是引用糾偏插件先後的對比:
注意:leaflet會以map初始化之後,加載的第一個圖層的座標,做爲整個map的座標,因此地圖初始化之後,要第一個添加互聯網地圖做爲底圖。
不熟悉github的童鞋,能夠微信搜索《GIS兵器庫》或掃描下面的二維碼,回覆 「地圖糾偏」 得到糾偏插件的下載連接。
本文會常常更新,請閱讀原文:[http://gisarmory.xyz/blog/ind...,以免被陳舊、錯誤的知識誤導。
微信搜索《GIS兵器庫》或掃描上文的二維碼,關注GIS兵器庫公衆號, 能夠第一時間得到GIS文章更新。
本文章採用 知識共享署名-非商業性使用-相同方式共享 4.0 國際許可協議 進行許可。歡迎轉載、使用、從新發布,但務必保留文章署名《GIS兵器庫》(包含連接: http://gisarmory.xyz/blog/),不得用於商業目的,基於本文修改後的做品務必以相同的許可發佈。