Files
audi-app/companion-app/src/screens/Karte.tsx
T
tobias f337820fc8 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>
2026-08-27 17:23:32 +02:00

87 lines
3.0 KiB
TypeScript

/**
* Karte für Fahrtdetails.
*
* Leaflet kommt hier **aus dem Bündel**, nicht von einem CDN. Im alten Panel
* wurde es zur Laufzeit nachgeladen, was auf einem Handy ohne eigenen
* Internetzugang (nur über den VPN-Tunnel erreichbar) stillschweigend nichts
* anzeigte — ein offener Befund des Audits. Die Kacheln selbst bleiben
* zwangsläufig entfernt; fehlen sie, bleibt wenigstens die Karte samt Markern
* bedienbar statt leer.
*/
import { useEffect, useRef } from "react"
import "leaflet/dist/leaflet.css"
export interface Punkt {
lat: number
lon: number
}
// Themeunabhaengig hell wie im Panel (Kartendienste zeigen die
// Standard-Strassenkarte immer hell) - und seit CARTOs anonyme
// basemaps.cartocdn.com-Kacheln einen eigenen API-Schluessel verlangen
// (ohne ihn nur noch "API key required"-Kacheln), die einzige hier weiterhin
// ohne Schluessel nutzbare Quelle.
const KACHEL_URL = "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
const KACHEL_ZUSATZ = "© OpenStreetMap contributors"
export function Karte({
start,
ziel,
route,
}: {
start: Punkt
ziel?: Punkt
/** Echte Streckenlinie aus dem GPS-Verlauf (Backend: screening.py/historienimport.py). */
route?: [number, number][]
}) {
const behaelter = useRef<HTMLDivElement | null>(null)
useEffect(() => {
const element = behaelter.current
if (!element) return
let karte: import("leaflet").Map | null = null
let abgebrochen = false
// Dynamisch geladen, damit Leaflet nicht im Startbündel jeder Seite liegt —
// gebündelt wird es trotzdem, es kommt aus node_modules, nicht aus dem Netz.
void import("leaflet").then((L) => {
if (abgebrochen) return
karte = L.map(element, { attributionControl: true, scrollWheelZoom: false })
L.tileLayer(KACHEL_URL, { attribution: KACHEL_ZUSATZ, maxZoom: 19 }).addTo(karte)
const punkte: [number, number][] = [[start.lat, start.lon]]
L.circleMarker([start.lat, start.lon], { radius: 6, color: "#F50537" })
.bindTooltip("Start")
.addTo(karte)
if (ziel) {
punkte.push([ziel.lat, ziel.lon])
L.circleMarker([ziel.lat, ziel.lon], { radius: 6, color: "#F50537", fill: true })
.bindTooltip("Ziel")
.addTo(karte)
// Echte Route, wenn vorhanden - sonst eine Verbindungslinie NUR zwischen
// den beiden echten Punkten, kein erfundener Verlauf dazwischen.
const linie = route && route.length >= 2 ? route : punkte
L.polyline(linie, { color: "#F50537", weight: 2, dashArray: route && route.length >= 2 ? undefined : "4 6" }).addTo(karte)
if (route && route.length >= 2) punkte.push(...route)
}
if (punkte.length > 1) {
karte.fitBounds(punkte, { padding: [24, 24] })
} else {
karte.setView(punkte[0]!, 14)
}
})
return () => {
abgebrochen = true
karte?.remove()
}
}, [start, ziel, route])
return <div ref={behaelter} className="dm-karte" role="img" aria-label="Karte der Fahrt" />
}