feat(web): add POI visibility checkbox to terrain popup
All checks were successful
CI / lint (push) Successful in 4s
CI / test (push) Successful in 5s
CI / build (push) Successful in 15s
CI / lint (pull_request) Successful in 4s
CI / test (pull_request) Successful in 4s
CI / build (pull_request) Successful in 3s

Adds a «POI» checkbox to the terrain popup that toggles the
poi-circles and poi-labels layers via map.setLayoutProperty. The
choice is persisted in localStorage (key `poi-visible`) and restored
on page load and after style changes, kept consistent with the
runtime layerState.poi per ADR-0001.

Tests: behavioral JS unit tests (TP-01..TP-04) run via `node --test`,
wrapped by tests/unit/test_poi_toggle.py with static structure checks
so they execute under the existing `pytest tests/` CI step.

Refs: ET-002

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-21 15:50:54 +00:00
parent af579f7f2a
commit 8c17a4f508
5 changed files with 396 additions and 1 deletions

View File

@@ -128,7 +128,8 @@ function rebuildMapOverlays() {
// Re-apply terrain and trails after style change
restoreTerrainState();
restoreTrailsState();
restorePoiState();
// Re-apply recon circle if active
if (reconMode && reconCenter) {
doRecon(reconCenter[0], reconCenter[1]);
@@ -2796,6 +2797,62 @@ function restoreTrailsState() {
}
}
// >>> ET-002 POI visibility block (do not remove markers — used by unit tests) >>>
// Видимость POI (слои poi-circles, poi-labels) управляется чекбоксом
// «POI» в попапе рельефа. Состояние хранится в localStorage под ключом
// 'poi-visible' ('1'/'0'). Источник истины в рантайме — layerState.poi.
// См. docs/work-items/ET-002/06-adr/adr-0001-poi-visibility-client-side.md
/**
* Применяет видимость группы слоёв POI и синхронизирует layerState.poi.
*
* Единый приватный хелпер: переиспользуется чекбоксом попапа
* (onPoiCheckbox) и восстановлением состояния при загрузке/смене стиля
* (restorePoiState). Не пишет в localStorage — персистентность остаётся
* ответственностью обработчика чекбокса.
*
* @param {boolean} visible - true — показать POI, false — скрыть.
*/
function applyPoiVisibility(visible) {
layerState.poi = visible;
const map = window._map;
if (!map) return;
const visibility = visible ? 'visible' : 'none';
layerGroups.poi.forEach(id => {
if (map.getLayer(id)) {
map.setLayoutProperty(id, 'visibility', visibility);
}
});
}
/**
* Обработчик чекбокса «POI» в попапе рельефа (атрибут onchange).
*
* Сохраняет выбор в localStorage ('poi-visible': '1' видимы | '0' скрыты)
* и применяет видимость слоёв POI через applyPoiVisibility().
*/
function onPoiCheckbox() {
const checked = document.getElementById('poi-visible-cb').checked;
localStorage.setItem('poi-visible', checked ? '1' : '0');
applyPoiVisibility(checked);
}
/**
* Восстанавливает видимость POI при загрузке страницы и после смены
* стиля карты (переключение темы).
*
* По умолчанию (ключ 'poi-visible' отсутствует или равен '1') POI
* видимы; '0' — скрыты. Синхронизирует чекбокс, layerState.poi и
* фактическую видимость слоёв.
*/
function restorePoiState() {
const stored = localStorage.getItem('poi-visible');
const poiOn = stored === null || stored === '1';
const cb = document.getElementById('poi-visible-cb');
if (cb) cb.checked = poiOn;
applyPoiVisibility(poiOn);
}
// <<< ET-002 POI visibility block <<<
function applyTerrainLayer(id, tileUrl, enabled, opacity, minzoom, maxzoom) {
const map = window._map;
if (!map) return;
@@ -2890,6 +2947,7 @@ function restoreTerrainState() {
// Initial state
restoreTerrainState();
restoreTrailsState();
restorePoiState();
} else {
// Map not ready yet, wait
const interval = setInterval(() => {
@@ -2902,6 +2960,7 @@ function restoreTerrainState() {
updateHillshadeAvailability();
restoreTerrainState();
restoreTrailsState();
restorePoiState();
}
}, 500);
}

View File

@@ -53,6 +53,11 @@
<input type="checkbox" id="trails-path-cb" onchange="onTrailsCheckbox()" checked>
<span>Тропы</span>
</label>
<hr style="margin:6px 0;border-color:rgba(128,128,128,0.3)">
<label class="terrain-checkbox">
<input type="checkbox" id="poi-visible-cb" onchange="onPoiCheckbox()" checked>
<span>POI</span>
</label>
</div>
<!-- ── Map Buttons (right) ───────────────── -->