From ed7e108cedd5cd8a59e7a29cd86e19599f1d1a1a Mon Sep 17 00:00:00 2001 From: Dustin Carlino Date: Sat, 28 Dec 2024 15:43:47 +0000 Subject: [PATCH] Add a layer of TS indirection around the WASM API. Not being too precise with the GJ types yet --- web/src/AnimatePaths.svelte | 8 +- web/src/App.svelte | 13 +-- web/src/AutoBoundariesMode.svelte | 14 +-- web/src/DebugMode.svelte | 6 +- web/src/ImpactOneDestinationMode.svelte | 28 +++-- web/src/ModalFilterLayer.svelte | 6 +- web/src/NetworkMode.svelte | 25 +++-- web/src/RouteMode.svelte | 20 ++-- web/src/SetBoundaryMode.svelte | 6 +- web/src/ViewShortcutsMode.svelte | 10 +- web/src/common/pick_names.ts | 7 +- web/src/edit/NeighbourhoodMode.svelte | 24 ++-- web/src/stores.ts | 6 +- web/src/title/NewProjectMode.svelte | 6 +- web/src/title/TitleMode.svelte | 4 +- web/src/title/loader.ts | 19 ++-- web/src/wasm.ts | 139 +++++++++++++++++++++++- 17 files changed, 234 insertions(+), 107 deletions(-) diff --git a/web/src/AnimatePaths.svelte b/web/src/AnimatePaths.svelte index 21aa22f..4ee007f 100644 --- a/web/src/AnimatePaths.svelte +++ b/web/src/AnimatePaths.svelte @@ -1,14 +1,12 @@ @@ -39,7 +39,7 @@
window.open(notNull(f.properties).way, "_blank")} > @@ -76,7 +76,7 @@ - +
- + import { GeoJSON, SymbolLayer } from "svelte-maplibre"; + import { emptyGeojson } from "svelte-utils/map"; import { layerId } from "./common"; - import { app, mutationCounter } from "./stores"; + import { backend, mutationCounter } from "./stores"; // TODO Runes would make this so nicer. The > 0 part is a hack... - $: gj = $mutationCounter > 0 ? JSON.parse($app!.renderModalFilters()) : null; + $: gj = + $mutationCounter > 0 ? $backend!.renderModalFilters() : emptyGeojson(); diff --git a/web/src/NetworkMode.svelte b/web/src/NetworkMode.svelte index 0f9d7e7..2983d23 100644 --- a/web/src/NetworkMode.svelte +++ b/web/src/NetworkMode.svelte @@ -10,21 +10,21 @@ import { pickNeighbourhoodName } from "./common/pick_names"; import ModalFilterLayer from "./ModalFilterLayer.svelte"; import { - app, autosave, + backend, editPerimeterRoads, mode, projectName, } from "./stores"; // Note we do this to trigger a refresh when loading stuff - $: gj = JSON.parse($app!.toSavefile()); + $: gj = $backend!.toSavefile(); $: boundaryNames = gj.features .filter((f: Feature) => f.properties!.kind == "boundary") .map((f: Feature) => f.properties!.name); function pickNeighbourhood(name: string) { - $app!.setCurrentNeighbourhood(name, $editPerimeterRoads); + $backend!.setCurrentNeighbourhood(name, $editPerimeterRoads); $mode = { mode: "neighbourhood" }; } @@ -34,29 +34,29 @@ `Really delete neighbourhood ${name}? You can't undo this.`, ) ) { - $app!.deleteNeighbourhoodBoundary(name); + $backend!.deleteNeighbourhoodBoundary(name); autosave(); // TODO Improve perf, don't call this twice - gj = JSON.parse($app!.toSavefile()); + gj = $backend!.toSavefile(); } } function renameNeighbourhood(name: string) { let newName = pickNeighbourhoodName( - $app!, + $backend!, `Rename neighbourhood ${name} to what?`, name, ); if (newName) { - $app!.renameNeighbourhoodBoundary(name, newName); + $backend!.renameNeighbourhoodBoundary(name, newName); autosave(); - gj = JSON.parse($app!.toSavefile()); + gj = $backend!.toSavefile(); } } function newBoundary() { let name = pickNeighbourhoodName( - $app!, + $backend!, "What do you want to name the neighbourhood?", "", ); @@ -66,13 +66,16 @@ } function exportGJ() { - downloadGeneratedFile($projectName + ".geojson", $app!.toSavefile()); + downloadGeneratedFile( + $projectName + ".geojson", + JSON.stringify($backend!.toSavefile()), + ); } function debugRouteSnapper() { downloadGeneratedFile( "debug_route_snapper.geojson", - $app!.toRouteSnapperGj(), + $backend!.toRouteSnapperGj(), ); } diff --git a/web/src/RouteMode.svelte b/web/src/RouteMode.svelte index 6511d08..4c7dc51 100644 --- a/web/src/RouteMode.svelte +++ b/web/src/RouteMode.svelte @@ -7,19 +7,17 @@ import { layerId, Link } from "./common"; import ModalFilterLayer from "./ModalFilterLayer.svelte"; import RenderNeighbourhood from "./RenderNeighbourhood.svelte"; - import { app, mainRoadPenalty, mode, route_pt_a, route_pt_b } from "./stores"; + import { + backend, + mainRoadPenalty, + mode, + route_pt_a, + route_pt_b, + } from "./stores"; export let prevMode: "network" | "neighbourhood" | "impact-one-destination"; - $: gj = JSON.parse( - $app!.compareRoute( - $route_pt_a.lng, - $route_pt_a.lat, - $route_pt_b.lng, - $route_pt_b.lat, - $mainRoadPenalty, - ), - ); + $: gj = $backend!.compareRoute($route_pt_a, $route_pt_b, $mainRoadPenalty); function back() { $mode = { mode: prevMode }; @@ -80,7 +78,7 @@
{#if prevMode == "neighbourhood"} {/if} diff --git a/web/src/SetBoundaryMode.svelte b/web/src/SetBoundaryMode.svelte index d6c1f05..7890b9c 100644 --- a/web/src/SetBoundaryMode.svelte +++ b/web/src/SetBoundaryMode.svelte @@ -5,7 +5,7 @@ import { Link } from "./common"; import AreaControls from "./common/draw_area/AreaControls.svelte"; import { calculateArea, waypoints } from "./common/draw_area/stores"; - import { app, autosave, editPerimeterRoads, map, mode } from "./stores"; + import { autosave, backend, editPerimeterRoads, map, mode } from "./stores"; export let name: string; export let existing: Feature | null; @@ -34,9 +34,9 @@ if ($waypoints.length >= 3) { try { let feature = calculateArea($waypoints); - $app!.setNeighbourhoodBoundary(name, feature); + $backend!.setNeighbourhoodBoundary(name, feature); autosave(); - $app!.setCurrentNeighbourhood(name, $editPerimeterRoads); + $backend!.setCurrentNeighbourhood(name, $editPerimeterRoads); $mode = { mode: "neighbourhood", }; diff --git a/web/src/ViewShortcutsMode.svelte b/web/src/ViewShortcutsMode.svelte index 3751fd4..b4f7f5f 100644 --- a/web/src/ViewShortcutsMode.svelte +++ b/web/src/ViewShortcutsMode.svelte @@ -11,7 +11,7 @@ import { layerId, Link } from "./common"; import ModalFilterLayer from "./ModalFilterLayer.svelte"; import RenderNeighbourhood from "./RenderNeighbourhood.svelte"; - import { app, map, mode } from "./stores"; + import { backend, map, mode } from "./stores"; type State = | { @@ -26,7 +26,7 @@ let state: State = { state: "neutral" }; function choseRoad(roadGj: Feature, _: LngLat) { - let gj = JSON.parse($app!.getShortcutsCrossingRoad(roadGj.properties!.id)); + let gj = $backend!.getShortcutsCrossingRoad(roadGj.properties!.id); if (gj.features.length == 0) { window.alert("No shortcuts here"); return; @@ -150,7 +150,7 @@
{#if state.state == "neutral"}
@@ -162,9 +162,7 @@
{:else if state.state == "chose-road"} - + = new Set( - JSON.parse(app.toSavefile()) + backend + .toSavefile() .features.filter((f: Feature) => f.properties!.kind == "boundary") .map((f: Feature) => f.properties!.name), ); diff --git a/web/src/edit/NeighbourhoodMode.svelte b/web/src/edit/NeighbourhoodMode.svelte index cef1399..ca8c8b7 100644 --- a/web/src/edit/NeighbourhoodMode.svelte +++ b/web/src/edit/NeighbourhoodMode.svelte @@ -13,8 +13,8 @@ import RenderNeighbourhood from "../RenderNeighbourhood.svelte"; import { animateShortcuts, - app, autosave, + backend, editPerimeterRoads, filterType, map, @@ -25,7 +25,7 @@ import ChangeModalFilter from "./ChangeModalFilter.svelte"; import FreehandLine from "./FreehandLine.svelte"; - // Caller is responsible for doing app.setCurrentNeighbourhood + // Caller is responsible for doing backend.setCurrentNeighbourhood type Action = "filter" | "freehand-filters" | "oneway"; let action: Action = "filter"; @@ -45,7 +45,7 @@ > | null; let gjInput: RenderNeighbourhoodOutput; - let allShortcuts = JSON.parse($app!.getAllShortcuts()); + let allShortcuts = $backend!.getAllShortcuts(); $: rerender($mutationCounter); $: numDisconnectedCells = gjInput.features.filter( @@ -58,20 +58,20 @@ }); function rerender(_x: number) { - gjInput = JSON.parse($app!.renderNeighbourhood()); + gjInput = $backend!.renderNeighbourhood(); // @ts-expect-error TS can't figure out that we're narrowing the case here boundary = gjInput.features.find((f) => f.properties.kind == "boundary")!; undoLength = gjInput.undo_length; redoLength = gjInput.redo_length; - allShortcuts = JSON.parse($app!.getAllShortcuts()); + allShortcuts = $backend!.getAllShortcuts(); autosave(); } function recalculateNeighbourhoodDefinition() { - $app!.setCurrentNeighbourhood( + $backend!.setCurrentNeighbourhood( boundary!.properties.name, $editPerimeterRoads, ); @@ -80,17 +80,17 @@ function onClickLine(f: Feature, pt: LngLat) { if (action == "filter") { - $app!.addModalFilter(pt, $filterType); + $backend!.addModalFilter(pt, $filterType); $mutationCounter++; } else if (action == "oneway") { - $app!.toggleDirection(f.properties!.road); + $backend!.toggleDirection(f.properties!.road); $mutationCounter++; } } function deleteFilter(e: CustomEvent) { let f = e.detail.features[0]; - $app!.deleteModalFilter(f.properties!.road); + $backend!.deleteModalFilter(f.properties!.road); $mutationCounter++; } @@ -116,18 +116,18 @@ } } function undo() { - $app!.undo(); + $backend!.undo(); $mutationCounter++; } function redo() { - $app!.redo(); + $backend!.redo(); $mutationCounter++; } function gotFreehandLine(e: CustomEvent | null>) { let f = e.detail; if (f) { - $app!.addManyModalFilters(f, $filterType); + $backend!.addManyModalFilters(f, $filterType); $mutationCounter++; } diff --git a/web/src/stores.ts b/web/src/stores.ts index 6f7bd28..19ec8d2 100644 --- a/web/src/stores.ts +++ b/web/src/stores.ts @@ -1,8 +1,8 @@ -import { LTN } from "backend"; import type { Feature, Polygon } from "geojson"; import { LngLat, type Map } from "maplibre-gl"; import { type AreaProps } from "route-snapper-ts"; import { get, writable, type Writable } from "svelte/store"; +import type { Backend } from "./wasm"; export const maptilerApiKey = "MZEJTanw3WpxRvt7qDfo"; @@ -50,7 +50,7 @@ export let useLocalVite: Writable = writable(false); export let projectName: Writable = writable(""); export let showAbout: Writable = writable(true); -export let app: Writable = writable(null); +export let backend: Writable = writable(null); export let route_pt_a: Writable = writable(new LngLat(0, 0)); export let route_pt_b: Writable = writable(new LngLat(0, 0)); export let one_destination: Writable = writable(new LngLat(0, 0)); @@ -68,5 +68,5 @@ export function autosave() { if (!key) { window.alert("Autosave failed; no projectName set?!"); } - window.localStorage.setItem(key, get(app)!.toSavefile()); + window.localStorage.setItem(key, JSON.stringify(get(backend)!.toSavefile())); } diff --git a/web/src/title/NewProjectMode.svelte b/web/src/title/NewProjectMode.svelte index 4eafdbb..a712c81 100644 --- a/web/src/title/NewProjectMode.svelte +++ b/web/src/title/NewProjectMode.svelte @@ -1,5 +1,4 @@