기계 번역으로 제공되는 번역입니다. 제공된 번역과 원본 영어의 내용이 상충하는 경우에는 영어 버전이 우선합니다.
Amazon Location Service로 Tangram 사용
Tangram
Tangram은 모바일 친화적 대화형 맵을 위한 오픈 소스 JavaScript 라이브러리인 리플릿
Tilezen 스키마
-
Bubble Wrap
– 모든 기능을 갖춘 길 찾기 스타일로, 관심 지점을 표시하는 유용한 아이콘이 포함되어 있습니다. -
Cinnabar
– 클래식한 디자인으로 일반 매핑 애플리케이션에 적합합니다. -
Refill
– Stamen Design의 획기적인 Toner 스타일에서 영감을 받아 데이터 시각화 오버레이를 위해 디자인된 미니멀한 맵 스타일입니다. -
Tron
- 의 시각적 언어로 스케일 변환 탐색 TRON -
Walkabout
– 야외 활동에 초점을 맞춘 스타일로 하이킹이나 야외 활동에 안성맞춤입니다.
이 안내서에서는 Bubble Wrap
다른 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 코드를 작성하는 방법을 안내합니다.
애플리케이션 빌드: 구성
리소스 및 보안 인증 정보로 애플리케이션을 구성하려면
-
리소스의 이름과 식별자를 입력합니다.
// 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단계, 인증 설정에서 생성한 인증되지 않은 자격 증명 풀을 사용하여 보안 인증 정보 공급자를 인스턴스화합니다. 이 작업은 정상 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
, }); -
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()); }
애플리케이션 빌드: 맵 초기화
페이지가 로드된 후 맵을 표시하려면 맵을 초기화해야 합니다. 초기 맵 위치를 조정하고, 컨트롤을 추가하고, 데이터를 오버레이할 수 있습니다.
참고
/** * 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.html
및 sw.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