From 52558ed3b2e7ed787b46605d6f087ce04c3f2aa4 Mon Sep 17 00:00:00 2001 From: ThePetrovich Date: Fri, 27 Jun 2025 19:27:19 +0800 Subject: [PATCH] Continue messing with stores --- src/lib/prediction.ts | 12 ++++--- src/lib/stores.ts | 62 ++++++++++++++++++++++++++++----- src/lib/telemetry.ts | 4 +-- src/lib/types.ts | 56 +++++++++++++++++++---------- src/routes/ControlPanel.svelte | 33 +++++++++--------- src/routes/map.svelte | 43 +++++++++-------------- src/routes/predict/+page.svelte | 21 ++++++----- 7 files changed, 148 insertions(+), 83 deletions(-) diff --git a/src/lib/prediction.ts b/src/lib/prediction.ts index cdda7a3..2eed534 100644 --- a/src/lib/prediction.ts +++ b/src/lib/prediction.ts @@ -3,8 +3,8 @@ import type { LatLngExpression } from "leaflet"; import L from "leaflet"; import { getCsrfToken } from "./auth"; -import type { PredictionStage, Prediction, ParsedPrediction } from "./types"; -import { latestPrediction, latestPredictionParsed } from "./stores"; +import type { PredictionStage, RawPrediction, Prediction } from "./types"; +import { PredictionStore, RawPredictionStore, writeLocalStorage } from "./stores"; function getLatestDataset() { const now = new Date(); @@ -76,8 +76,10 @@ export const getForecast = async ( const data = await response.json(); console.log("Forecast response:", data); - latestPrediction.set(data.result); - latestPredictionParsed.set(parsePrediction(data.result.prediction)); + RawPredictionStore.set(data.result as RawPrediction); + PredictionStore.set(parsePrediction(data.result.prediction) as Prediction); + writeLocalStorage("rawPrediction", data.result as RawPrediction); + writeLocalStorage("prediction", parsePrediction(data.result.prediction) as Prediction); alert("Forecast request successful!"); // Handle the response data as needed @@ -87,7 +89,7 @@ export const getForecast = async ( } }; -export function parsePrediction(prediction: PredictionStage[]): ParsedPrediction { +export function parsePrediction(prediction: PredictionStage[]): Prediction { const flight_path: [number, number, number][] = []; const launch: { latlng: LatLngExpression; datetime: Date } = {} as any; const burst: { latlng: LatLngExpression; datetime: Date } = {} as any; diff --git a/src/lib/stores.ts b/src/lib/stores.ts index 4e30cff..03a3c2c 100644 --- a/src/lib/stores.ts +++ b/src/lib/stores.ts @@ -1,8 +1,40 @@ import { writable } from "svelte/store"; -import type { FlightParameters, Telemetry, ParsedTelemetry } from "./types"; -import type { Prediction, ParsedPrediction } from "./types"; +import type { FlightParameters, RawTelemetry, Telemetry } from "./types"; +import type { RawPrediction, Prediction } from "./types"; -export const flightParametersStore = writable({ +export const readLocalStorage = (key: string, defaultValue: T): T => { + const item = localStorage.getItem(key); + if (item) { + try { + const parsed = JSON.parse(item); + if (typeof parsed === "object" && parsed !== null) { + return parsed as T; + } + } catch (error) { + console.error(`Error parsing ${key} from localStorage:`, error); + } + } + return defaultValue; +}; + +export const writeLocalStorage = (key: string, value: T): void => { + try { + localStorage.setItem(key, JSON.stringify(value)); + } catch (error) { + console.error(`Error writing ${key} to localStorage:`, error); + } +} + +export const clearLocalStorage = (key: string): void => { + try { + localStorage.removeItem(key); + } + catch (error) { + console.error(`Error clearing ${key} from localStorage:`, error); + } +} + +const flightParametersDefaults: FlightParameters = { ascent_rate: 5.0, burst_altitude: 30000.0, dataset: "", @@ -14,10 +46,24 @@ export const flightParametersStore = writable({ launch_longitude: 129.1234, profile: "standard_profile", version: 2, -}); +}; -export const latestTelemetry = writable({} as Telemetry); -export const latestTelemetryParsed = writable({} as ParsedTelemetry); +export const FlightParametersStore = writable( + readLocalStorage("flightParameters", flightParametersDefaults) +); -export const latestPrediction = writable({} as Prediction); -export const latestPredictionParsed = writable({} as ParsedPrediction); +export const RawTelemetryStore = writable( + readLocalStorage("rawTelemetry", {} as RawTelemetry) +); + +export const TelemetryStore = writable( + readLocalStorage("telemetry", {} as Telemetry) +); + +export const RawPredictionStore = writable( + readLocalStorage("rawPrediction", {} as RawPrediction) +); + +export const PredictionStore = writable( + readLocalStorage("prediction", {} as Prediction) +); diff --git a/src/lib/telemetry.ts b/src/lib/telemetry.ts index 906d144..b320f74 100644 --- a/src/lib/telemetry.ts +++ b/src/lib/telemetry.ts @@ -1,9 +1,9 @@ import { writable } from "svelte/store" import L from "leaflet"; -import type { TelemetryPoint, ParsedTelemetry } from "./types"; +import type { TelemetryPoint, Telemetry } from "./types"; -export function parseTelemetry(telemetry: TelemetryPoint[]): ParsedTelemetry { +export function parseTelemetry(telemetry: TelemetryPoint[]): Telemetry { const flight_path: [number, number, number][] = telemetry.map((point) => [ point.latitude, point.longitude, diff --git a/src/lib/types.ts b/src/lib/types.ts index fc0f6d4..34029d5 100644 --- a/src/lib/types.ts +++ b/src/lib/types.ts @@ -1,4 +1,4 @@ -import type { LatLngExpression } from "leaflet"; +import type { LatLngExpression, LatLngLiteral } from "leaflet"; export const PROFILE_MAP = { Normal: "standard_profile", @@ -31,7 +31,17 @@ export interface TelemetryPoint { payload: string; } -export interface ParsedTelemetry { +export interface TelemetryMetadata { + complete_datetime: string; + start_datetime: string; +} + +export interface RawTelemetry { + metadata: TelemetryMetadata; + telemetry: TelemetryPoint[]; +} + +export interface Telemetry { flight_path: [number, number, number][]; launch: { latlng: LatLngExpression; @@ -40,15 +50,6 @@ export interface ParsedTelemetry { datapoints: TelemetryPoint[]; } -export interface ParsedTelemetryMetadata { - complete_datetime: string; - start_datetime: string; -} - -export interface Telemetry { - metadata: ParsedTelemetryMetadata; - telemetry: TelemetryPoint[]; -} export interface TrajectoryPoint { altitude: number; @@ -62,7 +63,17 @@ export interface PredictionStage { trajectory: TrajectoryPoint[]; } -export interface ParsedPrediction { +export interface PredictionMetadata { + complete_datetime: string; + start_datetime: string; +} + +export interface RawPrediction { + metadata: PredictionMetadata; + prediction: PredictionStage[]; +} + +export interface Prediction { flight_path: [number, number, number][]; launch: { latlng: LatLngExpression; @@ -80,12 +91,21 @@ export interface ParsedPrediction { flight_time: number; } -export interface ParsedPredictionMetadata { - complete_datetime: string; - start_datetime: string; +export interface Point { + latlng: LatLngLiteral & { alt: number }; + datetime: Date; } -export interface Prediction { - metadata: ParsedPredictionMetadata; - prediction: PredictionStage[]; +export interface PredictionData { + launch: Point; + landing: Point; + burst: Point; + flight_path: LatLngExpression[]; + flight_time: number; +} + +export interface TelemetryData { + launch: Point; + datapoints: TelemetryPoint[]; + flight_path: LatLngExpression[]; } \ No newline at end of file diff --git a/src/routes/ControlPanel.svelte b/src/routes/ControlPanel.svelte index 3e08f65..c9b9858 100644 --- a/src/routes/ControlPanel.svelte +++ b/src/routes/ControlPanel.svelte @@ -14,7 +14,7 @@ import { getForecast } from "$lib/prediction"; import type { FlightParameters, ProfileName } from "$lib/types"; import { PROFILE_MAP } from "$lib/types"; - import { flightParametersStore } from '$lib/stores'; + import { FlightParametersStore, writeLocalStorage } from '$lib/stores'; let isCollapsed = false; let selectedProfile: ProfileName = "Normal"; @@ -24,19 +24,20 @@ let startDate = now.toISOString().split("T")[0]; // YYYY-MM-DD let startTime = now.toISOString().split("T")[1].split(".")[0]; // HH:MM:SS - let inputLat = $flightParametersStore.launch_latitude.toString(); - let inputLng = $flightParametersStore.launch_longitude.toString(); + let inputLat = $FlightParametersStore.launch_latitude.toString(); + let inputLng = $FlightParametersStore.launch_longitude.toString(); - $: $flightParametersStore.profile = PROFILE_MAP[selectedProfile]; + $: $FlightParametersStore.profile = PROFILE_MAP[selectedProfile]; const handleGetPrediction = async () => { - console.log("Fetching prediction with parameters:", $flightParametersStore); + console.log("Fetching prediction with parameters:", $FlightParametersStore); console.log(startDate, startTime); - $flightParametersStore.launch_datetime = `${startDate}T${startTime}Z`; + $FlightParametersStore.launch_datetime = `${startDate}T${startTime}Z`; + writeLocalStorage("flightParameters", $FlightParametersStore); try { - const response = await getForecast($flightParametersStore); + const response = await getForecast($FlightParametersStore); console.log(response); // TODO: Notify other components of the new prediction. // const dispatch = createEventDispatcher(); @@ -52,9 +53,9 @@ const lng = parseFloat(inputLng); if (!isNaN(lat) && !isNaN(lng)) { - $flightParametersStore.launch_latitude = lat; - $flightParametersStore.launch_longitude = lng; - console.log("Updated position:", $flightParametersStore.launch_latitude, $flightParametersStore.launch_longitude); + $FlightParametersStore.launch_latitude = lat; + $FlightParametersStore.launch_longitude = lng; + console.log("Updated position:", $FlightParametersStore.launch_latitude, $FlightParametersStore.launch_longitude); } else { console.error("Invalid coordinate input"); // TODO: Show a validation error to the user. @@ -67,8 +68,8 @@ * @param {number} lng The new longitude. */ export const updateLaunchPosition = (lat: number, lng: number) => { - $flightParametersStore.launch_latitude = lat; - $flightParametersStore.launch_longitude = lng; + $FlightParametersStore.launch_latitude = lat; + $FlightParametersStore.launch_longitude = lng; console.log("Launch position updated:", lat, lng); inputLat = lat.toString(); inputLng = lng.toString(); @@ -214,7 +215,7 @@ type="number" id="startHeight" class="form-control-sm" - bind:value={$flightParametersStore.launch_altitude} + bind:value={$FlightParametersStore.launch_altitude} /> @@ -236,7 +237,7 @@ type="number" id="ascentRate" class="form-control-sm" - bind:value={$flightParametersStore.ascent_rate} + bind:value={$FlightParametersStore.ascent_rate} /> @@ -245,7 +246,7 @@ type="number" id="descentRate" class="form-control-sm" - bind:value={$flightParametersStore.descent_rate} + bind:value={$FlightParametersStore.descent_rate} /> @@ -256,7 +257,7 @@ type="number" id="burstAltitude" class="form-control-sm" - bind:value={$flightParametersStore.burst_altitude} + bind:value={$FlightParametersStore.burst_altitude} /> diff --git a/src/routes/map.svelte b/src/routes/map.svelte index af0222b..1774d04 100644 --- a/src/routes/map.svelte +++ b/src/routes/map.svelte @@ -2,37 +2,12 @@ import { onMount, createEventDispatcher } from "svelte"; import * as L from "leaflet"; import type { Map as LeafletMap, LayerGroup } from "leaflet"; - type LatLngExpression = [number, number] | { lat: number; lng: number }; - type LatLngLiteral = { lat: number; lng: number }; import "leaflet/dist/leaflet.css"; import VelocityLayer from "./velocity.svelte"; import { distHaversine } from "../lib/mathutil.ts"; + import type { PredictionData, TelemetryData } from "../lib/types.ts"; - interface Point { - latlng: LatLngLiteral & { alt: number }; - datetime: Date; - } - interface PredictionData { - launch: Point; - landing: Point; - burst: Point; - flight_path: LatLngExpression[]; - flight_time: number; - } - - interface TelemetryPoint { - altitude: number; - datetime: string; - latitude: number; - longitude: number; - } - - interface TelemetryData { - launch: Point; - datapoints: TelemetryPoint[]; - flight_path: LatLngExpression[]; - } /** * @type {'prediction' | 'telemetry'} @@ -151,6 +126,22 @@ map?.fitBounds(L.latLngBounds(telemetry.flight_path)); }; + + export const panTo = (lat: number, lng: number) => { + if (map) { + map.setView([lat, lng], map.getZoom()); + } + }; + + export const zoomTo = (lat: number, lng: number, zoomLevel: number) => { + if (map) { + map.setView([lat, lng], zoomLevel); + } + }; + + export const getMap = () => { + return map; + };
diff --git a/src/routes/predict/+page.svelte b/src/routes/predict/+page.svelte index 9ea74b4..6af1fe0 100644 --- a/src/routes/predict/+page.svelte +++ b/src/routes/predict/+page.svelte @@ -3,24 +3,29 @@ import ControlPanel from '../ControlPanel.svelte'; import Navbar from '../Navbar.svelte'; import { onMount } from 'svelte'; - import { latestPredictionParsed } from '$lib/stores'; + import { PredictionStore } from '$lib/stores'; import { Modal } from '@sveltestrap/sveltestrap'; + import L from 'leaflet'; - let map: { plotData?: (prediction: any) => void } | null = null; + + let map: Map | null = null; + let panel: ControlPanel | null = null; onMount(() => { - latestPredictionParsed.subscribe((prediction) => { - if (prediction && map) { - map.plotData?.(prediction); + PredictionStore.subscribe((data) => { + if (data) { + map?.clearMapLayers(); } }); + + L.DomEvent.disableClickPropagation(panel?.$element); + L.DomEvent.disableScrollPropagation(panel?.$element); });
- - + +
\ No newline at end of file