Complete Beast format implementation with enhanced features and fixes #19

Merged
olemd merged 38 commits from beast-format-refactor into main 2025-08-24 20:50:38 +02:00
7 changed files with 174 additions and 1415 deletions
Showing only changes of commit 776cef1185 - Show all commits

Clean up excessive console logging and remove duplicate app files

- Remove verbose console.log statements from WebSocket, map, and aircraft managers
- Keep essential error messages and warnings for debugging
- Consolidate app-new.js into app.js to eliminate confusing duplicate files
- Update HTML reference to use clean app.js with incremented cache version
- Significantly reduce console noise for better user experience

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

Co-Authored-By: Claude <noreply@anthropic.com>
Ole-Morten Duesund 2025-08-24 14:55:54 +02:00

View file

@ -222,6 +222,6 @@
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
<!-- Custom JS -->
<script type="module" src="/static/js/app-new.js?v=3"></script>
<script type="module" src="/static/js/app.js?v=4"></script>
</body>
</html>

View file

@ -1,391 +0,0 @@
// Import Three.js modules
import * as THREE from 'three';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
// Import our modular components
import { WebSocketManager } from './modules/websocket.js?v=2';
import { AircraftManager } from './modules/aircraft-manager.js?v=2';
import { MapManager } from './modules/map-manager.js?v=2';
import { UIManager } from './modules/ui-manager.js?v=2';
class SkyView {
constructor() {
console.log('🚀 SkyView v2 - KISS approach loaded');
// Initialize managers
this.wsManager = null;
this.aircraftManager = null;
this.mapManager = null;
this.uiManager = null;
// 3D Radar
this.radar3d = null;
// Charts
this.charts = {};
this.init();
}
async init() {
try {
console.log('Initializing SkyView application...');
// Initialize UI manager first
this.uiManager = new UIManager();
this.uiManager.initializeViews();
this.uiManager.initializeEventListeners();
// Initialize map manager and get the main map
this.mapManager = new MapManager();
const map = await this.mapManager.initializeMap();
// Initialize aircraft manager with the map
this.aircraftManager = new AircraftManager(map);
// Initialize WebSocket with callbacks
this.wsManager = new WebSocketManager(
(message) => this.handleWebSocketMessage(message),
(status) => this.uiManager.updateConnectionStatus(status)
);
await this.wsManager.connect();
// Initialize other components
this.initializeCharts();
this.uiManager.updateClocks();
this.initialize3DRadar();
// Set up map controls
this.setupMapControls();
// Set up aircraft selection listener
this.setupAircraftSelection();
this.startPeriodicTasks();
console.log('SkyView application initialized successfully');
} catch (error) {
console.error('Initialization failed:', error);
this.uiManager.showError('Failed to initialize application');
}
}
setupMapControls() {
const centerMapBtn = document.getElementById('center-map');
const resetMapBtn = document.getElementById('reset-map');
const toggleTrailsBtn = document.getElementById('toggle-trails');
const toggleRangeBtn = document.getElementById('toggle-range');
const toggleSourcesBtn = document.getElementById('toggle-sources');
if (centerMapBtn) {
centerMapBtn.addEventListener('click', () => this.aircraftManager.centerMapOnAircraft());
}
if (resetMapBtn) {
resetMapBtn.addEventListener('click', () => this.mapManager.resetMap());
}
if (toggleTrailsBtn) {
toggleTrailsBtn.addEventListener('click', () => {
const showTrails = this.aircraftManager.toggleTrails();
toggleTrailsBtn.textContent = showTrails ? 'Hide Trails' : 'Show Trails';
});
}
if (toggleRangeBtn) {
toggleRangeBtn.addEventListener('click', () => {
const showRange = this.mapManager.toggleRangeCircles();
toggleRangeBtn.textContent = showRange ? 'Hide Range' : 'Show Range';
});
}
if (toggleSourcesBtn) {
toggleSourcesBtn.addEventListener('click', () => {
const showSources = this.mapManager.toggleSources();
toggleSourcesBtn.textContent = showSources ? 'Hide Sources' : 'Show Sources';
});
}
// Coverage controls
const toggleHeatmapBtn = document.getElementById('toggle-heatmap');
const coverageSourceSelect = document.getElementById('coverage-source');
if (toggleHeatmapBtn) {
toggleHeatmapBtn.addEventListener('click', async () => {
const isActive = await this.mapManager.toggleHeatmap();
toggleHeatmapBtn.textContent = isActive ? 'Hide Heatmap' : 'Show Heatmap';
});
}
if (coverageSourceSelect) {
coverageSourceSelect.addEventListener('change', (e) => {
this.mapManager.setSelectedSource(e.target.value);
this.mapManager.updateCoverageDisplay();
});
}
}
setupAircraftSelection() {
document.addEventListener('aircraftSelected', (e) => {
const { icao, aircraft } = e.detail;
this.uiManager.switchView('map-view');
// DON'T change map view - just open popup like Leaflet expects
if (this.mapManager.map && aircraft.Latitude && aircraft.Longitude) {
const marker = this.aircraftManager.aircraftMarkers.get(icao);
if (marker) {
marker.openPopup();
}
}
});
}
handleWebSocketMessage(message) {
switch (message.type) {
case 'initial_data':
console.log('Received initial data - setting up source markers');
this.updateData(message.data);
// Setup source markers only on initial data load
this.mapManager.updateSourceMarkers();
break;
case 'aircraft_update':
this.updateData(message.data);
break;
default:
console.log('Unknown message type:', message.type);
}
}
updateData(data) {
// Update all managers with new data
this.uiManager.updateData(data);
this.aircraftManager.updateAircraftData(data);
this.mapManager.updateSourcesData(data);
// Update UI components
this.aircraftManager.updateMarkers();
this.uiManager.updateAircraftTable();
this.uiManager.updateStatistics();
this.uiManager.updateHeaderInfo();
// Update coverage controls
this.mapManager.updateCoverageControls();
if (this.uiManager.currentView === 'radar3d-view') {
this.update3DRadar();
}
}
// View switching
async switchView(viewId) {
const actualViewId = this.uiManager.switchView(viewId);
// Handle view-specific initialization
const baseName = actualViewId.replace('-view', '');
switch (baseName) {
case 'coverage':
await this.mapManager.initializeCoverageMap();
break;
case 'radar3d':
this.update3DRadar();
break;
}
}
// Charts
initializeCharts() {
const aircraftChartCanvas = document.getElementById('aircraft-chart');
if (!aircraftChartCanvas) {
console.warn('Aircraft chart canvas not found');
return;
}
try {
this.charts.aircraft = new Chart(aircraftChartCanvas, {
type: 'line',
data: {
labels: [],
datasets: [{
label: 'Aircraft Count',
data: [],
borderColor: '#00d4ff',
backgroundColor: 'rgba(0, 212, 255, 0.1)',
tension: 0.4
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: { display: false }
},
scales: {
x: { display: false },
y: {
beginAtZero: true,
ticks: { color: '#888' }
}
}
}
});
} catch (error) {
console.warn('Chart.js not available, skipping charts initialization');
}
}
updateCharts() {
if (!this.charts.aircraft) return;
const now = new Date();
const timeLabel = now.toLocaleTimeString();
// Update aircraft count chart
const chart = this.charts.aircraft;
chart.data.labels.push(timeLabel);
chart.data.datasets[0].data.push(this.aircraftManager.aircraftData.size);
if (chart.data.labels.length > 20) {
chart.data.labels.shift();
chart.data.datasets[0].data.shift();
}
chart.update('none');
}
// 3D Radar (basic implementation)
initialize3DRadar() {
try {
const container = document.getElementById('radar3d-container');
if (!container) return;
// Create scene
this.radar3d = {
scene: new THREE.Scene(),
camera: new THREE.PerspectiveCamera(75, container.clientWidth / container.clientHeight, 0.1, 1000),
renderer: new THREE.WebGLRenderer({ alpha: true, antialias: true }),
controls: null,
aircraftMeshes: new Map()
};
// Set up renderer
this.radar3d.renderer.setSize(container.clientWidth, container.clientHeight);
this.radar3d.renderer.setClearColor(0x0a0a0a, 0.9);
container.appendChild(this.radar3d.renderer.domElement);
// Add lighting
const ambientLight = new THREE.AmbientLight(0x404040, 0.6);
this.radar3d.scene.add(ambientLight);
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8);
directionalLight.position.set(10, 10, 5);
this.radar3d.scene.add(directionalLight);
// Set up camera
this.radar3d.camera.position.set(0, 50, 50);
this.radar3d.camera.lookAt(0, 0, 0);
// Add controls
this.radar3d.controls = new OrbitControls(this.radar3d.camera, this.radar3d.renderer.domElement);
this.radar3d.controls.enableDamping = true;
this.radar3d.controls.dampingFactor = 0.05;
// Add ground plane
const groundGeometry = new THREE.PlaneGeometry(200, 200);
const groundMaterial = new THREE.MeshLambertMaterial({
color: 0x2a4d3a,
transparent: true,
opacity: 0.5
});
const ground = new THREE.Mesh(groundGeometry, groundMaterial);
ground.rotation.x = -Math.PI / 2;
this.radar3d.scene.add(ground);
// Add grid
const gridHelper = new THREE.GridHelper(200, 20, 0x44aa44, 0x44aa44);
this.radar3d.scene.add(gridHelper);
// Start render loop
this.render3DRadar();
console.log('3D Radar initialized successfully');
} catch (error) {
console.error('Failed to initialize 3D radar:', error);
}
}
update3DRadar() {
if (!this.radar3d || !this.radar3d.scene || !this.aircraftManager) return;
try {
// Update aircraft positions in 3D space
this.aircraftManager.aircraftData.forEach((aircraft, icao) => {
if (aircraft.Latitude && aircraft.Longitude) {
const key = icao.toString();
if (!this.radar3d.aircraftMeshes.has(key)) {
// Create new aircraft mesh
const geometry = new THREE.ConeGeometry(0.5, 2, 6);
const material = new THREE.MeshLambertMaterial({ color: 0x00ff00 });
const mesh = new THREE.Mesh(geometry, material);
this.radar3d.aircraftMeshes.set(key, mesh);
this.radar3d.scene.add(mesh);
}
const mesh = this.radar3d.aircraftMeshes.get(key);
// Convert lat/lon to local coordinates (simplified)
const x = (aircraft.Longitude - (-0.4600)) * 111320 * Math.cos(aircraft.Latitude * Math.PI / 180) / 1000;
const z = -(aircraft.Latitude - 51.4700) * 111320 / 1000;
const y = (aircraft.Altitude || 0) / 1000; // Convert feet to km for display
mesh.position.set(x, y, z);
// Orient mesh based on track
if (aircraft.Track !== undefined) {
mesh.rotation.y = -aircraft.Track * Math.PI / 180;
}
}
});
// Remove old aircraft
this.radar3d.aircraftMeshes.forEach((mesh, key) => {
if (!this.aircraftManager.aircraftData.has(key)) {
this.radar3d.scene.remove(mesh);
this.radar3d.aircraftMeshes.delete(key);
}
});
} catch (error) {
console.error('Failed to update 3D radar:', error);
}
}
render3DRadar() {
if (!this.radar3d) return;
requestAnimationFrame(() => this.render3DRadar());
if (this.radar3d.controls) {
this.radar3d.controls.update();
}
this.radar3d.renderer.render(this.radar3d.scene, this.radar3d.camera);
}
startPeriodicTasks() {
// Update clocks every second
setInterval(() => this.uiManager.updateClocks(), 1000);
// Update charts every 10 seconds
setInterval(() => this.updateCharts(), 10000);
// Periodic cleanup
setInterval(() => {
// Clean up old trail data, etc.
}, 30000);
}
}
// Initialize application when DOM is ready
document.addEventListener('DOMContentLoaded', () => {
window.skyview = new SkyView();
});

