Amazon Location Service로 Tangram 사용 - Amazon Location Service

기계 번역으로 제공되는 번역입니다. 제공된 번역과 원본 영어의 내용이 상충하는 경우에는 영어 버전이 우선합니다.

Amazon Location Service로 Tangram 사용

Tangram은 벡터 타일에서 2D 및 3D 맵을 실시간으로 렌더링하도록 설계된 유연한 매핑 엔진입니다. Amazon Location Service Maps에서 제공하는 Mapzen이 설계한 스타일 및 HERE 타일과 함께 사용할 수 있습니다API. 이 가이드에서는 기본 HTML/JavaScript 애플리케이션 내에서 Tangram을 Amazon Location과 통합하는 방법을 설명합니다. 하지만 React 및 Angular와 같은 프레임워크를 사용할 때도 동일한 라이브러리와 기법이 적용됩니다.

Tangram은 모바일 친화적 대화형 맵을 위한 오픈 소스 JavaScript 라이브러리인 리플릿 위에 구축되었습니다. 즉, 많은 Leaflet 호환 플러그인 및 컨트롤이 Tangram에서도 작동합니다.

Tilezen 스키마와 함께 작동하도록 구축된 탄그램 스타일은 의 맵을 사용할 때 Amazon Location과 대부분 호환됩니다HERE. 다음이 포함됩니다.

  • Bubble Wrap – 모든 기능을 갖춘 길 찾기 스타일로, 관심 지점을 표시하는 유용한 아이콘이 포함되어 있습니다.

  • Cinnabar – 클래식한 디자인으로 일반 매핑 애플리케이션에 적합합니다.

  • Refill – Stamen Design의 획기적인 Toner 스타일에서 영감을 받아 데이터 시각화 오버레이를 위해 디자인된 미니멀한 맵 스타일입니다.

  • Tron - 의 시각적 언어로 스케일 변환 탐색 TRON

  • Walkabout – 야외 활동에 초점을 맞춘 스타일로 하이킹이나 야외 활동에 안성맞춤입니다.

이 안내서에서는 Bubble Wrap이라는 Tangram 스타일을 사용하여 기본 HTML/JavaScript 애플리케이션 내에서 Tangram을 Amazon Location과 통합하는 방법을 설명합니다. 이 샘플은 의 Amazon Location Service 샘플 리포지토리의 일부로 사용할 수 있습니다GitHub.

다른 Tangram 스타일은 지형 정보를 인코딩하는 래스터 타일을 사용하는 것이 가장 좋지만, Amazon Location에서는 아직 이 기능을 지원하지 않습니다.

중요

다음 튜토리얼의 Tangram 스타일은 VectorHereContrast 스타일로 구성된 Amazon Location 맵 리소스와만 호환됩니다.

애플리케이션 빌드: 스캐폴딩

애플리케이션은 웹 애플리케이션에 맵을 빌드 JavaScript 하기 위한 의 HTML 페이지입니다. HTML 페이지(index.html)를 생성하고 맵의 컨테이너를 생성합니다.

  • 맵의 id가 포함된 div 요소를 입력하여 맵의 크기를 맵 보기에 적용합니다.

  • 크기는 뷰포트에서 상속됩니다.

<html> <head> <style> body { margin: 0; } #map { height: 100vh; /* 100% of viewport height */ } </style> </head> <body> <!-- map container --> <div id="map" /> </body> </html>

애플리케이션 빌드: 종속성 추가

다음 종속성을 추가합니다.

  • 리플릿 및 관련 CSS.

  • Tangram.

  • AWS SDK 용 JavaScript.

<!-- CSS dependencies --> <link rel="stylesheet" href="https://unpkg.com/leaflet@1.7.1/dist/leaflet.css" integrity="sha512-xodZBNTC5n17Xt2atTPuE1HxjVMSvLVW9ocqUKLsCC5CXdbqCmblAshOMAS6/keqq/sMZMZ19scR4PsZChSR7A==" crossorigin="" /> <!-- JavaScript dependencies --> <script src="https://unpkg.com/leaflet@1.7.1/dist/leaflet.js"></script> <script src="https://unpkg.com/tangram"></script> <script src="https://sdk.amazonaws.com/js/aws-sdk-2.784.0.min.js"></script> <script> // application-specific code </script>

