Manche Webserver liefern .mjs ohne JavaScript-MIME-Typ aus; der Browser verweigert dann den Modul-Import und die Karte bleibt bei der Vorschau stehen. Interne Verweise (shared, worker) mit umbenannt. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
110 lines
4.0 KiB
JavaScript
110 lines
4.0 KiB
JavaScript
/* ==========================================================================
|
|
Kirschner Gebäudeservice — Karte
|
|
MapLibre GL (lokal) mit Kacheln von OpenFreeMap. Lädt erst, wenn die Karte
|
|
in die Nähe des sichtbaren Bereichs scrollt; bis dahin (und falls WebGL
|
|
fehlt) bleibt die schematische Vorschau stehen.
|
|
========================================================================== */
|
|
const STYLE = 'https://tiles.openfreemap.org/styles/dark';
|
|
|
|
/* Dunkler Stil, auf die Nachtblau-Palette der Seite umgefärbt */
|
|
const TINT = [
|
|
['background', 'background-color', '#0A1424'],
|
|
['water', 'fill-color', '#16263F'],
|
|
['waterway', 'line-color', '#16263F'],
|
|
['landuse_residential', 'fill-color', '#0F1D33'],
|
|
['landcover_wood', 'fill-color', '#0E1B2F'],
|
|
['landuse_park', 'fill-color', '#0E1B2F'],
|
|
['building', 'fill-color', '#13233B'],
|
|
['building', 'fill-outline-color', '#1F3354'],
|
|
['highway_path', 'line-color', '#1F3354'],
|
|
['highway_minor', 'line-color', '#1B2D4A'],
|
|
['highway_major_casing', 'line-color', 'rgba(91,138,214,.28)'],
|
|
['highway_major_inner', 'line-color', '#1F3354'],
|
|
['highway_major_subtle', 'line-color', '#1F3354'],
|
|
['highway_motorway_casing', 'line-color', 'rgba(91,138,214,.4)'],
|
|
['highway_motorway_subtle', 'line-color', '#1F3354'],
|
|
['railway', 'line-color', '#1F3354'],
|
|
['highway_name_other', 'text-color', '#8C9BB3'],
|
|
['highway_name_other', 'text-halo-color', '#0A1424'],
|
|
];
|
|
|
|
const LOCALE = {
|
|
'CooperativeGesturesHandler.WindowsHelpText': 'Strg + Scrollen zum Zoomen',
|
|
'CooperativeGesturesHandler.MacHelpText': '⌘ + Scrollen zum Zoomen',
|
|
'CooperativeGesturesHandler.MobileHelpText': 'Mit zwei Fingern verschieben',
|
|
'NavigationControl.ZoomIn': 'Vergrößern',
|
|
'NavigationControl.ZoomOut': 'Verkleinern',
|
|
'AttributionControl.ToggleAttribution': 'Quellenangaben',
|
|
};
|
|
|
|
const reduce = matchMedia('(prefers-reduced-motion: reduce)').matches;
|
|
|
|
function loadCss(href) {
|
|
if (document.querySelector(`link[href="${href}"]`)) return;
|
|
const l = document.createElement('link');
|
|
l.rel = 'stylesheet';
|
|
l.href = href;
|
|
document.head.appendChild(l);
|
|
}
|
|
|
|
function hasWebGL() {
|
|
try {
|
|
const c = document.createElement('canvas');
|
|
return !!(c.getContext('webgl2') || c.getContext('webgl'));
|
|
} catch (e) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
async function mount(el) {
|
|
const lng = Number(el.dataset.lng);
|
|
const lat = Number(el.dataset.lat);
|
|
loadCss(new URL('vendor/maplibre/maplibre-gl.css', import.meta.url).href);
|
|
const maplibregl = await import('./vendor/maplibre/maplibre-gl.js');
|
|
|
|
const canvas = document.createElement('div');
|
|
canvas.className = 'map__canvas';
|
|
el.appendChild(canvas);
|
|
|
|
const map = new maplibregl.Map({
|
|
container: canvas,
|
|
style: STYLE,
|
|
center: [lng, lat],
|
|
zoom: reduce ? 15 : 12.6,
|
|
attributionControl: { compact: true },
|
|
cooperativeGestures: true,
|
|
dragRotate: false,
|
|
pitchWithRotate: false,
|
|
locale: LOCALE,
|
|
});
|
|
map.addControl(new maplibregl.NavigationControl({ showCompass: false }), 'bottom-right');
|
|
|
|
const marker = document.createElement('div');
|
|
marker.className = 'map-marker';
|
|
marker.innerHTML = `<span class="map-marker__label">${el.dataset.label}</span><span class="map-marker__dot" aria-hidden="true"></span>`;
|
|
new maplibregl.Marker({ element: marker, anchor: 'bottom' }).setLngLat([lng, lat]).addTo(map);
|
|
|
|
map.on('style.load', () => {
|
|
for (const [layer, prop, value] of TINT) {
|
|
if (map.getLayer(layer)) map.setPaintProperty(layer, prop, value);
|
|
}
|
|
});
|
|
|
|
map.once('load', () => {
|
|
el.classList.add('is-live');
|
|
if (!reduce) map.flyTo({ center: [lng, lat], zoom: 15, duration: 2600, essential: false });
|
|
});
|
|
}
|
|
|
|
const maps = [...document.querySelectorAll('[data-map]')];
|
|
if (maps.length && hasWebGL()) {
|
|
const io = new IntersectionObserver((entries) => {
|
|
entries.forEach((e) => {
|
|
if (!e.isIntersecting) return;
|
|
io.unobserve(e.target);
|
|
mount(e.target).catch((err) => console.warn('Karte nicht geladen, Vorschau bleibt:', err));
|
|
});
|
|
}, { rootMargin: '400px 0px' });
|
|
maps.forEach((m) => io.observe(m));
|
|
}
|