[fix](trx-frontend): maximize spectrum viewport and add resize grip
Make spectrum plot use maximum available viewport height by default. Add draggable vertical resize grip with a reasonable minimum height and double-click reset back to auto-max. Co-authored-by: Codex <codex@openai.com> Signed-off-by: Stan Grams <sjg@haxx.space>
This commit is contained in:
@@ -1932,7 +1932,10 @@ let spectrumCoverageMarginHz = 50_000;
|
||||
let spectrumUsableSpanRatio = 0.92;
|
||||
const DEFAULT_OVERVIEW_PLOT_HEIGHT_PX = 160;
|
||||
const DEFAULT_SPECTRUM_PLOT_HEIGHT_PX = 160;
|
||||
const MIN_SPECTRUM_PLOT_HEIGHT_PX = 130;
|
||||
let spectrumLayoutPending = false;
|
||||
let spectrumManualPlotHeightPx = null;
|
||||
let spectrumResizeState = null;
|
||||
|
||||
function updateFooterBuildInfo() {
|
||||
const serverEl = document.getElementById("footer-server-build");
|
||||
@@ -1951,6 +1954,28 @@ function scheduleSpectrumLayout() {
|
||||
});
|
||||
}
|
||||
|
||||
function currentSpectrumHeightPx(spectrumCanvasEl) {
|
||||
return Math.max(
|
||||
MIN_SPECTRUM_PLOT_HEIGHT_PX,
|
||||
Math.round(spectrumCanvasEl?.clientHeight || DEFAULT_SPECTRUM_PLOT_HEIGHT_PX),
|
||||
);
|
||||
}
|
||||
|
||||
function spectrumHeightBoundsPx(tabMainEl, contentEl, spectrumCanvasEl) {
|
||||
const currentSpectrumHeight = currentSpectrumHeightPx(spectrumCanvasEl);
|
||||
const tabBottom = tabMainEl.getBoundingClientRect().bottom;
|
||||
const contentBottom = contentEl.getBoundingClientRect().bottom;
|
||||
const slackPx = Math.floor(tabBottom - contentBottom);
|
||||
const maxHeight = Math.max(
|
||||
MIN_SPECTRUM_PLOT_HEIGHT_PX,
|
||||
currentSpectrumHeight + slackPx - 2,
|
||||
);
|
||||
return {
|
||||
min: MIN_SPECTRUM_PLOT_HEIGHT_PX,
|
||||
max: maxHeight,
|
||||
};
|
||||
}
|
||||
|
||||
function updateSpectrumAutoHeight() {
|
||||
const root = document.documentElement;
|
||||
const tabMainEl = document.getElementById("tab-main");
|
||||
@@ -1986,30 +2011,86 @@ function updateSpectrumAutoHeight() {
|
||||
return;
|
||||
}
|
||||
|
||||
const tabBottom = tabMainEl.getBoundingClientRect().bottom;
|
||||
const contentBottom = contentEl.getBoundingClientRect().bottom;
|
||||
const slackPx = Math.floor(tabBottom - contentBottom);
|
||||
const nextCombinedHeight = Math.max(
|
||||
DEFAULT_OVERVIEW_PLOT_HEIGHT_PX + DEFAULT_SPECTRUM_PLOT_HEIGHT_PX,
|
||||
currentOverviewHeight + currentSpectrumHeight + slackPx - 2,
|
||||
);
|
||||
const nextHeight = Math.max(
|
||||
DEFAULT_SPECTRUM_PLOT_HEIGHT_PX,
|
||||
Math.round(nextCombinedHeight / 2),
|
||||
const bounds = spectrumHeightBoundsPx(tabMainEl, contentEl, spectrumCanvasEl);
|
||||
const requestedSpectrumHeight = spectrumManualPlotHeightPx == null
|
||||
? bounds.max
|
||||
: spectrumManualPlotHeightPx;
|
||||
const nextSpectrumHeight = Math.max(
|
||||
bounds.min,
|
||||
Math.min(bounds.max, Math.round(requestedSpectrumHeight)),
|
||||
);
|
||||
if (spectrumManualPlotHeightPx != null) {
|
||||
spectrumManualPlotHeightPx = nextSpectrumHeight;
|
||||
}
|
||||
if (
|
||||
Math.abs(nextHeight - currentOverviewHeight) < 2
|
||||
&& Math.abs(nextHeight - currentSpectrumHeight) < 2
|
||||
Math.abs(DEFAULT_OVERVIEW_PLOT_HEIGHT_PX - currentOverviewHeight) < 2
|
||||
&& Math.abs(nextSpectrumHeight - currentSpectrumHeight) < 2
|
||||
) return;
|
||||
|
||||
root.style.setProperty("--overview-plot-height", `${nextHeight}px`);
|
||||
root.style.setProperty("--spectrum-plot-height", `${nextHeight}px`);
|
||||
root.style.setProperty("--overview-plot-height", `${DEFAULT_OVERVIEW_PLOT_HEIGHT_PX}px`);
|
||||
root.style.setProperty("--spectrum-plot-height", `${nextSpectrumHeight}px`);
|
||||
if (lastSpectrumData) {
|
||||
scheduleSpectrumDraw();
|
||||
scheduleOverviewDraw();
|
||||
}
|
||||
}
|
||||
|
||||
function beginSpectrumResize(clientY) {
|
||||
const tabMainEl = document.getElementById("tab-main");
|
||||
const contentEl = document.getElementById("content");
|
||||
const spectrumCanvasEl = document.getElementById("spectrum-canvas");
|
||||
const spectrumPanelEl = document.getElementById("spectrum-panel");
|
||||
if (!tabMainEl || !contentEl || !spectrumCanvasEl || !spectrumPanelEl) return false;
|
||||
if (getComputedStyle(spectrumPanelEl).display === "none") return false;
|
||||
spectrumResizeState = {
|
||||
startY: clientY,
|
||||
startHeight: currentSpectrumHeightPx(spectrumCanvasEl),
|
||||
};
|
||||
document.body.classList.add("spectrum-resizing");
|
||||
return true;
|
||||
}
|
||||
|
||||
function updateSpectrumResize(clientY) {
|
||||
if (!spectrumResizeState) return;
|
||||
const deltaY = clientY - spectrumResizeState.startY;
|
||||
spectrumManualPlotHeightPx = spectrumResizeState.startHeight + deltaY;
|
||||
updateSpectrumAutoHeight();
|
||||
}
|
||||
|
||||
function endSpectrumResize() {
|
||||
spectrumResizeState = null;
|
||||
document.body.classList.remove("spectrum-resizing");
|
||||
}
|
||||
|
||||
const spectrumSizeGrip = document.getElementById("spectrum-size-grip");
|
||||
if (spectrumSizeGrip) {
|
||||
spectrumSizeGrip.addEventListener("pointerdown", (event) => {
|
||||
if (event.button !== 0) return;
|
||||
if (!beginSpectrumResize(event.clientY)) return;
|
||||
event.preventDefault();
|
||||
if (typeof spectrumSizeGrip.setPointerCapture === "function") {
|
||||
spectrumSizeGrip.setPointerCapture(event.pointerId);
|
||||
}
|
||||
});
|
||||
spectrumSizeGrip.addEventListener("pointermove", (event) => {
|
||||
if (!spectrumResizeState) return;
|
||||
updateSpectrumResize(event.clientY);
|
||||
});
|
||||
const finishResize = (event) => {
|
||||
if (!spectrumResizeState) return;
|
||||
if (typeof spectrumSizeGrip.releasePointerCapture === "function" && spectrumSizeGrip.hasPointerCapture(event.pointerId)) {
|
||||
spectrumSizeGrip.releasePointerCapture(event.pointerId);
|
||||
}
|
||||
endSpectrumResize();
|
||||
};
|
||||
spectrumSizeGrip.addEventListener("pointerup", finishResize);
|
||||
spectrumSizeGrip.addEventListener("pointercancel", finishResize);
|
||||
spectrumSizeGrip.addEventListener("dblclick", () => {
|
||||
spectrumManualPlotHeightPx = null;
|
||||
scheduleSpectrumLayout();
|
||||
});
|
||||
}
|
||||
|
||||
function updateTitle() {
|
||||
const titleEl = document.getElementById("rig-title");
|
||||
if (titleEl) {
|
||||
|
||||
@@ -95,6 +95,7 @@
|
||||
<div id="spectrum-tooltip"></div>
|
||||
<div id="spectrum-freq-axis"></div>
|
||||
</div>
|
||||
<div id="spectrum-size-grip" title="Drag to resize spectrum height" aria-label="Resize spectrum height"></div>
|
||||
<div id="spectrum-controls">
|
||||
<div id="spectrum-bw-row">
|
||||
<label id="spectrum-bw-label">Bandwidth <input type="number" id="spectrum-bw-input" value="" step="0.1" min="0.1" /> kHz</label>
|
||||
|
||||
@@ -2111,6 +2111,11 @@ button:focus-visible, input:focus-visible, select:focus-visible {
|
||||
#spectrum-panel {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.spectrum-resizing,
|
||||
.spectrum-resizing * {
|
||||
cursor: ns-resize !important;
|
||||
user-select: none !important;
|
||||
}
|
||||
.spectrum-wrap {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
@@ -2184,6 +2189,26 @@ button:focus-visible, input:focus-visible, select:focus-visible {
|
||||
border: 1px solid var(--border);
|
||||
border-top: none;
|
||||
}
|
||||
#spectrum-size-grip {
|
||||
position: relative;
|
||||
height: 0.9rem;
|
||||
margin-top: 0.1rem;
|
||||
margin-bottom: 0.3rem;
|
||||
cursor: ns-resize;
|
||||
touch-action: none;
|
||||
}
|
||||
#spectrum-size-grip::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
width: 3.8rem;
|
||||
height: 0.26rem;
|
||||
transform: translate(-50%, -50%);
|
||||
border-radius: 999px;
|
||||
border: 1px solid color-mix(in srgb, var(--border-light) 76%, transparent);
|
||||
background: color-mix(in srgb, var(--btn-bg) 78%, transparent);
|
||||
}
|
||||
#spectrum-freq-axis span {
|
||||
position: absolute;
|
||||
transform: translateX(-50%);
|
||||
|
||||
Reference in New Issue
Block a user