天天看點

什麼是mapbox?

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的,非常強大的,硬體加速的制圖庫,它可以完全控制每個地圖樣式的元素。
什麼是mapbox?
  • 2014.08 推出了Mapbox GL JS,它是新的一個快速而強大的Web地圖系統。Mapbox GL JS是一個用戶端的地圖渲染器,使用JavaScript和WebGL的動态繪制資料,呈現視訊遊戲級别的速度和平滑。
  • 2014.09 Mapbox Studio Classic 。是開源的地圖設計平台,在所有桌面平台上推出:OS X作業系統,Windows和Linux。Mapbox Studio Classic允許任何人設計完全定制的地圖,很輕松地處理巨量的全球資料,在幾秒鐘内釋出更新地圖,并且它所設計的地圖是與分辨率無關的,适應所有從Retina裝置到高分辨率的列印。
什麼是mapbox?
  • 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。
什麼是mapbox?
  • 2017.12 Mapbox GL JS中的3D功能
什麼是mapbox?

Mapbox開源項目介紹

筆者對Mapbox的一些開源項目、原理進行研究,下面将一一介紹這些筆者看過的項目并給出一些原了解讀。

MBTiles瓦片存儲規範

MBTiles瓦片存儲規範的制定主要是為了解決、優化傳統瓦片的存儲方案存在的兩個問題:

  1. 可移植性差,無法在移動端上做離線應用
  2. 存儲量大,大家都知道,因為網際網路上的地圖都以“瓦片”的形式存在,高層級的瓦片存儲數量往往是海量的。例如,對于“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檔案的執行個體:

什麼是mapbox?

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

什麼是mapbox?

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

什麼是mapbox?

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

什麼是mapbox?

對于不同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的樣式編輯區域

什麼是mapbox?

當然右側編輯區域用符合CartoCSS規範的的樣式描述語言去描述“圖層(layer)”的樣式(當然可以控制在圖層下面更加細節的feature)的時候,左側的地圖樣式也會随之改變。 CartoCSS的用法在這裡不詳細展開了,在需要用到時可以自行檢視,總之是非常類似CSS的一門标記文法。

不難發現,左側的地圖區域采用的是“栅格瓦片”,即由Mapnik将Mapnik XML描述檔案渲染成的圖檔。它的工作原理入下圖所示:

什麼是mapbox?

當然,在制作完地圖的樣式之後,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.
什麼是mapbox?

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

什麼是mapbox?

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?

Mapbox Studio Classic

Mapbox Studio Classic是Tilemill的更新版,目前也已經不維護了。

什麼是mapbox?

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

什麼是mapbox?

和Tilemill相比,當改變樣式檔案的時候,不用再到伺服器去使用Mapnik重新把資料渲染成栅格瓦片再傳回前端了,現在有Mapbox-gl.js可以在前端直接利用矢量瓦片和樣式檔案渲染出地圖來。

Mapbox Studio

Mapbox Studio是一個線上制圖、分享平台,“平台”意思是,跟之前的Tilemill/Mapbox Stduio Classic的本地制圖的模式有很大的不同。可以說,矢量瓦片的出現,給了“線上制圖平台”誕生的可能性。使用者在Mapbox網站上制作的地圖(本身在用戶端渲染瓦片的模式對服務端的開銷很低了)後,可以将瓦片、樣式、字型、Mark等資料直接托管在Mapbox平台上,然後使用者自己的APP、網站利用自己的Accesskey 可以通路自己的制作好的瓦片資料跟樣式。以下是筆者線上改變水系的顔色的制圖。

什麼是mapbox?

這個平台肯定是不開源的,沒法從源碼探究它的實作,但是矢量瓦片這塊的基本原理跟Mapbox Studio Classic肯定是一緻的。

利用Mapbox提供的開源技術,我們完全可以在本地可以實作一個自己的簡易版的Mapbox Studio。

其他