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 = { '
SPD ' + (typeof spd === 'number' ? Math.round(spd) + ' kts' : spd) + '
HDG ' + 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; });