Navi: Fenster-Index statt globaler Suche — Loop-Routen brachen Bellen/Fortschritt/Gruen

Praxistest Rene (Gassirunde Siegenhofen, Loop Start=Ende): _closestIdx suchte
GLOBAL -> am Start war der END-Index genauso nah -> Fortschritt sprang ans
Track-Ende: nie Abbiege-Bellen (keine Turns mehr 'vor' einem), done-Linie
malte sofort alles gruen, 99%.
- _closestIdx: Fenster um den aktuellen Index (-15/+80), global nur beim
  ersten Fix (mit Start-Praeferenz bei Quasi-Gleichstand <25m) oder wenn
  verloren (>300m). Simulation auf der echten Route: 13/13 Turns feuern
  bei 41-49m Vorlauf.
- Gelaufener Weg als BREADCRUMB: gruen = auf der Route, rot = daneben
  (Segment-Wechsel nahtlos); done-Linie (Track-Slice-Malen) entfernt —
  nie gelaufene Abschnitte bleiben jetzt orange
- Off-Route-Schwelle 50->35m (Klaeffen kam ~5m zu spaet), Abbiege-Ansage 45->50m
Bump v1250
This commit is contained in:
rene 2026-06-07 08:22:02 +02:00
parent a31d08a2dc
commit 6d9a04fd10
6 changed files with 61 additions and 27 deletions

View file

@ -1 +1 @@
1249
1250

View file

@ -86,14 +86,14 @@
<title>Ban Yaro</title>
<!-- Theme + theme-color Statusleiste vor CSS setzen -->
<script src="/js/boot-early.js?v=1249"></script>
<script src="/js/boot-early.js?v=1250"></script>
<!-- CSS: Reihenfolge ist wichtig — ?v= zwingt Browser zur Neuladung -->
<link rel="stylesheet" href="/css/design-system.css?v=1249">
<link rel="stylesheet" href="/css/layout.css?v=1249">
<link rel="stylesheet" href="/css/components.css?v=1249">
<link rel="stylesheet" href="/css/utilities.css?v=1249">
<link rel="stylesheet" href="/css/lists.css?v=1249">
<link rel="stylesheet" href="/css/design-system.css?v=1250">
<link rel="stylesheet" href="/css/layout.css?v=1250">
<link rel="stylesheet" href="/css/components.css?v=1250">
<link rel="stylesheet" href="/css/utilities.css?v=1250">
<link rel="stylesheet" href="/css/lists.css?v=1250">
</head>
<body>
@ -612,11 +612,11 @@
<div id="modal-container"></div>
<!-- JS: Reihenfolge ist wichtig — erst Basis, dann Features -->
<script src="/js/api.js?v=1249"></script>
<script src="/js/ui.js?v=1249"></script>
<script src="/js/app.js?v=1249"></script>
<script src="/js/worlds.js?v=1249"></script>
<script src="/js/offline-indicator.js?v=1249"></script>
<script src="/js/api.js?v=1250"></script>
<script src="/js/ui.js?v=1250"></script>
<script src="/js/app.js?v=1250"></script>
<script src="/js/worlds.js?v=1250"></script>
<script src="/js/offline-indicator.js?v=1250"></script>
<!-- Feature-Seiten werden lazy geladen -->
@ -626,7 +626,7 @@
<!-- Boot: Offline-Banner + SW-Registration (extrahiert für CSP) -->
<script src="/js/boot.js?v=1249"></script>
<script src="/js/boot.js?v=1250"></script>
</body>

View file

@ -3,7 +3,7 @@
Router, State-Management, Navigation, Initialisierung.
============================================================ */
const APP_VER = '1249'; // ← bei jedem Deploy mit Frontend-Änderungen erhöhen
const APP_VER = '1250'; // ← 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;

View file

