diff --git a/viewer/index.html b/viewer/index.html
index 4740ad8..390e63c 100644
--- a/viewer/index.html
+++ b/viewer/index.html
@@ -9,6 +9,51 @@
* { box-sizing: border-box; margin: 0; padding: 0; }
body { font-family: monospace; background: #1a1a2e; color: #e0e0e0; display: flex; flex-direction: column; height: 100vh; }
#map { flex: 1; }
+
+ /* ── top bar: date picker ── */
+ #datebar {
+ background: #0d1b2a;
+ padding: 6px 12px;
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ border-bottom: 1px solid #0f3460;
+ flex-wrap: wrap;
+ }
+ #datebar label { font-size: 11px; color: #a0c4ff; white-space: nowrap; }
+ #date-picker {
+ background: #16213e;
+ color: #e0e0e0;
+ border: 1px solid #0f3460;
+ padding: 4px 8px;
+ font-family: monospace;
+ font-size: 12px;
+ cursor: pointer;
+ }
+ #date-picker::-webkit-calendar-picker-indicator { filter: invert(1); }
+ #btn-today {
+ background: #0f3460;
+ color: #a0c4ff;
+ border: 1px solid #1a5276;
+ padding: 4px 10px;
+ font-family: monospace;
+ font-size: 11px;
+ cursor: pointer;
+ }
+ #btn-today:hover { background: #1a5276; }
+ #mission-label {
+ font-size: 12px;
+ color: #e94560;
+ font-weight: bold;
+ min-width: 160px;
+ }
+ #dates-hint {
+ font-size: 10px;
+ color: #556;
+ white-space: nowrap;
+ }
+
+ /* ── bottom bar: slider ── */
#controls {
background: #16213e;
padding: 8px 12px;
@@ -23,7 +68,19 @@
+
+
+
+
+
+
+ —
+ Chargement calendrier…
+
+
+
+
USV Track
@@ -47,7 +104,6 @@ const seamarks = L.tileLayer('https://tiles.openseamap.org/seamark/{z}/{x}/{y}.p
opacity: 0.8,
});
-// GEBCO bathymetry (tile-based, simpler than WMS)
const gebco = L.tileLayer(
'https://tiles.arcgis.com/tiles/C8EMgrsFcRFL6LrL/arcgis/rest/services/GEBCO_basemap_NCEI/MapServer/tile/{z}/{y}/{x}',
{
@@ -78,7 +134,74 @@ function makeArrowIcon(heading) {
});
}
-// ── Data loading ──────────────────────────────────────────────────────────
+// ── Calendar data ─────────────────────────────────────────────────────────
+const BACKEND = 'http://192.168.0.83:8766';
+let dataMissions = {}; // date → {missions, session_count}
+
+async function loadCalendar() {
+ try {
+ const resp = await fetch(`${BACKEND}/api/data-dates`);
+ if (!resp.ok) throw new Error(`HTTP ${resp.status}`);
+ const json = await resp.json();
+ json.dates.forEach(d => {
+ dataMissions[d.date] = { missions: d.missions, session_count: d.session_count };
+ });
+
+ const availDates = Object.keys(dataMissions).sort();
+ const picker = document.getElementById('date-picker');
+
+ if (availDates.length > 0) {
+ picker.min = availDates[0];
+ picker.max = availDates[availDates.length - 1];
+ }
+
+ // Highlight available dates via custom attribute list (CSS trick)
+ // We inject a datalist for browsers that support it
+ const dl = document.createElement('datalist');
+ dl.id = 'available-dates';
+ availDates.forEach(d => {
+ const opt = document.createElement('option');
+ opt.value = d;
+ dl.appendChild(opt);
+ });
+ document.body.appendChild(dl);
+ picker.setAttribute('list', 'available-dates');
+
+ document.getElementById('dates-hint').textContent =
+ `${availDates.length} dates avec données`;
+
+ // Select most recent date by default
+ if (availDates.length > 0) {
+ picker.value = availDates[availDates.length - 1];
+ onDateChange(picker.value);
+ }
+ } catch (e) {
+ document.getElementById('dates-hint').textContent = 'Calendrier indispo: ' + e.message;
+ }
+}
+
+function onDateChange(date) {
+ const label = document.getElementById('mission-label');
+ const info = dataMissions[date];
+ if (info) {
+ label.textContent = info.missions.join(', ') + ` (${info.session_count} session${info.session_count > 1 ? 's' : ''})`;
+ label.style.color = '#00e676';
+ } else {
+ label.textContent = 'Aucune donnée pour cette date';
+ label.style.color = '#666';
+ }
+}
+
+document.getElementById('date-picker').addEventListener('change', e => onDateChange(e.target.value));
+
+document.getElementById('btn-today').addEventListener('click', () => {
+ const today = new Date().toISOString().split('T')[0];
+ const picker = document.getElementById('date-picker');
+ picker.value = today;
+ onDateChange(today);
+});
+
+// ── Track data loading ────────────────────────────────────────────────────
let points = [];
let trackLayer = null;
let marker = null;
@@ -136,6 +259,8 @@ function updateInfo(idx) {
`[${idx+1}/${points.length}] ${p.t} | Lat: ${p.lat.toFixed(6)} Lon: ${p.lon.toFixed(6)} | Cap: ${hdg}`;
}
+// ── Init ──────────────────────────────────────────────────────────────────
+loadCalendar();
loadData();