Map: TRAFFIC (TCAS) + NEXRAD overlays — two more dead softkeys now functional
The TRAFFIC and NEXRAD map keys were dead. Now: TRAFFIC draws TCAS diamonds (threat-coloured other/proximate/TA/RA, relative altitude + climb/descend arrow); NEXRAD draws green/yellow/red precip cells. Both toggle from the MAP softkeys and light when active. Driven by values.traffic / values.wxCells, which the demo synthesizes so they're demonstrable; the live-sim binding (TCAS/weather datarefs) is the part that still needs a sim session to wire+verify. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -326,6 +326,17 @@ function startDemo() {
|
||||
engRpm: [2410], fuelFlow: [0.0072], oilTemp: [88], oilPress: [52], egt: [720],
|
||||
fuelQty: [60, 58], volts: [process.env.DEMO_ALERT ? 23.4 : 28.0, 27.8], amps: [-1.5], genAmps: [20.5], engHrs: 5040,
|
||||
fuelTot: 118 * 2.72, fuelMax: 144 * 2.72, // fuel totalizer: 118 of 144 gal (kg) — SYSTEM keys adjust
|
||||
// TRAFFIC (TCAS) + NEXRAD demo data so those map overlays are demonstrable.
|
||||
// relAlt = hundreds of ft vs own ship; vs +/- = climb/descend; thr = TA/RA.
|
||||
traffic: [
|
||||
{ lat: 47.52, lon: -122.28, relAlt: 12, vs: 1, thr: 0 },
|
||||
{ lat: 47.40, lon: -122.45, relAlt: -8, vs: -1, thr: 1 },
|
||||
{ lat: 47.47, lon: -122.18, relAlt: 2, vs: 0, thr: 2 },
|
||||
],
|
||||
wxCells: [ // synthetic NEXRAD precip: lat,lon,radiusNm,level(1 green·2 yellow·3 red)
|
||||
{ lat: 47.7, lon: -122.0, r: 8, lvl: 2 }, { lat: 47.75, lon: -121.9, r: 5, lvl: 3 },
|
||||
{ lat: 47.2, lon: -122.6, r: 10, lvl: 1 }, { lat: 47.25, lon: -122.5, r: 6, lvl: 2 },
|
||||
],
|
||||
});
|
||||
// a sample plan so the map/FMS show something in demo mode
|
||||
fp.setPlan({ name: 'DEMO', waypoints: [
|
||||
|
||||
@@ -76,6 +76,8 @@ export default function Bezel({ variant = 'pfd', xp, svt3d, onToggleSvt, svtOpts
|
||||
else if (label === 'DCLTR') cycleDcltr(onMapMode);
|
||||
else if (label === 'AIRWAYS') onMapMode && onMapMode((m) => ({ ...m, airways: (((m.airways | 0) + 1) % 4) })); // off→all→Victor→Jet
|
||||
else if (label === 'AIRSPACE') onMapMode && onMapMode((m) => ({ ...m, airspace: !m.airspace }));
|
||||
else if (label === 'TRAFFIC') onMapMode && onMapMode((m) => ({ ...m, traffic: !m.traffic }));
|
||||
else if (label === 'NEXRAD') onMapMode && onMapMode((m) => ({ ...m, nexrad: !m.nexrad }));
|
||||
} else {
|
||||
if (label === 'PFD') setPage('pfd');
|
||||
else if (label === 'BACK') setPage({ xpdrcode: 'xpdr', altunit: 'pfd' }[page] || 'root');
|
||||
@@ -118,7 +120,7 @@ export default function Bezel({ variant = 'pfd', xp, svt3d, onToggleSvt, svtOpts
|
||||
if (variant === 'mfd') return (label === 'TOPO' && mapMode?.base === 'topo')
|
||||
|| (label === 'TERRAIN' && mapMode?.terrain) || (label === 'OSM' && mapMode?.base === 'osm')
|
||||
|| (label === 'DCLTR' && mapMode?.dcltr > 0) || (label === 'AIRWAYS' && mapMode?.airways)
|
||||
|| (label === 'AIRSPACE' && mapMode?.airspace);
|
||||
|| (label === 'AIRSPACE' && mapMode?.airspace) || (label === 'TRAFFIC' && mapMode?.traffic) || (label === 'NEXRAD' && mapMode?.nexrad);
|
||||
return (label === 'SYN TERR' && svt3d) || (label === 'PATHWAY' && svtOpts?.pathway) || (label === 'APTSIGNS' && svtOpts?.aptSigns)
|
||||
|| (label === 'INSET' && inset) || (label === 'NRST' && nrst) || (label === 'TMR/REF' && tmr)
|
||||
|| (label === 'DME' && dme) || (label === 'OBS' && obs) || (label === 'CAUTION' && (alerts || hasAlerts))
|
||||
|
||||
@@ -57,6 +57,19 @@ const TILES = {
|
||||
dark: null,
|
||||
};
|
||||
|
||||
// TCAS target symbol: diamond coloured by threat (other/proximate/TA/RA), with
|
||||
// relative altitude (hundreds of ft, ± vs own ship) and a climb/descend arrow.
|
||||
const TCAS_COLOR = ['#cfd6dd', '#19d3ff', '#ffce00', '#ff3b3b'];
|
||||
function tcasSymbol(t) {
|
||||
const C = TCAS_COLOR[t.thr || 0];
|
||||
const filled = (t.thr || 0) >= 1;
|
||||
const arrow = t.vs > 0 ? '▲' : t.vs < 0 ? '▼' : '';
|
||||
const rel = (t.relAlt >= 0 ? '+' : '−') + String(Math.abs(Math.round(t.relAlt))).padStart(2, '0');
|
||||
const diamond = `<svg viewBox='0 0 16 16' width='16' height='16'><polygon points='8,1 15,8 8,15 1,8' fill='${filled ? C : 'none'}' stroke='${C}' stroke-width='2'/></svg>`;
|
||||
const html = `<div class='tcas-sym' style='color:${C}'>${diamond}<span class='tcas-lbl'>${rel}${arrow}</span></div>`;
|
||||
return L.marker([t.lat, t.lon], { icon: L.divIcon({ className: 'tcas-divicon', html, iconSize: [16, 16], iconAnchor: [8, 8] }), interactive: false, zIndexOffset: 1200 });
|
||||
}
|
||||
|
||||
// G1000 / aeronautical-chart airspace styling, keyed by our coarse class. B/C/D
|
||||
// follow chart convention (B solid blue, C solid magenta, D dashed blue);
|
||||
// special-use areas use warm hues. Class A/E are omitted (they blanket huge
|
||||
@@ -88,6 +101,8 @@ export default function MapView({ values, flightPlan, fp, inset = false, hud = t
|
||||
const aspLayerRef = useRef(null);
|
||||
const aspOnRef = useRef(false);
|
||||
const refreshAirspaceRef = useRef(null);
|
||||
const wxLayerRef = useRef(null);
|
||||
const trafficLayerRef = useRef(null);
|
||||
const baseRef = useRef(null);
|
||||
const terrRef = useRef(null);
|
||||
const zoomingRef = useRef(false);
|
||||
@@ -102,6 +117,8 @@ export default function MapView({ values, flightPlan, fp, inset = false, hud = t
|
||||
const base = mapMode?.base || 'topo';
|
||||
const airways = (mapMode?.airways | 0); // 0 off · 1 all · 2 Victor (low) · 3 Jet (high)
|
||||
const airspace = !!mapMode?.airspace;
|
||||
const traffic = !!mapMode?.traffic;
|
||||
const nexrad = !!mapMode?.nexrad;
|
||||
aspOnRef.current = airspace;
|
||||
const dcltrRef = useRef(dcltr);
|
||||
dcltrRef.current = dcltr;
|
||||
@@ -135,11 +152,13 @@ export default function MapView({ values, flightPlan, fp, inset = false, hud = t
|
||||
map.getPane('terrain').style.zIndex = 250;
|
||||
map.getPane('terrain').style.pointerEvents = 'none';
|
||||
|
||||
aspLayerRef.current = L.layerGroup().addTo(map); // airspace polygons (bottom overlay)
|
||||
wxLayerRef.current = L.layerGroup().addTo(map); // NEXRAD precip (bottom)
|
||||
aspLayerRef.current = L.layerGroup().addTo(map); // airspace polygons
|
||||
awyLayerRef.current = L.layerGroup().addTo(map); // airways
|
||||
navLayerRef.current = L.layerGroup().addTo(map); // real airports/navaids/fixes
|
||||
routeRef.current = L.layerGroup().addTo(map); // flight-plan legs (white + magenta active)
|
||||
wpLayerRef.current = L.layerGroup().addTo(map);
|
||||
trafficLayerRef.current = L.layerGroup().addTo(map); // TCAS targets (top)
|
||||
|
||||
// AIRWAYS overlay (Victor/Jet routes from X-Plane's earth_awy.dat). Light
|
||||
// blue lines with the airway name at the segment midpoint (labels ≥ z8).
|
||||
@@ -259,6 +278,26 @@ export default function MapView({ values, flightPlan, fp, inset = false, hud = t
|
||||
// redraw airspace when the AIRSPACE toggle changes
|
||||
useEffect(() => { refreshAirspaceRef.current && refreshAirspaceRef.current(); }, [airspace]); // eslint-disable-line
|
||||
|
||||
// NEXRAD precip cells (green/yellow/red) — toggled by the MFD NEXRAD softkey.
|
||||
useEffect(() => {
|
||||
const layer = wxLayerRef.current; if (!layer) return;
|
||||
layer.clearLayers();
|
||||
if (!nexrad) return;
|
||||
const col = { 1: '#1fa83a', 2: '#e6c200', 3: '#e23131' };
|
||||
for (const c of (values.wxCells || [])) {
|
||||
if (!isFinite(c.lat)) continue;
|
||||
L.circle([c.lat, c.lon], { radius: (c.r || 5) * 1852, stroke: false, fillColor: col[c.lvl] || col[1], fillOpacity: 0.32, interactive: false }).addTo(layer);
|
||||
}
|
||||
}, [nexrad, values.wxCells]); // eslint-disable-line
|
||||
|
||||
// TCAS traffic targets — toggled by the MFD TRAFFIC softkey.
|
||||
useEffect(() => {
|
||||
const layer = trafficLayerRef.current; if (!layer) return;
|
||||
layer.clearLayers();
|
||||
if (!traffic) return;
|
||||
for (const tgt of (values.traffic || [])) { if (isFinite(tgt.lat)) layer.addLayer(tcasSymbol(tgt)); }
|
||||
}, [traffic, values.traffic]); // eslint-disable-line
|
||||
|
||||
// TERRAIN AWARENESS overlay: colour the elevation grid (from the FlyWithLua
|
||||
// terrain probe) relative to aircraft altitude — red within 100 ft below/above,
|
||||
// yellow 100–1000 ft below, transparent otherwise (G1000 TAWS colours). Only
|
||||
|
||||
@@ -411,6 +411,10 @@ body {
|
||||
.nav-sym { position: relative; width: 18px; height: 18px; }
|
||||
.nav-lbl { position: absolute; left: 19px; top: 1px; font: 700 11px/1 monospace; white-space: nowrap;
|
||||
text-shadow: 0 0 2px #000, 0 0 2px #000, 1px 1px 1px #000; }
|
||||
/* TCAS traffic target: diamond + relative-altitude label */
|
||||
.tcas-sym { position: relative; width: 16px; height: 16px; }
|
||||
.tcas-lbl { position: absolute; left: 50%; top: -11px; transform: translateX(-50%); font: 700 10px/1 monospace; white-space: nowrap;
|
||||
text-shadow: 0 0 2px #000, 0 0 2px #000, 1px 1px 1px #000; }
|
||||
/* Bank pivots about the aircraft reference (attitude centre), which sits ~28%
|
||||
down the full-screen terrain box — so terrain roll tracks the attitude. */
|
||||
.svt-canvas { width: 100%; height: 100%; transform-origin: 50% 28%; }
|
||||
|
||||
Reference in New Issue
Block a user