Mapbox公司于2010年6月01日在美國成立,http://Mapbox.com 是一個很棒的地圖制作及分享網站,用戶可以使用Mapbox Studio創建一個自定義、互動式的地圖,然后可以將這些自定義的地圖和資料服務你自己的網站(Web)或移動應用程式(Mobile Web/Android/IOS)上,
在技術和體驗上,這家公司對傳統的地圖GIS系統的沖擊簡直都是顛覆性的,值得一提的是它為開源社區貢獻了mapbox-gl-native /mapbox-gl-js / node-sqlite3等許許多多開源專案,因此有必要對它的一些核心開源專案和矢量瓦片技術進行研究,
發展歷程
由2010年成立至今,Mapbox在業界的影響力可也說是蒸蒸日上了,筆者以為,為原本沉悶、技術陳舊的GIS界,注入了強大的活力,為移動互聯網時代帶來了一個嶄新的地圖互動方式,下面,先列出一些在Mapbox發展歷程中經歷的一些比較重要的大事件:
- 2011.01 起草MBTiles標準,這是一個新的跨平臺、支持離線的地圖存盤格式,
- 2011.02-2011.06 TileMill發布,允許用戶根據自定義資料來創建地圖,開發了CartoCSS樣式描述語言(類CSS),TileMill桌面軟體是使用Mapnik和Node.js開發的,
- 2013.05 矢量切片出現,推出了一個新的開源矢量瓦片規范,應用到Mapbox所有的Web地圖中,矢量切片提供了一種超快速、高效的格式,強化了地圖在互動特性、GeoJSON資料流、移動端渲染等等方面的性能,現在,設計迭代一個地圖可以在幾秒鐘內完成,在幾分鐘內就可以得到一個完整的全球矢量地圖,這個Mapbox Vector Tile(Mapbox 矢量瓦片)幾乎是革命性的,
- 2014.06 Mapbox GL誕生,它是一個新的可互動的,回應式地圖的渲染庫,Mapbox GL是一個基于OpenGL ES的,非常強大的,硬體加速的制圖庫,它可以完全控制每個地圖樣式的元素,

- 2014.08 推出了Mapbox GL JS,它是新的一個快速而強大的Web地圖系統,Mapbox GL JS是一個客戶端的地圖渲染器,使用JavaScript和WebGL的動態繪制資料,呈現視頻游戲級別的速度和平滑,
- 2014.09 Mapbox Studio Classic ,是開源的地圖設計平臺,在所有桌面平臺上推出:OS X作業系統,Windows和Linux,Mapbox Studio Classic允許任何人設計完全定制的地圖,很輕松地處理巨量的全球資料,在幾秒鐘內發布更新地圖,并且它所設計的地圖是與解析度無關的,適應所有從Retina設備到高解析度的列印,

- 2014.12 Turf.js.Turf是,它是一個快速、緊湊且開源的JavaScript庫,實作了最常見的地理空間操作功能,Turf作為新的地理空間基礎設施的一部分,不同于JavaScript的ArcGIS API,由于Turf可以完全在客戶端完成所有操作,Web應用程式可以脫機作業,
- 2015.11 Mapbox Studio 發布了Mapbox Studio,它是一個用于優化移動應用和現代網頁的制圖系統,Mapbox Studio包含矢量渲染來制繪地圖,更新和互動的速度與平滑程度和視頻游戲一樣,擁有的強大的資料基礎架構,支持自定義資料,格式轉換和處理快速而可靠,
- 2016.08 上海辦公室成立
- 2016.10 發布Mapbox Unity SDK 將Mapbox API的全部功能帶到基于位置的游戲、VR,

- 2017.12 Mapbox GL JS中的3D功能

Mapbox開源專案介紹
筆者對Mapbox的一些開源專案、原理進行研究,下面將一一介紹這些筆者看過的專案并給出一些原理解讀,
MBTiles瓦片存盤規范
MBTiles瓦片存盤規范的制定主要是為了解決、優化傳統瓦片的存盤方案存在的兩個問題:
- 可移植性差,無法在移動端上做離線應用
- 存盤量大,大家都知道,因為互聯網上的地圖都以“瓦片”的形式存在,高層級的瓦片存盤數量往往是海量的,例如,對于“Web 墨卡托”投影的瓦片金字塔來說,第15層資料有 4^15 = 1073741824個瓦片,
參見檔案,Mbtiles其實本質是一個SQLite3檔案,大家知道,SQLite有它天然的可移植特性(整個資料庫就是一個sqlite3檔案,當然可移植性夠好),這個解決了1的問題,
下面簡單解讀一下規范,該規范描述了這個sqlite3檔案的表必須符合以下規定:
- 必須要一個名叫“metadata”的table(表)或者view(視圖),這個表其實就是“元資料”表,用來描述存盤的資料,這個表必須要有兩列,一列是"name",一列是“value”,這兩列都是text型別的,這個表必須包含一些特定的row,例如name="name",value="資料集名稱";name: "format" ,value: "pbf"代表存盤的瓦片格式;name: "center" ,value: -122.1906,37.7599,1代表這個資料集存盤的資料中心在這個經緯度處,對于Mapbox矢量瓦片集,有特殊的json欄位,用來描述矢量瓦片集,
- 必須要有一個名字叫“tiles”的表,建表陳述句CREATE TABLE tiles (zoom_level integer, tile_column integer, tile_row integer, tile_data blob);
它可能會有一個索引:
CREATE UNIQUE INDEX tile_index on tiles (zoom_level, tile_column, tile_row);
這個表主要存了x/y/z和對應的瓦片資料(BLOB),標準還提到了TMS tiling scheme,有 興趣可以詳細看下,
- grids和grids_data表 可有可無,不細說了,
這邊給出一個MBTiles檔案的實體:

