From b248c7e039f1e3a28d10ac0ae90bb5ac9ae997bf Mon Sep 17 00:00:00 2001 From: Claude Dev Date: Tue, 24 Mar 2026 10:31:14 +0100 Subject: [PATCH] GEOINT Performance-Fix: Canvas-Renderer statt DOM-Marker Vorher: 18.000+ DOM-Elemente (divIcon) -> Browser-Absturz Jetzt: Canvas-basierte circleMarker (L.canvas Renderer) - Flugzeuge: max 400 im sichtbaren Bereich, gruene Punkte - Schiffe: max 500 im sichtbaren Bereich, blaue Punkte - Canvas rendert tausende Marker als ein einzelnes HTML-Element - Popups weiterhin per Klick verfuegbar --- src/static/js/geoint.js | 54 ++++++++++++++++++----------------------- 1 file changed, 23 insertions(+), 31 deletions(-) diff --git a/src/static/js/geoint.js b/src/static/js/geoint.js index a071950..eb92999 100644 --- a/src/static/js/geoint.js +++ b/src/static/js/geoint.js @@ -53,6 +53,7 @@ const GEOINT = { if (cb2) cb2.checked = enabled; if (enabled) { + if (!this._canvasRenderer) this._canvasRenderer = L.canvas({ padding: 0.5 }); this._applySatelliteTiles(map); this._createSubControl(map); this._restoreSublayers(map); @@ -202,7 +203,7 @@ const GEOINT = { self._moveDebounce = setTimeout(function() { self._renderFlights(map); self._renderShips(map); - }, 300); + }, 500); }; map.on('moveend', this._moveHandler); }, @@ -256,18 +257,11 @@ const GEOINT = { if (!map || !this._flightLayer || !this._flightsData) return; var newLayer = L.layerGroup(); var bounds = map.getBounds(); - this._flightsData.forEach(function(a) { - if (!a.lat || !a.lon || !bounds.contains([a.lat, a.lon])) return; - var heading = a.track || a.true_heading || 0; - var icon = L.divIcon({ - className: '', - html: '
' + - '' + - '' + - '
', - iconSize: [14, 14], - iconAnchor: [7, 7], - }); + var count = 0; + for (var i = 0; i < this._flightsData.length && count < 400; i++) { + var a = this._flightsData[i]; + if (!a.lat || !a.lon || !bounds.contains([a.lat, a.lon])) continue; + count++; var callsign = (a.flight || a.callsign || a.hex || '???').trim(); var alt = a.alt_baro || a.altitude || '?'; var spd = a.gs || a.ground_speed || '?'; @@ -277,10 +271,12 @@ const GEOINT = { (typ ? ' (' + typ + ')' : '') + '
ALT ' + (typeof alt === 'number' ? alt.toLocaleString() + ' ft' : alt) + '
SPD ' + (typeof spd === 'number' ? Math.round(spd) + ' kts' : spd) + - '
HDG ' + Math.round(heading) + '\u00b0' + ''; - L.marker([a.lat, a.lon], { icon: icon }).bindPopup(popup, { className: 'geoint-leaflet-popup' }).addTo(newLayer); - }); + L.circleMarker([a.lat, a.lon], { + radius: 3, fillColor: '#00ff88', color: '#004422', + fillOpacity: 0.9, weight: 1, renderer: this._canvasRenderer + }).bindPopup(popup, { className: 'geoint-leaflet-popup' }).addTo(newLayer); + } if (this._map) { this._map.removeLayer(this._flightLayer); this._flightLayer = newLayer.addTo(this._map); @@ -345,30 +341,26 @@ const GEOINT = { if (!map || !this._shipsLayer || !this._shipsData) return; var newLayer = L.layerGroup(); var bounds = map.getBounds(); - this._shipsData.forEach(function(s) { - if (!s.lat || !s.lon || !bounds.contains([s.lat, s.lon])) return; - var heading = s.heading || s.cog || 0; + var count = 0; + for (var i = 0; i < this._shipsData.length && count < 500; i++) { + var s = this._shipsData[i]; + if (!s.lat || !s.lon || !bounds.contains([s.lat, s.lon])) continue; + count++; var sog = s.sog || 0; - var icon = L.divIcon({ - className: '', - html: '
' + - '' + - '' + - '
', - iconSize: [10, 10], - iconAnchor: [5, 5], - }); + var color = sog > 0.5 ? '#4499ff' : '#556688'; var mmsi = s.mmsi || '?'; var navLabels = {0:'Motorbetrieb', 1:'Vor Anker', 2:'Nicht steuerbar', 3:'Eingeschraenkt', 5:'Festgemacht', 7:'Fischfang', 8:'Unter Segel'}; var navText = navLabels[s.navStat] || 'Status ' + s.navStat; var popup = '
' + 'MMSI ' + mmsi + '' + '
SOG ' + sog.toFixed(1) + ' kn' + - '
COG ' + Math.round(s.cog || 0) + '\u00b0' + '
NAV ' + navText + '
'; - L.marker([s.lat, s.lon], { icon: icon }).bindPopup(popup, { className: 'geoint-leaflet-popup' }).addTo(newLayer); - }); + L.circleMarker([s.lat, s.lon], { + radius: 2.5, fillColor: color, color: '#223355', + fillOpacity: 0.85, weight: 0.5, renderer: this._canvasRenderer + }).bindPopup(popup, { className: 'geoint-leaflet-popup' }).addTo(newLayer); + } if (this._map) { this._map.removeLayer(this._shipsLayer); this._shipsLayer = newLayer.addTo(this._map);