Festgehalten als Feature-Plan: Region-Extract per pmtiles (budget-getrieben statt Radius, ~16 MB Default, gemessen 15 MB für 10km München / ~18-22km Land), Client IndexedDB-Blob + MapLibre lokal/remote, adaptives Lernen (rollendes Vorausladen beim Aufzeichnen + Funkloch-Gedächtnis aus echten Fetch-Fehlern, alles lokal), manuelles Vorab-Laden, Budget+LRU. Umsetzung nach Produktions-Rollout.
4.9 KiB
Offline-Karten (GL/Vektor) — Feature-Plan
Status: geplant (Umsetzung nach Tile-Build/Produktions-Rollout der GL-Karten). Stand: 2026-06-05. Autor: René + Claude (Design).
Ziel
GL-Vektorkarten offline-tauglich machen — Kernszenario Gassi/Wandern im Funkloch. Selbst-zielend (cacht wo nötig, nicht überall), speichersparsam, ohne Nutzeraufwand.
Problem (warum GL aktuell NICHT offline geht)
- PMTiles lädt per HTTP-Range (206 Partial Content). Die Cache-API kann 206 nicht speichern
(
cache.put()wirft) → Basemap-Kacheln landen nie im Offline-Cache. - SW hat keine Regel für
/tiles(nur fürtile.openstreetmap.org= altes Raster). offline-indicator.jsprefetcht weiterhin OSM-Raster (a.tile.openstreetmap.org), das die GL-Karte gar nicht nutzt → doppelter Regress: Raster gecacht das niemand zeigt, GL-Karte offline trotzdem leer.- Folge offline heute: App + Daten da, aber GL-Karte = Routenlinie/Marker auf leerem Hintergrund.
Gemessene Speicher-Fakten (an echter dach.pmtiles, maxzoom=14 + Overzoom bis ~16)
| Gebiet | Fläche | Tiles | Größe |
|---|---|---|---|
| München (48,1/11,5), dicht | 20×20 km (10 km Radius) | 252 | 15 MB |
| Bayerischer Wald, ländlich | 20×20 km | 285 | 4,4 MB |
| Bayerischer Wald, ländlich | 50×50 km (~25 km Radius) | 1.595 | 20 MB |
→ Vektor ist ~10× sparsamer als Raster (Raster 10 km ≈ 100–300 MB). Stadt-Tiles ~3,4× dicker als Land.
→ Budget ≈ 16 MB deckt in der Stadt ~10 km, auf dem Land ~18–22 km Radius ab (mehr Reichweite
genau dort wo die Funklöcher sind). Glyphs (~1–2 MB) + Style (winzig) obendrauf → ~17 MB pro Gegend.
→ Messmethode (reproduzierbar): docker run --rm -v /tmp/pmt:/out protomaps/go-pmtiles:latest extract https://staging.banyaro.app/tiles/dach.pmtiles /out/x.pmtiles --bbox=W,S,E,N → Dateigröße ablesen.
Architektur
Region-Extract (budget-getrieben, NICHT fester Radius)
- PMTiles-Directory enthält pro Tile die Byte-Länge → Server kann die Größe einer Region aufsummieren OHNE die Tiles zu laden.
- Endpoint
GET /tiles/region?lat=&lon=&budget=16(MB): wächst die bbox um die Position, bis die summierte Tile-Länge ≈ Budget erreicht (Stadt → kleiner Radius, Land → großer Radius), extrahiert dann genau diese Region alsregion.pmtiles(ein 200er, ~16 MB).pmtiles extract(go-pmtiles) oder python-pmtiles im Container. - Client lädt die Datei einmal → IndexedDB (Blob; 200er, anders als die 206-Ranges cachebar).
- MapLibre liest offline aus dem lokalen Blob via
pmtiles://(pmtiles.js kann aus ArrayBuffer lesen); online weiter remotedach.pmtiles(immer aktuell, ganz DACH+Anrainer). Source je nach Verbindung wählen. - Glyphs (
/fonts/*.pbf, Open Sans Regular+Semibold) mit cachen (200er, cachebar).
Adaptive Strategie (der eigentliche Clou — lernt von selbst)
- Rollendes Vorausladen beim Aufzeichnen: Solange GPS aktiv UND Empfang da, fortlaufend Tiles um die aktuelle Position cachen. Deckt den echten Weg + die Anfahrt automatisch ab — auch beim ersten Mal, bevor man ins Funkloch läuft.
- Funkloch-Gedächtnis: Wo echte Requests scheitern (Timeout/Fehler während aktivem GPS — NICHT
navigator.onLine, das lügt bei Captive-Portal/Schwachempfang), den Bereich als „Offline nötig" markieren → priorisiert behalten, beim nächsten Online-Durchgang großzügiger nachladen. Caveat: im Funkloch selbst kann nicht geladen werden → greift ab dem 2. Besuch (Gassi = repetitiv → ok). - Manuelles Vorab-Laden: Button „Diese Gegend offline speichern" für geplante neue Touren (Lernen deckt nur Bekanntes ab). Fortschritt + „X MB gespeichert" + Löschen/Aktualisieren.
Drumherum
- Budget-Cap + LRU: Gesamtspeicher gedeckelt; selten besuchte Funkloch-Caches fallen raus.
- Privatsphäre: „Wo verliere ich Netz" = Aufenthaltsorte → komplett lokal (IndexedDB), nie hochgeladen.
- Aktualität: Offline-Region beim nächsten Online-Sein neu ziehbar (Basemap-Updates / pmtiles-Refresh).
- Aufräumen: Den alten OSM-Raster-Prefetch in
offline-indicator.jsablösen/abschalten (cacht ungenutztes Raster).
Offene Entscheidungen / Defaults
- Budget-Default 16 MB, optional Stufe „Groß 40 MB" (Stadt ~16 km / Land ~30+ km) für Wandertage.
- Zoom z0–14 (Overzoom liefert Straßenebene gratis).
- Detektionssignal = echte Fetch-Timeouts bei aktivem GPS (nicht
navigator.onLine). - Speicher = IndexedDB (Blobs); MapLibre-Source-Umschaltung online/offline.
Abhängigkeiten
- GL-Tiles in Produktion (dach.pmtiles + fonts auf Prod-Volume) — Voraussetzung.
- pmtiles-Directory-Byte-Summierung (Server) + pmtiles.js Blob-Source (Client).
- WebGL-Kontext-Disziplin beachten (siehe Skill/Memory: jede GL-Karte beim Schließen
remove()).
Siehe docs/TILE_SERVER_HANDOVER.md (Tile-Pipeline) + Memory project_tile_server_maintenance.