Skip to content

Commit

Permalink
Add a layer of TS indirection around the WASM API. Not being too precise
Browse files Browse the repository at this point in the history
with the GJ types yet
  • Loading branch information
dabreegster committed Dec 28, 2024
1 parent 86d9446 commit ed7e108
Show file tree
Hide file tree
Showing 17 changed files with 234 additions and 107 deletions.
8 changes: 3 additions & 5 deletions web/src/AnimatePaths.svelte
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
<script lang="ts">
import along from "@turf/along";
import type { FeatureCollection, LineString } from "geojson";
import type { FeatureCollection } from "geojson";
import { onDestroy } from "svelte";
import { CircleLayer, GeoJSON } from "svelte-maplibre";
import { layerId } from "./common";
import type { AllShortcuts } from "./wasm";
export let paths: FeatureCollection<
LineString,
{ directness: number; length_meters: number }
>;
export let paths: AllShortcuts;
let totalDirectness = sumWeights();
Expand Down
13 changes: 5 additions & 8 deletions web/src/App.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
import SetBoundaryMode from "./SetBoundaryMode.svelte";
import Settings from "./Settings.svelte";
import {
app,
backend,
map as mapStore,
maptilerApiKey,
maptilerBasemap,
Expand Down Expand Up @@ -60,10 +60,7 @@
}
function zoomToFit() {
$mapStore!.fitBounds(
Array.from($app!.getBounds()) as [number, number, number, number],
{ animate: false },
);
$mapStore!.fitBounds($backend!.getBounds(), { animate: false });
}
let topDiv: HTMLSpanElement;
Expand Down Expand Up @@ -97,7 +94,7 @@

<hr />

