From 9be68eaf69d40501195ff30d21109e976707d3db Mon Sep 17 00:00:00 2001 From: Anushka Maitra Date: Sat, 17 Jan 2026 20:35:05 +0530 Subject: [PATCH 01/19] Add OrbitCanvas component for live orbit visualization --- frontend/src/components/OrbitCanvas.jsx | 92 +++++++++++++++++++++++++ 1 file changed, 92 insertions(+) create mode 100644 frontend/src/components/OrbitCanvas.jsx diff --git a/frontend/src/components/OrbitCanvas.jsx b/frontend/src/components/OrbitCanvas.jsx new file mode 100644 index 0000000..653a032 --- /dev/null +++ b/frontend/src/components/OrbitCanvas.jsx @@ -0,0 +1,92 @@ +import { useRef, useEffect } from 'react'; + +const OrbitCanvas = () => { + const canvasRef = useRef(null); + const animationRef = useRef(); + + useEffect(() => { + const canvas = canvasRef.current; + const ctx = canvas.getContext('2d'); + let time = 0; + + const resize = () => { + canvas.width = canvas.clientWidth; + canvas.height = canvas.clientHeight; + }; + resize(); + window.addEventListener('resize', resize); + + const animate = () => { + ctx.fillStyle = 'rgba(10, 10, 20, 0.1)'; + ctx.fillRect(0, 0, canvas.width, canvas.height); + + const centerX = canvas.width / 2; + const centerY = canvas.height / 2; + + // Central body (Earth-like) + ctx.fillStyle = '#4fd1c7'; + ctx.beginPath(); + ctx.arc(centerX, centerY, 20, 0, Math.PI * 2); + ctx.fill(); + + // Orbit 1: Close asteroid + ctx.strokeStyle = '#60a5fa'; + ctx.lineWidth = 1; + ctx.beginPath(); + ctx.arc(centerX, centerY, 80, 0, Math.PI * 2); + ctx.stroke(); + + // Orbit 2: Far asteroid + ctx.strokeStyle = '#f59e0b'; + ctx.lineWidth = 1; + ctx.beginPath(); + ctx.arc(centerX, centerY, 140, 0, Math.PI * 2); + ctx.stroke(); + + // Animated asteroids + ctx.save(); + ctx.translate(centerX, centerY); + + // Close asteroid + ctx.rotate(time * 0.02); + ctx.fillStyle = '#3b82f6'; + ctx.beginPath(); + ctx.arc(80, 0, 6, 0, Math.PI * 2); + ctx.fill(); + + // Far asteroid + ctx.rotate(-time * 0.01); + ctx.fillStyle = '#d97706'; + ctx.beginPath(); + ctx.arc(140, 0, 8, 0, Math.PI * 2); + ctx.fill(); + + ctx.restore(); + + time += 1; + animationRef.current = requestAnimationFrame(animate); + }; + + animate(); + + return () => { + window.removeEventListener('resize', resize); + if (animationRef.current) cancelAnimationFrame(animationRef.current); + }; + }, []); + + return ( +
+

Live Orbit Visualization

+ +

+ Blue: Low-risk NEO | Orange: Medium-risk NEO +

+
+ ); +}; + +export default OrbitCanvas; From 3fc8d1579b4b34b4699987e886ef3dd15a8f7ad4 Mon Sep 17 00:00:00 2001 From: Anushka Maitra Date: Sat, 17 Jan 2026 20:35:57 +0530 Subject: [PATCH 02/19] Add AsteroidPanel component to display nearby asteroids --- frontend/src/components/AsteroidPanel.jsx | 31 +++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 frontend/src/components/AsteroidPanel.jsx diff --git a/frontend/src/components/AsteroidPanel.jsx b/frontend/src/components/AsteroidPanel.jsx new file mode 100644 index 0000000..c1f1b6d --- /dev/null +++ b/frontend/src/components/AsteroidPanel.jsx @@ -0,0 +1,31 @@ +import { useState, useEffect } from 'react'; +import api from '../services/api.js'; + +const AsteroidPanel = () => { + const [asteroids, setAsteroids] = useState([]); + + useEffect(() => { + api.getAsteroids().then(setAsteroids); + }, []); + + return ( +
+

Nearby Asteroids

+
+ {asteroids.slice(0,5).map((ast) => ( +
+
{ast.name}
+
Distance: {ast.distance} LD
+
Velocity: {ast.velocity} km/s
+
Risk: {ast.risk}
+
+ ))} +
+ {asteroids.error && ( +

Connection error - using mock data

+ )} +
+ ); +}; + +export default AsteroidPanel; From 078392c2c772edd85d72ceb749939ac796431435 Mon Sep 17 00:00:00 2001 From: Anushka Maitra Date: Sat, 17 Jan 2026 20:37:35 +0530 Subject: [PATCH 03/19] Refactor Dashboard component to display stats --- frontend/src/components/Dashboard.jsx | 65 +++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 frontend/src/components/Dashboard.jsx diff --git a/frontend/src/components/Dashboard.jsx b/frontend/src/components/Dashboard.jsx new file mode 100644 index 0000000..665c195 --- /dev/null +++ b/frontend/src/components/Dashboard.jsx @@ -0,0 +1,65 @@ +import { useState, useEffect } from 'react'; +import { Line } from 'react-chartjs-2'; +import { + Chart as ChartJS, + CategoryScale, + LinearScale, + PointElement, + LineElement, + Title, + Tooltip, + Legend, +} from 'chart.js'; +import api from '../services/api.js'; + +ChartJS.register(CategoryScale, LinearScale, PointElement, LineElement, Title, Tooltip, Legend); + +const Dashboard = () => { + const [stats, setStats] = useState({ total: 0, avgDistance: 0, avgVelocity: 0 }); + + useEffect(() => { + api.getStats().then(setStats); + }, []); + + const data = { + labels: ['NEOs Tracked', 'Avg Distance (LD)', 'Avg Velocity (km/s)'], + datasets: [{ + label: 'Metrics', + data: [stats.total, stats.avgDistance, stats.avgVelocity], + borderColor: 'rgb(59, 130, 246)', + backgroundColor: 'rgba(59, 130, 246, 0.2)', + tension: 0.4, + }], + }; + + const options = { + responsive: true, + plugins: { legend: { position: 'top' } }, + scales: { y: { beginAtZero: true } }, + }; + + return ( +
+

Risk Metrics

+
+ +
+
+
+
{stats.total}
+
Total NEOs
+
+
+
{stats.avgDistance.toFixed(1)} LD
+
Avg Distance
+
+
+
{stats.avgVelocity.toFixed(1)} km/s
+
Avg Velocity
+
+
+
+ ); +}; + +export default Dashboard; From 937203df821966c05eab1874beb85496d44ee812 Mon Sep 17 00:00:00 2001 From: Anushka Maitra Date: Sat, 17 Jan 2026 20:39:53 +0530 Subject: [PATCH 04/19] Implement API service for fetching asteroids and stats --- frontend/src/services/api.js | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 frontend/src/services/api.js diff --git a/frontend/src/services/api.js b/frontend/src/services/api.js new file mode 100644 index 0000000..7b9b8a0 --- /dev/null +++ b/frontend/src/services/api.js @@ -0,0 +1,27 @@ +const API_BASE = import.meta.env.VITE_API_URL || 'http://localhost:8000/api'; + +const api = { + getAsteroids: async () => { + try { + const response = await fetch(`${API_BASE}/asteroids`); + if (!response.ok) throw new Error(`HTTP ${response.status}`); + return await response.json(); + } catch (error) { + console.error('API Error:', error); + return { asteroids: [], error: 'Failed to fetch asteroids' }; + } + }, + + getStats: async () => { + try { + const response = await fetch(`${API_BASE}/stats`); + if (!response.ok) throw new Error(`HTTP ${response.status}`); + return await response.json(); + } catch (error) { + console.error('Stats Error:', error); + return { total: 0, avgDistance: 0, avgVelocity: 0, error: 'Failed to fetch stats' }; + } + } +}; + +export default api; From dc96228395e9a7da0fc7e5e3e9887e38eea2564f Mon Sep 17 00:00:00 2001 From: Anushka Maitra Date: Sat, 17 Jan 2026 20:40:47 +0530 Subject: [PATCH 05/19] Create App.jsx --- frontend/src/services/App.jsx | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 frontend/src/services/App.jsx diff --git a/frontend/src/services/App.jsx b/frontend/src/services/App.jsx new file mode 100644 index 0000000..77752ab --- /dev/null +++ b/frontend/src/services/App.jsx @@ -0,0 +1,22 @@ +import OrbitCanvas from './components/OrbitCanvas.jsx'; +import AsteroidPanel from './components/AsteroidPanel.jsx'; +import Dashboard from './components/Dashboard.jsx'; + +function App() { + return ( +
+
+

+ Asteroid Orbit Tracker 🚀 +

+
+
+ + + +
+
+ ); +} + +export default App; From 4c0c1e76ae838366ca67283b435762b3154bd430 Mon Sep 17 00:00:00 2001 From: Anushka Maitra Date: Sat, 17 Jan 2026 20:43:33 +0530 Subject: [PATCH 06/19] Update and rename App.jsx to blank.js --- frontend/src/services/App.jsx | 22 ---------------------- frontend/src/services/blank.js | 1 + 2 files changed, 1 insertion(+), 22 deletions(-) delete mode 100644 frontend/src/services/App.jsx create mode 100644 frontend/src/services/blank.js diff --git a/frontend/src/services/App.jsx b/frontend/src/services/App.jsx deleted file mode 100644 index 77752ab..0000000 --- a/frontend/src/services/App.jsx +++ /dev/null @@ -1,22 +0,0 @@ -import OrbitCanvas from './components/OrbitCanvas.jsx'; -import AsteroidPanel from './components/AsteroidPanel.jsx'; -import Dashboard from './components/Dashboard.jsx'; - -function App() { - return ( -
-
-

- Asteroid Orbit Tracker 🚀 -

-
-
- - - -
-
- ); -} - -export default App; diff --git a/frontend/src/services/blank.js b/frontend/src/services/blank.js new file mode 100644 index 0000000..f70432a --- /dev/null +++ b/frontend/src/services/blank.js @@ -0,0 +1 @@ +//blank From d780e6ce60727d1ee216c639e9ac63ef56f660b9 Mon Sep 17 00:00:00 2001 From: Anushka Maitra Date: Sat, 17 Jan 2026 20:44:56 +0530 Subject: [PATCH 07/19] Initialize App component with layout and imports --- frontend/src/App.jsx | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 frontend/src/App.jsx diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx new file mode 100644 index 0000000..77752ab --- /dev/null +++ b/frontend/src/App.jsx @@ -0,0 +1,22 @@ +import OrbitCanvas from './components/OrbitCanvas.jsx'; +import AsteroidPanel from './components/AsteroidPanel.jsx'; +import Dashboard from './components/Dashboard.jsx'; + +function App() { + return ( +
+
+

+ Asteroid Orbit Tracker 🚀 +

+
+
+ + + +
+
+ ); +} + +export default App; From de275eb8aff5fee54e9b50e5318072e9bcbc8827 Mon Sep 17 00:00:00 2001 From: Anushka Maitra Date: Sat, 17 Jan 2026 20:45:28 +0530 Subject: [PATCH 08/19] Initialize main.jsx with React setup --- frontend/src/main.jsx | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 frontend/src/main.jsx diff --git a/frontend/src/main.jsx b/frontend/src/main.jsx new file mode 100644 index 0000000..54b39dd --- /dev/null +++ b/frontend/src/main.jsx @@ -0,0 +1,10 @@ +import React from 'react' +import ReactDOM from 'react-dom/client' +import App from './App.jsx' +import './index.css' + +ReactDOM.createRoot(document.getElementById('root')).render( + + + , +) From 3141c804bcfdf2a51b261645f1e2b1e8b7ce7764 Mon Sep 17 00:00:00 2001 From: Anushka Maitra Date: Sun, 18 Jan 2026 00:54:29 +0530 Subject: [PATCH 09/19] Add initial package.json for frontend setup --- frontend/package.json | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 frontend/package.json diff --git a/frontend/package.json b/frontend/package.json new file mode 100644 index 0000000..be84799 --- /dev/null +++ b/frontend/package.json @@ -0,0 +1,31 @@ +{ + "name": "asteroid-frontend", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "vite build", + "lint": "eslint . --ext js,jsx --report-unused-disable-directives --max-warnings 0", + "preview": "vite preview" + }, + "dependencies": { + "react": "^18.3.1", + "react-dom": "^18.3.1", + "chart.js": "^4.4.4", + "react-chartjs-2": "^5.2.0" + }, + "devDependencies": { + "@types/react": "^18.3.3", + "@types/react-dom": "^18.3.0", + "@vitejs/plugin-react": "^4.3.1", + "autoprefixer": "^10.4.20", + "eslint": "^9.6.1", + "eslint-plugin-react": "^7.35.0", + "eslint-plugin-react-hooks": "^5.0.0", + "eslint-plugin-react-refresh": "^0.4.7", + "postcss": "^8.4.41", + "tailwindcss": "^3.4.10", + "vite": "^5.4.1" + } +} From e1f5ec18eccd93092446e86364864bc97e5b785c Mon Sep 17 00:00:00 2001 From: Anushka Maitra Date: Mon, 19 Jan 2026 17:13:55 +0530 Subject: [PATCH 10/19] Add initial HTML structure for the app --- frontend/src/index.html | 52 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 frontend/src/index.html diff --git a/frontend/src/index.html b/frontend/src/index.html new file mode 100644 index 0000000..ea2378d --- /dev/null +++ b/frontend/src/index.html @@ -0,0 +1,52 @@ + + + + + Asteroid Orbit Tracker + + + + +
+

