Usando o Tangram com o Amazon Location Service - Amazon Location Service

As traduções são geradas por tradução automática. Em caso de conflito entre o conteúdo da tradução e da versão original em inglês, a versão em inglês prevalecerá.

Usando o Tangram com o Amazon Location Service

O Tangram é um mecanismo de mapeamento flexível, projetado para renderização em tempo real de mapas 2D e 3D a partir de blocos vetoriais. Ele pode ser usado com estilos projetados pelo MapZen e os blocos HERE fornecidos pela API de mapas do Amazon Location Service. Este guia descreve como integrar o Tangram com o Amazon Location em um JavaScript aplicativo HTML/ básico, embora as mesmas bibliotecas e técnicas também se apliquem ao usar estruturas como React e Angular.

O Tangram é construído sobre o Leaflet, uma JavaScript biblioteca de código aberto para mapas interativos compatíveis com dispositivos móveis. Isso significa que muitos plug-ins e controles compatíveis com o Leaflet também funcionam com o Tangram.

Os estilos do Tangram criados para funcionar com o esquema Tilezen são amplamente compatíveis com o Amazon Location ao usar mapas da HERE. Isso inclui:

  • Bubble Wrap — Um estilo de orientação completo com ícones úteis para pontos de interesse

  • Cinnabar — Um visual clássico e ideal para aplicações gerais de mapeamento

  • Refill — Um estilo de mapa minimalista projetado para sobreposições de visualização de dados, inspirado no estilo seminal de Toner da Stamen Design

  • Tron — Uma exploração das transformações de escala na linguagem visual de TRON

  • Walkabout — Um estilo voltado para atividades ao ar livre que é perfeito para caminhar ou passear

Este guia descreve como integrar o Tangram com o Amazon Location em um JavaScript aplicativo HTML/básico usando o estilo Tangram chamado Bubble Wrap. Essa amostra está disponível como parte do repositório de amostras do Amazon Location Service em GitHub.

Embora outros estilos do Tangram sejam melhor acompanhados por blocos Raster, que codificam informações sobre o terreno, esse atributo ainda não é suportado pelo Amazon Location.

Importante

Os estilos do Tangram no tutorial a seguir são compatíveis somente com os recursos de mapa do Amazon Location configurados com o estilo VectorHereContrast.

Construindo o aplicativo: estrutura

O aplicativo é uma página HTML JavaScript para criar o mapa em seu aplicativo web. Crie uma página HTML (index.html) e crie o contêiner do mapa:

  • Insira um elemento div com um id de mapa para aplicar as dimensões do mapa à visualização do mapa.

  • As dimensões são herdadas da janela de exibição.

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

Construindo o aplicativo: adicionando dependências

Adicione a seguinte dependência:

  • Folheto e seu CSS associado.

  • Tangram.

  • SDK da AWS para 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>

Isso cria uma página vazia com os pré-requisitos necessários. A próxima etapa orienta você na criação do JavaScript código para seu aplicativo.

Construindo o aplicativo: configuração

Para configurar seu aplicativo com seus recursos e credenciais:

  1. Insira os nomes e identificadores dos seus recursos.

    // 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. Instancie um provedor de credenciais usando o banco de identidade não autenticado que você criou em Usando mapas – Etapa 2, Configurar a autenticação. Como isso usa credenciais fora do fluxo de trabalho normal do SDK da AWS, as sessões expiram depois de uma hora.

    // 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. Embora o Tangram permita que você substitua o(s) URL(s) usados para buscar blocos, ele não inclui a capacidade de interceptar solicitações para que elas possam ser assinadas.

    Para contornar isso, substitua sources.mapzen.url para apontar para o Amazon Location usando um nome de host sintético amazon.location, que será gerenciado por um Service Worker. Veja a seguir um exemplo de configuração de cena usando o 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, }, }, };

Construindo o aplicativo: Solicitar transformação

Para registrar e inicializar o Service Worker, crie uma função registerServiceWorker a ser chamada antes que o mapa seja inicializado. Isso registra o JavaScript código fornecido em um arquivo separado chamado sw.js de controle index.html do service worker.

As credenciais são carregadas do Amazon Cognito e passadas para o Service Worker junto com a região para fornecer informações para assinar solicitações de blocos com o Signature versão 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"); } }

A implementação do Service Worker sw.js escuta os eventos do message para coletar as alterações nas credenciais e na configuração da região. Ele também atua como um servidor proxy, ouvindo eventos fetch. Eventos fetch direcionados ao nome de host sintético amazon.location serão reescritos para atingir a API do Amazon Location apropriada e assinados usando o Signer do Amplify Core.

// 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)); });

Para renovar automaticamente as credenciais e enviá-las ao Service Worker antes que elas expirem, use a seguinte função com 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()); }

Construindo o aplicativo: Inicialização do mapa

Para que o mapa seja exibido após o carregamento da página, você deve inicializar o mapa. Você tem a opção de ajustar a localização inicial do mapa, adicionar controles adicionais e sobrepor dados.

nota

Você deve fornecer uma marca nominativa ou atribuição de texto para cada provedor de dados que você usa, seja em seu aplicativo ou em sua documentação. As strings de atribuição estão incluídas na resposta do descritor de estilo sob as teclas sources.esri.attribution, sources.here.attribution e source.grabmaptiles.attribution.

Como o Tangram não solicita esses recursos e só é compatível com mapas da HERE, use “© 2020 HERE”. Ao usar os recursos do Amazon Location com provedores de dados, certifique-se de ler os termos e condições do serviço.

/** * 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();

Executando o aplicativo

Para executar esse exemplo, você pode:

  • Usar um host que ofereça suporte a HTTPS,

  • Use um servidor da web local para cumprir as restrições de segurança do Service Worker.

Para usar um servidor da web local, você pode usar o npx, porque ele é instalado como parte do Node.js. Você pode usar npx serve de dentro do mesmo diretório que index.html e sw.js. Isso serve ao aplicativo em localhost:5000.

A seguir está o arquivo 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>

A seguir está o arquivo 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)); });

Essa amostra está disponível como parte do repositório de amostras do Amazon Location Service em GitHub.