Implement server-side trail tracking and fix aircraft marker orientation

- Replace client-side trail collection with server-provided position history
- Fix aircraft markers to properly orient based on track heading using SVG rotation
- Add beast-dump binary to debian package with comprehensive man pages
- Trail visualization now uses gradient effect where newer positions are brighter
- Marker icons update when track heading changes by more than 5 degrees for performance

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Ole-Morten Duesund 2025-08-24 15:18:51 +02:00
commit da4645d483
5 changed files with 231 additions and 32 deletions

View file

@ -74,16 +74,13 @@ export class AircraftManager {
const oldPos = marker.getLatLng();
marker.setLatLng(pos);
// Update rotation using Leaflet's options if available, otherwise skip rotation
// Update icon if track has changed to apply new rotation
if (aircraft.Track !== undefined) {
if (marker.setRotationAngle) {
// Use Leaflet rotation plugin method if available
marker.setRotationAngle(aircraft.Track);
} else if (marker.options) {
// Update the marker's options for consistency
marker.options.rotationAngle = aircraft.Track;
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;
}
// Don't manually set CSS transforms - let Leaflet handle it
}
// Handle popup exactly like Leaflet expects
@ -99,10 +96,12 @@ export class AircraftManager {
try {
const marker = L.marker(pos, {
icon: icon,
rotationAngle: aircraft.Track || 0
icon: icon
}).addTo(this.map);
// Store current rotation for future updates
marker._currentRotation = aircraft.Track || 0;
marker.bindPopup(this.createPopupContent(aircraft), {
maxWidth: 450,
className: 'aircraft-popup'
@ -124,7 +123,7 @@ export class AircraftManager {
// Update trails
if (this.showTrails) {
this.updateAircraftTrail(icao, pos);
this.updateAircraftTrail(icao, aircraft);
}
}
@ -132,6 +131,7 @@ export class AircraftManager {
const iconType = this.getAircraftIconType(aircraft);
const color = this.getAircraftColor(iconType);
const size = aircraft.OnGround ? 12 : 16;
const rotation = aircraft.Track || 0;
// Create different SVG shapes based on aircraft type
let aircraftPath;
@ -182,7 +182,7 @@ export class AircraftManager {
const svg = `
<svg width="${size * 2}" height="${size * 2}" viewBox="0 0 32 32">
<g transform="translate(16,16)">
<g transform="translate(16,16) rotate(${rotation})">
${aircraftPath}
</g>
</svg>
@ -236,33 +236,48 @@ export class AircraftManager {
}
updateAircraftTrail(icao, pos) {
updateAircraftTrail(icao, aircraft) {
// Use server-provided position history
if (!aircraft.position_history || aircraft.position_history.length < 2) {
// No trail data available or not enough points
if (this.aircraftTrails.has(icao)) {
const trail = this.aircraftTrails.get(icao);
if (trail.polyline) {
this.map.removeLayer(trail.polyline);
}
this.aircraftTrails.delete(icao);
}
return;
}
// Convert position history to Leaflet format
const trailPoints = aircraft.position_history.map(point => [point.lat, point.lon]);
// Get or create trail object
if (!this.aircraftTrails.has(icao)) {
this.aircraftTrails.set(icao, []);
this.aircraftTrails.set(icao, {});
}
const trail = this.aircraftTrails.get(icao);
trail.push(pos);
// Keep only last 50 positions
if (trail.length > 50) {
trail.shift();
// Remove old polyline if it exists
if (trail.polyline) {
this.map.removeLayer(trail.polyline);
}
// Draw polyline
const trailLine = L.polyline(trail, {
color: '#00d4ff',
weight: 2,
opacity: 0.6
}).addTo(this.map);
// Store reference for cleanup
if (!this.aircraftTrails.get(icao).polyline) {
this.aircraftTrails.get(icao).polyline = trailLine;
} else {
this.map.removeLayer(this.aircraftTrails.get(icao).polyline);
this.aircraftTrails.get(icao).polyline = trailLine;
// Create gradient effect - newer points are brighter
const segments = [];
for (let i = 1; i < trailPoints.length; i++) {
const opacity = 0.2 + (0.6 * (i / trailPoints.length)); // Fade from 0.2 to 0.8
const segment = L.polyline([trailPoints[i-1], trailPoints[i]], {
color: '#00d4ff',
weight: 2,
opacity: opacity
});
segments.push(segment);
}
// Create a feature group for all segments
trail.polyline = L.featureGroup(segments).addTo(this.map);
}
createPopupContent(aircraft) {