// Onglet « Carte et corrections » : déplacer ou placer les photos et vidéos, // masquer des zones de trace. Chaque correction est enregistrée aussitôt dans // voyage.toml (ou site.toml pour une zone privée) ; les pages du site la // prennent en compte à la génération suivante. (function () { "use strict"; const racine = document.getElementById("editeur"); if (!racine || !window.L) return; const voyage = racine.dataset.voyage; const $ = id => document.getElementById(id); let carte = null, donnees = null, coucheTraces, coucheMedias, coucheZones; let brouillon = null, modeZone = false, aPlacer = null, cadree = false; // --- Échanges avec le serveur ------------------------------------------- function message(html) { const m = $("messages"); m.innerHTML = html; clearTimeout(window._rtgMessage); window._rtgMessage = setTimeout(() => { m.innerHTML = ""; }, 6000); } function lireReponse(r) { const redirection = r.headers.get("HX-Redirect"); if (redirection) { location.href = redirection; throw new Error("session"); } if (!(r.headers.get("Content-Type") || "").includes("json")) { return r.text().then(t => { message(t); throw new Error("refus"); }); } return r.json(); } function poster(url, params) { return fetch(url, { method: "POST", headers: { "HX-Request": "true", "Content-Type": "application/x-www-form-urlencoded" }, body: new URLSearchParams(Object.assign({ v: voyage }, params)) }).then(lireReponse); } function etat(texte) { $("ed-etat").textContent = texte; } function charger() { return fetch("/voyage/carte.json?v=" + encodeURIComponent(voyage), { headers: { "HX-Request": "true" } }) .then(lireReponse) .then(d => { donnees = d; remplirJours(); dessinerTout(); }); } // --- Carte ---------------------------------------------------------------- function initialiser() { $("ed-carte").innerHTML = ""; carte = L.map("ed-carte"); const plan = L.tileLayer("https://tile.openstreetmap.org/{z}/{x}/{y}.png", { maxZoom: 19, attribution: "© OpenStreetMap" }).addTo(carte); const satellite = L.tileLayer( "https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}", { maxZoom: 19, attribution: "Esri World Imagery" }); L.control.layers({ "Plan": plan, "Satellite": satellite }).addTo(carte); carte.setView([46.5, 2.5], 5); coucheTraces = L.featureGroup().addTo(carte); coucheZones = L.featureGroup().addTo(carte); coucheMedias = L.featureGroup().addTo(carte); carte.on("click", clicCarte); $("ed-jour").addEventListener("change", () => { cadree = false; dessinerTout(); }); $("ed-photos").addEventListener("change", dessinerMedias); $("ed-videos").addEventListener("change", dessinerMedias); $("ed-nouvelle-zone").addEventListener("click", commencerZone); $("ed-zone-annuler").addEventListener("click", finirZone); $("ed-zone-ok").addEventListener("click", enregistrerZone); $("ed-rayon").addEventListener("input", () => { $("ed-rayon-texte").textContent = $("ed-rayon").value + " m"; if (brouillon) brouillon.setRadius(+$("ed-rayon").value); }); document.addEventListener("keydown", e => { if (e.key === "Escape") { aPlacer = null; finirZone(); mode(""); } }); document.body.addEventListener("tache-finie", () => charger()); charger(); } function remplirJours() { const choix = $("ed-jour"), actuel = choix.value; choix.length = 1; donnees.jours.forEach(j => choix.add(new Option(j.nom, j.jour))); choix.value = actuel; } function jourChoisi() { return $("ed-jour").value; } function dessinerTout() { dessinerTraces(); dessinerZones(); dessinerMedias(); if (!cadree) { const b = coucheTraces.getLayers().length ? coucheTraces.getBounds() : (coucheMedias.getLayers().length ? coucheMedias.getBounds() : null); if (b && b.isValid()) carte.fitBounds(b, { padding: [30, 30] }); cadree = true; } } function dessinerTraces() { coucheTraces.clearLayers(); const jour = jourChoisi(); donnees.couches.forEach(c => { if (jour && c.jour !== jour) return; c.segments.forEach(s => L.polyline(s, { color: c.couleur, weight: 4, opacity: 0.85, interactive: false }) .addTo(coucheTraces)); }); } function icone(m) { return L.divIcon({ className: "", iconSize: [16, 16], iconAnchor: [8, 8], html: '' }); } function popup(m) { const d = document.createElement("div"); d.className = "ed-popup"; if (m.vignette) { const img = document.createElement("img"); img.src = m.vignette; img.alt = ""; img.loading = "lazy"; d.append(img); } const t = document.createElement("div"); t.textContent = m.fichier + " · " + m.jour + " " + m.heure; d.append(t); if (m.deplace) { const b = document.createElement("button"); b.className = "petit"; b.textContent = "Revenir à la position d'origine"; b.addEventListener("click", () => { carte.closePopup(); enregistrerPosition(m.fichier, "", ""); }); d.append(b); } return d; } function dessinerMedias() { coucheMedias.clearLayers(); const jour = jourChoisi(), photos = $("ed-photos").checked, videos = $("ed-videos").checked; const sans = []; donnees.medias.forEach(m => { if (jour && m.jour !== jour) return; if ((m.type === "photo" && !photos) || (m.type === "video" && !videos)) return; if (m.lat === null) { sans.push(m); return; } L.marker([m.lat, m.lon], { icon: icone(m), draggable: true, title: m.fichier }) .bindPopup(() => popup(m), { minWidth: 200 }) .on("dragend", e => { const p = e.target.getLatLng(); enregistrerPosition(m.fichier, p.lat.toFixed(6), p.lng.toFixed(6)); }) .addTo(coucheMedias); }); const liste = $("ed-sans"); liste.innerHTML = ""; $("ed-nb-sans").textContent = sans.length; sans.forEach(m => { const li = document.createElement("li"); const a = document.createElement("a"); a.href = "#carte"; a.textContent = (m.type === "photo" ? "📷 " : "🎬 ") + m.fichier; a.title = m.jour + " " + m.heure; a.addEventListener("click", e => { e.preventDefault(); finirZone(); aPlacer = m.fichier; mode("Cliquez sur la carte pour placer " + m.fichier + " (Échap pour annuler)"); }); const quand = document.createElement("span"); quand.className = "discret"; quand.textContent = " " + m.jour + " " + m.heure; li.append(a, quand); liste.append(li); }); if (!sans.length) liste.innerHTML = '