Prise en main
Cette page vous mène d'une carte publiée à une page qui la pilote. Elle suppose qu'une carte a déjà été publiée et que vous disposez de son identifiant de publication (il ressemble à pub_... et constitue la dernière partie de l'URL d'incorporation).
1. Autoriser votre site
Une carte n'accepte de commandes que des sites désignés par son auteur. Demandez à l'auteur d'ouvrir la carte dans Icon Map, de choisir Publish, puis :
- D'ajouter votre site dans Allowed origins : le schéma et l'hôte depuis lesquels votre page est servie, par exemple
https://portal.contoso.com. Un sous-domaine générique est autorisé (https://*.contoso.com) ; un chemin ne l'est pas. - De laisser Let the hosting page control this map from script (Embed API) activé, ainsi que les groupes de commandes dont vous avez besoin.
- De publier. Les origines autorisées et les réglages de groupes font partie de la publication signée : toute modification nécessite donc une nouvelle publication.
Pendant le développement, ajoutez aussi votre origine locale, par exemple http://localhost:5173. Une origine est composée du schéma, de l'hôte et du port : http://localhost:5173 et http://localhost:3000 sont donc des sites différents.
Si votre origine est absente, la carte s'affiche quand même dans votre page, mais elle ne peut pas être pilotée. map.ready est rejetée avec le code denied_origin, ce qui vous permet de le savoir immédiatement au lieu de vous demander pourquoi rien ne se passe.
2. Installer le SDK
Chargez le SDK avec une balise script. Il définit une seule variable globale, IconMapEmbed :
<script src="https://www.icon-map.com/js/iconmap-embed/2/iconmap-embed.umd.min.js"></script>
<script>
const { embed } = IconMapEmbed;
</script>
Le SDK pèse environ 17 KB et n'a aucune dépendance. Il fonctionne partout où une balise script fonctionne, y compris dans les pages SharePoint, Confluence et de CMS.
Un package npm (@iconmap/embed, avec des types TypeScript, à utiliser avec un bundler) est en préparation. L'API est la même ; les extraits ci-dessous qui utilisent import s'appliqueront une fois le package publié. D'ici là, utilisez la variable globale IconMapEmbed.
3. Monter la carte
Donnez à la carte un élément qui a une taille. Le cadre le remplit.
<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 se résout avec le descripteur de capacités. Utilisez-le pour décider de ce que votre page propose :
const can = (name) => capabilities.commands.includes(name);
if (!can("setFilters")) hideMyFilterPanel();
Basez vos choix sur les capacités, pas sur les numéros de version : la liste tient déjà compte de la version de la visionneuse, du type d'incorporation et des réglages de l'auteur.
4. Envoyer des commandes
Chaque commande est une méthode qui renvoie une promesse.
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"] } });
Vous pouvez appeler des commandes dès que vous avez le handle. Tout ce qui est envoyé avant la fin du démarrage de la carte est mis en attente et traité dès que la partie de la carte nécessaire existe. Ceci fonctionne donc :
const map = embed(el, { publishId });
await map.fitLayer({ layerId: "depots" }); // no need to wait for anything first
5. Écouter les événements
Rien n'est envoyé tant que vous ne le demandez pas.
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
Chaque événement d'état porte une reason : voir Événements pour comprendre pourquoi c'est important.
6. Gérer les erreurs
Une commande rejetée produit une EmbedError avec un code stable :
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;
}
}
Les codes sont listés dans la référence et expliqués dans Erreurs et gestion des versions.
Démarrer au bon endroit
Tout ce que vous pouvez modifier à l'exécution peut aussi être défini au montage de la carte, afin que le lecteur ne voie jamais apparaître brièvement la vue par défaut de l'auteur :
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 applique l'un des signets de l'auteur, et scene restaure une vue que vous avez capturée auparavant.
Cartes protégées par jeton
Si l'auteur a publié la carte en exigeant des jetons signés, votre serveur génère un jeton de courte durée à l'aide du secret d'incorporation de la publication, et votre page le transmet. Le secret ne doit jamais atteindre le navigateur.
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 est appelé au montage et chaque fois que la carte demande un nouveau jeton. tokenExpiring est déclenché une minute avant l'expiration, ce qui vous permet de fournir un nouveau jeton à l'avance.
Si la génération du jeton est lente, lancez d'abord le téléchargement et fournissez le jeton dès que vous l'avez :
const map = embed(el, { publishId: "pub_...", deferRender: true }); // frame starts loading now
const token = await mintToken();
map.render({ getToken: () => token });
Incorporation pour votre organisation
Pour incorporer une carte en direct destinée à des collègues connectés, changez de point d'entrée. Le handle est le même.
const { embedForOrganization } = IconMapEmbed;
const map = embedForOrganization(el, {
mapItem: { workspaceId: "...", itemId: "..." },
getToken: (scopes) => myMsal.acquireTokenSilent({ scopes }).then((r) => r.accessToken),
});
getToken reçoit les étendues dont la carte a besoin à ce moment-là (OneLake, Fabric et d'autres selon les données de la carte) et renvoie un jeton délégué pour l'utilisateur connecté. Si vous l'omettez, la carte gère sa propre connexion à l'intérieur du cadre. Consultez Incorporation pour votre organisation pour la configuration complète.
Les sites autorisés à piloter une incorporation organisationnelle se définissent sur l'élément de carte, dans Publish > Embedding for your organization. Par défaut, ce sont les mêmes sites que les Allowed origins de la publication (« Use the allowed origins above »), enregistrés avec la carte lors de la publication, ou avec Save origins si vous ne publiez jamais. Décochez la case pour conserver une liste distincte, par exemple lorsque la copie publiée peut être incorporée par n'importe quel site, mais que seul votre intranet peut piloter la carte en direct par script.
Sur une incorporation organisationnelle, les filtres déclarés et refreshData n'existent pas (ils sont absents de capabilities.commands), highlight répond unsupported_command (utilisez setSelection), et exportImage / print sont refusées avec denied_capability lorsque la carte ou l'une de ses sources de données porte une étiquette de confidentialité.
TypeScript
Le package npm (à venir, voir la remarque ci-dessus) inclut ses types : les commandes, leurs arguments et résultats, ainsi que les charges utiles des événements sont tous typés :
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
Aucun wrapper à installer : le handle s'intègre dans une ref et un effet :
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 }} />;
}
Exemples en direct
Les exemples sont des cartes en direct que vous pouvez manipuler, chacune suivie de la page complète qui la produit : caméra, couches, segments, filtres, sélection et mise en surbrillance, scènes et visites, changement de style, commandes de fenêtre contextuelle et événements.
Résolution des problèmes
| Symptôme | Cause |
|---|---|
ready est rejetée avec denied_origin |
L'origine de votre page ne figure pas parmi les origines autorisées de la carte, ou la carte n'a pas été republiée après son ajout. Vérifiez exactement le schéma, l'hôte et le port. |
Le cadre est vide et la console signale une violation de frame-ancestors |
La même liste d'origines autorisées détermine aussi quels sites peuvent encadrer la carte. Ajoutez votre origine et republiez. |
ready se résout, mais commands est presque vide |
L'auteur a désactivé l'API Embed (ou la plupart des groupes) pour cette publication. |
Une commande est rejetée avec denied_capability |
Le groupe de cette commande est désactivé pour cette carte. |
Une commande est rejetée avec unsupported_command |
La carte, ou ce type d'incorporation, ne la propose pas. Vérifiez capabilities.commands avant de proposer la fonctionnalité. |
| Les commandes expirent | Le cadre n'a pas pu se charger : consultez onError et l'onglet réseau. |