From c35a05c8149048eb91c859166f07bc7770415c70 Mon Sep 17 00:00:00 2001 From: Yorick de Wid Date: Sun, 26 Jul 2026 21:18:48 +0000 Subject: [PATCH] feat(layers): add HotSpot layer to the Risico mapset Closes #919. A HotSpot is a building whose highest risk class across the two groundwater-driven models is D or E: MAX(drystand_risk, dewatering_depth_risk) >= 'd' The classes order a < b < c < d < e, so "the maximum" is the worse of the two; A/B/C are excluded. It answers "where do we look first" at a glance, it is not a new model. No data work: maplayer.building_tiles already carries both columns and maplayer.buildings(z,x,y) emits both at every zoom (z12-13 included), so the layer is purely a filter + paint expression over the existing 'buildings' source. address_count != 0 matches the other risk layers. Colored by the worst of the two classes, reusing the exact D and E swatches of the drystand-risk / dewatering-depth-risk legends so HotSpot reads as a summary of those two rather than a separate scale. Verified against @maplibre/maplibre-gl-style-spec, and by compiling the filter and color expressions and evaluating all 108 combinations of (drystand, dewatering) x {null,a..e} x address_count {0,1,4} against the spec table. The absent-attribute cases matter: 3.6M buildings have no drystand_risk, and MVT drops null attributes entirely. The matching legend row lives in FunderMapsWorker sql/migrate/add_hotspot_layer.sql and must be applied AFTER this ships - the other order leaves a layer id in layerSet that has no config here. Co-Authored-By: Claude Opus 5 (1M context) --- src/config/layers/hotspot.json | 55 ++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 src/config/layers/hotspot.json diff --git a/src/config/layers/hotspot.json b/src/config/layers/hotspot.json new file mode 100644 index 0000000..5d02b27 --- /dev/null +++ b/src/config/layers/hotspot.json @@ -0,0 +1,55 @@ +{ + "id": "hotspot", + "type": "fill-extrusion", + "source": "buildings", + "source-layer": "buildings", + "filter": [ + "all", + [ + "any", + [ + "match", + ["get", "drystand_risk"], + ["d", "e"], + true, + false + ], + [ + "match", + ["get", "dewatering_depth_risk"], + ["d", "e"], + true, + false + ] + ], + ["!=", ["get", "address_count"], 0] + ], + "layout": {"visibility": "none"}, + "paint": { + "fill-extrusion-height": [ + "interpolate", + ["linear"], + ["zoom"], + 0, + ["get", "height"], + 22, + ["get", "height"] + ], + "fill-extrusion-color": [ + "case", + [ + "any", + ["==", ["get", "drystand_risk"], "e"], + ["==", ["get", "dewatering_depth_risk"], "e"] + ], + "#ff5533", + [ + "any", + ["==", ["get", "drystand_risk"], "d"], + ["==", ["get", "dewatering_depth_risk"], "d"] + ], + "#ffac33", + "hsla(0, 0%, 0%, 0)" + ] + } +}