Draw on-gram labels on a white plate instead of a halo (#243) - #246
Merged
Conversation
Harmonic and sideband pin numbers, and analysis marker labels, were drawn as black glyphs inside a white halo — a stroke painted behind the letterforms. A halo only whitens the pixels immediately around each stroke, so a noisy gram still shows through the counters of the digits and the space between them. The legacy spectrogram viewer plates its harmonic numbers instead: an opaque white rounded rectangle containing the characters, which clears one contiguous area and reads the same everywhere in the label. Every in-gram label now sits on such a plate: - New `src/utils/labelPlate.js` owns the plate. `plateLabel()` wraps a fully-attributed `<text>` in a group with the rectangle behind it, sized from the text measured at the font it is drawn in (canvas measurement, with a character-count fallback for the Node unit lane). The geometry is pure so the placement rules can size their gaps from it. - The two placement rules — `markerLabelPlacement` and `PinSetMode.labelStackPositions` — now measure their gaps to the edge of the plate rather than to the baseline, so the white rectangle clears the symbol, the crosshair and the image's top edge by as much as the bare glyphs used to. A pin's grab region tracks the plate too. - The text keeps its class and attributes, so selectors, CSS and tests still find the label where they did. Labels stay black-on-white whatever colour the feature is; identity is still carried by the pin's line and symbol. Closes #243
Contributor
PR PreviewPreview deployment is ready! View Preview Last updated: 2026-08-21T13:39:36.783Z |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #243.
Harmonic and sideband pin numbers, and analysis marker labels, were drawn as black glyphs inside a white halo — a stroke painted behind the letterforms. A halo only whitens the pixels immediately around each stroke, so a noisy gram still shows through the counters of the digits and the space between them. The legacy viewer plates its harmonic numbers instead: an opaque white rounded rectangle containing the characters, which clears one contiguous area so the contrast is the same everywhere in the label.
Every in-gram label now sits on such a plate — both the harmonic/sideband index labels and the cross-cursor text labels, as the issue asks.
What changed
src/utils/labelPlate.jsowns the plate.plateLabel()wraps a fully-attributed SVG text element in a group with the rectangle behind it, sized from the text measured at the font it is drawn in (canvas measurement, with a character-count fallback for the Node unit lane). The geometry is pure, so the placement rules can size their gaps from the same numbers the renderer draws with. It replacessrc/utils/svg.js, whose only job was the halo.markerLabelPlacementandPinSetMode.labelStackPositionsnow measure their gaps to the plate's edge rather than to the text baseline, so the white rectangle clears the symbol, the crosshair's centre dot and the image's top edge by as much as the bare glyphs used to. A pin's grab region (labelStackBounds/labelStackHalfWidth) tracks the drawn plate too, and its width is now measured rather than estimated from a character count.The plate rises 0.95 em above the baseline — enough to cover the font's full ascent, so a tall or accented character can never clip the top edge. That makes it slightly taller than digits alone need;
PLATE_ABOVE_RATIOinlabelPlate.jsis the one number to change if a tighter plate reads better on a real gram.Testing
yarn test— 333 passed (includes the rewrittentests/harmonic-label-plate.spec.js, replacingharmonic-label-halo.spec.js, and three new marker-label tests: the plate is white and rounded, it covers the characters on every side, and it stays clear of the crosshair it annotates).yarn test:unit— 149 passed (newtests/unit/label-plate.test.jscovers the pure plate geometry: extents, anchoring, padding).yarn typecheck,yarn lint,yarn hygiene— all clean.debug.html: harmonic pins 1–5 and a labelled crosshair, over both dark and saturated areas of the gram.Docs
CLAUDE.md's file list,docs/Gram-Modes.md, and the three docs pages that pointed atsrc/utils/svg.js(for helpers that no longer existed) now name the real modules.