本文為英文版的機器翻譯版本,如內容有任何歧義或不一致之處,概以英文版為準。
Tangram
Tangram 建立在 Leaflet
使用來自 的映射時,為搭配 Tilezen 結構描述
-
Bubble Wrap
– 功能完整的尋路樣式,具有適用於興趣點的實用圖示 -
Cinnabar
– 一般映射應用程式的經典外觀和首選 -
補充
– 專為資料視覺化重疊所設計的極簡地圖樣式,其靈感來自 Stamen Design 的精實碳粉樣式 -
Tron
– 探索 視覺化語言的規模轉換 TRON -
Walkabout
– 專注於戶外的樣式,非常適合健行或出遊
本指南說明如何使用名為 Bubble Wrap
雖然其他 Tangram 樣式最好搭配編碼地形資訊的光柵圖磚,但 Amazon Location 尚不支援此功能。
重要
下列教學課程中的 Tangram 樣式僅與以 VectorHereContrast
樣式設定的 Amazon Location Map 資源相容。
建置應用程式:鷹架
應用程式是使用 的HTML頁面 JavaScript ,可在 Web 應用程式中建置地圖。建立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,設定身分驗證 中建立的未驗證身分集區,來即時化憑證提供者。由於這會在正常AWSSDK工作流程之外使用憑證,因此工作階段會在一小時後過期。
// 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),但它不包括攔截請求的功能,以便可以簽署。
若要解決此問題,請覆寫
sources.mapzen.url
以使用合成主機名稱 指向 Amazon Locationamazon.location
,該名稱將由服務工作者處理。以下是使用 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 第 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 位置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,
-
使用本機 Web 伺服器來遵守服務工作者安全限制。
若要使用本機 Web 伺服器,您可以使用 npx,因為它是 Node.js 的一部分。您可以在npx serve
與 index.html
和 相同的目錄中使用 sw.js
。這可在 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