Asteroid Orbit Tracker 🚀

+
+ +
+
+

Live Orbit Visualization

+ +

+ Blue: Low-risk NEO | Orange: Medium-risk NEO +

+
+ +
+

Nearby Asteroids

+
+ +
+ +
+

Risk Metrics

+
+
+
0
+
Total NEOs
+
+
+
0 LD
+
Avg Distance
+
+
+
0 km/s
+
Avg Velocity
+
+
+
+
+ + + + From c842cc5412899dc8f51a502f9c9c6cbcf3486209 Mon Sep 17 00:00:00 2001 From: Anushka Maitra Date: Mon, 19 Jan 2026 17:14:37 +0530 Subject: [PATCH 11/19] Delete frontend/src/index.html --- frontend/src/index.html | 52 ----------------------------------------- 1 file changed, 52 deletions(-) delete mode 100644 frontend/src/index.html diff --git a/frontend/src/index.html b/frontend/src/index.html deleted file mode 100644 index ea2378d..0000000 --- a/frontend/src/index.html +++ /dev/null @@ -1,52 +0,0 @@ - - - - - Asteroid Orbit Tracker - - - - -
-

Asteroid Orbit Tracker 🚀

-
- -
-
-

Live Orbit Visualization

- -

- Blue: Low-risk NEO | Orange: Medium-risk NEO -

