Introdução
Esta página leva você de um mapa publicado a uma página que o controla. Ela supõe que um mapa já foi publicado e que você tem o ID de publicação dele (tem o formato pub_... e é a última parte da URL de incorporação).
1. Permita o seu site
Um mapa só aceita comandos de sites que o autor indicou. Peça ao autor que abra o mapa no Icon Map, escolha Publish e:
- Adicione seu site em Allowed origins: o esquema e o host de onde sua página é servida, por exemplo
https://portal.contoso.com. Um subdomínio curinga é permitido (https://*.contoso.com); um caminho não é. - Deixe Let the hosting page control this map from script (Embed API) ativado, assim como os grupos de comandos de que você precisa.
- Publique. As origens permitidas e as chaves dos grupos fazem parte da publicação assinada, então qualquer alteração exige uma nova publicação.
Durante o desenvolvimento, adicione também sua origem local, por exemplo http://localhost:5173. Uma origem é esquema + host + porta, portanto http://localhost:5173 e http://localhost:3000 são sites diferentes.
Se a sua origem não estiver na lista, o mapa ainda é exibido na sua página, só não pode ser controlado. map.ready é rejeitado com o código denied_origin, para que você descubra na hora em vez de ficar se perguntando por que nada acontece.
2. Instale o SDK
Carregue o SDK com uma tag de script. Ele define um único objeto global, IconMapEmbed:
<script src="https://www.icon-map.com/js/iconmap-embed/2/iconmap-embed.umd.min.js"></script>
<script>
const { embed } = IconMapEmbed;
</script>
O SDK tem cerca de 17 KB e nenhuma dependência. Funciona em qualquer lugar que aceite uma tag de script, incluindo páginas do SharePoint, do Confluence e de sistemas de CMS.
Um pacote npm (@iconmap/embed, com tipos TypeScript, para uso com um bundler) está a caminho. A API é a mesma; os trechos abaixo que usam import se aplicam quando ele for publicado. Até lá, use o objeto global IconMapEmbed.
3. Monte o mapa
Dê ao mapa um elemento com tamanho definido. O frame o preenche.
<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 é resolvido com o descritor de capacidades. Use-o para decidir o que sua página oferece:
const can = (name) => capabilities.commands.includes(name);
if (!can("setFilters")) hideMyFilterPanel();
Tome decisões com base nas capacidades, não em números de versão: a lista já considera a versão do visualizador, o tipo de incorporação e as chaves do autor.
4. Envie comandos
Cada comando é um método que retorna uma promise.
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"] } });
Você pode chamar comandos assim que tiver o handle. Tudo o que for enviado antes de o mapa terminar de iniciar fica retido e é respondido quando a parte do mapa de que precisa estiver disponível, então isto funciona:
const map = embed(el, { publishId });
await map.fitLayer({ layerId: "depots" }); // no need to wait for anything first
5. Escute eventos
Nada é enviado até que você peça.
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
Todo evento de estado traz um reason. Veja em Eventos por que isso importa.
6. Trate erros
Um comando rejeitado é um EmbedError com um code estável:
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;
}
}
Os códigos estão listados na referência e explicados em Erros e controle de versão.
Comece no lugar certo
Tudo o que você pode alterar em tempo de execução também pode ser definido quando o mapa é montado, para que o leitor nunca veja a vista padrão do autor aparecer primeiro:
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 aplica um dos indicadores do autor, e scene restaura uma vista que você capturou antes.
Mapas protegidos por token
Se o autor publicou o mapa exigindo tokens assinados, o seu servidor gera um token de curta duração com o segredo de incorporação da publicação, e a sua página o repassa. O segredo nunca deve chegar ao navegador.
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 é chamado na montagem e sempre que o mapa pede um novo token. tokenExpiring é disparado um minuto antes da expiração, para que você possa enviar um token novo com antecedência.
Se a geração do token for lenta, inicie o download primeiro e forneça o token quando o tiver:
const map = embed(el, { publishId: "pub_...", deferRender: true }); // frame starts loading now
const token = await mintToken();
map.render({ getToken: () => token });
Incorporação para sua organização
Para incorporar um mapa ao vivo para colegas conectados, troque o ponto de entrada. O handle é o mesmo.
const { embedForOrganization } = IconMapEmbed;
const map = embedForOrganization(el, {
mapItem: { workspaceId: "...", itemId: "..." },
getToken: (scopes) => myMsal.acquireTokenSilent({ scopes }).then((r) => r.accessToken),
});
getToken recebe os escopos de que o mapa precisa naquele momento (OneLake, Fabric e outros, conforme os dados do mapa) e retorna um token delegado para o usuário conectado. Se você omiti-lo, o mapa faz a própria entrada dentro do frame. Veja Incorporação para sua organização para a configuração completa.
Os sites autorizados a controlar uma incorporação organizacional são definidos no item do mapa, em Publish > Embedding for your organization. Por padrão, são os mesmos sites de Allowed origins da publicação ("Use the allowed origins above"), salvos com o mapa quando você publica, ou com Save origins se você nunca publicar. Desmarque a caixa para manter uma lista separada, por exemplo quando a cópia publicada pode ser incorporada por qualquer site, mas só a sua intranet pode controlar o mapa ao vivo por script.
Em uma incorporação organizacional, os filtros declarados e refreshData não existem (não aparecem em capabilities.commands), highlight responde unsupported_command (use setSelection), e exportImage / print são recusados com denied_capability quando o mapa ou qualquer uma de suas fontes de dados tem um rótulo de confidencialidade.
TypeScript
O pacote npm (em breve, veja a nota acima) inclui seus tipos, de modo que os comandos, seus argumentos e resultados e os payloads dos eventos são todos tipados:
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
Não há wrapper para instalar. O handle cabe em uma ref e em um 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 }} />;
}
Exemplos ao vivo
Os exemplos são mapas ao vivo que você pode usar, cada um seguido da página completa que o produz: câmera, camadas, segmentações, filtros, seleção e realce, cenas e tours, mudança de estilo, comandos de pop-up e eventos.
Solução de problemas
| Sintoma | Causa |
|---|---|
ready é rejeitado com denied_origin |
A origem da sua página não está nas origens permitidas do mapa, ou o mapa não foi publicado de novo depois que ela foi adicionada. Confira o esquema, o host e a porta exatos. |
O frame fica em branco e o console informa uma violação de frame-ancestors |
A mesma lista de origens permitidas também controla quais sites podem exibir o mapa em um frame. Adicione sua origem e publique de novo. |
ready é resolvido, mas commands está quase vazio |
O autor desativou a Embed API (ou a maioria dos grupos) para esta publicação. |
Um comando é rejeitado com denied_capability |
O grupo desse comando está desativado para este mapa. |
Um comando é rejeitado com unsupported_command |
O mapa, ou este tipo de incorporação, não tem esse comando. Verifique capabilities.commands antes de oferecer o recurso. |
| Os comandos atingem o tempo limite | O frame não carregou. Veja onError e a guia de rede. |