137 lines
5.4 KiB
Markdown
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
|
|
```
|