diff --git a/frontend/src/app/globe/page.tsx b/frontend/src/app/globe/page.tsx deleted file mode 100644 index 9167e34..0000000 --- a/frontend/src/app/globe/page.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import dynamic from "next/dynamic"; -const GHGlobe = dynamic(() => import("@components/map/githubglobe/GHGlobe"), { - ssr: false, -}); - -// Example Datasources -import { exampleData } from "@components/map/exampleSatData"; -import { SatelliteData, mapRawDataToSatData } from "@/lib/mapHelpers"; - -const FETCH_EXAMPLE_DATA = true; -const SATELLITE_AMOUNT = 50; // amount of satellites to display - -export default async function Page() { - let satDatas: SatelliteData[] = []; - if (FETCH_EXAMPLE_DATA) { - satDatas = mapRawDataToSatData(exampleData); - } - - satDatas = satDatas.slice(0, SATELLITE_AMOUNT); - - return ; -} diff --git a/frontend/src/app/page.tsx b/frontend/src/app/page.tsx index b9fbf72..db4ceaf 100644 --- a/frontend/src/app/page.tsx +++ b/frontend/src/app/page.tsx @@ -7,28 +7,28 @@ import Link from "next/link"; import fetchMostRecentImage from "@/lib/data/fetchMostRecentImage"; import SatelliteDataHome from "@/components/satelliteData/SatelliteDataHome"; -import SatelliteSelector from "@/components/SatelliteSelector"; -import SatelliteGlobe from "@/components/map/newGlobe"; +import SatelliteSelector from "@/components/homeComponents/SatelliteSelector"; +import SatelliteGlobe from "@/components/homeComponents/homeGlobe"; export default async function Home() { const mostRecentImageURL = await fetchMostRecentImage(); return ( <> -
+
{/* Stats Container */} -
-
+
+
-
+
{/* Globe Container */} -
+
diff --git a/frontend/src/components/Combobox.tsx b/frontend/src/components/Combobox.tsx deleted file mode 100644 index 610ed99..0000000 --- a/frontend/src/components/Combobox.tsx +++ /dev/null @@ -1,80 +0,0 @@ -"use client"; -import React, { useState } from "react"; -import { Check, ChevronsUpDown } from "lucide-react"; - -import { cn } from "@/lib/utils"; -import { Button } from "@/components/ui/button"; -import { - Command, - CommandEmpty, - CommandGroup, - CommandInput, - CommandItem, -} from "@/components/ui/command"; -import { - Popover, - PopoverContent, - PopoverTrigger, -} from "@/components/ui/popover"; -import { SatelliteData } from "@/lib/mapHelpers"; -interface ComboboxDemoProps { - data: SatelliteData[]; - // eslint-disable-next-line no-unused-vars - onSelect: (selectedValue: SatelliteData) => void; -} - -export function Combobox({ data, onSelect }: ComboboxDemoProps) { - console.log(); - - const [open, setOpen] = useState(false); - const [value, setValue] = useState(""); - - const handleSelect = (currentValue: SatelliteData) => { - setValue(currentValue.name === value ? "" : currentValue.name); - setOpen(false); - onSelect(currentValue); // Call the passed onSelect function with the selected value - }; - - return ( - - - - - - - - No framework found. - - {data.map((item) => ( - handleSelect(item)} - > - - {item.name} - - ))} - - - - - ); -} diff --git a/frontend/src/components/SatelliteSelector.tsx b/frontend/src/components/SatelliteSelector.tsx deleted file mode 100644 index a07feed..0000000 --- a/frontend/src/components/SatelliteSelector.tsx +++ /dev/null @@ -1,46 +0,0 @@ -"use client"; -import React from "react"; -import { useSatelliteStore } from "@/lib/store"; - -export default function SatelliteSelector() { - const satelliteNames = useSatelliteStore((state) => state.satelliteNames); - const selectedSatellite = useSatelliteStore( - (state) => state.selectedSatellite, - ); - const setSelectedSatellite = useSatelliteStore( - (state) => state.setSelectedSatellite, - ); - const fetchAndSetSatelliteData = useSatelliteStore( - (state) => state.fetchAndSetSatelliteData, - ); - - const handleChange = (event: React.ChangeEvent) => { - setSelectedSatellite(event.target.value); - }; - - for (const satellite of satelliteNames) { - fetchAndSetSatelliteData(satellite); - } - - return ( -
- -
- ); -} diff --git a/frontend/src/components/homeComponents/SatDropdown.tsx b/frontend/src/components/homeComponents/SatDropdown.tsx new file mode 100644 index 0000000..eea118d --- /dev/null +++ b/frontend/src/components/homeComponents/SatDropdown.tsx @@ -0,0 +1,62 @@ +import React, { useState } from "react"; +import { motion } from "framer-motion"; +import { cn } from "@/lib/utils"; + +type DropdownProps = { + satelliteNames: string[]; + selectedSatellite: string; + // eslint-disable-next-line no-unused-vars + setSelectedSatellite: (satellite: string) => void; +}; + +export default function SatDropdown({ + satelliteNames, + selectedSatellite, + setSelectedSatellite, +}: DropdownProps) { + const [isOpen, setIsOpen] = useState(false); + + const toggleDropdown = () => setIsOpen(!isOpen); + + const handleSelect = (satellite: string) => { + setSelectedSatellite(satellite); + setIsOpen(false); + }; + + // Animation variants for the dropdown content + const variants = { + open: { opacity: 1, height: "auto", maxHeight: "300px" }, + collapsed: { opacity: 0, height: 0 }, + }; + + return ( +
+ + {isOpen &&
} + + {satelliteNames.map((satellite) => ( +
handleSelect(satellite)} + > + {satellite !== selectedSatellite + ? satellite + : `${satellite} (Selected)`} +
+ ))} +
+
+ ); +} diff --git a/frontend/src/components/homeComponents/SatelliteSelector.tsx b/frontend/src/components/homeComponents/SatelliteSelector.tsx new file mode 100644 index 0000000..9350cf2 --- /dev/null +++ b/frontend/src/components/homeComponents/SatelliteSelector.tsx @@ -0,0 +1,32 @@ +"use client"; +import React from "react"; +import { useSatelliteStore } from "@/lib/store"; +import SatDropdown from "@/components/homeComponents/SatDropdown"; + +export default function SatelliteSelector() { + const satelliteNames = useSatelliteStore((state) => state.satelliteNames); + const selectedSatellite = useSatelliteStore( + (state) => state.selectedSatellite, + ); + const setSelectedSatellite = useSatelliteStore( + (state) => state.setSelectedSatellite, + ); + const fetchAndSetSatelliteData = useSatelliteStore( + (state) => state.fetchAndSetSatelliteData, + ); + + // Fetch data for each satellite and set it in the store + for (const satellite of satelliteNames) { + fetchAndSetSatelliteData(satellite); + } + + return ( +
+ +
+ ); +} diff --git a/frontend/src/components/map/githubglobe/files/earth-dark.jpg b/frontend/src/components/homeComponents/files/earth-dark.jpg similarity index 100% rename from frontend/src/components/map/githubglobe/files/earth-dark.jpg rename to frontend/src/components/homeComponents/files/earth-dark.jpg diff --git a/frontend/src/components/map/githubglobe/files/globe-cables-data.json b/frontend/src/components/homeComponents/files/globe-cables-data.json similarity index 100% rename from frontend/src/components/map/githubglobe/files/globe-cables-data.json rename to frontend/src/components/homeComponents/files/globe-cables-data.json diff --git a/frontend/src/components/map/githubglobe/files/globe-data-min.json b/frontend/src/components/homeComponents/files/globe-data-min.json similarity index 100% rename from frontend/src/components/map/githubglobe/files/globe-data-min.json rename to frontend/src/components/homeComponents/files/globe-data-min.json diff --git a/frontend/src/components/map/githubglobe/files/globe-data.json b/frontend/src/components/homeComponents/files/globe-data.json similarity index 100% rename from frontend/src/components/map/githubglobe/files/globe-data.json rename to frontend/src/components/homeComponents/files/globe-data.json diff --git a/frontend/src/components/map/newGlobe.tsx b/frontend/src/components/homeComponents/homeGlobe.tsx similarity index 100% rename from frontend/src/components/map/newGlobe.tsx rename to frontend/src/components/homeComponents/homeGlobe.tsx diff --git a/frontend/src/components/map/githubglobe/GHGlobe.tsx b/frontend/src/components/map/githubglobe/GHGlobe.tsx deleted file mode 100644 index c456106..0000000 --- a/frontend/src/components/map/githubglobe/GHGlobe.tsx +++ /dev/null @@ -1,246 +0,0 @@ -"use client"; -import ThreeGlobe from "three-globe"; -import { WebGLRenderer, Scene } from "three"; -import * as THREE from "three"; -import { - PerspectiveCamera, - AmbientLight, - DirectionalLight, - Color, - Fog, - // AxesHelper, - // DirectionalLightHelper, - // CameraHelper, - PointLight, -} from "three"; -import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js"; -import countries from "./files/globe-data-min.json"; -import { useEffect } from "react"; -import * as satellite from "satellite.js"; -import { SatelliteData } from "@/lib/mapHelpers"; -import Tooltip from "./tooltip"; - -const EARTH_RADIUS_KM = 6371; // km -const SAT_SIZE = 250; // km - -var satDataArray: SatelliteData[] = []; - -var renderer: WebGLRenderer; -var camera: PerspectiveCamera; -var scene: Scene; -var controls: OrbitControls; -var Globe: ThreeGlobe; -var myCanvas: HTMLCanvasElement; -var viewportDimensions: DOMRect; -var tooltipDiv: HTMLDivElement; - -var raycaster: THREE.Raycaster; -var pointer: THREE.Vector2; -var tooltipPointer: THREE.Vector2; - -// SECTION Initializing core ThreeJS elements -function init() { - // Initialize renderer - myCanvas = document.getElementById("gh-globe-canvas")! as HTMLCanvasElement; - tooltipDiv = document.getElementById("tooltip-globe")! as HTMLDivElement; - - renderer = new WebGLRenderer({ antialias: true, canvas: myCanvas }); - renderer.setPixelRatio(window.devicePixelRatio); - - renderer.setSize(myCanvas.clientWidth, myCanvas.clientHeight, false); - - // Initialize scene, light - scene = new Scene(); - scene.add(new AmbientLight(0xbbbbbb, 0.3)); - scene.background = new Color(0x0e100f); - - // Initialize camera, light - viewportDimensions = myCanvas.getBoundingClientRect(); - camera = new PerspectiveCamera(); - camera.aspect = viewportDimensions.width / viewportDimensions.height; - camera.updateProjectionMatrix(); - - // Raycaster - raycaster = new THREE.Raycaster(); - pointer = new THREE.Vector2(); - tooltipPointer = new THREE.Vector2(); - - var dLight = new DirectionalLight(0xffffff, 0.8); - dLight.position.set(-800, 2000, 400); - camera.add(dLight); - - var dLight1 = new DirectionalLight(0x7982f6, 1); - dLight1.position.set(-100, 300, 200); - camera.add(dLight1); - - var dLight2 = new PointLight(0x8566cc, 0.5); - dLight2.position.set(-200, 500, 200); - camera.add(dLight2); - - camera.position.z = 400; - camera.position.x = 0; - camera.position.y = 200; - - scene.add(camera); - - // Additional effects - scene.fog = new Fog(0x535ef3, 400, 2000); - - // Initialize controls - controls = new OrbitControls(camera, renderer.domElement); - controls.enableDamping = true; - controls.enablePan = false; - controls.minDistance = 200; - controls.maxDistance = 500; - controls.rotateSpeed = 0.7; - controls.zoomSpeed = 1; - controls.autoRotate = true; - controls.autoRotateSpeed = 0.1; - controls.enableZoom = false; - - controls.minPolarAngle = Math.PI / 3.5; - controls.maxPolarAngle = Math.PI - Math.PI / 3; - - window.addEventListener("resize", onWindowResize, false); - window.addEventListener("mousemove", onPointerMove); - // document.addEventListener("mousemove", onMouseMove); -} - -// SECTION Globe -function initGlobe() { - // Initialize the Globe - Globe = new ThreeGlobe({ - waitForGlobeReady: true, - animateIn: true, - }) - .hexPolygonsData(countries.features) - .hexPolygonResolution(3) - .hexPolygonMargin(0.7) - .showAtmosphere(true) - .atmosphereAltitude(0.25) - .hexPolygonColor(() => "#ffffff") - .atmosphereColor("#00509e") - .objectLat("lat") - .objectAltitude("alt") - .objectLng("lng") - .objectFacesSurface(false); - - Globe.rotateY(-Math.PI * (5 / 9)); - Globe.rotateZ(-Math.PI / 6); - const globeMaterial = new THREE.MeshLambertMaterial({ - color: "#00509e", - transparent: true, - opacity: 1, - }); - Globe.globeMaterial(globeMaterial); - - // NOTE Cool stuff - // globeMaterial.wireframe = true; - - scene.add(Globe); -} - -function initSatellites() { - // Make the satellite geometry using a sphere - const satGeometry = new THREE.SphereGeometry( - (SAT_SIZE * Globe.getGlobeRadius()) / EARTH_RADIUS_KM / 2, - 16, - 8, - ); - - // Make the satellite material - const satMaterial = new THREE.MeshLambertMaterial({ - color: "palegreen", - transparent: true, - opacity: 0.7, - }); - - // Set which object to render satellites as - Globe.objectThreeObject((obj: any) => { - let object = new THREE.Mesh(satGeometry, satMaterial); - object.userData = { name: obj.name }; - return object; - }); - - updateSatellites(); -} - -function updateSatellites() { - // Get current time - let time = new Date(); - - const gmst = satellite.gstime(time); - satDataArray.forEach((d: any) => { - const eci = satellite.propagate(d.satrec, time); - if (eci.position) { - const gdPos = satellite.eciToGeodetic( - eci.position as satellite.EciVec3, - gmst, - ); - d.lat = THREE.MathUtils.radToDeg(gdPos.latitude); - d.lng = THREE.MathUtils.radToDeg(gdPos.longitude); - d.alt = gdPos.height / EARTH_RADIUS_KM; - } - }); - - Globe.objectsData(satDataArray); -} - -function onPointerMove(event: MouseEvent) { - let rect = myCanvas.getBoundingClientRect(); - pointer.x = ((event.clientX - rect.left) / rect.width) * 2 - 1; - pointer.y = -((event.clientY - rect.top) / rect.height) * 2 + 1; - - tooltipPointer.x = event.clientX; - tooltipPointer.y = event.clientY; -} - -function onWindowResize() { - camera.aspect = myCanvas.clientWidth / myCanvas.clientHeight; - camera.updateProjectionMatrix(); - // renderer.setSize(myCanvas.clientWidth, myCanvas.clientHeight, false); // I dont know why, but this line breaks the sizing after resizing window -} - -function animate() { - updateSatellites(); - camera.lookAt(scene.position); - controls.update(); - - raycaster.setFromCamera(pointer, camera); - const intersects = raycaster.intersectObjects(scene.children, true); - if (intersects.length > 0) { - let first = intersects[0].object; - if (first.userData.name) { - tooltipDiv.style.visibility = "visible"; - tooltipDiv.innerHTML = first.userData.name; - tooltipDiv.style.left = tooltipPointer.x + "px"; - tooltipDiv.style.top = tooltipPointer.y + "px"; - } - } else { - tooltipDiv.style.visibility = "hidden"; - } - - renderer.render(scene, camera); - requestAnimationFrame(animate); -} - -export default function GHGlobe({ satDatas }: { satDatas: SatelliteData[] }) { - useEffect(() => { - satDataArray = satDatas; - init(); - initGlobe(); - onWindowResize(); - initSatellites(); - animate(); - }); - - return ( -
- - TEST -
- ); -} diff --git a/frontend/src/components/map/githubglobe/tooltip.tsx b/frontend/src/components/map/githubglobe/tooltip.tsx deleted file mode 100644 index 1467016..0000000 --- a/frontend/src/components/map/githubglobe/tooltip.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import { cn } from "@/lib/utils"; -import React from "react"; - -interface TooltipProps extends React.HTMLAttributes { - className?: string; -} - -const Tooltip = React.forwardRef( - ({ children, className, ...props }, ref) => ( -
-
{children}
-
- ), -); - -Tooltip.displayName = "Tooltip"; // Add display name - -export default Tooltip; diff --git a/frontend/src/components/satelliteData/SatelliteDataHome.tsx b/frontend/src/components/satelliteData/SatelliteDataHome.tsx index 9daa27d..d0b26b3 100644 --- a/frontend/src/components/satelliteData/SatelliteDataHome.tsx +++ b/frontend/src/components/satelliteData/SatelliteDataHome.tsx @@ -3,7 +3,7 @@ import { useState, useEffect } from "react"; import { convertSatrec, SatelliteInfo } from "@/lib/convertSatrec"; import { useSatelliteStore } from "@/lib/store"; -const updateInterval = 10; +const updateInterval = 50; export default function SatelliteDataHome() { const { satelliteData, fetchAndSetSatelliteData, selectedSatellite } = diff --git a/frontend/src/components/satelliteData/SatelliteDataTable.tsx b/frontend/src/components/satelliteData/SatelliteDataTable.tsx deleted file mode 100644 index 0b286d8..0000000 --- a/frontend/src/components/satelliteData/SatelliteDataTable.tsx +++ /dev/null @@ -1,129 +0,0 @@ -// Ensure all necessary imports are present -"use client"; -import React, { useState, useEffect } from "react"; -import { Combobox } from "../Combobox"; // Adjust the path as necessary -import { - mapRawDataToTleData, - mapTleToSatData, - SatelliteData, -} from "@/lib/mapHelpers"; -import { convertSatrec, SatelliteInfo } from "@/lib/convertSatrec"; - -const updateInterval = 10; - -interface ClientOnlyComponentProps { - fetchSatelliteData: ({ - // eslint-disable-next-line no-unused-vars - useExampleData, - }: { - useExampleData: boolean; - filterList?: string[]; - }) => Promise; -} - -const SatelliteDataTable: React.FC = ({ - fetchSatelliteData, -}) => { - const [satelliteData, setSatelliteData] = useState([]); - const [selectedSatellite, setSelectedSatellite] = useState< - SatelliteData | undefined - >(); - const [satelliteInfo, setSatelliteInfo] = useState( - null, - ); - - // Fetch satellite data on component mount - useEffect(() => { - const fetchData = async () => { - const rawData = await fetchSatelliteData({ useExampleData: true }); - - const tleData = mapRawDataToTleData(rawData); - - const mappedData = mapTleToSatData(tleData).slice(0, 10); - setSatelliteData(mappedData); - if (mappedData.length > 0) { - updateSatelliteInfo(mappedData[0]); - setSelectedSatellite(mappedData[0]); // Ensure the first satellite is selected by default - } - }; - - fetchData(); - }, [fetchSatelliteData]); - - // Function to update satellite info based on selected satellite - const updateSatelliteInfo = (satellite: SatelliteData) => { - const sat = satelliteData.find((s) => s.name === satellite.name); - if (sat) { - const info = convertSatrec(sat.satrec, sat.name); - setSatelliteInfo(info); - } - }; - - // Handle satellite selection from Combobox - const handleSelectSatellite = (value: SatelliteData) => { - setSelectedSatellite(value); - updateSatelliteInfo(value); - }; - - useEffect(() => { - const intervalId = setInterval(() => { - // Access satellite data by name - if (selectedSatellite) { - const updatedInfo = convertSatrec( - selectedSatellite.satrec, - selectedSatellite.name, - ); - setSatelliteInfo(updatedInfo); - } - }, updateInterval); - - // Clear interval on component unmount - return () => clearInterval(intervalId); - }, [selectedSatellite]); - - return satelliteData.length > 0 && selectedSatellite && satelliteInfo ? ( - <> -
-
- -
{/* Include the dropdown arrow icon here */}
-
- -
-
-

