Mapbox本地離線部署

一 離線部署說(shuō)明

從官網(wǎng)抄一個(gè)HelloWorld的例子,完整代碼如下:

<!DOCTYPE html>
<html>
<head>
    <meta charset='utf-8' />
    <title>Display a map</title>
    <meta name='viewport' content='initial-scale=1,maximum-scale=1,user-scalable=no' />
    <script src='https://api.tiles.mapbox.com/mapbox-gl-js/v0.54.0/mapbox-gl.js'></script>
    <link  rel='stylesheet' />
    <style>
        body { margin:0; padding:0; }
        #map { position:absolute; top:0; bottom:0; width:100%; }
    </style>
</head>
<body>

<div id='map'></div>
<script>
mapboxgl.accessToken = 'pk.eyJ1IjoiYW56aGlodW4iLCJhIjoiY2lsdnhjdjN5MDFvMHVia3NpYTlnbmUzaSJ9.twlExCjpR7uwH2IiFC7aDA';
var map = new mapboxgl.Map({
    container: 'map', // container id
    style: 'mapbox://styles/mapbox/streets-v11', // stylesheet location
    center: [-74.50, 40], // starting position [lng, lat]
    zoom: 9 // starting zoom
});
</script>
</body>
</html>
Mapbox HelloWorld

從該例子看,平常的js庫(kù)只需要將js,css存放本地就可以離線使用了,但是mapbox比較特殊:

  • 聲明了一個(gè)accessToken,通過(guò)這個(gè)accessToken 才能訪問(wèn)mapbox在線的地圖,樣式等。
  • mapbox的map構(gòu)造,直接一個(gè)style,定制了整個(gè)地圖的樣式。本地離線部署,必須要知道這個(gè)style的定義才行。

查詢官網(wǎng)Style Specification資料,style除了這個(gè)url聲明之外,還可以通過(guò)以下方式定義:

{
    "version": 8,
    "name": "Mapbox Streets",
    "sprite": "mapbox://sprites/mapbox/streets-v8",
    "glyphs": "mapbox://fonts/mapbox/{fontstack}/{range}.pbf",
    "sources": {...},
    "layers": [...]
}

參數(shù)說(shuō)明如下:

  • version:樣式版本,當(dāng)前必須必須設(shè)置8。
  • name:樣式名稱,設(shè)置一個(gè)可讀的名稱描述即可。
  • sprite:mapbox地圖使用的圖標(biāo)。
  • glyphs:mapbox地圖使用的標(biāo)注字體。
  • sources: mapbox地圖使用的地圖服務(wù)資源定義。
  • layers: mapbox地圖使用的圖層定義。

明顯的,當(dāng)我們嘗試將mapbox離線本地化時(shí),應(yīng)當(dāng)解決如下內(nèi)容:

  • mapbox-gl.js,mapbox-gl.css存儲(chǔ)本地服務(wù)器
  • layers,sources 圖層本地化
  • sprite 圖標(biāo)本地化
  • glyphs 字體本地化

二 圖層本地化

先保持HelloWorld的所有內(nèi)容不變,嘗試自定義一個(gè)xyz的osm底圖,替換原底圖即可。

 "sources": {
     "osm-tiles": {
         "type": "raster",
         "tiles": [
                 "http://c.tile.openstreetmap.org/{z}/{x}/{y}.png"
          ],
          "tileSize": 256
       }
  },
  "layers":[{
      "id": "123",
       "type": "raster",
       "source": "osm-tiles",
       "source-layer": "osmtiles"
  }]

sources參數(shù)說(shuō)明:

  • sources是地圖資源對(duì)象,以key,value組成,sources里的key不能重復(fù),唯一聲明一個(gè)地圖資源的組成。
  • value里的type是資源的類(lèi)型,必須是 vector, raster, raster-dem, geojson, image, video中的一種。當(dāng)前聲明是xyz的png圖片組成的底圖,所以聲明類(lèi)型是raster。
  • value里的tiles是xyz底圖的url模板組合,tileSize聲明一個(gè)切片寬高,一般切片都是是256*256的,所以此處聲明256 。

