最近在折騰的 web 端的可視化項(xiàng)目,由于相關(guān)業(yè)務(wù)的需要,用到了 Mapbox 這一地圖開發(fā)的神器。在此先奉上一個(gè)基于mapbox-gl實(shí)現(xiàn)的demo(來源:uber的deck.gl項(xiàng)目):
下面我們從這個(gè)項(xiàng)目一步步來介紹 Mapbox 的前端 GIS 引擎 Mapbox GL JS.
一、簡單了解
首先,Mapbox 在地圖領(lǐng)域是一家很 Newbee 的公司。已為 Foursquare、Pinterest、Evernote、金融時(shí)報(bào)、天氣頻道、優(yōu)步科技 等公司的網(wǎng)站提供了訂制在線地圖服務(wù)。
自2010年起,該公司快速地拓展了訂制地圖的市場地位,以回應(yīng) Google地圖 等地圖供應(yīng)商提供的有限選擇。Mapbox 是一些開放源代碼地圖庫及應(yīng)用程序的創(chuàng)建者或最大的貢獻(xiàn)者,其中包含了MBTiles 規(guī)范、TileMill 制圖 IDE、Leaflet JavaScript 庫,以及 CartoCSS 地圖格式化語言與語法分析器等。
該公司的數(shù)據(jù)同時(shí)從開放與專有的來源獲取,開放的數(shù)據(jù)源如 開放街圖(OSM, Open Street Map) 以及 NASA 等,而專有的數(shù)據(jù)源則包含了 DigitalGlobe。其技術(shù)奠基于 Node.js、CouchDB、Mapnik、GDAL 與 Leafletjs。
[圖片上傳失敗...(image-e27a1b-1515395418070)]
Mapbox 針對不同平臺均開發(fā)了相應(yīng)的 GIS 引擎以滿足開發(fā)者或相關(guān)用戶的需要,如:iOS SDK(用于iOS端開發(fā))、Android SDK(用于Andriod端開發(fā))、Navigation SDK(用于Navigation端開發(fā))、Unity SDK(用于Unity端開發(fā))、GL JS(用于web端開發(fā))。不同平臺的SDK,除使用方式不同外,功能特性上也多多少少存在不同。此外,Uber還針對react開發(fā)了 react-map-gl??偟膩碚f,Mapbox的開源技術(shù)棧是非常全面的。
二、輕松上手
[圖片上傳失敗...(image-426b0b-1515395418070)]
mapbox-gl 的 文檔 由 API、Style Specification、Example、Plugins 四部分內(nèi)容組成。
顧名思義,API 是一般框架(類庫)提供給用戶的全部接口(方法)的說明書;Style Specification 是 Mapbox 地圖的樣式規(guī)范;Example 是一些常用功能或常見業(yè)務(wù)的代碼示例,囊括了使用 Mapbox 所能實(shí)現(xiàn)的大部分功能效果;Plugins 則是官方推薦的可與 mapbox-gl 一同使用的一些增效插件和開源項(xiàng)目,如一些第三方的UI控件、顯示類插件、框架集成工具、開發(fā)輔助工具、實(shí)用工具類庫等等。
對于初了解 Mapbox 的童鞋,建議先從官網(wǎng)的 Example 入手,能夠較快掌握 mapbox-gl 的使用并投入開發(fā)實(shí)踐。
三、快速實(shí)踐
下面以文章開頭展示的項(xiàng)目為主,介紹其實(shí)戰(zhàn)步驟。
1. 加載地圖:
由于使用在線地圖服務(wù)和 style 時(shí)需要驗(yàn)證用戶 token,所以在使用 mapboxgl 時(shí)需要先配置用戶 token(在Mapbox官網(wǎng)注冊用戶即可獲取)。
import mapboxgl from 'mapbox-gl';
mapboxgl.accessToken = '<Your Token Here>';
接下來使用創(chuàng)建地圖實(shí)例。主要配置項(xiàng)如下:
const myMap = new mapboxgl.Map({
container: '<Id of Container Element>',
style: '<Your Style Here>',
center: [112.508203125, 37.97980872872457],
zoom: 4,
pitch: 0,
bearing: 0,
});
其中,container 是地圖容器的元素 id,style 是地圖樣式的 url,或者你自己定義的 style(需遵循Mapbox樣式規(guī)范),center 是地圖加載后默認(rèn)的中心點(diǎn)位置,用以定位地圖加載時(shí)的位置。zoom pitch bearing 分別指縮放級別、地面法線偏移角、地軸偏移角等,用以確定當(dāng)前視窗所顯示的地圖區(qū)域和空間關(guān)系。配置項(xiàng)的意義均可查看官網(wǎng)文檔。
2. 繪制圖形
這里主要介紹視頻中的3D建筑、飛線動畫等是如何實(shí)現(xiàn)的。這里以相關(guān)代碼片段來介紹實(shí)踐的方法。
在Mapbox中繪制圖形時(shí), layer 和 source 是最重要的一組概念,后者用于存儲圖形的數(shù)據(jù)內(nèi)容,前者則是圖形在3D場景中的表現(xiàn)(圖層)。在Mapbox中,圖層一旦被創(chuàng)建,與其同名(id相同)的數(shù)據(jù)源源(即source)也必然被創(chuàng)建。反之,也可以在創(chuàng)建source后再創(chuàng)建一個(gè)圖層使用這個(gè)已創(chuàng)建的數(shù)據(jù)源,這時(shí)數(shù)據(jù)源與圖層間并不要求同名。而我們通過改變數(shù)據(jù)來驅(qū)動圖形變化,便是才去的第二種方式:
// 創(chuàng)建id為buildings的數(shù)據(jù)源
myMap.addSource('buildings', {
type: 'geojson',
data: '<GeoJson Contents>',
});
// 使用buildings的數(shù)據(jù)來繪制id為building_layer的圖形
myMap.addLayer({
id: 'building_layer',
type: 'fill-extrusion',
source: 'buildings',
...<Other Options>,
});
基于上面的方式,當(dāng)數(shù)據(jù)改變時(shí),我們只需要重設(shè)數(shù)據(jù)源的數(shù)據(jù),即可驅(qū)動圖層重繪:
if (myMap.getLayer('building_layer')) {
myMap.getSource('buildings').setData(<New GeoJson Contents>);
}
至于3D效果及動畫的具體實(shí)現(xiàn),這里給出兩個(gè)官網(wǎng)上的示例,相信大家能一目了然:
3. 圖形交互
Mapbox提供的交互方法是比較靈活的,活學(xué)活用API文檔便能實(shí)現(xiàn)各種炫酷、實(shí)用的交互效果。比如:使用
myMap.on('zoom', callback) 可以將圖形與地圖的縮放相綁定,當(dāng)縮放系數(shù)小于某個(gè)值時(shí),可以隱藏掉一些圖形元素:
myMap.on('zoom', () => {
if (myMap.getZoom() <= 4) {
myMap.setLayoutProperty('building_layer', 'visibility', 'none');
} else {
myMap.setLayoutProperty('building_layer', 'visibility', 'visible');
}
});
再比如,連續(xù)調(diào)用 myMap.flyTo() 的方法使視圖在地圖上按照一定的軌跡緩慢移動,可以給用戶一種模擬飛行的體驗(yàn)。視頻中的自動巡視的效果正是這樣實(shí)現(xiàn)的。
諸如 click mouseover popup 等效果,官網(wǎng)文檔中的示例已經(jīng)具體呈現(xiàn),這里就不詳細(xì)展開了。
4. tiles-server的本地化
由于 Mapbox 地圖服務(wù)使用 MBTiles 存儲數(shù)據(jù),目前很多地圖服務(wù)都接受了這套標(biāo)準(zhǔn)(如:OSM,Open Street Map)。所以可以通過搭建自己的 tiles-server 以替代直接使用 Mapbox 的在線地圖服務(wù)。
這樣做的好處是顯而易見的:一是可以通過負(fù)載均衡等手段提高數(shù)據(jù)接口的訪問速度,有效提高數(shù)據(jù)的加載速度;一是保障應(yīng)用能在零帶寬的環(huán)境下仍能有效部署和使用。
這里墻裂安利一個(gè)docker開源鏡像:openmaptiles-server ,在其 官網(wǎng) 和 dockerhub 上均可下載。個(gè)人認(rèn)為其最大的亮點(diǎn)在于——即使不了解內(nèi)部實(shí)現(xiàn),也不影響其使用。

