Skip to content

Anchor radial labels at the rim and guard against overflow - #52

Merged
fummicc1 merged 2 commits into
mainfrom
claude/repository-improvements-fhid6w
Aug 28, 2026
Merged

fummicc1 merged 2 commits into
mainfrom
claude/repository-improvements-fhid6w

Conversation

@fummicc1

Copy link
Copy Markdown
Owner

Pre-release quality fix for the #47 layout, so v2.0.0 ships matching the reference wheel.

The gap

The reference image in #47 has every number's outer end on the same circle. The layout merged in #51 instead centred each label at 0.74R, so outer ends wandered with label length — "JavaScript" poked past where "Dart" stopped well short — and nothing stopped a long label from spilling out of the wheel.

The fix

Rim-anchored band layout. A radial label now lives in a band running from the hub to an anchor radius, aligned to the band's outer end and rotated as one piece. Every label's outer end lands on the same circle without the library ever measuring text. On radialUpright's flipped half the band's leading edge faces the rim, so the anchored end swaps sides (.leading vs .trailing) to keep the same geometry.

labelPosition becomes the anchor radius. Radial orientations align the label's outer end to it; .tangential / .fixed centre on it as before. It is now optional, and nil — the new default — resolves per orientation: 0.95 for radial, 0.5 for the others. That way RouletteStyle(labelOrientation: .tangential) alone can never pair a rim anchor with a centred layout.

Overflow guard. Built-in text labels get lineLimit(1) + minimumScaleFactor(0.5): a long label shrinks down to half size inside the band, then truncates as a last resort, instead of spilling out of the wheel. Custom views are left to their author.

Before (merged #51) After
Radial label placement centre at 0.74R outer end anchored at 0.95R
Outer ends aligned? no — varies with label length yes — same circle for every label
Long-label overflow unguarded shrink to 50%, then truncate
labelPosition Double, centre for all modes Double?, anchor for radial / centre for others

Tests

11 tests: the two new anchor-resolution cases (per-orientation default, explicit value wins), the flipped-band predicate (only radialUpright's left half, boundaries excluded), plus the existing rotation/clamping/preset coverage.

Not verified here

Same caveat as before: CI proves compile + unit tests, and the geometry was re-checked by rasterising the same maths outside SwiftUI (outer ends align in both .radial and .radialUpright). The SwiftUI-rendered result — real font metrics, the shrink behaviour — still deserves one look in the demo app before tagging 2.0.0.


Generated by Claude Code

claude added 2 commits August 28, 2026 09:40
The issue #47 reference wheel has every number's outer end on the same
circle. The shipped layout instead centred each label at 0.74R, so outer
ends wandered in and out with label length — "JavaScript" poked past
where "Dart" stopped well short — and nothing stopped a long label from
spilling out of the wheel entirely.

Radial labels now live in a band running from the hub to an anchor
radius, aligned to the band's outer end and rotated as one piece, so
every outer end lands on the same circle without measuring text. On
radialUpright's flipped half the band's leading edge faces the rim, so
the anchored end swaps sides to match.

labelPosition becomes the anchor radius: radial orientations align the
label's outer end to it, tangential/fixed centre on it as before. nil
(the new default) resolves per orientation — 0.95 for radial, 0.5 for
the others — so switching orientation alone never pairs a rim anchor
with a centred layout.

Built-in text labels additionally shrink down to half size before
truncating, so long labels stay inside the wheel. Custom views are left
to their author.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RnVAQvHFsMievKMZBpRHTP
RouletteInternalView is generic over StopView, so the labelHubInset
constant moves to file scope.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RnVAQvHFsMievKMZBpRHTP
@fummicc1
fummicc1 merged commit 25e5e45 into main Aug 28, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants