Amazon Location ServiceとLeafletとAWS AmplifyとVue.jsを組み合わせてマップアプリケーションを構築してみた

![](https://day-journal.com/memo/images/try-061_00.gif)

<br>

![](https://day-journal.com/memo/images/try-061_12.png)

<br>

### Amazon Location ServiceとLeafletとAWS AmplifyとVue.jsを組み合わせてマップアプリケーションを構築してみました :tada:  

前回投稿した[記事](https://qiita.com/dayjournal/items/b131fe834e957f62575f)のLeafletバージョンを構築してみました :thumbsup: 

Amazon Location Serviceとは、AWS内で利用できる位置情報アプリケーションを構築するためのサービスになります。現時点の機能として、地図表示機能・住所検索機能・ルート検索機能・ジオフェンス機能・トラッキング機能の5種類を利用できます。今回は、地図表示機能を利用しマップアプリケーションを構築してみました！

<br>

事前準備

- AWS AmplifyとVue.jsのログイン機能までの設定  
以前書いた記事からの続きで説明します。  
[AWS AmplifyとAmplify UI VueとVue.jsでログイン機能を構築してみた](https://day-journal.com/memo/try-059)

<br>

## Amazon Location Mapsの設定
はじめに、AWSコンソールでAmazon Location Mapsの設定をします。

<br>

「Maps」をクリックします。
![画像](https://day-journal.com/memo/images/try-061_01.png)

「Create map」をクリックします。
![画像](https://day-journal.com/memo/images/try-061_02.png)

マップ名の入力とマップを選択します。今回は「sample」としました。
![画像](https://day-journal.com/memo/images/try-061_03.png)

作成されたマップをクリックします。
![画像](https://day-journal.com/memo/images/try-061_04.png)

ここで表示されている「Name」と「ARN」を今後の設定で利用するのでコピーしておきます。
![画像](https://day-journal.com/memo/images/try-061_05.png)

これでAmazon Location Mapsの設定は完了になります :thumbsup: 

<br>

## フロントエンド
次に、実際にマップアプリケーションを構築していきます。  

AmplifyとVue.jsの構成ができていると、基本的には「MapPane.vue」を新規で追加するのと、コードを一部変更するのみになります。

<br>

実行環境

- node v16.3.0  
- npm v7.15.1  

<br>

事前に、Leafletのパッケージをインストールします。また、ベクトルタイルを表示するためにMapbox GL Leafletのパッケージと、Mapbox GL JSのOSSバージョンのパッケージもインストールします。

```sh
npm install leaflet
npm install mapbox-gl-leaflet
npm install mapbox-gl@1.13.0
```

<br>

全体構成

![画像](https://day-journal.com/memo/images/try-061_06.png)


#### package.json

```json
{
  "name": "amazon-location-app",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "serve": "vue-cli-service serve",
    "build": "vue-cli-service build",
    "lint": "vue-cli-service lint"
  },
  "dependencies": {
    "@aws-amplify/ui-vue": "^1.0.12",
    "aws-amplify": "^4.1.1",
    "core-js": "^3.6.5",
    "leaflet": "^1.7.1",
    "mapbox-gl": "^1.13.0",
    "mapbox-gl-leaflet": "^0.0.15",
    "vue": "^2.6.11",
    "vue-router": "^3.2.0",
    "vuetify": "^2.4.0",
    "vuex": "^3.4.0"
  },
  "devDependencies": {
    "@vue/cli-plugin-babel": "~4.5.0",
    "@vue/cli-plugin-eslint": "~4.5.0",
    "@vue/cli-plugin-router": "~4.5.0",
    "@vue/cli-plugin-vuex": "~4.5.0",
    "@vue/cli-service": "~4.5.0",
    "babel-eslint": "^10.1.0",
    "eslint": "^6.7.2",
    "eslint-plugin-vue": "^6.2.2",
    "sass": "~1.32.0",
    "sass-loader": "^10.0.0",
    "vue-cli-plugin-vuetify": "~2.4.1",
    "vue-template-compiler": "^2.6.11",
    "vuetify-loader": "^1.7.0"
  },
  "eslintConfig": {
    "root": true,
    "env": {
      "node": true
    },
    "extends": [
      "plugin:vue/essential",
      "eslint:recommended"
    ],
    "parserOptions": {
      "parser": "babel-eslint"
    },
    "rules": {}
  },
  "browserslist": [
    "> 1%",
    "last 2 versions",
    "not dead"
  ]
}
```

<br>

/src

#### main.js

```javascript
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
import vuetify from './plugins/vuetify'

// LeafletとMapbox GL JSのOSSバージョンのCSSを読み込み
import 'leaflet/dist/leaflet.css'
import 'mapbox-gl/dist/mapbox-gl.css'

// Amplify読み込み
import '@aws-amplify/ui-vue'
import Amplify from 'aws-amplify'
import awsconfig from './aws-exports'
Amplify.configure(awsconfig)

Vue.config.productionTip = false

new Vue({
  router,
  store,
  vuetify,
  render: h => h(App)
}).$mount('#app')
```

<br>

LeafletとMapbox GL JSのOSSバージョンを読み込みます。

```javascript
// LeafletとMapbox GL JSのOSSバージョンのCSSを読み込み
import 'leaflet/dist/leaflet.css'
import 'mapbox-gl/dist/mapbox-gl.css'
```

<br>

/src/views

#### Home.vue

```vue
<template>
    <div class="home">
        <v-container>
            <v-row>
                <v-col>
                    <h1>Amazon Location Service</h1>
                </v-col>
            </v-row>
            <v-row>
                <v-col>
                    <MapPane></MapPane>
                </v-col>
            </v-row>
            <v-row>
                <v-col>
                    <!--ログアウトコンポーネント-->
                    <amplify-sign-out></amplify-sign-out>
                </v-col>
            </v-row>
        </v-container>
    </div>
</template>

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

    export default {
        name: 'home',
        components: {
            MapPane
        }
    }
</script>

<style>
    .home {
        padding-top: 100px;
    }
</style>
```

<br>

マップコンポーネントを設定します。

```vue
<v-row>
    <v-col>
        <MapPane></MapPane>
    </v-col>
</v-row>
```

<br>

マップコンポーネントを読み込みます。

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

export default {
    name: 'home',
    components: {
        MapPane
    }
}
```

<br>

<br>

/src/components

#### MapPane.vue

```vue
<!--マップコンポーネント-->
<template>
    <div class='mapPane'>
        <!--マップ表示-->
        <div id='map'></div>
    </div>
</template>

<script>
    // LeafletとMapbox GL Leafletを読み込み
    import L from 'leaflet'
    import 'mapbox-gl-leaflet'
    // Amplify読み込み
    import { Auth, Signer } from 'aws-amplify'
    import awsconfig from '../aws-exports'

    export default {
        name: 'MapPane',
        data() {
            return {
                credentials: null,
            }
        },
        mounted: async function () {
            // 認証情報取得
            this.credentials = await Auth.currentCredentials()
            // マップオブジェクト生成
            this.mapCreate();
        },
        methods: {
            // マップオブジェクト生成
            mapCreate: function() {
                // Amazon Location Maps読み込み
                const sample = L.mapboxGL({
                    style: 'sample',
                    attribution: '© 2021 HERE',
                    transformRequest: this.transformRequest,
                });
                // マップ読み込み
                const map = L.map('map', {
                    center: [35.681, 139.767],
                    zoom: 14,
                    zoomControl: true,
                    layers: [sample]
                });

                //背景レイヤ
                const Map_BaseLayer = {
                    'sample': sample
                };
                //レイヤ設定
                L.control.layers(
                    Map_BaseLayer,
                    null
                ).addTo(map);
            },
            // Amazon Location Maps設定
            transformRequest: function (url, resourceType) {
                if (resourceType === 'Style' && !url.includes('://')) {
                    // スタイル設定
                    url = `https://maps.geo.${awsconfig.aws_project_region}.amazonaws.com/maps/v0/maps/${url}/style-descriptor`
                }
                if (url.includes('amazonaws.com')) {
                    return {
                        url: Signer.signUrl(url, {
                            access_key: this.credentials.accessKeyId,
                            secret_key: this.credentials.secretAccessKey,
                            session_token: this.credentials.sessionToken,
                        }),
                    }
                }
                return { url }
            },
        }
    }
</script>

<style scoped>
    #map {
        z-index: 0;
        height: 800px;
    }
</style>
```

<br>

LeafletとMapbox GL LeafletとAmplifyを読み込みます。

```javascript
// LeafletとMapbox GL Leafletを読み込み
import L from 'leaflet'
import 'mapbox-gl-leaflet'
// Amplify読み込み
import { Auth, Signer } from 'aws-amplify'
import awsconfig from '../aws-exports'
```

<br>

認証情報を取得します。

```javascript
// 認証情報取得
this.credentials = await Auth.currentCredentials()
```

<br>

styleに作成したマップの「Name」を指定します。

```javascript
// Amazon Location Maps読み込み
const sample = L.mapboxGL({
    style: 'sample',
    attribution: '© 2021 HERE',
    transformRequest: this.transformRequest,
});
// マップ読み込み
const map = L.map('map', {
    center: [35.681, 139.767],
    zoom: 14,
    zoomControl: true,
    layers: [sample]
});

//背景レイヤ
const Map_BaseLayer = {
    'sample': sample
};
//レイヤ設定
L.control.layers(
    Map_BaseLayer,
    null
).addTo(map);
```

<br>

Amazon Location Mapsを読み込む設定をします。

```javascript
// Amazon Location Maps設定
transformRequest: function (url, resourceType) {
    if (resourceType === 'Style' && !url.includes('://')) {
        // スタイル設定
        url = `https://maps.geo.${awsconfig.aws_project_region}.amazonaws.com/maps/v0/maps/${url}/style-descriptor`
    }
    if (url.includes('amazonaws.com')) {
        return {
            url: Signer.signUrl(url, {
                access_key: this.credentials.accessKeyId,
                secret_key: this.credentials.secretAccessKey,
                session_token: this.credentials.sessionToken,
            }),
        }
    }
    return { url }
},
```

<br>

## Amplifyのロール設定
最後にAmplifyのロールにAmazon Location Mapsのポリシーを追加します。

<br>

ログイン機能で利用しているロールを検索します。「amplify-xxxxx-authRole」を選択します。

![画像](https://day-journal.com/memo/images/try-061_07.png)

「インラインポリシーの追加」をクリックします。

![画像](https://day-journal.com/memo/images/try-061_08.png)

「JSON」を選択しポリシーを設定します。Resourceは作成したマップの「ARN」を設定します。

```json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "MapsReadOnly",
            "Effect": "Allow",
            "Action": [
                "geo:GetMapStyleDescriptor",
                "geo:GetMapGlyphs",
                "geo:GetMapSprites",
                "geo:GetMapTile"
            ],
            "Resource": "arn:aws:geo:us-west-2:xxxxx:map/sample"
        }
    ]
}
```

![画像](https://day-journal.com/memo/images/try-061_09.png)

名前を任意で設定します。今回は「amazon-location-maps」としました。

![画像](https://day-journal.com/memo/images/try-061_10.png)

ポリシーが作成されているのを確認します。

![画像](https://day-journal.com/memo/images/try-061_11.png)

これでAmplifyのロール設定は完了になります :thumbsup: 

<br>

簡易ローカルサーバーで確認してみます。

```shell
npm run serve
```

<br>

ローカルサーバーを立ち上げて、ログインしてみます。Amazon Location Mapsの表示を確認できました :bulb: 

![画像](https://day-journal.com/memo/images/try-061_00.gif)  

#### Amazon Location ServiceとLeafletとAWS AmplifyとVue.jsを組み合わせてマップアプリケーションを構築できました :thumbsup: 

事前にAmplifyを導入すると、Amazon Location Serviceを手軽に構築することができました。ただ、ロールの設定が別途必要だったり、選択できるスタイルが限定されている等(アレをアレするとスタイル設定変更できたりするのですが...)まだまだ進化できる部分がありそうです。他の機能についても引き続き探っていきたいと思います :thumbsup: 

<br>

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

やってみたシリーズ :grinning:
<a href="https://day-journal.com/memo/tags/Try" target="_blank">tags - Try</a>
<a href="https://day-journal.com/memo/try-059" target="_blank">AWS AmplifyとAmplify UI VueとVue.jsでログイン機能を構築してみた</a>

<br>
<br>

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