Building a Map Application with Amazon Location Service, MapLibre GL JS, AWS Amplify, and Vue.js
Tags: amazonlocationservice, awsamplify, maplibre, vue
Published: 2021-10-21 12:24:51


![img](https://day-journal.com/memo/images/try-060_12.png)
<br>

### I built a map application using Amazon Location Service, MapLibre GL JS, AWS Amplify, and Vue.js :tada:  

Amazon Location Service is a service for building location-based applications within AWS. At present, five types of functions are available: map display function, address search function, route search function, geofence function, and tracking function. This time, I used the map display function to build a map application!

<br>

Advance Preparation
- Setting up AWS Amplify and Vue.js to the login feature
<br>

## Configure Amazon Location Maps
First, we will configure Amazon Location Maps in the AWS console.

<br>

Click on "Maps".
![img](https://day-journal.com/memo/images/try-060_01.png)

Click on "Create map".
![img](https://day-journal.com/memo/images/try-060_02.png)

Enter a map name and select a map. This time, select "sample."
![img](https://day-journal.com/memo/images/try-060_03.png)

Click on the map that has been created.
![img](https://day-journal.com/memo/images/try-060_04.png)

Copy the "Name" and "ARN" shown here to use them in future settings.
![img](https://day-journal.com/memo/images/try-060_05.png)

This will complete the setup of Amazon Location Maps :thumbsup: 
<br>

## Frontend
Next, let's build the actual map application.  

Once Amplify and Vue.js are configured, it's just a matter of adding a new "MapPane.vue" and changing some of the code.

<br>

execution environment
- node v16.3.0  
- npm v7.15.1  

<br>

Install the MapLibre GL JS package in advance.

```sh
npm install maplibre-gl
```

<br>

Overall composition

![img](https://day-journal.com/memo/images/try-060_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",
    "maplibre-gl": "^1.14.1-rc.2",
    "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'
import 'maplibre-gl/dist/maplibre-gl.css'
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>

Load MapLibre GL JS.

```javascript
import 'maplibre-gl/dist/maplibre-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>

Set the map component.

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

<br>

Loads the map component.

```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>
    import maplibregl from 'maplibre-gl'
    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() {
                const map = new maplibregl.Map({
                    container: 'map',
                    style: 'sample',
                    center: [139.7648, 35.6794],
                    zoom: 15,
                    bearing: 64.8,
                    pitch: 60,
                    hash: true,
                    transformRequest: this.transformRequest,
                });

                map.addControl(new maplibregl.NavigationControl());
            },
            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>

Load MapLibre GL JS and Amplify.

```javascript
import maplibregl from 'maplibre-gl'
import { Auth, Signer } from 'aws-amplify'
import awsconfig from '../aws-exports'
```

<br>

Obtain authentication information.

```javascript
this.credentials = await Auth.currentCredentials()
```

<br>

Specify the "Name" of the map created in style.

```javascript
const map = new maplibregl.Map({
    container: 'map',
    style: 'sample',
    center: [139.7648, 35.6794],
    zoom: 15,
    bearing: 64.8,
    pitch: 60,
    hash: true,
    transformRequest: this.transformRequest,
});
```

<br>

Configure the settings to load Amazon Location Maps.

```javascript
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>

## Configure Amplify Roles
The last step is to add the Amazon Location Maps policy to the Amplify role.

<br>

Search for the role that is used for the login function. Select "amplify-xxxxx-authRole".

![img](https://day-journal.com/memo/images/try-060_07.png)

Click "Add Inline Policy".

![img](https://day-journal.com/memo/images/try-060_08.png)

Select "JSON" to set the policy. Set the "ARN" of the created map to "Resource."

```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"
        }
    ]
}
```

![img](https://day-journal.com/memo/images/try-060_09.png)

Set the name as needed. This time, set it as "amazon-location-maps."

![img](https://day-journal.com/memo/images/try-060_10.png)

Make sure that the policy has been created.

![img](https://day-journal.com/memo/images/try-060_11.png)

This completes the role configuration for Amplify :thumbsup: 

<br>

Let's check with a simple local server.

```shell
npm run serve
```

<br>

Startup a local server and try logging in. You are now able to see Amazon Location Maps :bulb: 

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

#### I was able to build a map application using a combination of Amazon Location Service, MapLibre GL JS, AWS Amplify, and Vue.js :thumbsup: 

When I installed Amplify in advance, I was able to build Amazon Location Service quickly. However, some areas can still be improved, such as the need for separate role settings and the limited styles that can be selected. I'll continue to explore other features as well :thumbsup: