視覺化大屏:mapbox+vue全攻略

2023-04-24 18:01:28

如題圖,mapbox是一個支援真3D地形展示的webGIS框架,與常用的Leaflet、Cesium和Openlayers並稱四大框架,本文將介紹mapbox-gl js 在 vue 中的用法。

為什麼要用 mapbox ?

各位可以自行搜尋上面提到的或者其他的webGIS框架或者整合服務商,可以很輕鬆的比較出mapbox的優勢:

  • 支援3D地形、3D模型
  • 支援多種座標系投影
  • mapbox studio 線上編輯地圖樣式,使用時只需一個連結,更新時連結也無需修改(無可替代)
  • 漂亮(誰能反駁?)
  • 簡單易上手(對比Cesium、Openlayers)
  • 地理資料全格式支援(Image、KML、WMS、 WMTS、 GeoJson)
  • 功能齊全,mapbox再也不是那個花瓶了,它現在是一個強大的、完整的大型框架

註冊mapbox賬號

mapbox禁止中國地區的新使用者註冊,需要開啟全域性的魔法,進入 mapbox官網註冊

如果要求輸入 海外銀行卡號,參閱:知乎:mapbox的註冊怎麼需要填卡號,有銀行要求嗎,之前看網上說不需要填,具體要怎麼操作,求大神指點。?

完成註冊後會看到如下畫面

左上紅框可以線上建立、編輯地圖樣式。下方紅框是公鑰,可以用來存取你建立的公開地圖。

建立你的個性化地圖

你可以自行探索各個圖層分別是什麼,我這裡只新增了一個衛星圖,圖層越多,載入的時候就越慢,用起來就越卡。

點選左上角3D按鈕,即可開啟3D檢視,mapbox會根據全球等高線資訊模擬出地形

上圖為山東省泰安市。此外還支援:

  • 自定義光源
  • 自定義座標系
  • 自定義地形誇張
  • 霧氣(視野可見範圍,適當設定有助於效能優化)

在VUE專案中使用mapBox

