如何使用 Mapbox 在 Vue.js 中構建地理編碼應用程序

已發表: 2022-03-10
快速總結↬在本指南中,我們將大致了解正向地理編碼和反向地理編碼的概念。 我們將構建一個應用這些概念來顯示特定位置的小應用程序,使用 Mapbox 和 Vue.js 2.6.11 來實現這一點。

精確定位的準確性和模塊化是使地理編碼成為查找特定位置的完美手段的優勢之一。

在本指南中,我們將使用 Vue.js 和 Mapbox 從頭開始構建一個簡單的地理編碼應用程序。 我們將介紹從構建前端腳手架到構建地理編碼器以處理正向地理編碼和反向地理編碼的過程。 要充分利用本指南,您需要對 JavaScript 和 Vue.js 以及如何進行 API 調用有基本的了解。

什麼是地理編碼?

地理編碼是將基於文本的位置轉換為指示世界位置的地理坐標(通常為經度和緯度)。

地理編碼有兩種類型:正向和反向。 正向地理編碼將位置文本轉換為地理坐標,而反向地理編碼將坐標轉換為位置文本。

換句話說,反向地理編碼將 40.714224、-73.961452 變為“277 Bedford Ave, Brooklyn”,而正向地理編碼則相反,將“277 Bedford Ave, Brooklyn”變為 40.714224、-73.961452。

為了提供更多信息,我們將構建一個迷你 Web 應用程序,該應用程序使用帶有自定義標記的交互式 Web 地圖來顯示位置坐標,隨後我們將其解碼為位置文本。

我們的應用程序將具有以下基本功能:

  • 允許用戶訪問帶有標記的交互式地圖顯示;
  • 允許用戶隨意移動標記,同時顯示坐標;
  • 根據用戶請求返回基於文本的位置或位置坐標。
跳躍後更多! 繼續往下看↓

使用 Vue CLI 設置項目

我們將使用此存儲庫中的樣板。 它包含一個帶有 Vue CLI 和yarn作為包管理器的新項目。 您需要克隆存儲庫。 確保您使用的是geocoder/boilerplate分支。

設置應用程序的文件結構

接下來,我們需要設置項目的文件結構。 將組件文件夾中的Helloworld.vue文件重命名為Index.vue ,暫時留空。 繼續並將以下內容複製到App.vue文件中:

 <template> <div> <!--Navbar Here --> <div> <nav> <div class="header"> <h3>Geocoder</h3> </div> </nav> </div> <!--Index Page Here --> <index /> </div> </template> <script> import index from "./components/index.vue"; export default { name: "App", components: { index, }, }; </script>

在這裡,我們已經導入並在本地註冊了最近重命名的組件。 我們還添加了一個導航欄來提升我們應用的美感。

我們需要一個.env文件來加載環境變量。 繼續在項目文件夾的根目錄中添加一個。

安裝所需的包和庫

要啟動開發過程,我們需要安裝所需的庫。 這是我們將用於此項目的列表:

  1. Mapbox GL JS
    這個 JavaScript 庫使用 WebGL 從矢量切片和 Mapbox 呈現交互式地圖。
  2. Mapbox-gl-地理編碼器
    Mapbox GL 的這個地理編碼器控件將有助於我們的前向地理編碼。
  3. 多騰夫
    我們不必安裝它,因為它預裝了 Vue CLI。 它幫助我們將環境變量從.env文件加載到process.env中。 這樣,我們可以將配置與代碼分開。
  4. 愛訊
    這個庫將幫助我們發出 HTTP 請求。

根據您首選的包管理器在 CLI 中安裝包。 如果您使用的是 Yarn,請運行以下命令:

 cd geocoder && yarn add mapbox-gl @mapbox/mapbox-gl-geocoder axios

如果您使用的是 npm,請運行以下命令:

 cd geocoder && npm i mapbox-gl @mapbox/mapbox-gl-geocoder axios --save

在運行安裝命令之前,我們首先必須進入geocoder文件夾。

使用 Vue.js 搭建前端

讓我們繼續為我們的應用程序創建一個佈局。 我們需要一個元素來容納我們的地圖,一個區域來顯示坐標,同時監聽標記在地圖上的移動,以及在我們調用反向地理編碼 API 時顯示位置的東西。 我們可以將所有這些都包含在一個卡片組件中。

