# 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:
```typescript
const maxIntensity = Math.max(0.5, Math.min(0.9, 1.0 - mapZoom * 0.03)); // ❌ BAD
```

**Replace with:**
```typescript
const maxIntensity = 0.75; // ✅ MUST be constant!
```

**B. Heatmap layer not re-rendering** on zoom

Add force re-render:
```typescript
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:
```typescript
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

```typescript
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):**
```typescript
<Rectangle
  bounds={[[minLat, minLon], [maxLat, maxLon]]}
  pathOptions={{ color: '#00ff00', weight: 3, opacity: 1 }}
/>
```

**Change to subtle dashed line:**
```typescript
<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:**
```typescript
// 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

```typescript
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:

```typescript
// 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)

```typescript
// 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:
1. Calculate coverage at zoom 8
2. Note color at specific location (e.g., 3km from site)
3. Zoom to 10, 12, 14, 16
4. Color at same location should NOT change
5. Check console - maxIntensity should always be 0.75

### Calculation Square:
1. Click "Calculate Coverage"
2. Rectangle should be subtle (thin, dashed, gray)
3. OR auto-hide after 2-3 seconds
4. 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

```bash
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! 🚀