layers參數(shù)說(shuō)明:

  • layers是個(gè)數(shù)組,數(shù)組每一項(xiàng)代表一個(gè)圖層。
  • id是每個(gè)圖層的主鍵,每個(gè)圖層的id必須不能重復(fù)。
  • type,聲明一個(gè)圖層的類(lèi)型。
  • source,圖層的地圖數(shù)據(jù)來(lái)源,指向sources里的某個(gè)key的資源定義,比如sources里定義了一個(gè)osm-tiles的資源,該圖層數(shù)據(jù)來(lái)源指向這個(gè)資源,即將key的值輸入此處。
  • source-layer:圖層的名稱,可以當(dāng)做是圖層別名,用以描述圖層的。

完整的代碼和效果如下:

<!DOCTYPE html>
<html>
<head>
    <meta charset='utf-8' />
    <title>Display a map</title>
    <meta name='viewport' content='initial-scale=1,maximum-scale=1,user-scalable=no' />
    <script src='https://api.tiles.mapbox.com/mapbox-gl-js/v0.54.0/mapbox-gl.js'></script>
    <link  rel='stylesheet' />
    <style>
        body { margin:0; padding:0; }
        #map { position:absolute; top:0; bottom:0; width:100%; }
    </style>
</head>
<body>

<div id='map'></div>
<script>
mapboxgl.accessToken = 'pk.eyJ1IjoiYW56aGlodW4iLCJhIjoiY2lsdnhjdjN5MDFvMHVia3NpYTlnbmUzaSJ9.twlExCjpR7uwH2IiFC7aDA';
var map = new mapboxgl.Map({
    container: 'map', // container id
    style:{
        "version": 8,
        "name": "Mapbox Streets",
        "sprite": "mapbox://sprites/mapbox/streets-v8",
        "glyphs": "mapbox://fonts/mapbox/{fontstack}/{range}.pbf",
         "sources": {
             "osm-tiles": {
                 "type": "raster",
                 "tiles": [
                   "http://c.tile.openstreetmap.org/{z}/{x}/{y}.png"
                  ],
                 "tileSize": 256
             }
        },
      "layers":[{
          "id": "123",
           "type": "raster",
           "source": "osm-tiles",
           "source-layer": "osmtiles"
      }]
    },
    center: [-74.50, 40], // starting position [lng, lat]
    zoom: 9 // starting zoom
});
</script>
</body>
</html>
圖層本地化效果

實(shí)際使用時(shí),使用mapbox加載wms,wmts,xyz這種柵格或者矢量切片等地圖圖層等。加載自己的地圖服務(wù)這個(gè)初級(jí)目標(biāo)達(dá)成。

三 圖標(biāo)本地化

3.1 圖標(biāo)離線使用

mapbox明顯是偏向于互聯(lián)網(wǎng)應(yīng)用的地圖庫(kù),它使用sprite這種將所有圖標(biāo)放一起的方式,減少小圖片資源請(qǐng)求次數(shù),在高并發(fā)的應(yīng)用情況下,起到優(yōu)化應(yīng)用的目的,比如高德,百度地圖都是使用sprite形式組合的地圖圖標(biāo),我們先尊重這樣的設(shè)計(jì)。
上個(gè)例子中,圖標(biāo)定義形式是:"sprite": "mapbox://sprites/mapbox/streets-v8",初次接觸一臉懵逼,不知道這個(gè)是啥意思,簡(jiǎn)單點(diǎn),我們f12打開(kāi)networ查看如圖:

sprites請(qǐng)求

瀏覽器根據(jù)我們的定義,實(shí)際發(fā)送了兩個(gè)url請(qǐng)求,一個(gè)png圖片,一個(gè)json位置描述信息。暫時(shí)將這兩個(gè)文件存儲(chǔ)本地服務(wù)器:
sprites本地存儲(chǔ)

然后僅僅將之前的代碼,僅僅更改url為本地服務(wù)器的url即可:

 "sprite": "http://localhost:8080/mapbox_build/sprite/sprite",

這樣,sprite圖標(biāo)的問(wèn)題就解決了。

3.2 圖標(biāo)生成工具

mapbox提供了一個(gè)spritezero工具,用于自定義生成mapbox的sprite。spritezero工具用于將一個(gè)文件夾的svg矢量圖片,轉(zhuǎn)換成一個(gè)sprite的png圖片和一個(gè)json文件。
本文簡(jiǎn)單介紹下,方便以后創(chuàng)建自己地圖的sprite。
環(huán)境約束
操作系統(tǒng):centos 7.2,win下基本裝不上。
node:node6.3.0,其他高版本親測(cè)很多難以裝上。