本文使用vue3,選配如下:

  • router
  • vuex
  • less
  1. 安裝,通過NPM安裝

    1. npm i mapbox-gl
      
  2. 引入

    1. import mapboxgl from 'mapbox-gl';
      import 'mapbox-gl/dist/mapbox-gl.css';
      import MapboxLanguage from '@mapbox/mapbox-gl-language'; //可以將標籤改為中文
      
  3. 初始化

    1. mapboxgl.accessToken='pk.eyJ1IjoiemJiZW4iLCJhIjoiACtpemtnOXRoMDRhcDMwbG43aGYxbXhqYyJ9.YOJzSXzubABBJeK7SXg60w'; //這是一個無效的公鑰,上面提到了公鑰在哪裡可以獲取到
      this.map = new mapboxgl.Map({
              container: "basicMapbox",
              style: 'mapbox://styles/xxx/ckus1uok22m4117aif4pg9qa6', //這是個假連結,在上面有提到分享按鈕,那裡有你自己的連結
              center: [118, 28],
              zoom: 3, //zoom你都不懂就別看了
              pitch: 0, // 相對於地面3D視角的角度
              bearing: 0, // 東西南北 方向,正北方為 0
              projection: 'globe', // 為 3D 地球
              antialias: false, //抗鋸齒,通過false關閉提升效能
              essential: true, //不知道什麼意思,我看人家寫我就寫了
              renderWorldCopies: false, //可理解為loop,在projection: 'globe'時無效
              skipOnboarding: true,//可選擇不等待瓦片載入
            });
      // ### 標籤漢化
      // this.map.addControl(new MapboxLanguage({ defaultLanguage: 'zh-Hans' }));
      // ### 新增導航控制條
      // this.map.addControl(new mapboxgl.NavigationControl(), 'top-left');
      
  4. 監聽事件

    1. this.map.on("eventName",()=>{})
      // 常用事件有:load、moveend、render等,自行探索
      
  5. 常用方法

    1. this.map.setFog({}); //開啟宇宙、星空
      this.map.flyTo({
           center: [109.926476, 19.088415], //目標中心點 海南省瓊中縣灣嶺鎮
           zoom: 11, //目標縮放級別
           bearing: 56.50, //目標方位角
           pitch: 47.50, //目標傾斜角
      },duration: 7000,) //飛行
      let shape = await request.get("some_geoJosn")
      this.map.addSource('customSourceName'{
          type:"geojson" //可選: raster || image || 等
          // 每個型別所需的引數不一樣,自行探索,這裡用geojson舉例。
          "data": shape
      }) //新增資源
      this.map.getSource('customSourceName') && this.map.removeSource('customSourceName') //獲取資源、刪除資源
      this.map.addLayer({
              id: 'measure-lines',
              type: 'line',
              source: 'customSourceName', //使用剛剛新增的資源
              layout: {
                'line-cap': 'round',
                'line-join': 'round'
              },
              paint: {
                'line-color': '#00FFF4',
                'line-width': 2.5,
                'line-opacity': 1,
                'line-gap-width': 0,
              },
      }); // 新增圖層,如上使用 名為 customSourceName 的資源 新增了一個用線勾勒輪廓的圖層。
      this.map.getLayer('measure-lines') && this.map.removeLayer('measure-lines') // 獲取圖層、刪除圖層
      
    2. 插點,以下是一個插點的簡單範例,可以用vue元件渲染插點的響應彈窗:

      import mapboxPopView from '../mapboxPopView/mapboxPopView.vue'; //彈窗元件需提前引入
        
      async setMaker(makerList) {
            if (!makerList) {
              return
            }
            // console.log('makerList::: ', makerList);
            for (let item of makerList) {
              let dom = document.createElement('img')
              dom.src = require(`../../../public/static/img/${item.deviceType}.png`) //這裡使用了自定義圖片來替換預設插點圖示
              dom.style.width = '52.4px'
              dom.style.height = 'auto' //可以保持比例
              dom.id = `marker-${item.deviceId}`
              dom.classList.add("markerCustom")
              dom.addEventListener("click", () => {
                this.setPopContent(item)
              })
              let marker = new mapboxgl.Marker({
                element: dom,
                offset: [0, -50], //圖示偏移量
              }).setLngLat([item.lon, item.lat]).addTo(this.map);
              // 新增標記的彈窗事件
              var popup = new mapboxgl.Popup({
                offset: [0, -100], //彈窗偏移量
              }).setHTML(`<div id="popup-content-${item.deviceId}"></div>`)
              // this.setPopContent(item)
              marker.setPopup(popup);
              this.markerList.push(marker)
              // 點選標記時顯示彈窗
            }
            this.$store.dispatch('addLayer')
          },
         setPopContent(item) {
            const MyNewPopup = defineComponent({
              extends: mapboxPopView,
              setup() {
                const deviceItem = item
                return { deviceItem } //這裡的常數可以直接在元件的this物件中獲取
              },
            })
            setTimeout(() => {
              createApp(MyNewPopup).mount(`#popup-content-${item.deviceId}`) //掛載到剛剛定義的擁有唯一ID的DOM節點上
            }, 10);
          },
      

      插點效果如圖:

至此,mapbox的基本功能介紹完畢,另外,mapbox支援自定義圖源,下面是一個使用天地圖瓦片的例子:

setTiandituLaryer() {
      this.map.addSource('tianditu', {
        type: 'raster',
        tiles: [
          '你的天地圖連結',
        ],
        tileSize: 256,
      });
      this.map.addLayer({
        id: 'tianditu',
        type: 'raster',
        source: 'tianditu',
      });
},

如果使用其他的圖源,記得在mapbox studio裡關閉或刪除無用的圖層。

碼雲:mapbox_demo

旗鼓相當的對手,就是我們磨礪爪子的堅石。