diff --git a/src/routers/geoint.py b/src/routers/geoint.py
index a407211..65dd7ce 100644
--- a/src/routers/geoint.py
+++ b/src/routers/geoint.py
@@ -45,8 +45,8 @@ async def get_flights(
_user: dict = Depends(get_current_user),
):
"""Proxy fuer airplanes.live API. 10s Cache, max 300 Aircraft."""
- cache_key = f"flights:{round(lat, 1)}:{round(lon, 1)}:{radius}"
- cached = _get_cached(cache_key, ttl=10)
+ cache_key = f"flights:{round(lat*2)/2:.1f}:{round(lon*2)/2:.1f}:{radius}"
+ cached = _get_cached(cache_key, ttl=20)
if cached:
return cached
diff --git a/src/static/js/geoint.js b/src/static/js/geoint.js
index b5e6a20..69c9503 100644
--- a/src/static/js/geoint.js
+++ b/src/static/js/geoint.js
@@ -189,11 +189,11 @@ const GEOINT = {
this._flightLayer = L.layerGroup().addTo(map);
var self = this;
this._fetchFlights(map);
- this._flightInterval = setInterval(function() { self._fetchFlights(map); }, 15000);
+ this._flightInterval = setInterval(function() { self._fetchFlights(map); }, 30000);
// Bei Kartenbewegung neu laden
this._moveHandler = function() {
clearTimeout(self._moveDebounce);
- self._moveDebounce = setTimeout(function() { self._fetchFlights(map); }, 1200);
+ self._moveDebounce = setTimeout(function() { self._fetchFlights(map); }, 2000);
};
map.on('moveend', this._moveHandler);
},
@@ -207,32 +207,19 @@ const GEOINT = {
_fetchFlights(map) {
if (this._flightFetching || !map || map.getZoom() < 3) return;
this._flightFetching = true;
- var bounds = map.getBounds();
+ var center = map.getCenter();
var self = this;
var token = localStorage.getItem('osint_token') || '';
var headers = token ? { 'Authorization': 'Bearer ' + token } : {};
- // Grid-Punkte berechnen fuer vollstaendige Abdeckung
- var points = this._calcGridPoints(bounds);
-
- Promise.all(points.map(function(p) {
- return fetch('/api/geoint/flights?lat=' + p.lat.toFixed(4) + '&lon=' + p.lon.toFixed(4) + '&radius=' + p.radius, { headers: headers })
- .then(function(r) { return r.ok ? r.json() : { ac: [] }; })
- .catch(function() { return { ac: [] }; });
- }))
- .then(function(results) {
+ fetch('/api/geoint/flights?lat=' + center.lat.toFixed(2) + '&lon=' + center.lng.toFixed(2) + '&radius=250', { headers: headers })
+ .then(function(r) { return r.ok ? r.json() : { ac: [] }; })
+ .then(function(data) {
if (!self._flightLayer) return;
- self._flightLayer.clearLayers();
- // Alle Ergebnisse zusammenfuehren, Duplikate per hex entfernen
- var seen = {};
- var allAc = [];
- results.forEach(function(data) {
- (data.ac || data.aircraft || []).forEach(function(a) {
- var key = a.hex || (a.lat + ',' + a.lon);
- if (!seen[key]) { seen[key] = true; allAc.push(a); }
- });
- });
- allAc.slice(0, 500).forEach(function(a) {
+ // Neue Marker in temporaerem Layer bauen, dann atomar swappen
+ var newLayer = L.layerGroup();
+ var ac = data.ac || data.aircraft || [];
+ ac.slice(0, 500).forEach(function(a) {
if (!a.lat || !a.lon) return;
var heading = a.track || a.true_heading || 0;
var icon = L.divIcon({
@@ -255,8 +242,13 @@ const GEOINT = {
'
' + (typeof spd === 'number' ? Math.round(spd) + ' kts' : spd) +
'
' + Math.round(heading) + '°' +
'';
- L.marker([a.lat, a.lon], { icon: icon }).bindPopup(popup, { className: 'geoint-leaflet-popup' }).addTo(self._flightLayer);
+ L.marker([a.lat, a.lon], { icon: icon }).bindPopup(popup, { className: 'geoint-leaflet-popup' }).addTo(newLayer);
});
+ // Atomar swappen: alte Marker entfernen, neue hinzufuegen
+ if (self._map && self._flightLayer) {
+ self._map.removeLayer(self._flightLayer);
+ self._flightLayer = newLayer.addTo(self._map);
+ }
})
.catch(function(e) { if (typeof DEV_MODE !== 'undefined' && DEV_MODE) console.warn('GEOINT flights:', e); })
.finally(function() { self._flightFetching = false; });