3.2.1 安裝node6.3.0

[root@localhost ~]# cd /usr/local
[root@localhost local]# wget http://nodejs.org/dist/v6.3.0/node-v6.3.0.tar.gz
[root@localhost local]# tar -zxvf node-v6.3.0.tar.gz
[root@localhost local]# vi /etc/profile
#編輯內(nèi)容如下:
export NODE_HOME=/usr/local/node-v6.3.0
export PATH=$NODE_HOME/bin:$PATH
#保存退出

#啟用profile生效
[root@localhost local]# source /etc/profile

#查看node,npm版本
[root@localhost local]# node -v
v6.3.0
[root@localhost local]# npm -v
3.10.3

#linux下root執(zhí)行權(quán)限,重要,一定要操作
[root@localhost local]# chown -R root.root ./node-v6.3.0

3.2.2 安裝spritezero,spritezero-cli

npm install -g @mapbox/spritezero
npm install -g @mapbox/spritezero-cli --unsafe-perm

3.2.3 sprite創(chuàng)建

icons輸入資源

將icons下的svg圖標(biāo)轉(zhuǎn)成sprite:

[root@localhost test]# spritezero sprite ./icons
輸出結(jié)果

神奇的生成了一個(gè)叫sprite.png和sprite.json文件。

四 字體本地化

mapbox中使用的字體,也是pbf格式而不是tff格式,需要使用工具轉(zhuǎn)換,查詢資料發(fā)現(xiàn),genfontgl這個(gè)node庫(kù)可以執(zhí)行將tff文件轉(zhuǎn)成mapbox可用的pbf字體。

4.1 全局安裝genfontgl

[root@localhost local]# npm i genfontgl -g

4.2 字體轉(zhuǎn)換

用法:genfontgl OpenSans-Regular.ttf [output location]
示例:將OpenSans-Regular.ttf轉(zhuǎn)換成pbf存到當(dāng)前目錄。

[root@localhost test]# genfontgl OpenSans-Regular.ttf ./
Process OpenSans-Regular.ttf

轉(zhuǎn)換效果:


字體轉(zhuǎn)換結(jié)果文件.png

4.3 字體應(yīng)用

本地字體

將轉(zhuǎn)換完成的字體,存放到本地服務(wù)器,修改glyphs參數(shù)即可:

 "glyphs": "http://localhost:8080/mapbox_build/fonts/{fontstack}/{range}.pbf",

疑問(wèn):fontstack,range這個(gè)參數(shù)占位是干嘛的?實(shí)際上,fontstack和range會(huì)被具體的字體類(lèi)型和這個(gè)字在字體中所處的實(shí)際范圍給替換了,我們先用一個(gè)矢量圖層的樣式來(lái)說(shuō)明:

map.on('load', function () {
    map.addLayer({
        "id": "points",
        "type": "symbol",
        "source": {
            "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"
                    }
                }]
            }
        },
        "layout": {
            "icon-image": "{icon}-15",--矢量數(shù)據(jù)中properties的icon注入
            "text-field": "{title}",--矢量數(shù)據(jù)的properties中tile注入
            "text-font": ["Open Sans Regular"],  --字體,fontstack占位符就是對(duì)應(yīng)這個(gè)聲明。
            "text-offset": [0, 0.6],
            "text-anchor": "top"
        }
    });
});

mapbox大量使用注入的形式,比如文字標(biāo)注綁定了矢量數(shù)據(jù)的title字段,圖標(biāo)綁定了icon字段,字體用我們轉(zhuǎn)換后的本地字體。
完整代碼如下:

<!DOCTYPE html>
<html>
<head>
    <meta charset='utf-8' />
    <title>Display a map</title>
    <meta name='viewport' content='initial-scale=1,maximum-scale=1,user-scalable=no' />
    <script src='https://api.tiles.mapbox.com/mapbox-gl-js/v0.54.0/mapbox-gl.js'></script>
    <link  rel='stylesheet' />
    <style>
        body { margin:0; padding:0; }
        #map { position:absolute; top:0; bottom:0; width:100%; }
    </style>
</head>
<body>

