Skip to content

Commit

Permalink
138 create 2 2d map component tracking a single satellite (#231)
Browse files Browse the repository at this point in the history
* feat(ide): ✨ Add zustand and store.ts

* feat(backend): ✨ Add fetch of satellite data based on name

* example usage

* semi-working country finder

* prettier

* lint

* simple styling for component

* feat(backend): ✨ Refactor code of zustand store to enable multiple satellite showings

* small fixes

* eslint and prettier

* testing setup

* geomercator

* feat(frontend): add new map projection

* feat(frontend): ✨ Add better map projection and add live data for satellite

* show to pradipta

* small change to test code

* feat(frontend): Finish map, fix styling, add turf to check country

Fixed general styling of the map, can be changed later based on new designs. Added turf to check country to fix bugs with the previous method.

* lint and prettier

* add 2dmap to satdatatable

* lint and prettier
  • Loading branch information
Lukas Thrane authored and GitHub committed Apr 7, 2024
1 parent 6928f11 commit 7ad0821
Show file tree
Hide file tree
Showing 9 changed files with 29,728 additions and 183 deletions.
2,008 changes: 1,933 additions & 75 deletions frontend/package-lock.json

Large diffs are not rendered by default.

9 changes: 9 additions & 0 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,13 @@
"@radix-ui/react-separator": "^1.0.3",
"@radix-ui/react-slot": "^1.0.2",
"@strapi/blocks-react-renderer": "^1.0.0",
"@turf/boolean-point-in-polygon": "^6.5.0",
"@turf/helpers": "^6.5.0",
"@turf/nearest-point-to-line": "^6.5.0",
"@turf/point-to-line-distance": "^6.5.0",
"@turf/turf": "^6.5.0",
"@visx/geo": "^3.5.0",
"@visx/scale": "^3.5.0",
"add": "^2.0.6",
"chart.js": "^4.4.1",
"chartjs-adapter-luxon": "^1.3.1",
Expand Down Expand Up @@ -53,6 +60,7 @@
"tailwind-merge": "^2.2.0",
"tailwindcss-animate": "^1.0.7",
"three": "^0.161.0",
"topojson-client": "^3.1.0",
"vaul": "^0.9.0",
"zustand": "^4.5.2"
},
Expand All @@ -72,6 +80,7 @@
"@types/react": "^18",
"@types/react-dom": "^18",
"@types/three": "^0.161.2",
"@types/topojson-client": "^3.1.4",
"autoprefixer": "^10.0.1",
"eslint": "^8",
"eslint-config-next": "14.1.0",
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import ColoredSection from "@/components/ui/coloredSection";

import Image from "next/image";
import Link from "next/link";
import SatelliteDataTable from "@/components/satelliteData/SatelliteDataTableMultiple";
import SatelliteDataTableMultiple from "@/components/satelliteData/SatelliteDataTableMultiple";
import fetchSatelliteData from "@components/map/SatelliteFetcher";

import fetchMostRecentImage from "@/lib/data/fetchMostRecentImage";
Expand All @@ -15,7 +15,7 @@ export default async function Home() {
<>
<div className="grid grid-cols-2">
<div className="grid grid-cols-2">
<SatelliteDataTable
<SatelliteDataTableMultiple
fetchSatelliteData={fetchSatelliteData}
/>
</div>
Expand Down
99 changes: 99 additions & 0 deletions frontend/src/components/2dmap/2dMapProjection.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
"use client";
/* eslint-disable react/jsx-handler-names */
import React from "react";
import * as topojson from "topojson-client";
import { CustomProjection } from "@visx/geo";
import { geoNaturalEarth1 } from "@visx/vendor/d3-geo";
import topology from "./world-topo.json";

export type GeoCustomProps = {
width: number;
height: number;
satLatitude?: number;
satLongitude?: number;
};

interface FeatureShape {
type: "Feature";
id: string;
geometry: { coordinates: [number, number][][]; type: "Polygon" };
properties: { name: string };
}

export const background = "";

// @ts-expect-error
const world = topojson.feature(topology, topology.objects.units) as {
type: "FeatureCollection";
features: FeatureShape[];
};

export default function GeoCustom({
width,
height,
satLatitude,
satLongitude,
}: GeoCustomProps) {
const centerX = width / 2;
const centerY = height / 2;
const scale = (width / 630) * 100;

// This function projects lat/long to the SVG coordinate system
const projection = geoNaturalEarth1()
.scale(scale)
.translate([centerX, centerY]);

// Check if both satLatitude and satLongitude are defined
let satPoint: [number, number] | undefined;
if (typeof satLatitude === "number" && typeof satLongitude === "number") {
satPoint = projection([satLongitude, satLatitude]) || undefined;
}
return width < 10 ? null : (
<>
<div className="relative">
<svg width={width} height={height}>
<rect
x={0}
y={0}
width={width}
height={height}
fill={background}
rx={14}
/>
<CustomProjection<FeatureShape>
projection={geoNaturalEarth1}
data={world.features}
scale={scale}
translate={[centerX, centerY]}
>
{(customProjection) => (
<g>
{customProjection.features.map(
({ path }, i) => (
<path
key={`map-feature-${i}`}
d={path || ""}
fill={"#d3d3d3"}
stroke={"#000"}
strokeWidth={0.5}
/>
),
)}
{satPoint && (
<circle
cx={satPoint[0]}
cy={satPoint[1]}
r="6"
fill="red"
stroke="black"
strokeWidth="1"
/>
)}
</g>
)}
</CustomProjection>
</svg>
</div>
</>
);
}
56 changes: 56 additions & 0 deletions frontend/src/components/2dmap/Map2d.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
"use client";
import GeoCustom from "./2dMapProjection";
import { useSatelliteStore } from "@/lib/store";
import React, { useState, useEffect } from "react";
import { SatelliteInfo, convertSatrec } from "@/lib/convertSatrec";

const updateInterval = 10;

export default function Map2d({ satName }: { satName: string }) {
const { satelliteData, fetchAndSetSatelliteData } = useSatelliteStore();
const [satelliteInfo, setSatelliteInfo] = useState<SatelliteInfo | null>(
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]);

// Convert string values to numbers
const satLatitude = satelliteInfo
? parseFloat(satelliteInfo.latitudeDeg)
: undefined;
const satLongitude = satelliteInfo
? parseFloat(satelliteInfo.longitudeDeg)
: undefined;

const width = 960;
const height = width / 2;

return (
<div className="">
<GeoCustom
width={width}
height={height}
satLatitude={satLatitude}
satLongitude={satLongitude}
/>
</div>
);
}
Loading

0 comments on commit 7ad0821

Please sign in to comment.