From 74550be6798a03a5f253193e9e3a8cf665101ad7 Mon Sep 17 00:00:00 2001 From: Chop <28534054+RChopin@users.noreply.github.com> Date: Tue, 24 Jun 2025 22:46:53 +0200 Subject: [PATCH] Refactor LeafletMap to implement custom WMSLayer component and remove WMSTileLayer usage; update mapLayers configuration for improved readability and maintainability; delete obsolete page_backup.js file. --- src/app/projects/map/page.js | 244 +++++++-------- src/app/projects/map/page_backup.js | 0 src/components/ui/LeafletMap.js | 48 ++- src/components/ui/mapLayers.js | 443 +++++++++++++++------------- 4 files changed, 395 insertions(+), 340 deletions(-) delete mode 100644 src/app/projects/map/page_backup.js diff --git a/src/app/projects/map/page.js b/src/app/projects/map/page.js index 79a23a2..bbd0916 100644 --- a/src/app/projects/map/page.js +++ b/src/app/projects/map/page.js @@ -29,7 +29,8 @@ export default function ProjectsMapPage() { in_progress_design: true, in_progress_construction: true, fulfilled: true, - }); const [activeBaseLayer, setActiveBaseLayer] = useState("Polish Geoportal Orthophoto"); + }); + const [activeBaseLayer, setActiveBaseLayer] = useState("OpenStreetMap"); const [activeOverlays, setActiveOverlays] = useState([]); const [showLayerPanel, setShowLayerPanel] = useState(true); const [currentTool, setCurrentTool] = useState("move"); // Current map tool @@ -103,10 +104,10 @@ export default function ProjectsMapPage() { // Update URL with current map state (debounced to avoid too many updates) const updateURL = (center, zoom) => { const params = new URLSearchParams(); - params.set('lat', center[0].toFixed(6)); - params.set('lng', center[1].toFixed(6)); - params.set('zoom', zoom.toString()); - + params.set("lat", center[0].toFixed(6)); + params.set("lng", center[1].toFixed(6)); + params.set("zoom", zoom.toString()); + // Use replace to avoid cluttering browser history router.replace(`/projects/map?${params.toString()}`, { scroll: false }); }; @@ -115,7 +116,7 @@ export default function ProjectsMapPage() { const handleMapViewChange = (center, zoom) => { setMapCenter(center); setMapZoom(zoom); - + // Debounce URL updates to avoid too many history entries clearTimeout(window.mapUpdateTimeout); window.mapUpdateTimeout = setTimeout(() => { @@ -126,9 +127,9 @@ export default function ProjectsMapPage() { // Hide navigation and ensure full-screen layout useEffect(() => { // Check for URL parameters for coordinates and zoom - const lat = searchParams.get('lat'); - const lng = searchParams.get('lng'); - const zoom = searchParams.get('zoom'); + const lat = searchParams.get("lat"); + const lng = searchParams.get("lng"); + const zoom = searchParams.get("zoom"); if (lat && lng) { const latitude = parseFloat(lat); @@ -154,7 +155,7 @@ export default function ProjectsMapPage() { // Prevent scrolling on body document.body.style.overflow = "hidden"; document.documentElement.style.overflow = "hidden"; - + // Cleanup when leaving page return () => { if (nav) { @@ -162,7 +163,7 @@ export default function ProjectsMapPage() { } document.body.style.overflow = ""; document.documentElement.style.overflow = ""; - + // Clear any pending URL updates if (window.mapUpdateTimeout) { clearTimeout(window.mapUpdateTimeout); @@ -177,9 +178,9 @@ export default function ProjectsMapPage() { setProjects(data); // Only calculate center based on projects if no URL parameters are provided - const lat = searchParams.get('lat'); - const lng = searchParams.get('lng'); - + const lat = searchParams.get("lat"); + const lng = searchParams.get("lng"); + if (!lat || !lng) { // Calculate center based on projects with coordinates const projectsWithCoords = data.filter((p) => p.coordinates); @@ -348,9 +349,7 @@ export default function ProjectsMapPage() { ); } return ( -
+
{/* Floating Header - Left Side */}
{/* Title Box */} @@ -362,187 +361,183 @@ export default function ProjectsMapPage() {
{markers.length} of {projects.length} projects with coordinates
-
+
{" "} + - {/* Zoom Controls - Below Title */}
- -
-
{/* Tool Panel - Below Zoom Controls */} -
{/* Move Tool */} -
+
{" "} + {/* Tool Panel - Below Zoom Controls */} +
+ {" "} +
+ {" "} + {/* Move Tool */} + - {/* Select Tool */} - - {/* Measure Tool */} - - {/* Draw Tool */} - - {/* Pin/Marker Tool */} - - {/* Area Tool */} -
- {/* Layer Control Panel - Right Side */}
{/* Action Buttons */} @@ -635,10 +630,15 @@ export default function ProjectsMapPage() { /> -
{/* Layer Control Content */} -
+
{" "} + {/* Layer Control Content */} +
{/* Base Layers Section */}
@@ -697,7 +697,8 @@ export default function ProjectsMapPage() { /> Overlay Layers -
+ {" "} +
{mapLayers.overlays.map((layer, index) => (
-
+
{" "} +
- {/* Status Filter Panel - Bottom Left */}
@@ -728,7 +729,6 @@ export default function ProjectsMapPage() { Filters: - {/* Toggle All Button */} - {/* Individual Status Filters */} {Object.entries(statusConfig).map(([status, config]) => { const isActive = statusFilters[status]; @@ -795,10 +794,13 @@ export default function ProjectsMapPage() { ); - })}
+ })}{" "} +
- {/* Status Panel - Bottom Left */} - {markers.length > 0 && (
+
{" "} + {/* Status Panel - Bottom Left */} + {markers.length > 0 && ( +
Filters: @@ -873,7 +875,8 @@ export default function ProjectsMapPage() { })}
- )} {/* Full Screen Map */} + )}{" "} + {/* Full Screen Map */} {markers.length === 0 ? (
@@ -919,6 +922,7 @@ export default function ProjectsMapPage() { onViewChange={handleMapViewChange} />
- )}
+ )}{" "} + ); } diff --git a/src/app/projects/map/page_backup.js b/src/app/projects/map/page_backup.js deleted file mode 100644 index e69de29..0000000 diff --git a/src/components/ui/LeafletMap.js b/src/components/ui/LeafletMap.js index c66fa46..54946c9 100644 --- a/src/components/ui/LeafletMap.js +++ b/src/components/ui/LeafletMap.js @@ -3,7 +3,6 @@ import { MapContainer, TileLayer, - WMSTileLayer, Marker, Popup, LayersControl, @@ -15,6 +14,45 @@ import "leaflet/dist/leaflet.css"; import { useEffect } from "react"; import { mapLayers } from "./mapLayers"; +// Custom WMS Layer component using Leaflet's native WMS support +function WMSLayer({ url, params, opacity = 1, attribution }) { + const map = useMap(); + + useEffect(() => { + if (!map || !url) return; + + // Clean up params for L.tileLayer.wms + const wmsOptions = { + layers: params.layers, + styles: params.styles || '', + format: params.format || 'image/png', + transparent: params.transparent !== false, + version: params.version || '1.1.1', + attribution: attribution, + opacity: opacity + }; + + // Add CRS/SRS parameter based on version + const version = parseFloat(params.version || '1.1.1'); + if (version >= 1.3) { + wmsOptions.crs = L.CRS.EPSG3857; + } else { + wmsOptions.srs = 'EPSG:3857'; + } + + // Create WMS layer using Leaflet's native support + const wmsLayer = L.tileLayer.wms(url, wmsOptions); + + wmsLayer.addTo(map); + + return () => { + map.removeLayer(wmsLayer); + }; + }, [map, url, params, opacity, attribution]); + + return null; +} + // Fix for default markers in react-leaflet const fixLeafletIcons = () => { if (typeof window !== "undefined") { @@ -148,12 +186,10 @@ export default function EnhancedLeafletMap({ name={layer.name} > {layer.type === "wms" ? ( - ) : ( @@ -188,13 +224,11 @@ export default function EnhancedLeafletMap({ .map((layer, index) => { if (layer.type === "wms") { return ( - ); diff --git a/src/components/ui/mapLayers.js b/src/components/ui/mapLayers.js index dd436b0..cc79539 100644 --- a/src/components/ui/mapLayers.js +++ b/src/components/ui/mapLayers.js @@ -1,227 +1,244 @@ // Map layer configurations -import { generateLayerConfig } from './wmtsCapabilities'; +import { generateLayerConfig } from "./wmtsCapabilities"; // Generate layer configurations from WMTS capabilities -const polishOrthophoto = generateLayerConfig('orthophoto'); +const polishOrthophoto = generateLayerConfig("orthophoto"); export const mapLayers = { - base: [ - { - name: "OpenStreetMap", - checked: true, - attribution: '© OpenStreetMap contributors', - url: "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", - maxZoom: 20 - }, - { - name: "🇵🇱 Polish Orthophoto (Standard)", - attribution: '© Geoportal', - url: "https://mapy.geoportal.gov.pl/wss/service/PZGIK/ORTO/WMTS/StandardResolution?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=ORTO&STYLE=default&TILEMATRIXSET=EPSG:3857&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&FORMAT=image/jpeg", - maxZoom: 20, - checked: false - }, - { - name: "🇵🇱 Polish Orthophoto (High Resolution)", - attribution: '© Geoportal', - url: "https://mapy.geoportal.gov.pl/wss/service/PZGIK/ORTO/WMTS/HighResolution?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=ORTO&STYLE=default&TILEMATRIXSET=EPSG:3857&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&FORMAT=image/jpeg", - maxZoom: 20, - checked: false - }, - { - name: "🌍 Google Satellite", - attribution: '© Google', - url: "http://mt1.google.com/vt/lyrs=s&hl=pl&x={x}&y={y}&z={z}", - maxZoom: 20, - checked: false - }, { - name: "🌍 Google Hybrid", - attribution: '© Google', - url: "http://mt1.google.com/vt/lyrs=y&hl=pl&x={x}&y={y}&z={z}", - maxZoom: 20, - checked: false - }, - { - name: "Satellite (Esri)", - attribution: '© Esri — Source: Esri, i-cubed, USDA, USGS, AEX, GeoEye, Getmapping, Aerogrid, IGN, IGP, UPR-EGP, and the GIS User Community', - url: "https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}", - maxZoom: 20 - }, - { - name: "Topographic", - attribution: '© OpenStreetMap contributors, © CARTO', - url: "https://{s}.basemaps.cartocdn.com/rastertiles/voyager/{z}/{x}/{y}{r}.png", - maxZoom: 20 - } - ].filter(Boolean), // Remove any null entries - overlays: [ - { - name: "🌍 Google Roads", - type: "tile", - attribution: '© Google', - url: "http://mt1.google.com/vt/lyrs=h&hl=pl&x={x}&y={y}&z={z}", - maxZoom: 20, - opacity: 1.0, - checked: false - }, { - name: "📋 Polish Cadastral Data (Działki) - Server 1", - type: "wms", - attribution: '© GUGiK - Krajowa Integracja Ewidencji Gruntów', - url: "https://integracja01.gugik.gov.pl/cgi-bin/KrajowaIntegracjaEwidencjiGruntow", - params: { - service: 'WMS', - request: 'GetMap', - layers: 'powiaty,powiaty_obreby,zsin,obreby,dzialki,geoportal,numery_dzialek,budynki', - styles: ',,,,,,,', - format: 'image/png', - transparent: true, - version: '1.3.0', - srs: 'EPSG:3857', - exceptions: 'xml', - tiled: true - }, - opacity: 0.8, - checked: false - }, - { - name: "📋 Polish Cadastral Data (Działki) - Server 2", - type: "wms", - attribution: '© GUGiK - Krajowa Integracja Ewidencji Gruntów', - url: "https://integracja.gugik.gov.pl/cgi-bin/KrajowaIntegracjaEwidencjiGruntow", - params: { - service: 'WMS', - request: 'GetMap', - layers: 'dzialki,obreby,numery_dzialek,budynki,kontury,uzytki', - styles: ',,,,,,', - format: 'image/png', - transparent: true, - version: '1.3.0', - srs: 'EPSG:3857', - tiled: true - }, - opacity: 0.8, - checked: false - }, - { - name: "🏗️ Polish Spatial Planning", - type: "wms", - attribution: '© Geoportal', - url: "https://mapy.geoportal.gov.pl/wss/ext/KrajowaIntegracjaMiejscowychPlanowZagospodarowaniaPrzestrzennego", - params: { - service: 'WMS', - request: 'GetMap', - layers: 'raster,wektor-str,wektor-lzb,wektor-pow,wektor-lin,wektor-pkt,granice', - styles: ',,,,,,', - format: 'image/png', - transparent: true, - version: '1.3.0', - srs: 'EPSG:3857', - tiled: true - }, - opacity: 0.7, - checked: false - }, - { - name: "🛣️ LP-Portal Roads", - type: "wms", - attribution: '© LP-Portal', - url: "https://geoserver.lp-portal.pl/geoserver/pzdnowysacz/wms", - params: { - service: 'WMS', - request: 'GetMap', - layers: '00_6_mapainteraktywna_drogi', - styles: '', - format: 'image/png8', - transparent: true, - version: '1.3.0', - srs: 'EPSG:3857', - tiled: true - }, - opacity: 0.9, - checked: false - }, - { - name: "🏷️ LP-Portal Street Names", - type: "wms", - attribution: '© LP-Portal', - url: "https://geoserver.lp-portal.pl/geoserver/pzdnowysacz/wms", - params: { - service: 'WMS', - request: 'GetMap', - layers: '00_5_mapainteraktywna_opisy_drog,00_3_mapainteraktywna_nazwy_ulic', - styles: '', - format: 'image/png8', - transparent: true, - version: '1.1.1', - srs: 'EPSG:3857', - tiled: true - }, - opacity: 1.0, - checked: false - }, - { - name: "📐 LP-Portal Parcels", - type: "wms", - attribution: '© LP-Portal', - url: "https://geoserver.lp-portal.pl/geoserver/pzdnowysacz/wms", - params: { - service: 'WMS', - request: 'GetMap', - layers: 'dzialki', - styles: '', - format: 'image/png', - transparent: true, - version: '1.1.1', - srs: 'EPSG:3857', - tiled: true - }, - opacity: 0.6, - checked: false - }, - { - name: "📍 LP-Portal Survey Markers", - type: "wms", - attribution: '© LP-Portal', - url: "https://geoserver.lp-portal.pl/geoserver/pzdnowysacz/wms", - params: { - service: 'WMS', - request: 'GetMap', - layers: '00_2_view_geop_odcinek_pikietaz_glob_multi', - styles: '', - format: 'image/png8', - transparent: true, - version: '1.1.1', - crs: 'EPSG:3857', - tiled: true - }, - opacity: 0.8, - checked: false - } - ] + base: [ + { + name: "OpenStreetMap", + checked: true, + attribution: + '© OpenStreetMap contributors', + url: "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", + maxZoom: 20, + }, + { + name: "🇵🇱 Polish Orthophoto (Standard)", + attribution: + '© Geoportal', + url: "https://mapy.geoportal.gov.pl/wss/service/PZGIK/ORTO/WMTS/StandardResolution?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=ORTO&STYLE=default&TILEMATRIXSET=EPSG:3857&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&FORMAT=image/jpeg", + maxZoom: 20, + checked: false, + }, + { + name: "🇵🇱 Polish Orthophoto (High Resolution)", + attribution: + '© Geoportal', + url: "https://mapy.geoportal.gov.pl/wss/service/PZGIK/ORTO/WMTS/HighResolution?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=ORTO&STYLE=default&TILEMATRIXSET=EPSG:3857&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&FORMAT=image/jpeg", + maxZoom: 20, + checked: false, + }, + { + name: "🌍 Google Satellite", + attribution: "© Google", + url: "http://mt1.google.com/vt/lyrs=s&hl=pl&x={x}&y={y}&z={z}", + maxZoom: 20, + checked: false, + }, + { + name: "🌍 Google Hybrid", + attribution: "© Google", + url: "http://mt1.google.com/vt/lyrs=y&hl=pl&x={x}&y={y}&z={z}", + maxZoom: 20, + checked: false, + }, + { + name: "Satellite (Esri)", + attribution: + '© Esri — Source: Esri, i-cubed, USDA, USGS, AEX, GeoEye, Getmapping, Aerogrid, IGN, IGP, UPR-EGP, and the GIS User Community', + url: "https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}", + maxZoom: 20, + }, + { + name: "Topographic", + attribution: + '© OpenStreetMap contributors, © CARTO', + url: "https://{s}.basemaps.cartocdn.com/rastertiles/voyager/{z}/{x}/{y}{r}.png", + maxZoom: 20, + }, + ].filter(Boolean), // Remove any null entries + overlays: [ + { + name: "🌍 Google Roads", + type: "tile", + attribution: "© Google", + url: "http://mt1.google.com/vt/lyrs=h&hl=pl&x={x}&y={y}&z={z}", + maxZoom: 20, + opacity: 1.0, + checked: false, + }, + { + name: "📋 Polish Cadastral Data (Działki) - Server 1", + type: "wms", + attribution: + '© GUGiK - Krajowa Integracja Ewidencji Gruntów', + url: "https://integracja01.gugik.gov.pl/cgi-bin/KrajowaIntegracjaEwidencjiGruntow", + params: { + service: "WMS", + request: "GetMap", + layers: + "powiaty,powiaty_obreby,zsin,obreby,dzialki,geoportal,numery_dzialek,budynki", + styles: ",,,,,,,", + format: "image/png", + transparent: true, + version: "1.3.0", + srs: "EPSG:3857", + exceptions: "xml", + tiled: true, + }, + opacity: 0.8, + checked: false, + }, + { + name: "📋 Polish Cadastral Data (Działki) - Server 2", + type: "wms", + attribution: + '© GUGiK - Krajowa Integracja Ewidencji Gruntów', + url: "https://integracja.gugik.gov.pl/cgi-bin/KrajowaIntegracjaEwidencjiGruntow", + params: { + service: "WMS", + request: "GetMap", + layers: "dzialki,obreby,numery_dzialek,budynki,kontury,uzytki", + styles: ",,,,,,", + format: "image/png", + transparent: true, + version: "1.3.0", + srs: "EPSG:3857", + tiled: true, + }, + opacity: 0.8, + checked: false, + }, + { + name: "🏗️ Polish Spatial Planning", + type: "wms", + attribution: + '© Geoportal', + url: "https://mapy.geoportal.gov.pl/wss/ext/KrajowaIntegracjaMiejscowychPlanowZagospodarowaniaPrzestrzennego", + params: { + service: "WMS", + request: "GetMap", + layers: + "raster,wektor-str,wektor-lzb,wektor-pow,wektor-lin,wektor-pkt,granice", + styles: ",,,,,,", + format: "image/png", + transparent: true, + version: "1.3.0", + srs: "EPSG:3857", + tiled: true, + }, + opacity: 0.7, + checked: false, + }, + { + name: "🛣️ LP-Portal Roads", + type: "wms", + attribution: '© LP-Portal', + url: "https://geoserver.lp-portal.pl/geoserver/pzdnowysacz/wms", + params: { + service: "WMS", + request: "GetMap", + layers: "00_6_mapainteraktywna_drogi", + styles: "", + format: "image/png8", + transparent: true, + version: "1.3.0", + srs: "EPSG:3857", + tiled: true, + }, + opacity: 0.9, + checked: false, + }, + { + name: "🏷️ LP-Portal Street Names", + type: "wms", + attribution: '© LP-Portal', + url: "https://geoserver.lp-portal.pl/geoserver/pzdnowysacz/wms", + params: { + service: "WMS", + request: "GetMap", + layers: + "00_5_mapainteraktywna_opisy_drog,00_3_mapainteraktywna_nazwy_ulic", + styles: "", + format: "image/png8", + transparent: true, + version: "1.1.1", + srs: "EPSG:3857", + tiled: true, + }, + opacity: 1.0, + checked: false, + }, + { + name: "📐 LP-Portal Parcels", + type: "wms", + attribution: '© LP-Portal', + url: "https://geoserver.lp-portal.pl/geoserver/pzdnowysacz/wms", + params: { + service: "WMS", + request: "GetMap", + layers: "dzialki", + styles: "", + format: "image/png", + transparent: true, + version: "1.1.1", + srs: "EPSG:3857", + tiled: true, + }, + opacity: 0.6, + checked: false, + }, + { + name: "📍 LP-Portal Survey Markers", + type: "wms", + attribution: '© LP-Portal', + url: "https://geoserver.lp-portal.pl/geoserver/pzdnowysacz/wms", + params: { + service: "WMS", + request: "GetMap", + layers: "00_2_view_geop_odcinek_pikietaz_glob_multi", + styles: "", + format: "image/png8", + transparent: true, + version: "1.1.1", + srs: "EPSG:3857", + tiled: true, + }, + opacity: 0.8, + checked: false, + }, + ], }; // WMTS services configuration with GetCapabilities URLs export const wmtsServices = { - polishOrthophoto: { - capabilitiesUrl: "https://mapy.geoportal.gov.pl/wss/service/PZGIK/ORTO/WMTS/StandardResolution?Service=WMTS&Request=GetCapabilities", - layer: "ORTO", - style: "default", - tilematrixSet: "EPSG:2180", - format: "image/jpeg" - } + polishOrthophoto: { + capabilitiesUrl: + "https://mapy.geoportal.gov.pl/wss/service/PZGIK/ORTO/WMTS/StandardResolution?Service=WMTS&Request=GetCapabilities", + layer: "ORTO", + style: "default", + tilematrixSet: "EPSG:2180", + format: "image/jpeg", + }, }; // Helper function to check WMTS capabilities export async function checkWMTSCapabilities(serviceKey) { - const service = wmtsServices[serviceKey]; - if (!service) return null; - - try { - const response = await fetch(service.capabilitiesUrl); - const xml = await response.text(); - console.log(`WMTS Capabilities for ${serviceKey}:`, xml); - return xml; - } catch (error) { - console.error(`Failed to fetch WMTS capabilities for ${serviceKey}:`, error); - return null; - } + const service = wmtsServices[serviceKey]; + if (!service) return null; + + try { + const response = await fetch(service.capabilitiesUrl); + const xml = await response.text(); + console.log(`WMTS Capabilities for ${serviceKey}:`, xml); + return xml; + } catch (error) { + console.error( + `Failed to fetch WMTS capabilities for ${serviceKey}:`, + error + ); + return null; + } }