將以下內容複製到您的Index.vue文件中:

 <template> <div class="main"> <div class="flex"> <!-- Map Display here --> <div class="map-holder"> <div></div> </div> <!-- Coordinates Display here --> <div class="dislpay-arena"> <div class="coordinates-header"> <h3>Current Coordinates</h3> <p>Latitude:</p> <p>Longitude:</p> </div> <div class="coordinates-header"> <h3>Current Location</h3> <div class="form-group"> <input type="text" class="location-control" :value="location" readonly /> <button type="button" class="copy-btn">Copy</button> </div> <button type="button" class="location-btn">Get Location</button> </div> </div> </div> </div> </template>

要查看我們目前擁有的內容,請啟動您的開發服務器。 對於紗線:

 yarn serve

或者對於 npm:

 npm run serve

我們的應用程序現在應該是這樣的:

腳手架預覽
地理編碼應用程序腳手架預覽。 (大預覽)

左邊的空白點看起來不對。 它應該容納我們的地圖顯示。 讓我們補充一下。

使用 Mapbox 進行交互式地圖顯示

我們需要做的第一件事是訪問 Mapbox GL 和 Geocoder 庫。 我們將首先在Index.vue文件中導入 Mapbox GL 和 Geocoder 庫。

 import axios from "axios"; import mapboxgl from "mapbox-gl"; import MapboxGeocoder from "@mapbox/mapbox-gl-geocoder"; import "@mapbox/mapbox-gl-geocoder/dist/mapbox-gl-geocoder.css";

Mapbox 需要一個唯一的訪問令牌來計算地圖矢量瓦片。 獲取您的,並將其作為環境變量添加到您的.env文件中。

 .env
 VUE_APP_MAP_ACCESS_TOKEN=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

我們還需要定義有助於將地圖圖塊放在數據實例中的屬性。 在我們導入庫的位置下方添加以下內容:

 export default { data() { return { loading: false, location: "", access_token: process.env.VUE_APP_MAP_ACCESS_TOKEN, center: [0, 0], map: {}, }; }, }
  • location屬性將被建模為我們在腳手架中的輸入。 我們將使用它來處理反向地理編碼(即顯示坐標中的位置)。
  • center屬性包含我們的坐標(經度和緯度)。 正如我們稍後將看到的,這對於將我們的地圖圖塊放在一起至關重要。
  • access_token屬性指的是我們之前添加的環境變量。
  • map屬性充當我們地圖組件的構造函數。

讓我們繼續創建一個方法來繪製我們的交互式地圖,其中嵌入了我們的正向地理編碼器。 這個方法是我們的基礎函數,充當我們的組件和 Mapbox GL 之間的中介; 我們將調用此方法createMap 。 在數據對像下面添加:

 mounted() { this.createMap() }, methods: { async createMap() { try { mapboxgl.accessToken = this.access_token; this.map = new mapboxgl.Map({ container: "map", style: "mapbox://styles/mapbox/streets-v11", center: this.center, zoom: 11, }); } catch (err) { console.log("map error", err); } }, },

為了創建我們的地圖,我們指定了一個容納地圖的container 、一個用於地圖顯示格式的style屬性和一個用於容納坐標的center屬性。 center屬性是一個數組類型,保存經度和緯度。

Mapbox GL JS 根據頁面上的這些參數初始化我們的地圖,並返回一個Map對像給我們。 Map對象引用我們頁面上的地圖,同時公開使我們能夠與地圖交互的方法和屬性。 我們已將此返回的對象存儲在我們的數據實例this.map中。

使用 Mapbox 地理編碼器進行前向地理編碼

現在,我們將添加地理編碼器和自定義標記。 地理編碼器通過將基於文本的位置轉換為坐標來處理正向地理編碼。 這將以附加到我們地圖的搜索輸入框的形式出現。

在我們上面的this.map初始化下面添加以下內容:

 let geocoder = new MapboxGeocoder({ accessToken: this.access_token, mapboxgl: mapboxgl, marker: false, }); this.map.addControl(geocoder); geocoder.on("result", (e) => { const marker = new mapboxgl.Marker({ draggable: true, color: "#D80739", }) .setLngLat(e.result.center) .addTo(this.map); this.center = e.result.center; marker.on("dragend", (e) => { this.center = Object.values(e.target.getLngLat()); }); });

在這裡,我們首先使用MapboxGeocoder構造函數創建了一個新的地理編碼器實例。 這會根據提供的參數初始化地理編碼器,並返回一個對象,暴露給方法和事件。 accessToken屬性指的是我們的 Mapbox 訪問令牌, mapboxgl指的是當前使用的地圖庫。

我們應用的核心是自定義標記; 地理編碼器默認帶有一個。 然而,這並不能為我們提供我們需要的所有定制; 因此,我們禁用了它。

