Skip to content

Commit

Permalink
Centralize layer z-ordering.
Browse files Browse the repository at this point in the history
  • Loading branch information
dabreegster committed May 16, 2023
1 parent 300126c commit 41be5db
Show file tree
Hide file tree
Showing 5 changed files with 98 additions and 72 deletions.
35 changes: 12 additions & 23 deletions src/lib/draw/HoverLayer.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -29,36 +29,25 @@
data: emptyGeojson(),
});
// Draw polygon outlines on top of interventions-polygons
overwriteLayer($map, {
id: "hover-polygons",
source,
filter: isPolygon,
// Outline around the polygons
...drawLine(colors.hovering, 0.5 * lineWidth, 1.0),
});
// Draw underneath lines, so the thick line looks like an outline
overwriteLayer(
$map,
{
id: "hover-lines",
source,
filter: isLine,
...drawLine(colors.hovering, 1.5 * lineWidth, 1.0),
},
"interventions-lines"
);
// Draw underneath points, so it looks like an outline
overwriteLayer(
$map,
{
id: "hover-points",
source,
filter: isPoint,
...drawCircle(colors.hovering, 1.5 * circleRadius, 1.0),
},
"interventions-points"
);
overwriteLayer($map, {
id: "hover-lines",
source,
filter: isLine,
...drawLine(colors.hovering, 1.5 * lineWidth, 1.0),
});
overwriteLayer($map, {
id: "hover-points",
source,
filter: isPoint,
...drawCircle(colors.hovering, 1.5 * circleRadius, 1.0),
});
// When a form is open, ignore regular map and sidebar interactions
$: {
Expand Down
47 changes: 16 additions & 31 deletions src/lib/draw/InterventionLayer.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,6 @@
export let schema: Schema;
// TODO Document here the z-ordering between all the layers defined
// everywhere. Or maybe even pass a list to overwriteLayer and have it figure
// things out!
let source = "interventions";
overwriteSource($map, source, {
Expand Down Expand Up @@ -99,19 +95,12 @@
// TODO Outline?
});
// Draw underneath the route tool
// TODO Also want this to be beneath route-points, but we can only specify one
// TODO Also draw beneath draw-split-route
overwriteLayer(
$map,
{
id: "interventions-lines",
source,
filter: ["all", isLine, hideWhileEditing],
...drawLine(colorByInterventionType, lineWidth),
},
"route-lines"
);
overwriteLayer($map, {
id: "interventions-lines",
source,
filter: ["all", isLine, hideWhileEditing],
...drawLine(colorByInterventionType, lineWidth),
});
// Draw endpoints to emphasize where two LineStrings meet
overwriteLayer($map, {
id: "interventions-lines-endpoints",
Expand All @@ -126,18 +115,14 @@
},
});
overwriteLayer(
$map,
{
id: "interventions-polygons",
source,
filter: ["all", isPolygon, hideWhileEditing],
...drawPolygon(
schema == "planning" ? colorByReferenceType : colorByInterventionType,
0.5
),
// TODO Outline too?
},
"hover-polygons"
);
overwriteLayer($map, {
id: "interventions-polygons",
source,
filter: ["all", isPolygon, hideWhileEditing],
...drawPolygon(
schema == "planning" ? colorByReferenceType : colorByInterventionType,
0.5
),
// TODO Outline too?
});
</script>
1 change: 0 additions & 1 deletion src/lib/draw/polygon/polygon_tool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,6 @@ export class PolygonTool {
data: emptyGeojson(),
});

// Order matters here!
overwriteLayer(map, {
id: "edit-polygon-fill",
source,
Expand Down
1 change: 0 additions & 1 deletion src/lib/draw/route/SplitRouteMode.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@
data: emptyGeojson(),
});
// TODO Scissors icon?
// TODO Z-ordering wrong?
overwriteLayer($map, {
id: "draw-split-route",
source,
Expand Down
86 changes: 70 additions & 16 deletions src/maplibre_helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,6 @@ import type {
import type { GeoJSON, FeatureCollection, Feature, Geometry } from "geojson";
import turfBbox from "@turf/bbox";

const roundedLine = {
"line-cap": "round",
"line-join": "round",
};

export const isPolygon = ["==", "$type", "Polygon"];
export const isLine = ["==", "$type", "LineString"];
export const isPoint = ["==", "$type", "Point"];
Expand All @@ -23,7 +18,10 @@ export function drawLine(
) {
return {
type: "line",
layout: roundedLine,
layout: {
"line-cap": "round",
"line-join": "round",
},
paint: {
"line-color": color,
"line-width": width,
Expand Down Expand Up @@ -86,20 +84,39 @@ export function overwriteSource(
map.addSource(id, source);
}

export function overwriteLayer(
map: Map,
layer,
beforeId: string | undefined = undefined
) {
// The layer.id here MUST be present in layerZorder.
export function overwriteLayer(map: Map, layer) {
if (map.getLayer(layer.id)) {
map.removeLayer(layer.id);
}
// If we want this layer to appear below another, and the other layer doesn't
// exist yet, we don't need to do anything; it'll naturally be ordered
// beneath.
if (beforeId && !map.getLayer(beforeId)) {
beforeId = undefined;

// layerZorder lists all layers in the desired z-order. map.addLayer takes an
// optional beforeId, placing the new layer beneath this beforeId. Due to
// hot-module reloading and Svelte component initialization being
// unpredictable, we might call overwriteLayer in any order, so use beforeId
// to guarantee we wind up in the correct order.
//
// Find the last layer currently in the map that should be on top of this new
// layer.
let beforeId;
let found = false;
for (let i = layerZorder.length - 1; i >= 0; i--) {
let id = layerZorder[i];
if (id == layer.id) {
found = true;
break;
}
if (map.getLayer(id)) {
beforeId = id;
}
}
// When adding a new layer somewhere, force the programmer to decide where it
// should be z-ordered.
if (!found) {
throw new Error(`Layer ID ${layer.id} not defined in layerZorder`);
}
// If beforeId isn't set, we'll add the layer on top of everything else.

map.addLayer(layer, beforeId);
}

Expand All @@ -119,3 +136,40 @@ export function bbox(gj: GeoJSON): [number, number, number, number] {
export type FeatureWithProps<G extends Geometry> = Feature<G> & {
properties: { [name: string]: any };
};

// All layer IDs used with overwriteLayer must be defined here, with later
// entries drawn on top.
const layerZorder = [
// Polygons are bigger than lines, which're bigger than points. When geometry
// overlaps, put the smaller thing on top
"interventions-polygons",
// This is an outline, so draw on top
"hover-polygons",

// The hover effect thickens, so draw beneath
"hover-lines",
"interventions-lines",
"interventions-lines-endpoints",

"hover-points",
"interventions-points",

"edit-point-mode",

"edit-polygon-fill",
"edit-polygon-lines",
"edit-polygon-vertices",

"route-points",
"route-lines",
"route-polygons",

"draw-split-route",

// Draw most things beneath text road labels. This is the only layer in this
// list generated by the MapTiler basemap we use.
"road_label",

// Draw the inverted boundary fade on top of basemap labels
"boundary",
];

0 comments on commit 41be5db

Please sign in to comment.