Skip to content

Commit

Permalink
Add a freehand polygon draw tool for area check summary
Browse files Browse the repository at this point in the history
  • Loading branch information
dabreegster committed Mar 22, 2024
1 parent 78565f3 commit 6c941c7
Show file tree
Hide file tree
Showing 5 changed files with 275 additions and 1 deletion.
174 changes: 174 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
"@sveltejs/kit": "^2.0.0",
"@sveltejs/vite-plugin-svelte": "^3.0.0",
"@types/eslint": "^8.56.5",
"@types/geojson": "^7946.0.14",
"@types/uuid": "^9.0.8",
"@typescript-eslint/eslint-plugin": "^7.2.0",
"@typescript-eslint/parser": "^7.2.0",
Expand All @@ -34,8 +35,10 @@
"type": "module",
"dependencies": {
"@maptiler/geocoding-control": "^1.2.2",
"@turf/area": "^6.5.0",
"govuk-frontend": "^5.2.0",
"govuk-svelte": "github:acteng/govuk-svelte",
"maplibre-draw-polygon": "github:dabreegster/maplibre-draw-polygon",
"svelte-maplibre": "^0.8.2",
"uuid": "^9.0.1"
}
Expand Down
3 changes: 3 additions & 0 deletions src/routes/area_check/data.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { writable } from "svelte/store";
import type { Feature, Polygon } from "geojson";

export interface State {
summary: {
Expand All @@ -17,6 +18,7 @@ export interface State {
// TODO number
schemeAreaSizeKm2: string;
notes: string;
polygon: Feature<Polygon> | null;
};
// Exactly 13 entries, matching up with the scorecard questions. The values are the stringified scores.
existingScores: string[];
Expand Down Expand Up @@ -57,6 +59,7 @@ export function emptyState(): State {
inspectorEmail: "",
schemeAreaSizeKm2: "",
notes: "",
polygon: null,
},
existingScores: Array(13).fill(""),
proposedScores: Array(13).fill(""),
Expand Down
5 changes: 5 additions & 0 deletions src/routes/area_check/summary/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -84,5 +84,10 @@

<TextArea label="Notes" bind:value={$state.summary.notes} />

<h2>Network context</h2>
<p>
Please add a drawing of the area being assessed below, including the
location of measures proposed by the scheme.
</p>
<DrawArea />
</div>
91 changes: 90 additions & 1 deletion src/routes/area_check/summary/DrawArea.svelte
Original file line number Diff line number Diff line change
@@ -1,8 +1,84 @@
<script lang="ts">
import { MapLibre } from "svelte-maplibre";
import { state } from "../data";
import area from "@turf/area";
import { onDestroy } from "svelte";
import { WarningButton, DefaultButton, SecondaryButton } from "govuk-svelte";
import {
undoLength,
PolygonTool,
PolygonToolLayer,
} from "maplibre-draw-polygon";
import { MapLibre, GeoJSON, FillLayer, type Map } from "svelte-maplibre";
import { Geocoder } from "$lib";
// TODO Is it worth trying to preserve the map while navigating to other pages?
let map: Map | null = null;
$: gj = $state.summary.polygon ?? {
type: "FeatureCollection" as const,
features: [],
};
let draw: PolygonTool | null = null;
// TODO HMR is not working correctly
onDestroy(() => {
draw?.tearDown();
});
// Auto-start the tool
$: if (map) {
start();
}
function start() {
if (!map) {
return;
}
draw = new PolygonTool(map);
if ($state.summary.polygon) {
draw.editExisting($state.summary.polygon);
} else {
draw.startNew();
}
draw.addEventListenerSuccess(async (f) => {
draw = null;
$state.summary.polygon = f;
});
draw.addEventListenerFailure(() => {
draw = null;
// Leave previous polygon alone
});
}
function reset() {
$state.summary.polygon = null;
start();
}
</script>

{#if draw}
<div style="display: flex; justify-content: space-between;">
<SecondaryButton on:click={() => draw?.finish()}>Finish</SecondaryButton>
<SecondaryButton on:click={() => draw?.cancel()}>Cancel</SecondaryButton>
<SecondaryButton disabled={$undoLength == 0} on:click={() => draw?.undo()}>
{#if $undoLength == 0}
Undo
{:else}
Undo ({$undoLength})
{/if}
</SecondaryButton>
</div>
{:else if map}
<DefaultButton on:click={start}>Edit polygon</DefaultButton>
{#if $state.summary.polygon}
<WarningButton on:click={reset}>Delete and start over</WarningButton>
<p>Polygon area: {area($state.summary.polygon).toFixed(1)} square meters</p>
{/if}
{:else}
<p>Map loading...</p>
{/if}

<div style="position: relative; width: 100%; height: 300px;">
<MapLibre
style={`https://api.maptiler.com/maps/uk-openzoomstack-light/style.json?key=${import.meta.env.VITE_MAPTILER_API_KEY}`}
Expand All @@ -12,7 +88,20 @@
console.log(e.detail.error);
}}
let:map
bind:map
>
<Geocoder {map} />
<PolygonToolLayer />
<GeoJSON data={gj}>
<FillLayer
layout={{
visibility: draw ? "none" : "visible",
}}
paint={{
"fill-color": "red",
"fill-opacity": 0.8,
}}
/>
</GeoJSON>
</MapLibre>
</div>

0 comments on commit 6c941c7

Please sign in to comment.