-
- -
-

Nearby Asteroids

-
- -
- -
-

Risk Metrics

-
-
-
0
-
Total NEOs
-
-
-
0 LD
-
Avg Distance
-
-
-
0 km/s
-
Avg Velocity
-
-
-
-
- - - - From 88450d62381d9eb261e4c450a8e21a006d3cd366 Mon Sep 17 00:00:00 2001 From: Anushka Maitra Date: Mon, 19 Jan 2026 17:15:11 +0530 Subject: [PATCH 12/19] Create index.html --- frontend/index.html | 52 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 frontend/index.html diff --git a/frontend/index.html b/frontend/index.html new file mode 100644 index 0000000..ea2378d --- /dev/null +++ b/frontend/index.html @@ -0,0 +1,52 @@ + + + + + Asteroid Orbit Tracker + + + + +
+

Asteroid Orbit Tracker 🚀

+
+ +
+
+

Live Orbit Visualization

+ +

+ Blue: Low-risk NEO | Orange: Medium-risk NEO +

+
+ +
+

Nearby Asteroids

+
+ +
+ +
+

Risk Metrics

+
+
+
0
+
Total NEOs
+
+
+
0 LD
+
Avg Distance
+
+
+
0 km/s
+
Avg Velocity
+
+
+
+
+ + + + From 7451a41ecd9bcbb15e7d18ccd891b33c1fdc05b0 Mon Sep 17 00:00:00 2001 From: Anushka Maitra Date: Mon, 19 Jan 2026 17:15:53 +0530 Subject: [PATCH 13/19] Add initial CSS styles for the application --- frontend/styles.css | 147 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 147 insertions(+) create mode 100644 frontend/styles.css diff --git a/frontend/styles.css b/frontend/styles.css new file mode 100644 index 0000000..9ba368b --- /dev/null +++ b/frontend/styles.css @@ -0,0 +1,147 @@ +:root { + --card: rgba(15, 23, 42, 0.9); + --border: rgba(148, 163, 184, 0.4); + --text-main: #e5e7eb; + --text-muted: #9ca3af; + --accent-blue: #3b82f6; + --accent-orange: #f97316; +} + +*, +*::before, +*::after { + box-sizing: border-box; +} + +body { + margin: 0; + min-height: 100vh; + font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; + background: radial-gradient(circle at top, #0f172a 0, #020617 45%, #000 100%); + color: var(--text-main); + padding: 24px; +} + +.app-header { + text-align: center; + margin-bottom: 24px; +} + +.app-header h1 { + margin: 0; + font-size: 2.2rem; + background: linear-gradient(90deg, #60a5fa, #a855f7, #22d3ee); + -webkit-background-clip: text; + background-clip: text; + color: transparent; +} + +.app-layout { + max-width: 1200px; + margin: 0 auto; + display: grid; + grid-template-columns: minmax(0, 2fr) minmax(0, 1.2fr) minmax(0, 1.4fr); + gap: 20px; +} + +@media (max-width: 1024px) { + .app-layout { + grid-template-columns: 1fr; + } +} + +.card { + background: var(--card); + border-radius: 16px; + padding: 16px 18px 20px; + border: 1px solid var(--border); + box-shadow: 0 18px 45px rgba(15, 23, 42, 0.8); +} + +.card h2 { + margin: 0 0 12px; + font-size: 1.2rem; + text-align: center; +} + +.card-orbit { + grid-column: span 2; +} + +#orbitCanvas { + width: 100%; + height: 320px; + display: block; + border-radius: 12px; + background: radial-gradient(circle at top, #020617 0, #000 70%); + border: 1px solid rgba(59, 130, 246, 0.5); +} + +.hint { + margin-top: 8px; + font-size: 0.8rem; + text-align: center; + color: var(--text-muted); +} + +.asteroid-list { + max-height: 320px; + overflow-y: auto; + display: flex; + flex-direction: column; + gap: 8px; + padding-right: 6px; +} + +.asteroid-item { + padding: 10px 12px; + border-radius: 10px; + background: rgba(15, 23, 42, 0.85); + border-left: 4px solid var(--accent-blue); +} + +.asteroid-name { + font-weight: 600; + margin-bottom: 4px; +} + +.asteroid-meta { + font-size: 0.8rem; + color: var(--text-muted); +} + +.metrics-grid { + display: grid; + grid-template-columns: repeat(3, minmax(0, 1fr)); + gap: 10px; + margin-top: 10px; +} + +.metric-box { + padding: 10px 8px; + border-radius: 10px; + background: rgba(15, 23, 42, 0.85); + text-align: center; +} + +.metric-value { + font-size: 1.2rem; + font-weight: 700; + margin-bottom: 4px; +} + +.metric-label { + font-size: 0.8rem; + color: var(--text-muted); +} + +.error { + margin-top: 10px; + font-size: 0.8rem; + text-align: center; + color: #f97373; +} + +.hidden { + display: none; +} From 4fc5866c56abb90b4e6f875b7cbbc7362a22510a Mon Sep 17 00:00:00 2001 From: Anushka Maitra Date: Mon, 19 Jan 2026 17:18:17 +0530 Subject: [PATCH 14/19] Refactor API service and add mock data handling Refactor API service to use a centralized fetch function and handle errors more gracefully. Added mock data for asteroids and stats in case of fetch failure. --- frontend/src/services/api.js | 52 ++++++++++++++++++++---------------- 1 file changed, 29 insertions(+), 23 deletions(-) diff --git a/frontend/src/services/api.js b/frontend/src/services/api.js index 7b9b8a0..d5230f5 100644 --- a/frontend/src/services/api.js +++ b/frontend/src/services/api.js @@ -1,27 +1,33 @@ -const API_BASE = import.meta.env.VITE_API_URL || 'http://localhost:8000/api'; +const API_BASE = ''; -const api = { - getAsteroids: async () => { - try { - const response = await fetch(`${API_BASE}/asteroids`); - if (!response.ok) throw new Error(`HTTP ${response.status}`); - return await response.json(); - } catch (error) { - console.error('API Error:', error); - return { asteroids: [], error: 'Failed to fetch asteroids' }; - } - }, +async function fetchJson(path) { + if (!API_BASE) throw new Error('API disabled'); + const res = await fetch(API_BASE + path); + if (!res.ok) throw new Error('HTTP ' + res.status); + return res.json(); +} - getStats: async () => { - try { - const response = await fetch(`${API_BASE}/stats`); - if (!response.ok) throw new Error(`HTTP ${response.status}`); - return await response.json(); - } catch (error) { - console.error('Stats Error:', error); - return { total: 0, avgDistance: 0, avgVelocity: 0, error: 'Failed to fetch stats' }; - } +export async function getAsteroids() { + try { + const data = await fetchJson('/asteroids'); + return data.asteroids || data || []; + } catch (e) { + console.warn('Using mock asteroids:', e); + return [ + { id: 1, name: '2026 AB1', distance: 3.4, velocity: 17.1, risk: 'Low' }, + { id: 2, name: 'Apollo-NEO 33', distance: 1.2, velocity: 22.4, risk: 'Medium' }, + { id: 3, name: '2025 QX9', distance: 0.8, velocity: 28.9, risk: 'Medium' }, + { id: 4, name: 'PHA-192', distance: 10.1, velocity: 12.3, risk: 'Low' }, + { id: 5, name: 'Tempel-NEO', distance: 6.7, velocity: 19.5, risk: 'Low' }, + ]; } -}; +} -export default api; +export async function getStats() { + try { + return await fetchJson('/stats'); + } catch (e) { + console.warn('Using mock stats:', e); + return { total: 5, avgDistance: 4.4, avgVelocity: 20.4 }; + } +} From 33a85cafc4fcc2bec05b4e9e557e28f21d627885 Mon Sep 17 00:00:00 2001 From: Anushka Maitra Date: Mon, 19 Jan 2026 17:19:03 +0530 Subject: [PATCH 15/19] Delete frontend/src/components directory --- frontend/src/components/AsteroidPanel.jsx | 31 -------- frontend/src/components/Dashboard.jsx | 65 ---------------- frontend/src/components/OrbitCanvas.jsx | 92 ----------------------- 3 files changed, 188 deletions(-) delete mode 100644 frontend/src/components/AsteroidPanel.jsx delete mode 100644 frontend/src/components/Dashboard.jsx delete mode 100644 frontend/src/components/OrbitCanvas.jsx diff --git a/frontend/src/components/AsteroidPanel.jsx b/frontend/src/components/AsteroidPanel.jsx deleted file mode 100644 index c1f1b6d..0000000 --- a/frontend/src/components/AsteroidPanel.jsx +++ /dev/null @@ -1,31 +0,0 @@ -import { useState, useEffect } from 'react'; -import api from '../services/api.js'; - -const AsteroidPanel = () => { - const [asteroids, setAsteroids] = useState([]); - - useEffect(() => { - api.getAsteroids().then(setAsteroids); - }, []); - - return ( -
-

Nearby Asteroids

-
- {asteroids.slice(0,5).map((ast) => ( -
-
{ast.name}
-
Distance: {ast.distance} LD
-
Velocity: {ast.velocity} km/s
-
Risk: {ast.risk}
-
- ))} -
- {asteroids.error && ( -

Connection error - using mock data

- )} -
- ); -}; - -export default AsteroidPanel; diff --git a/frontend/src/components/Dashboard.jsx b/frontend/src/components/Dashboard.jsx deleted file mode 100644 index 665c195..0000000 --- a/frontend/src/components/Dashboard.jsx +++ /dev/null @@ -1,65 +0,0 @@ -import { useState, useEffect } from 'react'; -import { Line } from 'react-chartjs-2'; -import { - Chart as ChartJS, - CategoryScale, - LinearScale, - PointElement, - LineElement, - Title, - Tooltip, - Legend, -} from 'chart.js'; -import api from '../services/api.js'; - -ChartJS.register(CategoryScale, LinearScale, PointElement, LineElement, Title, Tooltip, Legend); - -const Dashboard = () => { - const [stats, setStats] = useState({ total: 0, avgDistance: 0, avgVelocity: 0 }); - - useEffect(() => { - api.getStats().then(setStats); - }, []); - - const data = { - labels: ['NEOs Tracked', 'Avg Distance (LD)', 'Avg Velocity (km/s)'], - datasets: [{ - label: 'Metrics', - data: [stats.total, stats.avgDistance, stats.avgVelocity], - borderColor: 'rgb(59, 130, 246)', - backgroundColor: 'rgba(59, 130, 246, 0.2)', - tension: 0.4, - }], - }; - - const options = { - responsive: true, - plugins: { legend: { position: 'top' } }, - scales: { y: { beginAtZero: true } }, - }; - - return ( -
-

Risk Metrics

-
- -
-
-
-
{stats.total}
-
Total NEOs
-
-
-
{stats.avgDistance.toFixed(1)} LD
-
Avg Distance
-
-
-
{stats.avgVelocity.toFixed(1)} km/s
-
Avg Velocity
-
-
-
- ); -}; - -export default Dashboard; diff --git a/frontend/src/components/OrbitCanvas.jsx b/frontend/src/components/OrbitCanvas.jsx deleted file mode 100644 index 653a032..0000000 --- a/frontend/src/components/OrbitCanvas.jsx +++ /dev/null @@ -1,92 +0,0 @@ -import { useRef, useEffect } from 'react'; - -const OrbitCanvas = () => { - const canvasRef = useRef(null); - const animationRef = useRef(); - - useEffect(() => { - const canvas = canvasRef.current; - const ctx = canvas.getContext('2d'); - let time = 0; - - const resize = () => { - canvas.width = canvas.clientWidth; - canvas.height = canvas.clientHeight; - }; - resize(); - window.addEventListener('resize', resize); - - const animate = () => { - ctx.fillStyle = 'rgba(10, 10, 20, 0.1)'; - ctx.fillRect(0, 0, canvas.width, canvas.height); - - const centerX = canvas.width / 2; - const centerY = canvas.height / 2; - - // Central body (Earth-like) - ctx.fillStyle = '#4fd1c7'; - ctx.beginPath(); - ctx.arc(centerX, centerY, 20, 0, Math.PI * 2); - ctx.fill(); - - // Orbit 1: Close asteroid - ctx.strokeStyle = '#60a5fa'; - ctx.lineWidth = 1; - ctx.beginPath(); - ctx.arc(centerX, centerY, 80, 0, Math.PI * 2); - ctx.stroke(); - - // Orbit 2: Far asteroid - ctx.strokeStyle = '#f59e0b'; - ctx.lineWidth = 1; - ctx.beginPath(); - ctx.arc(centerX, centerY, 140, 0, Math.PI * 2); - ctx.stroke(); - - // Animated asteroids - ctx.save(); - ctx.translate(centerX, centerY); - - // Close asteroid - ctx.rotate(time * 0.02); - ctx.fillStyle = '#3b82f6'; - ctx.beginPath(); - ctx.arc(80, 0, 6, 0, Math.PI * 2); - ctx.fill(); - - // Far asteroid - ctx.rotate(-time * 0.01); - ctx.fillStyle = '#d97706'; - ctx.beginPath(); - ctx.arc(140, 0, 8, 0, Math.PI * 2); - ctx.fill(); - - ctx.restore(); - - time += 1; - animationRef.current = requestAnimationFrame(animate); - }; - - animate(); - - return () => { - window.removeEventListener('resize', resize); - if (animationRef.current) cancelAnimationFrame(animationRef.current); - }; - }, []); - - return ( -
-

Live Orbit Visualization

- -

- Blue: Low-risk NEO | Orange: Medium-risk NEO -

-
- ); -}; - -export default OrbitCanvas; From 8316576e1e85b328d46881395577d0e4a539737c Mon Sep 17 00:00:00 2001 From: Anushka Maitra Date: Mon, 19 Jan 2026 17:20:40 +0530 Subject: [PATCH 16/19] Add OrbitCanvas component for animated canvas rendering --- frontend/src/components/OrbitCanvas.js | 65 ++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 frontend/src/components/OrbitCanvas.js diff --git a/frontend/src/components/OrbitCanvas.js b/frontend/src/components/OrbitCanvas.js new file mode 100644 index 0000000..24e579a --- /dev/null +++ b/frontend/src/components/OrbitCanvas.js @@ -0,0 +1,65 @@ +export function initOrbitCanvas() { + const canvas = document.getElementById('orbitCanvas'); + if (!canvas) return; + + const ctx = canvas.getContext('2d'); + + function resize() { + const rect = canvas.getBoundingClientRect(); + canvas.width = rect.width * window.devicePixelRatio; + canvas.height = rect.height * window.devicePixelRatio; + ctx.setTransform(window.devicePixelRatio, 0, 0, window.devicePixelRatio, 0, 0); + } + + resize(); + window.addEventListener('resize', resize); + + let t = 0; + + function draw() { + const w = canvas.clientWidth; + const h = canvas.clientHeight; + + ctx.fillStyle = 'rgba(2, 6, 23, 0.6)'; + ctx.fillRect(0, 0, w, h); + + const cx = w / 2; + const cy = h / 2; + + ctx.strokeStyle = 'rgba(148, 163, 184, 0.6)'; + ctx.lineWidth = 1; + ctx.beginPath(); + ctx.arc(cx, cy, 80, 0, Math.PI * 2); + ctx.stroke(); + + ctx.beginPath(); + ctx.arc(cx, cy, 140, 0, Math.PI * 2); + ctx.stroke(); + + ctx.fillStyle = '#22d3ee'; + ctx.beginPath(); + ctx.arc(cx, cy, 18, 0, Math.PI * 2); + ctx.fill(); + + const angle1 = t * 0.02; + const x1 = cx + 80 * Math.cos(angle1); + const y1 = cy + 80 * Math.sin(angle1); + ctx.fillStyle = '#3b82f6'; + ctx.beginPath(); + ctx.arc(x1, y1, 6, 0, Math.PI * 2); + ctx.fill(); + + const angle2 = t * -0.012; + const x2 = cx + 140 * Math.cos(angle2); + const y2 = cy + 140 * Math.sin(angle2); + ctx.fillStyle = '#f97316'; + ctx.beginPath(); + ctx.arc(x2, y2, 8, 0, Math.PI * 2); + ctx.fill(); + + t += 1; + requestAnimationFrame(draw); + } + + requestAnimationFrame(draw); +} From 271ae7d377887176c1577677446f1addd2fab1a1 Mon Sep 17 00:00:00 2001 From: Anushka Maitra Date: Mon, 19 Jan 2026 17:21:17 +0530 Subject: [PATCH 17/19] Implement asteroid panel initialization function --- frontend/src/components/AsteroidPanel.js | 44 ++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 frontend/src/components/AsteroidPanel.js diff --git a/frontend/src/components/AsteroidPanel.js b/frontend/src/components/AsteroidPanel.js new file mode 100644 index 0000000..6330bfa --- /dev/null +++ b/frontend/src/components/AsteroidPanel.js @@ -0,0 +1,44 @@ +import { getAsteroids } from '../services/api.js'; + +export async function initAsteroidPanel() { + const listEl = document.getElementById('asteroidList'); + const errorEl = document.getElementById('asteroidError'); + if (!listEl) return; + + const asteroids = await getAsteroids(); + + if (!asteroids || asteroids.length === 0) { + if (errorEl) errorEl.classList.remove('hidden'); + return; + } + + listEl.innerHTML = ''; + + asteroids.slice(0, 5).forEach((ast) => { + const item = document.createElement('div'); + item.className = 'asteroid-item'; + + const name = document.createElement('div'); + name.className = 'asteroid-name'; + name.textContent = ast.name; + + const meta1 = document.createElement('div'); + meta1.className = 'asteroid-meta'; + meta1.textContent = 'Distance: ' + ast.distance + ' LD'; + + const meta2 = document.createElement('div'); + meta2.className = 'asteroid-meta'; + meta2.textContent = 'Velocity: ' + ast.velocity + ' km/s'; + + const risk = document.createElement('div'); + risk.className = 'asteroid-risk'; + risk.textContent = 'Risk: ' + ast.risk; + + item.appendChild(name); + item.appendChild(meta1); + item.appendChild(meta2); + item.appendChild(risk); + + listEl.appendChild(item); + }); +} From f9caf38eb553abb2355d921cbd1732e0399b0103 Mon Sep 17 00:00:00 2001 From: Anushka Maitra Date: Mon, 19 Jan 2026 17:21:43 +0530 Subject: [PATCH 18/19] Implement dashboard initialization with API stats --- frontend/src/components/Dashboard.js | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 frontend/src/components/Dashboard.js diff --git a/frontend/src/components/Dashboard.js b/frontend/src/components/Dashboard.js new file mode 100644 index 0000000..d4a63bc --- /dev/null +++ b/frontend/src/components/Dashboard.js @@ -0,0 +1,18 @@ +import { getStats } from '../services/api.js'; + +export async function initDashboard() { + const totalEl = document.getElementById('metricTotal'); + const distEl = document.getElementById('metricAvgDistance'); + const velEl = document.getElementById('metricAvgVelocity'); + + if (!totalEl || !distEl || !velEl) return; + + const stats = await getStats(); + const total = stats.total || 0; + const avgDistance = stats.avgDistance || 0; + const avgVelocity = stats.avgVelocity || 0; + + totalEl.textContent = total; + distEl.textContent = avgDistance.toFixed(1) + ' LD'; + velEl.textContent = avgVelocity.toFixed(1) + ' km/s'; +} From 57d449f6c7f3acd62caf42bb6e261db87b279808 Mon Sep 17 00:00:00 2001 From: Anushka Maitra Date: Mon, 19 Jan 2026 17:23:58 +0530 Subject: [PATCH 19/19] Create main.js this replaces app.jsx+main.jsx --- frontend/src/main.js | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 frontend/src/main.js diff --git a/frontend/src/main.js b/frontend/src/main.js new file mode 100644 index 0000000..f6eda32 --- /dev/null +++ b/frontend/src/main.js @@ -0,0 +1,9 @@ +import { initOrbitCanvas } from './components/OrbitCanvas.js'; +import { initAsteroidPanel } from './components/AsteroidPanel.js'; +import { initDashboard } from './components/Dashboard.js'; + +window.addEventListener('DOMContentLoaded', () => { + initOrbitCanvas(); + initAsteroidPanel(); + initDashboard(); +});