AWSの地図サービス、Amazon Location Service を試してみた!(2)実践編

Posted by naoki on June 07, 2021 · 3 mins read

前回の記事 AWSの地図サービス、Amazon Location Service を試してみた!(1)概要編 では、Amazon Location Service についてざっくり説明しましたが、今回は実際に地図を表示してみようと思います。

今回解説するコードは GitHub にアップロードしています。

1. Amazon Location Service で 地図を作成

Amazon Management Consoleにログインし Amazon Location Service のページへ移動します。

左のサイドバーより「Maps」をクリックして下さい。

「Create Map」をクリックします。

「Name」に地図の名前を入力します。このデモでは explore.map と入力したと仮定して説明を進めます。

「Maps」では、地図のスタイルを選択できます。お好きなスタイルをを選択して下さい。

下にスクロールをして「Create Map」をクリック。地図を作成します。

2. ID プールを作成する

地図タイルへの認証のために、ID プールを作成していきます。

Amazon Cognito のページへ移動します。

「IDプールの管理」をクリックします。

「新しい ID プールの作成」をクリックします。

「ID プール名」 に一意の名前を入力して下さい。ここでは Test Amazon Location と入力したと仮定して説明を進めます。

「認証されていない ID に対してアクセスを有効にする」 にチェックを入れます。

「プールの作成」 をクリックし、次に「許可」をクリックします。

作成した ID プールにマップへのアクセスを許可する IAM ポリシーを追加します。

IAM ページへ移動し、左のサイドバーのロールを選択します。

https://console.aws.amazon.com/iam/home?region=ap-northeast-1#/policies

先ほど作成したロールのうち、Unauth_Role を含むロール名を選択し、「ポリシーをアタッチします」 をクリックします。

「ポリシーの作成」 をクリックします。

以下のポリシーを追加します。

explore.map には、1 で作成したマップ名を入力して下さい。aws:referer の値にアクセスを許可したいリファラーのオリジンを指定して下さい。

aws:referer についてはこちらを参考にして下さい。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "MapsReadOnly",
            "Effect": "Allow",
            "Action": [
                "geo:GetMapStyleDescriptor",
                "geo:GetMapGlyphs",
                "geo:GetMapSprites",
                "geo:GetMapTile"
            ],
            "Resource": "arn:aws:geo:ap-northeast-1:xxxxxxxxxxxx:map/explore.map",
            "Condition": {
                "ForAnyValue:StringLike": {
                    "aws:referer": [
                        "http://localhost*",
                        "https://geolonia.github.io/*",
                        "https://example.com/*"
                    ]
                }
            }
        }
    ]
}

3. 地図のスタイルを表示

あとは、以下のコードの identityPoolIdmapName の値をステップ1・2で作成したものに置き換えると、地図が表示されます。

<!-- example-1.html -->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link
    href="https://api.mapbox.com/mapbox-gl-js/v1.12.0/mapbox-gl.css"
    rel="stylesheet"
  />
  <style>
    body {
      margin: 0;
    }

    #map {
      height: 100vh;
    }
  </style>
</head>
<body>
    <!-- map container -->
    <div id="map" />
    <!-- JavaScript dependencies -->
    <script src="https://api.mapbox.com/mapbox-gl-js/v1.12.0/mapbox-gl.js"></script>
    <script src="https://sdk.amazonaws.com/js/aws-sdk-2.775.0.min.js"></script>
    <script src="https://unpkg.com/@aws-amplify/core@3.7.0/dist/aws-amplify-core.min.js"></script>
    <script>
      // use Signer from @aws-amplify/core
      const { Signer } = window.aws_amplify_core;

      // configuration
      const identityPoolId = "ap-northeast-1:d995db2c-8646-4ed2-8122-45dbd2c80019"; // Cognito Identity Pool ID
      const mapName = 'explore.map'; // Amazon Location Service Map Name

      // extract the region from the Identity Pool ID
      AWS.config.region = identityPoolId.split(":")[0];

      // instantiate a Cognito-backed credential provider
      const credentials = new AWS.CognitoIdentityCredentials({
        IdentityPoolId: identityPoolId,
      });

      /**
       * Sign requests made by Mapbox GL using AWS SigV4.
       */
      function transformRequest(url, resourceType) {
        if (resourceType === "Style" && !url.includes("://")) {
          // resolve to an AWS URL
          url = `https://maps.geo.${AWS.config.region}.amazonaws.com/maps/v0/maps/${url}/style-descriptor`;
        }

        if (url.includes("amazonaws.com")) {
          // only sign AWS requests (with the signature as part of the query string)
          return {
            url: Signer.signUrl(url, {
              access_key: credentials.accessKeyId,
              secret_key: credentials.secretAccessKey,
              session_token: credentials.sessionToken,
            }),
          };
        }

        // don't sign
        return { url };
      }

      /**
       * Initialize a map.
       */
      async function initializeMap() {
        // load credentials and set them up to refresh
        await credentials.getPromise();

        // actually initialize the map
        const map = new mapboxgl.Map({
          container: "map",
          center: [139.7673068, 35.6809591], // initial map centerpoint
          zoom: 14, // initial map zoom
          style: mapName,
          hash: true,
          transformRequest,
        });

        map.addControl(new mapboxgl.NavigationControl(), "top-left");
      }

      initializeMap();
    </script>
</body>
</html>

実際の表示デモは以下をご覧ください。

https://geolonia.github.io/aws-example-2021-06-07/example-1.html

感想

試してみて気になったのは以下の点です。

  • 地名が英語表記なので、実務で使う時は日本語化が必要。
  • PoIs(店舗や施設等)のデータが少ないので、用途によって別データとの組み合わせが必要。
  • IAM ポリシーに aws:referer を追加しないと、第三者が地図が使い放題になる。

なので次回は、Geolonia の Embed API を使って 日本語化 & PoIのレイヤーを追加してみようと思います!

参考



Geolonia では、ウェブ地図や位置情報を利用したウェブアプリケーションや、モバイルアプリケーションの開発を承っています。

お問い合わせ

また、Geolonia では、エンジニアを募集しています。Geolonia で働くことに興味がある方はぜひ一度お話しませんか?

採用ページ