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 { t } = useI18n();
|
||||||
const range = BAND_RANGES[band];
|
const range = BAND_RANGES[band];
|
||||||
const segments = SEGMENT_COLORS[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 scrollerRef = useRef<HTMLDivElement | null>(null);
|
||||||
const [containerH, setContainerH] = useState(400);
|
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 innerH = Math.max(containerH - TOP_PAD - BOT_PAD, span * pxPerKHz);
|
||||||
const freqToY = (kHz: number) => TOP_PAD + (1 - (kHz - lo) / span) * innerH;
|
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
|
// Keep the map centred on the rig frequency: the effect re-runs only when the
|
||||||
// (once per band, so it doesn't fight the user's manual scrolling). Waits
|
// frequency actually changes (or band/zoom/size), so tuning follows the rig
|
||||||
// for the scroller height to be measured and a valid in-band rig freq.
|
// while a stable frequency leaves your manual scroll alone.
|
||||||
const centeredForRef = useRef<string>('');
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!range || containerH <= 0 || currentFreqHz <= 0) return;
|
if (!range || containerH <= 0 || currentFreqHz <= 0) return;
|
||||||
const kHz = currentFreqHz / 1000;
|
const kHz = currentFreqHz / 1000;
|
||||||
if (kHz < lo || kHz > hi) return;
|
if (kHz < lo || kHz > hi) return;
|
||||||
if (centeredForRef.current === band) return;
|
|
||||||
const el = scrollerRef.current;
|
const el = scrollerRef.current;
|
||||||
if (!el) return;
|
if (!el) return;
|
||||||
centeredForRef.current = band;
|
|
||||||
el.scrollTop = Math.max(0, freqToY(kHz) - containerH / 2);
|
el.scrollTop = Math.max(0, freqToY(kHz) - containerH / 2);
|
||||||
// freqToY is recomputed each render; intentionally excluded from deps.
|
// freqToY is recomputed each render; intentionally excluded from deps.
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [band, containerH, currentFreqHz, range, lo, hi]);
|
}, [band, containerH, currentFreqHz, range, lo, hi, pxPerKHz]);
|
||||||
|
|
||||||
// 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]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const el = scrollerRef.current;
|
const el = scrollerRef.current;
|
||||||
@@ -365,16 +348,16 @@ export function BandMap({ band, spots, spotStatus, currentFreqHz, onSpotClick, o
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="h-full w-full flex flex-col min-h-0 bg-card">
|
<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">
|
<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">{t('bmp.map')} · {band}</span>
|
<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}
|
<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')}>
|
title={t('bmp.zoomOut')}>
|
||||||
<Minus className="size-3" />
|
<Minus className="size-3" />
|
||||||
</button>
|
</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}
|
<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')}>
|
title={t('bmp.zoomIn')}>
|
||||||
<Plus className="size-3" />
|
<Plus className="size-3" />
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
Reference in New Issue
Block a user