繼續前進,我們將新創建的地理編碼器作為參數傳遞給addControl方法,由我們的地圖對象公開給我們。 addControl接受一個control作為參數。

為了創建我們的自定義標記,我們使用了地理編碼器對象向我們公開的事件。 on事件監聽器使我們能夠訂閱地理編碼器中發生的事件。 它接受各種事件作為參數。 我們正在監聽result事件,該事件在設置輸入時觸發。

簡而言之,在result上,我們的標記構造函數根據我們提供的參數(在本例中為可拖動的屬性和顏色)創建一個標記。 它返回一個對象,我們使用setLngLat方法來獲取我們的坐標。 我們使用addTo方法將自定義標記附加到現有地圖。 最後,我們用新坐標更新實例中的center屬性。

我們還必須跟踪自定義標記的移動。 我們通過使用dragend事件監聽器實現了這一點,並且我們用當前坐標更新了center屬性。

讓我們更新模板以顯示我們的交互式地圖和轉發地理編碼器。 使用以下內容更新我們模板中的坐標顯示部分:

 <div class="coordinates-header"> <h3>Current Coordinates</h3> <p>Latitude: {{ center[0] }}</p> <p>Longitude: {{ center[1] }}</p> </div>

還記得我們如何總是在事件發生後更新我們的center屬性嗎? 我們在這裡根據當前值顯示坐標。

為了提升我們應用的美感,在index.html文件的head部分添加以下 CSS 文件。 將此文件放在公用文件夾中。

 <link href="https://api.tiles.mapbox.com/mapbox-gl-js/v0.53.0/mapbox-gl.css" rel="stylesheet" />

我們的應用程序現在應該是這樣的:

正向地理編碼預覽
轉發地理編碼預覽。 (大預覽)

使用 Mapbox API 反向地理編碼位置

現在,我們將處理反向地理編碼我們的坐標到基於文本的位置。 讓我們編寫一個方法來處理它並使用模板中的Get Location按鈕觸發它。

Mapbox 中的反向地理編碼由反向地理編碼 API 處理。 這接受longitudelatitudeaccess token作為請求參數。 此調用返迴響應負載——通常帶有各種詳細信息。 我們關注的是features數組中的第一個對象,即反向地理編碼位置所在的位置。

我們需要創建一個函數,將我們想要到達的位置的longitudelatitudeaccess_token發送到 Mapbox API。 我們需要發送它們以獲取該位置的詳細信息。

最後,我們需要使用對像中place_name鍵的值更新實例中的location屬性。

createMap()函數下面,讓我們添加一個新函數來處理我們想要的。 它應該是這樣的:

 async getLocation() { try { this.loading = true; const response = await axios.get( `https://api.mapbox.com/geocoding/v5/mapbox.places/${this.center[0]},${this.center[1]}.json?access_token=${this.access_token}` ); this.loading = false; this.location = response.data.features[0].place_name; } catch (err) { this.loading = false; console.log(err); } },

該函數向 Mapbox API 發出GET請求。 響應包含place_name — 所選位置的名稱。 我們從響應中獲取它,然後將其設置為this.location的值。

完成後,我們需要編輯和設置將調用我們創建的這個函數的按鈕。 我們將使用一個click事件監聽器——當用戶點擊它時它會調用getLocation方法。 繼續並將按鈕組件編輯為此。

 <button type="button" :disabled="loading" :class="{ disabled: loading }" class="location-btn" @click="getLocation" > Get Location </button>

作為錦上添花,讓我們附加一個函數來將顯示的位置複製到剪貼板。 在getLocation函數下方添加:

 copyLocation() { if (this.location) { navigator.clipboard.writeText(this.location); alert("Location Copied") } return; },

更新Copy按鈕組件以觸發此操作:

 <button type="button" class="copy-btn" @click="copyLocation">

結論

在本指南中,我們研究了使用 Mapbox 進行地理編碼。 我們構建了一個地理編碼應用程序,它將基於文本的位置轉換為坐標,在交互式地圖上顯示位置,並根據用戶的請求將坐標轉換為基於文本的位置。 本指南只是一個開始。 使用地理編碼 API 可以實現更多功能,例如使用 Mapbox 提供的各種地圖樣式更改地圖的呈現方式。

  • 源代碼可在 GitHub 上獲得。

資源

  • “地理編碼”,Mapbox 文檔
  • “樣式”,Mapbox 文檔
  • “在客戶端代碼中使用環境變量”,在“模式和環境變量”中,Vue CLI