fix: Bandmap now follows freq properly and zoom by ddefault is 32px/Khz
This commit is contained in:
@@ -151,7 +151,7 @@ export function BandMap({ band, spots, spotStatus, currentFreqHz, onSpotClick, o
|
||||
const { t } = useI18n();
|
||||
const range = BAND_RANGES[band];
|
||||
const segments = SEGMENT_COLORS[band] ?? [];
|
||||
const [zoomIdx, setZoomIdx] = useState(0);
|
||||
const [zoomIdx, setZoomIdx] = useState(2); // default 32 px/kHz
|
||||
const scrollerRef = useRef<HTMLDivElement | null>(null);
|
||||
const [containerH, setContainerH] = useState(400);
|
||||
|
||||
@@ -284,36 +284,19 @@ export function BandMap({ band, spots, spotStatus, currentFreqHz, onSpotClick, o
|
||||
const innerH = Math.max(containerH - TOP_PAD - BOT_PAD, span * pxPerKHz);
|
||||
const freqToY = (kHz: number) => TOP_PAD + (1 - (kHz - lo) / span) * innerH;
|
||||
|
||||
// Auto-centre on the rig frequency when the map opens or the band changes
|
||||
// (once per band, so it doesn't fight the user's manual scrolling). Waits
|
||||
// for the scroller height to be measured and a valid in-band rig freq.
|
||||
const centeredForRef = useRef<string>('');
|
||||
// Keep the map centred on the rig frequency: the effect re-runs only when the
|
||||
// frequency actually changes (or band/zoom/size), so tuning follows the rig
|
||||
// while a stable frequency leaves your manual scroll alone.
|
||||
useEffect(() => {
|
||||
if (!range || containerH <= 0 || currentFreqHz <= 0) return;
|
||||
const kHz = currentFreqHz / 1000;
|
||||
if (kHz < lo || kHz > hi) return;
|
||||
if (centeredForRef.current === band) return;
|
||||
const el = scrollerRef.current;
|
||||
if (!el) return;
|
||||
centeredForRef.current = band;
|
||||
el.scrollTop = Math.max(0, freqToY(kHz) - containerH / 2);
|
||||
// freqToY is recomputed each render; intentionally excluded from deps.
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [band, containerH, currentFreqHz, range, lo, hi]);
|
||||
|
||||
// Re-centre on the rig frequency whenever the zoom level changes — zooming
|
||||
// would otherwise drift away from where you're operating. Skips the initial
|
||||
// mount (the band-centre effect above handles that).
|
||||
const firstZoomRef = useRef(true);
|
||||
useEffect(() => {
|
||||
if (firstZoomRef.current) { firstZoomRef.current = false; return; }
|
||||
const el = scrollerRef.current;
|
||||
if (!el || !range || containerH <= 0) return;
|
||||
const kHz = currentFreqHz && currentFreqHz / 1000 >= lo && currentFreqHz / 1000 <= hi
|
||||
? currentFreqHz / 1000 : (lo + hi) / 2;
|
||||
el.scrollTop = Math.max(0, freqToY(kHz) - containerH / 2);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [zoomIdx]);
|
||||
}, [band, containerH, currentFreqHz, range, lo, hi, pxPerKHz]);
|
||||
|
||||
useEffect(() => {
|
||||
const el = scrollerRef.current;
|
||||
@@ -365,16 +348,16 @@ export function BandMap({ band, spots, spotStatus, currentFreqHz, onSpotClick, o
|
||||
|
||||
return (
|
||||
<div className="h-full w-full flex flex-col min-h-0 bg-card">
|
||||
<div className="px-3 py-1.5 text-xs font-semibold uppercase tracking-wider text-muted-foreground bg-muted/40 border-b border-border flex items-center gap-1 shrink-0">
|
||||
<span className="flex-1">{t('bmp.map')} · {band}</span>
|
||||
<div className="px-2 py-1.5 text-xs font-semibold uppercase tracking-wider text-muted-foreground bg-muted/40 border-b border-border flex flex-nowrap items-center gap-0.5 shrink-0">
|
||||
<span className="flex-1 min-w-0 truncate">{t('bmp.map')} · {band}</span>
|
||||
<button type="button" onClick={() => setZoomIdx((z) => Math.max(0, z - 1))} disabled={zoomIdx === 0}
|
||||
className="size-5 inline-flex items-center justify-center rounded hover:bg-muted disabled:opacity-30"
|
||||
className="size-5 shrink-0 inline-flex items-center justify-center rounded hover:bg-muted disabled:opacity-30"
|
||||
title={t('bmp.zoomOut')}>
|
||||
<Minus className="size-3" />
|
||||
</button>
|
||||
<span className="font-mono text-[10px] w-12 text-center">{pxPerKHz}px/kHz</span>
|
||||
<span className="shrink-0 font-mono text-[10px] normal-case tracking-normal whitespace-nowrap px-0.5">{pxPerKHz}px/kHz</span>
|
||||
<button type="button" onClick={() => setZoomIdx((z) => Math.min(PX_PER_KHZ.length - 1, z + 1))} disabled={zoomIdx === PX_PER_KHZ.length - 1}
|
||||
className="size-5 inline-flex items-center justify-center rounded hover:bg-muted disabled:opacity-30"
|
||||
className="size-5 shrink-0 inline-flex items-center justify-center rounded hover:bg-muted disabled:opacity-30"
|
||||
title={t('bmp.zoomIn')}>
|
||||
<Plus className="size-3" />
|
||||
</button>
|
||||
|
||||
Reference in New Issue
Block a user