運(yùn)行 tiles-server 服務(wù)的 docker 命令如下:
$ docker run --rm -it -v $(pwd):/data -p 8080:80
然后剩下來需要做的事情就是打開其導(dǎo)航頁面 http://localhost:8080/(端口號取決于你的啟動命令),然后跟著頁面上的提示一步一步設(shè)置就好了(最后一步設(shè)置后會從OSM走動下載地圖,所以一開始你不用擔(dān)心數(shù)據(jù)從哪來),完全是傻瓜式的部署。
四、性能調(diào)優(yōu)
在 Mapbox GL 實(shí)踐的過程中,發(fā)現(xiàn)了一些影響應(yīng)用整體性能的因素,故而在此陳述一番,為之后填坑的童鞋提供一些經(jīng)驗(yàn):
- 使用geo數(shù)據(jù)(如 GeoJson 格式數(shù)據(jù))來定義圖形的時(shí)候,若數(shù)據(jù)量過大,則會拖慢數(shù)據(jù)加載的速度,此時(shí)可考慮:
i. 在 http 請求前后對數(shù)據(jù)進(jìn)行合理的壓縮和解壓,以盡可能節(jié)省 http 請求傳輸?shù)臄?shù)據(jù)量;
ii. 條件允許的情況下,可將一組數(shù)據(jù)分片加載,以空間換時(shí)間。
在 Mapboox 中繪制的圖層不宜過多,一是不方便管理(當(dāng)然,github上有很多管理Mapbox圖層的第三方工具),一是圖層過多會明顯降低GL的渲染和響應(yīng)性能。所以在繪制圖形前,可以先考慮一下圖層的劃分,以最少的圖層實(shí)現(xiàn)盡可能多的效果。
數(shù)據(jù)量相同的情況下,使用
mapboxgl.Marker來添加標(biāo)記,其性能不如使用type為symbol類型的圖層來添加標(biāo)記。原因在于前者生成的標(biāo)記是一個(gè)個(gè) DOM 元素,如果你可以想象在一個(gè) web 頁面中同時(shí)操作成百上千個(gè) DOM 節(jié)點(diǎn)會是什么結(jié)果,那么你或許能明白我的建議。
五、一點(diǎn)總結(jié)
最后,在此總結(jié)下個(gè)人對 Mapbox 的一些感觀。
Mapbox 的產(chǎn)品定位是隨時(shí)隨地的 GIS(跨平臺、應(yīng)用),它為我們提供了一系列的簡單操作的 API,使得 GIS 開發(fā)變得靈活而有趣。尤其對于開發(fā) GIS 類型的數(shù)據(jù)可視化應(yīng)用,Mapbox 是絕佳的選擇。
然而,如果你只是為了那些絢麗的 3D 效果的話,或許選擇專門的框架更為合適。