Skip to content

Commit

Permalink
Clean up URL code
Browse files Browse the repository at this point in the history
  • Loading branch information
dabreegster committed Jun 5, 2024
1 parent b482861 commit 9c785d6
Show file tree
Hide file tree
Showing 8 changed files with 57 additions and 64 deletions.
8 changes: 4 additions & 4 deletions src/lib/browse/layers/areas/CensusOutputAreas.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
import { colors } from "../../colors";
import OsOglLicense from "../OsOglLicense.svelte";
import SequentialLegend from "../SequentialLegend.svelte";
import { customUrl } from "../url";
import { customUrlState } from "../url";
let name = "census_output_areas";
let colorScale = colors.sequential_low_to_high;
Expand All @@ -33,13 +33,13 @@
function stringify(x: State): string | null {
return x.show ? x.kind : null;
}
function parse(result: string): State {
function parse(x: string): State {
return {
show: true,
kind: result,
kind: x,
};
}
let state = customUrl(name, defaultState, stringify, parse);
let state = customUrlState(name, defaultState, stringify, parse);
// Mutually exclusive, like a radio button. We need these for checkboxes to work
let showHouseholdsWithCar = $state.kind == "percent_households_with_car";
Expand Down
8 changes: 4 additions & 4 deletions src/lib/browse/layers/areas/Pollution.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import { layerId } from "lib/maplibre";
import { RasterLayer, RasterTileSource } from "svelte-maplibre";
import OsOglLicense from "../OsOglLicense.svelte";
import { customUrl } from "../url";
import { customUrlState } from "../url";
type State = {
show: boolean;
Expand All @@ -19,15 +19,15 @@
function stringify(x: State): string | null {
return x.show ? `${x.pollutant}/${x.opacity}` : null;
}
function parse(result: string): State {
let [pollutant, opacity] = result.split("/");
function parse(x: string): State {
let [pollutant, opacity] = x.split("/");
return {
show: true,
pollutant,
opacity: parseInt(opacity),
};
}
let state = customUrl("pollution", defaultState, stringify, parse);
let state = customUrlState("pollution", defaultState, stringify, parse);
// URLs and layers found from https://uk-air.defra.gov.uk/data/wms-services
// and QGIS
Expand Down
31 changes: 14 additions & 17 deletions src/lib/browse/layers/lines/CyclePaths.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,12 @@
} from "svelte-maplibre";
import { colors, denseLineWidth } from "../../colors";
import OsmLicense from "../OsmLicense.svelte";
import { customUrl } from "../url";
import { customUrlState } from "../url";
let name = "cycle_paths";
type State = {
group: boolean;
show: boolean;
track: boolean;
lane: boolean;
shared_use_segregated: boolean;
Expand All @@ -34,29 +34,26 @@
"shared_use_unsegregated",
] as const;
let defaultState = {
group: false,
show: false,
track: true,
lane: true,
shared_use_segregated: true,
shared_use_unsegregated: true,
};
function stringify(x: State): string | null {
if (!x.group) {
return null;
}
return keys.filter((c) => x[c]).join(",");
return x.show ? keys.filter((c) => x[c]).join(",") : null;
}
function parse(result: string): State {
function parse(x: string): State {
return {
group: true,
track: result.includes("track"),
lane: result.includes("lane"),
shared_use_segregated: result.includes("shared_use_segregated"),
shared_use_unsegregated: result.includes("shared_use_unsegregated"),
show: true,
track: x.includes("track"),
lane: x.includes("lane"),
shared_use_segregated: x.includes("shared_use_segregated"),
shared_use_unsegregated: x.includes("shared_use_unsegregated"),
};
}
let state = customUrl(name, defaultState, stringify, parse);
let state = customUrlState(name, defaultState, stringify, parse);
let legend = [
["track", "Separated tracks", colors.cycle_paths.track],
Expand Down Expand Up @@ -104,7 +101,7 @@
}
</script>

<Checkbox bind:checked={$state.group}>
<Checkbox bind:checked={$state.show}>
Cycle paths
<span slot="right">
<HelpButton>
Expand Down Expand Up @@ -142,7 +139,7 @@
</HelpButton>
</span>
</Checkbox>
{#if $state.group}
{#if $state.show}
<div style="border: 1px solid black; padding: 8px;">
<CheckboxGroup>
{#each legend as [kind, label, color]}
Expand Down Expand Up @@ -176,7 +173,7 @@
"line-opacity": hoverStateFilter(1.0, 0.5),
}}
layout={{
visibility: $state.group ? "visible" : "none",
visibility: $state.show ? "visible" : "none",
}}
filter={makeFilter($state)}
manageHoverState
Expand Down
13 changes: 5 additions & 8 deletions src/lib/browse/layers/lines/PCT.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
} from "svelte-maplibre";
import { colors, denseLineWidth } from "../../colors";
import SequentialLegend from "../SequentialLegend.svelte";
import { customUrl } from "../url";
import { customUrlState } from "../url";
// TODO It'd be much simpler to have one source with both attributes
let nameCommute = "pct_commute";
Expand All @@ -33,20 +33,17 @@
scenario: "baseline",
};
function stringify(x: State): string | null {
if (!x.show) {
return null;
}
return `${x.tripPurpose}/${x.scenario}`;
return x.show ? `${x.tripPurpose}/${x.scenario}` : null;
}
function parse(result: string): State {
let [tripPurpose, scenario] = result.split("/");
function parse(x: string): State {
let [tripPurpose, scenario] = x.split("/");
return {
show: true,
tripPurpose,
scenario,
};
}
let state = customUrl("pct", defaultState, stringify, parse);
let state = customUrlState("pct", defaultState, stringify, parse);
// TODO Don't use a function and @html; do everything in Svelte?
function tooltip(props: { [name: string]: any }): string {
Expand Down
13 changes: 5 additions & 8 deletions src/lib/browse/layers/lines/RoadSpeeds.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
} from "svelte-maplibre";
import { colors, denseLineWidth } from "../../colors";
import SequentialLegend from "../SequentialLegend.svelte";
import { customUrl } from "../url";
import { customUrlState } from "../url";
let name = "road_speeds";
let colorScale = colors.sequential_low_to_high;
Expand All @@ -29,18 +29,15 @@
kind: "indicative_mph",
};
function stringify(x: State): string | null {
if (!x.show) {
return null;
}
return x.kind;
return x.show ? x.kind : null;
}
function parse(result: string): State {
function parse(x: string): State {
return {
show: true,
kind: result,
kind: x,
};
}
let state = customUrl(name, defaultState, stringify, parse);
let state = customUrlState(name, defaultState, stringify, parse);
let times: Record<string, string> = {
mf4to7: "Monday-Friday 4-7am",
Expand Down
29 changes: 13 additions & 16 deletions src/lib/browse/layers/points/Education.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -15,47 +15,44 @@
} from "svelte-maplibre";
import { colors } from "../../colors";
import OsmLicense from "../OsmLicense.svelte";
import { customUrl } from "../url";
import { customUrlState } from "../url";
let name = "education";
type State = {
group: boolean;
show: boolean;
school: boolean;
college: boolean;
university: boolean;
};
let keys = ["school", "college", "university"] as const;
let defaultState = {
group: false,
show: false,
school: true,
college: true,
university: true,
};
function stringify(x: State): string | null {
if (!x.group) {
return null;
}
return keys.filter((c) => x[c]).join(",");
return x.show ? keys.filter((c) => x[c]).join(",") : null;
}
function parse(result: string): State {
function parse(x: string): State {
return {
group: true,
school: result.includes("school"),
college: result.includes("college"),
university: result.includes("university"),
show: true,
school: x.includes("school"),
college: x.includes("college"),
university: x.includes("university"),
};
}
let state = customUrl(name, defaultState, stringify, parse);
let state = customUrlState(name, defaultState, stringify, parse);
function makeFilter(state: State): ExpressionSpecification {
let include = keys.filter((l) => state[l]);
return ["in", ["get", "type"], ["literal", include]];
}
</script>

<Checkbox bind:checked={$state.group}>
<Checkbox bind:checked={$state.show}>
Education
<span slot="right">
<HelpButton>
Expand All @@ -67,7 +64,7 @@
</HelpButton>
</span>
</Checkbox>
{#if $state.group}
{#if $state.show}
<div style="border: 1px solid black; padding: 8px;">
<CheckboxGroup>
<Checkbox bind:checked={$state.school}>
Expand Down Expand Up @@ -105,7 +102,7 @@
"fill-opacity": hoverStateFilter(0.7, 1.0),
}}
layout={{
visibility: $state.group ? "visible" : "none",
visibility: $state.show ? "visible" : "none",
}}
filter={makeFilter($state)}
manageHoverState
Expand Down
8 changes: 4 additions & 4 deletions src/lib/browse/layers/points/Stats19.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
} from "svelte-maplibre";
import { colors } from "../../colors";
import OsOglLicense from "../OsOglLicense.svelte";
import { customUrl } from "../url";
import { customUrlState } from "../url";
let name = "stats19";
Expand Down Expand Up @@ -46,8 +46,8 @@
let bools = keys.filter((c) => x[c]).join(",");
return `${bools}/${x.minYear}/${x.maxYear}`;
}
function parse(result: string): State {
let [bools, minYear, maxYear] = result.split("/");
function parse(x: string): State {
let [bools, minYear, maxYear] = x.split("/");
return {
show: true,
pedestrians: bools.includes("pedestrians"),
Expand All @@ -59,7 +59,7 @@
};
}
let state = customUrl(name, defaultState, stringify, parse);
let state = customUrlState(name, defaultState, stringify, parse);
$: filter = makeFilter(
$state.minYear,
Expand Down
11 changes: 8 additions & 3 deletions src/lib/browse/layers/url.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { writable, type Writable } from "svelte/store";

// Create a store to represent whether a layer should be shown or hidden. The
// state is synced as a URL query parameter.
export function showHideLayer(name: string): Writable<boolean> {
let initialValue = new URLSearchParams(window.location.search).has(name);
let store = writable(initialValue);
Expand All @@ -16,11 +18,14 @@ export function showHideLayer(name: string): Writable<boolean> {
return store;
}

export function customUrl<T>(
// Create a store to represent some state about a layer, syncing it to a URL
// query parameter. The parameter missing is equivalent to stringify returning
// null.
export function customUrlState<T>(
name: string,
defaultValue: T,
stringify: (x: T) => string | null,
parse: (x: string) => T,
stringify: (state: T) => string | null,
parse: (param: string) => T,
): Writable<T> {
let param = new URLSearchParams(window.location.search).get(name);
let initialValue = param == null ? defaultValue : parse(param);
Expand Down

0 comments on commit 9c785d6

Please sign in to comment.