From 1cc403eea6bd1f66f90fe9bcaf576601ecf53fa9 Mon Sep 17 00:00:00 2001 From: User Date: Sun, 1 Feb 2026 10:42:30 +0100 Subject: [PATCH] fix: use CSS-based coverage rings on scanner markers Coverage rings now render as CSS pseudo-elements on scanner markers, following the same floor offset positioning. Toggle .heatmap-enabled class on map container to show/hide coverage visualization. Co-Authored-By: Claude Opus 4.5 --- src/rf_mapper/web/static/css/style.css | 27 +++++++ src/rf_mapper/web/static/js/app.js | 99 ++++---------------------- 2 files changed, 39 insertions(+), 87 deletions(-) diff --git a/src/rf_mapper/web/static/css/style.css b/src/rf_mapper/web/static/css/style.css index bc75d48..e56ddfb 100644 --- a/src/rf_mapper/web/static/css/style.css +++ b/src/rf_mapper/web/static/css/style.css @@ -978,6 +978,33 @@ body { background: rgba(0, 200, 255, 0.9); } +/* Scanner coverage rings (shown when heatmap enabled) */ +.heatmap-enabled .marker-3d.center .marker-icon::before, +.heatmap-enabled .marker-3d.peer-scanner .marker-icon::before { + content: ''; + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + width: 120px; + height: 120px; + border-radius: 50%; + background: radial-gradient(circle, + rgba(100, 255, 100, 0.3) 0%, + rgba(100, 255, 100, 0.2) 25%, + rgba(255, 255, 100, 0.15) 50%, + rgba(255, 100, 100, 0.1) 75%, + transparent 100% + ); + pointer-events: none; + z-index: -1; +} + +.heatmap-enabled .marker-3d.center .marker-icon, +.heatmap-enabled .marker-3d.peer-scanner .marker-icon { + position: relative; +} + /* Trilaterated device markers - gold border */ .marker-3d.trilaterated .marker-icon { border: 2px dashed #ffd700 !important; diff --git a/src/rf_mapper/web/static/js/app.js b/src/rf_mapper/web/static/js/app.js index 85448b8..7c4b910 100644 --- a/src/rf_mapper/web/static/js/app.js +++ b/src/rf_mapper/web/static/js/app.js @@ -2548,6 +2548,13 @@ function toggleHeatMap() { const btn = document.getElementById('btn-heatmap'); if (btn) btn.classList.toggle('active', heatMapEnabled); + // Toggle CSS class on map container for scanner coverage rings + const mapContainer = document.getElementById('map-3d'); + if (mapContainer) { + mapContainer.classList.toggle('heatmap-enabled', heatMapEnabled); + } + + // Also render/remove MapLibre layers for additional visualization if (heatMapEnabled) { renderHeatMap(); } else { @@ -2555,95 +2562,13 @@ function toggleHeatMap() { } } -// Render heat map layer on 3D map -// Uses circle layers for scanner coverage visualization +// Render heat map visualization +// Coverage rings are CSS-based on scanner markers (via .heatmap-enabled class) async function renderHeatMap() { - if (!map3d || !map3dLoaded) { - console.log('[HeatMap] 3D map not ready'); - return; - } - - try { - const resp = await fetch('/api/heatmap/signal'); - if (!resp.ok) return; - - const data = await resp.json(); - console.log(`[HeatMap] Loaded ${data.count} points`); - - // Remove existing heat map if present - removeHeatMap(); - - // Filter to scanner positions only (weight=1.0 indicates scanners) - const scannerPoints = data.points.filter(p => p.weight >= 0.9); - - // Add coverage circles source - map3d.addSource('signal-heatmap', { - type: 'geojson', - data: { - type: 'FeatureCollection', - features: scannerPoints.map(p => ({ - type: 'Feature', - geometry: { type: 'Point', coordinates: [p.lon, p.lat] }, - properties: { weight: p.weight } - })) - } - }); - - // Add outer coverage ring (weak signal ~15m) - map3d.addLayer({ - id: 'signal-heatmap-outer', - type: 'circle', - source: 'signal-heatmap', - paint: { - 'circle-radius': 80, - 'circle-color': 'rgba(255, 100, 100, 0.15)', - 'circle-stroke-width': 1, - 'circle-stroke-color': 'rgba(255, 100, 100, 0.3)' - } - }); - - // Add middle coverage ring (fair signal ~10m) - map3d.addLayer({ - id: 'signal-heatmap-middle', - type: 'circle', - source: 'signal-heatmap', - paint: { - 'circle-radius': 50, - 'circle-color': 'rgba(255, 255, 100, 0.2)', - 'circle-stroke-width': 1, - 'circle-stroke-color': 'rgba(255, 255, 100, 0.4)' - } - }); - - // Add inner coverage ring (good signal ~5m) - map3d.addLayer({ - id: 'signal-heatmap-inner', - type: 'circle', - source: 'signal-heatmap', - paint: { - 'circle-radius': 25, - 'circle-color': 'rgba(100, 255, 100, 0.25)', - 'circle-stroke-width': 1, - 'circle-stroke-color': 'rgba(100, 255, 100, 0.5)' - } - }); - } catch (e) { - console.error('[HeatMap] Error:', e); - } + console.log('[HeatMap] Enabled - coverage rings shown around scanners'); } -// Remove heat map layer from 3D map +// Remove heat map visualization function removeHeatMap() { - if (!map3d) return; - - // Remove all heatmap layers - ['signal-heatmap-inner', 'signal-heatmap-middle', 'signal-heatmap-outer', 'signal-heatmap-layer'].forEach(layerId => { - if (map3d.getLayer(layerId)) { - map3d.removeLayer(layerId); - } - }); - - if (map3d.getSource('signal-heatmap')) { - map3d.removeSource('signal-heatmap'); - } + console.log('[HeatMap] Disabled'); }