Vue.js v3でLeafletの開発環境を構築してみた

![sample201123_01.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/60444/d117039e-85a9-7ac1-0831-7ad29518d9b7.gif)

<br>

![try-049_00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/60444/a8c6aa15-81c2-918d-d9c3-b7121c726be1.png)

<br>

この記事は、「[Vue Advent Calendar 2020](https://qiita.com/advent-calendar/2020/vue)」の5日目の記事です。

### Vue.js v3でLeafletの開発環境を構築してみました :tada:  

Vue.js v3でLeafletを利用されているかたはまだ少ないと思うので、Vue.js v3向けのラッパーライブラリを利用して開発環境を構築してみました！  

Mapbox GL JSとOpenLayersについては、2020年12月現在Vue 3に対応したラッパーライブラリはまだ公開されていないようです...

<br>

事前準備

- Vue.jsの環境準備  
    - [Vue.js #005 – Vue CLI 4でVue 3環境構築](https://memo.dayjournal.dev/memo/vue-js-005)
    - node v15.2.0
    - npm v7.0.8
    - Vue.js v3.0.0

![try-049_02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/60444/c7acd5c4-aee8-b5df-11e5-b996bef484f3.png)

<br>

### Vue.js v3 x Leaflet

Vue.js v3とLeafletの組み合わせの場合は、「[vue-leaflet](https://github.com/vue-leaflet/vue-leaflet)」を利用します。

<br>

はじめに、各ライブラリをインストールします。今回は「Vue CLI UI」を利用しleaflet、@types/leaflet、@vue-leaflet/vue-leafletを検索しインストールします。

![try-049_03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/60444/21411fb6-bdae-642e-d1c7-9f53898911a0.png)

<br>

次に、ひな形に地図を表示させるためのコードを追記していきます。  

全体構成

![try-049_04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/60444/de6ecab6-6741-ab79-169d-74d9c1ca3394.png)

<br>

#### package.json

```json
{
  "name": "vue3_prj",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "serve": "vue-cli-service serve",
    "build": "vue-cli-service build",
    "lint": "vue-cli-service lint"
  },
  "dependencies": {
    "@types/leaflet": "^1.5.19",
    "@vue-leaflet/vue-leaflet": "^0.4.2",
    "core-js": "^3.6.5",
    "leaflet": "^1.7.1",
    "vue": "^3.0.0",
    "vue-class-component": "^8.0.0-0",
    "vue-router": "^4.0.0-0",
    "vuex": "^4.0.0-0"
  },
  "devDependencies": {
    "@typescript-eslint/eslint-plugin": "^2.33.0",
    "@typescript-eslint/parser": "^2.33.0",
    "@vue/cli-plugin-babel": "~4.5.0",
    "@vue/cli-plugin-eslint": "~4.5.0",
    "@vue/cli-plugin-router": "~4.5.0",
    "@vue/cli-plugin-typescript": "~4.5.0",
    "@vue/cli-plugin-vuex": "~4.5.0",
    "@vue/cli-service": "~4.5.0",
    "@vue/compiler-sfc": "^3.0.0",
    "@vue/eslint-config-typescript": "^5.0.2",
    "eslint": "^6.7.2",
    "eslint-plugin-vue": "^7.0.0-0",
    "typescript": "~3.9.3"
  },
  "eslintConfig": {
    "root": true,
    "env": {
      "node": true
    },
    "extends": [
      "plugin:vue/vue3-essential",
      "eslint:recommended",
      "@vue/typescript/recommended"
    ],
    "parserOptions": {
      "ecmaVersion": 2020
    },
    "rules": {}
  },
  "browserslist": [
    "> 1%",
    "last 2 versions",
    "not dead"
  ]
}
```

<br>

/src

#### main.ts

```typescript
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
// Leafletのスタイル読み込み
import 'leaflet/dist/leaflet.css'

createApp(App).use(store).use(router).mount('#app')
```

main.tsでleaflet.cssを読み込みます。

```javascript
// Leafletのスタイル読み込み
import 'leaflet/dist/leaflet.css'
```

<br>

/src/views

#### Home.vue

```vue
<template>
  <div class="home">
    <img alt="Vue logo" src="../assets/logo.png">
    <HelloWorld msg="Welcome to Your Vue.js + TypeScript App"/>
    <MapPane></MapPane>
  </div>
</template>

<script lang="ts">
import { Options, Vue } from 'vue-class-component';
import HelloWorld from '@/components/HelloWorld.vue';
// マップコンポーネント読み込み
import MapPane from '@/components/MapPane.vue';

@Options({
  components: {
    HelloWorld,
    MapPane
  },
})
export default class Home extends Vue {}
</script>
```

Home.vueでMapPaneコンポーネントを読み込みます。

```html
<MapPane></MapPane>
```

```javascript
// マップコンポーネント読み込み
import MapPane from '@/components/MapPane.vue'

components: {
    MapPane
}
```

<br>

/src/components

#### MapPane.vue

```vue
<template>
    <div class="mapPane">
        <!--マップ-->
        <l-map
            :zoom="zoom"
            :center="center"
        >
            <!--レイヤーコントロール-->
            <l-control-layers
                position="topright"
            ></l-control-layers>
            <!--レイヤ設定-->
            <l-tile-layer
                v-for="tileProvider in tileProviders"
                :key="tileProvider.name"
                :name="tileProvider.name"
                :visible="tileProvider.visible"
                :url="tileProvider.url"
                :attribution="tileProvider.attribution"
                layer-type="base"
            ></l-tile-layer>
            <!--マーカー-->
            <l-marker
                :lat-lng="marker"
            ></l-marker>
        </l-map>
    </div>
</template>

<script lang="ts">
import {
    LMap,
    LTileLayer,
    LControlLayers,
    LMarker
} from '@vue-leaflet/vue-leaflet';

export default {
    name: 'MapPane',
    components: {
        LMap,
        LTileLayer,
        LControlLayers,
        LMarker
    },
    data() {
        return {
            center: [35.681, 139.763],
            zoom: 14,
            marker: [35.681, 139.763],
            tileProviders: [
                {
                    name: 'MIERUNE Streets',
                    visible: true,
                    url: 'https://api.maptiler.com/maps/jp-mierune-streets/256/{z}/{x}/{y}.png?key=[APIキー]',
                    attribution: '<a href="https://maptiler.jp/" target="_blank">&copy; MIERUNE</a> <a href="https://www.maptiler.com/copyright/" target="_blank">&copy; MapTiler</a> <a href="https://www.openstreetmap.org/copyright" target="_blank">&copy; OpenStreetMap contributors</a>'
                },
                {
                    name: 'MIERUNE Gray',
                    visible: false,
                    url: 'https://api.maptiler.com/maps/jp-mierune-gray/256/{z}/{x}/{y}.png?key=[APIキー]',
                    attribution: '<a href="https://maptiler.jp/" target="_blank">&copy; MIERUNE</a> <a href="https://www.maptiler.com/copyright/" target="_blank">&copy; MapTiler</a> <a href="https://www.openstreetmap.org/copyright" target="_blank">&copy; OpenStreetMap contributors</a>'
                }
            ]
        }
    }
}
</script>

<style scoped>
.mapPane {
    height: 800px;
    margin: 0;
    text-align: left;
}
</style>
```

マップのタグを指定します。

```vue
<template>
    <div class="mapPane">
        <!--マップ-->
        <l-map
            :zoom="zoom"
            :center="center"
        >
            <!--レイヤーコントロール-->
            <l-control-layers
                position="topright"
            ></l-control-layers>
            <!--レイヤ設定 Maptiler-->
            <l-tile-layer
                v-for="tileProvider in tileProviders"
                :key="tileProvider.name"
                :name="tileProvider.name"
                :visible="tileProvider.visible"
                :url="tileProvider.url"
                :attribution="tileProvider.attribution"
                layer-type="base"
            ></l-tile-layer>
            <!--マーカー-->
            <l-marker
                :lat-lng="marker"
            ></l-marker>
        </l-map>
    </div>
</template>
```

マップのサイズを指定します。

```css
.mapPane {
    height: 800px;
    margin: 0;
    text-align: left;
}
```

マップとレイヤとマーカーの設定をします。背景レイヤは、今回[Maptiler](https://maptiler.jp)を指定します。

```javascript
import {
    LMap,
    LTileLayer,
    LControlLayers,
    LMarker
} from '@vue-leaflet/vue-leaflet';

export default {
    name: 'MapPane',
    components: {
        LMap,
        LTileLayer,
        LControlLayers,
        LMarker
    },
    data() {
        return {
            center: [35.681, 139.763],
            zoom: 14,
            marker: [35.681, 139.763],
            tileProviders: [
                {
                    name: 'MIERUNE Streets',
                    visible: true,
                    url: 'https://api.maptiler.com/maps/jp-mierune-streets/256/{z}/{x}/{y}.png?key=[APIキー]',
                    attribution: '<a href="https://maptiler.jp/" target="_blank">&copy; MIERUNE</a> <a href="https://www.maptiler.com/copyright/" target="_blank">&copy; MapTiler</a> <a href="https://www.openstreetmap.org/copyright" target="_blank">&copy; OpenStreetMap contributors</a>'
                },
                {
                    name: 'MIERUNE Gray',
                    visible: false,
                    url: 'https://api.maptiler.com/maps/jp-mierune-gray/256/{z}/{x}/{y}.png?key=[APIキー]',
                    attribution: '<a href="https://maptiler.jp/" target="_blank">&copy; MIERUNE</a> <a href="https://www.maptiler.com/copyright/" target="_blank">&copy; MapTiler</a> <a href="https://www.openstreetmap.org/copyright" target="_blank">&copy; OpenStreetMap contributors</a>'
                }
            ]
        }
    }
}
```

<br>

ローカルサーバーで確認

```shell
npm run serve
```

<br>
       
ローカルサーバーを立ち上げると、マップが表示されます。

![try-049_01.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/60444/216ecc64-29c8-f1a3-fcff-b8446d3945ce.gif)

<br>

#### Vue.js v3とvue-leafletを利用することで、手軽にVue 3用Leafletの開発環境の構築ができました :thumbsup: 

Leafletのライブラリを、直接読み込んで利用することもできると思いますが、ラッパーライブラリを利用することである程度は手軽に操作ができると思います。ただ、用途により直接読み込むかラッパーライブラリを利用するかの選択は必要となりそうです:bulb: また、vue-leafletはまだベータ版ではありますが、Vue 2からVue 3への移行の参考になればと思います！ 

Vue 2の記事、「[Vue.jsでLeafletとMapbox GL JSの開発環境を構築してみた](https://memo.dayjournal.dev/memo/try-027)」と比べてみて頂ければと思います :grinning: 

<br>

Vue.js・Leafletについて、他にも記事を書いています。よろしければぜひ :bow:
<a href="https://memo.dayjournal.dev/tags/leaflet" target="_blank">tags - Leaflet</a>
<a href="https://memo.dayjournal.dev/tags/vue-js" target="_blank">tags - Vue.js</a>

やってみたシリーズ :grinning:
<a href="https://memo.dayjournal.dev/tags/try" target="_blank">tags - Try</a>

<br>
<br>

<a href="https://dayjournal.booth.pm" target="_blank"><img src="https://memo.dayjournal.dev/images/etc/book.png" alt="book"></a>