diff --git a/templates/adsb_dashboard.html b/templates/adsb_dashboard.html index 244d665..9cd1e30 100644 --- a/templates/adsb_dashboard.html +++ b/templates/adsb_dashboard.html @@ -2973,12 +2973,17 @@ sudo make install const color = militaryInfo.military ? '#556b2f' : getAltitudeColor(ac.altitude); const callsign = ac.callsign || icao; const alt = ac.altitude ? ac.altitude + ' ft' : 'N/A'; + const typeLabel = ac.type_desc || ac.type_code || ''; const iconType = getAircraftIconType(ac.type_code, militaryInfo.military); const isSelected = icao === selectedIcao; const prevState = markerState[icao] || {}; const iconChanged = prevState.rotation !== rotation || prevState.color !== color || prevState.iconType !== iconType || prevState.isSelected !== isSelected; - const tooltipChanged = prevState.callsign !== callsign || prevState.alt !== alt; + const tooltipChanged = prevState.callsign !== callsign || prevState.alt !== alt || prevState.typeLabel !== typeLabel; + + const tooltipContent = typeLabel + ? `${callsign}
${typeLabel}
${alt}` + : `${callsign}
${alt}`; if (markers[icao]) { markers[icao].setLatLng([ac.lat, ac.lon]); @@ -2987,7 +2992,7 @@ sudo make install } if (tooltipChanged) { markers[icao].unbindTooltip(); - markers[icao].bindTooltip(`${callsign}
${alt}`, { + markers[icao].bindTooltip(tooltipContent, { permanent: false, direction: 'top', className: 'aircraft-tooltip' }); } @@ -2995,24 +3000,32 @@ sudo make install markers[icao] = L.marker([ac.lat, ac.lon], { icon: createMarkerIcon(rotation, color, iconType, isSelected) }) .addTo(radarMap) .on('click', () => selectAircraft(icao, 'map')); - markers[icao].bindTooltip(`${callsign}
${alt}`, { + markers[icao].bindTooltip(tooltipContent, { permanent: false, direction: 'top', className: 'aircraft-tooltip' }); } - markerState[icao] = { rotation, color, callsign, alt, iconType, isSelected }; + markerState[icao] = { rotation, color, callsign, alt, typeLabel, iconType, isSelected }; } // Aircraft type icon SVG paths const AIRCRAFT_ICONS = { + // Widebody: wide wingspan, wide tail — 747, 777, A330, A380 etc. + widebody: 'M12 2L7 10H2v2l10 4 10-4v-2h-5L12 2zm0 14l-7 3v1h14v-1l-7-3z', + // Narrowbody / default jet — A320, B737 etc. jet: 'M12 2L8 10H4v2l8 4 8-4v-2h-4L12 2zm0 14l-6 3v1h12v-1l-6-3z', + // Business jet: narrow swept wings set further aft + bizjet: 'M12 2L11 11H7v2l5 2.5 5-2.5v-2h-4L12 2zm0 13l-4 2v1h8v-1l-4-2z', + // Turboprop: straight high-aspect wings, engines forward + turboprop: 'M12 2L10 8H3v2.5l9 3.5 9-3.5V8h-7L12 2zm0 13l-5 2.5v1h10v-1l-5-2.5z', helicopter: 'M12 4L10 6H8V8h1l3 8 3-8h1V6h-2L12 4zm-1 14v2H9v1h6v-1h-2v-2h-2zm7-7h-2v2h2v-2zM4 11h2v2H4v-2z', + // Light piston GA — C172, PA28 etc. prop: 'M12 3L9 8H5v2l7 6 7-6v-2h-4L12 3zm0 12l-4 2v1h8v-1l-4-2z', military: 'M12 2L7 9H3l1 3 8 6 8-6 1-3h-4L12 2zm0 14l-5 2.5V20h10v-1.5L12 16z', glider: 'M12 4L10 8H4v1.5l8 4 8-4V8h-6L12 4zm0 10l-6 2v1h12v-1l-6-2z' }; - // Determine aircraft type from type_code + // Determine aircraft icon type from ICAO type_code function getAircraftIconType(typeCode, isMilitary) { if (isMilitary) return 'military'; if (!typeCode) return 'jet'; @@ -3021,22 +3034,51 @@ sudo make install // Helicopters if (code.startsWith('H') || code.includes('HELI') || - ['R22', 'R44', 'R66', 'EC35', 'EC45', 'AS50', 'AS55', 'AS65', 'B06', 'B212', 'B412', 'S76', 'A109', 'AW139', 'AW169'].some(h => code.includes(h))) { + ['R22', 'R44', 'R66', 'EC35', 'EC45', 'AS50', 'AS55', 'AS65', 'B06', 'B212', 'B412', + 'S76', 'S92', 'A109', 'AW139', 'AW169', 'AW189', 'EC25', 'EC30', 'EC75', 'EC85', + 'MI8', 'MI17', 'MI26', 'CH47', 'UH60', 'UH72', 'NH90'].some(h => code.includes(h))) { return 'helicopter'; } - // Gliders - if (code.startsWith('G') || code.includes('GLID')) { + // Gliders / motorgliders + if (code.startsWith('G') || ['GLID', 'DG1', 'DG2', 'DG3', 'DG4', 'DG5', 'ASK', 'ASW', + 'LS4', 'LS6', 'LS8', 'DUET', 'DISC', 'NIMB', 'PUCH', 'VENT'].some(g => code.includes(g))) { return 'glider'; } - // Light props (common GA aircraft) - if (['C150', 'C152', 'C172', 'C182', 'C206', 'C208', 'C210', 'PA28', 'PA32', 'PA34', 'PA44', 'PA46', 'SR20', 'SR22', 'DA40', 'DA42', 'TB20', 'M20', 'BE35', 'BE36', 'BE58'].some(p => code.includes(p))) { - return 'prop'; + // Widebody jets (twin-aisle) + if (['B741', 'B742', 'B743', 'B744', 'B748', 'B74D', 'B74R', 'B74S', + 'B762', 'B763', 'B764', 'B772', 'B773', 'B77L', 'B77W', 'B778', 'B779', + 'B788', 'B789', 'B78X', + 'A306', 'A30B', 'A310', 'A332', 'A333', 'A338', 'A339', + 'A342', 'A343', 'A345', 'A346', 'A359', 'A35K', 'A388', + 'IL86', 'IL96', 'MD11', 'DC10', 'L101'].some(w => code.startsWith(w) || code === w)) { + return 'widebody'; } - // Turboprops - if (['ATR', 'DH8', 'DHC', 'SF34', 'J328', 'B190', 'PC12', 'TBM'].some(t => code.includes(t))) { + // Business jets + if (['C25', 'C50', 'C51', 'C52', 'C55', 'C56', 'C65', 'C68', 'C70', 'C75', + 'GLF', 'GLEX', 'G150', 'G200', 'G280', 'G450', 'G500', 'G550', 'G600', 'G650', + 'LJ2', 'LJ3', 'LJ4', 'LJ5', 'LJ6', 'LJ7', + 'F2TH', 'F900', 'F7X', 'F8X', 'DA50', + 'CL30', 'CL35', 'CL60', 'CRJ1', 'CRJ2', + 'E135', 'E145', 'PC24', 'BE40', 'HA4T', 'PRM1'].some(b => code.startsWith(b))) { + return 'bizjet'; + } + + // Turboprops (regional airliners and utility) + if (['ATR', 'DH8', 'DHC', 'SF34', 'J328', 'B190', 'PC12', 'TBM', 'C208', + 'PAY', 'BE99', 'BE9L', 'SW4', 'IL18', 'AN24', 'AN26', 'AN28', + 'F27', 'F50', 'JS31', 'JS32', 'JS41', 'MA60', 'Y12'].some(t => code.startsWith(t) || code.includes(t))) { + return 'turboprop'; + } + + // Light piston GA + if (['C150', 'C152', 'C172', 'C182', 'C206', 'C210', 'C310', 'C337', + 'PA18', 'PA28', 'PA32', 'PA34', 'PA44', 'PA46', + 'SR20', 'SR22', 'DA40', 'DA42', 'TB20', 'TB9', + 'M20', 'BE35', 'BE36', 'BE58', 'BE60', + 'RV6', 'RV7', 'RV8', 'RV9', 'RV10'].some(p => code.startsWith(p) || code.includes(p))) { return 'prop'; } @@ -3045,7 +3087,7 @@ sudo make install function createMarkerIcon(rotation, color, iconType = 'jet', isSelected = false) { const path = AIRCRAFT_ICONS[iconType] || AIRCRAFT_ICONS.jet; - const size = iconType === 'helicopter' ? 22 : 24; + const size = iconType === 'helicopter' ? 22 : iconType === 'widebody' ? 26 : iconType === 'bizjet' ? 22 : 24; const glowColor = isSelected ? 'rgba(255,255,255,0.9)' : color; const glowSize = isSelected ? '10px' : '5px'; const trackingRing = isSelected ?