Skip to content

Commit

Permalink
Let users initialize empty schemes. To avoid circular dependency, have
Browse files Browse the repository at this point in the history
to rethink the API of new{xyz}Feature, which is probably good anyway.
  • Loading branch information
dabreegster committed Jul 8, 2024
1 parent bd03de1 commit 17152c4
Show file tree
Hide file tree
Showing 10 changed files with 110 additions and 79 deletions.
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ TODO: Document all of these
- upgrade packages
- consider renaming "intervention" and "scheme"
- coverage polygons in InterventionLayer
- addEmptyScheme needs to blank pipeline
- can we totally remove mapStyle from this library and let streetview tool use a config hook instead?
- GeocoderControls assumes maptiler api key
- baselayer switcher at bottom of sidebar
41 changes: 7 additions & 34 deletions src/lib/config.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,3 @@
import {
newFeatureId,
getArbitrarySchemeRef,
gjSchemeCollection,
} from "$lib/draw/stores";
import type {
FeatureWithAnyProps,
FeatureWithID,
Expand Down Expand Up @@ -36,6 +31,8 @@ export let cfg = {
return json as SchemeCollection;
},

initializeEmptyScheme: (scheme: SchemeData) => {},

interventionWarning: (feature: FeatureWithAnyProps) => {
return null;
},
Expand All @@ -53,35 +50,11 @@ export let cfg = {
}>
>,

newPointFeature: (f: Feature<Point>) => {
gjSchemeCollection.update((gj) => {
f.id = newFeatureId(gj);
f.properties ||= {};
f.properties.scheme_reference = getArbitrarySchemeRef(gj);
gj.features.push(f as FeatureWithID);
return gj;
});
},

newPolygonFeature: (f: Feature<Polygon>) => {
gjSchemeCollection.update((gj) => {
f.id = newFeatureId(gj);
f.properties ||= {};
f.properties.scheme_reference = getArbitrarySchemeRef(gj);
gj.features.push(f as FeatureWithID);
return gj;
});
},

newLineStringFeature: (f: Feature<LineString>) => {
gjSchemeCollection.update((gj) => {
f.id = newFeatureId(gj);
f.properties ||= {};
f.properties.scheme_reference = getArbitrarySchemeRef(gj);
gj.features.push(f as FeatureWithID);
return gj;
});
},
// Should assign any necessary properties. Runs inside a gjSchemeCollection
// update; the logic shouldn't look at anything in there.
newPointFeature: (f: Feature<Point>) => {},
newPolygonFeature: (f: Feature<Polygon>) => {},
newLineStringFeature: (f: Feature<LineString>) => {},

updateFeature: (
destination: FeatureWithAnyProps,
Expand Down
23 changes: 19 additions & 4 deletions src/lib/draw/point/PointMode.svelte
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
<script lang="ts">
import type { Feature, Point } from "geojson";
import { mode, pointTool } from "$lib/draw/stores";
import {
mode,
pointTool,
gjSchemeCollection,
newFeatureId,
getArbitrarySchemeRef,
} from "$lib/draw/stores";
import { SecondaryButton } from "govuk-svelte";
import { onDestroy, onMount } from "svelte";
import PointControls from "./PointControls.svelte";
import { cfg } from "$lib/config";
import type { FeatureWithID } from "$lib/draw/types";
onMount(() => {
$pointTool!.start();
Expand All @@ -16,9 +23,17 @@
$pointTool!.clearEventListeners();
});
function onSuccess(feature: Feature<Point>) {
cfg.newPointFeature(feature);
mode.set({ mode: "edit-form", id: feature.id as number });
function onSuccess(f: Feature<Point>) {
gjSchemeCollection.update((gj) => {
f.id = newFeatureId(gj);
f.properties ||= {};
f.properties.scheme_reference = getArbitrarySchemeRef(gj);
cfg.newPointFeature(f);
gj.features.push(f as FeatureWithID);
return gj;
});
mode.set({ mode: "edit-form", id: f.id as number });
}
function onFailure() {
Expand Down
23 changes: 19 additions & 4 deletions src/lib/draw/polygon/PolygonMode.svelte
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
<script lang="ts">
import type { Feature, Polygon } from "geojson";
import { mode, polygonTool } from "$lib/draw/stores";
import {
mode,
polygonTool,
newFeatureId,
getArbitrarySchemeRef,
gjSchemeCollection,
} from "$lib/draw/stores";
import { ButtonGroup, DefaultButton, SecondaryButton } from "govuk-svelte";
import { onDestroy, onMount } from "svelte";
import PolygonControls from "./PolygonControls.svelte";
import { cfg } from "$lib/config";
import type { FeatureWithID } from "$lib/draw/types";
onMount(() => {
$polygonTool!.startNew();
Expand All @@ -16,9 +23,17 @@
$polygonTool!.clearEventListeners();
});
function onSuccess(feature: Feature<Polygon>) {
cfg.newPolygonFeature(feature);
mode.set({ mode: "edit-form", id: feature.id as number });
function onSuccess(f: Feature<Polygon>) {
gjSchemeCollection.update((gj) => {
f.id = newFeatureId(gj);
f.properties ||= {};
f.properties.scheme_reference = getArbitrarySchemeRef(gj);
cfg.newPolygonFeature(f);
gj.features.push(f as FeatureWithID);
return gj;
});
mode.set({ mode: "edit-form", id: f.id as number });
}
function onFailure() {
Expand Down
25 changes: 20 additions & 5 deletions src/lib/draw/route/RouteMode.svelte
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
<script lang="ts">
import type { Feature, LineString, Polygon } from "geojson";
import { mode, routeTool } from "$lib/draw/stores";
import {
mode,
routeTool,
newFeatureId,
getArbitrarySchemeRef,
gjSchemeCollection,
} from "$lib/draw/stores";
import { ButtonGroup, DefaultButton, SecondaryButton } from "govuk-svelte";
import { onDestroy, onMount } from "svelte";
import RouteControls from "./RouteControls.svelte";
import { cfg } from "$lib/config";
import type { FeatureWithID } from "$lib/draw/types";
onMount(() => {
$routeTool!.startRoute();
Expand All @@ -16,10 +23,18 @@
$routeTool!.clearEventListeners();
});
function onSuccess(feature: Feature<LineString | Polygon>) {
// We did startRoute, so we know it's a LineString
cfg.newLineStringFeature(feature as Feature<LineString>);
mode.set({ mode: "edit-form", id: feature.id as number });
function onSuccess(f: Feature<LineString | Polygon>) {
gjSchemeCollection.update((gj) => {
f.id = newFeatureId(gj);
f.properties ||= {};
f.properties.scheme_reference = getArbitrarySchemeRef(gj);
// @ts-expect-error We did startRoute, so we know it's a LineString
cfg.newPolygonFeature(f as Feature<LineString>);
gj.features.push(f as FeatureWithID);
return gj;
});
mode.set({ mode: "edit-form", id: f.id as number });
}
function onFailure() {
Expand Down
22 changes: 0 additions & 22 deletions src/lib/draw/schemes.ts
Original file line number Diff line number Diff line change
@@ -1,22 +0,0 @@
import { v4 as uuidv4 } from "uuid";
import { randomSchemeColor } from "./colors";
import type { SchemeCollection } from "./types";

export function emptyCollection(): SchemeCollection {
let gj = {
type: "FeatureCollection" as const,
features: [],
schemes: {},
};
addEmptyScheme(gj);
return gj;
}

export function addEmptyScheme(gj: SchemeCollection) {
let scheme_reference = uuidv4();
gj.schemes[scheme_reference] = {
scheme_reference,
color: randomSchemeColor(),
};
// TODO Give a hook for user to backfill / set up defaults here?
}
25 changes: 20 additions & 5 deletions src/lib/draw/snap_polygon/SnapPolygonMode.svelte
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
<script lang="ts">
import type { Feature, LineString, Polygon } from "geojson";
import { mode, routeTool } from "$lib/draw/stores";
import {
mode,
routeTool,
newFeatureId,
getArbitrarySchemeRef,
gjSchemeCollection,
} from "$lib/draw/stores";
import { ButtonGroup, DefaultButton, SecondaryButton } from "govuk-svelte";
import { onDestroy, onMount } from "svelte";
import SnapPolygonControls from "./SnapPolygonControls.svelte";
import { cfg } from "$lib/config";
import type { FeatureWithID } from "$lib/draw/types";
onMount(() => {
$routeTool!.startArea();
Expand All @@ -16,10 +23,18 @@
$routeTool!.clearEventListeners();
});
function onSuccess(feature: Feature<LineString | Polygon>) {
// We did startArea, so we know it's a Polygon
cfg.newPolygonFeature(feature as Feature<Polygon>);
mode.set({ mode: "edit-form", id: feature.id as number });
function onSuccess(f: Feature<LineString | Polygon>) {
gjSchemeCollection.update((gj) => {
f.id = newFeatureId(gj);
f.properties ||= {};
f.properties.scheme_reference = getArbitrarySchemeRef(gj);
// We did startArea, so we know it's a Polygon
cfg.newPolygonFeature(f as Feature<Polygon>);
gj.features.push(f as FeatureWithID);
return gj;
});
mode.set({ mode: "edit-form", id: f.id as number });
}
function onFailure() {
Expand Down
24 changes: 23 additions & 1 deletion src/lib/draw/stores.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import { emptyCollection } from "./schemes";
import { cfg } from "$lib/config";
import { writable, type Writable } from "svelte/store";
import type { Mode, SchemeCollection } from "./types";
import { PointTool } from "./point/point_tool";
import { PolygonTool } from "maplibre-draw-polygon";
import { RouteTool } from "route-snapper-ts";
import type { Position } from "geojson";
import { isStreetViewImagery, type UserSettings } from "./types";
import { v4 as uuidv4 } from "uuid";
import { randomSchemeColor } from "./colors";

// TODO Should we instead store a map from ID to feature?
export const gjSchemeCollection: Writable<SchemeCollection> =
Expand Down Expand Up @@ -103,3 +105,23 @@ function loadUserSettings(): UserSettings {
// The cast is necessary, because of streetViewImagery looking like just a string
return settings as UserSettings;
}

export function emptyCollection(): SchemeCollection {
let gj = {
type: "FeatureCollection" as const,
features: [],
schemes: {},
};
addEmptyScheme(gj);
return gj;
}

export function addEmptyScheme(gj: SchemeCollection) {
let scheme_reference = uuidv4();
let scheme = {
scheme_reference,
color: randomSchemeColor(),
};
cfg.initializeEmptyScheme(scheme);
gj.schemes[scheme_reference] = scheme;
}
3 changes: 1 addition & 2 deletions src/lib/sidebar/ListMode.svelte
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
<script lang="ts">
import { gjSchemeCollection } from "$lib/draw/stores";
import { gjSchemeCollection, addEmptyScheme } from "$lib/draw/stores";
import { ErrorMessage, FileInput, SecondaryButton } from "govuk-svelte";
import PerSchemeControls from "./PerSchemeControls.svelte";
import { cfg } from "$lib/config";
import { addEmptyScheme } from "$lib/draw/schemes";
function newBlankScheme() {
addEmptyScheme($gjSchemeCollection);
Expand Down
2 changes: 1 addition & 1 deletion src/lib/sidebar/PerSchemeControls.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
hideSchemes,
mode,
sidebarHover,
emptyCollection,
} from "$lib/draw/stores";
import {
ButtonGroup,
Expand All @@ -18,7 +19,6 @@
import { map, cfg } from "$lib/config";
import { onDestroy } from "svelte";
import deleteIcon from "$lib/assets/delete.svg?url";
import { emptyCollection } from "$lib/draw/schemes";
export let scheme_reference: string;
Expand Down

0 comments on commit 17152c4

Please sign in to comment.