const DATA_ROOT = '/data/';
let MAP = null;
let LAYER = null;
let PLACES = {};
const DEFAULT_CENTER = [51.2, 9];
const DEFAULT_ZOOM = 6;
// ---------------------
// Load data
// ---------------------
async function loadJson(url) {
const res = await fetch(url);
return await res.json();
}
async function loadData() {
PLACES = {};
for (const place of await loadJson(DATA_ROOT + 'data.json')) {
if (since(place.until) > 0) {
continue; // not vacant anymore
}
PLACES[place.id] = place;
}
updateCounter();
}
// ---------------------
// Helper
// ---------------------
function since(date) {
if (!date) {
return 0;
}
const [y, m] = (date + '-01').split('-');
const diff = Date.now() - new Date(y, m - 1);
return Math.floor(diff / (1000 * 60 * 60 * 24));
}
function makeIcon(className) {
return L.divIcon({
className: className,
html: '',
iconSize: [34, 55],
iconAnchor: [17, 55],
popupAnchor: [0, -20],
tooltipAnchor: [0, -20],
offset: [10, 20],
});
}
function makeMarker(place) {
const vacantYears = Math.floor(since(place.since) / 365);
return L.marker(L.latLng(place.loc), {
pid: place.id,
title: place.addr,
icon: makeIcon('pin fc' + Math.min(vacantYears, 7)),
}).on('click', clickPin);
}
function clickPin(pin) {
setPlace(pin.target.options.pid);
}
function closePopup(e) {
setPlace(null)
}
// ---------------------
// UI updates
// ---------------------
function setPlace(placeId) {
const hide = !placeId;
const place = hide ? {} : PLACES[placeId];
const div = document.getElementById('popup');
div.hidden = hide;
div.querySelector('img').src = place.img || '';
div.querySelector('h3').innerText = place.addr || '';
div.querySelector('#_since').innerText = place.until
? 'von ' + place.since + ' bis ' + place.until
: place.since ? 'seit ' + place.since : '???';
div.querySelector('#_desc').innerText = place.desc || '';
location.hash = hide ? '' : placeId;
document.title = document.title.split(' "', 1)[0] + (hide ? '' : ' "' + place.addr + '"');
}
function updateCounter() {
const total = Object.keys(PLACES).length;
const counter = document.getElementById('city-counter');
counter.innerText = total;
counter.hidden = total === 0;
}
// ---------------------
// Initialize
// ---------------------
function initMap() {
const osm = L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: [
' < 1 Jahr',
' 1–3 J.',
' 3–5 J.',
' 5–7 J.',
' 7+ Jahre',
'© OpenStreetMap',
'Impressum',
].join(' | '),
});
MAP = L.map('map', {
layers: [osm], center: DEFAULT_CENTER, zoom: DEFAULT_ZOOM,
zoomSnap: 0.5,
});
LAYER = L.layerGroup([]).addTo(MAP);
L.control.locate({ showPopup: false }).addTo(MAP);
}
function initPins() {
var bounds = L.latLngBounds();
for (const place of Object.values(PLACES)) {
const marker = makeMarker(place).addTo(LAYER);
bounds.extend(marker.getLatLng());
}
// adjust bounds & zoom
if (bounds.isValid()) {
MAP.fitBounds(bounds, { padding: [50, 50] });
}
}
async function start() {
initMap();
await loadData();
initPins();
// LAYER.clearLayers();
// MAP.setView(city.loc, city.zoom);
const place_id = location.hash.substring(1);
if (place_id) {
setPlace(place_id);
}
document.getElementById('loading').hidden = true;
}