import leaflet from "https://esm.sh/leaflet@1.9.4"; const london = [51.505, -0.09]; const centerOfTheWorld = london; function findBaryCenter(points) { let lat = 0; let lon = 0; for (const point of points) { lat += point[0]; lon += point[1]; } return [lat / points.length, lon / points.length] } function elementSpecifyMapCenter(elm) { return !!elm.getAttribute('data-initial-lon') && elm.getAttribute('data-initial-lat'); } function getMapCenterFromElement(elm) { const lon = parseFloat(elm.getAttribute('data-initial-lon')) const lat = parseFloat(elm.getAttribute('data-initial-lat')) return [lat, lon]; } function elementSpecifyMapZoom(elm) { return !!elm.getAttribute('data-initial-zoom'); } function getMapZoomFromElement(elm) { return parseFloat(elm.getAttribute('data-initial-zoom')) } function getCenter(data, elm) { if(elementSpecifyMapCenter(elm)){ return getMapCenterFromElement(elm) } if (!data) { return centerOfTheWorld; } // good enough estimation return findBaryCenter(data.map(road => findBaryCenter(road.points))); } function addRoad(road, map) { leaflet.polyline(road.points).addTo(map); } function addRoads(roads, map) { for (const road of roads) { addRoad(road, map); } } function getActiveCity() { const elm = document.getElementById("leaflet-map"); return elm.getAttribute('data-city'); } function getActiveDate() { const elm = document.getElementById("leaflet-map"); return elm.getAttribute('data-date') ?? ""; } function getUrl(city, date) { const params = {city: city} if (date.trim() !== "") { params.date = date; } return `/api/roads?${new URLSearchParams(params).toString()}` } function recenterURLPointsToMaps(url, center, zoom) { url.searchParams.set('lat', center.lat); url.searchParams.set('lon', center.lng); url.searchParams.set('zoom', zoom); return url; } function recenterLinkThatPointsToMaps(elm, center, zoom) { const href = elm.getAttribute("href"); try { const url = new URL(href, window.document.location.origin) const newUrl = recenterURLPointsToMaps(url, center, zoom); elm.setAttribute("href", newUrl.toString()); } catch (e) { console.error(`Could not recenter ${elm} with href ${href}.`) } } function recenterLinksThatPointsToMaps(center, zoom) { const elms = document.getElementsByClassName("map-link"); for (const elm of elms) { recenterLinkThatPointsToMaps(elm, center, zoom); } } function onMapChange(e) { const center = e.target.getCenter(); const zoom = e.target.getZoom(); recenterLinksThatPointsToMaps(center, zoom); } function hookEvents(map){ const events = ['zoomend', 'moveend', 'load']; events.forEach((event) => map.on(event, onMapChange)); } function getZoom(elm){ return elementSpecifyMapCenter(elm) ? getMapZoomFromElement(elm): 13; } async function renderLeafletMap(city, date) { const resp = await fetch(getUrl(city, date)); const roads = await resp.json(); const elm = document.getElementById("leaflet-map") const map = leaflet.map(elm); hookEvents(map) map.setView(getCenter(roads, elm), getZoom(elm)); leaflet .tileLayer("https://tile.openstreetmap.org/{z}/{x}/{y}.png", {maxZoom: 19}) .addTo(map); addRoads(roads, map); } const activeCity = getActiveCity(); const activeDate = getActiveDate(); await Promise.all([renderLeafletMap(activeCity, activeDate)])