f337820fc8
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>
87 lines
3.0 KiB
TypeScript
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" />
|
|
}
|