Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions web-standalone/changelog.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
[
{
"id": "2026-09-07-map-layers",
"date": "2026-09-07",
"title": "Ranges, links and heat can be switched off",
"body": "Once a cluster is locked, three chips above the map switch the range polygons, the proven links (with their arrows and support nodes) and the heat on or off. On a phone the ranges and links start off, because on a small map they covered the answer in one pink wash; the clue zone, the tied region and the observers always stay."
},
{
"id": "2026-09-07-easier-on-a-phone",
"date": "2026-09-07",
Expand Down
59 changes: 59 additions & 0 deletions web-standalone/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,19 @@
/* Meta/product actions (help, changelog) sit apart from the map actions
so they don't read as part of the Step 1-3 task flow. The first one
opens the right-aligned group; the rest follow it. */
/* Layer switch (#119): the evidence layers can be turned off, and start
off on a narrow screen where they hide the answer. */
.layer-chips {
display: inline-flex;
gap: 6px;
}
.layer-chips[hidden] {
display: none;
}
.controls-card .layer-chip {
padding: 6px 10px;
font-size: 0.78rem;
}
/* The help and What's new buttons stay together at the right, and wrap
as one unit. Wrapping them separately left the bell alone at the far
left of a second row on a phone, with the panel anchored to it opening
Expand Down Expand Up @@ -1477,6 +1490,11 @@ <h3>Unknown Node Estimate</h3>
<button id="clear-map-button" type="button" class="button-muted">Clear Map</button>
<button id="manual-mode-button" type="button" class="button-secondary" aria-pressed="false" hidden>Resolve on map</button>
<button id="share-button" type="button" class="button-secondary">Share</button>
<div id="layer-chips" class="layer-chips" role="group" aria-label="Map layers" hidden>
<button type="button" class="button-muted layer-chip" data-layer="ranges" aria-pressed="true">Ranges</button>
<button type="button" class="button-muted layer-chip" data-layer="links" aria-pressed="true">Links</button>
<button type="button" class="button-muted layer-chip" data-layer="heat" aria-pressed="true">Heat</button>
</div>
<div class="controls-meta">
<button id="intro-open-button" type="button" class="button-muted is-icon" aria-label="How this works" title="How this works">?</button>
<div class="whats-new">
Expand Down Expand Up @@ -1768,6 +1786,9 @@ <h3>Unknown Node Estimate</h3>
manualModeButton.hidden = !hasRegion;
if (!hasRegion && manualMode) setManualMode(false);
}
// Same rule as the manual-mode button: the evidence layers exist once
// a cluster is locked, so the switch appears with them (#119).
if (layerChips) layerChips.hidden = !hasRegion;
}

// ── Share link (#34) ────────────────────────────────────────────────────
Expand Down Expand Up @@ -1905,6 +1926,43 @@ <h3>Unknown Node Estimate</h3>
element.scrollIntoView({ block: "start" });
}

// ── Layer switch (#119) ─────────────────────────────────────────────────
// Ranges, links (with their arrows and support nodes) and heat can be
// switched off. The clue zone and the tied region are always on: they
// are the answer, the others are the evidence. On a narrow screen the
// evidence starts off, since 13 range polygons and 100 proven links on a
// 380 px map hide the answer under a pink wash. Session only.
const LAYER_GROUPS = {
ranges: ["t3d-ranges-fill", "t3d-ranges-line"],
links: ["t3d-links-line", "t3d-links-arrow", "t3d-support-circle"],
heat: ["t3d-heat-fill"]
};
const layerChips = document.getElementById("layer-chips");
const layerVisible = { ranges: !narrowScreen(), links: !narrowScreen(), heat: true };

function applyLayerVisibility() {
if (layerChips) {
layerChips.querySelectorAll(".layer-chip").forEach((chip) => {
chip.setAttribute("aria-pressed", layerVisible[chip.dataset.layer] ? "true" : "false");
});
}
if (!map3d || !map3d.getStyle()) return;
Object.entries(LAYER_GROUPS).forEach(([group, ids]) => {
ids.forEach((id) => {
if (map3d.getLayer(id)) map3d.setLayoutProperty(id, "visibility", layerVisible[group] ? "visible" : "none");
});
});
}

if (layerChips) {
layerChips.addEventListener("click", (event) => {
const chip = event.target.closest(".layer-chip");
if (!chip) return;
layerVisible[chip.dataset.layer] = !layerVisible[chip.dataset.layer];
applyLayerVisibility();
});
}

function fitMapToNodes(nodesList) {
if (!nodesList.length || !map3d) {
return;
Expand Down Expand Up @@ -5020,6 +5078,7 @@ <h3>Unknown Node Estimate</h3>
}

function add3dInteractions(m) {
applyLayerVisibility();
const clickable = [
"t3d-links-line", "t3d-obs-circle", "t3d-candidates-fill",
"t3d-candidate-pts-circle", "t3d-manual-circle", "t3d-est-circle",
Expand Down
Loading