fix: use coverage circles instead of heatmap layer

Replace heatmap layer with concentric circle layers around scanner
positions. This avoids the z-index issue where heatmap appeared at
floor 0 below all markers.

Shows three coverage rings:
- Green inner (good signal ~5m)
- Yellow middle (fair signal ~10m)
- Red outer (weak signal ~15m)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
User
2026-02-01 10:39:20 +01:00
parent 24de6c7f06
commit 4b4cc47e67

View File

@@ -2556,6 +2556,7 @@ function toggleHeatMap() {
} }
// Render heat map layer on 3D map // Render heat map layer on 3D map
// Uses circle layers for scanner coverage visualization
async function renderHeatMap() { async function renderHeatMap() {
if (!map3d || !map3dLoaded) { if (!map3d || !map3dLoaded) {
console.log('[HeatMap] 3D map not ready'); console.log('[HeatMap] 3D map not ready');
@@ -2572,12 +2573,15 @@ async function renderHeatMap() {
// Remove existing heat map if present // Remove existing heat map if present
removeHeatMap(); removeHeatMap();
// Add heat map source // 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', { map3d.addSource('signal-heatmap', {
type: 'geojson', type: 'geojson',
data: { data: {
type: 'FeatureCollection', type: 'FeatureCollection',
features: data.points.map(p => ({ features: scannerPoints.map(p => ({
type: 'Feature', type: 'Feature',
geometry: { type: 'Point', coordinates: [p.lon, p.lat] }, geometry: { type: 'Point', coordinates: [p.lon, p.lat] },
properties: { weight: p.weight } properties: { weight: p.weight }
@@ -2585,24 +2589,42 @@ async function renderHeatMap() {
} }
}); });
// Add heat map layer // Add outer coverage ring (weak signal ~15m)
map3d.addLayer({ map3d.addLayer({
id: 'signal-heatmap-layer', id: 'signal-heatmap-outer',
type: 'heatmap', type: 'circle',
source: 'signal-heatmap', source: 'signal-heatmap',
paint: { paint: {
'heatmap-weight': ['get', 'weight'], 'circle-radius': 80,
'heatmap-intensity': 0.6, 'circle-color': 'rgba(255, 100, 100, 0.15)',
'heatmap-radius': 40, 'circle-stroke-width': 1,
'heatmap-opacity': 0.6, 'circle-stroke-color': 'rgba(255, 100, 100, 0.3)'
'heatmap-color': [ }
'interpolate', ['linear'], ['heatmap-density'], });
0, 'rgba(0,0,255,0)',
0.3, 'rgba(0,255,255,0.5)', // Add middle coverage ring (fair signal ~10m)
0.5, 'rgba(0,255,0,0.6)', map3d.addLayer({
0.7, 'rgba(255,255,0,0.7)', id: 'signal-heatmap-middle',
1, 'rgba(255,0,0,0.8)' 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) { } catch (e) {
@@ -2614,9 +2636,13 @@ async function renderHeatMap() {
function removeHeatMap() { function removeHeatMap() {
if (!map3d) return; if (!map3d) return;
if (map3d.getLayer('signal-heatmap-layer')) { // Remove all heatmap layers
map3d.removeLayer('signal-heatmap-layer'); ['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')) { if (map3d.getSource('signal-heatmap')) {
map3d.removeSource('signal-heatmap'); map3d.removeSource('signal-heatmap');
} }