如何使用 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