diff --git a/martin.yaml b/martin.yaml index 2dba2ae..01f015d 100644 --- a/martin.yaml +++ b/martin.yaml @@ -84,7 +84,7 @@ postgres: geometry_column: geom srid: 3844 bounds: [20.2, 43.5, 30.0, 48.3] - minzoom: 14 + minzoom: 17 maxzoom: 18 properties: object_id: text @@ -139,7 +139,7 @@ postgres: geometry_column: geom srid: 3844 bounds: [20.2, 43.5, 30.0, 48.3] - minzoom: 15 + minzoom: 17 maxzoom: 18 properties: object_id: text diff --git a/prisma/postgis-setup.sql b/prisma/postgis-setup.sql index c78ae38..3bc4421 100644 --- a/prisma/postgis-setup.sql +++ b/prisma/postgis-setup.sql @@ -59,10 +59,6 @@ WHERE geometry IS NOT NULL AND geom IS NULL; CREATE INDEX IF NOT EXISTS gis_feature_geom_idx ON "GisFeature" USING GIST (geom); --- Compound index: layerId + spatial — Martin queries filter by layer via views -CREATE INDEX IF NOT EXISTS gis_feature_layer_geom_idx - ON "GisFeature" ("layerId", geom) WHERE geom IS NOT NULL; - -- B-tree index on layerId for view filtering (LIKE 'TERENURI%', 'CLADIRI%') CREATE INDEX IF NOT EXISTS gis_feature_layer_id_idx ON "GisFeature" ("layerId"); diff --git a/scripts/rebuild-overview-tiles.sh b/scripts/rebuild-overview-tiles.sh index cbdc665..3183d36 100644 --- a/scripts/rebuild-overview-tiles.sh +++ b/scripts/rebuild-overview-tiles.sh @@ -83,8 +83,8 @@ tippecanoe \ --named-layer=gis_terenuri:terenuri_overview.fgb \ --named-layer=gis_cladiri:cladiri_overview.fgb \ --minimum-zoom=0 \ - --maximum-zoom=14 \ - --base-zoom=14 \ + --maximum-zoom=16 \ + --base-zoom=16 \ --drop-densest-as-needed \ --detect-shared-borders \ --simplification=10 \ diff --git a/src/modules/geoportal/components/map-viewer.tsx b/src/modules/geoportal/components/map-viewer.tsx index 730a946..09f8efc 100644 --- a/src/modules/geoportal/components/map-viewer.tsx +++ b/src/modules/geoportal/components/map-viewer.tsx @@ -328,7 +328,7 @@ export const MapViewer = forwardRef( LAYER_IDS.uatsZ12Fill, LAYER_IDS.uatsZ12Line, LAYER_IDS.uatsZ12Label, ], administrativ: [LAYER_IDS.adminLineOuter, LAYER_IDS.adminLineInner], - terenuri: [LAYER_IDS.terenuriFill, LAYER_IDS.terenuriLine, LAYER_IDS.terenuriLabel, "l-terenuri-pm-fill", "l-terenuri-pm-line"], + terenuri: [LAYER_IDS.terenuriFill, LAYER_IDS.terenuriLine, LAYER_IDS.terenuriLabel, "l-terenuri-pm-fill", "l-terenuri-pm-line", "l-terenuri-pm-label"], cladiri: [LAYER_IDS.cladiriFill, LAYER_IDS.cladiriLine, LAYER_IDS.cladiriLabel, "l-cladiri-pm-fill", "l-cladiri-pm-line"], }; for (const [group, layerIds] of Object.entries(mapping)) { @@ -467,22 +467,29 @@ export const MapViewer = forwardRef( // === Terenuri (parcels) === if (usePmtiles) { - // PMTiles overview at z13 (fast, pre-generated), Martin for z14+ (live detail) - map.addLayer({ id: "l-terenuri-pm-fill", type: "fill", source: "overview-pmtiles", "source-layer": SOURCES.terenuri, minzoom: 13, maxzoom: 14, + // PMTiles serves z13-z16 (pre-generated, instant), Martin only z17-z18 (close detail) + map.addLayer({ id: "l-terenuri-pm-fill", type: "fill", source: "overview-pmtiles", "source-layer": SOURCES.terenuri, minzoom: 13, maxzoom: 17, paint: { "fill-color": "#22c55e", "fill-opacity": 0.15 } }); - map.addLayer({ id: "l-terenuri-pm-line", type: "line", source: "overview-pmtiles", "source-layer": SOURCES.terenuri, minzoom: 13, maxzoom: 14, + map.addLayer({ id: "l-terenuri-pm-line", type: "line", source: "overview-pmtiles", "source-layer": SOURCES.terenuri, minzoom: 13, maxzoom: 17, paint: { "line-color": "#15803d", "line-width": 0.8 } }); - // Martin source starts at z14 (saves generating heavy z10-z13 tiles) - map.addSource(SOURCES.terenuri, { type: "vector", tiles: [`${m}/${SOURCES.terenuri}/{z}/{x}/{y}`], minzoom: 14, maxzoom: 18 }); + // PMTiles labels z16 (cadastral_ref available in PMTiles) + map.addLayer({ id: "l-terenuri-pm-label", type: "symbol", source: "overview-pmtiles", "source-layer": SOURCES.terenuri, minzoom: 16, maxzoom: 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": "#166534", "text-halo-color": "#fff", "text-halo-width": 1 } }); + map.addSource(SOURCES.terenuri, { type: "vector", tiles: [`${m}/${SOURCES.terenuri}/{z}/{x}/{y}`], minzoom: 17, maxzoom: 18 }); } else { map.addSource(SOURCES.terenuri, { type: "vector", tiles: [`${m}/${SOURCES.terenuri}/{z}/{x}/{y}`], minzoom: 10, maxzoom: 18 }); } - map.addLayer({ id: LAYER_IDS.terenuriFill, type: "fill", source: SOURCES.terenuri, "source-layer": SOURCES.terenuri, minzoom: 14, + map.addLayer({ id: LAYER_IDS.terenuriFill, type: "fill", source: SOURCES.terenuri, "source-layer": SOURCES.terenuri, minzoom: usePmtiles ? 17 : 13, paint: { "fill-color": "#22c55e", "fill-opacity": 0.15 } }); - map.addLayer({ id: LAYER_IDS.terenuriLine, type: "line", source: SOURCES.terenuri, "source-layer": SOURCES.terenuri, minzoom: 14, + map.addLayer({ id: LAYER_IDS.terenuriLine, type: "line", source: SOURCES.terenuri, "source-layer": SOURCES.terenuri, minzoom: usePmtiles ? 17 : 13, paint: { "line-color": "#15803d", "line-width": 0.8 } }); - // Parcel cadastral number label (always from Martin — needs live data) - map.addLayer({ id: LAYER_IDS.terenuriLabel, type: "symbol", source: SOURCES.terenuri, "source-layer": SOURCES.terenuri, minzoom: 16, + map.addLayer({ id: LAYER_IDS.terenuriLabel, type: "symbol", source: SOURCES.terenuri, "source-layer": SOURCES.terenuri, minzoom: usePmtiles ? 17 : 16, layout: { "text-field": ["coalesce", ["get", "cadastral_ref"], ""], "text-font": ["Noto Sans Regular"], @@ -493,18 +500,18 @@ export const MapViewer = forwardRef( // === Cladiri (buildings) === if (usePmtiles) { - // PMTiles overview at z14 (pre-generated), Martin for z15+ (live detail) - map.addLayer({ id: "l-cladiri-pm-fill", type: "fill", source: "overview-pmtiles", "source-layer": SOURCES.cladiri, minzoom: 14, maxzoom: 15, + // PMTiles serves z14-z16, Martin only z17-z18 + map.addLayer({ id: "l-cladiri-pm-fill", type: "fill", source: "overview-pmtiles", "source-layer": SOURCES.cladiri, minzoom: 14, maxzoom: 17, paint: { "fill-color": "#3b82f6", "fill-opacity": 0.5 } }); - map.addLayer({ id: "l-cladiri-pm-line", type: "line", source: "overview-pmtiles", "source-layer": SOURCES.cladiri, minzoom: 14, maxzoom: 15, + map.addLayer({ id: "l-cladiri-pm-line", type: "line", source: "overview-pmtiles", "source-layer": SOURCES.cladiri, minzoom: 14, maxzoom: 17, paint: { "line-color": "#1e3a5f", "line-width": 0.6 } }); - map.addSource(SOURCES.cladiri, { type: "vector", tiles: [`${m}/${SOURCES.cladiri}/{z}/{x}/{y}`], minzoom: 15, maxzoom: 18 }); + map.addSource(SOURCES.cladiri, { type: "vector", tiles: [`${m}/${SOURCES.cladiri}/{z}/{x}/{y}`], minzoom: 17, maxzoom: 18 }); } else { map.addSource(SOURCES.cladiri, { type: "vector", tiles: [`${m}/${SOURCES.cladiri}/{z}/{x}/{y}`], minzoom: 12, maxzoom: 18 }); } - map.addLayer({ id: LAYER_IDS.cladiriFill, type: "fill", source: SOURCES.cladiri, "source-layer": SOURCES.cladiri, minzoom: usePmtiles ? 15 : 14, + map.addLayer({ id: LAYER_IDS.cladiriFill, type: "fill", source: SOURCES.cladiri, "source-layer": SOURCES.cladiri, minzoom: usePmtiles ? 17 : 14, paint: { "fill-color": "#3b82f6", "fill-opacity": 0.5 } }); - map.addLayer({ id: LAYER_IDS.cladiriLine, type: "line", source: SOURCES.cladiri, "source-layer": SOURCES.cladiri, minzoom: usePmtiles ? 15 : 14, + map.addLayer({ id: LAYER_IDS.cladiriLine, type: "line", source: SOURCES.cladiri, "source-layer": SOURCES.cladiri, minzoom: usePmtiles ? 17 : 14, paint: { "line-color": "#1e3a5f", "line-width": 0.6 } }); // Building body labels — extract suffix after last dash (e.g. "291479-C1" → "C1") map.addLayer({ id: LAYER_IDS.cladiriLabel, type: "symbol", source: SOURCES.cladiri, "source-layer": SOURCES.cladiri, minzoom: 16,