이는 필수 사전 조건이 포함된 빈 페이지를 만듭니다. 다음 단계에서는 애플리케이션의 JavaScript 코드를 작성하는 방법을 안내합니다.

애플리케이션 빌드: 구성

리소스 및 보안 인증 정보로 애플리케이션을 구성하려면

  1. 리소스의 이름과 식별자를 입력합니다.

    // Cognito Identity Pool ID const identityPoolId = "us-east-1:54f2ba88-9390-498d-aaa5-0d97fb7ca3bd"; // Amazon Location Service map name; must be HERE-backed const mapName = "TangramExampleMap";
  2. 맵 사용 - 2단계, 인증 설정에서 생성한 인증되지 않은 자격 증명 풀을 사용하여 보안 인증 정보 공급자를 인스턴스화합니다. 이 작업은 정상 AWS SDK 워크플로 외부에서 자격 증명을 사용하므로 세션은 1시간 후에 만료됩니다.

    // extract the region from the Identity Pool ID; this will be used for both Amazon Cognito and Amazon Location AWS.config.region = identityPoolId.split(":", 1)[0]; // instantiate a Cognito-backed credential provider const credentials = new AWS.CognitoIdentityCredentials({ IdentityPoolId: identityPoolId, });
  3. Tangram을 사용하면 타일을 가져오는 데 사용되는 URL(s)를 재정의할 수 있지만 요청을 가로채서 서명할 수 있는 기능은 포함되지 않습니다.

    이 문제를 해결하려면 서비스 작업자가 처리할 가상 호스트 이름 amazon.location을 사용하여 Amazon Location을 가리키도록 sources.mapzen.url을 재정의합니다. 다음은 Bubble Wrap을 사용한 장면 구성의 예시입니다.

    const scene = { import: [ // Bubble Wrap style "https://www.nextzen.org/carto/bubble-wrap-style/10/bubble-wrap-style.zip", "https://www.nextzen.org/carto/bubble-wrap-style/10/themes/label-7.zip", "https://www.nextzen.org/carto/bubble-wrap-style/10/themes/bubble-wrap-road-shields-usa.zip", "https://www.nextzen.org/carto/bubble-wrap-style/10/themes/bubble-wrap-road-shields-international.zip", ], // override values beneath the `sources` key in the style above sources: { mapzen: { // point at Amazon Location using a synthetic URL, which will be handled by the service // worker url: `https://amazon.location/${mapName}/{z}/{x}/{y}`, }, // effectively disable raster tiles containing encoded normals normals: { max_zoom: 0, }, "normals-elevation": { max_zoom: 0, }, }, };

애플리케이션 빌드: 변환 요청

서비스 작업자를 등록하고 초기화하려면 맵을 초기화하기 전에 호출할 registerServiceWorker 함수를 만듭니다. 이렇게 하면 를 제어하는 서비스 작업자sw.js라는 별도의 파일에 제공된 JavaScript 코드가 등록됩니다index.html.

보안 인증 정보는 Amazon Cognito에서 로드되고 리전과 함께 서비스 작업자로 전달되어 Signature Version 4의 타일 요청에 서명하기 위한 정보를 제공합니다.

/** * Register a service worker that will rewrite and sign requests using Signature Version 4. */ async function registerServiceWorker() { if ("serviceWorker" in navigator) { try { const reg = await navigator.serviceWorker.register("./sw.js"); // refresh credentials from Amazon Cognito await credentials.refreshPromise(); await reg.active.ready; if (navigator.serviceWorker.controller == null) { // trigger a navigate event to active the controller for this page window.location.reload(); } // pass credentials to the service worker reg.active.postMessage({ credentials: { accessKeyId: credentials.accessKeyId, secretAccessKey: credentials.secretAccessKey, sessionToken: credentials.sessionToken, }, region: AWS.config.region, }); } catch (error) { console.error("Service worker registration failed:", error); } } else { console.warn("Service worker support is required for this example"); } }

sw.js의 서비스 작업자 구현은 message이벤트를 수신하여 보안 인증 정보 및 리전 구성 변경 사항을 수집합니다. 또한 fetch 이벤트를 수신하여 프록시 서버 역할을 합니다. amazon.location 합성 호스트 이름을 대상으로 하는 fetch 이벤트는 적절한 Amazon Location을 대상으로 다시 작성API되고 Amplify Core의 를 사용하여 서명됩니다Signer.

// sw.js self.importScripts( "https://unpkg.com/@aws-amplify/core@3.7.0/dist/aws-amplify-core.min.js" ); const { Signer } = aws_amplify_core; let credentials; let region; self.addEventListener("install", (event) => { // install immediately event.waitUntil(self.skipWaiting()); }); self.addEventListener("activate", (event) => { // control clients ASAP event.waitUntil(self.clients.claim()); }); self.addEventListener("message", (event) => { const { data: { credentials: newCredentials, region: newRegion }, } = event; if (newCredentials != null) { credentials = newCredentials; } if (newRegion != null) { region = newRegion; } }); async function signedFetch(request) { const url = new URL(request.url); const path = url.pathname.slice(1).split("/"); // update URL to point to Amazon Location url.pathname = `/maps/v0/maps/${path[0]}/tiles/${path.slice(1).join("/")}`; url.host = `maps.geo.${region}.amazonaws.com`; // strip params (Tangram generates an empty api_key param) url.search = ""; const signed = Signer.signUrl(url.toString(), { access_key: credentials.accessKeyId, secret_key: credentials.secretAccessKey, session_token: credentials.sessionToken, }); return fetch(signed); } self.addEventListener("fetch", (event) => { const { request } = event; // match the synthetic hostname we're telling Tangram to use if (request.url.includes("amazon.location")) { return event.respondWith(signedFetch(request)); } // fetch normally return event.respondWith(fetch(request)); });

보안 인증 정보를 자동으로 갱신하여 만료되기 전에 서비스 작업자에게 보내려면 index.html 내에서 다음 함수를 사용하세요.

async function refreshCredentials() { await credentials.refreshPromise(); if ("serviceWorker" in navigator) { const controller = navigator.serviceWorker.controller; controller.postMessage({ credentials: { accessKeyId: credentials.accessKeyId, secretAccessKey: credentials.secretAccessKey, sessionToken: credentials.sessionToken, }, }); } else { console.warn("Service worker support is required for this example."); } // schedule the next credential refresh when they're about to expire setTimeout(refreshCredentials, credentials.expireTime - new Date()); }

애플리케이션 빌드: 맵 초기화

페이지가 로드된 후 맵을 표시하려면 맵을 초기화해야 합니다. 초기 맵 위치를 조정하고, 컨트롤을 추가하고, 데이터를 오버레이할 수 있습니다.

참고

애플리케이션 또는 문서에서 사용하는 각 데이터 공급자에 대한 워드마크 또는 텍스트 속성을 제공해야 합니다. 속성 문자열은 sources.esri.attribution, sources.here.attribution, source.grabmaptiles.attribution 키의 스타일 설명자 응답에 포함됩니다.

Tangram은 이러한 리소스를 요청하지 않으며 의 맵과만 호환되므로 “© 2020HERE”을 HERE사용합니다. 데이터 공급자와 함께 Amazon Location 리소스를 사용할 때는 서비스 이용 약관을 반드시 읽어보세요.

/** * Initialize a map. */ async function initializeMap() { // register the service worker to handle requests to https://amazon.location await registerServiceWorker(); // Initialize the map const map = L.map("map").setView([49.2819, -123.1187], 10); Tangram.leafletLayer({ scene, }).addTo(map); map.attributionControl.setPrefix(""); map.attributionControl.addAttribution("© 2020 HERE"); } initializeMap();

애플리케이션 실행

이 샘플을 실행하기 위해 다음을 수행할 수 있습니다.

  • HTTPS, 를 지원하는 호스트를 사용합니다.

  • 로컬 웹 서버를 사용하여 서비스 작업자 보안 제한 사항을 준수합니다.

로컬 웹 서버를 사용하려면 npx를 사용할 수 있습니다. npx는 Node.js 일부로 설치되기 때문입니다. index.htmlsw.js와 동일한 디렉터리 내에서 npx serve를 사용할 수 있습니다. 이는 localhost:5000에서 애플리케이션을 제공합니다.

index.html 파일은 다음과 같습니다.

<!-- index.html --> <html> <head> <link rel="stylesheet" href="https://unpkg.com/leaflet@1.7.1/dist/leaflet.css" integrity="sha512-xodZBNTC5n17Xt2atTPuE1HxjVMSvLVW9ocqUKLsCC5CXdbqCmblAshOMAS6/keqq/sMZMZ19scR4PsZChSR7A==" crossorigin="" /> <style> body { margin: 0; } #map { height: 100vh; } </style> </head> <body> <div id="map" /> <script src="https://unpkg.com/leaflet@1.7.1/dist/leaflet.js"></script> <script src="https://unpkg.com/tangram"></script> <script src="https://sdk.amazonaws.com/js/aws-sdk-2.784.0.min.js"></script> <script> // configuration // Cognito Identity Pool ID const identityPoolId = "<Identity Pool ID>"; // Amazon Location Service Map name; must be HERE-backed const mapName = "<Map name>"; AWS.config.region = identityPoolId.split(":")[0]; // instantiate a credential provider credentials = new AWS.CognitoIdentityCredentials({ IdentityPoolId: identityPoolId, }); const scene = { import: [ // Bubble Wrap style "https://www.nextzen.org/carto/bubble-wrap-style/10/bubble-wrap-style.zip", "https://www.nextzen.org/carto/bubble-wrap-style/10/themes/label-7.zip", "https://www.nextzen.org/carto/bubble-wrap-style/10/themes/bubble-wrap-road-shields-usa.zip", "https://www.nextzen.org/carto/bubble-wrap-style/10/themes/bubble-wrap-road-shields-international.zip", ], // override values beneath the `sources` key in the style above sources: { mapzen: { // point at Amazon Location using a synthetic URL, which will be handled by the service // worker url: `https://amazon.location/${mapName}/{z}/{x}/{y}`, }, // effectively disable raster tiles containing encoded normals normals: { max_zoom: 0, }, "normals-elevation": { max_zoom: 0, }, }, }; /** * Register a service worker that will rewrite and sign requests using Signature Version 4. */ async function registerServiceWorker() { if ("serviceWorker" in navigator) { try { const reg = await navigator.serviceWorker.register("./sw.js"); // refresh credentials from Amazon Cognito await credentials.refreshPromise(); await reg.active.ready; if (navigator.serviceWorker.controller == null) { // trigger a navigate event to active the controller for this page window.location.reload(); } // pass credentials to the service worker reg.active.postMessage({ credentials: { accessKeyId: credentials.accessKeyId, secretAccessKey: credentials.secretAccessKey, sessionToken: credentials.sessionToken, }, region: AWS.config.region, }); } catch (error) { console.error("Service worker registration failed:", error); } } else { console.warn("Service Worker support is required for this example"); } } /** * Initialize a map. */ async function initializeMap() { // register the service worker to handle requests to https://amazon.location await registerServiceWorker(); // Initialize the map const map = L.map("map").setView([49.2819, -123.1187], 10); Tangram.leafletLayer({ scene, }).addTo(map); map.attributionControl.setPrefix(""); map.attributionControl.addAttribution("© 2020 HERE"); } initializeMap(); </script> </body> </html>

sw.js 파일은 다음과 같습니다.

// sw.js self.importScripts( "https://unpkg.com/@aws-amplify/core@3.7.0/dist/aws-amplify-core.min.js" ); const { Signer } = aws_amplify_core; let credentials; let region; self.addEventListener("install", (event) => { // install immediately event.waitUntil(self.skipWaiting()); }); self.addEventListener("activate", (event) => { // control clients ASAP event.waitUntil(self.clients.claim()); }); self.addEventListener("message", (event) => { const { data: { credentials: newCredentials, region: newRegion }, } = event; if (newCredentials != null) { credentials = newCredentials; } if (newRegion != null) { region = newRegion; } }); async function signedFetch(request) { const url = new URL(request.url); const path = url.pathname.slice(1).split("/"); // update URL to point to Amazon Location url.pathname = `/maps/v0/maps/${path[0]}/tiles/${path.slice(1).join("/")}`; url.host = `maps.geo.${region}.amazonaws.com`; // strip params (Tangram generates an empty api_key param) url.search = ""; const signed = Signer.signUrl(url.toString(), { access_key: credentials.accessKeyId, secret_key: credentials.secretAccessKey, session_token: credentials.sessionToken, }); return fetch(signed); } self.addEventListener("fetch", (event) => { const { request } = event; // match the synthetic hostname we're telling Tangram to use if (request.url.includes("amazon.location")) { return event.respondWith(signedFetch(request)); } // fetch normally return event.respondWith(fetch(request)); });

이 샘플은 의 Amazon Location Service 샘플 리포지토리의 일부로 사용할 수 있습니다GitHub.