<div id='map'></div>
<script>
mapboxgl.accessToken = 'pk.eyJ1IjoiYW56aGlodW4iLCJhIjoiY2lsdnhjdjN5MDFvMHVia3NpYTlnbmUzaSJ9.twlExCjpR7uwH2IiFC7aDA';
var map = new mapboxgl.Map({
    container: 'map', // container id
    style:{
        "version": 8,
        "name": "Mapbox Streets",
        "sprite": "http://localhost:8080/mapbox_build/sprite/sprite",
        "glyphs": "http://localhost:8080/mapbox_build/fonts/{fontstack}/{range}.pbf",
         "sources": {
             "osm-tiles": {
                 "type": "raster",
                 "tiles": [
                   "http://c.tile.openstreetmap.org/{z}/{x}/{y}.png"
                  ],
                 "tileSize": 256
             }
        },
      "layers":[{
          "id": "123",
           "type": "raster",
           "source": "osm-tiles",
           "source-layer": "osmtiles"
      }]
    },
    center: [-74.50, 40], // starting position [lng, lat]
    zoom: 9 // starting zoom
});




map.on('load', function () {
    map.addLayer({
        "id": "points",
        "type": "symbol",
        "source": {
            "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"
                    }
                }]
            }
        },
        "layout": {
            "icon-image": "{icon}-15",
            "text-field": "{title}",
            "text-font": ["Open Sans Regular"],
            "text-offset": [0, 0.6],
            "text-anchor": "top"
        }
    });
});
</script>
</body>
</html>
標(biāo)注與圖標(biāo)

4.4 可能遇到的問(wèn)題

4.4.1 npm install EACCES: permission denied

原因是npm的存儲(chǔ)目錄沒(méi)有操作權(quán)限,解決方法:

[root@localhost local]# chown -R root.root /usr/local/node-v6.3.0

4.4.2 genfontgl命令,ibstdc++.so.6: version `GLIBCXX_3.4.20' not found

版本問(wèn)題,具體操作參考《關(guān)于libstdc++.so.6: version `GLIBCXX_3.4.20' not found問(wèn)題解決》

五 最終部署

我們已經(jīng)逐漸將字體,圖標(biāo),圖層,資源都采用本地的服務(wù),但上面例子還是公網(wǎng)的mapbox-gl和accessToken,其實(shí)當(dāng)資源都是使用本地的,accessToken 就沒(méi)用了,我們只用把js,css也放到本地就可以了,完整代碼如下:

<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>hello world</title>
    <meta charset="utf-8" />
    <script src='./plugin/mapbox-gl.js'></script>
    <link href='./plugin/mapbox-gl.css' rel='stylesheet' />
    <style>
        body { margin:0; padding:0; }
        #map { position:absolute; top:0; bottom:0; width:100%; }
    </style>
</head>
<body>
     <div id='map'></div>
     <script>
        //mapboxgl.accessToken = 'pk.eyJ1IjoiZnJlZWdpcyIsImEiOiJjam04dXRudWwwNXczM3Fqb3dkd201dGZzIn0.jvDsB3YWibUpk1oR9vva1A';
        var map = new mapboxgl.Map({
            container: 'map',
            style: {
                 "version": 8,
                 "name": "Mapbox Streets",
                 "sprite": "http://localhost:8080/mapbox_build/sprite/sprite",
                 "glyphs": "http://localhost:8080/mapbox_build/fonts/{fontstack}/{range}.pbf",
                 "sources": {
                    "osm-tiles": {
                        "type": "raster",
                        'tiles': [
                            "http://c.tile.openstreetmap.org/{z}/{x}/{y}.png"
                        ],
                        'tileSize': 256
                    }
                  },
                  "layers":[{
                         "id": "123",
                         "type": "raster",
                         "source": "osm-tiles",
                         "source-layer": "osmtiles"
                  }]
            },
            center: [-96, 37.8],
            zoom: 3
        });




map.on('load', function () {
    map.addLayer({
        "id": "points",
        "type": "symbol",
        "source": {
            "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"
                    }
                }]
            }
        },
        "layout": {
            "icon-image": "{icon}-15",
            "text-field": "{title}",
            "text-font": ["Open Sans Regular"],
            "text-offset": [0, 0.6],
            "text-anchor": "top"
        }
    });
});
     </script>
</body>
</html>

所有的資源都是本地了,可以做離線應(yīng)用了。本地使用的話,mapbox的很多在線服務(wù)我們是使用不了了的,都要自己離線開(kāi)發(fā)定制自己的服務(wù)。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容