Fix: Ortsnamen-Layer, InfoBox bei Klick, globale Flugabdeckung

Ortsnamen: Esri World Boundaries als zuschaltbarer Imagery-Layer.
InfoBox: CSS-Ausblendung entfernt, Dark-Theme Styling.
Flugverkehr: Batch-Groesse 3, Pause 3s, zufaellige Reihenfolge —
alle Regionen bekommen Daten statt nur Europa.
Dieser Commit ist enthalten in:
Claude Dev
2026-03-24 11:44:13 +01:00
Ursprung 785c9b1e9e
Commit cbb6596513
3 geänderte Dateien mit 49 neuen und 8 gelöschten Zeilen

Datei anzeigen

@@ -27,10 +27,12 @@ _lock = asyncio.Lock()
_task = None _task = None
import random
async def _fetch_all(): async def _fetch_all():
"""Holt Flugdaten fuer alle Stuetzpunkte.""" """Holt Flugdaten fuer alle Stuetzpunkte."""
now = time.time() now = time.time()
if _cache["data"] and now - _cache["ts"] < 25: if _cache["data"] and now - _cache["ts"] < 45:
return _cache["data"] return _cache["data"]
async with _lock: async with _lock:
@@ -39,9 +41,11 @@ async def _fetch_all():
seen = {} seen = {}
errors = 0 errors = 0
grid = list(_GRID)
random.shuffle(grid)
async with httpx.AsyncClient(timeout=10) as client: async with httpx.AsyncClient(timeout=10) as client:
for i in range(0, len(_GRID), 10): for i in range(0, len(grid), 3):
batch = _GRID[i:i+10] batch = grid[i:i+3]
tasks = [client.get(f"https://api.airplanes.live/v2/point/{lat:.2f}/{lon:.2f}/250") tasks = [client.get(f"https://api.airplanes.live/v2/point/{lat:.2f}/{lon:.2f}/250")
for lat, lon in batch] for lat, lon in batch]
results = await asyncio.gather(*tasks, return_exceptions=True) results = await asyncio.gather(*tasks, return_exceptions=True)
@@ -56,8 +60,8 @@ async def _fetch_all():
seen[h] = ac seen[h] = ac
except Exception: except Exception:
errors += 1 errors += 1
if i + 10 < len(_GRID): if i + 3 < len(grid):
await asyncio.sleep(0.2) await asyncio.sleep(3.0)
_cache["data"] = {"ac": list(seen.values()), "total": len(seen), "errors": errors} _cache["data"] = {"ac": list(seen.values()), "total": len(seen), "errors": errors}
_cache["ts"] = time.time() _cache["ts"] = time.time()
@@ -73,7 +77,7 @@ async def _collector_loop():
await _fetch_all() await _fetch_all()
except Exception as e: except Exception as e:
logger.warning(f"Flight collector error: {e}") logger.warning(f"Flight collector error: {e}")
await asyncio.sleep(30) await asyncio.sleep(60)
def start_flight_collector(): def start_flight_collector():

Datei anzeigen

@@ -19,7 +19,7 @@ html, body { height: 100%; overflow: hidden; background: var(--bg-primary); colo
.cesium-viewer-animationContainer, .cesium-viewer-animationContainer,
.cesium-viewer-timelineContainer, .cesium-viewer-timelineContainer,
.cesium-viewer-fullscreenContainer, .cesium-viewer-fullscreenContainer,
.cesium-viewer-infoBoxContainer,
.cesium-viewer-geocoderContainer, .cesium-viewer-geocoderContainer,
.cesium-viewer-bottom { display: none !important; } .cesium-viewer-bottom { display: none !important; }
.cesium-credit-logoContainer { opacity: 0.3; } .cesium-credit-logoContainer { opacity: 0.3; }
@@ -92,3 +92,23 @@ html, body { height: 100%; overflow: hidden; background: var(--bg-primary); colo
/* === Cesium InfoBox Override === */ /* === Cesium InfoBox Override === */
.cesium-infoBox { background: var(--bg-panel) !important; border: 1px solid var(--border) !important; } .cesium-infoBox { background: var(--bg-panel) !important; border: 1px solid var(--border) !important; }
.cesium-infoBox-title { color: var(--accent) !important; font-family: var(--font-mono) !important; } .cesium-infoBox-title { color: var(--accent) !important; font-family: var(--font-mono) !important; }
/* === InfoBox (Entity-Details bei Klick) === */
.cesium-infoBox {
background: var(--bg-panel) !important;
border: 1px solid var(--border) !important;
border-radius: 8px !important;
box-shadow: 0 8px 32px rgba(0,0,0,0.5) !important;
}
.cesium-infoBox-title {
color: var(--accent) !important;
font-family: var(--font-mono) !important;
font-size: 12px !important;
background: rgba(0,255,136,0.08) !important;
}
.cesium-infoBox-iframe {
background: var(--bg-primary) !important;
}
.cesium-selection-wrapper {
border-color: var(--accent) !important;
}

Datei anzeigen

@@ -5,6 +5,7 @@ const Globe = {
viewer: null, viewer: null,
layers: {}, layers: {},
_statsInterval: null, _statsInterval: null,
_labelsLayer: null,
init() { init() {
// Cesium Ion Token // Cesium Ion Token
@@ -82,6 +83,22 @@ const Globe = {
document.getElementById('bottom-stats').textContent = 'Globe initialisiert — Lade Daten...'; document.getElementById('bottom-stats').textContent = 'Globe initialisiert — Lade Daten...';
}, },
_toggleLabels(on) {
if (on && !this._labelsLayer) {
this._labelsLayer = this.viewer.imageryLayers.addImageryProvider(
new Cesium.UrlTemplateImageryProvider({
url: 'https://server.arcgisonline.com/ArcGIS/rest/services/Reference/World_Boundaries_and_Places/MapServer/tile/{z}/{y}/{x}',
maximumLevel: 18,
credit: 'Esri',
})
);
this._labelsLayer.alpha = 0.9;
} else if (!on && this._labelsLayer) {
this.viewer.imageryLayers.remove(this._labelsLayer);
this._labelsLayer = null;
}
},
_setupLayerToggles() { _setupLayerToggles() {
var toggles = { var toggles = {
'layer-flights': function(on) { on ? FlightsLayer.start(Globe.viewer) : FlightsLayer.stop(); }, 'layer-flights': function(on) { on ? FlightsLayer.start(Globe.viewer) : FlightsLayer.stop(); },
@@ -89,7 +106,7 @@ const Globe = {
'layer-quakes': function(on) { on ? QuakesLayer.start(Globe.viewer) : QuakesLayer.stop(); }, 'layer-quakes': function(on) { on ? QuakesLayer.start(Globe.viewer) : QuakesLayer.stop(); },
'layer-gdelt': function(on) { on ? GdeltLayer.start(Globe.viewer) : GdeltLayer.stop(); }, 'layer-gdelt': function(on) { on ? GdeltLayer.start(Globe.viewer) : GdeltLayer.stop(); },
'layer-daynight': function(on) { Globe.viewer.scene.globe.enableLighting = on; }, 'layer-daynight': function(on) { Globe.viewer.scene.globe.enableLighting = on; },
'layer-labels': function(on) { /* Phase 2 */ }, 'layer-labels': function(on) { Globe._toggleLabels(on); },
}; };
Object.keys(toggles).forEach(function(id) { Object.keys(toggles).forEach(function(id) {
var cb = document.getElementById(id); var cb = document.getElementById(id);