{satelliteInfo.velocity} km/s

-

Velocity

-
-
-

{satelliteInfo.altitude} km

-

Altitude

-
-
-

- {satelliteInfo.latitudeDeg}° N -

-

Latitude

-
-
-

- {satelliteInfo.longitudeDeg}° E -

-

Longitude

-
-
- -
-

Above {satelliteInfo.country}

-
-
{/* Include the flag icon here */}
-
- - ) : ( -
Loading...
- ); -}; - -export default SatelliteDataTable; diff --git a/frontend/src/components/satelliteData/SatelliteDataTableSingle.tsx b/frontend/src/components/satelliteData/SatelliteDataTableSingle.tsx deleted file mode 100644 index 8d5fc4e..0000000 --- a/frontend/src/components/satelliteData/SatelliteDataTableSingle.tsx +++ /dev/null @@ -1,81 +0,0 @@ -"use client"; -import React, { useState, useEffect } from "react"; -import { convertSatrec, SatelliteInfo } from "@/lib/convertSatrec"; -import { useSatelliteStore } from "@/lib/store"; - -const updateInterval = 10; - -export default function SatelliteDataTable({ - satName, - combobox, -}: { - satName: string; - combobox: React.ReactNode; -}) { - const { satelliteData, fetchAndSetSatelliteData } = useSatelliteStore(); - const [satelliteInfo, setSatelliteInfo] = useState( - null, - ); - - // Fetch satellite data on component mount - useEffect(() => { - fetchAndSetSatelliteData(satName); - }, [fetchAndSetSatelliteData, satName]); - - // Update satellite info every `updateInterval` ms - useEffect(() => { - const intervalId = setInterval(() => { - // Access satellite data by name - const satData = satelliteData[satName]; - if (satData) { - const updatedInfo = convertSatrec(satData.satrec, satData.name); - setSatelliteInfo(updatedInfo); - } - }, updateInterval); - - // Clear interval on component unmount - return () => clearInterval(intervalId); - }, [satelliteData, satName]); - - // Display loading message if satellite info is not available - if (!satelliteInfo) { - return ( -
-

Loading...

-
- ); - } - - return ( -
-
-
{combobox}
-

{satelliteInfo.name}

-
- -
-
-

{satelliteInfo.velocity} km/s

-

Velocity

-
-
-

{satelliteInfo.altitude} km

-

Altitude

-
-
-

{satelliteInfo.latitudeDeg}° N

-

Latitude

-
-
-

{satelliteInfo.longitudeDeg}° E

-

Longitude

-
-
- -
-

Above {satelliteInfo.country}

-
-
{/* Include the flag icon here */}
-
- ); -} diff --git a/frontend/src/components/map/exampleSatData.js b/frontend/src/components/satelliteData/exampleSatData.js similarity index 100% rename from frontend/src/components/map/exampleSatData.js rename to frontend/src/components/satelliteData/exampleSatData.js diff --git a/frontend/src/lib/convertSatrec.ts b/frontend/src/lib/convertSatrec.ts index d7f93e1..11aeef5 100644 --- a/frontend/src/lib/convertSatrec.ts +++ b/frontend/src/lib/convertSatrec.ts @@ -1,6 +1,6 @@ import * as satellite from "satellite.js"; import { SatRec } from "satellite.js"; -import globeData from "@components/map/githubglobe/files/globe-data.json"; +import globeData from "@components/homeComponents/files/globe-data.json"; // turf needs ts ignore to work with typescript // @ts-ignore diff --git a/frontend/src/lib/getSatelliteData.ts b/frontend/src/lib/getSatelliteData.ts index 7cea5a7..db9e88e 100644 --- a/frontend/src/lib/getSatelliteData.ts +++ b/frontend/src/lib/getSatelliteData.ts @@ -1,6 +1,6 @@ import { twoline2satrec } from "satellite.js"; import { SatRec } from "satellite.js"; -import { exampleData } from "@/components/map/exampleSatData"; +import { exampleData } from "@/components/satelliteData/exampleSatData"; // Satellite data interface interface SatelliteData { diff --git a/frontend/src/lib/store.ts b/frontend/src/lib/store.ts index 64d3912..072c4e0 100644 --- a/frontend/src/lib/store.ts +++ b/frontend/src/lib/store.ts @@ -26,6 +26,10 @@ export const useSatelliteStore = create((set, get) => ({ "0 EXPLORER 7", "0 SOLRAD 3/INJUN 1", "0 STARLINK-1007", + "0 TIROS 1", + "0 EXPLORER 11", + "0 GREB", + "0 METEOR 1-5", ], selectedSatellite: "0 VANGUARD 2",