この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
こんにちは!DA(データアナリティクス)事業本部 インテグレーション部の大高です。
先日Amazon Location Serviceのマップを、地図表示ライブラリの「Mapbox GL JS」を利用しているサンプルコードで表示してみました。
本エントリでは、このサンプルコードを参考に、オープンソースの地図表示ライブラリであるOpenLayersを利用してマップを表示してみたいと思います。
前提と事前準備
前提条件として下記のドキュメントに記載のとおり「map」リソースが作成されている必要があります。今回は検証環境に既にexplore.map
という名前の「map」が存在していたので、これを利用しています。
また、リソースへのリクエストについてはCognitoを利用した認証設定が必要になります。今回は地図表示をするために必要となるので、下記のドキュメントに従ってIDプールを作成します。
ドキュメントの通りですが、作成時のポイントとしては以下になります。
- 「認証されていない ID に対してアクセスを有効にする」にチェックを入れて作成
- 「Identify the IAM roles to use with your new identity pool」の画面が表示される
- 「詳細を表示」をクリックする
- 「ロールの概要」の「IAM ロール」プルダウンで「新しい IAM ロールの作成」を選択
- 下の方の「Your unauthenticated identities would like access to Cognito.」であることに注意
- 「ポリシードキュメントを表示」をクリックして「編集」リンクをクリック
- ブラウザの高さがある程度ないと隠れて見えないので注意
- ポリシードキュメントは、サンプルと同様に以下のように記載する(Resourceの箇所は自分のMapリソースに合わせる)
{
"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"
}
]
}
なお、ドキュメントにも記載されているとおり、セキュリティを考慮して不必要なリソースへのアクセスは許可しないように十分留意してください。
今回は簡単な検証のために認証されていないIDに対してもアクセスを有効化していますが、本番利用の際には用途にあわせて設定を行う必要があります。
プロジェクトの準備
今回はOpenLayersのサイトで公開されている以下のサンプル「Mapbox-gl Layer」が参考になりそうなので、こちらをベースに作っていきます。先日試してみた公式サンプルに「mapbox-gl-js」のサンプルコードがありますので、こちらが一番親和性が高いと判断しました。
なお、サンプルコードからもわかるように、最近のOpenLayersはモジュール形式になっているのでnpm
かyarn
を利用する必要があります。
サンプルコードのmain.js
、index.html
、package.json
をフォルダ内に配置したら、下記のようにして必要なパッケージのインストールをして簡単に動作確認しておきます。
$ yarn install
$ yarn start
なお、この時点ではサンプルコードの実行に必要なAPIキーは設定していないので認証エラーで地図画像はでません。
サンプルコードの修正
では、このサンプルコードをベースとして修正を加えていきます。基本的な方針としては、下記で公開されているサンプルの「mapbox-gl-js」の処理を組み込んでいく方針です。
まず、index.html
には、aws-sdkとamplifyのライブラリを読み込ませるようにします。また、地図の表示範囲もちょっと広げておきましょう。
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Mapbox-gl Layer</title>
<script src="https://sdk.amazonaws.com/js/aws-sdk-2.784.0.min.js"></script>
<script src="https://unpkg.com/@aws-amplify/core@3.7.0/dist/aws-amplify-core.min.js"></script>
<!-- Pointer events polyfill for old browsers, see https://caniuse.com/#feat=pointer -->
<script src="https://unpkg.com/elm-pep"></script>
<!-- The line below is only needed for old environments like Internet Explorer and Android 4.x -->
<script src="https://cdn.polyfill.io/v3/polyfill.min.js?features=fetch,requestAnimationFrame,Element.prototype.classList,URL,TextDecoder"></script>
<script src="https://unpkg.com/mapbox-gl@1.11.1/dist/mapbox-gl.js"></script>
<link rel="stylesheet" href="https://unpkg.com/mapbox-gl@1.11.1/dist/mapbox-gl.css">
<style>
.map {
width: 100%;
height: 95vh;
}
/* Reset font size changed by Mapbox CSS */
.map {
font-size: medium;
font-family: 'Quattrocento Sans', sans-serif;
}
</style>
</head>
<body>
<div id="map" class="map"></div>
<script src="main.js"></script>
</body>
</html>
次に、main.js
です。identityPoolId
とmapName
はそれぞれ利用しているものに合わせて修正します。ちょっと気をつけるポイントとしては、リクエストのパラメータに署名が必要なので、initializeMap
で async/await を利用してcredentials.getPromise()
を呼んでいるあたりになります。また、今回は地図の中心を東京にしてみました。
main.js
import "ol/ol.css";
import Layer from "ol/layer/Layer";
import Map from "ol/Map";
import View from "ol/View";
import { fromLonLat, toLonLat } from "ol/proj";
// use Signer from @aws-amplify/core
const { Signer } = window.aws_amplify_core;
// configuration
// Cognito Identity Pool ID
const identityPoolId = "<Identity Pool ID>";
// Amazon Location Service Map Name
const mapName = "<Map name>";
// extract the region from the Identity Pool ID
AWS.config.region = identityPoolId.split(":")[0];
// instantiate a credential provider
const credentials = new AWS.CognitoIdentityCredentials({
IdentityPoolId: identityPoolId,
});
var center = [139.7696, 35.6796];
/**
* 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();
const mbMap = new mapboxgl.Map({
container: "map",
center: center, // initial map centerpoint
zoom: 10, // initial map zoom
style: mapName,
transformRequest,
});
var mbLayer = new Layer({
render: function (frameState) {
var canvas = mbMap.getCanvas();
var viewState = frameState.viewState;
var visible = mbLayer.getVisible();
canvas.style.display = visible ? "block" : "none";
var opacity = mbLayer.getOpacity();
canvas.style.opacity = opacity;
// adjust view parameters in mapbox
var rotation = viewState.rotation;
mbMap.jumpTo({
center: toLonLat(viewState.center),
zoom: viewState.zoom - 1,
bearing: (-rotation * 180) / Math.PI,
animate: false,
});
// cancel the scheduled update & trigger synchronous redraw
// see https://github.com/mapbox/mapbox-gl-js/issues/7893#issue-408992184
// NOTE: THIS MIGHT BREAK IF UPDATING THE MAPBOX VERSION
if (mbMap._frame) {
mbMap._frame.cancel();
mbMap._frame = null;
}
mbMap._render();
return canvas;
},
});
var map = new Map({
target: "map",
view: new View({
center: fromLonLat(center),
zoom: 4,
}),
layers: [mbLayer],
});
}
initializeMap();
地図を表示してみる
では、実際に地図を表示させてみましょう。
$ yarn start
ローカルサーバが立ち上がるのでhttp://localhost:1234
にアクセスして確認します。
想定どおりに表示されました!
まとめ
以上、Amazon Location Service のマップをOpenLayersを利用して表示してみました。
当初は、OpenLayersの他のサンプルをベースに試していましたが、なかなかうまくいかずに困っていました。ですが、途中で「Mapbox-gl Layer」のサンプルを見つけ、このサンプルがあったおかげで簡単に表示することができました。今回は単純に1レイヤを表示していますが、OpenLayersを利用することで任意のレイヤーを重ねることもできそうですね。
どなたかのお役に立てば幸いです。それでは!