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:
parent
a31d08a2dc
commit
6d9a04fd10
6 changed files with 61 additions and 27 deletions
2
VERSION
2
VERSION
|
|
@ -1 +1 @@
|
||||||
1249
|
1250
|
||||||
|
|
@ -86,14 +86,14 @@
|
||||||
<title>Ban Yaro</title>
|
<title>Ban Yaro</title>
|
||||||
|
|
||||||
<!-- Theme + theme-color Statusleiste vor CSS setzen -->
|
<!-- 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 -->
|
<!-- CSS: Reihenfolge ist wichtig — ?v= zwingt Browser zur Neuladung -->
|
||||||
<link rel="stylesheet" href="/css/design-system.css?v=1249">
|
<link rel="stylesheet" href="/css/design-system.css?v=1250">
|
||||||
<link rel="stylesheet" href="/css/layout.css?v=1249">
|
<link rel="stylesheet" href="/css/layout.css?v=1250">
|
||||||
<link rel="stylesheet" href="/css/components.css?v=1249">
|
<link rel="stylesheet" href="/css/components.css?v=1250">
|
||||||
<link rel="stylesheet" href="/css/utilities.css?v=1249">
|
<link rel="stylesheet" href="/css/utilities.css?v=1250">
|
||||||
<link rel="stylesheet" href="/css/lists.css?v=1249">
|
<link rel="stylesheet" href="/css/lists.css?v=1250">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
|
|
@ -612,11 +612,11 @@
|
||||||
<div id="modal-container"></div>
|
<div id="modal-container"></div>
|
||||||
|
|
||||||
<!-- JS: Reihenfolge ist wichtig — erst Basis, dann Features -->
|
<!-- JS: Reihenfolge ist wichtig — erst Basis, dann Features -->
|
||||||
<script src="/js/api.js?v=1249"></script>
|
<script src="/js/api.js?v=1250"></script>
|
||||||
<script src="/js/ui.js?v=1249"></script>
|
<script src="/js/ui.js?v=1250"></script>
|
||||||
<script src="/js/app.js?v=1249"></script>
|
<script src="/js/app.js?v=1250"></script>
|
||||||
<script src="/js/worlds.js?v=1249"></script>
|
<script src="/js/worlds.js?v=1250"></script>
|
||||||
<script src="/js/offline-indicator.js?v=1249"></script>
|
<script src="/js/offline-indicator.js?v=1250"></script>
|
||||||
|
|
||||||
<!-- Feature-Seiten werden lazy geladen -->
|
<!-- Feature-Seiten werden lazy geladen -->
|
||||||
|
|
||||||
|
|
@ -626,7 +626,7 @@
|
||||||
|
|
||||||
|
|
||||||
<!-- Boot: Offline-Banner + SW-Registration (extrahiert für CSP) -->
|
<!-- 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>
|
</body>
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
Router, State-Management, Navigation, Initialisierung.
|
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
|
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_VER = APP_VER; // global verfügbar für andere Module (z.B. offline-indicator)
|
||||||
window.APP_VERSION = APP_VERSION;
|
window.APP_VERSION = APP_VERSION;
|
||||||
|
|
|
||||||
|
|
@ -1917,8 +1917,25 @@ window.Page_routes = (() => {
|
||||||
_navMap.invalidateSize();
|
_navMap.invalidateSize();
|
||||||
|
|
||||||
// Route-Polylines: erledigt (grün) + ausstehend (orange)
|
// 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);
|
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] });
|
_navMap.fitBounds(remainLine.getBounds(), { padding: [20, 20] });
|
||||||
_addRouteArrows(_navMap, track, '#3b82f6');
|
_addRouteArrows(_navMap, track, '#3b82f6');
|
||||||
|
|
||||||
|
|
@ -1974,13 +1991,30 @@ window.Page_routes = (() => {
|
||||||
// Hilfsfunktionen
|
// Hilfsfunktionen
|
||||||
const _navHaversine = (a, b) => _haversineKm(a.lat, a.lon, b.lat, b.lon);
|
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) => {
|
const _closestIdx = (lat, lon) => {
|
||||||
let best = 0, bestD = Infinity;
|
const search = (from, to) => {
|
||||||
track.forEach((p, i) => {
|
let best = from, bestD = Infinity;
|
||||||
const d = _haversineKm(lat, lon, p.lat, p.lon);
|
for (let i = from; i <= to; i++) {
|
||||||
if (d < bestD) { bestD = d; best = i; }
|
const d = _haversineKm(lat, lon, track[i].lat, track[i].lon);
|
||||||
});
|
if (d < bestD) { bestD = d; best = i; }
|
||||||
return best;
|
}
|
||||||
|
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) => {
|
const _remainingKm = (fromIdx) => {
|
||||||
|
|
@ -2055,7 +2089,7 @@ window.Page_routes = (() => {
|
||||||
const next = _navTurns.find(t => t.idx > idx && t.idx > _navSndAnnouncedIdx);
|
const next = _navTurns.find(t => t.idx > idx && t.idx > _navSndAnnouncedIdx);
|
||||||
if (next) {
|
if (next) {
|
||||||
const dM = _haversineKm(userLat, userLon, track[next.idx].lat, track[next.idx].lon) * 1000;
|
const dM = _haversineKm(userLat, userLon, track[next.idx].lat, track[next.idx].lon) * 1000;
|
||||||
if (dM <= 45) {
|
if (dM <= 50) {
|
||||||
_navSndAnnouncedIdx = next.idx;
|
_navSndAnnouncedIdx = next.idx;
|
||||||
if (next.right) NavSound.rechts(); else NavSound.links();
|
if (next.right) NavSound.rechts(); else NavSound.links();
|
||||||
}
|
}
|
||||||
|
|
@ -2063,7 +2097,7 @@ window.Page_routes = (() => {
|
||||||
}
|
}
|
||||||
|
|
||||||
const offWarn = document.getElementById('rk-nav-offwarn');
|
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 = '';
|
offWarn.style.display = '';
|
||||||
if (navigator.vibrate) navigator.vibrate([200, 100, 200]);
|
if (navigator.vibrate) navigator.vibrate([200, 100, 200]);
|
||||||
// Falscher Weg = Kläffen (beim Abkommen + Erinnerung alle 30 s)
|
// Falscher Weg = Kläffen (beim Abkommen + Erinnerung alle 30 s)
|
||||||
|
|
@ -2077,9 +2111,9 @@ window.Page_routes = (() => {
|
||||||
offWarn.style.display = 'none';
|
offWarn.style.display = 'none';
|
||||||
_navSndOffRoute = false;
|
_navSndOffRoute = false;
|
||||||
}
|
}
|
||||||
// Polylines aktualisieren
|
// Verbleibende Route aktualisieren; der gelaufene Weg kommt vom Breadcrumb (s.o.)
|
||||||
doneLine.setLatLngs(track.slice(0, idx + 1).map(p => [p.lat, p.lon]));
|
|
||||||
remainLine.setLatLngs(track.slice(idx).map(p => [p.lat, p.lon]));
|
remainLine.setLatLngs(track.slice(idx).map(p => [p.lat, p.lon]));
|
||||||
|
if (userLat != null) _walkAdd(userLat, userLon, distToRoute * 1000 > 35);
|
||||||
};
|
};
|
||||||
|
|
||||||
// GPS-Watch
|
// GPS-Watch
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<meta name="color-scheme" content="light dark">
|
<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>
|
<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="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">
|
<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
|
// ← 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_VERSION = `by-v${VER}`;
|
||||||
const CACHE_STATIC = `${CACHE_VERSION}-static`;
|
const CACHE_STATIC = `${CACHE_VERSION}-static`;
|
||||||
const CACHE_TILES = 'ban-yaro-tiles-v1'; // bleibt über SW-Updates erhalten
|
const CACHE_TILES = 'ban-yaro-tiles-v1'; // bleibt über SW-Updates erhalten
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue