Let the SPL readout fill its tile
The number was capped at 6rem, so a readout given half a wall stopped growing at the size it reached in a small tile. Removing the cap was not enough on its own. Sizing text off container units means choosing a coefficient for some assumed number of characters, and the value here is not a fixed width: the coefficient that fills a tile nicely for "-45.9" pushes "-100.5" nine percent out through the side. Measured it rather than guessed — the tile now sets a trial size, reads the width the actual text wants, and scales to fit. That runs only when the tile size or the length of the reading changes, not on every frame. It now fills about 98% of the width wherever width is the limit and 92% of the height wherever height is, at every tile size from 180x70 up to 1400x700, with no overflow on either axis. The CSS keeps a conservative size for the first paint before the measurement has run. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
d2d4207fe4
commit
543795f9fd
@@ -196,6 +196,38 @@ function readoutView(root, moduleApi) {
|
|||||||
const unit = root.querySelector('.spl-unit');
|
const unit = root.querySelector('.spl-unit');
|
||||||
const sub = root.querySelector('.spl-sub');
|
const sub = root.querySelector('.spl-sub');
|
||||||
const box = root.querySelector('.spl-readout');
|
const box = root.querySelector('.spl-readout');
|
||||||
|
const value = root.querySelector('.spl-value');
|
||||||
|
let fitKey = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Grow the number until it fills the tile, measuring the text we actually
|
||||||
|
* have rather than assuming a digit count.
|
||||||
|
*
|
||||||
|
* The CSS can only guess at width — it has to pick a cqw coefficient for
|
||||||
|
* some number of characters, and then "-100.5" overflows the tile that
|
||||||
|
* "-45.9" merely filled. Measuring costs one layout read, and only when
|
||||||
|
* the tile size or the length of the reading changes.
|
||||||
|
*/
|
||||||
|
function fit() {
|
||||||
|
const w = root.clientWidth, h = root.clientHeight;
|
||||||
|
const key = `${w}x${h}:${num.textContent.length}:${unit.textContent}`;
|
||||||
|
if (key === fitKey || w < 2 || h < 2) return;
|
||||||
|
fitKey = key;
|
||||||
|
|
||||||
|
const TRIAL = 100;
|
||||||
|
num.style.fontSize = `${TRIAL}px`;
|
||||||
|
unit.style.fontSize = `${TRIAL * 0.26}px`;
|
||||||
|
const natural = value.scrollWidth || 1;
|
||||||
|
|
||||||
|
// Leave the caption its room when it is showing, and a little air either
|
||||||
|
// way so descenders and the tile's padding never clip.
|
||||||
|
const subH = sub.offsetParent ? sub.getBoundingClientRect().height + 6 : 0;
|
||||||
|
const byHeight = (h - subH) * 0.92;
|
||||||
|
const byWidth = ((w - 8) * TRIAL) / natural;
|
||||||
|
const size = Math.max(12, Math.min(byHeight, byWidth));
|
||||||
|
num.style.fontSize = `${size}px`;
|
||||||
|
unit.style.fontSize = `${size * 0.26}px`;
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
render(payload) {
|
render(payload) {
|
||||||
@@ -205,6 +237,7 @@ function readoutView(root, moduleApi) {
|
|||||||
num.textContent = '––.–';
|
num.textContent = '––.–';
|
||||||
sub.textContent = payload && payload.error ? payload.error : '';
|
sub.textContent = payload && payload.error ? payload.error : '';
|
||||||
box.dataset.level = 'idle';
|
box.dataset.level = 'idle';
|
||||||
|
fit();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const value = readValue(ch, s);
|
const value = readValue(ch, s);
|
||||||
@@ -225,8 +258,9 @@ function readoutView(root, moduleApi) {
|
|||||||
if (ch.clip) parts.push('CLIP');
|
if (ch.clip) parts.push('CLIP');
|
||||||
if (!payload.calibrated) parts.push('uncalibrated');
|
if (!payload.calibrated) parts.push('uncalibrated');
|
||||||
sub.textContent = parts.join(' · ');
|
sub.textContent = parts.join(' · ');
|
||||||
|
fit();
|
||||||
},
|
},
|
||||||
resize() {},
|
resize() { fitKey = ''; fit(); },
|
||||||
destroy() { root.innerHTML = ''; },
|
destroy() { root.innerHTML = ''; },
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"id": "spl-meter",
|
"id": "spl-meter",
|
||||||
"name": "SPL Meter",
|
"name": "SPL Meter",
|
||||||
"version": "0.2.0",
|
"version": "0.2.1",
|
||||||
"proddash": ">=1.5.0",
|
"proddash": ">=1.5.0",
|
||||||
"description": "Calibrated sound level, Leq and RTA from an audio input on this machine",
|
"description": "Calibrated sound level, Leq and RTA from an audio input on this machine",
|
||||||
"permissions": [
|
"permissions": [
|
||||||
|
|||||||
@@ -30,18 +30,19 @@
|
|||||||
color: var(--text);
|
color: var(--text);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Sized off the tile, so one cell and six cells both read well. Height has
|
/* A first-paint size only. client.js measures the text and sets the real
|
||||||
to be in the min() as well as width: a 2x1 tile is wide and short, and
|
one inline, because CSS has to assume a digit count and gets it wrong the
|
||||||
sizing on width alone pushes the digits straight out through the top. */
|
moment the reading needs a sixth character: the coefficient that fills a
|
||||||
|
tile for "-45.9" pushes "-100.5" straight out through the side. */
|
||||||
[data-module="spl-meter"] .spl-num {
|
[data-module="spl-meter"] .spl-num {
|
||||||
font-size: clamp(1.25rem, min(20cqw, 42cqh), 6rem);
|
font-size: clamp(1.25rem, min(26cqw, 60cqh), 100rem);
|
||||||
font-variant-numeric: tabular-nums;
|
font-variant-numeric: tabular-nums;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
letter-spacing: -0.02em;
|
letter-spacing: -0.02em;
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-module="spl-meter"] .spl-unit {
|
[data-module="spl-meter"] .spl-unit {
|
||||||
font-size: clamp(0.65rem, min(6cqw, 13cqh), 1.5rem);
|
font-size: clamp(0.65rem, min(7cqw, 15cqh), 26rem);
|
||||||
color: var(--muted);
|
color: var(--muted);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user