"""Builds a self-contained, transparent 3D globe (Globe.gl / Three.js) as an iframe srcdoc, with flight points and animated estimated-path arcs.""" from __future__ import annotations import base64 import json _TEMPLATE = r"""
>> FLIGHTDECK // LIVE TELEMETRY
TARGETS: 0
flight   destination
╌╌ path to destination
""" def build_globe_html(flights, stamp="", focus=None) -> str: """flights: list of dicts from app.normalize_flight(). Returns an iframe.""" points, arcs = [], [] dest_seen = {} # dedup destination cubes by rounded coordinate for f in flights: lat, lon = f.get("lat"), f.get("lon") if lat is None or lon is None: continue alt = f.get("alt") # Plain-text tooltip (htmlElement uses the title attribute). label = ( f"{f.get('callsign') or f.get('flight') or '??'} " f"{f.get('orig') or '?'} -> {f.get('dest') or '?'} | " f"alt {alt or '?'} ft · {f.get('gspeed') or '?'} kt · " f"ETA {f.get('eta_human') or '—'}" ) points.append({ "lat": lat, "lng": lon, "kind": "flight", "alt": 0.015, # sit just above the surface (a marker, not a pole) "label": label, }) ep = f.get("est_path") if ep: arcs.append({ "sLat": lat, "sLng": lon, "eLat": ep[0], "eLng": ep[1], "color": ["#39FF14", "#aaffcc"], "label": f"{f.get('callsign') or '??'} → {f.get('dest') or '?'} · ETA {f.get('eta_human') or '—'}", }) # Grey cube marking the destination airport (deduplicated). key = (round(ep[0], 3), round(ep[1], 3)) if key not in dest_seen: dest_seen[key] = True points.append({ "lat": ep[0], "lng": ep[1], "kind": "dest", "alt": 0.015, "label": f"DEST {f.get('dest') or '?'}", }) data = {"points": points, "arcs": arcs, "stamp": stamp, "focus": focus} html = _TEMPLATE.replace("/*__DATA__*/", json.dumps(data)) b64 = base64.b64encode(html.encode("utf-8")).decode("ascii") return ( f'' )