import React, { useEffect, useRef } from 'react'; import maplibregl from 'maplibre-gl'; import 'maplibre-gl/dist/maplibre-gl.css'; import mlcontour from 'maplibre-contour'; import { attachIconLoader } from '../utils/mapIcons'; const demSource = new mlcontour.DemSource({ url: 'https://s3.amazonaws.com/elevation-tiles-prod/terrarium/{z}/{x}/{y}.png', encoding: 'terrarium', maxzoom: 14, worker: true, }); demSource.setupMaplibre(maplibregl); interface MapComponentProps { onMapLoad: (map: maplibregl.Map) => void; onMapClick?: (lat: number, lng: number) => void; show3D?: boolean; showPOIs?: boolean; showTerrain?: boolean; showContours?: boolean; showAdminBoundaries?: boolean; } const MapComponent: React.FC = ({ onMapLoad, onMapClick, show3D = false, showPOIs = true, showTerrain = true, showContours = false, showAdminBoundaries = true }) => { const mapContainer = useRef(null); const map = useRef(null); // Sync toggles with map layers useEffect(() => { if (!map.current || !map.current.isStyleLoaded()) return; // Toggle 3D Buildings ['building-3d', 'building-3d-osm'].forEach(layerId => { if (map.current!.getLayer(layerId)) { map.current!.setLayoutProperty(layerId, 'visibility', show3D ? 'visible' : 'none'); } }); if (map.current.getLayer('overture-building-footprint')) { map.current.setLayoutProperty('overture-building-footprint', 'visibility', show3D ? 'none' : 'visible'); } map.current.easeTo({ pitch: show3D ? 55 : 0, duration: 600 }); // Toggle POI Layers const poiLayers = ['poi-icons', 'place-labels', 'overture-building-names', 'places-jordan-labels']; poiLayers.forEach(layerId => { if (map.current!.getLayer(layerId)) { map.current!.setLayoutProperty(layerId, 'visibility', showPOIs ? 'visible' : 'none'); } }); // Toggle Hillshading / Terrain if (map.current.getLayer('hillshading')) { map.current.setLayoutProperty('hillshading', 'visibility', showTerrain ? 'visible' : 'none'); } // Toggle Contours const contourLayers = ['contour-lines-minor', 'contour-lines-major', 'contour-labels']; contourLayers.forEach(layerId => { if (map.current!.getLayer(layerId)) { map.current!.setLayoutProperty(layerId, 'visibility', showContours ? 'visible' : 'none'); } }); // Toggle Admin Boundaries const adminLayers = [ 'admin-boundary-national', 'admin-boundary-governorate-poly', 'admin-boundary-governorate', 'admin-boundary-district-poly', 'admin-boundary-district' ]; adminLayers.forEach(layerId => { if (map.current!.getLayer(layerId)) { map.current!.setLayoutProperty(layerId, 'visibility', showAdminBoundaries ? 'visible' : 'none'); } }); }, [show3D, showPOIs, showTerrain, showContours, showAdminBoundaries]); useEffect(() => { if (map.current) return; if (!mapContainer.current) return; // Load RTL Text Plugin for correct Arabic rendering if (maplibregl.getRTLTextPluginStatus() === 'unavailable') { maplibregl.setRTLTextPlugin( '/rtl-plugin.js', true ); } try { const initialMap = new maplibregl.Map({ container: mapContainer.current, style: '/style.json', center: [35.9106, 31.9539], zoom: 12, attributionControl: false }); map.current = initialMap; attachIconLoader(initialMap); // Request User Location if ('geolocation' in navigator) { navigator.geolocation.getCurrentPosition( (position) => { if (initialMap) { initialMap.flyTo({ center: [position.coords.longitude, position.coords.latitude], zoom: 14, essential: true }); } }, (error) => console.warn('Geolocation denied or failed', error), { timeout: 5000 } ); } initialMap.on('load', () => { console.log("MapComponent: Map Loaded Successfully"); const contourUrl = demSource.contourProtocolUrl({ thresholds: { 10: [100, 500], 11: [50, 250], 12: [25, 100], 13: [20, 100], 14: [10, 50], 15: [10, 50], 16: [10, 50], 17: [10, 50], 18: [10, 50], }, elevationKey: 'ele', levelKey: 'level', contourLayer: 'contours', }); if (!initialMap.getSource('contour-source')) { initialMap.addSource('contour-source', { type: 'vector', tiles: [contourUrl], maxzoom: 18, }); initialMap.addLayer({ id: 'contour-lines-minor', type: 'line', source: 'contour-source', 'source-layer': 'contours', minzoom: 10, layout: { visibility: showContours ? 'visible' : 'none', }, filter: ['==', ['get', 'level'], 0], paint: { 'line-color': '#a86324', 'line-width': 1.1, 'line-opacity': 0.9, }, }); initialMap.addLayer({ id: 'contour-lines-major', type: 'line', source: 'contour-source', 'source-layer': 'contours', minzoom: 9, layout: { visibility: showContours ? 'visible' : 'none', }, filter: ['>', ['get', 'level'], 0], paint: { 'line-color': '#703800', 'line-width': 2.0, 'line-opacity': 1.0, }, }); initialMap.addLayer({ id: 'contour-labels', type: 'symbol', source: 'contour-source', 'source-layer': 'contours', minzoom: 12, layout: { visibility: showContours ? 'visible' : 'none', 'symbol-placement': 'line', 'text-field': ['concat', ['to-string', ['get', 'ele']], ' m'], 'text-size': 10, 'text-font': ['Noto Sans Bold', 'Open Sans Bold'], }, paint: { 'text-color': '#5c2d00', 'text-halo-color': 'rgba(255, 255, 255, 0.95)', 'text-halo-width': 2, }, }); } onMapLoad(map.current!); }); map.current.on('click', (e) => { if (onMapClick) { onMapClick(e.lngLat.lat, e.lngLat.lng); } }); map.current.on('error', (e) => { console.error("MapComponent: Map Error:", e); }); } catch (err) { console.error("MapComponent: Fatal Initialization Error:", err); } return () => { if (map.current) { map.current.remove(); map.current = null; } }; }, []); return (
{/* Intaleq Premium Branding Watermark */}
Intaleq Powered by Intaleq
); }; export default MapComponent;