Skip to content

release(18.6.1): fix label perf (#304) + group position race (#305)#306

Merged
siarheihuzarevich merged 3 commits into
mainfrom
release/18.6.1
May 14, 2026
Merged

release(18.6.1): fix label perf (#304) + group position race (#305)#306
siarheihuzarevich merged 3 commits into
mainfrom
release/18.6.1

Conversation

@siarheihuzarevich
Copy link
Copy Markdown
Member

Summary

  • fix(connection-content)close #304. fConnectionContent no longer reads getBoundingClientRect() on every redraw. Each label installs a ResizeObserver once and reports its size from a cached value via the new IPolylineContent.measureSize(). The placement loop in PolylineContentPlace.compute() was interleaving DOM reads with style.transform writes per iteration, which forced a synchronous layout flush per label and turned drag at a few hundred labelled connections into O(N²) browser work.
  • fix(reflow)close #305. The reflow orchestrator no longer plans shifts against half-applied node state. When withReflowOnResize() is paired with fAutoSizeToFitChildren on a group and the graph is swapped, candidates whose position() signal had not yet been mirrored into _position used to feed one stale DOM rect to every sibling, collapsing them onto the same fractional point. Such candidates are now skipped for the tick.
  • chore(release) — bump @foblex/flow, @foblex/flow-dagre-layout, @foblex/flow-elk-layout, and the root workspace to 18.6.1; CHANGELOG section pinned under the new release header.

Test plan

  • New regression spec libs/f-flow/.../connection-content-perf.spec.ts — 30 source-position redraws produce 0 getBoundingClientRect() calls on label hosts.
  • New regression spec libs/f-flow/.../group-children-position-race.spec.ts — small → big graph swap with withReflowOnResize() + fAutoSizeToFitChildren keeps every child at its assigned position.
  • Full nx test f-flow suite green (138 + 1 + 1 specs).
  • nx lint f-flow clean.
  • Manual verification in the portal stress example: dragging "Move me" at 1000 labelled edges is smooth after the fix; was unusably slow before.

🤖 Generated with Claude Code

siarheihuzarevich and others added 3 commits May 14, 2026 18:46
When `withReflowOnResize()` is paired with a group that uses
`fAutoSizeToFitChildren` and the graph is swapped in (e.g. by
replacing the `@for` source), several children of the group could
collapse onto a single DOM-measured position. The orchestrator was
building its plan from candidates whose `position()` signal had not
yet been mirrored into `_position`, so one stale rect propagated as
the same shift target to many siblings.

`_safeGetRect` now returns `null` when a node's model signal and
`_position` mirror are out of sync. The orchestrator skips that
candidate for the tick and picks up the node again once the next
coherent state arrives.

Fixes #305.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
`ConnectionContentLayoutEngine.layout()` runs a tight loop that
computes a position for every `fConnectionContent` and writes its
`style.transform`. The size lookup inside `PolylineContentPlace`
used to call `RectExtensions.fromElement(...)`, which means a
`getBoundingClientRect()` on every iteration. Each read after the
previous iteration's transform write forced the browser to flush
layout — at a few hundred labelled connections this became O(N²)
work and stalled drag.

`IPolylineContent` now exposes a `measureSize()` accessor; the
`FConnectionContentBase` implementation installs a `ResizeObserver`
on its host element once and updates a cached `{width, height}`
asynchronously when the label actually resizes. The placement loop
reads from memory and never touches the DOM.

Trade-off: until the observer delivers its first entry the cache
holds `{0, 0}`, so the edge guard does not push labels away from
path endpoints on the very first frame. Labels at `position` other
than 0 or 1 are unaffected.

Fixes #304.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant