Batteriespannung: 8V-Plausibilitätsgrenze; Fahrten: echte Start-/Zielposition und Streckenlinie
Batteriespannung: Werte unter 8V (Sensor-/Verbindungsfehler, nicht physikalisch
plausibel für eine 12V-Bleibatterie) werden nicht mehr erfasst - live und beim
Import. "Neue Räder anlegen"-Knopf sitzt jetzt auf derselben Zeile wie "Montiert".
Fahrten: start_lat/-lon, end_lat/-lon und route wurden bisher nur beim
rückwirkenden Import befüllt, nie bei live erkannten Fahrten (dem Normalfall) -
Screening trägt sie jetzt aus dem GPS-Verlauf nach, unabhängig vom
Kilometerstand-Status. fakeTrack() (eine erfundene Linie) ist entfernt, die
Karte zeichnet jetzt die echte Route oder eine ehrliche Gerade zwischen den
bekannten Punkten. CARTOs anonyme Kartenkacheln verlangen inzwischen einen
API-Schlüssel ("API key required" auf jeder Karte in beiden Apps) - auf
schlüssellose OpenStreetMap-Kacheln umgestellt. Start/Ziel zeigen jetzt Datum
und Uhrzeit über der Adresse; die fehlerhafte "Status"-Zeile ist entfernt.
Batteriespannungs-Diagramm nutzt auf großen Bildschirmen die volle
Spaltenbreite statt einer festen 400px-Deckelung.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1 +1 @@
|
||||
{"version":"2026.8.25.8","sha256":"464c294c6c07dcb636a8ea3bd93c7e525b21722defb41f573e2b31fefade49ea","bytes":235525,"gebaut":"2026-08-27T09:40:45Z"}
|
||||
{"version":"2026.8.27.1","sha256":"d7cd168032a93ed8430e3a86ee583c635004fc3518eecf0d1e69abd78741ebc4","bytes":235552,"gebaut":"2026-08-27T15:13:25Z"}
|
||||
Binary file not shown.
@@ -377,6 +377,10 @@ const dedat = (d) => (gueltigesDatum(d)
|
||||
? d.toLocaleDateString("de-DE", { day: "2-digit", month: "2-digit", year: "numeric" })
|
||||
: "–");
|
||||
function dat(s) { const [d, m, j] = s.split(".").map(Number); return new Date(j, m - 1, d); }
|
||||
/* Datum + Uhrzeit in einer Zeile, für Start-/Zielzeitpunkt der Einzelfahrt. */
|
||||
const dezeitpunkt = (d) => (gueltigesDatum(d)
|
||||
? `${dedat(d)} · ${d.toLocaleTimeString("de-DE", { hour: "2-digit", minute: "2-digit" })} Uhr`
|
||||
: "–");
|
||||
|
||||
const MISCHDAUER = 180;
|
||||
function tagesleistung() {
|
||||
@@ -449,9 +453,14 @@ let BELEG_STATION_POS = null;
|
||||
/* Bewusst themeunabhaengig hell: Kartendienste (Google Maps & Co.) zeigen die
|
||||
Standard-Strassenkarte immer im hellen Stil, weil Strassen, Beschriftungen
|
||||
und Wegfarben darauf lesbar bleiben. Die frueher bei Nacht eingeblendeten
|
||||
dark_all-Kacheln liessen die Karte im Panel schwarz wirken. */
|
||||
const TILE_URL = "https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}{r}.png";
|
||||
const ATTR = "© OpenStreetMap · CARTO";
|
||||
dark_all-Kacheln liessen die Karte im Panel schwarz wirken.
|
||||
CARTOs anonyme basemaps.cartocdn.com-Kacheln (vorher hier) verlangen
|
||||
inzwischen einen eigenen API-Schlüssel - ohne ihn zeigten die Kacheln nur
|
||||
noch "API key required". Die Standard-OpenStreetMap-Kacheln sind weiterhin
|
||||
ohne Schlüssel nutzbar und decken diesen Bedarf (ein Fahrzeug, geringes
|
||||
Kartenaufkommen) ohne eigenen Dienst. */
|
||||
const TILE_URL = "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png";
|
||||
const ATTR = "© OpenStreetMap contributors";
|
||||
/* Satellitenansicht der Standort-Vollbildkarte (Layer-Knopf) - wie die
|
||||
CARTO-Straßenkacheln oben ohne eigenen Schlüssel nutzbar. */
|
||||
const SAT_TILE_URL = "https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}";
|
||||
@@ -527,15 +536,6 @@ function kartenMittelpunkt() {
|
||||
return pos && pos.length === 2 ? pos : [51.1657, 10.4515];
|
||||
}
|
||||
|
||||
function fakeTrack(a, b, n = 13) {
|
||||
const pts = []; let seed = Math.round((a[0] + b[1]) * 1000);
|
||||
const rnd = () => { seed = (seed * 1103515245 + 12345) & 0x7fffffff; return seed / 0x7fffffff - 0.5; };
|
||||
for (let i = 0; i <= n; i++) {
|
||||
const t = i / n, k = Math.sin(t * Math.PI);
|
||||
pts.push([a[0] + (b[0] - a[0]) * t + rnd() * 0.05 * k, a[1] + (b[1] - a[1]) * t + rnd() * 0.05 * k]);
|
||||
}
|
||||
pts[0] = a; pts[n] = b; return pts;
|
||||
}
|
||||
function tiles() {
|
||||
if (!MAP || !window.L) return;
|
||||
const url = TILE_URL;
|
||||
@@ -552,14 +552,20 @@ async function initMap() {
|
||||
if (route.name === "trip") {
|
||||
const t = TRIPS.find((x) => x.trip_id === route.id);
|
||||
if (t && t.start_lat != null && t.end_lat != null) {
|
||||
const track = fakeTrack([t.start_lat, t.start_lon], [t.end_lat, t.end_lon]);
|
||||
const line = window.L.polyline(track, { color: rot, weight: 2.5, opacity: 0.9 }).addTo(MAP);
|
||||
// Echte Streckenlinie aus dem GPS-Verlauf (route, screening.py), wenn
|
||||
// vorhanden - sonst eine ehrliche gerade Linie zwischen Start und Ziel,
|
||||
// keine erfundene Kurve mehr (siehe companion-app/Karte.tsx, dieselbe
|
||||
// Haltung: keine Route zu zeigen, die es so nicht gab).
|
||||
const track = Array.isArray(t.route) && t.route.length >= 2
|
||||
? t.route
|
||||
: [[t.start_lat, t.start_lon], [t.end_lat, t.end_lon]];
|
||||
const line = window.L.polyline(track, { color: rot, weight: 2.5, opacity: 0.9, dashArray: Array.isArray(t.route) && t.route.length >= 2 ? null : "4 6" }).addTo(MAP);
|
||||
track.slice(1, -1).forEach((pt) => window.L.circleMarker(pt, { radius: 2.5, color: rot, weight: 0, fillColor: rot, fillOpacity: 0.85 }).addTo(MAP));
|
||||
window.L.circleMarker([t.start_lat, t.start_lon], { radius: 6, color: "#fff", weight: 2, fillColor: "#000", fillOpacity: 1 }).addTo(MAP).bindPopup("Start · " + (t.start_address || ""));
|
||||
window.L.circleMarker([t.end_lat, t.end_lon], { radius: 6, color: rot, weight: 2, fillColor: rot, fillOpacity: 1 }).addTo(MAP).bindPopup("Ziel · " + (t.end_address || ""));
|
||||
MAP.fitBounds(line.getBounds(), { padding: [26, 26] });
|
||||
} else {
|
||||
MAP.setView(kartenMittelpunkt(), 11); // kein Track ohne GPS-Daten (§7a-Backend-Lücke)
|
||||
MAP.setView(kartenMittelpunkt(), 11); // kein Track ohne GPS-Daten
|
||||
}
|
||||
} else if (route.name === "fill") {
|
||||
BELEG_STATION_POS = null; // gehört zum vorherigen Beleg, sonst zentriert der Knopf falsch
|
||||
@@ -1804,7 +1810,7 @@ function vBatterieverlauf() {
|
||||
</div>
|
||||
${genug ? `
|
||||
<div id="bvChart" style="margin-top:14px;touch-action:none;position:relative">
|
||||
<svg id="bvSvg" viewBox="0 0 ${BV_W} ${BV_H}" preserveAspectRatio="none" style="width:100%;height:170px;display:block"></svg>
|
||||
<svg id="bvSvg" viewBox="0 0 ${BV_W} ${BV_H}" preserveAspectRatio="none" style="width:100%;aspect-ratio:${BV_W}/${BV_H};display:block"></svg>
|
||||
</div>
|
||||
<div style="display:flex;justify-content:space-between;align-items:center;margin-top:10px">
|
||||
<span class="label" id="bvRange" style="margin-top:0"></span>
|
||||
@@ -2886,8 +2892,8 @@ function vReifen() {
|
||||
<button type="button" data-bildersetzen="${radDatei}">Foto ersetzen</button>
|
||||
<button type="button" class="loeschen" data-bildloeschen="${radDatei}">Löschen</button>
|
||||
</div>` : ""}
|
||||
<button data-satz="${k === "sommer" ? "Sommer" : "Winter"}" class="montiert ${aktiv ? "on" : ""}">Montiert</button>
|
||||
<div style="display:flex;justify-content:flex-end;margin-top:10px">
|
||||
<div style="display:flex;justify-content:space-between;align-items:center">
|
||||
<button data-satz="${k === "sommer" ? "Sommer" : "Winter"}" class="montiert ${aktiv ? "on" : ""}">Montiert</button>
|
||||
<button class="iconbtn" data-reifenarchivieren="${k}" aria-label="Neue Räder anlegen">${ciSVG(CI.packageS, 18)}</button>
|
||||
</div>
|
||||
<div style="margin-top:12px">
|
||||
@@ -3150,13 +3156,12 @@ function vTrip(id) {
|
||||
style="cursor:pointer;font-family:inherit">${artText(t.art)}</button></div>
|
||||
</div>
|
||||
<div class="tile"><dl class="rows">
|
||||
<div class="row"><dt>Startort</dt><dd>${esc(t.start_address || "unbekannt")}<small>${dedat(new Date(t.ts_start))}</small></dd></div>
|
||||
<div class="row"><dt>Zielort</dt><dd>${esc(t.end_address || "unbekannt")}</dd></div>
|
||||
<div class="row"><dt>Start</dt><dd>${dezeitpunkt(new Date(t.ts_start))}<small>${esc(t.start_address || "unbekannt")}</small></dd></div>
|
||||
<div class="row"><dt>Ziel</dt><dd>${dezeitpunkt(new Date(t.ts_end))}<small>${esc(t.end_address || "unbekannt")}</small></dd></div>
|
||||
<div class="row"><dt>Startkilometer</dt><dd>${t.odo_start != null ? de(t.odo_start) + " km" : "noch offen"}</dd></div>
|
||||
<div class="row"><dt>Endkilometer</dt><dd>${t.odo_end != null ? de(t.odo_end) + " km" : "noch offen"}</dd></div>
|
||||
<div class="row"><dt>Dauer</dt><dd>${dauerText(t.duration_s)}</dd></div>
|
||||
<div class="row"><dt>Verbrauch</dt><dd>${fahrtVerbrauch(t) != null ? de(fahrtVerbrauch(t), 1) + " l/100 km" : "liegt nicht vor"}<small>vom Fahrzeug gemeldet</small></dd></div>
|
||||
<div class="row"><dt>Status</dt><dd>${t.status}<small>Quelle: ${t.km_quelle || "–"}</small></dd></div>
|
||||
</dl>
|
||||
<button class="aktion" data-fahrtbearbeiten>Werte bearbeiten</button>
|
||||
</div>
|
||||
|
||||
@@ -336,12 +336,14 @@ main#view{--seitenrand:16px;padding:0 var(--seitenrand) 30px;scroll-behavior:smo
|
||||
.standortmenu{max-width:640px;margin-left:auto;margin-right:auto}
|
||||
|
||||
/* Batteriespannungs-Diagramm ist auf BV_W=320 SVG-Einheiten gezeichnet
|
||||
(audi-dashboard-app.js) und haelt seine Hoehe fest bei 170px - bei voller
|
||||
Spaltenbreite (772px Inhaltsbreite: 860 - 2*44px Seitenrand) zog
|
||||
preserveAspectRatio="none" das Diagramm zu einem extrem breiten, flachen
|
||||
Band auseinander. Gedeckelt wie die Popups oben, statt die feste Hoehe
|
||||
oder die BV_*-Zeichen-Logik anzufassen. */
|
||||
#bvChart{max-width:400px;margin-left:auto;margin-right:auto}
|
||||
(audi-dashboard-app.js), vorher mit fester Hoehe von 170px bei
|
||||
preserveAspectRatio="none" - bei voller Spaltenbreite (772px
|
||||
Inhaltsbreite: 860 - 2*44px Seitenrand) zog das Diagramm zu einem extrem
|
||||
breiten, flachen Band auseinander, gedeckelt mit max-width:400px (macht
|
||||
es dafuer auf grossen Bildschirmen unnoetig klein). Das SVG traegt jetzt
|
||||
ein aspect-ratio passend zum viewBox-Verhaeltnis (320/170), wodurch die
|
||||
Hoehe mit der Breite mitwaechst - das Diagramm darf deshalb die volle
|
||||
Spaltenbreite nutzen, ohne wieder zu verzerren. */
|
||||
}
|
||||
|
||||
/* Fahrzeugbild randlos wie in einer Fahrzeug-App: der Platzhalter bleibt
|
||||
|
||||
Reference in New Issue
Block a user