Skip to content

fix(map): a container has to be big enough for its own name - #583

Merged
angel-manuel merged 2 commits into
devfrom
fix/live-map-container-fits-its-chip
Aug 28, 2026
Merged

fix(map): a container has to be big enough for its own name#583
angel-manuel merged 2 commits into
devfrom
fix/live-map-container-fits-its-chip

Conversation

@angel-manuel

Copy link
Copy Markdown
Contributor

Reported on #582: a container can come out narrower than the chip naming it, which
reads as the label having come loose from the box.

The chip counter-scales by 1/k so its text stays readable at 30% zoom — that is
the whole reason it is DOM and not canvas. Which means it grows in world units
as the map zooms out, while the cluster it names does not. computeBoxes sized
the box off its members alone, so a user with a single ball under them and an
email for a name got a label hanging out past both edges. #582 made this easier
to hit twice over: services joined containers (so more users have a box at all),
and identity labels became emails rather than short IdP display names.

The box now reserves room for its own chip. The width floor is the chip's
measured width; the top padding is its measured height rather than a constant.
BOX_PAD_TOP = 26 was that height at k=1 all along — below 100% zoom the chip
was already sitting on the cluster's top row, which is the same bug in the other
axis.

Measured rather than estimated, because the label is an email whose length
nothing here controls. Measured in syncChips at the UI cadence rather than in
computeBoxes per frame: reading offsetWidth right after writing the
transforms forces a synchronous layout, and the value only changes when the
label does. A chip that has not been measured yet falls back to the old
constants for a frame or two.

The magic 10 for the chip's inset from the left edge, which appeared in three
places, is now CHIP_INSET.

Verification

Real stack, a cluster whose owner's name is a long address next to one whose
name is short.

75%

100

36% — where the chip is at its widest in world units

zoomed out

Follow-up

Not in this PR, coming next: nothing stops a non-member — an org-level service,
another user's ball — from sitting inside a container, and collapsed containers
take no part in the box-vs-box separation, so a folded chip can land on top of an
open box.

The name chip counter-scales by `1/k` so its text stays readable at 30% zoom,
which means it *grows* in world units as the map zooms out while the cluster it
names does not. `computeBoxes` sized the box off its members alone, so a user
with one ball under them got a label wider than the container it belongs to —
the chip hanging out past both edges, reading as though it had come loose.

The box now reserves room for its own chip: the width floor is the chip's
measured width, and the top padding is its measured height rather than a
constant. `BOX_PAD_TOP` was that height at k=1 all along; below that the chip
was already sitting on the cluster's top row.

Measured, not estimated — the label is an email whose length nothing here
controls — and measured at the UI cadence rather than per frame, because
reading `offsetWidth` right after writing the transforms forces a synchronous
layout, and the value only changes when the label does.
@vercel

vercel Bot commented Aug 28, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
overslash Ready Ready Preview Aug 28, 2026 8:19am

Request Review

@github-actions

github-actions Bot commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

Code diff size

+90 / −9 across 1 file (net +81)

Area Files Added Removed Net
dashboard 1 +90 −9 +81

Source files under src/ only (.cjs, .go, .js, .jsx, .mjs, .py, .rs, .svelte, .ts, .tsx); test files and inline #[cfg(test)] modules excluded. 0 other changed files not counted.

`computeBoxes` sized a container off `radiusOf`, which describes the ball. A
node is a ball *and* a caption, the caption is the wider of the two — it carries
an agent's name or a user's email, up to a 132px `max-width`, and it has a
`scale()` of its own on top of that — so every label along a container's left or
bottom edge hung outside it.

The extent now comes from what the browser actually laid out: the union of
`.lm-node-in` and its `.lm-cap`, as offsets from the node's anchor. Reading it
back beats arithmetic over the stylesheet, which would be a copy of the CSS that
goes stale the first time someone touches it, and it is the only way to know how
wide a caption ended up when it may have been ellipsised. The caption's `scale()`
lands after layout and can spill past its parent's border box, hence the union
rather than the parent alone.

Measured on the same cadence as the chip and for the same reason. Unlike a chip
this rides the map's zoom, so the world offsets hold at any `k` and the cache
only goes stale when a label changes. A node the DOM has not laid out yet — or
one mid-leave, whose rect describes where it is going rather than how big it is
— falls back to `radiusOf`.
@angel-manuel

Copy link
Copy Markdown
Contributor Author

Second half of the same bug, reported on the first: a node's caption could still hang outside the container.

computeBoxes sized the box off radiusOf, which describes the ball. But a node is a ball and a caption, and the caption is the wider of the two — it carries an agent's name or a user's email up to a 132px max-width, with a scale() of its own on top. So every label along a container's left or bottom edge sat outside it.

The extent now comes from what the browser laid out: the union of .lm-node-in and its .lm-cap, as offsets from the node's anchor. Reading it back beats arithmetic over the stylesheet — that would be a copy of the CSS that goes stale the first time someone touches it, and it is the only way to know how wide a caption ended up when it may have been ellipsised. The scale() applies after layout and can spill past the parent's border box, hence the union rather than the parent alone.

Same cadence as the chip measurement, same reason. Unlike a chip this one rides the map's zoom, so the world offsets hold at any k.

Screenshots above are re-captured against this commit. The annabel.lecomte-va… caption used to start ~17px left of its box edge; it is now inside it, at both zoom levels.

@angel-manuel
angel-manuel enabled auto-merge (squash) August 28, 2026 08:24
@angel-manuel
angel-manuel merged commit 2c455d2 into dev Aug 28, 2026
14 checks passed
@angel-manuel
angel-manuel deleted the fix/live-map-container-fits-its-chip branch August 28, 2026 08:26
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.

1 participant