perf(geoportal): zoom-dependent UAT simplification + Martin config + tile cache

PostGIS:
- gis_uats view: ST_SimplifyPreserveTopology(geom, 50) + only name/county/siruta
- gis_uats_simple view: ST_SimplifyPreserveTopology(geom, 500) for z0-z9

Martin config (martin.yaml):
- Explicit source definitions (auto_publish: false)
- gis_uats_simple (z0-9): only name+siruta, 500m simplified geometry
- gis_uats (z0-14): name+siruta+county, 50m simplified
- gis_terenuri (z10-18): object_id+siruta+cadastral_ref+area_value+layer_id
- gis_cladiri (z12-18): same properties
- 24h cache headers on all tiles

MapViewer:
- Dual UAT sources: simplified (z0-9) + detailed (z9+) with seamless handoff
- Zoom-interpolated paint: thin lines at z5, thicker at z12
- UAT labels only z9+, fill opacity z-interpolated (0.03→0.08)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
AI Assistant
2026-03-23 20:24:38 +02:00
parent 6c55264fa3
commit 76c19449f3
4 changed files with 145 additions and 11 deletions
@@ -34,6 +34,7 @@ const DEFAULT_ZOOM = 7;
/** Source/layer IDs used on the map */
const SOURCES = {
uatsSimple: "gis_uats_simple",
uats: "gis_uats",
terenuri: "gis_terenuri",
cladiri: "gis_cladiri",
@@ -41,6 +42,8 @@ const SOURCES = {
/** Map layer IDs (prefixed to avoid collisions) */
const LAYER_IDS = {
uatsSimpleFill: "layer-uats-simple-fill",
uatsSimpleLine: "layer-uats-simple-line",
uatsFill: "layer-uats-fill",
uatsLine: "layer-uats-line",
uatsLabel: "layer-uats-label",
@@ -232,7 +235,7 @@ export const MapViewer = forwardRef<MapViewerHandle, MapViewerProps>(
if (!map || !map.isStyleLoaded()) return;
const mapping: Record<string, string[]> = {
uats: [LAYER_IDS.uatsFill, LAYER_IDS.uatsLine, LAYER_IDS.uatsLabel],
uats: [LAYER_IDS.uatsSimpleFill, LAYER_IDS.uatsSimpleLine, LAYER_IDS.uatsFill, LAYER_IDS.uatsLine, LAYER_IDS.uatsLabel],
terenuri: [LAYER_IDS.terenuriFill, LAYER_IDS.terenuriLine],
cladiri: [LAYER_IDS.cladiriFill, LAYER_IDS.cladiriLine],
};
@@ -278,11 +281,51 @@ export const MapViewer = forwardRef<MapViewerHandle, MapViewerProps>(
/* ---- Add Martin sources + layers on load ---- */
map.on("load", () => {
// --- UAT boundaries ---
// --- UAT boundaries (simplified, low zoom z0-z9) ---
map.addSource(SOURCES.uatsSimple, {
type: "vector",
tiles: [`${resolvedMartinUrl}/${SOURCES.uatsSimple}/{z}/{x}/{y}`],
minzoom: 0,
maxzoom: 9,
});
map.addLayer({
id: LAYER_IDS.uatsSimpleFill,
type: "fill",
source: SOURCES.uatsSimple,
"source-layer": SOURCES.uatsSimple,
maxzoom: 9,
paint: {
"fill-color": "#8b5cf6",
"fill-opacity": [
"interpolate", ["linear"], ["zoom"],
5, 0.03,
8, 0.05,
],
},
});
map.addLayer({
id: LAYER_IDS.uatsSimpleLine,
type: "line",
source: SOURCES.uatsSimple,
"source-layer": SOURCES.uatsSimple,
maxzoom: 9,
paint: {
"line-color": "#7c3aed",
"line-width": [
"interpolate", ["linear"], ["zoom"],
5, 0.5,
8, 1,
],
},
});
// --- UAT boundaries (detailed, high zoom z9+) ---
map.addSource(SOURCES.uats, {
type: "vector",
tiles: [`${resolvedMartinUrl}/${SOURCES.uats}/{z}/{x}/{y}`],
minzoom: 0,
minzoom: 9,
maxzoom: 16,
});
@@ -291,9 +334,14 @@ export const MapViewer = forwardRef<MapViewerHandle, MapViewerProps>(
type: "fill",
source: SOURCES.uats,
"source-layer": SOURCES.uats,
minzoom: 8,
paint: {
"fill-color": "#8b5cf6",
"fill-opacity": 0.05,
"fill-opacity": [
"interpolate", ["linear"], ["zoom"],
8, 0.03,
12, 0.08,
],
},
});
@@ -302,9 +350,15 @@ export const MapViewer = forwardRef<MapViewerHandle, MapViewerProps>(
type: "line",
source: SOURCES.uats,
"source-layer": SOURCES.uats,
minzoom: 9,
paint: {
"line-color": "#7c3aed",
"line-width": 1.5,
"line-width": [
"interpolate", ["linear"], ["zoom"],
5, 0.5,
8, 1,
12, 2,
],
},
});
@@ -313,9 +367,14 @@ export const MapViewer = forwardRef<MapViewerHandle, MapViewerProps>(
type: "symbol",
source: SOURCES.uats,
"source-layer": SOURCES.uats,
minzoom: 9,
layout: {
"text-field": ["coalesce", ["get", "name"], ["get", "uat_name"], ""],
"text-size": 12,
"text-size": [
"interpolate", ["linear"], ["zoom"],
9, 10,
14, 14,
],
"text-anchor": "center",
"text-allow-overlap": false,
},
@@ -431,6 +490,7 @@ export const MapViewer = forwardRef<MapViewerHandle, MapViewerProps>(
LAYER_IDS.terenuriFill,
LAYER_IDS.cladiriFill,
LAYER_IDS.uatsFill,
LAYER_IDS.uatsSimpleFill,
];
map.on("click", (e) => {