feat(geoportal-v2): map styling parity with eterra.live
Marius didn't like the previous map palette + missing labels.
Re-paint to match eterra.live's V2 map:
UATs:
Was: #9ca3af / #6b7280 (two-tone gray)
Now: #7c3aed violet, width ramps 0.3 → 0.6 by zoom band
Plus new v2-uats-z8-label symbol layer that prints the UAT name
at z9–12 (Noto Sans 10px, violet text + white halo).
Parcele (terenuri):
Was: #0ea5e9 sky-blue line, transparent 0.001 fill (hit-only)
Now: #22c55e green fill at 0.15 opacity (so the click area is
visible at the same time it acts as hit-target) + #15803d
darker green outline at 0.8 / 0.9 opacity. Cadastral-ref label
layer renders at z17+ (small enough zoom that the polygon can
carry a 10px label without overlapping neighbours).
Cladiri (buildings):
Was: #fb923c orange / #ea580c dark orange
Now: #3b82f6 blue fill at 0.5 / #1e3a5f navy line — same blue
eterra.live uses, distinct from the green parcel underlay and
from the violet UATs.
Cladiri „fără acte" (build_legal == 0):
NEW. Two amber overlay layers, filtered on the tile's
build_legal property:
v2-cladiri-unreg-fill — #f59e0b at 0.6 opacity
v2-cladiri-unreg-line — #b45309 at width 1
Renders on top of the default cladiri layers so illegal builds
visibly pop. If a PMTiles tile doesn't carry build_legal yet
the layer is empty — no regression on legal buildings.
Building suffix label (C1, C2, C3…):
NEW. v2-cladiri-label symbol at z16+. Mirrors eterra.live's
expression: extract the slice after the last "-" of
cadastral_ref ("354686-C1" → "C1"). Noto Sans 9px, navy text +
white halo so it reads on both light and dark basemaps.
Click handler unchanged — v2-cladiri-fill covers ALL buildings
(no filter), so legal vs unreg both route through the same query.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -116,7 +116,10 @@ export const MapViewer = forwardRef<MapViewerHandle, Props>(function MapViewer(
|
|||||||
url: `pmtiles://${PMTILES_URL}`,
|
url: `pmtiles://${PMTILES_URL}`,
|
||||||
});
|
});
|
||||||
|
|
||||||
// UAT boundaries — visible at every zoom, more prominent on low/mid zoom
|
// ── UAT boundaries ──
|
||||||
|
// Palette mirrors eterra.live's map: violet #7c3aed at increasing
|
||||||
|
// line-width per zoom band so the boundary stays visible from
|
||||||
|
// country view to street view without overpowering parcels.
|
||||||
map.addLayer({
|
map.addLayer({
|
||||||
id: "v2-uats-z5",
|
id: "v2-uats-z5",
|
||||||
type: "line",
|
type: "line",
|
||||||
@@ -125,9 +128,9 @@ export const MapViewer = forwardRef<MapViewerHandle, Props>(function MapViewer(
|
|||||||
minzoom: 0,
|
minzoom: 0,
|
||||||
maxzoom: 8,
|
maxzoom: 8,
|
||||||
paint: {
|
paint: {
|
||||||
"line-color": "#9ca3af",
|
"line-color": "#7c3aed",
|
||||||
"line-width": 0.8,
|
"line-width": 0.3,
|
||||||
"line-opacity": 0.6,
|
"line-opacity": 0.7,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
map.addLayer({
|
map.addLayer({
|
||||||
@@ -138,13 +141,86 @@ export const MapViewer = forwardRef<MapViewerHandle, Props>(function MapViewer(
|
|||||||
minzoom: 8,
|
minzoom: 8,
|
||||||
maxzoom: 13,
|
maxzoom: 13,
|
||||||
paint: {
|
paint: {
|
||||||
"line-color": "#6b7280",
|
"line-color": "#7c3aed",
|
||||||
"line-width": 1.2,
|
"line-width": 0.6,
|
||||||
"line-opacity": 0.7,
|
"line-opacity": 0.85,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
// UAT name label at z9–12 (when the boundary is the main feature)
|
||||||
|
map.addLayer({
|
||||||
|
id: "v2-uats-z8-label",
|
||||||
|
type: "symbol",
|
||||||
|
source: PM_SRC,
|
||||||
|
"source-layer": "gis_uats_z8",
|
||||||
|
minzoom: 9,
|
||||||
|
maxzoom: 13,
|
||||||
|
layout: {
|
||||||
|
"text-field": ["coalesce", ["get", "name"], ""],
|
||||||
|
"text-font": ["Noto Sans Regular"],
|
||||||
|
"text-size": 10,
|
||||||
|
"text-anchor": "center",
|
||||||
|
"text-allow-overlap": false,
|
||||||
|
},
|
||||||
|
paint: {
|
||||||
|
"text-color": "#5b21b6",
|
||||||
|
"text-halo-color": "#ffffff",
|
||||||
|
"text-halo-width": 1.5,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
// Buildings — fill + outline
|
// ── Parcele (terenuri) ──
|
||||||
|
// Green fill (#22c55e/0.15) + dark green stroke (#15803d/0.8).
|
||||||
|
// Fill provides the click-hit area without needing a separate
|
||||||
|
// transparent layer; the low opacity keeps overlapping buildings
|
||||||
|
// legible underneath.
|
||||||
|
map.addLayer({
|
||||||
|
id: "v2-terenuri-hit",
|
||||||
|
type: "fill",
|
||||||
|
source: PM_SRC,
|
||||||
|
"source-layer": "gis_terenuri",
|
||||||
|
minzoom: 13,
|
||||||
|
paint: {
|
||||||
|
"fill-color": "#22c55e",
|
||||||
|
"fill-opacity": 0.15,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
map.addLayer({
|
||||||
|
id: "v2-terenuri-line",
|
||||||
|
type: "line",
|
||||||
|
source: PM_SRC,
|
||||||
|
"source-layer": "gis_terenuri",
|
||||||
|
minzoom: 13,
|
||||||
|
paint: {
|
||||||
|
"line-color": "#15803d",
|
||||||
|
"line-width": 0.8,
|
||||||
|
"line-opacity": 0.9,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
// Parcel cadastral ref label — z17+ where the polygon is big
|
||||||
|
// enough that the label doesn't clutter.
|
||||||
|
map.addLayer({
|
||||||
|
id: "v2-terenuri-label",
|
||||||
|
type: "symbol",
|
||||||
|
source: PM_SRC,
|
||||||
|
"source-layer": "gis_terenuri",
|
||||||
|
minzoom: 17,
|
||||||
|
layout: {
|
||||||
|
"text-field": ["coalesce", ["get", "cadastral_ref"], ""],
|
||||||
|
"text-font": ["Noto Sans Regular"],
|
||||||
|
"text-size": 10,
|
||||||
|
"text-anchor": "center",
|
||||||
|
"text-allow-overlap": false,
|
||||||
|
"text-max-width": 8,
|
||||||
|
},
|
||||||
|
paint: {
|
||||||
|
"text-color": "#14532d",
|
||||||
|
"text-halo-color": "#ffffff",
|
||||||
|
"text-halo-width": 1.5,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// ── Cladiri (buildings) ──
|
||||||
|
// Default blue (#3b82f6/0.5 fill + #1e3a5f/0.6 stroke) at z13+.
|
||||||
map.addLayer({
|
map.addLayer({
|
||||||
id: "v2-cladiri-fill",
|
id: "v2-cladiri-fill",
|
||||||
type: "fill",
|
type: "fill",
|
||||||
@@ -152,8 +228,8 @@ export const MapViewer = forwardRef<MapViewerHandle, Props>(function MapViewer(
|
|||||||
"source-layer": "gis_cladiri",
|
"source-layer": "gis_cladiri",
|
||||||
minzoom: 13,
|
minzoom: 13,
|
||||||
paint: {
|
paint: {
|
||||||
"fill-color": "#fb923c",
|
"fill-color": "#3b82f6",
|
||||||
"fill-opacity": 0.25,
|
"fill-opacity": 0.5,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
map.addLayer({
|
map.addLayer({
|
||||||
@@ -163,34 +239,84 @@ export const MapViewer = forwardRef<MapViewerHandle, Props>(function MapViewer(
|
|||||||
"source-layer": "gis_cladiri",
|
"source-layer": "gis_cladiri",
|
||||||
minzoom: 13,
|
minzoom: 13,
|
||||||
paint: {
|
paint: {
|
||||||
"line-color": "#ea580c",
|
"line-color": "#1e3a5f",
|
||||||
"line-width": 0.6,
|
"line-width": 0.6,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
// Parcels (terenuri) — line outline only
|
// ── Cladiri „fără acte" (build_legal == 0) ──
|
||||||
|
// Amber overlay (#f59e0b/0.6) + darker stroke so illegal /
|
||||||
|
// un-registered buildings pop visibly against the default blue.
|
||||||
|
// The layer renders only when the tile property `build_legal` is
|
||||||
|
// present; PMTiles overview built without that property simply
|
||||||
|
// shows nothing here (no overlap on legal buildings either).
|
||||||
map.addLayer({
|
map.addLayer({
|
||||||
id: "v2-terenuri-line",
|
id: "v2-cladiri-unreg-fill",
|
||||||
type: "line",
|
|
||||||
source: PM_SRC,
|
|
||||||
"source-layer": "gis_terenuri",
|
|
||||||
minzoom: 13,
|
|
||||||
paint: {
|
|
||||||
"line-color": "#0ea5e9",
|
|
||||||
"line-width": 0.8,
|
|
||||||
"line-opacity": 0.85,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
// Invisible fill for click hit-testing
|
|
||||||
map.addLayer({
|
|
||||||
id: "v2-terenuri-hit",
|
|
||||||
type: "fill",
|
type: "fill",
|
||||||
source: PM_SRC,
|
source: PM_SRC,
|
||||||
"source-layer": "gis_terenuri",
|
"source-layer": "gis_cladiri",
|
||||||
minzoom: 13,
|
minzoom: 13,
|
||||||
|
filter: ["==", ["get", "build_legal"], 0],
|
||||||
paint: {
|
paint: {
|
||||||
"fill-color": "#0ea5e9",
|
"fill-color": "#f59e0b",
|
||||||
"fill-opacity": 0.001,
|
"fill-opacity": 0.6,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
map.addLayer({
|
||||||
|
id: "v2-cladiri-unreg-line",
|
||||||
|
type: "line",
|
||||||
|
source: PM_SRC,
|
||||||
|
"source-layer": "gis_cladiri",
|
||||||
|
minzoom: 13,
|
||||||
|
filter: ["==", ["get", "build_legal"], 0],
|
||||||
|
paint: {
|
||||||
|
"line-color": "#b45309",
|
||||||
|
"line-width": 1,
|
||||||
|
"line-opacity": 0.9,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// Building suffix label — "354686-C1" → "C1". Same logic eterra.live
|
||||||
|
// uses: slice after the last dash. z16+ so we don't clutter the
|
||||||
|
// overview when zoomed out.
|
||||||
|
map.addLayer({
|
||||||
|
id: "v2-cladiri-label",
|
||||||
|
type: "symbol",
|
||||||
|
source: PM_SRC,
|
||||||
|
"source-layer": "gis_cladiri",
|
||||||
|
minzoom: 16,
|
||||||
|
layout: {
|
||||||
|
"text-field": [
|
||||||
|
"case",
|
||||||
|
["has", "cadastral_ref"],
|
||||||
|
[
|
||||||
|
"let",
|
||||||
|
"ref",
|
||||||
|
["get", "cadastral_ref"],
|
||||||
|
[
|
||||||
|
"let",
|
||||||
|
"dashIdx",
|
||||||
|
["index-of", "-", ["var", "ref"]],
|
||||||
|
[
|
||||||
|
"case",
|
||||||
|
[">=", ["var", "dashIdx"], 0],
|
||||||
|
["slice", ["var", "ref"], ["+", ["var", "dashIdx"], 1]],
|
||||||
|
["var", "ref"],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
"",
|
||||||
|
],
|
||||||
|
"text-font": ["Noto Sans Regular"],
|
||||||
|
"text-size": 9,
|
||||||
|
"text-anchor": "center",
|
||||||
|
"text-allow-overlap": false,
|
||||||
|
"text-max-width": 6,
|
||||||
|
},
|
||||||
|
paint: {
|
||||||
|
"text-color": "#1e3a5f",
|
||||||
|
"text-halo-color": "#ffffff",
|
||||||
|
"text-halo-width": 1.2,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}, []);
|
}, []);
|
||||||
|
|||||||
Reference in New Issue
Block a user