Ladebalken bei Layer-Aktivierung + Ortsnamen-Rendering verbessert

- Animierter Ladebalken unter jedem Layer-Toggle bei Datenabruf
- Status-Text (Lade Daten.../Fehler beim Laden)
- Fetch-Wrapper: nur 401 redirected zum Login, nicht 403
- Ortsnamen: minimumLevel, tileWidth/Height, LINEAR Texture-Filter
  fuer konsistente Schriftgroessen beim Laden
Dieser Commit ist enthalten in:
Claude Dev
2026-03-24 12:22:21 +01:00
Ursprung 01f0b375e7
Commit 6f4c5ab3a6
7 geänderte Dateien mit 74 neuen und 5 gelöschten Zeilen

Datei anzeigen

@@ -112,3 +112,40 @@ html, body { height: 100%; overflow: hidden; background: var(--bg-primary); colo
.cesium-selection-wrapper { .cesium-selection-wrapper {
border-color: var(--accent) !important; border-color: var(--accent) !important;
} }
/* === Loading Indicator === */
.layer-loading {
display: none;
height: 2px;
background: var(--accent);
position: relative;
overflow: hidden;
border-radius: 1px;
margin: 4px 0 0;
}
.layer-loading.active {
display: block;
}
.layer-loading::after {
content: '';
position: absolute;
left: -40%;
width: 40%;
height: 100%;
background: linear-gradient(90deg, transparent, #00ff88, transparent);
animation: layer-loading-slide 1s ease-in-out infinite;
}
@keyframes layer-loading-slide {
0% { left: -40%; }
100% { left: 100%; }
}
.layer-status {
font-size: 9px;
color: var(--text-dim);
margin-top: 2px;
display: none;
}
.layer-status.active {
display: block;
}

Datei anzeigen

@@ -21,7 +21,7 @@
opts.headers['Authorization'] = 'Bearer ' + localStorage.getItem('globe_token'); opts.headers['Authorization'] = 'Bearer ' + localStorage.getItem('globe_token');
} }
return _origFetch(url, opts).then(function(r) { return _origFetch(url, opts).then(function(r) {
if (r.status === 401 || r.status === 403) { localStorage.removeItem('globe_token'); window.location.href = '/login'; } if (r.status === 401) { localStorage.removeItem('globe_token'); window.location.href = '/login'; }
return r; return r;
}); });
}; };
@@ -52,24 +52,32 @@
<span class="layer-name">Flugverkehr</span> <span class="layer-name">Flugverkehr</span>
<span class="layer-count" id="count-flights">-</span> <span class="layer-count" id="count-flights">-</span>
</label> </label>
<div class="layer-loading" id="loading-flights"></div>
<div class="layer-status" id="status-flights"></div>
<label class="layer-toggle"> <label class="layer-toggle">
<input type="checkbox" id="layer-ships" checked> <input type="checkbox" id="layer-ships" checked>
<span class="layer-dot dot-ships"></span> <span class="layer-dot dot-ships"></span>
<span class="layer-name">Schiffsverkehr</span> <span class="layer-name">Schiffsverkehr</span>
<span class="layer-count" id="count-ships">-</span> <span class="layer-count" id="count-ships">-</span>
</label> </label>
<div class="layer-loading" id="loading-ships"></div>
<div class="layer-status" id="status-ships"></div>
<label class="layer-toggle"> <label class="layer-toggle">
<input type="checkbox" id="layer-quakes"> <input type="checkbox" id="layer-quakes">
<span class="layer-dot dot-quakes"></span> <span class="layer-dot dot-quakes"></span>
<span class="layer-name">Erdbeben</span> <span class="layer-name">Erdbeben</span>
<span class="layer-count" id="count-quakes">-</span> <span class="layer-count" id="count-quakes">-</span>
</label> </label>
<div class="layer-loading" id="loading-quakes"></div>
<div class="layer-status" id="status-quakes"></div>
<label class="layer-toggle"> <label class="layer-toggle">
<input type="checkbox" id="layer-gdelt"> <input type="checkbox" id="layer-gdelt">
<span class="layer-dot dot-gdelt"></span> <span class="layer-dot dot-gdelt"></span>
<span class="layer-name">Nachrichten</span> <span class="layer-name">Nachrichten</span>
<span class="layer-count" id="count-gdelt">-</span> <span class="layer-count" id="count-gdelt">-</span>
</label> </label>
<div class="layer-loading" id="loading-gdelt"></div>
<div class="layer-status" id="status-gdelt"></div>
</div> </div>
<div class="panel-divider"></div> <div class="panel-divider"></div>
<div class="panel-section"> <div class="panel-section">

Datei anzeigen