其中,map表存的是zoom_level/tile_column/tile_row/tile_id,其中tile_id是一個哈希值,

images表存的是tile_data/tile_id,其中tile_data是一個BLOB,

tiles表是基于map表和images表的一個視圖

對于不同zoom_level/tile_column/tile_row三元組,在map表中對應的tile_id有可能是相同的,這樣最終通過tiles視圖在images表中對應的tile_data就是同一個,這樣做于可以減少冗余瓦片,地圖中像海洋或空曠的土地等區域包含有成千上萬重復而冗余的純色瓦片,例如太平洋中蔚藍色的瓦片,在小比例尺中,它可能只有幾張,但在大比例尺如1:10000的地圖中,就會存在上百萬這種單一顏色的藍色瓦片,MBTiles 通過拆分瓦片索引和瓦片原始影像的存盤,使用視圖的方式來關聯二者,這樣成千上萬的瓦片索引就可以指向同一個瓦片影像,從而大大減少純色瓦片的冗余存盤,提升磁盤利用率以及瓦片檢索效率,
TileMill
TileMill這個專案到現在已經沒在維護了(但是還是可以下載使用),但是在當時這個專案引入了CartoCSS,利用Mapnik渲染瓦片圖片,還是有一定的先進性的,看了下是基于Node 0.10.x開發的,看版本號就知道有點久遠了,直接下載release版本,結果軟體一直在loading狀態所以放棄了,后來發現了這個fork,下載安裝,其中有個mime包依賴版本有break change,手動裝會1.x版本才可以成功跑起來,
下圖是TileMill自帶的一個華盛頓特區的地圖的示例,左側是地圖區域,右側是CartoCSS的樣式編輯區域

當然右側編輯區域用符合CartoCSS規范的的樣式描述語言去描述“圖層(layer)”的樣式(當然可以控制在圖層下面更加細節的feature)的時候,左側的地圖樣式也會隨之改變, CartoCSS的用法在這里不詳細展開了,在需要用到時可以自行查看,總之是非常類似CSS的一門標記語法,
不難發現,左側的地圖區域采用的是“柵格瓦片”,即由Mapnik將Mapnik XML描述檔案渲染成的圖片,它的作業原理入下圖所示:

當然,在制作完地圖的樣式之后,TileMill支持將地圖進行匯出為MBTiles格式,用于離線地圖,由上圖可以看出,這里利用Mapnik的強大渲染能力,對資料、樣式的分離有了一種很好的實踐,同樣的思想為日后的MVT矢量瓦片奠定了基礎,不過這種由客戶端改變樣式描述檔案,讓服務器去觸發渲染的模式,還是有一定的局限性,畢竟增加了前后端通信的開銷,另外對于更加復雜的地圖而言,Mapnik XML檔案往往會變得非常巨大,Mapnik縱使渲染能力強大,也會有其性能的瓶頸,所以這種模式只適用于本地環境制作地圖,對標現在的Mapbox Studio來看,是遠遠不夠的,
Tilelive
在TileMill的代碼中,其實就用到了Tilelive,筆者認為,Tilelive在瓦片的調度里面是一個非常核心的庫,雖然代碼量不大,但是它的設計和Plugin能力實在是有點“小而美”,有興趣可以看看原始碼,
Tilelive is designed for streaming map tiles from sources (like custom geographic data formats) to sinks (destinations, like file systems) by providing a consistent API. This repository enables the interaction between sources and sinks and is meant to be used in tandem with at least one Tilelive plugin. Tilelive plugins (modules) follow a consistent architecture (defined in API.md) and implement the logic for generating and reading map tiles from a source or putting map tiles to a destination, or both.

如上圖,Tilelive其實在整個Mapbox瓦片體系里面占著比較重要的地位,看Tilelive的實作和用法,有點像設計模式中的“配接器模式”,只要按照Tilelive的設計,實作Tilelive提供的標準函式,可以利用Tilelive的一些方法,實作各個資料源的資料互導,例如:想將別人家在MBTiles里面存的瓦片資料匯入到MongoDB里面去,就可以使用Tilelive和MBTiles/MongoDB的相關“plugin”辦到,甚至你也可以自己寫一個Plugin,當然,利用Tilelive配合其他Node Web庫(例如egg等)很容易在本地搭建出一個離線的瓦片服務器,有關Tilelive Pugin的示意圖如下:

