Files
rfcp/docs/devlog/gpu_supp/RFCP-3.10.4-TerrainClick-TxHeight.md
2026-02-07 12:56:25 +02:00

137 lines
5.4 KiB
Markdown

# RFCP — Iteration 3.10.4: Terrain Profile Click Fix & TX Height
## Two bugs remaining from previous iterations.
---
## Bug 1: Terrain Profile click still places ruler point
**Problem:** Clicking inside the Terrain Profile popup (chart area, close button, fresnel checkbox, anywhere in the popup) triggers the map click handler underneath, which places a ruler point or resets the measurement.
**Previous fix was incomplete** — stopPropagation was added to some elements but not the entire popup container and its backdrop.
**Fix:** The Terrain Profile popup needs a FULL click barrier. Every mouse event must be caught:
```typescript
// The OUTERMOST container of the Terrain Profile popup:
<div
className="terrain-profile-container"
onClick={(e) => { e.stopPropagation(); e.nativeEvent.stopImmediatePropagation(); }}
onMouseDown={(e) => { e.stopPropagation(); e.nativeEvent.stopImmediatePropagation(); }}
onMouseUp={(e) => { e.stopPropagation(); e.nativeEvent.stopImmediatePropagation(); }}
onPointerDown={(e) => { e.stopPropagation(); e.nativeEvent.stopImmediatePropagation(); }}
onPointerUp={(e) => { e.stopPropagation(); e.nativeEvent.stopImmediatePropagation(); }}
onDoubleClick={(e) => { e.stopPropagation(); e.nativeEvent.stopImmediatePropagation(); }}
>
{/* All terrain profile content */}
</div>
```
**IMPORTANT:** `stopPropagation()` alone may not be enough because Leaflet listens to DOM events directly, not React synthetic events. The fix MUST also call `e.nativeEvent.stopImmediatePropagation()` to prevent Leaflet's native DOM listener from firing.
**Alternative approach (more robust):** Add the popup OUTSIDE the Leaflet map container in the DOM tree. If the Terrain Profile div is a sibling or parent of the map div (not a child), Leaflet's event delegation won't catch clicks on it at all.
```tsx
// In the main layout:
<div className="app-layout">
<div id="map-container">
{/* Leaflet map renders here */}
</div>
{/* These are OUTSIDE the map container — Leaflet can't intercept */}
{showTerrainProfile && (
<TerrainProfile ... />
)}
{showLinkBudget && (
<LinkBudgetPanel ... />
)}
</div>
```
If moving outside the map container is too much refactoring, the stopImmediatePropagation approach should work. But check: is the TerrainProfile component rendered INSIDE a Leaflet pane or overlay? If so, moving it out is the correct fix.
**Also apply the same fix to:**
- Link Budget Calculator panel
- Any other floating panel/popup that sits over the map
---
## Bug 2: TX Height always shows 2m in Link Budget Calculator
**Problem:** The Link Budget Calculator TRANSMITTER section always shows `Height: 2m` regardless of the actual site configuration. It should read the height from the selected site's settings.
**Root cause:** The LinkBudgetPanel component likely reads `site.height` but the site object might store height in a different field name (e.g., `site.antennaHeight`, `site.towerHeight`, `site.params.height`, or per-sector height).
**Fix:** Find where site height is stored and pass the correct value:
```typescript
// In LinkBudgetPanel.tsx, find where TX height is set:
// WRONG (probably current):
const txHeight = site.height || 2; // Defaults to 2 if field is missing
// Check the actual site data structure. It might be:
const txHeight = site.antennaHeight
|| site.tower_height
|| site.params?.height
|| site.sectors?.[0]?.height // If height is per-sector
|| 30; // Default should be 30m for a typical cell tower, not 2m
// Or if height is stored in meters in a nested config:
const txHeight = selectedSite?.config?.height || selectedSite?.height || 30;
```
**Steps to debug:**
1. In the browser console (F12), find the selected site object
2. Check what field contains the height value
3. Update LinkBudgetPanel to read from the correct field
**Display fix:**
```typescript
// In the TRANSMITTER section of the panel:
<div className="param-row">
<span>Height:</span>
<span>{txHeight} m</span>
</div>
```
The height should also be EDITABLE in the link budget calculator (as an input field, not just display), since you might want to test "what if I put the antenna at 40m instead of 30m?" without changing the actual site config.
```typescript
// Make height an editable field with site value as default:
const [txHeightOverride, setTxHeightOverride] = useState<number | null>(null);
const txHeight = txHeightOverride ?? (site?.height || 30);
<div className="param-row">
<label>Height:</label>
<input
type="number"
value={txHeight}
onChange={(e) => setTxHeightOverride(parseFloat(e.target.value))}
/> m
</div>
```
---
## Testing Checklist
- [ ] Click ANYWHERE inside Terrain Profile popup — NO ruler point placed
- [ ] Click Terrain Profile close button (X) — popup closes, no ruler point
- [ ] Click Fresnel Zone checkbox — toggles, no ruler point
- [ ] Click chart area — no ruler point
- [ ] Drag/scroll inside chart — no map pan/zoom
- [ ] TX Height in Link Budget shows actual site height (not 2m)
- [ ] TX Height is editable for what-if scenarios
- [ ] Changing TX height recalculates link budget
## Commit Message
```
fix(ui): block all click propagation from terrain profile, fix TX height
- Add stopImmediatePropagation on terrain profile container
- Prevent all mouse/pointer events from reaching Leaflet map
- Fix TX height reading from site config (was defaulting to 2m)
- Make TX height editable in link budget calculator
```