diff --git a/static/css/globe.css b/static/css/globe.css
index 241fb6a..04a6e7d 100644
--- a/static/css/globe.css
+++ b/static/css/globe.css
@@ -112,3 +112,40 @@ html, body { height: 100%; overflow: hidden; background: var(--bg-primary); colo
.cesium-selection-wrapper {
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;
+}
diff --git a/static/index.html b/static/index.html
index c08aae6..d588f46 100644
--- a/static/index.html
+++ b/static/index.html
@@ -21,7 +21,7 @@
opts.headers['Authorization'] = 'Bearer ' + localStorage.getItem('globe_token');
}
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;
});
};
@@ -52,24 +52,32 @@
Flugverkehr
-
+
+
+
+
+
+
+
+
diff --git a/static/js/app.js b/static/js/app.js
index cc81909..6c81153 100644
--- a/static/js/app.js
+++ b/static/js/app.js
@@ -89,11 +89,16 @@ const Globe = {
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}',
+ minimumLevel: 1,
maximumLevel: 18,
+ tileWidth: 256,
+ tileHeight: 256,
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) {
this.viewer.imageryLayers.remove(this._labelsLayer);
this._labelsLayer = null;
diff --git a/static/js/layers/flights.js b/static/js/layers/flights.js
index 25f3078..3474c0b 100644
--- a/static/js/layers/flights.js
+++ b/static/js/layers/flights.js
@@ -28,6 +28,10 @@ const FlightsLayer = {
_fetch() {
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')
.then(function(r) { return r.json(); })
.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); });
},
};
diff --git a/static/js/layers/gdelt.js b/static/js/layers/gdelt.js
index 70cebbc..0966625 100644
--- a/static/js/layers/gdelt.js
+++ b/static/js/layers/gdelt.js
@@ -28,6 +28,10 @@ const GdeltLayer = {
_fetch() {
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')
.then(function(r) { return r.json(); })
.then(function(data) {
diff --git a/static/js/layers/quakes.js b/static/js/layers/quakes.js
index 8e2f72e..e3f186b 100644
--- a/static/js/layers/quakes.js
+++ b/static/js/layers/quakes.js
@@ -28,6 +28,10 @@ const QuakesLayer = {
_fetch() {
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')
.then(function(r) { return r.json(); })
.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); });
},
};
diff --git a/static/js/layers/ships.js b/static/js/layers/ships.js
index 9d4d59b..bc482f3 100644
--- a/static/js/layers/ships.js
+++ b/static/js/layers/ships.js
@@ -28,6 +28,10 @@ const ShipsLayer = {
_fetch() {
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')
.then(function(r) { return r.json(); })
.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); });
},
};