From 43e55b2ba005d1191ba9a4d051b6bfcdaded5a38 Mon Sep 17 00:00:00 2001 From: Ole-Morten Duesund Date: Sun, 24 Aug 2025 15:29:43 +0200 Subject: [PATCH] Extract aircraft SVG icons to external files and add dynamic marker updates MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Extract all aircraft type SVG designs to separate files in /static/icons/ - Add icon caching system with async loading and fallback mechanisms - Implement dynamic marker icon updates when aircraft properties change - Detect and respond to aircraft type/category, ground status, and rotation changes - Use currentColor in SVG files for dynamic color application - Maintain performance with intelligent change detection (5° rotation threshold) - Support real-time marker updates for weight class transitions and ADS-B changes 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- assets/static/icons/cargo.svg | 9 ++ assets/static/icons/commercial.svg | 7 + assets/static/icons/ga.svg | 7 + assets/static/icons/ground.svg | 10 ++ assets/static/icons/helicopter.svg | 12 ++ assets/static/icons/military.svg | 7 + assets/static/js/modules/aircraft-manager.js | 154 ++++++++++++------- 7 files changed, 147 insertions(+), 59 deletions(-) create mode 100644 assets/static/icons/cargo.svg create mode 100644 assets/static/icons/commercial.svg create mode 100644 assets/static/icons/ga.svg create mode 100644 assets/static/icons/ground.svg create mode 100644 assets/static/icons/helicopter.svg create mode 100644 assets/static/icons/military.svg diff --git a/assets/static/icons/cargo.svg b/assets/static/icons/cargo.svg new file mode 100644 index 0000000..b3605b1 --- /dev/null +++ b/assets/static/icons/cargo.svg @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/assets/static/icons/commercial.svg b/assets/static/icons/commercial.svg new file mode 100644 index 0000000..f1f1b28 --- /dev/null +++ b/assets/static/icons/commercial.svg @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/assets/static/icons/ga.svg b/assets/static/icons/ga.svg new file mode 100644 index 0000000..cfba161 --- /dev/null +++ b/assets/static/icons/ga.svg @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/assets/static/icons/ground.svg b/assets/static/icons/ground.svg new file mode 100644 index 0000000..ee5af8e --- /dev/null +++ b/assets/static/icons/ground.svg @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/assets/static/icons/helicopter.svg b/assets/static/icons/helicopter.svg new file mode 100644 index 0000000..5197bea --- /dev/null +++ b/assets/static/icons/helicopter.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/assets/static/icons/military.svg b/assets/static/icons/military.svg new file mode 100644 index 0000000..c4e58a7 --- /dev/null +++ b/assets/static/icons/military.svg @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/assets/static/js/modules/aircraft-manager.js b/assets/static/js/modules/aircraft-manager.js index c032cfc..781c339 100644 --- a/assets/static/js/modules/aircraft-manager.js +++ b/assets/static/js/modules/aircraft-manager.js @@ -12,9 +12,67 @@ export class AircraftManager { this.markerUpdateCount = 0; this.markerRemoveCount = 0; + // SVG icon cache + this.iconCache = new Map(); + this.loadIcons(); + // Map event listeners removed - let Leaflet handle positioning naturally } + async loadIcons() { + const iconTypes = ['commercial', 'helicopter', 'military', 'cargo', 'ga', 'ground']; + + for (const type of iconTypes) { + try { + const response = await fetch(`/static/icons/${type}.svg`); + const svgText = await response.text(); + this.iconCache.set(type, svgText); + } catch (error) { + console.warn(`Failed to load icon for ${type}:`, error); + // Fallback to inline SVG if needed + this.iconCache.set(type, this.createFallbackIcon(type)); + } + } + } + + createFallbackIcon(type) { + // Fallback inline SVG if file loading fails + const color = 'currentColor'; + let path = ''; + + switch (type) { + case 'helicopter': + path = ` + + + `; + break; + case 'military': + path = ``; + break; + case 'cargo': + path = ` + `; + break; + case 'ga': + path = ``; + break; + case 'ground': + path = ` + + `; + break; + default: + path = ``; + } + + return ` + + + ${path} + +`; + } updateAircraftData(data) { if (data.aircraft) { @@ -74,13 +132,21 @@ export class AircraftManager { const oldPos = marker.getLatLng(); marker.setLatLng(pos); - // Update icon if track has changed to apply new rotation - if (aircraft.Track !== undefined) { - const currentRotation = marker._currentRotation || 0; - if (Math.abs(currentRotation - aircraft.Track) > 5) { // Update if rotation changed by more than 5 degrees - marker.setIcon(this.createAircraftIcon(aircraft)); - marker._currentRotation = aircraft.Track; - } + // Check if icon needs to be updated (track rotation, aircraft type, or ground status changes) + const currentRotation = marker._currentRotation || 0; + const currentType = marker._currentType || null; + const currentOnGround = marker._currentOnGround || false; + + const newType = this.getAircraftIconType(aircraft); + const rotationChanged = aircraft.Track !== undefined && Math.abs(currentRotation - aircraft.Track) > 5; + const typeChanged = currentType !== newType; + const groundStatusChanged = currentOnGround !== aircraft.OnGround; + + if (rotationChanged || typeChanged || groundStatusChanged) { + marker.setIcon(this.createAircraftIcon(aircraft)); + marker._currentRotation = aircraft.Track || 0; + marker._currentType = newType; + marker._currentOnGround = aircraft.OnGround || false; } // Handle popup exactly like Leaflet expects @@ -99,8 +165,10 @@ export class AircraftManager { icon: icon }).addTo(this.map); - // Store current rotation for future updates + // Store current properties for future update comparisons marker._currentRotation = aircraft.Track || 0; + marker._currentType = this.getAircraftIconType(aircraft); + marker._currentOnGround = aircraft.OnGround || false; marker.bindPopup(this.createPopupContent(aircraft), { maxWidth: 450, @@ -133,60 +201,28 @@ export class AircraftManager { const size = aircraft.OnGround ? 12 : 16; const rotation = aircraft.Track || 0; - // Create different SVG shapes based on aircraft type - let aircraftPath; + // Get SVG template from cache + let svgTemplate = this.iconCache.get(iconType) || this.iconCache.get('commercial'); - switch (iconType) { - case 'helicopter': - // Helicopter shape with rotor disc - aircraftPath = ` - - - - - `; - break; - case 'military': - // Swept-wing fighter jet shape - aircraftPath = ` - - `; - break; - case 'cargo': - // Wide-body cargo aircraft shape - aircraftPath = ` - - - `; - break; - case 'ga': - // Small general aviation aircraft - aircraftPath = ` - - `; - break; - case 'ground': - // Ground vehicle - simplified truck/car shape - aircraftPath = ` - - - - `; - break; - default: - // Default commercial aircraft shape - aircraftPath = ` - - `; + if (!svgTemplate) { + // Ultimate fallback - create a simple circle + svgTemplate = ` + + + + `; } - const svg = ` - - - ${aircraftPath} - - - `; + // Apply color and rotation to the SVG + let svg = svgTemplate + .replace(/currentColor/g, color) + .replace(/width="32"/, `width="${size * 2}"`) + .replace(/height="32"/, `height="${size * 2}"`); + + // Add rotation to the transform + if (rotation !== 0) { + svg = svg.replace(/transform="translate\(16,16\)"/, `transform="translate(16,16) rotate(${rotation})"`); + } return L.divIcon({ html: svg,