diff --git a/modules/spl-meter/client.js b/modules/spl-meter/client.js index 85909ee..59e3765 100644 --- a/modules/spl-meter/client.js +++ b/modules/spl-meter/client.js @@ -196,6 +196,38 @@ function readoutView(root, moduleApi) { const unit = root.querySelector('.spl-unit'); const sub = root.querySelector('.spl-sub'); 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 { render(payload) { @@ -205,6 +237,7 @@ function readoutView(root, moduleApi) { num.textContent = '––.–'; sub.textContent = payload && payload.error ? payload.error : ''; box.dataset.level = 'idle'; + fit(); return; } const value = readValue(ch, s); @@ -225,8 +258,9 @@ function readoutView(root, moduleApi) { if (ch.clip) parts.push('CLIP'); if (!payload.calibrated) parts.push('uncalibrated'); sub.textContent = parts.join(' · '); + fit(); }, - resize() {}, + resize() { fitKey = ''; fit(); }, destroy() { root.innerHTML = ''; }, }; } diff --git a/modules/spl-meter/module.json b/modules/spl-meter/module.json index 7a5eb03..f35af77 100644 --- a/modules/spl-meter/module.json +++ b/modules/spl-meter/module.json @@ -1,7 +1,7 @@ { "id": "spl-meter", "name": "SPL Meter", - "version": "0.2.0", + "version": "0.2.1", "proddash": ">=1.5.0", "description": "Calibrated sound level, Leq and RTA from an audio input on this machine", "permissions": [ diff --git a/modules/spl-meter/style.css b/modules/spl-meter/style.css index 98e2dda..a120f46 100644 --- a/modules/spl-meter/style.css +++ b/modules/spl-meter/style.css @@ -30,18 +30,19 @@ color: var(--text); } -/* Sized off the tile, so one cell and six cells both read well. Height has - to be in the min() as well as width: a 2x1 tile is wide and short, and - sizing on width alone pushes the digits straight out through the top. */ +/* A first-paint size only. client.js measures the text and sets the real + one inline, because CSS has to assume a digit count and gets it wrong the + 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 { - font-size: clamp(1.25rem, min(20cqw, 42cqh), 6rem); + font-size: clamp(1.25rem, min(26cqw, 60cqh), 100rem); font-variant-numeric: tabular-nums; font-weight: 600; letter-spacing: -0.02em; } [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); }