How to use MapboxGL in Vue more elegantly
Tags: vue, gis, javascript, typescript
Published: 2022-08-26 04:00:00

Vue provides a declarative and component-based programming model that helps you efficiently develop user interfaces, be it simple or complex.

To more elegantly in using mapbox-gl, there is a package named [`MapVue`](https://github.com/timeroute/mapvue).

MapVue is a comprehensive MapboxGL component library. You can easily and happily apply MapVue to your Vue projects. Import various data sources and layers in the form of components, and update props of layers and sources in map by MVVM.

### How it works?

MapVue essentially wraps some classes in MapboxGL and implements componentization through some variable properties of the watch class.

For example, the `v-fill-layer` component actually wraps the `FillLayer` class.

There are [`25 components`](https://mapvue.netlify.app/components/#common-components) im MapVue, almost contains all of the mapbox-gl APIS.

The core component is `VMap` component. It is the top-level component, all other components must be wrapped in `VMap`, it instantiates a `mapboxgl.Map` and provides the `map` instance to child components.

### Components lists

- Core Components
 - VMap
- Common Components
 - VMarker: wrap `mapboxgl.Marker`
 - VPopup: wrap `mapboxgl.Popup`
 - VSprit: add an image to the style
 - VFog: wrap `map.setFog`
 - VFeatureState: set the state of a feature
- Control Components
 - VAttributionControl: wrap `AttributionControl` control
 - VNavigationControl: wrap `NavigationControl` control
 - VScaleControl: wrap `ScaleControl` control
- Layer Components
 - VBackgroundLayer: wrap `background` layer
 - VCircleLayer: wrap `circle` layer
 - VFillExtrusionLayer: wrap `fillextrusion` layer
 - VFillLayer: wrap `fill` layer
 - VHeatmapLayer: wrap `heatmap` layer
 - VHillshadeLayer: wrap `hillshade` layer
 - VLineLayer: wrap `line` layer
 - VRasterLayer: wrap `raster` layer
 - VSymbolLayer: wrap `symbol` layer
 - VCanvasLayer: wrap `canvas` layer
- Source Components
 - VGeoSource: wrap `geojson` source
 - VVectorSource: wrap `vector` source
 - VImageSource: wrap `image` source
 - VVideoSource: wrap `video` source
 - VRasterSource: wrap `raster` source
 - VRasterDemSource: wrap `rasterdem` source

### Install

```shell
# use yarn
yarn add mapvue
```

```shell
# use pnpm
pnpm add mapvue
```

### Import

Vite

```
import { createApp } from "vue";
import MapVue from "mapvue";
import "mapvue/dist/mapvue.css";
import App from "./App.vue";

createApp(App).use(MapVue).mount("#app");
```

### Use case

```
<script>
import { defineComponent, reactive, watch } from "vue";
import { accessToken } from "../store";

export default defineComponent({
  setup() {
    const state = reactive({
      "heatmap-color": [
        "interpolate",
        ["linear"],
        ["heatmap-density"],
        0,
        "rgba(33,102,172,0)",
        0.2,
        "rgb(103,169,207)",
        0.4,
        "rgb(209,229,240)",
        0.6,
        "rgb(253,219,199)",
        0.8,
        "rgb(239,138,98)",
        1,
        "rgb(178,24,43)",
      ],
      "heatmap-opacity": ["interpolate", ["linear"], ["zoom"], 7, 1, 9, 0],
      "heatmap-radius": ["interpolate", ["linear"], ["zoom"], 0, 2, 9, 20],
      "heatmap-intensity": ["interpolate", ["linear"], ["zoom"], 0, 1, 9, 3],
      radius: 20,
      intensity: 3,
      layout: {
        visibility: "visible",
      },
    });

    return {
      state,
      accessToken,
    };
  },
});
</script>

<template>
  <div class="container">
    <v-map
      :accessToken="accessToken"
      :options="{
        center: [-124.137343, 45.137451],
        zoom: 3,
      }"
    >
      <v-geo-source
        id="geo"
        data="https://docs.mapbox.com/mapbox-gl-js/assets/earthquakes.geojson"
      />
      <v-heatmap-layer
        id="heatmap"
        source="geo"
        :paint="{
          'heatmap-color': state['heatmap-color'],
          'heatmap-opacity': state['heatmap-opacity'],
          'heatmap-radius': state['heatmap-radius'],
          'heatmap-intensity': state['heatmap-intensity'],
        }"
        :layout="state.layout"
      />
    </v-map>
  </div>
</template>

<style scoped>
.container {
  height: 100vh;
  width: 100%;
}
</style>

```

![render heatmap](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xcgi8wrw5ib7ig1keh6q.png)

more examples please visiting [examples](https://codesandbox.io/s/vmap-examples-mnqjgn)

github: [MapVue](https://github.com/timeroute/mapvue)
docs: [MapVue doc](https://mapvue.netlify.app/)