Skip to content

Commit 3bbf5af

Browse files
committed
Sort out zordering. #3
1 parent 9f6bb95 commit 3bbf5af

14 files changed

+145
-19
lines changed

web/src/App.svelte

+8-5
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
import initRouteSnapper from "route-snapper";
55
import { onMount } from "svelte";
66
import { FillLayer, GeoJSON, MapLibre } from "svelte-maplibre";
7-
import { Layout } from "./common";
7+
import { Layout, layerId } from "./common";
88
import DebugMode from "./DebugMode.svelte";
99
import DebugGJ from "./DebugGJ.svelte";
1010
import NeighbourhoodMode from "./edit/NeighbourhoodMode.svelte";
@@ -16,7 +16,6 @@
1616
mapContents,
1717
map as mapStore,
1818
mode,
19-
showBasemap,
2019
sidebarContents,
2120
} from "./stores";
2221
import TitleMode from "./title/TitleMode.svelte";
@@ -29,7 +28,8 @@
2928
wasmReady = true;
3029
});
3130
32-
$: mapStyle = $showBasemap
31+
let showBasemap = true;
32+
$: mapStyle = showBasemap
3333
? "https://api.maptiler.com/maps/dataviz/style.json?key=MZEJTanw3WpxRvt7qDfo"
3434
: {
3535
version: 8 as const,
@@ -72,7 +72,7 @@
7272
{/if}
7373
<div>
7474
<label
75-
><input type="checkbox" bind:checked={$showBasemap} />Show basemap</label
75+
><input type="checkbox" bind:checked={showBasemap} />Show basemap</label
7676
>
7777
</div>
7878
</div>
@@ -111,7 +111,10 @@
111111
{/if}
112112
{#if $app}
113113
<GeoJSON data={JSON.parse($app.getInvertedBoundary())}>
114-
<FillLayer paint={{ "fill-color": "black", "fill-opacity": 0.3 }} />
114+
<FillLayer
115+
{...layerId("boundary")}
116+
paint={{ "fill-color": "black", "fill-opacity": 0.3 }}
117+
/>
115118
</GeoJSON>
116119
{#if $mode.mode == "network"}
117120
<NetworkMode />

web/src/DebugMode.svelte

+4-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<script lang="ts">
22
import { CircleLayer, GeoJSON, LineLayer } from "svelte-maplibre";
3-
import { notNull, PropertiesTable, Popup } from "./common";
3+
import { layerId, notNull, PropertiesTable, Popup } from "./common";
44
import RenderNeighbourhood from "./RenderNeighbourhood.svelte";
55
import SplitComponent from "./SplitComponent.svelte";
66
import { app, mode } from "./stores";
@@ -30,6 +30,7 @@
3030
</div>
3131
<svelte:fragment slot="more-layers">
3232
<CircleLayer
33+
{...layerId("debug-borders")}
3334
filter={["==", ["get", "kind"], "border_intersection"]}
3435
paint={{
3536
"circle-radius": 15,
@@ -41,6 +42,7 @@
4142
</Popup>
4243
</CircleLayer>
4344
<LineLayer
45+
{...layerId("debug-crosses")}
4446
filter={["==", ["get", "kind"], "crosses"]}
4547
paint={{
4648
"line-width": 5,
@@ -56,6 +58,7 @@
5658

5759
<GeoJSON data={JSON.parse(notNull($app).renderModalFilters())} generateId>
5860
<CircleLayer
61+
{...layerId("debug-filters")}
5962
paint={{
6063
"circle-radius": 15,
6164
"circle-color": "black",

web/src/ModalFilterLayer.svelte

+2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
<script lang="ts">
2+
import { layerId } from "./common";
23
import { GeoJSON, SymbolLayer } from "svelte-maplibre";
34
import { app, mutationCounter } from "./stores";
45
@@ -8,6 +9,7 @@
89

910
<GeoJSON data={gj}>
1011
<SymbolLayer
12+
{...layerId("modal-filters")}
1113
layout={{
1214
"icon-image": ["get", "filter_kind"],
1315
"icon-allow-overlap": true,

web/src/NetworkMode.svelte

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<script lang="ts">
22
import type { Feature } from "geojson";
33
import { FillLayer, GeoJSON, hoverStateFilter } from "svelte-maplibre";
4-
import { notNull, Popup } from "./common";
4+
import { layerId, notNull, Popup } from "./common";
55
import ManageSavefiles from "./ManageSavefiles.svelte";
66
import ModalFilterLayer from "./ModalFilterLayer.svelte";
77
import SplitComponent from "./SplitComponent.svelte";
@@ -80,6 +80,7 @@
8080
<div slot="map">
8181
<GeoJSON data={gj} generateId>
8282
<FillLayer
83+
{...layerId("neighbourhood-boundaries")}
8384
filter={["==", ["get", "kind"], "boundary"]}
8485
paint={{
8586
"fill-color": "red",

web/src/RenderNeighbourhood.svelte

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
<script lang="ts">
22
import type { Feature, FeatureCollection } from "geojson";
33
import { FillLayer, GeoJSON, LineLayer } from "svelte-maplibre";
4-
import { showBasemap } from "./stores";
54
import { setCellColors } from "./cells";
5+
import { layerId } from "./common";
66
77
export let gjInput: FeatureCollection;
88
// When disabled, can't click lines or filters, no slots, no hoverCursor
@@ -17,7 +17,7 @@
1717

1818
<GeoJSON data={gj} generateId>
1919
<FillLayer
20-
beforeId={$showBasemap ? "Building" : undefined}
20+
{...layerId("cells")}
2121
filter={["==", ["get", "kind"], "cell"]}
2222
paint={{
2323
"fill-color": ["get", "color"],
@@ -26,6 +26,7 @@
2626
/>
2727

2828
<LineLayer
29+
{...layerId("interior-roads")}
2930
filter={["==", ["get", "kind"], "interior_road"]}
3031
paint={{
3132
"line-width": 5,

web/src/RouteMode.svelte

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<script lang="ts">
22
import { onDestroy, onMount } from "svelte";
33
import { GeoJSON, LineLayer, Marker } from "svelte-maplibre";
4-
import { constructMatchExpression, notNull } from "./common";
4+
import { layerId, constructMatchExpression, notNull } from "./common";
55
import ModalFilterLayer from "./ModalFilterLayer.svelte";
66
import RenderNeighbourhood from "./RenderNeighbourhood.svelte";
77
import SplitComponent from "./SplitComponent.svelte";
@@ -60,6 +60,7 @@
6060
<ModalFilterLayer />
6161
<GeoJSON data={gj}>
6262
<LineLayer
63+
{...layerId("compare-route")}
6364
paint={{
6465
"line-width": 10,
6566
"line-color": constructMatchExpression(

web/src/ViewShortcutsMode.svelte

+5-3
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,11 @@
33
import type { Feature, FeatureCollection } from "geojson";
44
import { onDestroy, onMount } from "svelte";
55
import { FillLayer, GeoJSON, LineLayer } from "svelte-maplibre";
6-
import { notNull, Popup } from "./common";
6+
import { layerId, notNull, Popup } from "./common";
77
import ModalFilterLayer from "./ModalFilterLayer.svelte";
88
import RenderNeighbourhood from "./RenderNeighbourhood.svelte";
99
import SplitComponent from "./SplitComponent.svelte";
10-
import { app, map, mode, showBasemap } from "./stores";
10+
import { app, map, mode } from "./stores";
1111
1212
type State =
1313
| {
@@ -135,7 +135,7 @@
135135
data={setCellColors(JSON.parse(notNull($app).renderNeighbourhood()))}
136136
>
137137
<FillLayer
138-
beforeId={$showBasemap ? "Building" : undefined}
138+
{...layerId("cells")}
139139
filter={["==", ["get", "kind"], "cell"]}
140140
paint={{
141141
"fill-color": ["get", "color"],
@@ -146,6 +146,7 @@
146146

147147
<GeoJSON data={state.gj.features[state.shortcutIndex]}>
148148
<LineLayer
149+
{...layerId("shortcuts")}
149150
paint={{
150151
"line-width": 5,
151152
"line-color": "red",
@@ -154,6 +155,7 @@
154155
</GeoJSON>
155156
<GeoJSON data={state.roadGj}>
156157
<LineLayer
158+
{...layerId("shortcuts-focus")}
157159
paint={{
158160
"line-width": 5,
159161
"line-color": "blue",

web/src/common/draw_polygon/PolygonToolLayer.svelte

+4-3
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
<script lang="ts">
22
import { CircleLayer, FillLayer, GeoJSON, LineLayer } from "svelte-maplibre";
3-
import { isLine, isPoint, isPolygon } from "../";
3+
import { layerId, isLine, isPoint, isPolygon } from "../";
44
import { polygonToolGj } from "./stores";
55
</script>
66

77
<GeoJSON data={$polygonToolGj}>
88
<FillLayer
9-
id="edit-polygon-fill"
9+
{...layerId("edit-polygon-fill")}
1010
filter={isPolygon}
1111
paint={{
1212
"fill-color": "red",
@@ -19,6 +19,7 @@
1919
}}
2020
/>
2121
<LineLayer
22+
{...layerId("edit-polygon-lines")}
2223
filter={isLine}
2324
paint={{
2425
// TODO Dashed
@@ -28,7 +29,7 @@
2829
}}
2930
/>
3031
<CircleLayer
31-
id="edit-polygon-vertices"
32+
{...layerId("edit-polygon-vertices")}
3233
filter={isPoint}
3334
paint={{
3435
"circle-color": "black",

web/src/common/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ export { default as Modal } from "./Modal.svelte";
1111
export { default as OverpassSelector } from "./OverpassSelector.svelte";
1212
export { default as Popup } from "./Popup.svelte";
1313
export { default as PropertiesTable } from "./PropertiesTable.svelte";
14+
export { layerId } from "./zorder";
1415

1516
export const isPolygon: ExpressionSpecification = [
1617
"==",

web/src/common/snapper/RouteSnapperLayer.svelte

+10-1
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,20 @@
11
<script lang="ts">
22
import { CircleLayer, FillLayer, GeoJSON, LineLayer } from "svelte-maplibre";
3-
import { constructMatchExpression, isLine, isPoint, isPolygon } from "../";
3+
import {
4+
layerId,
5+
constructMatchExpression,
6+
isLine,
7+
isPoint,
8+
isPolygon,
9+
} from "../";
410
import { routeToolGj } from "./stores";
511
612
const circleRadiusPixels = 10;
713
</script>
814

915
<GeoJSON data={$routeToolGj}>
1016
<CircleLayer
17+
{...layerId("route-points")}
1118
filter={isPoint}
1219
paint={{
1320
"circle-color": constructMatchExpression(
@@ -27,13 +34,15 @@
2734
}}
2835
/>
2936
<LineLayer
37+
{...layerId("route-lines")}
3038
filter={isLine}
3139
paint={{
3240
"line-color": ["case", ["get", "snapped"], "red", "blue"],
3341
"line-width": 2.5,
3442
}}
3543
/>
3644
<FillLayer
45+
{...layerId("route-polygons")}
3746
filter={isPolygon}
3847
paint={{
3948
"fill-color": "black",

web/src/common/zorder.ts

+100
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
import { map as mapStore } from "../stores";
2+
import { get } from "svelte/store";
3+
4+
interface LayerProps {
5+
id: string;
6+
beforeId: string | undefined;
7+
}
8+
9+
// Use this helper for every svelte-maplibre layer component. It sets the layer
10+
// ID, beforeId (for z-ordering between layers), and defaults to only using the
11+
// top-most layer for hovering/clicking.
12+
export function layerId(layerId: string): LayerProps {
13+
return {
14+
id: layerId,
15+
beforeId: getBeforeId(layerId),
16+
};
17+
}
18+
19+
// Calculates the beforeId for adding a layer. Due to hot-module reloading and
20+
// Svelte component initialization order being unpredictable, callers might add
21+
// layers in any order. Use beforeId to guarantee the layers wind up in an
22+
// explicitly defined order.
23+
function getBeforeId(layerId: string): string | undefined {
24+
let map = get(mapStore);
25+
if (!map) {
26+
console.warn(
27+
`getBeforeId(${layerId}) called before map is ready. Z-ordering may be incorrect.`,
28+
);
29+
return undefined;
30+
}
31+
32+
// Find the last layer currently in the map that should be on top of this new
33+
// layer.
34+
let beforeId = undefined;
35+
let found = false;
36+
for (let i = layerZorder.length - 1; i >= 0; i--) {
37+
let id = layerZorder[i];
38+
if (id == layerId) {
39+
found = true;
40+
break;
41+
}
42+
if (map.getLayer(id)) {
43+
beforeId = id;
44+
}
45+
}
46+
// When adding a new layer somewhere, force the programmer to decide where it
47+
// should be z-ordered.
48+
if (!found) {
49+
throw new Error(`Layer ID ${layerId} not defined in layerZorder`);
50+
}
51+
// If beforeId isn't set, we'll add the layer on top of everything else.
52+
return beforeId;
53+
}
54+
55+
// All layer IDs used with layerId must be defined here, with later entries
56+
// drawn on top.
57+
//
58+
// This list covers all pages. We should maybe split it.
59+
const layerZorder = [
60+
// MapTiler basemap
61+
"Background",
62+
63+
"neighbourhood-boundaries",
64+
65+
// MapTiler basemap
66+
// TODO Need to play with what looks best, but this is good enough
67+
"Residential",
68+
69+
"debug-borders",
70+
"debug-crosses",
71+
"debug-filters",
72+
73+
"cells",
74+
"interior-roads",
75+
76+
"compare-route",
77+
78+
"shortcuts",
79+
"shortcuts-focus",
80+
81+
// MapTiler basemap
82+
"Building",
83+
84+
"route-points",
85+
"route-lines",
86+
"route-polygons",
87+
88+
// MapTiler basemap
89+
"Road labels",
90+
91+
"modal-filters",
92+
93+
"boundary",
94+
95+
"freehand-line",
96+
97+
"edit-polygon-fill",
98+
"edit-polygon-lines",
99+
"edit-polygon-vertices",
100+
];

web/src/edit/FreehandLine.svelte

+2
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import type { Map, MapMouseEvent } from "maplibre-gl";
44
import { createEventDispatcher, onDestroy } from "svelte";
55
import { GeoJSON, LineLayer } from "svelte-maplibre";
6+
import { layerId } from "../common";
67
78
export let map: Map;
89
let line: Feature<LineString> | null = null;
@@ -53,6 +54,7 @@
5354
{#if line}
5455
<GeoJSON data={line}>
5556
<LineLayer
57+
{...layerId("freehand-line")}
5658
paint={{
5759
"line-width": 5,
5860
"line-color": "red",

0 commit comments

Comments
 (0)