From dc2c8b6eb1d9cf67c2e72e9c85fd6b1e3d4e1f7f Mon Sep 17 00:00:00 2001 From: Stan Grams Date: Sun, 22 Mar 2026 07:51:30 +0100 Subject: [PATCH] [fix](trx-frontend-http): instant spectrum overlay on freq/bw changes Call drawSignalOverlay() synchronously on frequency and bandwidth changes instead of deferring entirely to requestAnimationFrame. Also make bookmark apply fire-and-forget so the click handler returns immediately after optimistic UI updates. Co-Authored-By: Claude Opus 4.6 Signed-off-by: Stan Grams --- .../trx-frontend-http/assets/web/app.js | 19 +++++++++++++++++-- .../assets/web/plugins/bookmarks.js | 17 +++++++++++------ 2 files changed, 28 insertions(+), 8 deletions(-) diff --git a/src/trx-client/trx-frontend/trx-frontend-http/assets/web/app.js b/src/trx-client/trx-frontend/trx-frontend-http/assets/web/app.js index bacfaaa..de452db 100644 --- a/src/trx-client/trx-frontend/trx-frontend-http/assets/web/app.js +++ b/src/trx-client/trx-frontend/trx-frontend-http/assets/web/app.js @@ -1694,6 +1694,10 @@ function applyLocalTunedFrequency(hz, forceDisplay = false) { window.refreshCwTonePicker(); } if (lastSpectrumData) { + // Redraw the signal/BW overlay immediately so the frequency marker and + // bandwidth picker move without waiting for the next spectrum frame or + // requestAnimationFrame callback. + drawSignalOverlay(); scheduleSpectrumDraw(); } positionRdsPsOverlay(); @@ -3784,6 +3788,10 @@ async function applyBwDefaultForMode(mode, sendToServer) { currentBandwidthHz = def; window.currentBandwidthHz = currentBandwidthHz; syncBandwidthInput(def); + if (lastSpectrumData) { + drawSignalOverlay(); + scheduleSpectrumDraw(); + } if (sendToServer) { try { await postPath(`/set_bandwidth?hz=${def}`); } catch (_) {} } @@ -3802,7 +3810,10 @@ async function applyBandwidthFromInput() { currentBandwidthHz = clamped; window.currentBandwidthHz = currentBandwidthHz; syncBandwidthInput(clamped); - if (lastSpectrumData) scheduleSpectrumDraw(); + if (lastSpectrumData) { + drawSignalOverlay(); + scheduleSpectrumDraw(); + } try { if (typeof vchanInterceptBandwidth === "function" && await vchanInterceptBandwidth(clamped)) return; await postPath(`/set_bandwidth?hz=${clamped}`); @@ -3877,7 +3888,10 @@ async function applyAutoBandwidth() { currentBandwidthHz = estimated; window.currentBandwidthHz = currentBandwidthHz; syncBandwidthInput(estimated); - if (lastSpectrumData) scheduleSpectrumDraw(); + if (lastSpectrumData) { + drawSignalOverlay(); + scheduleSpectrumDraw(); + } try { if (typeof vchanInterceptBandwidth === "function" && await vchanInterceptBandwidth(estimated)) return; await postPath(`/set_bandwidth?hz=${estimated}`); @@ -9711,6 +9725,7 @@ if (spectrumCanvas || overviewCanvas) { currentBandwidthHz = newBw; window.currentBandwidthHz = currentBandwidthHz; syncBandwidthInput(newBw); + drawSignalOverlay(); scheduleSpectrumDraw(); scheduleOverviewDraw(); return; diff --git a/src/trx-client/trx-frontend/trx-frontend-http/assets/web/plugins/bookmarks.js b/src/trx-client/trx-frontend/trx-frontend-http/assets/web/plugins/bookmarks.js index e5f3d4b..208d674 100644 --- a/src/trx-client/trx-frontend/trx-frontend-http/assets/web/plugins/bookmarks.js +++ b/src/trx-client/trx-frontend/trx-frontend-http/assets/web/plugins/bookmarks.js @@ -344,7 +344,9 @@ async function bmApply(bm) { scheduleSpectrumDraw(); } - // --- Send mode, bandwidth, and frequency to server in parallel --- + // --- Fire-and-forget: send mode, bandwidth, and frequency in parallel --- + // The UI is already updated optimistically above; don't block on the + // network round-trips so the bookmark click feels instant. const modePromise = (async () => { const onVirtual = typeof vchanInterceptMode === "function" && await vchanInterceptMode(bm.mode); @@ -370,10 +372,8 @@ async function bmApply(bm) { await postPath("/set_freq?hz=" + bm.freq_hz); } })(); - await Promise.all([modePromise, bwPromise, freqPromise]); - - // --- Toggle decoders when in DIG mode --- - if (bm.mode === "DIG" && Array.isArray(bm.decoders)) { + // Decoder toggles (DIG mode) — also fire-and-forget. + const decoderPromise = (bm.mode === "DIG" && Array.isArray(bm.decoders)) ? (async () => { const statusResp = await fetch("/status"); if (statusResp.ok) { const st = await statusResp.json(); @@ -386,7 +386,12 @@ async function bmApply(bm) { check("ft8"); check("ft4"); check("ft2"); check("wspr"); check("hf-aprs"); if (toggles.length) await Promise.all(toggles); } - } + })() : Promise.resolve(); + // Don't await — let the network calls settle in the background. + // Errors are logged but don't block the UI. + Promise.all([modePromise, bwPromise, freqPromise, decoderPromise]).catch( + (err) => console.error("Bookmark apply background error:", err) + ); } catch (err) { console.error("Failed to apply bookmark:", err); }