Erste Schritte
Diese Seite führt Sie von einer veröffentlichten Karte zu einer Seite, die sie steuert. Sie setzt voraus, dass eine Karte bereits veröffentlicht wurde und Sie ihre Publish-ID kennen (sie sieht aus wie pub_... und ist der letzte Teil der Einbettungs-URL).
1. Ihre Website zulassen
Eine Karte nimmt Befehle nur von Websites an, die ihr Autor angegeben hat. Bitten Sie den Autor, die Karte in Icon Map zu öffnen, Publish zu wählen und dann:
- Ihre Website unter Allowed origins hinzuzufügen: das Schema und den Host, von dem Ihre Seite ausgeliefert wird, zum Beispiel
https://portal.contoso.com. Eine Platzhalter-Subdomain ist erlaubt (https://*.contoso.com), ein Pfad nicht. - Let the hosting page control this map from script (Embed API) aktiviert zu lassen, ebenso die Befehlsgruppen, die Sie benötigen.
- Zu veröffentlichen. Zulässige Ursprünge und die Gruppenschalter sind Teil der signierten Veröffentlichung, eine Änderung erfordert daher eine erneute Veröffentlichung.
Fügen Sie während der Entwicklung auch Ihren lokalen Ursprung hinzu, zum Beispiel http://localhost:5173. Ein Ursprung besteht aus Schema, Host und Port, daher sind http://localhost:5173 und http://localhost:3000 unterschiedliche Websites.
Fehlt Ihr Ursprung, wird die Karte in Ihrer Seite trotzdem angezeigt, sie lässt sich nur nicht steuern. map.ready wird mit dem Code denied_origin abgelehnt, sodass Sie es sofort bemerken, statt sich zu wundern, warum nichts passiert.
2. Das SDK installieren
Laden Sie das SDK mit einem Script-Tag. Es definiert eine globale Variable, IconMapEmbed:
<script src="https://www.icon-map.com/js/iconmap-embed/2/iconmap-embed.umd.min.js"></script>
<script>
const { embed } = IconMapEmbed;
</script>
Das SDK ist etwa 17 KB groß und hat keine Abhängigkeiten. Es funktioniert überall, wo ein Script-Tag funktioniert, auch in SharePoint, Confluence und CMS-Seiten.
Ein npm-Paket (@iconmap/embed, mit TypeScript-Typen, für die Verwendung mit einem Bundler) ist in Vorbereitung. Die API ist dieselbe; die Snippets unten, die import verwenden, gelten, sobald es veröffentlicht ist. Bis dahin verwenden Sie die globale Variable IconMapEmbed.
3. Die Karte einbinden
Geben Sie der Karte ein Element mit einer Größe. Der Frame füllt es aus.
<div id="map" style="height: 600px"></div>
const map = embed(document.getElementById("map"), {
publishId: "pub_...",
onError: (e) => console.error(e.code, e.message),
});
const capabilities = await map.ready;
console.log(capabilities.commands); // exactly what THIS map answers
ready wird mit dem Capability-Deskriptor aufgelöst. Entscheiden Sie anhand dessen, was Ihre Seite anbietet:
const can = (name) => capabilities.commands.includes(name);
if (!can("setFilters")) hideMyFilterPanel();
Verzweigen Sie anhand der Capabilities, nicht anhand von Versionsnummern: Die Liste berücksichtigt bereits den Viewer-Build, die Art der Einbettung und die Schalter des Autors.
4. Befehle senden
Jeder Befehl ist eine Methode, die ein Promise zurückgibt.
await map.flyTo({ center: [-3.18, 51.48], zoom: 12 });
const layers = await map.getLayers();
await map.setLayerVisibility({ layerId: layers[0].id, visible: false });
await map.setSlicerState({ slicerId: "slicer-region", state: { values: ["Wales"] } });
Sie können Befehle aufrufen, sobald Sie das Handle haben. Alles, was gesendet wird, bevor die Karte vollständig gestartet ist, wird zurückgehalten und beantwortet, sobald der benötigte Teil der Karte existiert. Das hier ist also in Ordnung:
const map = embed(el, { publishId });
await map.fitLayer({ layerId: "depots" }); // no need to wait for anything first
5. Auf Ereignisse reagieren
Es wird nichts gesendet, bis Sie es anfordern.
const stop = map.on("featureClick", (feature) => {
if (!feature) return; // a click on empty map
showDetails(feature.layerName, feature.fields, feature.featureKey);
});
map.on("viewChanged", (view) => {
if (view.reason === "user") saveLastView(view); // ignore moves your own code caused
});
stop(); // unsubscribe
Jedes Zustandsereignis enthält einen reason. Warum das wichtig ist, erfahren Sie unter Ereignisse.
6. Fehler behandeln
Ein abgelehnter Befehl ist ein EmbedError mit einem stabilen code:
const { EmbedError } = IconMapEmbed;
try {
await map.setFilters({ region: ["EMEA"], colour: "red" });
} catch (e) {
if (e instanceof EmbedError && e.code === "undeclared_filter") {
console.warn("not a filter on this map:", e.detail.undeclared);
} else {
throw e;
}
}
Die Codes sind in der Referenz aufgeführt und unter Fehler und Versionierung erklärt.
Am richtigen Ort starten
Alles, was Sie zur Laufzeit ändern können, können Sie auch beim Einbinden der Karte festlegen. So sieht der Betrachter nie zuerst kurz die Standardansicht des Autors:
embed(el, {
publishId: "pub_...",
filters: { region: ["EMEA"] },
view: { center: [2.35, 48.85], zoom: 9 },
visibility: { layers: { depots: false } },
basemapId: "slate",
theme: { mode: "dark" },
language: "fr",
chrome: { legend: false, layerControl: false },
background: "transparent",
hyperlinkBehavior: "raiseEvent",
events: ["featureClick", "linkClicked"],
});
bookmarkId wendet eines der Lesezeichen des Autors an, und scene stellt eine Ansicht wieder her, die Sie zuvor erfasst haben.
Karten mit Token-Schutz
Hat der Autor die Karte mit erforderlichen signierten Tokens veröffentlicht, erzeugt Ihr Server mit dem Einbettungsgeheimnis der Veröffentlichung ein kurzlebiges Token, und Ihre Seite übergibt es. Das Geheimnis darf nie in den Browser gelangen.
const map = embed(el, {
publishId: "pub_...",
getToken: () => fetch("/api/iconmap-token").then((r) => r.text()),
});
map.on("tokenExpiring", async () => {
await map.setToken({ token: await fetch("/api/iconmap-token").then((r) => r.text()) });
});
getToken wird beim Einbinden aufgerufen und immer dann, wenn die Karte ein neues Token anfordert. tokenExpiring wird eine Minute vor dem Ablauf ausgelöst, damit Sie rechtzeitig ein frisches Token übergeben können.
Wenn das Erzeugen des Tokens lange dauert, starten Sie zuerst den Download und liefern das Token nach, sobald Sie es haben:
const map = embed(el, { publishId: "pub_...", deferRender: true }); // frame starts loading now
const token = await mintToken();
map.render({ getToken: () => token });
Einbetten für Ihre Organisation
Um eine Live-Karte für angemeldete Kollegen einzubetten, tauschen Sie den Einstiegspunkt aus. Das Handle bleibt dasselbe.
const { embedForOrganization } = IconMapEmbed;
const map = embedForOrganization(el, {
mapItem: { workspaceId: "...", itemId: "..." },
getToken: (scopes) => myMsal.acquireTokenSilent({ scopes }).then((r) => r.accessToken),
});
getToken erhält die Bereiche (Scopes), die die Karte gerade benötigt (OneLake, Fabric und je nach Daten der Karte weitere), und gibt ein delegiertes Token für den angemeldeten Benutzer zurück. Lassen Sie es weg, führt die Karte ihre eigene Anmeldung im Frame durch. Die vollständige Einrichtung finden Sie unter Einbetten für Ihre Organisation.
Die Websites, die eine organisationsinterne Einbettung steuern dürfen, werden am Kartenelement unter Publish > Embedding for your organization festgelegt. Standardmäßig sind es dieselben Websites wie die Allowed origins der Veröffentlichung („Use the allowed origins above“). Sie werden beim Veröffentlichen mit der Karte gespeichert oder mit Save origins, falls Sie nie veröffentlichen. Deaktivieren Sie das Kontrollkästchen, um eine separate Liste zu führen, zum Beispiel wenn die veröffentlichte Kopie von jeder Website eingebettet werden darf, die Live-Karte aber nur von Ihrem Intranet per Skript gesteuert werden soll.
Bei einer organisationsinternen Einbettung gibt es keine deklarierten Filter und kein refreshData (sie fehlen in capabilities.commands), highlight antwortet mit unsupported_command (verwenden Sie setSelection), und exportImage / print werden mit denied_capability abgelehnt, wenn die Karte oder eine ihrer Datenquellen eine Vertraulichkeitsbezeichnung trägt.
TypeScript
Das npm-Paket (in Vorbereitung, siehe Hinweis oben) bringt seine Typen mit. Befehle, ihre Argumente und Ergebnisse sowie die Nutzdaten der Ereignisse sind also durchgehend typisiert:
import { embed, type EmbedHandle, type EmbedScene, type EmbedFeatureClick } from "@iconmap/embed";
const map: EmbedHandle = embed(el, { publishId });
const scene = (await map.captureScene()) as EmbedScene;
map.on("featureClick", (f: EmbedFeatureClick | null) => { /* ... */ });
React
Es gibt keinen Wrapper zu installieren: Das Handle passt in eine Ref und einen Effect.
function IconMap({ publishId, filters, onFeatureClick }) {
const el = useRef(null);
const map = useRef(null);
useEffect(() => {
map.current = embed(el.current, { publishId, filters });
const stop = map.current.on("featureClick", onFeatureClick);
return () => { stop(); map.current.destroy(); };
}, [publishId]);
useEffect(() => { map.current?.setFilters(filters).catch(console.error); }, [filters]);
return <div ref={el} style={{ height: 600 }} />;
}
Live-Beispiele
Die Beispiele sind Live-Karten zum Ausprobieren, jeweils gefolgt von der vollständigen Seite, die sie erzeugt: Kamera, Ebenen, Datenschnitte, Filter, Auswahl und Hervorhebung, Szenen und Touren, Umgestaltung, Popup-Befehle und Ereignisse.
Fehlerbehebung
| Symptom | Ursache |
|---|---|
ready wird mit denied_origin abgelehnt |
Der Ursprung Ihrer Seite steht nicht unter den zulässigen Ursprüngen der Karte, oder die Karte wurde nach dem Hinzufügen nicht erneut veröffentlicht. Prüfen Sie Schema, Host und Port genau. |
Der Frame ist leer, und die Konsole meldet einen Verstoß gegen frame-ancestors |
Dieselbe Liste zulässiger Ursprünge legt auch fest, welche Websites die Karte in einem Frame einbinden dürfen. Fügen Sie Ihren Ursprung hinzu und veröffentlichen Sie erneut. |
ready wird aufgelöst, aber commands ist fast leer |
Der Autor hat die Embed API (oder die meisten Gruppen) für diese Veröffentlichung deaktiviert. |
Ein Befehl wird mit denied_capability abgelehnt |
Die Gruppe dieses Befehls ist für diese Karte deaktiviert. |
Ein Befehl wird mit unsupported_command abgelehnt |
Die Karte oder diese Art der Einbettung bietet ihn nicht. Prüfen Sie capabilities.commands, bevor Sie die Funktion anbieten. |
| Befehle laufen in ein Timeout | Der Frame konnte nicht geladen werden. Sehen Sie sich onError und den Netzwerk-Tab an. |