/* RealMap — geographically accurate Greece map via Leaflet + OpenStreetMap tiles. Draws the actual motorway corridor (multi-waypoint polyline) for the active route and fits the view to it. Requires Leaflet CSS+JS loaded globally (window.L). */ /* Real motorway corridors — [lat, lng] waypoints tracing PATHE (A1) / Olympia (A8) / Egnatia (A2). */ const ROUTE_PATHS = { 'ath-thes': [ // Athens → Thessaloniki via A1 (PATHE) [37.9838, 23.7275], [38.3170, 23.3190], [38.6100, 22.9000], [38.9000, 22.4350], [39.0700, 22.4200], [39.3620, 22.3450], [39.6390, 22.4194], [40.0000, 22.3000], [40.2710, 22.5040], [40.4500, 22.7300], [40.6401, 22.9444], ], 'ath-pat': [ // Athens → Patras via A8 (Olympia Odos) [37.9838, 23.7275], [37.9700, 23.3000], [37.9380, 22.9320], [38.0200, 22.4000], [38.1900, 21.9000], [38.2466, 21.7346], ], 'ath-vol': [ // Athens → Volos via A1 [37.9838, 23.7275], [38.3170, 23.3190], [38.6100, 22.9000], [38.9000, 22.4350], [39.1500, 22.7000], [39.3621, 22.9420], ], 'thes-ioa': [ // Thessaloniki → Ioannina via A2 (Egnatia) [40.6401, 22.9444], [40.5240, 22.2030], [40.3000, 21.7000], [40.0830, 21.4280], [39.7900, 21.1000], [39.6650, 20.8530], ], }; const CITY_COORDS = { ATH: { ll: [37.9838, 23.7275], el: 'Αθήνα', en: 'Athens' }, THE: { ll: [40.6401, 22.9444], el: 'Θεσσαλονίκη', en: 'Thessaloniki' }, PAT: { ll: [38.2466, 21.7346], el: 'Πάτρα', en: 'Patras' }, VOL: { ll: [39.3621, 22.9420], el: 'Βόλος', en: 'Volos' }, IOA: { ll: [39.6650, 20.8530], el: 'Ιωάννινα', en: 'Ioannina' }, }; function RealMap({ routeId, from, to, km }) { const elRef = React.useRef(null); const mapRef = React.useRef(null); const layerRef = React.useRef(null); const [ready, setReady] = React.useState(typeof window.L !== 'undefined'); const [, force] = React.useState(0); // Wait for Leaflet to load React.useEffect(() => { if (window.L) { setReady(true); return; } const iv = setInterval(() => { if (window.L) { setReady(true); clearInterval(iv); } }, 120); return () => clearInterval(iv); }, []); React.useEffect(() => { const onLang = () => force(n => n + 1); window.addEventListener('langchange', onLang); return () => window.removeEventListener('langchange', onLang); }, []); // Init map once Leaflet is ready React.useEffect(() => { if (!ready || !elRef.current || mapRef.current) return; const L = window.L; const map = L.map(elRef.current, { zoomControl: false, scrollWheelZoom: false, attributionControl: false, dragging: true, doubleClickZoom: false, }); L.tileLayer('https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}{r}.png', { maxZoom: 19, subdomains: 'abcd', }).addTo(map); L.control.attribution({ prefix: false, position: 'bottomright' }) .addAttribution('© OpenStreetMap · CARTO').addTo(map); mapRef.current = map; force(n => n + 1); }, [ready]); // Draw / update active route React.useEffect(() => { const map = mapRef.current; if (!map || !window.L) return; const L = window.L; if (layerRef.current) { map.removeLayer(layerRef.current); layerRef.current = null; } const path = ROUTE_PATHS[routeId]; if (!path) return; const group = L.layerGroup(); // all other corridors — faint, to communicate "network" Object.entries(ROUTE_PATHS).forEach(([id, pts]) => { if (id === routeId) return; L.polyline(pts, { color: '#8B95A5', weight: 2, opacity: 0.35, lineJoin: 'round', dashArray: '2 6' }).addTo(group); }); // glow underlay + main line (active) L.polyline(path, { color: '#289FFC', weight: 9, opacity: 0.18, lineJoin: 'round' }).addTo(group); L.polyline(path, { color: '#289FFC', weight: 4, opacity: 0.95, lineJoin: 'round' }).addTo(group); const lang = window.__LANG__ || 'el'; const endpoints = [ { ll: path[0], city: from }, { ll: path[path.length - 1], city: to }, ]; endpoints.forEach(({ ll, city }) => { const c = CITY_COORDS[city]; const name = c ? (lang === 'el' ? c.el : c.en) : ''; const icon = L.divIcon({ className: '', iconSize: [16, 16], iconAnchor: [8, 8], html: `