Ajouter la légende « Comment lire » tirée de VIZ_LEGENDS
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@ -520,6 +520,16 @@ def test_meta_serves_reading_text(tmp_path, monkeypatch):
|
|||||||
assert layers["densite_sol"]["reading"]
|
assert layers["densite_sol"]["reading"]
|
||||||
|
|
||||||
|
|
||||||
|
def test_ui_reading_legend_from_meta():
|
||||||
|
"""Légende « Comment lire » : phrases de META.layers[].reading, jamais
|
||||||
|
codées en dur dans l'interface (VIZ_LEGENDS reste la seule source)."""
|
||||||
|
from lidar_pipeline.mapui import _MAP_HTML, _MAP_JS
|
||||||
|
assert 'id="readingBlock"' in _MAP_HTML and 'id="readingList"' in _MAP_HTML
|
||||||
|
assert "<details" in _MAP_HTML and "Comment lire" in _MAP_HTML
|
||||||
|
assert "function renderReading(" in _MAP_JS and ".reading" in _MAP_JS
|
||||||
|
assert "aucun point sol" not in _MAP_JS and "aucun point sol" not in _MAP_HTML
|
||||||
|
|
||||||
|
|
||||||
def test_ui_compare_mode_replaces_both():
|
def test_ui_compare_mode_replaces_both():
|
||||||
"""Mode « Comparer » : une barre glissante sépare deux couches (relief,
|
"""Mode « Comparer » : une barre glissante sépare deux couches (relief,
|
||||||
précision ou OSM seul) ; l'ancien mode « les deux » (produit) disparaît
|
précision ou OSM seul) ; l'ancien mode « les deux » (produit) disparaît
|
||||||
|
|||||||
@ -141,7 +141,10 @@ input[type="range"]::-moz-range-thumb { width: 10px; height: 10px; border-radius
|
|||||||
border: 1px solid var(--border); border-radius: 3px; overflow: hidden; }
|
border: 1px solid var(--border); border-radius: 3px; overflow: hidden; }
|
||||||
.prec-ticks { display: flex; justify-content: space-between; font-size: var(--fs-xs); color: var(--muted);
|
.prec-ticks { display: flex; justify-content: space-between; font-size: var(--fs-xs); color: var(--muted);
|
||||||
font-variant-numeric: tabular-nums; margin-top: 2px; }
|
font-variant-numeric: tabular-nums; margin-top: 2px; }
|
||||||
.prec-cap { font-size: var(--fs-xs); color: var(--muted); margin-top: 2px; }
|
.reading summary { cursor: pointer; font-size: var(--fs-sm); font-weight: 600; color: var(--text); }
|
||||||
|
.reading ul { margin: var(--sp-2) 0 0; padding-left: var(--sp-4); }
|
||||||
|
.reading li { font-size: var(--fs-sm); color: var(--muted); line-height: 1.5; }
|
||||||
|
.reading li + li { margin-top: var(--sp-1); }
|
||||||
.eye { width: 24px; height: 24px; padding: 0; border: none; background: none; color: var(--muted);
|
.eye { width: 24px; height: 24px; padding: 0; border: none; background: none; color: var(--muted);
|
||||||
display: flex; align-items: center; justify-content: center; }
|
display: flex; align-items: center; justify-content: center; }
|
||||||
.eye.on { color: var(--accent); }
|
.eye.on { color: var(--accent); }
|
||||||
|
|||||||
@ -59,13 +59,16 @@
|
|||||||
<div class="prec-legend" id="precLegend" hidden>
|
<div class="prec-legend" id="precLegend" hidden>
|
||||||
<div class="prec-bar" id="precBar"></div>
|
<div class="prec-bar" id="precBar"></div>
|
||||||
<div class="prec-ticks"><span>≤ 0,35</span><span>4</span><span>≥ 45 pts/m²</span></div>
|
<div class="prec-ticks"><span>≤ 0,35</span><span>4</span><span>≥ 45 pts/m²</span></div>
|
||||||
<div class="prec-cap">Points sol par m² : sombre = relief interpolé, noir = aucun point</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="legend" id="legendBlock" title="Relief orienté : la teinte donne l'orientation de la pente, la clarté le relief local">
|
<div class="legend" id="legendBlock" title="Relief orienté : la teinte donne l'orientation de la pente, la clarté le relief local">
|
||||||
<canvas id="roseCanvas" width="96" height="96"></canvas>
|
<canvas id="roseCanvas" width="96" height="96"></canvas>
|
||||||
<div class="rose-cap">Pente orientée vers…<br><span>clair = bosse · sombre = creux</span></div>
|
<div class="rose-cap">Pente orientée vers…<br><span>clair = bosse · sombre = creux</span></div>
|
||||||
</div>
|
</div>
|
||||||
|
<details id="readingBlock" class="reading">
|
||||||
|
<summary>Comment lire la carte</summary>
|
||||||
|
<ul id="readingList"></ul>
|
||||||
|
</details>
|
||||||
</section>
|
</section>
|
||||||
<section id="tab-tile" role="tabpanel" hidden>
|
<section id="tab-tile" role="tabpanel" hidden>
|
||||||
<p class="hint" id="tileHint">Cliquez une dalle sur la carte pour la sélectionner.</p>
|
<p class="hint" id="tileHint">Cliquez une dalle sur la carte pour la sélectionner.</p>
|
||||||
|
|||||||
@ -532,6 +532,25 @@ function renderPrecLegend() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// « Comment lire » : phrases de VIZ_LEGENDS (champ reading), servies par
|
||||||
|
// /api/map/meta — même texte que la légende de la planche PDF.
|
||||||
|
function renderReading() {
|
||||||
|
const mode = effectiveMode();
|
||||||
|
const keys = mode === 'precision' ? [precisionKey()]
|
||||||
|
: mode === 'compare' ? [sideLayerKey(STATE.compare.left), sideLayerKey(STATE.compare.right)]
|
||||||
|
: [STATE.main];
|
||||||
|
const seen = new Set();
|
||||||
|
const items = [];
|
||||||
|
for (const k of keys) {
|
||||||
|
if (!k || seen.has(k)) continue;
|
||||||
|
seen.add(k);
|
||||||
|
const info = META.layers.find(l => l.key === k);
|
||||||
|
for (const s of (info && info.reading) || []) items.push('<li>' + esc(s) + '</li>');
|
||||||
|
}
|
||||||
|
el('readingList').innerHTML = items.join('');
|
||||||
|
el('readingBlock').hidden = !items.length;
|
||||||
|
}
|
||||||
|
|
||||||
function renderPanel() {
|
function renderPanel() {
|
||||||
const labels = new Map(META.layers.map(l => [l.key, l]));
|
const labels = new Map(META.layers.map(l => [l.key, l]));
|
||||||
const mains = mainKeys(META);
|
const mains = mainKeys(META);
|
||||||
@ -552,6 +571,7 @@ function renderPanel() {
|
|||||||
el('reliefIntensity').value = STATE.intensity;
|
el('reliefIntensity').value = STATE.intensity;
|
||||||
el('reliefIntensityVal').textContent = fmtIntensity(STATE.intensity);
|
el('reliefIntensityVal').textContent = fmtIntensity(STATE.intensity);
|
||||||
el('intensityRow').hidden = effectiveMode() === 'precision';
|
el('intensityRow').hidden = effectiveMode() === 'precision';
|
||||||
|
renderReading();
|
||||||
if (!prec) return;
|
if (!prec) return;
|
||||||
renderPrecLegend();
|
renderPrecLegend();
|
||||||
const mode = effectiveMode();
|
const mode = effectiveMode();
|
||||||
@ -1310,9 +1330,10 @@ function _sanitizedPanelLS() {
|
|||||||
if (typeof s.tab === 'string') out.tab = s.tab;
|
if (typeof s.tab === 'string') out.tab = s.tab;
|
||||||
if (typeof s.collapsed === 'boolean') out.collapsed = s.collapsed;
|
if (typeof s.collapsed === 'boolean') out.collapsed = s.collapsed;
|
||||||
if (['closed', 'half', 'full'].includes(s.sheet)) out.sheet = s.sheet;
|
if (['closed', 'half', 'full'].includes(s.sheet)) out.sheet = s.sheet;
|
||||||
|
if (typeof s.reading === 'boolean') out.reading = s.reading;
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
const PANEL = Object.assign({ tab: 'view', collapsed: false, sheet: 'half' }, _sanitizedPanelLS());
|
const PANEL = Object.assign({ tab: 'view', collapsed: false, sheet: 'half', reading: false }, _sanitizedPanelLS());
|
||||||
// want = onglet choisi (mémorisé) ; tab = onglet affiché. Génération encore
|
// want = onglet choisi (mémorisé) ; tab = onglet affiché. Génération encore
|
||||||
// inconnue au démarrage (api/status) : Affichage en attendant, puis l'onglet
|
// inconnue au démarrage (api/status) : Affichage en attendant, puis l'onglet
|
||||||
// choisi revient dès qu'il est proposé.
|
// choisi revient dès qu'il est proposé.
|
||||||
@ -1337,7 +1358,7 @@ function panelVisibleTab() {
|
|||||||
return PANEL.tab;
|
return PANEL.tab;
|
||||||
}
|
}
|
||||||
|
|
||||||
function panelSave() { lsSet(PANEL_LS, { tab: PANEL.want, collapsed: PANEL.collapsed, sheet: PANEL.sheet }); }
|
function panelSave() { lsSet(PANEL_LS, { tab: PANEL.want, collapsed: PANEL.collapsed, sheet: PANEL.sheet, reading: PANEL.reading }); }
|
||||||
|
|
||||||
function panelRender() {
|
function panelRender() {
|
||||||
const tabs = panelTabs();
|
const tabs = panelTabs();
|
||||||
@ -1389,6 +1410,13 @@ function setSheet(state) {
|
|||||||
el('panelTabs').querySelectorAll('button[data-tab]').forEach(b =>
|
el('panelTabs').querySelectorAll('button[data-tab]').forEach(b =>
|
||||||
b.addEventListener('click', () => openTab(b.dataset.tab)));
|
b.addEventListener('click', () => openTab(b.dataset.tab)));
|
||||||
el('panelCollapse').addEventListener('click', () => setCollapsed(!PANEL.collapsed));
|
el('panelCollapse').addEventListener('click', () => setCollapsed(!PANEL.collapsed));
|
||||||
|
// État ouvert/fermé du « Comment lire » mémorisé à part (indépendant de
|
||||||
|
// l'onglet actif).
|
||||||
|
el('readingBlock').open = !!PANEL.reading;
|
||||||
|
el('readingBlock').addEventListener('toggle', () => {
|
||||||
|
PANEL.reading = el('readingBlock').open;
|
||||||
|
panelSave();
|
||||||
|
});
|
||||||
phoneQuery.addEventListener('change', panelRender);
|
phoneQuery.addEventListener('change', panelRender);
|
||||||
window.addEventListener('resize', panelRender); // hauteur du volet en vh (rotation)
|
window.addEventListener('resize', panelRender); // hauteur du volet en vh (rotation)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user