@@ -1204,6 +1214,7 @@ function showView(name) {
if (firesOn) loadFires();
if (camsOn) loadCams();
if (blipsOn) loadBlips();
+ if (newsOn) loadNewsPins();
}
}
if (name === 'news') loadNews(false);
@@ -1762,6 +1773,7 @@ async function saveSummaryModel() {
let map = null, mapLayer = null, mapInitStarted = false;
let firesHeat = null, camsGroup = null, firesOn = false, camsOn = false;
let blipsGroup = null, blipsOn = false, blipsSince = '24h';
+let newsGroup = null, newsOn = false, newsReq = 0;
let firesOpacity = 0.65, firesColor = 'brightness', firesSince = '24h';
let camsOpacity = 1.0, baseOpacity = 1.0;
let camReq = 0, fireReq = 0, blipReq = 0; // stale-response guards (rapid zoom races)
@@ -1954,6 +1966,7 @@ async function initMap() {
if (firesOn) loadFires();
if (camsOn) loadCams();
if (blipsOn) loadBlips();
+ if (newsOn) loadNewsPins();
refreshLiveOverlays();
sendLiveViewport();
}, 500);
@@ -1965,6 +1978,7 @@ async function initMap() {
firesOn = document.getElementById('lp-fires-on').checked;
camsOn = document.getElementById('lp-cams-on').checked;
blipsOn = document.getElementById('lp-blips-on').checked;
+ newsOn = document.getElementById('lp-news-on').checked;
firesSince = document.getElementById('lp-fires-since').value;
blipsSince = document.getElementById('lp-blips-since').value;
radarOn = document.getElementById('lp-radar-on').checked;
@@ -1979,6 +1993,7 @@ async function initMap() {
if (firesOn) loadFires();
if (camsOn) loadCams();
if (blipsOn) loadBlips();
+ if (newsOn) loadNewsPins();
refreshLiveOverlays();
connectLiveWs();
} catch(e) {
@@ -2001,8 +2016,9 @@ function syncHud() {
set('fires', firesOn ? (hudFiresCount) : '—', firesOn);
set('cams', camsOn ? (hudCamsCount) : '—', camsOn);
set('blips', blipsOn ? (hudBlipsCount) : '—', blipsOn);
+ set('news', newsOn ? (hudNewsCount) : '—', newsOn);
}
-let hudFiresCount = null, hudCamsCount = null, hudBlipsCount = null;
+let hudFiresCount = null, hudCamsCount = null, hudBlipsCount = null, hudNewsCount = null;
function setMapAttribution(text) {
if (!map) return;
@@ -2417,6 +2433,57 @@ async function loadBlips() {
}
}
+/* ── CRITICAL NEWS (LLM-estimated locations, critical/high only) ── */
+async function toggleNewsPins() {
+ newsOn = document.getElementById('lp-news-on').checked;
+ if (newsOn) {
+ await loadNewsPins();
+ return;
+ }
+ newsReq++;
+ if (newsGroup && map) { map.removeLayer(newsGroup); newsGroup = null; }
+ hudNewsCount = null;
+ const countEl = document.getElementById('lp-news-count');
+ if (countEl) countEl.textContent = '0';
+ syncHud();
+}
+async function loadNewsPins() {
+ if (!map) return;
+ const req = ++newsReq;
+ try {
+ const url = `${API}/api/news/map?bbox=${currentBBox()}&limit=200`;
+ const r = await overlayFetch(url);
+ const data = await r.json();
+ if (req !== newsReq) return; // superseded by a newer pan/zoom
+ const items = Array.isArray(data) ? data : [];
+ if (newsGroup) map.removeLayer(newsGroup);
+ const col = '#ff2e97';
+ const pins = items.filter(it => Number.isFinite(Number(it.lat)) && Number.isFinite(Number(it.lon)));
+ newsGroup = L.layerGroup(pins.map(it => {
+ const icon = L.divIcon({
+ className: '',
+ html: `
`,
+ iconSize: [14, 14], iconAnchor: [7, 7],
+ });
+ return L.marker([it.lat, it.lon], { icon })
+ .bindPopup(`
` +
+ `
◈ ${esc(it.importance || '')}${it.category ? ' · ' + esc(it.category) : ''}
` +
+ `
${esc(it.headline || '')}` +
+ `
${esc(it.location_name || '')}
` +
+ (it.url ? `
source ↗` : '') +
+ `
`);
+ }));
+ newsGroup.addTo(map);
+ document.getElementById('lp-news-count').textContent = pins.length.toLocaleString();
+ hudNewsCount = pins.length;
+ syncHud();
+ } catch(e) {
+ if (isAbort(e)) return;
+ document.getElementById('map-hint').textContent = `News pins load failed: ${e.message || e}`;
+ console.error('News pins load failed', e);
+ }
+}
+
/* ── Live overlays (radar / alerts / WFIGS / aircraft / trains / AIS / NHC) ── */
function refreshLiveOverlays() {
if (!map) return;