@@ -89,11 +89,16 @@ const Globe = {
this._labelsLayer = this.viewer.imageryLayers.addImageryProvider( this._labelsLayer = this.viewer.imageryLayers.addImageryProvider(
new Cesium.UrlTemplateImageryProvider({ new Cesium.UrlTemplateImageryProvider({
url: 'https://server.arcgisonline.com/ArcGIS/rest/services/Reference/World_Boundaries_and_Places/MapServer/tile/{z}/{y}/{x}', url: 'https://server.arcgisonline.com/ArcGIS/rest/services/Reference/World_Boundaries_and_Places/MapServer/tile/{z}/{y}/{x}',
minimumLevel: 1,
maximumLevel: 18, maximumLevel: 18,
tileWidth: 256,
tileHeight: 256,
credit: 'Esri', credit: 'Esri',
}) })
); );
this._labelsLayer.alpha = 0.9; this._labelsLayer.alpha = 0.95;
this._labelsLayer.minificationFilter = Cesium.TextureMinificationFilter.LINEAR;
this._labelsLayer.magnificationFilter = Cesium.TextureMagnificationFilter.LINEAR;
} else if (!on && this._labelsLayer) { } else if (!on && this._labelsLayer) {
this.viewer.imageryLayers.remove(this._labelsLayer); this.viewer.imageryLayers.remove(this._labelsLayer);
this._labelsLayer = null; this._labelsLayer = null;

Datei anzeigen

@@ -28,6 +28,10 @@ const FlightsLayer = {
_fetch() { _fetch() {
var self = this; var self = this;
var loadEl = document.getElementById('loading-flights');
var statusEl = document.getElementById('status-flights');
if (loadEl) loadEl.classList.add('active');
if (statusEl) { statusEl.textContent = 'Lade Daten...'; statusEl.classList.add('active'); }
fetch('/api/flights') fetch('/api/flights')
.then(function(r) { return r.json(); }) .then(function(r) { return r.json(); })
.then(function(data) { .then(function(data) {
@@ -72,6 +76,7 @@ const FlightsLayer = {
}); });
}); });
}) })
.catch(function(e) { console.warn('Flights fetch error:', e); }); .catch(function(e) { console.warn('Flights fetch error:', e); if (statusEl) { statusEl.textContent = 'Fehler beim Laden'; } })
.finally(function() { if (loadEl) loadEl.classList.remove('active'); setTimeout(function() { if (statusEl) statusEl.classList.remove('active'); }, 3000); });
}, },
}; };

Datei anzeigen

@@ -28,6 +28,10 @@ const GdeltLayer = {
_fetch() { _fetch() {
var self = this; var self = this;
var loadEl = document.getElementById('loading-gdelt');
var statusEl = document.getElementById('status-gdelt');
if (loadEl) loadEl.classList.add('active');
if (statusEl) { statusEl.textContent = 'Lade Daten...'; statusEl.classList.add('active'); }
fetch('/api/gdelt') fetch('/api/gdelt')
.then(function(r) { return r.json(); }) .then(function(r) { return r.json(); })
.then(function(data) { .then(function(data) {

Datei anzeigen

@@ -28,6 +28,10 @@ const QuakesLayer = {
_fetch() { _fetch() {
var self = this; var self = this;
var loadEl = document.getElementById('loading-quakes');
var statusEl = document.getElementById('status-quakes');
if (loadEl) loadEl.classList.add('active');
if (statusEl) { statusEl.textContent = 'Lade Daten...'; statusEl.classList.add('active'); }
fetch('/api/quakes') fetch('/api/quakes')
.then(function(r) { return r.json(); }) .then(function(r) { return r.json(); })
.then(function(data) { .then(function(data) {
@@ -66,6 +70,7 @@ const QuakesLayer = {
}); });
}); });
}) })
.catch(function(e) { console.warn('Quakes fetch error:', e); }); .catch(function(e) { console.warn('Quakes fetch error:', e); if (statusEl) { statusEl.textContent = 'Fehler beim Laden'; } })
.finally(function() { if (loadEl) loadEl.classList.remove('active'); setTimeout(function() { if (statusEl) statusEl.classList.remove('active'); }, 3000); });
}, },
}; };

Datei anzeigen

@@ -28,6 +28,10 @@ const ShipsLayer = {
_fetch() { _fetch() {
var self = this; var self = this;
var loadEl = document.getElementById('loading-ships');
var statusEl = document.getElementById('status-ships');
if (loadEl) loadEl.classList.add('active');
if (statusEl) { statusEl.textContent = 'Lade Daten...'; statusEl.classList.add('active'); }
fetch('/api/ships') fetch('/api/ships')
.then(function(r) { return r.json(); }) .then(function(r) { return r.json(); })
.then(function(data) { .then(function(data) {
@@ -72,6 +76,7 @@ const ShipsLayer = {
}); });
}); });
}) })
.catch(function(e) { console.warn('Ships fetch error:', e); }); .catch(function(e) { console.warn('Ships fetch error:', e); if (statusEl) { statusEl.textContent = 'Fehler beim Laden'; } })
.finally(function() { if (loadEl) loadEl.classList.remove('active'); setTimeout(function() { if (statusEl) statusEl.classList.remove('active'); }, 3000); });
}, },
}; };