6.4 KiB
RFCP - Quick Fix: Zoom Gradient + Calculation Square
Issue 1: Zoom Still Breaks Gradient
Problem: Despite maxIntensity=0.75, colors still shift with zoom.
Debug: Check console for 🔍 Heatmap Debug - what does it show?
Possible Root Causes:
A. maxIntensity is STILL a formula (not constant)
File: frontend/src/components/map/Heatmap.tsx
Check if this line exists:
const maxIntensity = Math.max(0.5, Math.min(0.9, 1.0 - mapZoom * 0.03)); // ❌ BAD
Replace with:
const maxIntensity = 0.75; // ✅ MUST be constant!
B. Heatmap layer not re-rendering on zoom
Add force re-render:
const [key, setKey] = useState(0);
useEffect(() => {
const handleZoomEnd = () => {
setMapZoom(map.getZoom());
setKey(prev => prev + 1); // Force re-render
};
map.on('zoomend', handleZoomEnd);
return () => { map.off('zoomend', handleZoomEnd); };
}, [map]);
return (
<div style={{ opacity }} key={key}> {/* ← Add key */}
<HeatmapLayer ... />
</div>
);
C. RSRP normalization range too narrow
Try wider range:
const normalizeRSRP = (rsrp: number): number => {
const minRSRP = -140; // Even wider (was -130)
const maxRSRP = -40; // Even wider (was -50)
const normalized = (rsrp - minRSRP) / (maxRSRP - minRSRP);
return Math.max(0, Math.min(1, normalized));
};
Nuclear Option: Remove Dynamic Parameters Entirely
export function Heatmap({ points, visible, opacity = 0.7 }: HeatmapProps) {
const map = useMap();
if (!visible || points.length === 0) return null;
// FIXED RSRP normalization
const normalizeRSRP = (rsrp: number): number => {
return Math.max(0, Math.min(1, (rsrp + 140) / 100)); // -140 to -40 dBm
};
const heatmapPoints = points.map(p => [
p.lat,
p.lon,
normalizeRSRP(p.rsrp)
] as [number, number, number]);
// CONSTANT parameters (NO zoom dependency!)
return (
<div style={{ opacity }}>
<HeatmapLayer
points={heatmapPoints}
longitudeExtractor={(p) => p[1]}
latitudeExtractor={(p) => p[0]}
intensityExtractor={(p) => p[2]}
gradient={{
0.0: '#1a237e',
0.2: '#2196f3',
0.4: '#00bcd4',
0.5: '#4caf50',
0.6: '#8bc34a',
0.7: '#ffeb3b',
0.8: '#ff9800',
1.0: '#f44336',
}}
radius={25} // FIXED (no zoom logic)
blur={15} // FIXED
max={0.75} // FIXED
minOpacity={0.3}
/>
</div>
);
}
Issue 2: Calculation Square Too Visible
Problem: Green rectangle shows calculation bounds - too distracting.
Option A: Make It Subtle
File: Find where calculation bounds are drawn (probably in Map or Coverage component)
Current (green bold line):
<Rectangle
bounds={[[minLat, minLon], [maxLat, maxLon]]}
pathOptions={{ color: '#00ff00', weight: 3, opacity: 1 }}
/>
Change to subtle dashed line:
<Rectangle
bounds={[[minLat, minLon], [maxLat, maxLon]]}
pathOptions={{
color: '#666', // Gray (was green)
weight: 1, // Thin (was 3)
opacity: 0.3, // Transparent (was 1)
dashArray: '5, 5', // Dashed
fillOpacity: 0 // No fill
}}
/>
Option B: Hide It Entirely
Add toggle:
// In settings store
showCalculationBounds: false, // Default hidden
// In Map component
{showCalculationBounds && (
<Rectangle ... />
)}
// In UI
<label>
<input
type="checkbox"
checked={showCalculationBounds}
onChange={(e) => setShowCalculationBounds(e.target.checked)}
/>
Show Calculation Bounds
</label>
Option C: Auto-Hide After Calculation
const [showBounds, setShowBounds] = useState(false);
// When calculation starts
setShowBounds(true);
// After calculation completes
setTimeout(() => setShowBounds(false), 3000); // Hide after 3s
{showBounds && <Rectangle ... />}
Option D: Progress Indicator Instead
Replace rectangle with corner markers:
// Instead of full rectangle, show 4 corner circles
{calculationBounds && (
<>
<CircleMarker center={[minLat, minLon]} radius={3} color="#666" />
<CircleMarker center={[maxLat, minLon]} radius={3} color="#666" />
<CircleMarker center={[minLat, maxLon]} radius={3} color="#666" />
<CircleMarker center={[maxLat, maxLon]} radius={3} color="#666" />
</>
)}
Recommended Fix
File: frontend/src/components/map/Map.tsx (or wherever Rectangle is)
// Find the calculation bounds Rectangle and replace with:
{calculationInProgress && (
<Rectangle
bounds={calculationBounds}
pathOptions={{
color: '#3b82f6', // Blue
weight: 1,
opacity: 0.5,
dashArray: '3, 3',
fillOpacity: 0
}}
/>
)}
// Auto-hide after calculation completes:
useEffect(() => {
if (!calculationInProgress && calculationBounds) {
const timer = setTimeout(() => {
setCalculationBounds(null);
}, 2000);
return () => clearTimeout(timer);
}
}, [calculationInProgress]);
Testing
Zoom Gradient:
- Calculate coverage at zoom 8
- Note color at specific location (e.g., 3km from site)
- Zoom to 10, 12, 14, 16
- Color at same location should NOT change
- Check console - maxIntensity should always be 0.75
Calculation Square:
- Click "Calculate Coverage"
- Rectangle should be subtle (thin, dashed, gray)
- OR auto-hide after 2-3 seconds
- Should not distract from heatmap
Quick Apply
For Claude Code:
Fix two remaining issues:
1. Heatmap zoom gradient:
- Ensure maxIntensity is CONSTANT 0.75 (not a formula)
- Remove ALL zoom-dependent parameters from HeatmapLayer
- Make radius/blur/max all fixed values
- Test: same location = same color at any zoom
2. Calculation bounds rectangle:
- Make it subtle: gray, thin (weight: 1), dashed, opacity: 0.3
- OR auto-hide 2 seconds after calculation completes
- Should not distract from coverage heatmap
Test gradient thoroughly at zoom levels 8, 10, 12, 14, 16.
Build & Test
cd /opt/rfcp/frontend
npm run build
sudo systemctl reload caddy
# Open https://rfcp.eliah.one
# Test zoom gradient (critical!)
# Check calculation bounds visibility
Віддати на Claude Code ці 2 фікси? Після цього можна братись за Backend! 🚀