Echte Karte auf Unternehmen und Kontakt (MapLibre + OpenFreeMap)
Ersetzt die schematische Karte durch MapLibre GL 6.11 (lokal eingebunden, ohne React, da die Seite statisch ist). Kacheln vom OpenFreeMap-Stil "dark", auf die Nachtblau-Palette umgefärbt; Marker mit Label, lädt beim Heranscrollen und zoomt sanft auf den Standort. Die schematische Karte bleibt als Vorschau und Fallback ohne WebGL. Datenschutzerklärung um den Kartenanbieter ergänzt. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
5172b54339
commit
09f40da363
14 files changed
+1139
-43
No files matched your search
+109
@@ -0,0 +1,109 @@
|
||||
/* ==========================================================================
|
||||
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.mjs');
|
||||
|
||||
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));
|
||||
}
|
||||
Reference in new issue
Block a user