[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;
|
let spectrumUsableSpanRatio = 0.92;
|
||||||
const DEFAULT_OVERVIEW_PLOT_HEIGHT_PX = 160;
|
const DEFAULT_OVERVIEW_PLOT_HEIGHT_PX = 160;
|
||||||
const DEFAULT_SPECTRUM_PLOT_HEIGHT_PX = 160;
|
const DEFAULT_SPECTRUM_PLOT_HEIGHT_PX = 160;
|
||||||
|
const MIN_SPECTRUM_PLOT_HEIGHT_PX = 130;
|
||||||
let spectrumLayoutPending = false;
|
let spectrumLayoutPending = false;
|
||||||
|
let spectrumManualPlotHeightPx = null;
|
||||||
|
let spectrumResizeState = null;
|
||||||
|
|
||||||
function updateFooterBuildInfo() {
|
function updateFooterBuildInfo() {
|
||||||
const serverEl = document.getElementById("footer-server-build");
|
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() {
|
function updateSpectrumAutoHeight() {
|
||||||
const root = document.documentElement;
|
const root = document.documentElement;
|
||||||
const tabMainEl = document.getElementById("tab-main");
|
const tabMainEl = document.getElementById("tab-main");
|
||||||
@@ -1986,30 +2011,86 @@ function updateSpectrumAutoHeight() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const tabBottom = tabMainEl.getBoundingClientRect().bottom;
|
const bounds = spectrumHeightBoundsPx(tabMainEl, contentEl, spectrumCanvasEl);
|
||||||
const contentBottom = contentEl.getBoundingClientRect().bottom;
|
const requestedSpectrumHeight = spectrumManualPlotHeightPx == null
|
||||||
const slackPx = Math.floor(tabBottom - contentBottom);
|
? bounds.max
|
||||||
const nextCombinedHeight = Math.max(
|
: spectrumManualPlotHeightPx;
|
||||||
DEFAULT_OVERVIEW_PLOT_HEIGHT_PX + DEFAULT_SPECTRUM_PLOT_HEIGHT_PX,
|
const nextSpectrumHeight = Math.max(
|
||||||
currentOverviewHeight + currentSpectrumHeight + slackPx - 2,
|
bounds.min,
|
||||||
);
|
Math.min(bounds.max, Math.round(requestedSpectrumHeight)),
|
||||||
const nextHeight = Math.max(
|
|
||||||
DEFAULT_SPECTRUM_PLOT_HEIGHT_PX,
|
|
||||||
Math.round(nextCombinedHeight / 2),
|
|
||||||
);
|
);
|
||||||
|
if (spectrumManualPlotHeightPx != null) {
|
||||||
|
spectrumManualPlotHeightPx = nextSpectrumHeight;
|
||||||
|
}
|
||||||
if (
|
if (
|
||||||
Math.abs(nextHeight - currentOverviewHeight) < 2
|
Math.abs(DEFAULT_OVERVIEW_PLOT_HEIGHT_PX - currentOverviewHeight) < 2
|
||||||
&& Math.abs(nextHeight - currentSpectrumHeight) < 2
|
&& Math.abs(nextSpectrumHeight - currentSpectrumHeight) < 2
|
||||||
) return;
|
) return;
|
||||||
|
|
||||||
root.style.setProperty("--overview-plot-height", `${nextHeight}px`);
|
root.style.setProperty("--overview-plot-height", `${DEFAULT_OVERVIEW_PLOT_HEIGHT_PX}px`);
|
||||||
root.style.setProperty("--spectrum-plot-height", `${nextHeight}px`);
|
root.style.setProperty("--spectrum-plot-height", `${nextSpectrumHeight}px`);
|
||||||
if (lastSpectrumData) {
|
if (lastSpectrumData) {
|
||||||
scheduleSpectrumDraw();
|
scheduleSpectrumDraw();
|
||||||
scheduleOverviewDraw();
|
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() {
|
function updateTitle() {
|
||||||
const titleEl = document.getElementById("rig-title");
|
const titleEl = document.getElementById("rig-title");
|
||||||
if (titleEl) {
|
if (titleEl) {
|
||||||
|
|||||||
@@ -95,6 +95,7 @@
|
|||||||
<div id="spectrum-tooltip"></div>
|
<div id="spectrum-tooltip"></div>
|
||||||
<div id="spectrum-freq-axis"></div>
|
<div id="spectrum-freq-axis"></div>
|
||||||
</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-controls">
|
||||||
<div id="spectrum-bw-row">
|
<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>
|
<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 {
|
#spectrum-panel {
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
}
|
}
|
||||||
|
.spectrum-resizing,
|
||||||
|
.spectrum-resizing * {
|
||||||
|
cursor: ns-resize !important;
|
||||||
|
user-select: none !important;
|
||||||
|
}
|
||||||
.spectrum-wrap {
|
.spectrum-wrap {
|
||||||
position: relative;
|
position: relative;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@@ -2184,6 +2189,26 @@ button:focus-visible, input:focus-visible, select:focus-visible {
|
|||||||
border: 1px solid var(--border);
|
border: 1px solid var(--border);
|
||||||
border-top: none;
|
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 {
|
#spectrum-freq-axis span {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
transform: translateX(-50%);
|
transform: translateX(-50%);
|
||||||
|
|||||||
Reference in New Issue
Block a user