在Mapbox GL JS 設(shè)計淺析中我們知道Mapbox GL JS使用的樣式是在線的弓候,比如官網(wǎng)中第一個例子:
<script>
mapboxgl.accessToken = 'pk.eyJ1IjoiYW56aGlodW4iLCJhIjoiY2lsdnhjdjN5MDFvMHVia3NpYTlnbmUzaSJ9.twlExCjpR7uwH2IiFC7aDA';
var map = new mapboxgl.Map({
container: 'map', // container id
style: 'mapbox://styles/mapbox/streets-v9', //stylesheet location
center: [-74.50, 40], // starting position
zoom: 9 // starting zoom
});
</script>
代碼里面需要設(shè)置accessToken
,而且mapboxgl.Map
的配置style
設(shè)置的是一個mapbox網(wǎng)站特有的樣式url:mapbox://styles/mapbox/streets-v9
钓账。通常毁渗,我們一看到這樣的情況灌诅,基本就放棄本地化的打算了芳来。但Mapbox GL JS確實太誘人了,我最終也沒有抵御住它的誘惑猜拾,想要本地化來使用即舌。經(jīng)過幾乎一天的努力,終于基本搞定挎袜。
另一種style配置
通過官網(wǎng)Style Reference顽聂,可以看到style除了可以設(shè)置為一個url
之外,還可以配置為一個如下的對象:
{
"version": 8,
"name": "Mapbox Streets",
"sprite": "mapbox://sprites/mapbox/streets-v8",
"glyphs": "mapbox://fonts/mapbox/{fontstack}/{range}.pbf",
"sources": {...},
"layers": [...]
}
從而我們就可以分開配置 sprite
盯仪,glyphs
紊搪,sources
和layers
,這樣或許還有一些希望全景。
自定義source耀石,加載OSM在線瓦片
sprite
和glyphs
看起來比較麻煩,那么我們先解決sources
爸黄,看有沒有可能加載本地瓦片滞伟,或者在線瓦片,反正不要加載mapbox的在線瓦片炕贵。Mapbox GL JS針對Raster Tile提供了一種Source
類型:raster
梆奈。經(jīng)過**聰明伶俐一休桑 **的嘗試和驗證,用下面這種方式:
"sources": {
"osm-tiles": {
"type": "raster",
'tiles': [
"http://c.tile.openstreetmap.org/{z}/{x}/{y}.png"
],
'tileSize': 256
}
}
是可以加載在線的OSM瓦片的鲁驶, 既然這樣可以鉴裹,那么本地瓦片,其他在線瓦片钥弯,或者自己服務(wù)器上的瓦片也是可以加載的。我們不需要修改任何的地方督禽,就能加載第三方的瓦片脆霎,從而實現(xiàn)了第一步。
加載一些feature
瓦片地圖加載后狈惫,我們嘗試往地圖上加載一些矢量的feature睛蛛,如果這一步不能達(dá)到鹦马,自然就沒辦法使用了。Mapbox GL JS提供了geojson
的數(shù)據(jù)源類型忆肾,我們就使用這個:
// 添加數(shù)據(jù)源
map.addSource("points", {
"type": "geojson",
"data": {
"type": "FeatureCollection",
"features": [{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [-77.03238901390978, 38.913188059745586]
},
"properties": {
"title": "Mapbox DC 中國文字",
"icon": "monument"
}
}, {
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [-122.414, 37.776]
},
"properties": {
"title": "Mapbox SF",
"icon": "harbor"
}
}]
}
});
// 添加圖層荸频,使得上面的數(shù)據(jù)源里面的數(shù)據(jù)可視化
map.addLayer({
"id": "points",
"type": "symbol",
"source": "points",
"layout": {
"icon-image": "{icon}-15",
"text-field": "{title}",
"text-font": ["Open Sans Regular"],
"text-offset": [0, 0.6],
"text-anchor": "top"
}
});
上面這段代碼,添加一個geojson
的矢量數(shù)據(jù)源客冈,同時添加一個對應(yīng)的symbol
的圖層旭从。并通過layout
定義要素的樣式。這段代碼出自官網(wǎng)例子Draw GeoJSON points场仲。通過上面的代碼和悦,我們發(fā)現(xiàn)icon-image
和text-font
的設(shè)置,不同于其他的webgis渠缕。一般icon-image
會設(shè)置為一個圖片的url鸽素,或者HTMLImage
對象。text-font
我們也不能隨意設(shè)定亦鳞。添加上這段代碼后馍忽,我們可以在地圖上看到圖標(biāo)和文字,如下:
基本達(dá)到我們的要求燕差。
圖標(biāo)從哪兒來的舵匾?
我們僅僅通過"icon-image": "{icon}-15",
這個設(shè)置,就在地圖上出現(xiàn)了圖標(biāo)谁不, 它們來自于哪里坐梯? 帶著這個疑問,快速打開控制面板看了一下HTTP請求刹帕,發(fā)現(xiàn)圖標(biāo)來源于"sprite": "mapbox://sprites/mapbox/streets-v8",
這個配置吵血。如果去掉這個配置,頁面顯示時偷溺,就會報錯:Error: layers.points.layout.icon-image: use of "icon-image" requires a style "sprite" property
蹋辅。看來要想本地化挫掏,就得解決這個sprite
的問題侦另。
本地化sprite
通過HTTP請求可以發(fā)現(xiàn),sprite的配置尉共,會導(dǎo)致兩個請求褒傅,一個sprite.png
的請求,一個是sprite.json
的請求袄友。sprite.png
請求的結(jié)果如下:
通過上圖殿托,基本可以看出來這是圖標(biāo)的集合,通過把所有的圖標(biāo)放在一起剧蚣,減少了HTTP請求次數(shù)支竹,從而起到優(yōu)化作用旋廷。Mapbox肯定很精通這種方式。既然是集合圖片礼搁,獲取其中的某一個圖片饶碘,自然就需要坐標(biāo)位置,圖片大小等信息馒吴,為此不難猜測sprite.json
里面存儲的是什么信息了:
{"us-highway-alternate-2":{"width":20,"height":38,"x":0,"y":0,"pixelRatio":1},"us-highway-alternate-3":{"width":26,"height":38,"x":0,"y":38,"pixelRatio":1},"us-highway-business-2":{"width":20,"height":38,"x":20,"y":0,"pixelRatio":1},"us-highway-business-3":{"width":26,"height":38,"x":40,"y":0,"pixelRatio":1},"us-highway-bypass-2":{"width":20,"height":38,"x":26,"y":38,"pixelRatio":1},"us-highway-bypass-3":{"width":26,"height":38,"x":46,"y":38,"pixelRatio":1},"us-highway-truck-2":{"width":20,"height":38,"x":0,"y":76,"pixelRatio":1},"us-highway-truck-3":{"width":26,"height":38,"x":20,"y":76,"pixelRatio":1},"gb-national-rail.london-dlr.london-overground.london-tfl-rail.london-underground":{"width":60,"height":34,"x":0,"y":114,"pixelRatio":1},"de-s-bahn-01":{"width":17,"height":32,"x":60,"y":114,"pixelRatio":1},"de-s-bahn.de-u-bahn":{"width":17,"height":32,"x":46,"y":76,"pixelRatio":1},"pe-national-2":{"width":18,"height":26,"x":77,"y":114,"pixelRatio":1},"pe-national-3":{"width":22,"height":26,"x":95,"y":114,"pixelRatio":1}
......
由于圖片比較多扎运,暫且放置一部分內(nèi)容在上面。通過上面的內(nèi)容可以看出募书,基本和我們猜想的一樣绪囱。既然Mapbox GL JS采用這種方式加載圖標(biāo),那么我們準(zhǔn)守這種約定莹捡,在本地提供圖標(biāo)合集和信息鬼吵,基本上也能解決問題。所以我們大膽的嘗試一下修改sprite
為本地路徑: "sprite": "./"
篮赢, 修改之后測試一下齿椅,發(fā)現(xiàn)請求的地址確實變成本地的了:http://127.0.0.1:3209/.json
, http://127.0.0.1:3209/.png
。我們還需要取一個名字启泣,比如這樣設(shè)置涣脚,"sprite": "./sprite"
。在本地準(zhǔn)備好sprite.png和sprite.json這兩個文件就好了寥茫。 Okay遣蚀,這樣圖標(biāo)的問題解決了。 那么還剩下glyphs
的本地化了纱耻。
本地化字體
通過上面排查圖標(biāo)的方式芭梯,我們可以發(fā)現(xiàn)字體也是從Mapbox網(wǎng)站上請求的,每一個漢字都會請求一次弄喘。想必我們也是有辦法在本地搭建一個本地化的服務(wù)器來提供漢字請求服務(wù)的玖喘。同樣的,我們修改為本地的地址試試:"glyphs": "./font/{fontstack}/{range}.pbf",
蘑志。確認(rèn)這次請求的地址是本地累奈,而fontstack
和range
會被具體的字體類型和這個字在字體中所處的實際范圍給替換了。完成了第一步之后急但,我們需要處理的是怎么提供這種字體服務(wù)器澎媒, 由于Mapbox GL JS使用的SDF的方式繪制字體,Mapbox團(tuán)隊也開源了一個工具羊始,將普通的ttf和otf字體轉(zhuǎn)換成Mapbox GL渲染需要的字體的工具:node-fontnik旱幼。轉(zhuǎn)換后的字體就像下面這樣:
這樣我們就可以把他們?nèi)糠旁诒镜亓恕?/p>
最終代碼
最后,我們的代碼也不需要設(shè)置accessToken
了突委,并沒有使用任何Mapbox的地圖樣式和地圖資源服務(wù)柏卤,可以這樣:
var map = new mapboxgl.Map({
container: 'map', // container id
style: {
"version": 8,
// style: 'mapbox://styles/mapbox/basic-v9',
// "sprite": "mapbox://sprites/mapbox/streets-v8",
"sprite": "./sprite",
"glyphs": "./font/{fontstack}/{range}.pbf",
"sources": {
"osm-tiles": {
"type": "raster",
'tiles': [
"http://c.tile.openstreetmap.org/{z}/{x}/{y}.png"
],
'tileSize': 256
}
},
"layers": [{
"id": "simple-tiles",
"type": "raster",
"source": "osm-tiles",
"minzoom": 0,
"maxzoom": 22
}]
},
center: [-96, 37.8],
zoom: 3
});
Okay,完成收工匀油!