Toggle layers
The switches on the left are built from getLayers() - nothing about the map is typed into the page. Hide the map's own layer control with chrome, supply yours, and listen to visibilityChanged so your switches stay true when something else changes visibility.
What to notice
setLayerVisibilityfor one layer;setVisibilityfor several toggles in one call - what you leave out stays as it is.resetVisibility()returns to what the author published.getLayerStatscounts the features a layer holds after filters and slicers.- Visibility is the whole of it: the API never restyles a layer.
The code
The complete page. Swap in your own publish id, and ask the map's author to add your site to its allowed origins.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Toggle layers - Icon Map Embed API</title>
<link rel="stylesheet" href="https://www.icon-map.com/embed-examples/examples.css"> <!-- demo styling only -->
</head>
<body>
<div class="ex-main">
<div class="ex-side">
<h2>Layers</h2>
<div id="layers">loading...</div>
<h2>Presets</h2>
<div class="ex-chips">
<button id="density">Density only</button>
<button id="all">Everything</button>
<button id="reset">Author's default</button>
</div>
<h2>On the map now</h2>
<pre class="ex-readout" id="counts"></pre>
</div>
<div id="map"></div>
</div>
<script src="https://www.icon-map.com/js/iconmap-embed/2/iconmap-embed.umd.min.js"></script>
<script>
const el = document.getElementById("map");
const map = IconMapEmbed.embed(el, {
publishId: "pub_...",
// The map is a globe: let this page's own background show in the space around it.
background: "transparent",
// Hide the map's own layer control - this page supplies its own.
chrome: { layerControl: false, bookmarksBar: false, tourTransport: false },
visibility: { visuals: { "chart-continent": false, "slicer-continent": false, "slicer-size": false, "slicer-capital": false } },
events: ["visibilityChanged"],
});
map.ready.catch((error) => console.error(error.code, error.message));
const boxes = new Map();
// Build the switches from what the map reports, not from ids typed into this page.
map.getLayers().then((layers) => {
const host = document.getElementById("layers");
host.textContent = "";
for (const layer of layers.filter((l) => l.name !== "Megacity labels")) {
const row = document.createElement("label");
row.className = "ex-check";
const box = Object.assign(document.createElement("input"), { type: "checkbox", checked: layer.visible });
box.onchange = () => map.setLayerVisibility({ layerId: layer.id, visible: box.checked });
row.append(box, layer.name);
host.append(row);
boxes.set(layer.id, box);
}
showCounts();
});
// Several toggles in one call. Anything you leave out stays as it is.
document.getElementById("density").onclick = () =>
map.setVisibility({ layers: { countries: false, cities: false, capitals: false, density: true } });
document.getElementById("all").onclick = () =>
map.setVisibility({ layers: { countries: true, cities: true, capitals: true, density: true } });
// resetVisibility returns to what the AUTHOR published: cities and countries on, the other two off.
// They were OFF when the map was published and still have their data - publishing includes it.
document.getElementById("reset").onclick = () => map.resetVisibility();
// The reader can change visibility too (a bookmark, the map's own controls),
// so keep the switches honest from the event rather than from your own clicks.
map.on("visibilityChanged", ({ visibility }) => {
for (const [id, box] of boxes) if (id in (visibility.layers ?? {})) box.checked = visibility.layers[id];
showCounts();
});
async function showCounts() {
const lines = [];
for (const id of ["cities", "countries"]) {
const stats = await map.getLayerStats({ layerId: id });
lines.push(`${id.padEnd(10)} ${stats.visibleFeatureCount.toLocaleString()} features`);
}
document.getElementById("counts").textContent = lines.join("\n");
}
</script>
</body>
</html>