Mapbox矢量瓦片(MVT)標準
前文也提到過,矢量瓦片標準是Mapbox的一個對業界非常大的貢獻,到目前為止,幾乎所有主流的Web端地圖渲染庫,例如ol3.js/Cesium.js/Leaflet等都已經支持MVT標準,即可以使用它們在Web端渲染出矢量瓦片資料,矢量瓦片標準規定了一種節省存盤空間的矢量瓦片資料編碼格式,這種格式應用于客戶端或服務端高效渲染或查詢要素資訊,
標準中規定了矢量瓦片的:
- 檔案格式 Google Protocol Buffers 、檔案后綴、MIME型別,
- 投影和范圍 Web Mercator是默認的投影方式,Google tile scheme是默認的瓦片編號方式,
- 內部結構
- 圖層
- 要素
- 幾何圖形編碼
- 要素屬性
矢量資料切片為瓦片后,其坐標從地理坐標轉換為螢屏坐標,以整數形式存盤,整型比浮點型所需的存盤空間更小,大大降低了瓦片的傳輸成本
實體:一個GeoJSON的格式要素如下:
{ "type": "FeatureCollection", "features": [ { "geometry": { "type": "Point", "coordinates": [ -8247861.1000836585, 4970241.327215323 ] }, "type": "Feature", "properties": { "hello": "world", "h": "world", "count": 1.23 } }, { "geometry": { "type": "Point", "coordinates": [ -8247861.1000836585, 4970241.327215323 ] }, "type": "Feature", "properties": { "hello": "again", "count": 2 } } ] }
會被結構化為:
layers { version: 2 name: "points" features: { id: 1 tags: 0 tags: 0 tags: 1 tags: 0 tags: 2 tags: 1 type: Point geometry: 9 geometry: 2410 geometry: 3080 } features { id: 1 tags: 0 tags: 2 tags: 2 tags: 3 type: Point geometry: 9 geometry: 2410 geometry: 3080 } keys: "hello" keys: "h" keys: "count" values: { string_value: "world" } values: { double_value: 1.23 } values: { string_value: "again" } values: { int_value: 2 } extent: 4096 }
有了矢量瓦片標準,對于在Web里面來說,利用WebGL的moveTo/lineTo之類的API,可以將矢量瓦片繪制出來,
Mapbox GL
Mapbox-GL.js是一個在Web瀏覽器里面決議矢量瓦片規范并且封裝了WebGL,可以在Canvas上對矢量瓦片進行繪制的地圖庫,其中也用到了一些硬體加速的東西(著色器)等,官方提供的示例也非常多非常棒,參考這些示例去開發一些基于地理位置的應用還是不錯的,

Mapbox Studio Classic
Mapbox Studio Classic是Tilemill的升級版,目前也已經不維護了,

與Tilemill的界面類似,也是左側是地圖,右側是CartoCSS的樣式編輯區域,它們的主要區別在于Mapbox Studio Classic使用了矢量瓦片進行地圖樣式的制作,同時,由于是矢量瓦片,字體之類的東西就沒法直接在矢量瓦片里面存盤,所以多了字體的功能,支持自己上傳字體等功能,它的原理基本如下圖:

和Tilemill相比,當改變樣式檔案的時候,不用再到服務器去使用Mapnik重新把資料渲染成柵格瓦片再回傳前端了,現在有Mapbox-gl.js可以在前端直接利用矢量瓦片和樣式檔案渲染出地圖來,
Mapbox Studio
Mapbox Studio是一個在線制圖、分享平臺,“平臺”意思是,跟之前的Tilemill/Mapbox Stduio Classic的本地制圖的模式有很大的不同,可以說,矢量瓦片的出現,給了“在線制圖平臺”誕生的可能性,用戶在Mapbox網站上制作的地圖(本身在客戶端渲染瓦片的模式對服務端的開銷很低了)后,可以將瓦片、樣式、字體、Mark等資料直接托管在Mapbox平臺上,然后用戶自己的APP、網站利用自己的Accesskey 可以訪問自己的制作好的瓦片資料跟樣式,以下是筆者在線改變水系的顏色的制圖,

這個平臺肯定是不開源的,沒法從原始碼探究它的實作,但是矢量瓦片這塊的基本原理跟Mapbox Studio Classic肯定是一致的,
利用Mapbox提供的開源技術,我們完全可以在本地可以實作一個自己的簡易版的Mapbox Studio,
其他
高德最近推出的自定義地圖:https://lbs.amap.com/dev/mapstyle/index

看起來也是前端做的矢量瓦片渲染,但是如果是這樣也肯定是自己的矢量瓦片標準吧,
原文鏈接: https://zhuanlan.zhihu.com/p/45518647
轉載請註明出處,本文鏈接:https://www.uj5u.com/qianduan/257808.html
標籤:其他
