MapLibre-Port Runde 1: Engine-Fundament (flag-gated, Default Leaflet)
map.js: _useGL()/loadMapLibre()/_initMapGL() + engine-neutrale Facade (_mapFlyTo/_mapSetView/_mapGetZoom/_mapResize/_mapGetCenter/_mapPaddedBounds, kapselt [lat,lon]↔[lng,lat]). init() verzweigt auf GL bei Flag 'by_map_gl'/?mapgl=1. Basemap+ Controls+Dark(setStyle)+Scan-Wiring+Crosshair. POI-Layer/Marker = Runde 2. Flag default AUS.
This commit is contained in:
parent
a27695d9c6
commit
63c9be68c6
1 changed files with 140 additions and 2 deletions
|
|
@ -16,6 +16,10 @@ window.Page_map = (() => {
|
|||
let _tempMarker = null;
|
||||
let _tileLayer = null;
|
||||
let _usingVector = false; // true wenn Vektor-Basemap (PMTiles) statt OSM-Raster
|
||||
let _engineGL = false; // true wenn MapLibre GL statt Leaflet (zentrale Karte)
|
||||
let _maplibreLoaded = false;
|
||||
let _glLayersReady = false; // GL: POI-Sources/Layer angelegt?
|
||||
let _pmtilesProtoReg = false; // pmtiles-Protokoll bei MapLibre registriert?
|
||||
let _themeObserver = null;
|
||||
|
||||
// Standort-Tracking
|
||||
|
|
@ -153,8 +157,14 @@ window.Page_map = (() => {
|
|||
// Alle-Button Initialzustand
|
||||
const anyOnInit = Object.entries(_visible).some(([k, v]) => v && k !== 'giftkoeder');
|
||||
document.getElementById('map-legend-all')?.classList.toggle('all-off', !anyOnInit);
|
||||
await _loadLeaflet();
|
||||
_initMap(); // sofort mit Deutschland-Mitte starten
|
||||
_engineGL = _useGL();
|
||||
if (_engineGL) {
|
||||
await loadMapLibre();
|
||||
_initMapGL(); // MapLibre-GL-Karte (GPU)
|
||||
} else {
|
||||
await _loadLeaflet();
|
||||
_initMap(); // Leaflet-Raster (Default), sofort mit Deutschland-Mitte starten
|
||||
}
|
||||
_startLocationTracking();
|
||||
_loadAll();
|
||||
_offerResume(); // unterbrochene Aufzeichnung anbieten
|
||||
|
|
@ -656,6 +666,134 @@ window.Page_map = (() => {
|
|||
});
|
||||
}
|
||||
|
||||
// ==========================================================
|
||||
// MapLibre-GL-Engine (zentrale Karte) — GPU/Worker, performant.
|
||||
// Flag-gated; Raster-Leaflet bleibt Default. [lng,lat]-Reihenfolge!
|
||||
// ==========================================================
|
||||
// Flag: ?mapgl=1/0 → localStorage 'by_map_gl'. Default AUS (bis vollständig portiert).
|
||||
function _useGL() {
|
||||
try {
|
||||
const u = new URLSearchParams(location.search);
|
||||
if (u.has('mapgl')) localStorage.setItem('by_map_gl', u.get('mapgl') === '0' ? '0' : '1');
|
||||
return localStorage.getItem('by_map_gl') === '1';
|
||||
} catch (e) { return false; }
|
||||
}
|
||||
|
||||
function loadMapLibre() {
|
||||
if (_maplibreLoaded) return Promise.resolve();
|
||||
const v = '?v=' + (window.APP_VER || '');
|
||||
if (!document.querySelector('link[href*="maplibre-gl.css"]')) {
|
||||
const l = document.createElement('link');
|
||||
l.rel = 'stylesheet'; l.href = '/js/vendor/maplibre-gl.css';
|
||||
document.head.appendChild(l);
|
||||
}
|
||||
const seq = (srcs) => srcs.reduce((p, src) => p.then(() => new Promise((res, rej) => {
|
||||
if ((src.includes('maplibre-gl.js') && window.maplibregl) ||
|
||||
(src.includes('pmtiles.js') && window.pmtiles) ||
|
||||
(src.includes('map-gl-style') && window.MapGLStyle)) return res();
|
||||
const s = document.createElement('script');
|
||||
s.src = src + v; s.onload = res; s.onerror = rej;
|
||||
document.head.appendChild(s);
|
||||
})), Promise.resolve());
|
||||
return seq(['/js/vendor/maplibre-gl.js', '/js/vendor/pmtiles.js', '/js/map-gl-style.js']).then(() => {
|
||||
if (!(window.maplibregl && window.pmtiles && window.MapGLStyle)) throw new Error('MapLibre nicht geladen');
|
||||
if (!_pmtilesProtoReg) {
|
||||
const proto = new pmtiles.Protocol();
|
||||
maplibregl.addProtocol('pmtiles', proto.tile);
|
||||
_pmtilesProtoReg = true;
|
||||
}
|
||||
_maplibreLoaded = true;
|
||||
});
|
||||
}
|
||||
|
||||
// ---- Engine-neutrale Facade (kapselt [lat,lon]↔[lng,lat] an EINER Stelle) ----
|
||||
function _mapFlyTo(lat, lon, zoom, opts) {
|
||||
if (!_map) return;
|
||||
if (_engineGL) _map.flyTo({ center: [lon, lat], zoom, duration: opts && opts.duration ? opts.duration * 1000 : 1200 });
|
||||
else _map.flyTo([lat, lon], zoom, opts);
|
||||
}
|
||||
function _mapSetView(lat, lon, zoom) {
|
||||
if (!_map) return;
|
||||
if (_engineGL) _map.jumpTo({ center: [lon, lat], zoom });
|
||||
else _map.setView([lat, lon], zoom);
|
||||
}
|
||||
function _mapGetZoom() { return _map ? _map.getZoom() : 0; }
|
||||
function _mapResize() { if (!_map) return; if (_engineGL) _map.resize(); else _map.invalidateSize(); }
|
||||
function _mapGetCenter() {
|
||||
if (!_map) return null;
|
||||
const c = _map.getCenter(); // beide Engines: {lat, lng}
|
||||
return { lat: c.lat, lon: c.lng };
|
||||
}
|
||||
// Bounds mit 15%-Padding (ersetzt Leaflets bounds.pad(0.15)) → {north,south,east,west}
|
||||
function _mapPaddedBounds(pad) {
|
||||
pad = pad == null ? 0.15 : pad;
|
||||
const b = _map.getBounds();
|
||||
let n = b.getNorth(), s = b.getSouth(), e = b.getEast(), w = b.getWest();
|
||||
const dLat = (n - s) * pad, dLon = (e - w) * pad;
|
||||
return { north: n + dLat, south: s - dLat, east: e + dLon, west: w - dLon };
|
||||
}
|
||||
|
||||
function _initMapGL() {
|
||||
const el = document.getElementById('central-map');
|
||||
if (!el || !window.maplibregl || _map) return;
|
||||
_engineGL = true;
|
||||
const center = _userPos ? [_userPos.lon, _userPos.lat] : [8.6821, 50.1109]; // Frankfurt [lng,lat]
|
||||
const zoom = _userPos ? 14 : 10;
|
||||
|
||||
_map = new maplibregl.Map({
|
||||
container: 'central-map',
|
||||
style: MapGLStyle.build({ dark: _isDarkMode() }),
|
||||
center, zoom, attributionControl: false,
|
||||
maxZoom: 19, dragRotate: false, pitchWithRotate: false,
|
||||
});
|
||||
_map.addControl(new maplibregl.NavigationControl({ showCompass: false }), 'top-left');
|
||||
_map.addControl(new maplibregl.ScaleControl());
|
||||
_map.addControl(new maplibregl.AttributionControl({
|
||||
compact: true, customAttribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors',
|
||||
}));
|
||||
|
||||
if (!_userPos) {
|
||||
_frankfurtTimer = setTimeout(() => _mapFlyTo(50.1109, 8.6821, 14, { duration: 2.5 }), 1200);
|
||||
}
|
||||
|
||||
// Theme-Wechsel → Style neu setzen (Sources/Layer danach neu anlegen).
|
||||
_themeObserver = new MutationObserver(() => _onThemeChangeGL());
|
||||
_themeObserver.observe(document.documentElement, { attributes: true, attributeFilter: ['data-theme'] });
|
||||
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', _onThemeChangeGL);
|
||||
|
||||
_map.on('load', () => {
|
||||
_initPoiLayersGL();
|
||||
_updateZoomDisplay();
|
||||
_scheduleOsmLoad();
|
||||
});
|
||||
_map.on('moveend', () => {
|
||||
_autoRetryCount = 0; _updateZoomDisplay(); _scheduleOsmLoad();
|
||||
document.getElementById('map-crosshair')?.classList.remove('dragging');
|
||||
});
|
||||
_map.on('movestart', () => {
|
||||
document.getElementById('map-crosshair')?.classList.add('dragging');
|
||||
});
|
||||
|
||||
window.addEventListener('resize', _mapResize);
|
||||
setTimeout(_mapResize, 100);
|
||||
setTimeout(_mapResize, 600);
|
||||
}
|
||||
|
||||
function _onThemeChangeGL() {
|
||||
if (!_map || !_engineGL) return;
|
||||
_glLayersReady = false;
|
||||
_map.setStyle(MapGLStyle.build({ dark: _isDarkMode() }));
|
||||
// setStyle entfernt eigene Sources/Layer → nach Style-Load neu anlegen.
|
||||
_map.once('styledata', () => { _initPoiLayersGL(); _scheduleOsmLoad(); });
|
||||
}
|
||||
|
||||
// POI-Sources/Layer in MapLibre anlegen — wird in Build-Runde 2 gefüllt.
|
||||
function _initPoiLayersGL() {
|
||||
if (!_map || !_engineGL || _glLayersReady) return;
|
||||
_glLayersReady = true;
|
||||
// (Build-Runde 2: GeoJSON-Sources + Cluster/Symbol-Layer + Icons)
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------
|
||||
// Standort-Tracking — pulsierender blauer Punkt
|
||||
// ----------------------------------------------------------
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue