使用 Mapbox 在 Vue 中开发一个地理信息定位应用

Posted 前端修罗场

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用 Mapbox 在 Vue 中开发一个地理信息定位应用相关的知识,希望对你有一定的参考价值。

⭐️ 本文首发自 前端修罗场(点击加入),是一个由 资深开发者 独立运行 的专业技术社区,我专注 Web 技术、Web3、区块链、答疑解惑、面试辅导以及职业发展博主创作的 《前端面试复习笔记》(点击订阅),广受好评,已帮助多人提升实力、拿到 offer。现在订阅,私聊博主即可获取一次 免费的模拟面试/简历指导服务,帮你评估知识点的掌握程度,获得更全面的学习指导意见!

在本文中,我们将大致了解正向地理编码和反向地理编码的概念。 我们将使用 Mapbox 和 Vue.js 2.6.11 构建一个应用这些概念来显示特定位置的应用程序。

什么是地理编码?

地理编码是将基于文本的位置转换为世界位置的地理坐标(通常为经度和纬度)。

地理编码有两种类型:正向和反向。 正向地理编码将位置文本转换为地理坐标,而反向地理编码将坐标转换为位置文本。

我们的应用程序将具有以下基本功能:

  • 允许用户访问带有标记的交互式地图显示;
  • 允许用户随意移动标记,同时显示坐标;
  • 根据用户请求返回基于文本的位置或位置坐标。

使用 Vue CLI 开启项目

我们将使用此存储库中的样板代码进行开发。 它包含一个带有 Vue CLI 和 yarn 作为包管理器的新项目。 你需要克隆该仓库,并确保你使用的是 geocoder/boilerplate 分支。

设置应用程序的文件结构

接下来,我们需要设置项目的文件结构。 将组件文件夹中的 Helloworld.vue 文件重命名为 Index.vue。 并将以下内容复制到 App.vue 文件中:

<template>
  <div id="app">
    <!--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 文件来加载环境变量。 继续在项目文件夹的根目录中添加一个。

安装所需的包和库

接下来,我们需要安装所需的库。 这是我们将用于此项目的列表:

  • Mapbox GL JS
  • Mapbox-gl-geocoder
  • Dotenv
  • Axios

根据你首选的包管理器在 CLI 中安装包。 如果你使用 Yarn,请运行以下命令:

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

or

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

在运行安装命令之前,我们首先必须进入 geocoder 文件夹。

使用 Vue 搭建前端

让我们继续为我们的应用程序创建一个布局。 我们需要一个元素来容纳我们的地图,一个区域来显示坐标,同时监听标记在地图上的移动,以及在我们调用反向地理编码 API 时显示位置的东西。 我们可以将所有这些都包含在一个卡片组件中。

将以下内容复制到你的 Index.vue 文件中:

<template>
  <div class="main">
    <div class="flex">
      <!-- Map Display here -->
      <div class="map-holder">
        <div id="map"></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

or

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 需要一个唯一的访问令牌来计算地图矢量。 获取你的 token,并将其作为环境变量添加到你的 .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);
    
  ,
,

为了创建我们的地图,我们指定了一个容纳地图的容器、一个用于地图显示格式的 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 接受一个控件作为参数。

为了创建我们的自定义标记,我们使用了地理编码器对象向我们公开的事件。 on 事件侦听器使我们能够订阅地理编码器中发生的事件。它接受各种事件作为参数。我们正在监听 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>

还记得我们如何总是在事件发生后更新我们的中心属性吗? 我们在这里根据当前值显示坐标。

为了提升我们应用的美感,在 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 处理。 这接受经度、纬度和访问令牌作为请求参数。 此调用返回响应负载——通常带有各种详细信息。 我们关注的是特征数组中的第一个对象,即反向地理编码位置所在的位置。

我们需要创建一个函数,将我们想要到达的位置的经度、纬度和 access_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 的值。

完成后,我们需要编辑和设置将调用我们创建的这个函数的按钮。 我们将使用一个点击事件监听器——当用户点击它时它会调用 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 进行地理编码。 我们构建了一个地理编码应用程序,它将基于文本的位置转换为坐标,在交互式地图上显示位置,并根据用户的请求将坐标转换为基于文本的位置。

以上是关于使用 Mapbox 在 Vue 中开发一个地理信息定位应用的主要内容,如果未能解决你的问题,请参考以下文章

vue项目中使用mapbox地图,切换底图

如何在 Vuex 中为 mapbox 地图设置集中状态?

vue中使用mapboxgl 加载天地图初始化并打点marker以及逆地理编码

五分钟学GIS _ 快速认识 MapBox GL

django+vue无法设置跨域cookies

Vue.js 单文件组件中的 Mapbox-gl (Quasar-Framework)