Skip to content

Commit

Permalink
Render more appropriate stuff in shortcuts mode
Browse files Browse the repository at this point in the history
  • Loading branch information
dabreegster committed Dec 24, 2023
1 parent 12ac548 commit 3f1b743
Show file tree
Hide file tree
Showing 5 changed files with 160 additions and 112 deletions.
3 changes: 2 additions & 1 deletion backend/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,8 @@ impl LTN {
self.render_neighbourhood()
}

fn render_neighbourhood(&self) -> Result<String, JsValue> {
#[wasm_bindgen(js_name = renderNeighbourhood)]
pub fn render_neighbourhood(&self) -> Result<String, JsValue> {
Ok(
serde_json::to_string(&self.neighbourhood.as_ref().unwrap().to_gj(&self.map))
.map_err(err_to_js)?,
Expand Down
8 changes: 7 additions & 1 deletion web/src/App.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,13 @@
bind:mode
/>
{:else if mode.mode == "view-shortcuts"}
<ViewShortcutsMode bind:mode {app} prevMode={mode.prevMode} {map} />
<ViewShortcutsMode
bind:mode
{app}
prevMode={mode.prevMode}
{map}
{showBasemap}
/>
{/if}
{/if}
</MapLibre>
Expand Down
115 changes: 15 additions & 100 deletions web/src/NeighbourhoodMode.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,7 @@
import type { Feature, Polygon } from "geojson";
import type { Map, MapMouseEvent } from "maplibre-gl";
import { onDestroy } from "svelte";
import {
CircleLayer,
FillLayer,
GeoJSON,
hoverStateFilter,
LineLayer,
Popup,
type LayerClickInfo,
} from "svelte-maplibre";
import {
constructMatchExpression,
isLine,
isPoint,
isPolygon,
PropertiesTable,
} from "./common";
import RenderNeighbourhood from "./RenderNeighbourhood.svelte";
import SplitComponent from "./SplitComponent.svelte";
export let mode: Mode;
Expand Down Expand Up @@ -46,29 +31,14 @@
"#ffed6f",
];
let details;
let maxShortcuts;
let gjInput;
render(app.analyzeNeighbourhood(boundary));
function render(gjString) {
let gj = JSON.parse(gjString);
maxShortcuts = Math.max(
...gj.features.map((f) => f.properties.shortcuts ?? 0)
);
gjInput = JSON.parse(gjString);
for (let f of gj.features) {
if (f.properties.color == "disconnected") {
f.properties.color = "red";
} else if (Object.hasOwn(f.properties, "color")) {
f.properties.color =
cell_colors[f.properties.color % cell_colors.length];
}
}
undoLength = gj.undo_length;
redoLength = gj.redo_length;
details = gj;
undoLength = gjInput.undo_length;
redoLength = gjInput.redo_length;
}
$: if (addingFilter) {
Expand All @@ -90,10 +60,9 @@
map.style.cursor = "inherit";
}
function deleteFilter(e: CustomEvent<LayerClickInfo>) {
let props = e.detail.features[0].properties;
if (props.kind == "modal_filter") {
render(app.deleteModalFilter(props.road));
function deleteFilter(f: Feature) {
if (f.properties.kind == "modal_filter") {
render(app.deleteModalFilter(f.properties.road));
}
}
Expand Down Expand Up @@ -164,66 +133,12 @@
</div>

<div slot="map">
<GeoJSON data={details} generateId>
<FillLayer
beforeId={showBasemap ? "Building" : undefined}
filter={isPolygon}
manageHoverState
paint={{
"fill-color": ["get", "color"],
"fill-opacity": hoverStateFilter(0.3, 0.5),
}}
/>

<LineLayer
filter={isLine}
paint={{
"line-width": 5,
"line-color": constructMatchExpression(
["get", "kind"],
{
interior_road: [
"interpolate-hcl",
["linear"],
["get", "shortcuts"],
0,
"#F19A93",
maxShortcuts,
"#A32015",
],
crosses: "blue",
},
"red"
),
}}
on:click={(e) =>
window.open(e.detail.features[0].properties.way, "_blank")}
hoverCursor="pointer"
>
<Popup openOn="hover" let:data>
<PropertiesTable properties={data.properties} />
</Popup>
</LineLayer>

<CircleLayer
filter={isPoint}
paint={{
"circle-radius": 15,
"circle-color": constructMatchExpression(
["get", "kind"],
{
border_intersection: "green",
modal_filter: "black",
},
"red"
),
}}
on:click={deleteFilter}
>
<Popup openOn="hover" let:data>
<PropertiesTable properties={data.properties} />
</Popup>
</CircleLayer>
</GeoJSON>
<RenderNeighbourhood
{gjInput}
{showBasemap}
onClickLine={(f) => window.open(f.properties.way, "_blank")}
onClickCircle={deleteFilter}
popups
/>
</div>
</SplitComponent>
125 changes: 125 additions & 0 deletions web/src/RenderNeighbourhood.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
<script lang="ts">
import {
CircleLayer,
FillLayer,
GeoJSON,
hoverStateFilter,
LineLayer,
Popup,
} from "svelte-maplibre";
import {
constructMatchExpression,
isLine,
isPoint,
isPolygon,
PropertiesTable,
} from "./common";
export let gjInput;
export let showBasemap: boolean;
export let onClickLine = (f) => {};
export let onClickCircle = (f) => {};
// TODO Or take some named slots
export let popups = false;
let gj;
let maxShortcuts;
$: render(gjInput, showBasemap);
function render(x, y) {
// A qualitative palette from colorbrewer2.org, skipping the red hue (used
// for levels of shortcutting) and grey (too close to the basemap)
let cell_colors = [
"#8dd3c7",
"#ffffb3",
"#bebada",
"#80b1d3",
"#fdb462",
"#b3de69",
"#fccde5",
"#bc80bd",
"#ccebc5",
"#ffed6f",
];
maxShortcuts = Math.max(
...gjInput.features.map((f) => f.properties.shortcuts ?? 0)
);
for (let f of gjInput.features) {
if (f.properties.color == "disconnected") {
f.properties.color = "red";
} else if (Object.hasOwn(f.properties, "color")) {
f.properties.color =
cell_colors[f.properties.color % cell_colors.length];
}
}
gj = gjInput;
}
</script>

<GeoJSON data={gj} generateId>
<FillLayer
beforeId={showBasemap ? "Building" : undefined}
filter={isPolygon}
manageHoverState
paint={{
"fill-color": ["get", "color"],
"fill-opacity": hoverStateFilter(0.3, 0.5),
}}
/>

<LineLayer
filter={isLine}
paint={{
"line-width": 5,
"line-color": constructMatchExpression(
["get", "kind"],
{
interior_road: [
"interpolate-hcl",
["linear"],
["get", "shortcuts"],
0,
"#F19A93",
maxShortcuts,
"#A32015",
],
crosses: "blue",
},
"red"
),
}}
on:click={(e) => onClickLine(e.detail.features[0])}
hoverCursor="pointer"
>
{#if popups}
<Popup openOn="hover" let:data>
<PropertiesTable properties={data.properties} />
</Popup>
{/if}
</LineLayer>

<CircleLayer
filter={isPoint}
paint={{
"circle-radius": 15,
"circle-color": constructMatchExpression(
["get", "kind"],
{
border_intersection: "green",
modal_filter: "black",
},
"red"
),
}}
on:click={(e) => onClickCircle(e.detail.features[0])}
>
{#if popups}
<Popup openOn="hover" let:data>
<PropertiesTable properties={data.properties} />
</Popup>
{/if}
</CircleLayer>
</GeoJSON>
21 changes: 11 additions & 10 deletions web/src/ViewShortcutsMode.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@
import type { Map } from "maplibre-gl";
import { onDestroy, onMount } from "svelte";
import { GeoJSON, LineLayer } from "svelte-maplibre";
import RenderNeighbourhood from "./RenderNeighbourhood.svelte";
import SplitComponent from "./SplitComponent.svelte";
export let mode: Mode;
export let app: LTN;
export let prevMode: Mode;
export let map: Map;
export let showBasemap: boolean;
type State =
| {
Expand Down Expand Up @@ -58,6 +60,10 @@
state.shortcutIndex++;
}
}
if (e.key == "Escape") {
e.stopPropagation();
back();
}
}
}
Expand Down Expand Up @@ -95,16 +101,11 @@

<div slot="map">
{#if state.state == "neutral"}
<GeoJSON data={JSON.parse(app.render())}>
<LineLayer
paint={{
"line-width": 5,
"line-color": "black",
}}
on:click={(e) => choseRoad(app, e.detail.features[0].properties.id)}
hoverCursor="pointer"
/>
</GeoJSON>
<RenderNeighbourhood
gjInput={JSON.parse(app.renderNeighbourhood())}
{showBasemap}
onClickLine={(f) => choseRoad(app, f.properties.id)}
/>
{:else if state.state == "chose-road"}
{#if state.shortcutIndex == null}
<GeoJSON data={state.gj}>
Expand Down

0 comments on commit 3f1b743

Please sign in to comment.