Sprint D: Karten-Familie auf UI.map.create+svgMarker konsolidiert, SW by-v1107
Neue zentrale Helper (in Sprint B vorbereitet) jetzt von 5 Seiten genutzt:
walks.js (1 Karten-Init):
- L.map+L.tileLayer → await UI.map.create('walks-map', {...})
- _initMap zu async, Aufrufer in _switchView und _loadData angepasst
- Mini-Karte im Walk-Formular (Modal) bleibt unverändert
(braucht eigene dragging/scrollWheelZoom-Options)
- view-toggle nicht migriert (responsive CSS-Konflikt mit Desktop)
poison.js (1 Karten-Init):
- L.map+L.tileLayer → await UI.map.create('poison-map', {...})
- _initMap zu async, manueller UI.loadLeaflet entfernt
- DangerCircle + User-Marker unverändert
events.js (1 Karten-Init + Diamant-Marker):
- await UI.map.create('ev-map', {...})
- Rotierter Diamant: L.divIcon+L.marker → UI.map.svgMarker
(HTML 1:1 erhalten)
lost.js (1 Karten-Init + Puls-Marker):
- Eigene async _loadLeaflet() Funktion komplett entfernt — UI.map.create
übernimmt das jetzt zentral
- await UI.map.create('lost-map', {...})
- Puls-Animation 🐕: L.divIcon+L.marker → UI.map.svgMarker
- _initMap zu async
routes.js (6 von 7 Karten-Inits):
- _suggestMap, _recMap, _searchMap, _navMap, trimMap, _buildDetailMap
alle auf UI.map.create umgestellt + zu async
- _buildMiniMap (Route-Card-Preview) bleibt unverändert
(braucht 6 spezifische Interaction-Disable Options)
- View-Toggle auf neue .map-list-toggle Klasse umgestellt
(Border-Inline-Styles raus)
NEUE CSS-KLASSE in components.css:
- .map-list-toggle (vereinheitlichter Karten/Listen-Umschalter)
- Verwendet von routes.js; walks/events können später folgen
Tests 19/19 grün. GPS-Tracking-Logik (Polylines, Recording, Trim)
komplett unangetastet. Marker-Cluster-Logik unverändert.
This commit is contained in:
parent
c8ef4939f1
commit
73872e2c21
11 changed files with 130 additions and 152 deletions
2
VERSION
2
VERSION
|
|
@ -1 +1 @@
|
|||
1106
|
||||
1107
|
||||
|
|
@ -8944,3 +8944,44 @@ svg.empty-state-icon {
|
|||
.offline-status-row .osr-text { flex: 1; min-width: 0; }
|
||||
.offline-status-row .osr-title { font-weight: 600; }
|
||||
.offline-status-row .osr-detail { font-size: var(--text-xs); color: var(--c-text-muted); margin-top: 2px; }
|
||||
|
||||
/* ============================================================
|
||||
.map-list-toggle — vereinheitlichter Karten/Listen-Umschalter
|
||||
Verwendet von walks.js, events.js, routes.js, etc.
|
||||
|
||||
<div class="map-list-toggle">
|
||||
<button class="active" data-view="list">Liste</button>
|
||||
<button data-view="map">Karte</button>
|
||||
</div>
|
||||
============================================================ */
|
||||
.map-list-toggle {
|
||||
display: flex;
|
||||
border: 1.5px solid var(--c-border);
|
||||
border-radius: var(--radius-md);
|
||||
overflow: hidden;
|
||||
background: var(--c-surface);
|
||||
}
|
||||
.map-list-toggle button {
|
||||
flex: 1;
|
||||
height: 44px;
|
||||
border: none;
|
||||
background: transparent;
|
||||
color: var(--c-text-secondary);
|
||||
cursor: pointer;
|
||||
font-size: var(--text-sm);
|
||||
font-weight: var(--weight-medium);
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: var(--space-1);
|
||||
transition: background 0.15s, color 0.15s;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
}
|
||||
.map-list-toggle button.active {
|
||||
background: var(--c-primary);
|
||||
color: #fff;
|
||||
}
|
||||
.map-list-toggle button:not(.active):hover {
|
||||
background: var(--c-surface-2);
|
||||
color: var(--c-text);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -86,14 +86,14 @@
|
|||
<title>Ban Yaro</title>
|
||||
|
||||
<!-- Theme + theme-color Statusleiste vor CSS setzen -->
|
||||
<script src="/js/boot-early.js?v=1106"></script>
|
||||
<script src="/js/boot-early.js?v=1107"></script>
|
||||
|
||||
<!-- CSS: Reihenfolge ist wichtig — ?v= zwingt Browser zur Neuladung -->
|
||||
<link rel="stylesheet" href="/css/design-system.css?v=1106">
|
||||
<link rel="stylesheet" href="/css/layout.css?v=1106">
|
||||
<link rel="stylesheet" href="/css/components.css?v=1106">
|
||||
<link rel="stylesheet" href="/css/utilities.css?v=1106">
|
||||
<link rel="stylesheet" href="/css/lists.css?v=1106">
|
||||
<link rel="stylesheet" href="/css/design-system.css?v=1107">
|
||||
<link rel="stylesheet" href="/css/layout.css?v=1107">
|
||||
<link rel="stylesheet" href="/css/components.css?v=1107">
|
||||
<link rel="stylesheet" href="/css/utilities.css?v=1107">
|
||||
<link rel="stylesheet" href="/css/lists.css?v=1107">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
|
|
@ -617,11 +617,11 @@
|
|||
<div id="modal-container"></div>
|
||||
|
||||
<!-- JS: Reihenfolge ist wichtig — erst Basis, dann Features -->
|
||||
<script src="/js/api.js?v=1106"></script>
|
||||
<script src="/js/ui.js?v=1106"></script>
|
||||
<script src="/js/app.js?v=1106"></script>
|
||||
<script src="/js/worlds.js?v=1106"></script>
|
||||
<script src="/js/offline-indicator.js?v=1106"></script>
|
||||
<script src="/js/api.js?v=1107"></script>
|
||||
<script src="/js/ui.js?v=1107"></script>
|
||||
<script src="/js/app.js?v=1107"></script>
|
||||
<script src="/js/worlds.js?v=1107"></script>
|
||||
<script src="/js/offline-indicator.js?v=1107"></script>
|
||||
|
||||
<!-- Feature-Seiten werden lazy geladen -->
|
||||
|
||||
|
|
@ -631,7 +631,7 @@
|
|||
|
||||
|
||||
<!-- Boot: Offline-Banner + SW-Registration (extrahiert für CSP) -->
|
||||
<script src="/js/boot.js?v=1106"></script>
|
||||
<script src="/js/boot.js?v=1107"></script>
|
||||
|
||||
|
||||
</body>
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
Router, State-Management, Navigation, Initialisierung.
|
||||
============================================================ */
|
||||
|
||||
const APP_VER = '1106'; // ← bei jedem Deploy mit Frontend-Änderungen erhöhen
|
||||
const APP_VER = '1107'; // ← bei jedem Deploy mit Frontend-Änderungen erhöhen
|
||||
const APP_VERSION = '1.6.0'; // ← semantische Version, wird bei make release gesetzt
|
||||
window.APP_VER = APP_VER; // global verfügbar für andere Module (z.B. offline-indicator)
|
||||
window.APP_VERSION = APP_VERSION;
|
||||
|
|
|
|||
|
|
@ -248,8 +248,10 @@ window.Page_events = (() => {
|
|||
await UI.loadLeaflet(true); // true = mit MarkerCluster
|
||||
|
||||
if (!_map) {
|
||||
_map = L.map('ev-map', { zoomControl: true }).setView([51.1657, 10.4515], 6);
|
||||
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { maxZoom: 19 }).addTo(_map);
|
||||
_map = await UI.map.create('ev-map', {
|
||||
center: [51.1657, 10.4515], zoom: 6,
|
||||
zoomControl: true, attributionControl: false,
|
||||
});
|
||||
}
|
||||
|
||||
// Cluster-Gruppe aufräumen und neu befüllen
|
||||
|
|
@ -266,12 +268,8 @@ window.Page_events = (() => {
|
|||
const typ = TYPEN.find(t => t.id === ev.typ) || TYPEN[TYPEN.length - 1];
|
||||
const d = new Date(ev.datum + 'T00:00:00');
|
||||
const datum = d.toLocaleDateString('de-DE', { day: 'numeric', month: 'short', year: 'numeric' });
|
||||
// Events nutzen rotierten Diamant-Marker (nicht Kreis) — UI.leafletMarker() nicht anwendbar
|
||||
const icon = L.divIcon({
|
||||
className: '',
|
||||
html: `<div style="width:32px;height:32px;border-radius:50% 50% 50% 0;background:${color};border:2px solid #fff;display:flex;align-items:center;justify-content:center;font-size:14px;box-shadow:0 2px 6px rgba(0,0,0,0.3);transform:rotate(-45deg);color:#fff"><svg style="width:14px;height:14px;transform:rotate(45deg);fill:currentColor" viewBox="0 0 256 256"><use href="/icons/phosphor.svg#${typ.icon}"></use></svg></div>`,
|
||||
iconSize: [32, 32], iconAnchor: [16, 32],
|
||||
});
|
||||
// Events nutzen rotierten Diamant-Marker (nicht Kreis) — UI.map.svgMarker mit custom HTML
|
||||
const html = `<div style="width:32px;height:32px;border-radius:50% 50% 50% 0;background:${color};border:2px solid #fff;display:flex;align-items:center;justify-content:center;font-size:14px;box-shadow:0 2px 6px rgba(0,0,0,0.3);transform:rotate(-45deg);color:#fff"><svg style="width:14px;height:14px;transform:rotate(45deg);fill:currentColor" viewBox="0 0 256 256"><use href="/icons/phosphor.svg#${typ.icon}"></use></svg></div>`;
|
||||
const popup = `
|
||||
<div style="min-width:180px">
|
||||
<strong>${UI.escape(ev.titel)}</strong><br>
|
||||
|
|
@ -282,7 +280,7 @@ window.Page_events = (() => {
|
|||
style="font-size:12px;color:var(--c-primary,#2563eb)">Details</a>
|
||||
</div>
|
||||
`;
|
||||
const m = L.marker([ev.lat, ev.lon], { icon }).bindPopup(popup);
|
||||
const m = UI.map.svgMarker(ev.lat, ev.lon, html, { size: 32, anchorY: 32 }).bindPopup(popup);
|
||||
_clusterGroup.addLayer(m);
|
||||
_markers.push(m);
|
||||
bounds.push([ev.lat, ev.lon]);
|
||||
|
|
|
|||
|
|
@ -130,54 +130,24 @@ window.Page_lost = (() => {
|
|||
document.getElementById('lost-btn-report')
|
||||
?.addEventListener('click', _showReportForm);
|
||||
|
||||
await _loadLeaflet();
|
||||
_initMap();
|
||||
await _initMap();
|
||||
setTimeout(() => _map?.invalidateSize(), 100);
|
||||
await _locateAndLoad();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------
|
||||
// LEAFLET DYNAMISCH LADEN
|
||||
// KARTE INITIALISIEREN (lädt Leaflet via UI.map.create)
|
||||
// ----------------------------------------------------------
|
||||
async function _loadLeaflet() {
|
||||
if (_leafletLoaded || window.L) { _leafletLoaded = true; return; }
|
||||
|
||||
await new Promise(resolve => {
|
||||
if (document.querySelector('link[href*="leaflet"]')) { resolve(); return; }
|
||||
const link = document.createElement('link');
|
||||
link.rel = 'stylesheet';
|
||||
link.href = '/css/leaflet.css';
|
||||
link.onload = resolve;
|
||||
link.onerror = resolve;
|
||||
document.head.appendChild(link);
|
||||
});
|
||||
|
||||
await new Promise((resolve, reject) => {
|
||||
if (document.querySelector('script[src*="leaflet"]')) { resolve(); return; }
|
||||
const s = document.createElement('script');
|
||||
s.src = '/js/leaflet.js';
|
||||
s.onload = resolve;
|
||||
s.onerror = reject;
|
||||
document.head.appendChild(s);
|
||||
});
|
||||
|
||||
_leafletLoaded = true;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------
|
||||
// KARTE INITIALISIEREN
|
||||
// ----------------------------------------------------------
|
||||
function _initMap() {
|
||||
async function _initMap() {
|
||||
_injectStyles();
|
||||
const mapEl = document.getElementById('lost-map');
|
||||
if (!mapEl || !window.L || _map) return;
|
||||
if (!mapEl || _map) return;
|
||||
|
||||
_map = L.map('lost-map', { zoomControl: true, attributionControl: false })
|
||||
.setView([51.1657, 10.4515], 6);
|
||||
|
||||
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
|
||||
maxZoom: 19,
|
||||
}).addTo(_map);
|
||||
_map = await UI.map.create('lost-map', {
|
||||
center: [51.1657, 10.4515], zoom: 6,
|
||||
zoomControl: true, attributionControl: false,
|
||||
});
|
||||
_leafletLoaded = true;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------
|
||||
|
|
@ -303,22 +273,17 @@ window.Page_lost = (() => {
|
|||
_reports.forEach(r => {
|
||||
const dotColor = r._isPending ? '#d97706' : '#e74c3c';
|
||||
const anim = r._isPending ? 'by-lost-pulse-p' : 'by-lost-pulse-r';
|
||||
const icon = L.divIcon({
|
||||
className : '',
|
||||
html : `<div style="background:${dotColor};color:#fff;border-radius:50%;
|
||||
const html = `<div style="background:${dotColor};color:#fff;border-radius:50%;
|
||||
width:34px;height:34px;
|
||||
display:flex;align-items:center;justify-content:center;
|
||||
font-size:17px;border:2px solid #fff;
|
||||
animation:${anim} 1.8s ease-in-out infinite">🐕</div>`,
|
||||
iconSize : [34, 34],
|
||||
iconAnchor : [17, 17],
|
||||
});
|
||||
animation:${anim} 1.8s ease-in-out infinite">🐕</div>`;
|
||||
|
||||
const distStr = r.distanz_m !== undefined
|
||||
? (r.distanz_m < 1000 ? `${Math.round(r.distanz_m)} m` : `${(r.distanz_m / 1000).toFixed(1)} km`)
|
||||
: '';
|
||||
|
||||
const marker = L.marker([r.lat, r.lon], { icon })
|
||||
const marker = UI.map.svgMarker(r.lat, r.lon, html, { size: 34, anchorY: 17 })
|
||||
.addTo(_map)
|
||||
.bindPopup(`
|
||||
<b>🔍 ${_escape(r.name)}</b><br>
|
||||
|
|
|
|||
|
|
@ -94,8 +94,7 @@ window.Page_poison = (() => {
|
|||
document.getElementById('poison-btn-erstehilfe')
|
||||
?.addEventListener('click', () => App.navigate('erste-hilfe', true, { tab: 'lebensgefahr' }));
|
||||
|
||||
await UI.loadLeaflet();
|
||||
_initMap();
|
||||
await _initMap();
|
||||
// Leaflet muss nach CSS-Load die Container-Größe neu berechnen
|
||||
setTimeout(() => _map?.invalidateSize(), 100);
|
||||
await _locateAndLoad();
|
||||
|
|
@ -104,17 +103,16 @@ window.Page_poison = (() => {
|
|||
// ----------------------------------------------------------
|
||||
// KARTE INITIALISIEREN
|
||||
// ----------------------------------------------------------
|
||||
function _initMap() {
|
||||
async function _initMap() {
|
||||
const mapEl = document.getElementById('poison-map');
|
||||
if (!mapEl || !window.L || _map) return;
|
||||
|
||||
_map = L.map('poison-map', { zoomControl: true, attributionControl: false })
|
||||
.setView([51.1657, 10.4515], 6); // Deutschland-Mitte
|
||||
|
||||
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
|
||||
maxZoom: 19,
|
||||
}).addTo(_map);
|
||||
if (!mapEl || _map) return;
|
||||
|
||||
_map = await UI.map.create('poison-map', {
|
||||
center: [51.1657, 10.4515], // Deutschland-Mitte
|
||||
zoom: 6,
|
||||
zoomControl: true,
|
||||
attributionControl: false,
|
||||
});
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -193,20 +193,15 @@ window.Page_routes = (() => {
|
|||
background:var(--c-surface);color:var(--c-text);outline:none;
|
||||
box-sizing:border-box;">
|
||||
</div>
|
||||
<div style="display:flex;border:1.5px solid var(--c-border);border-radius:10px;
|
||||
overflow:hidden;flex-shrink:0;height:46px;box-sizing:border-box">
|
||||
<div class="map-list-toggle" style="flex-shrink:0;width:auto">
|
||||
<button id="rk-view-list" title="Liste"
|
||||
style="width:44px;height:100%;border:none;cursor:pointer;
|
||||
display:flex;align-items:center;justify-content:center;
|
||||
background:${_viewMode==='list' ? 'var(--c-primary)' : 'var(--c-surface)'};
|
||||
color:${_viewMode==='list' ? '#fff' : 'var(--c-text-secondary)'}">
|
||||
class="${_viewMode==='list' ? 'active' : ''}"
|
||||
style="flex:0 0 auto;width:44px">
|
||||
${UI.icon('list')}
|
||||
</button>
|
||||
<button id="rk-view-map" title="Karte"
|
||||
style="width:44px;height:100%;border:none;border-left:1.5px solid var(--c-border);
|
||||
cursor:pointer;display:flex;align-items:center;justify-content:center;
|
||||
background:${_viewMode==='map' ? 'var(--c-primary)' : 'var(--c-surface)'};
|
||||
color:${_viewMode==='map' ? '#fff' : 'var(--c-text-secondary)'}">
|
||||
class="${_viewMode==='map' ? 'active' : ''}"
|
||||
style="flex:0 0 auto;width:44px">
|
||||
${UI.icon('map-trifold')}
|
||||
</button>
|
||||
</div>
|
||||
|
|
@ -602,16 +597,18 @@ window.Page_routes = (() => {
|
|||
</button>
|
||||
</div>`;
|
||||
|
||||
const _initMap = () => {
|
||||
const _initMap = async () => {
|
||||
const mapEl = document.getElementById('rks-map');
|
||||
if (!mapEl || !window.L) return;
|
||||
if (!mapEl) return;
|
||||
if (_suggestMap) { _suggestMap.remove(); _suggestMap = null; }
|
||||
const track = result.gps_track || [];
|
||||
if (track.length < 2) return;
|
||||
const lls = track.map(p => [p.lat, p.lon]);
|
||||
_suggestMap = L.map(mapEl, { zoomControl: false, attributionControl: false,
|
||||
dragging: true, touchZoom: true, scrollWheelZoom: false });
|
||||
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { maxZoom: 19 }).addTo(_suggestMap);
|
||||
_suggestMap = await UI.map.create(mapEl, {
|
||||
center: lls[0], zoom: 14,
|
||||
zoomControl: false, attributionControl: false,
|
||||
});
|
||||
_suggestMap.scrollWheelZoom.disable();
|
||||
const poly = L.polyline(lls, { color: '#C4843A', weight: 4, opacity: 0.9 }).addTo(_suggestMap);
|
||||
L.circleMarker(lls[0], { radius:7, color:'#22C55E', fillColor:'#22C55E', fillOpacity:1, weight:2 }).addTo(_suggestMap);
|
||||
L.circleMarker(lls.at(-1), { radius:7, color:'#EF4444', fillColor:'#EF4444', fillOpacity:1, weight:2 }).addTo(_suggestMap);
|
||||
|
|
@ -619,12 +616,7 @@ window.Page_routes = (() => {
|
|||
_suggestMap.fitBounds(poly.getBounds(), { padding: [16, 16] });
|
||||
setTimeout(() => _suggestMap?.invalidateSize(), 120);
|
||||
};
|
||||
if (window.L) { _initMap(); } else {
|
||||
let tries = 0;
|
||||
const poll = setInterval(() => {
|
||||
if (window.L || ++tries > 40) { clearInterval(poll); if (window.L) _initMap(); }
|
||||
}, 100);
|
||||
}
|
||||
_initMap();
|
||||
|
||||
document.getElementById('rks-nav-btn')?.addEventListener('click', () => {
|
||||
_openNavOverlay({ id: 'suggest-' + Date.now(), name: result.name,
|
||||
|
|
@ -668,8 +660,6 @@ window.Page_routes = (() => {
|
|||
if (!_appState.user) { UI.toast.warning('Bitte anmelden.'); return; }
|
||||
if (_recOvl) return;
|
||||
|
||||
try { await (UI.loadLeaflet?.() ?? Promise.resolve()); }
|
||||
catch { UI.toast.warning('Karte offline nicht verfügbar — GPS-Aufzeichnung läuft trotzdem.'); }
|
||||
|
||||
const ovl = document.createElement('div');
|
||||
ovl.id = 'rk-rec-ovl';
|
||||
|
|
@ -733,10 +723,10 @@ window.Page_routes = (() => {
|
|||
// Map-Setup: Leaflet könnte offline fehlen → alles in try/catch
|
||||
const pos = _userPos || { lat: 48.1, lon: 11.5 };
|
||||
try {
|
||||
if (!window.L) throw new Error('Leaflet not loaded');
|
||||
_recMap = L.map(ovl.querySelector('#rk-rec-map-wrap'), { zoomControl: false, attributionControl: false })
|
||||
.setView([pos.lat, pos.lon], 15);
|
||||
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { maxZoom: 19 }).addTo(_recMap);
|
||||
_recMap = await UI.map.create(ovl.querySelector('#rk-rec-map-wrap'), {
|
||||
center: [pos.lat, pos.lon], zoom: 15,
|
||||
zoomControl: false, attributionControl: false,
|
||||
});
|
||||
_recLocMarker = L.circleMarker([pos.lat, pos.lon], {
|
||||
radius: 8, color: '#fff', weight: 2.5, fillColor: '#3b82f6', fillOpacity: 1
|
||||
}).addTo(_recMap);
|
||||
|
|
@ -1127,8 +1117,7 @@ window.Page_routes = (() => {
|
|||
document.body.appendChild(sec);
|
||||
document.getElementById('rk-map-back')?.addEventListener('click', () => _switchView('list'));
|
||||
|
||||
// Wie _initMiniMaps: pollen bis window.L bereit ist
|
||||
_pollAndInitSearchMap();
|
||||
_initSearchMap();
|
||||
|
||||
} else {
|
||||
document.getElementById('rk-map-section')?.remove();
|
||||
|
|
@ -1140,26 +1129,16 @@ window.Page_routes = (() => {
|
|||
// ----------------------------------------------------------
|
||||
// Suchkarte
|
||||
// ----------------------------------------------------------
|
||||
function _pollAndInitSearchMap() {
|
||||
if (window.L) { _initSearchMap(); return; }
|
||||
let tries = 0;
|
||||
const poll = setInterval(() => {
|
||||
if (window.L || ++tries > 40) {
|
||||
clearInterval(poll);
|
||||
if (window.L) _initSearchMap();
|
||||
}
|
||||
}, 100);
|
||||
}
|
||||
|
||||
function _initSearchMap() {
|
||||
async function _initSearchMap() {
|
||||
if (!document.getElementById('rk-search-map')) return;
|
||||
|
||||
const center = _userPos ? [_userPos.lat, _userPos.lon] : [51.1, 10.4];
|
||||
const zoom = _userPos ? 13 : 6;
|
||||
|
||||
_searchMap = L.map('rk-search-map', { zoomControl: true, attributionControl: false })
|
||||
.setView(center, zoom);
|
||||
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { maxZoom: 19 }).addTo(_searchMap);
|
||||
_searchMap = await UI.map.create('rk-search-map', {
|
||||
center, zoom,
|
||||
zoomControl: true, attributionControl: false,
|
||||
});
|
||||
setTimeout(() => _searchMap?.invalidateSize(), 100);
|
||||
setTimeout(() => _searchMap?.invalidateSize(), 600);
|
||||
_renderRoutesOnMap();
|
||||
|
|
@ -1586,8 +1565,6 @@ window.Page_routes = (() => {
|
|||
try { await DeviceOrientationEvent.requestPermission(); } catch {}
|
||||
}
|
||||
|
||||
await UI.loadLeaflet?.() ?? Promise.resolve();
|
||||
|
||||
const ovl = document.createElement('div');
|
||||
ovl.id = 'rk-nav-ovl';
|
||||
ovl.style.cssText = 'position:fixed;inset:0;z-index:850;display:flex;flex-direction:column;background:var(--c-bg)';
|
||||
|
|
@ -1700,9 +1677,10 @@ window.Page_routes = (() => {
|
|||
// Karte initialisieren
|
||||
const mapEl = document.getElementById('rk-nav-map');
|
||||
const mid = track[Math.floor(track.length / 2)];
|
||||
_navMap = L.map(mapEl, { zoomControl: false, attributionControl: false })
|
||||
.setView([mid.lat, mid.lon], 15);
|
||||
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { maxZoom: 19 }).addTo(_navMap);
|
||||
_navMap = await UI.map.create(mapEl, {
|
||||
center: [mid.lat, mid.lon], zoom: 15,
|
||||
zoomControl: false, attributionControl: false,
|
||||
});
|
||||
|
||||
// Route-Polylines: erledigt (grün) + ausstehend (orange)
|
||||
const doneLine = L.polyline([], { color: '#22c55e', weight: 5, opacity: 0.85 }).addTo(_navMap);
|
||||
|
|
@ -2106,12 +2084,12 @@ window.Page_routes = (() => {
|
|||
document.body.appendChild(ovl);
|
||||
|
||||
// Map initialisieren
|
||||
await UI.loadLeaflet?.() ?? Promise.resolve();
|
||||
const mapEl = document.getElementById('rk-trim-map');
|
||||
const center = fullTrack[Math.floor(fullTrack.length/2)];
|
||||
const trimMap = L.map(mapEl, { zoomControl: false, attributionControl: false })
|
||||
.setView([center.lat, center.lon], 14);
|
||||
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { maxZoom: 19 }).addTo(trimMap);
|
||||
const trimMap = await UI.map.create(mapEl, {
|
||||
center: [center.lat, center.lon], zoom: 14,
|
||||
zoomControl: false, attributionControl: false,
|
||||
});
|
||||
|
||||
// Marker & Polylines
|
||||
let greyBefore = L.polyline([], { color: '#9ca3af', weight: 3, opacity: 0.5 }).addTo(trimMap);
|
||||
|
|
@ -2368,9 +2346,9 @@ window.Page_routes = (() => {
|
|||
route.gps_track = [...route.gps_track].reverse();
|
||||
// Karte neu aufbauen mit umgekehrtem Track
|
||||
const el = document.getElementById('rk-detail-map');
|
||||
if (el && window.L) {
|
||||
if (el) {
|
||||
if (_detailMap) { _detailMap.remove(); _detailMap = null; }
|
||||
_detailMap = _buildDetailMap(el, route.gps_track);
|
||||
_detailMap = await _buildDetailMap(el, route.gps_track);
|
||||
}
|
||||
UI.toast.success('Route dauerhaft umgekehrt');
|
||||
} catch (err) { UI.toast.error(err.message); }
|
||||
|
|
@ -2424,10 +2402,10 @@ window.Page_routes = (() => {
|
|||
|
||||
// Mini-Map
|
||||
let _detailMap = null;
|
||||
setTimeout(() => {
|
||||
setTimeout(async () => {
|
||||
const el = document.getElementById('rk-detail-map');
|
||||
if (!el || !track.length) return;
|
||||
if (window.L) _detailMap = _buildDetailMap(el, track);
|
||||
_detailMap = await _buildDetailMap(el, track);
|
||||
}, 80);
|
||||
|
||||
// Nearby POIs laden
|
||||
|
|
@ -2546,10 +2524,12 @@ window.Page_routes = (() => {
|
|||
}
|
||||
}
|
||||
|
||||
function _buildDetailMap(el, track) {
|
||||
const m = L.map(el, { zoomControl: false, attributionControl: false });
|
||||
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { maxZoom: 19 }).addTo(m);
|
||||
async function _buildDetailMap(el, track) {
|
||||
const lls = track.map(p => [p.lat, p.lon]);
|
||||
const m = await UI.map.create(el, {
|
||||
center: lls[0], zoom: 14,
|
||||
zoomControl: false, attributionControl: false,
|
||||
});
|
||||
const poly = L.polyline(lls, { color: '#C4843A', weight: 4, opacity: 0.85 }).addTo(m);
|
||||
_addRouteArrows(m, track, '#3b82f6');
|
||||
L.circleMarker(lls[0], { radius:7, color:'#22C55E', fillColor:'#22C55E', fillOpacity:1 }).addTo(m);
|
||||
|
|
|
|||
|
|
@ -222,8 +222,7 @@ window.Page_walks = (() => {
|
|||
document.getElementById('walks-map-view').style.display = view === 'karte' ? '' : 'none';
|
||||
|
||||
if (view === 'karte') {
|
||||
UI.loadLeaflet().then(() => {
|
||||
_initMap();
|
||||
_initMap().then(() => {
|
||||
setTimeout(() => _map?.invalidateSize(), 150);
|
||||
setTimeout(() => _map?.invalidateSize(), 400);
|
||||
});
|
||||
|
|
@ -245,8 +244,7 @@ window.Page_walks = (() => {
|
|||
_renderList();
|
||||
_renderMarkers();
|
||||
if (window.innerWidth >= 1024) {
|
||||
UI.loadLeaflet().then(() => {
|
||||
_initMap();
|
||||
_initMap().then(() => {
|
||||
setTimeout(() => _map?.invalidateSize(), 150);
|
||||
setTimeout(() => _map?.invalidateSize(), 400);
|
||||
});
|
||||
|
|
@ -363,13 +361,11 @@ window.Page_walks = (() => {
|
|||
// ----------------------------------------------------------
|
||||
// Leaflet + Karte
|
||||
// ----------------------------------------------------------
|
||||
function _initMap() {
|
||||
async function _initMap() {
|
||||
const el = document.getElementById('walks-map');
|
||||
if (!el || !window.L || _map) return;
|
||||
if (!el || _map) return;
|
||||
const center = _userPos ? [_userPos.lat, _userPos.lon] : [51.1657, 10.4515];
|
||||
_map = L.map('walks-map', { zoomControl: true, attributionControl: false })
|
||||
.setView(center, _userPos ? 12 : 6);
|
||||
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { maxZoom: 19 }).addTo(_map);
|
||||
_map = await UI.map.create('walks-map', { center, zoom: _userPos ? 12 : 6 });
|
||||
_renderMarkers();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="color-scheme" content="light dark">
|
||||
<script src="/js/landing-init.js?v=1106"></script>
|
||||
<script src="/js/landing-init.js?v=1107"></script>
|
||||
<title>Ban Yaro — Die Hunde-App für Deutschland, Österreich & Schweiz</title>
|
||||
<meta name="description" content="Ban Yaro: Die kostenlose All-in-One Hunde-App für DACH. Tagebuch, Giftköder-Alarm, Training mit KI, Forum, Wurfbörse, Stammbaum, Inzucht-Check — DSGVO-konform, offline-fähig, ohne App Store.">
|
||||
<meta name="keywords" content="Hunde App, Hunde Community, Wurfbörse, Züchter, Welpen kaufen, Stammbaum Hund, Inzuchtkoeffizient, Hundezucht, Impfpass Hund, Giftköder Alarm, Gassi Community, Hundetraining App, Hunde Forum, Hunde KI, Hundefilm Datenbank, Welpen Marktplatz">
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
============================================================ */
|
||||
|
||||
// ← EINZIGE Stelle für die Version — STATIC_ASSETS und CACHE_VERSION leiten sich ab
|
||||
const VER = '1106';
|
||||
const VER = '1107';
|
||||
const CACHE_VERSION = `by-v${VER}`;
|
||||
const CACHE_STATIC = `${CACHE_VERSION}-static`;
|
||||
const CACHE_TILES = 'ban-yaro-tiles-v1'; // bleibt über SW-Updates erhalten
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue