Pfeil aus Guidos SVG, weiche Drehung entlang der Strecke, Dunkelmodus, lesbare Ortsnamen im Satellit

- Server liefert pro Zug Positionen alle 2 s für die nächsten 10 s,
  der Browser fährt Kurven nach und dreht die Spitze weich (~0,3 s)
- Richtung unter ~2 m Bewegung ignoriert (kein Umklappen am Halt)
- Eigene Icon-Namen (tp-*), die Protomaps-Sprites hatten arrow/dot schon
- Modi Karte / Dunkel / Satellit; im Satellit weisse Schrift mit dunklem Rand

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01X48pE4bzjHej8w9HyZXCjb
This commit is contained in:
Claude
2026-10-21 20:31:46 +02:00
parent 4447c83ef4
commit b013753fc3
3 changed files with 109 additions and 52 deletions
+11 -5
View File
@@ -19,7 +19,7 @@ from . import realtime
from .feed import TZ, Feed
log = logging.getLogger("trainpulse")
AHEAD = 10
STEP, STEPS = 2, 5 # Positionen alle 2 s für die nächsten 10 s, damit der Browser Kurven nachfährt
WEB = Path(__file__).resolve().parent.parent / "web"
@@ -84,11 +84,17 @@ def compute_positions():
return
now = time.time()
feats = S.feed.vehicles(now, S.rt)
# Position in AHEAD s mitliefern: der Browser fährt die Züge damit flüssig dazwischen
ahead = {f["properties"]["id"]: f["geometry"]["coordinates"] for f in S.feed.vehicles(now + AHEAD, S.rt)}
future = [{f["properties"]["id"]: f["geometry"]["coordinates"] for f in S.feed.vehicles(now + STEP * k, S.rt)}
for k in range(1, STEPS + 1)]
for f in feats:
f["next"] = ahead.get(f["properties"]["id"])
S.vehicles = json.dumps({"type": "FeatureCollection", "ts": now, "ahead": AHEAD, "features": feats},
path = []
for pos in future:
p = pos.get(f["properties"]["id"])
if p is None:
break # Fahrt endet
path.append(p)
f["path"] = path
S.vehicles = json.dumps({"type": "FeatureCollection", "ts": now, "step": STEP, "features": feats},
separators=(",", ":")).encode()
S.vehicles_gz = gzip.compress(S.vehicles, 5)
S.count, S.computed_at = len(feats), time.time()