// Initialize charts let liveFeedChart, distributionChart, anomalyChart, lossTrendChart; // Simulate telemetry data let packetCounter = 0; let missingPackets = 0; let anomalies = 0; let isTimelinePaused = false; let timelineData = []; document.addEventListener('DOMContentLoaded', function() { // Only initialize if on dashboard page if (document.getElementById('live-feed-chart')) { initCharts(); simulateTelemetryData(); document.getElementById('pause-timeline').addEventListener('click', toggleTimeline); } // Set active nav link based on current page const navLinks = document.querySelectorAll('custom-navbar a'); navLinks.forEach(link => { if (link.getAttribute('href') === window.location.pathname) { link.classList.add('active'); } else { link.classList.remove('active'); } }); }); function initCharts() { const ctx1 = document.getElementById('live-feed-chart').getContext('2d'); liveFeedChart = new Chart(ctx1, { type: 'line', data: { labels: Array(20).fill().map((_, i) => i), datasets: [{ label: 'Packet Rate', data: Array(20).fill(0), borderColor: 'rgb(96, 165, 250)', tension: 0.1, fill: true, backgroundColor: 'rgba(96, 165, 250, 0.1)' }] }, options: { responsive: true, maintainAspectRatio: false, plugins: { legend: { display: false } }, scales: { y: { beginAtZero: true }, x: { display: false } } } }); const ctx2 = document.getElementById('packet-distribution-chart').getContext('2d'); distributionChart = new Chart(ctx2, { type: 'doughnut', data: { labels: ['Command', 'Telemetry', 'Science', 'Engineering'], datasets: [{ data: [25, 40, 20, 15], backgroundColor: [ 'rgba(59, 130, 246, 0.8)', 'rgba(139, 92, 246, 0.8)', 'rgba(16, 185, 129, 0.8)', 'rgba(245, 158, 11, 0.8)' ] }] }, options: { responsive: true, maintainAspectRatio: false } }); const ctx3 = document.getElementById('anomaly-detection-chart').getContext('2d'); anomalyChart = new Chart(ctx3, { type: 'bar', data: { labels: ['Temperature', 'Power', 'Radiation', 'Comms', 'Orientation'], datasets: [{ label: 'Anomaly Score', data: [0.2, 0.1, 0.05, 0.3, 0.15], backgroundColor: 'rgba(239, 68, 68, 0.8)' }] }, options: { responsive: true, maintainAspectRatio: false, scales: { y: { max: 1 } } } }); const ctx4 = document.getElementById('packet-loss-trend-chart').getContext('2d'); lossTrendChart = new Chart(ctx4, { type: 'line', data: { labels: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun'], datasets: [{ label: 'Packet Loss %', data: [2.1, 1.8, 1.5, 1.2, 0.9, 1.1], borderColor: 'rgb(239, 68, 68)', tension: 0.1 }] }, options: { responsive: true, maintainAspectRatio: false, plugins: { legend: { display: false } } } }); } function simulateTelemetryData() { setInterval(() => { if (Math.random() < 0.95) { // 95% packet reception rate packetCounter++; // Update live feed chart liveFeedChart.data.datasets[0].data.shift(); liveFeedChart.data.datasets[0].data.push(Math.floor(Math.random() * 100)); liveFeedChart.update(); // Add to timeline if not paused if (!isTimelinePaused) { const now = new Date(); const packet = { id: packetCounter, timestamp: now.toISOString(), type: ['CMD', 'TLM', 'SCI', 'ENG'][Math.floor(Math.random() * 4)], size: Math.floor(Math.random() * 1024) + 128, hasAnomaly: Math.random() < 0.05 }; if (packet.hasAnomaly) anomalies++; timelineData.unshift(packet); updateTimeline(); updateRawData(packet); } } else { missingPackets++; } // Update counters document.getElementById('packet-count').textContent = packetCounter; document.getElementById('missing-count').textContent = missingPackets; document.getElementById('anomaly-count').textContent = anomalies; }, 500); } function updateTimeline() { const timeline = document.getElementById('packet-timeline'); timeline.innerHTML = ''; timelineData.slice(0, 20).forEach(packet => { const item = document.createElement('div'); item.className = `flex items-center justify-between p-2 rounded-lg ${packet.hasAnomaly ? 'bg-red-900/50' : 'bg-gray-700/50'}`; item.innerHTML = `