Züge fahren flüssig statt zu springen

Server liefert zusätzlich die Position in 10 s, der Browser
interpoliert dazwischen (~15 fps).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01X48pE4bzjHej8w9HyZXCjb
This commit is contained in:
Guido
2026-10-21 15:00:12 +02:00
co-authored by Claude Opus 5.5
parent d92dac4a00
commit efeba65fb1
3 changed files with 44 additions and 6 deletions
+10 -3
View File
@@ -19,6 +19,7 @@ from . import realtime
from .feed import TZ, Feed
log = logging.getLogger("trainpulse")
AHEAD = 10
WEB = Path(__file__).resolve().parent.parent / "web"
@@ -81,8 +82,14 @@ def poll_realtime():
def compute_positions():
if not S.feed:
return
feats = S.feed.vehicles(time.time(), S.rt)
S.vehicles = json.dumps({"type": "FeatureCollection", "features": feats}, separators=(",", ":")).encode()
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)}
for f in feats:
f["next"] = ahead.get(f["properties"]["id"])
S.vehicles = json.dumps({"type": "FeatureCollection", "ts": now, "ahead": AHEAD, "features": feats},
separators=(",", ":")).encode()
S.vehicles_gz = gzip.compress(S.vehicles, 5)
S.count, S.computed_at = len(feats), time.time()
@@ -102,7 +109,7 @@ app = FastAPI(lifespan=lifespan, docs_url=None, redoc_url=None)
@app.get("/api/vehicles")
def vehicles(request: Request):
headers = {"Cache-Control": "no-store"}
headers = {"Cache-Control": "no-store", "X-Now": str(time.time())} # für den Uhrenabgleich im Browser
if "gzip" in request.headers.get("accept-encoding", ""):
return Response(S.vehicles_gz, media_type="application/json", headers={**headers, "Content-Encoding": "gzip"})
return Response(S.vehicles, media_type="application/json", headers=headers)