- map-gl-mini.js: Leaflet-kompatible MapLibre-Facade (createMap/svgMarker/circleMarker/ featureGroup-Wrapper mit setView/fitBounds/invalidateSize/addTo/bindPopup/openPopup/on/remove) - ui.js: UI.map.create/svgMarker/leafletMarker branchen auf GL (by_map_gl, Staging-Default), + UI.map.circleMarker/featureGroup, loadMapLibreUI - poison.js/lost.js: window.L-Guards entfernt, L.circleMarker→UI.map.circleMarker
146 lines
6.7 KiB
JavaScript
146 lines
6.7 KiB
JavaScript
// Leaflet-kompatible MapLibre-Facade für die SEITENKARTEN (Giftköder, Verlorene,
|
|
// Events, Gassi, Routen). Liefert Wrapper, die die von den Seiten genutzte Leaflet-
|
|
// API nachbilden (setView/fitBounds/invalidateSize/addTo/bindPopup/openPopup/on/remove),
|
|
// sodass die Seiten fast unverändert auf demselben GL-Style (MapGLStyle) laufen.
|
|
// Koordinaten nach außen [lat,lon] (Leaflet-Konvention), intern MapLibre [lng,lat].
|
|
(function () {
|
|
'use strict';
|
|
|
|
function _ll(latlon) { return [latlon[1], latlon[0]]; } // [lat,lon] → [lng,lat]
|
|
|
|
// ---- Map-Wrapper ----
|
|
function _wrapMap(map) {
|
|
return {
|
|
_gl: map,
|
|
_isGL: true,
|
|
setView: function (latlon, zoom) { map.jumpTo({ center: _ll(latlon), zoom: zoom }); return this; },
|
|
flyTo: function (latlon, zoom, opts) {
|
|
map.flyTo({ center: _ll(latlon), zoom: zoom, duration: opts && opts.duration ? opts.duration * 1000 : 1000 });
|
|
return this;
|
|
},
|
|
panTo: function (latlon) { map.panTo(_ll(latlon)); return this; },
|
|
fitBounds: function (b, opts) {
|
|
var bb = _toBounds(b);
|
|
if (bb) {
|
|
var pad = 40;
|
|
if (opts && opts.padding) pad = Array.isArray(opts.padding) ? opts.padding[0] : opts.padding;
|
|
map.fitBounds(bb, { padding: pad, maxZoom: opts && opts.maxZoom, duration: 0 });
|
|
}
|
|
return this;
|
|
},
|
|
invalidateSize: function () { map.resize(); return this; },
|
|
removeLayer: function (layer) { if (layer && layer.remove) layer.remove(); return this; },
|
|
addLayer: function (layer) { if (layer && layer.addTo) layer.addTo(this); return this; },
|
|
hasLayer: function () { return true; },
|
|
remove: function () { try { map.remove(); } catch (e) {} },
|
|
on: function (ev, fn) { map.on(ev, fn); return this; },
|
|
off: function (ev, fn) { map.off(ev, fn); return this; },
|
|
getZoom: function () { return map.getZoom(); },
|
|
getCenter: function () { var c = map.getCenter(); return { lat: c.lat, lng: c.lng }; },
|
|
};
|
|
}
|
|
|
|
// Bounds aus: Array von [lat,lon] | featureGroup-Wrapper (_coords) | Leaflet-Bounds.
|
|
function _toBounds(b) {
|
|
if (!b) return null;
|
|
var coords = null;
|
|
if (Array.isArray(b)) coords = b;
|
|
else if (b._coords) coords = b._coords;
|
|
else if (typeof b.getSouthWest === 'function') {
|
|
var sw = b.getSouthWest(), ne = b.getNorthEast();
|
|
return new maplibregl.LngLatBounds([sw.lng, sw.lat], [ne.lng, ne.lat]);
|
|
}
|
|
if (!coords || !coords.length) return null;
|
|
var bb = new maplibregl.LngLatBounds();
|
|
coords.forEach(function (c) { bb.extend(_ll(c)); });
|
|
return bb;
|
|
}
|
|
|
|
// ---- Marker-Wrapper (HTML-Marker; svgMarker + circleMarker) ----
|
|
function _wrapMarker(lat, lon, el, anchor) {
|
|
var m = new maplibregl.Marker({ element: el, anchor: anchor || 'center' }).setLngLat([lon, lat]);
|
|
var wrap = {
|
|
_gl: m,
|
|
_el: el,
|
|
addTo: function (mapWrap) { m.addTo(mapWrap && mapWrap._gl ? mapWrap._gl : mapWrap); return this; },
|
|
bindPopup: function (html, opts) {
|
|
m.setPopup(new maplibregl.Popup({ maxWidth: (opts && opts.maxWidth ? opts.maxWidth + 'px' : '260px'), closeButton: true, offset: 18 }).setHTML(html));
|
|
return this;
|
|
},
|
|
openPopup: function () { var p = m.getPopup(); if (p && !p.isOpen()) m.togglePopup(); return this; },
|
|
closePopup: function () { var p = m.getPopup(); if (p && p.isOpen()) m.togglePopup(); return this; },
|
|
bindTooltip: function (t) { try { el.title = typeof t === 'string' ? t.replace(/<[^>]*>/g, '') : ''; } catch (e) {} return this; },
|
|
on: function (ev, fn) {
|
|
if (ev === 'click') el.addEventListener('click', function (e) { e.stopPropagation(); fn(e); });
|
|
return this;
|
|
},
|
|
setLatLng: function (latlon) { m.setLngLat([latlon[1], latlon[0]]); return this; },
|
|
setOpacity: function (o) { el.style.opacity = o; return this; },
|
|
remove: function () { try { m.remove(); } catch (e) {} return this; },
|
|
};
|
|
return wrap;
|
|
}
|
|
|
|
// Element aus HTML-String (für svgMarker mit custom HTML).
|
|
function _elFromHtml(html, size, anchorY) {
|
|
var wrap = document.createElement('div');
|
|
wrap.innerHTML = html;
|
|
var el = wrap.firstElementChild || wrap;
|
|
el.style.cursor = 'pointer';
|
|
return el;
|
|
}
|
|
|
|
window.MapGLMini = {
|
|
createMap: function (container, opts) {
|
|
opts = opts || {};
|
|
var el = typeof container === 'string' ? document.getElementById(container) : container;
|
|
var center = opts.center || [51.1657, 10.4515];
|
|
var map = new maplibregl.Map({
|
|
container: el,
|
|
style: MapGLStyle.build({ dark: !!opts.dark }),
|
|
center: _ll(center), zoom: opts.zoom != null ? opts.zoom : 6,
|
|
attributionControl: false, dragRotate: false, pitchWithRotate: false, maxZoom: 19,
|
|
});
|
|
map.touchZoomRotate.disableRotation();
|
|
map.touchPitch.disable();
|
|
try { el.style.touchAction = 'none'; } catch (e) {}
|
|
if (opts.zoomControl !== false) map.addControl(new maplibregl.NavigationControl({ showCompass: false }), 'top-left');
|
|
map.addControl(new maplibregl.AttributionControl({
|
|
compact: true, customAttribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors',
|
|
}));
|
|
return _wrapMap(map);
|
|
},
|
|
|
|
// svgMarker: custom HTML-Icon. opts: { size, anchorY }
|
|
svgMarker: function (lat, lon, html, opts) {
|
|
opts = opts || {};
|
|
var el = _elFromHtml(html);
|
|
// anchorY: Pixel von oben zum Ankerpunkt (Leaflet iconAnchor). 'bottom' wenn anchorY≈size.
|
|
var anchor = 'center';
|
|
if (opts.anchorY != null && opts.size) {
|
|
anchor = opts.anchorY >= opts.size * 0.8 ? 'bottom' : 'center';
|
|
}
|
|
return _wrapMarker(lat, lon, el, anchor);
|
|
},
|
|
|
|
circleMarker: function (lat, lon, opts) {
|
|
opts = opts || {};
|
|
var r = opts.radius || 8;
|
|
var el = document.createElement('div');
|
|
el.style.cssText = 'width:' + (r * 2) + 'px;height:' + (r * 2) + 'px;border-radius:50%;background:' +
|
|
(opts.fillColor || opts.color || '#3B82F6') + ';border:' + (opts.weight || 2) + 'px solid ' +
|
|
(opts.color || '#fff') + ';opacity:' + (opts.fillOpacity != null ? opts.fillOpacity : 1) +
|
|
';box-shadow:0 1px 4px rgba(0,0,0,.35);cursor:pointer';
|
|
return _wrapMarker(lat, lon, el, 'center');
|
|
},
|
|
|
|
// featureGroup: nur als Bounds-Container (markers = Array von Wrappern mit _gl.getLngLat()).
|
|
featureGroup: function (markers) {
|
|
var coords = (markers || []).map(function (m) {
|
|
var ll = m && m._gl && m._gl.getLngLat ? m._gl.getLngLat() : null;
|
|
return ll ? [ll.lat, ll.lng] : null;
|
|
}).filter(Boolean);
|
|
return { _coords: coords, getBounds: function () { return { _coords: coords }; }, addTo: function () { return this; } };
|
|
},
|
|
};
|
|
})();
|