137 lines
3.3 KiB
JavaScript
137 lines
3.3 KiB
JavaScript
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)])
|
|
|