Add zoom-aware symbology, fix globe popovers, expand geo coverage (#34)
* Add zoom-aware symbology, fix globe popovers, expand geo coverage Map rendering improvements based on user feedback: - Globe markers now scale with camera altitude (onZoom hook) - Priority-based visibility culls low-priority markers at world view - Globe popovers use getScreenCoords for accurate positioning - Flat map labels hidden at low zoom, revealed progressively - Default globe altitude lowered from 2.5 to 1.8 for better fill - Americas region zoom tightened to CONUS focus Geographic coverage expansion: - 4 new OpenSky air theaters: Caribbean, Gulf of Guinea, Cape Route, Horn of Africa - Flight corridors now span Americas and Africa - NOAA alerts extract centroid lat/lon from GeoJSON geometry - EPA RadNet stations geocoded with hardcoded coords for 10 US cities - ISS + Tiangong positions estimated from TLE orbital elements - GDELT geoEvents() now called in briefing for mapped event points - New legend entries: Weather Alert, EPA RadNet, Space Station, GDELT Event * Fix null-safe coordinate checks and remove injected data blob - Use `!= null` instead of truthy checks for lat/lon in noaa.mjs and inject.mjs so valid 0-coordinates (equator/prime meridian) are not silently dropped - Reset jarvis.html `let D` back to null placeholder so generated runtime data is not part of the PR diff * Remove re-injected data blob from jarvis.html Reset let D back to null — previous commit was correct but inject.mjs build verification re-injected the payload.
This commit is contained in:
@@ -367,16 +367,54 @@ export async function synthesize(data) {
|
||||
const defense = (data.sources.USAspending?.recentDefenseContracts || []).slice(0, 5).map(c => ({
|
||||
recipient: c.recipient?.substring(0, 40), amount: c.amount, desc: c.description?.substring(0, 80)
|
||||
}));
|
||||
const noaa = { totalAlerts: data.sources.NOAA?.totalSevereAlerts || 0 };
|
||||
const noaa = {
|
||||
totalAlerts: data.sources.NOAA?.totalSevereAlerts || 0,
|
||||
alerts: (data.sources.NOAA?.topAlerts || []).filter(a => a.lat != null && a.lon != null).slice(0, 10).map(a => ({
|
||||
event: a.event, severity: a.severity, headline: a.headline?.substring(0, 120),
|
||||
lat: a.lat, lon: a.lon
|
||||
}))
|
||||
};
|
||||
|
||||
// EPA RadNet — pass through geo-tagged readings
|
||||
const epaData = data.sources.EPA || {};
|
||||
const epaStations = [];
|
||||
const seenEpa = new Set();
|
||||
for (const r of (epaData.readings || [])) {
|
||||
if (r.lat == null || r.lon == null) continue;
|
||||
const key = `${r.lat},${r.lon}`;
|
||||
if (seenEpa.has(key)) continue;
|
||||
seenEpa.add(key);
|
||||
epaStations.push({ location: r.location, state: r.state, lat: r.lat, lon: r.lon, analyte: r.analyte, result: r.result, unit: r.unit });
|
||||
}
|
||||
const epa = { totalReadings: epaData.totalReadings || 0, stations: epaStations.slice(0, 10) };
|
||||
|
||||
// Space/CelesTrak satellite data
|
||||
const spaceData = data.sources.Space || {};
|
||||
// Approximate subsatellite position from TLE orbital elements
|
||||
function estimateSatPosition(sat) {
|
||||
if (!sat?.inclination || !sat?.epoch) return null;
|
||||
const epoch = new Date(sat.epoch);
|
||||
const now = new Date();
|
||||
const elapsed = (now - epoch) / 1000;
|
||||
const period = (sat.period || 92.7) * 60; // minutes to seconds
|
||||
const orbits = elapsed / period;
|
||||
const frac = orbits % 1;
|
||||
const lat = sat.inclination * Math.sin(frac * 2 * Math.PI);
|
||||
const lonShift = (elapsed / 86400) * 360;
|
||||
const orbitLon = frac * 360;
|
||||
const lon = ((orbitLon - lonShift) % 360 + 540) % 360 - 180;
|
||||
return { lat: +lat.toFixed(2), lon: +lon.toFixed(2), name: sat.name };
|
||||
}
|
||||
const issPos = estimateSatPosition(spaceData.iss);
|
||||
const spaceStations = (spaceData.spaceStations || []).map(s => estimateSatPosition(s)).filter(Boolean);
|
||||
const space = {
|
||||
totalNewObjects: spaceData.totalNewObjects || 0,
|
||||
militarySats: spaceData.militarySatellites || 0,
|
||||
militaryByCountry: spaceData.militaryByCountry || {},
|
||||
constellations: spaceData.constellations || {},
|
||||
iss: spaceData.iss || null,
|
||||
issPosition: issPos,
|
||||
stationPositions: spaceStations.slice(0, 5),
|
||||
recentLaunches: (spaceData.recentLaunches || []).slice(0, 10).map(l => ({
|
||||
name: l.name, country: l.country, epoch: l.epoch,
|
||||
apogee: l.apogee, perigee: l.perigee, type: l.objectType
|
||||
@@ -398,7 +436,7 @@ export async function synthesize(data) {
|
||||
}))
|
||||
};
|
||||
|
||||
// GDELT news articles
|
||||
// GDELT news articles + geo events
|
||||
const gdeltData = data.sources.GDELT || {};
|
||||
const gdelt = {
|
||||
totalArticles: gdeltData.totalArticles || 0,
|
||||
@@ -406,7 +444,10 @@ export async function synthesize(data) {
|
||||
economy: (gdeltData.economy || []).length,
|
||||
health: (gdeltData.health || []).length,
|
||||
crisis: (gdeltData.crisis || []).length,
|
||||
topTitles: (gdeltData.allArticles || []).slice(0, 5).map(a => a.title?.substring(0, 80))
|
||||
topTitles: (gdeltData.allArticles || []).slice(0, 5).map(a => a.title?.substring(0, 80)),
|
||||
geoPoints: (gdeltData.geoPoints || []).slice(0, 20).map(p => ({
|
||||
lat: p.lat, lon: p.lon, name: (p.name || '').substring(0, 80), count: p.count || 1
|
||||
}))
|
||||
};
|
||||
|
||||
const health = Object.entries(data.sources).map(([name, src]) => ({
|
||||
@@ -457,7 +498,7 @@ export async function synthesize(data) {
|
||||
meta: data.crucix, air, thermal, tSignals, chokepoints, nuke, nukeSignals,
|
||||
sdr: { total: sdrNet.totalReceivers || 0, online: sdrNet.online || 0, zones: sdrZones },
|
||||
tg: { posts: tgData.totalPosts || 0, urgent: tgUrgent, topPosts: tgTop },
|
||||
who, fred, energy, bls, treasury, gscpi, defense, noaa, acled, gdelt, space, health, news,
|
||||
who, fred, energy, bls, treasury, gscpi, defense, noaa, epa, acled, gdelt, space, health, news,
|
||||
markets, // Live Yahoo Finance market data
|
||||
ideas: [], ideasSource: 'disabled',
|
||||
// newsFeed for ticker (merged RSS + GDELT + Telegram)
|
||||
|
||||
Reference in New Issue
Block a user