@ -1917,8 +1917,25 @@ window.Page_routes = (() => {
_navMap.invalidateSize();
// Route-Polylines: erledigt (grün) + ausstehend (orange)
const doneLine = UI.map.polyline([], { color: '#22c55e', weight: 5, opacity: 0.85 }).addTo(_navMap);
// Geplante Route (orange). Der GELAUFENE Weg wird als Breadcrumb gezeichnet:
// grün = auf der Route, rot = daneben (René 2026-06-07 — vorher malte eine
// done-Linie einfach den Track grün, auch nie gelaufene Abschnitte).
const remainLine = UI.map.polyline(track.map(p => [p.lat, p.lon]), { color: '#f97316', weight: 5, opacity: 0.9 }).addTo(_navMap);
let _walkSeg = null, _walkSegOff = null, _walkLast = null;
const _walkAdd = (lat, lon, off) => {
if (!_navMap) return;
if (_walkLast && _haversineKm(_walkLast[0], _walkLast[1], lat, lon) * 1000 < 2) return; // GPS-Rauschen
if (!_walkSeg || _walkSegOff !== off) {
_walkSegOff = off;
const seed = _walkLast ? [_walkLast, [lat, lon]] : [[lat, lon]]; // nahtloser Übergang
_walkSeg = UI.map.polyline(seed, {
color: off ? '#dc2626' : '#22c55e', weight: 5, opacity: 0.9,
}).addTo(_navMap);
} else {
_walkSeg.addLatLng([lat, lon]);
}
_walkLast = [lat, lon];
};
_navMap.fitBounds(remainLine.getBounds(), { padding: [20, 20] });
_addRouteArrows(_navMap, track, '#3b82f6');
@ -1974,13 +1991,30 @@ window.Page_routes = (() => {
// Hilfsfunktionen
const _navHaversine = (a, b) => _haversineKm(a.lat, a.lon, b.lat, b.lon);
// Fortschritts-Index NUR im Fenster um den aktuellen Index suchen — die globale
// Suche sprang bei RUNDEN (Start ≈ Ende) sofort ans Track-ENDE: nie Abbiege-Bellen,
// alles grün, 99 % ab Start (Praxistest René 2026-06-07, Gassirunde Siegenhofen).
// Global nur beim ersten Fix oder wenn verloren (Fenster-Treffer > 300 m entfernt).
let _navIdxInit = false;
const _closestIdx = (lat, lon) => {
let best = 0, bestD = Infinity;
track.forEach((p, i) => {
const d = _haversineKm(lat, lon, p.lat, p.lon);
if (d < bestD) { bestD = d; best = i; }
});
return best;
const search = (from, to) => {
let best = from, bestD = Infinity;
for (let i = from; i <= to; i++) {
const d = _haversineKm(lat, lon, track[i].lat, track[i].lon);
if (d < bestD) { bestD = d; best = i; }
}
return { best, bestD };
};
if (!_navIdxInit) {
_navIdxInit = true;
// Erster Fix: global, aber bei Quasi-Gleichstand (< 25 m) den START bevorzugen (Loop!)
const g = search(0, track.length - 1);
const s = search(0, Math.min(track.length - 1, 30));
return (s.bestD - g.bestD) * 1000 < 25 ? s.best : g.best;
}
const w = search(Math.max(0, _navCurrentIdx - 15), Math.min(track.length - 1, _navCurrentIdx + 80));
if (w.bestD <= 0.3) return w.best;
return search(0, track.length - 1).best; // verloren → neu orientieren
};
const _remainingKm = (fromIdx) => {
@ -2055,7 +2089,7 @@ window.Page_routes = (() => {
const next = _navTurns.find(t => t.idx > idx && t.idx > _navSndAnnouncedIdx);
if (next) {
const dM = _haversineKm(userLat, userLon, track[next.idx].lat, track[next.idx].lon) * 1000;
if (dM <= 45) {
if (dM <= 50) {
_navSndAnnouncedIdx = next.idx;
if (next.right) NavSound.rechts(); else NavSound.links();
}
@ -2063,7 +2097,7 @@ window.Page_routes = (() => {
}
const offWarn = document.getElementById('rk-nav-offwarn');
if (distToRoute * 1000 > 50) {
if (distToRoute * 1000 > 35) { // 50→35 m: Kläffen kam ~5 m zu spät (René 2026-06-07)
offWarn.style.display = '';
if (navigator.vibrate) navigator.vibrate([200, 100, 200]);
// Falscher Weg = Kläffen (beim Abkommen + Erinnerung alle 30 s)
@ -2077,9 +2111,9 @@ window.Page_routes = (() => {
offWarn.style.display = 'none';
_navSndOffRoute = false;
}
// Polylines aktualisieren
doneLine.setLatLngs(track.slice(0, idx + 1).map(p => [p.lat, p.lon]));
// Verbleibende Route aktualisieren; der gelaufene Weg kommt vom Breadcrumb (s.o.)
remainLine.setLatLngs(track.slice(idx).map(p => [p.lat, p.lon]));
if (userLat != null) _walkAdd(userLat, userLon, distToRoute * 1000 > 35);
};
// GPS-Watch

View file

@ -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=1249"></script>
<script src="/js/landing-init.js?v=1250"></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">

View file

@ -4,7 +4,7 @@
============================================================ */
// ← EINZIGE Stelle für die Version — STATIC_ASSETS und CACHE_VERSION leiten sich ab
const VER = '1249';
const VER = '1250';
const CACHE_VERSION = `by-v${VER}`;
const CACHE_STATIC = `${CACHE_VERSION}-static`;
const CACHE_TILES = 'ban-yaro-tiles-v1'; // bleibt über SW-Updates erhalten