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}`,
|
||||
});
|
||||
|
||||
// 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({
|
||||
id: "v2-uats-z5",
|
||||
type: "line",
|
||||
@@ -125,9 +128,9 @@ export const MapViewer = forwardRef<MapViewerHandle, Props>(function MapViewer(
|
||||
minzoom: 0,
|
||||
maxzoom: 8,
|
||||
paint: {
|
||||
"line-color": "#9ca3af",
|
||||
"line-width": 0.8,
|
||||
"line-opacity": 0.6,
|
||||
"line-color": "#7c3aed",
|
||||
"line-width": 0.3,
|
||||
"line-opacity": 0.7,
|
||||
},
|
||||
});
|
||||
map.addLayer({
|
||||
@@ -138,13 +141,86 @@ export const MapViewer = forwardRef<MapViewerHandle, Props>(function MapViewer(
|
||||
minzoom: 8,
|
||||
maxzoom: 13,
|
||||
paint: {
|
||||
"line-color": "#6b7280",
|
||||
"line-width": 1.2,
|
||||
"line-opacity": 0.7,
|
||||
"line-color": "#7c3aed",
|
||||
"line-width": 0.6,
|
||||
"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({
|
||||
id: "v2-cladiri-fill",
|
||||
type: "fill",
|
||||
@@ -152,8 +228,8 @@ export const MapViewer = forwardRef<MapViewerHandle, Props>(function MapViewer(
|
||||
"source-layer": "gis_cladiri",
|
||||
minzoom: 13,
|
||||
paint: {
|
||||
"fill-color": "#fb923c",
|
||||
"fill-opacity": 0.25,
|
||||
"fill-color": "#3b82f6",
|
||||
"fill-opacity": 0.5,
|
||||
},
|
||||
});
|
||||
map.addLayer({
|
||||
@@ -163,34 +239,84 @@ export const MapViewer = forwardRef<MapViewerHandle, Props>(function MapViewer(
|
||||
"source-layer": "gis_cladiri",
|
||||
minzoom: 13,
|
||||
paint: {
|
||||
"line-color": "#ea580c",
|
||||
"line-color": "#1e3a5f",
|
||||
"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({
|
||||
id: "v2-terenuri-line",
|
||||
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",
|
||||
id: "v2-cladiri-unreg-fill",
|
||||
type: "fill",
|
||||
source: PM_SRC,
|
||||
"source-layer": "gis_terenuri",
|
||||
"source-layer": "gis_cladiri",
|
||||
minzoom: 13,
|
||||
filter: ["==", ["get", "build_legal"], 0],
|
||||
paint: {
|
||||
"fill-color": "#0ea5e9",
|
||||
"fill-opacity": 0.001,
|
||||
"fill-color": "#f59e0b",
|
||||
"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