File diff suppressed because it is too large Load diff

View file

@ -22,7 +22,6 @@ export class AircraftManager {
for (const [icao, aircraft] of Object.entries(data.aircraft)) {
this.aircraftData.set(icao, aircraft);
}
console.log(`Aircraft data updated: ${this.aircraftData.size} aircraft`);
}
}
@ -57,9 +56,6 @@ export class AircraftManager {
updateAircraftMarker(icao, aircraft) {
const pos = [aircraft.Latitude, aircraft.Longitude];
// Debug: Log coordinate format and values
console.log(`📍 ${icao}: pos=[${pos[0]}, ${pos[1]}], types=[${typeof pos[0]}, ${typeof pos[1]}]`);
console.log(`🔍 Marker check for ${icao}: has=${this.aircraftMarkers.has(icao)}, map_size=${this.aircraftMarkers.size}`);
// Check for invalid coordinates - proper geographic bounds
const isValidLat = pos[0] >= -90 && pos[0] <= 90;
@ -76,7 +72,6 @@ export class AircraftManager {
// Always update position - let Leaflet handle everything
const oldPos = marker.getLatLng();
console.log(`🔄 Updating ${icao}: [${oldPos.lat}, ${oldPos.lng}] -> [${pos[0]}, ${pos[1]}]`);
marker.setLatLng(pos);
// Update rotation using Leaflet's options if available, otherwise skip rotation
@ -100,7 +95,6 @@ export class AircraftManager {
} else {
// Create new marker
console.log(`Creating new marker for ${icao}`);
const icon = this.createAircraftIcon(aircraft);
try {
@ -116,14 +110,12 @@ export class AircraftManager {
this.aircraftMarkers.set(icao, marker);
this.markerCreateCount++;
console.log(`Created marker for ${icao}, total markers: ${this.aircraftMarkers.size}`);
// Force immediate visibility
if (marker._icon) {
marker._icon.style.display = 'block';
marker._icon.style.opacity = '1';
marker._icon.style.visibility = 'visible';
console.log(`Forced visibility for new marker ${icao}`);
}
} catch (error) {
console.error(`Failed to create marker for ${icao}:`, error);
@ -442,8 +434,4 @@ export class AircraftManager {
}
}
// Simple debug method
debugState() {
console.log(`Aircraft: ${this.aircraftData.size}, Markers: ${this.aircraftMarkers.size}`);
}
}

View file

@ -32,7 +32,6 @@ export class MapManager {
// Store origin for reset functionality
this.mapOrigin = origin;
console.log(`🗺️ Map origin: [${origin.latitude}, ${origin.longitude}]`);
this.map = L.map('map').setView([origin.latitude, origin.longitude], 10);
// Dark tile layer
@ -42,7 +41,6 @@ export class MapManager {
maxZoom: 19
}).addTo(this.map);
console.log('Main map initialized');
return this.map;
}
@ -307,7 +305,6 @@ export class MapManager {
createHeatmapOverlay(data) {
// Simplified heatmap implementation
// In production, would use proper heatmap library like Leaflet.heat
console.log('Creating heatmap overlay with data:', data);
}
setSelectedSource(sourceId) {

View file

@ -14,12 +14,10 @@ export class WebSocketManager {
this.websocket = new WebSocket(wsUrl);
this.websocket.onopen = () => {
console.log('WebSocket connected');
this.onStatusChange('connected');
};
this.websocket.onclose = () => {
console.log('WebSocket disconnected');
this.onStatusChange('disconnected');
// Reconnect after 5 seconds
setTimeout(() => this.connect(), 5000);
@ -34,20 +32,6 @@ export class WebSocketManager {
try {
const message = JSON.parse(event.data);
// Debug: Log WebSocket messages to see what we're receiving
if (message.data && message.data.aircraft) {
const aircraftCount = Object.keys(message.data.aircraft).length;
console.log(`📡 WebSocket: ${message.type} with ${aircraftCount} aircraft`);
// Log first few aircraft with coordinates
let count = 0;
for (const [icao, aircraft] of Object.entries(message.data.aircraft)) {
if (count < 3 && aircraft.Latitude && aircraft.Longitude) {
console.log(`📡 ${icao}: lat=${aircraft.Latitude}, lon=${aircraft.Longitude}`);
}
count++;
}
}
this.onMessage(message);
} catch (error) {

BIN
beast-dump-with-heli.bin Normal file

Binary file not shown.