Ajouter le curseur d'intensité du relief, mémorisé et partagé dans le lien

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Antoine Jacquin
2026-09-27 20:24:42 +02:00
parent 90663405f7
commit 7b8060e893
3 changed files with 49 additions and 2 deletions

View File

@ -217,12 +217,22 @@ function validMain(meta, k) {
return mainKeys(meta).includes(k) ? k : null;
}
// Intensité du relief : contraste appliqué au conteneur de la couche
// principale (réglage de confort personnel, jamais figé comme défaut serveur
// ni appliqué au PDF exporté).
function clampIntensity(v) {
const n = Number(v);
return Number.isFinite(n) ? Math.round(Math.min(2, Math.max(0.5, n)) * 10) / 10 : 1;
}
const fmtIntensity = (v) => String(v).replace('.', ',') + '×';
function defaultState(meta) {
const b = meta.default_base || {};
return {
main: validMain(meta, meta.default_main) || mainKeys(meta)[0] || null,
mode: validMode(meta.default_mode) || 'relief',
compare: validCompare(null),
intensity: 1,
base: { on: b.on !== undefined ? !!b.on : true,
opacity: b.opacity !== undefined ? Number(b.opacity) : 0.85,
// null = suit le thème (choix explicite seulement si b.dark est déjà
@ -245,6 +255,7 @@ function loadState(meta) {
// Ancien mode « les deux » (produit) mémorisé : relief.
mode: validMode(s.mode === 'both' ? 'relief' : s.mode) || def.mode,
compare: validCompare(s.compare),
intensity: clampIntensity(s.intensity),
base: Object.assign({}, def.base, sBase) };
}
// Lien partagé : prime sur l'état local (les anciens liens &L=… de la
@ -255,6 +266,7 @@ function loadState(meta) {
if (hash.view) st.mode = hash.view.mode;
if (hash.compare) st.compare = hash.compare;
if (hash.base) st.base = hash.base;
if (hash.intensity != null) st.intensity = hash.intensity;
}
return st;
}
@ -271,13 +283,14 @@ function parseHash() {
const m = /^#([\d.]+)\/(-?[\d.]+)\/(-?[\d.]+)(.*)$/.exec(location.hash || '');
if (!m) return null;
const out = { zoom: parseFloat(m[1]), lat: parseFloat(m[2]), lng: parseFloat(m[3]),
main: null, view: null, compare: null, base: null };
main: null, view: null, compare: null, base: null, intensity: null };
const seg = {};
for (const part of m[4].split('&')) {
const i = part.indexOf('=');
if (i > 0) seg[part.slice(0, i)] = part.slice(i + 1);
}
if (seg.M) out.main = seg.M;
if (seg.I) out.intensity = clampIntensity(seg.I);
if (seg.P) {
const f = seg.P.split(':');
// Ancien mode « les deux » (produit) : s'ouvre en relief. L'opacité qui
@ -311,6 +324,7 @@ function viewHash(full) {
const dark = STATE.base.dark === null || STATE.base.dark === undefined ? themeIsDark() : STATE.base.dark;
h += '&B=' + (STATE.base.on ? '1' : '0') + ':' + Math.round(STATE.base.opacity * 100)
+ ':' + (dark ? '1' : '0');
if (STATE.intensity !== 1) h += '&I=' + STATE.intensity;
}
return h;
}
@ -416,6 +430,13 @@ function applyLayers() {
const container = base.getContainer && base.getContainer();
const dark = STATE.base.dark === null || STATE.base.dark === undefined ? themeIsDark() : STATE.base.dark;
if (container) container.classList.toggle('base-dark', dark);
// Intensité (contraste) : posée sur le conteneur de la couche relief
// seule — la découpe de comparaison (clipPath) reste indépendante, les
// deux propriétés CSS coexistent sur le même conteneur.
for (const [key, layer] of LAYERS) {
const c = layer.getContainer && layer.getContainer();
if (c) c.style.filter = key === STATE.main && STATE.intensity !== 1 ? 'contrast(' + STATE.intensity + ')' : '';
}
applyCompareClip();
updateRose();
}
@ -528,6 +549,9 @@ function renderPanel() {
}
const prec = precisionKey();
el('precBlock').hidden = !prec;
el('reliefIntensity').value = STATE.intensity;
el('reliefIntensityVal').textContent = fmtIntensity(STATE.intensity);
el('intensityRow').hidden = effectiveMode() === 'precision';
if (!prec) return;
renderPrecLegend();
const mode = effectiveMode();
@ -1456,7 +1480,7 @@ window.addEventListener('hashchange', () => {
if (!h) return;
applyingHash = true;
map.setView([h.lat, h.lng], h.zoom);
if (h.main || h.view || h.base || h.compare) {
if (h.main || h.view || h.base || h.compare || h.intensity != null) {
STATE = loadState(META);
saveState(); renderPanel(); renderBaseRow(); applyLayers();
}
@ -1511,6 +1535,12 @@ el('btnDefault').addEventListener('click', () => {
el('modeSeg').querySelectorAll('button').forEach(b =>
b.addEventListener('click', () => setMode(b.dataset.mode)));
el('reliefIntensity').addEventListener('input', (e) => {
STATE.intensity = clampIntensity(e.target.value);
el('reliefIntensityVal').textContent = fmtIntensity(STATE.intensity);
applyLayers();
});
el('reliefIntensity').addEventListener('change', saveState);
el('mainSel').addEventListener('change', (e) => {
STATE.main = e.target.value;
saveState(); renderPanel(); applyLayers();