{#if $app}
{#if $backend}
<button class="secondary" on:click={zoomToFit}>
Zoom to fit study area
</button>
Expand Down Expand Up @@ -144,8 +141,8 @@
{:else if $mode.mode == "new-project"}
<NewProjectMode />
{/if}
{#if $app}
<GeoJSON data={JSON.parse($app.getInvertedBoundary())}>
{#if $backend}
<GeoJSON data={$backend.getInvertedBoundary()}>
<FillLayer
{...layerId("boundary")}
paint={{ "fill-color": "black", "fill-opacity": 0.3 }}
Expand Down
14 changes: 7 additions & 7 deletions web/src/AutoBoundariesMode.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,15 @@
import BackButton from "./BackButton.svelte";
import { layerId, Link } from "./common";
import { pickNeighbourhoodName } from "./common/pick_names";
import { app, autosave, editPerimeterRoads, mode } from "./stores";
import { autosave, backend, editPerimeterRoads, mode } from "./stores";
let gj = JSON.parse($app!.renderAutoBoundaries());
let gj = $backend!.renderAutoBoundaries();
let minArea = 0;
let removeNonRoad = true;
function add(e: CustomEvent<LayerClickInfo>) {
let name = pickNeighbourhoodName(
$app!,
$backend!,
"What do you want to name the neighbourhood?",
"",
);
Expand All @@ -30,15 +30,15 @@
}
try {
let feature = {
type: "Feature",
type: "Feature" as const,
// Omit waypoints and lazily fill them out.
properties: {},
// Trust generateId to make IDs in order
geometry: gj.features[e.detail.features[0].id!].geometry,
geometry: gj.features[e.detail.features[0].id as number].geometry,
};
$app!.setNeighbourhoodBoundary(name, feature);
$backend!.setNeighbourhoodBoundary(name, feature);
autosave();
$app!.setCurrentNeighbourhood(name, $editPerimeterRoads);
$backend!.setCurrentNeighbourhood(name, $editPerimeterRoads);
$mode = {
mode: "neighbourhood",
};
Expand Down
6 changes: 3 additions & 3 deletions web/src/DebugMode.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import BackButton from "./BackButton.svelte";
import { layerId, Link } from "./common";
import RenderNeighbourhood from "./RenderNeighbourhood.svelte";
import { app, mode } from "./stores";
import { backend, mode } from "./stores";
</script>

<SplitComponent>
Expand Down Expand Up @@ -39,7 +39,7 @@

<div slot="map">
<RenderNeighbourhood
gjInput={JSON.parse(notNull($app).renderNeighbourhood())}
gjInput={notNull($backend).renderNeighbourhood()}
interactive
onClickLine={(f, _) => window.open(notNull(f.properties).way, "_blank")}
>
Expand Down Expand Up @@ -76,7 +76,7 @@
</svelte:fragment>
</RenderNeighbourhood>

<GeoJSON data={JSON.parse(notNull($app).renderModalFilters())} generateId>
<GeoJSON data={notNull($backend).renderModalFilters()} generateId>
<CircleLayer
{...layerId("debug-filters")}
paint={{
Expand Down
28 changes: 13 additions & 15 deletions web/src/ImpactOneDestinationMode.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,19 @@
import { setCellColors } from "./cells";
import { layerId, Link } from "./common";
import ModalFilterLayer from "./ModalFilterLayer.svelte";
import { app, mode, one_destination, route_pt_a, route_pt_b } from "./stores";
import {
backend,
mode,
one_destination,
route_pt_a,
route_pt_b,
} from "./stores";
function back() {
$mode = { mode: "neighbourhood" };
}
$: perRoadGj = JSON.parse(
$app!.impactToOneDestination($one_destination.lng, $one_destination.lat),
);
$: perRoadGj = $backend!.impactToOneDestination($one_destination);
let hovered: Feature | null = null;
Expand All @@ -37,14 +41,10 @@
if (!hovered) {
return emptyGeojson();
}
return JSON.parse(
$app!.compareRoute(
hovered.properties!.pt1_x,
hovered.properties!.pt1_y,
$one_destination.lng,
$one_destination.lat,
1.0,
),
return $backend!.compareRoute(
new LngLat(hovered.properties!.pt1_x, hovered.properties!.pt1_y),
$one_destination,
1.0,
);
}
Expand Down Expand Up @@ -96,9 +96,7 @@
</div>

<div slot="map">
<GeoJSON
data={setCellColors(JSON.parse(notNull($app).renderNeighbourhood()))}
>
<GeoJSON data={setCellColors(notNull($backend).renderNeighbourhood())}>
<FillLayer
{...layerId("cells")}
filter={["==", ["get", "kind"], "cell"]}
Expand Down
6 changes: 4 additions & 2 deletions web/src/ModalFilterLayer.svelte
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
<script lang="ts">
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();
</script>

<GeoJSON data={gj} generateId>
Expand Down
25 changes: 14 additions & 11 deletions web/src/NetworkMode.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -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" };
}
Expand All @@ -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?",
"",
);
Expand All @@ -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(),
);
}
Expand Down
20 changes: 9 additions & 11 deletions web/src/RouteMode.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -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 };
Expand Down Expand Up @@ -80,7 +78,7 @@
<div slot="map">
{#if prevMode == "neighbourhood"}
<RenderNeighbourhood
gjInput={JSON.parse(notNull($app).renderNeighbourhood())}
gjInput={notNull($backend).renderNeighbourhood()}
interactive={false}
/>
{/if}
Expand Down
6 changes: 3 additions & 3 deletions web/src/SetBoundaryMode.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -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<Polygon, AreaProps> | null;
Expand Down Expand Up @@ -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",
};
Expand Down
10 changes: 4 additions & 6 deletions web/src/ViewShortcutsMode.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -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 =
| {
Expand All @@ -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;
Expand Down Expand Up @@ -150,7 +150,7 @@
<div slot="map">
{#if state.state == "neutral"}
<RenderNeighbourhood
gjInput={JSON.parse(notNull($app).renderNeighbourhood())}
gjInput={notNull($backend).renderNeighbourhood()}
onClickLine={choseRoad}
>
<div slot="line-popup">
Expand All @@ -162,9 +162,7 @@
</div>
</RenderNeighbourhood>
{:else if state.state == "chose-road"}
<GeoJSON
data={setCellColors(JSON.parse(notNull($app).renderNeighbourhood()))}
>
<GeoJSON data={setCellColors(notNull($backend).renderNeighbourhood())}>
<FillLayer
{...layerId("cells")}
filter={["==", ["get", "kind"], "cell"]}
Expand Down
7 changes: 4 additions & 3 deletions web/src/common/pick_names.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
import { LTN } from "backend";
import type { Feature } from "geojson";
import type { Backend } from "../wasm";

// Returns a name for a neighbourhood, or null if the user cancels. Guaranteed to not overwrite an existing name.
export function pickNeighbourhoodName(
app: LTN,
backend: Backend,
promptMessage: string,
defaultValue: string,
): string | null {
let used: Set<String> = new Set(
JSON.parse(app.toSavefile())
backend
.toSavefile()
.features.filter((f: Feature) => f.properties!.kind == "boundary")
.map((f: Feature) => f.properties!.name),
);
Expand Down
Loading

0 comments on commit ed7e108

Please sign in to comment.