Skip to content

feat(connectionStrategies): add pin() factory with useModelGeometry and clamp options - #3580

Merged
kumilingus merged 2 commits into
clientIO:devfrom
Geliogabalus:feat/connection-strategies-pin
Oct 29, 2026
Merged

kumilingus merged 2 commits into
clientIO:devfrom
Geliogabalus:feat/connection-strategies-pin

Conversation

@Geliogabalus

@Geliogabalus Geliogabalus commented Oct 29, 2026 •

Copy link
Copy Markdown
Contributor

Description

Makes the private pin() factory public, with three options:

paper.options.connectionStrategy = connectionStrategies.pin({
    relative: true,          // percentages (pinRelative) or pixels (pinAbsolute)
    useModelGeometry: true,  // measure the model bbox; the created anchor gets `useModelGeometry: true` too
    clamp: true              // a point outside the element is moved onto its edge
});
  • useModelGeometry measures element.getBBox(), or element.getPortBBox(port) when the end has a port. It undoes the rotation around that box's center. The topLeft anchor with useModelGeometry and rotate: true uses the same box and pivot, so the anchor resolves to the dropped point.
  • clamp limits the offsets to [0, width] × [0, height].
  • pinAbsolute and pinRelative are now pin() and pin({ relative: true }) and behave as before. The strategy no longer rotates the passed coords in place.
  • Link-to-link ends ignore useModelGeometry and clamp, because the closest point on a connection already lies on it.

Fixes #3531

Motivation and Context

pinRelative / pinAbsolute measure the rendered node under the pointer. An app whose anchors use useModelGeometry gets offsets computed for one box and applied to another. With snapLinks, an end dropped next to an element is also stored outside it, so it floats beside the element and drifts away when the element is resized. Today an app has to write its own strategy to work around this.

Tests

  • test/jointjs/linkView.js adds a pin() module. It covers the defaults, relative, clamp, useModelGeometry on a label magnet and on a port, and that coords are left unchanged. A round-trip test on a rotated element checks that the anchor resolves back to the dropped point for every combination of relative and useModelGeometry.
  • test/ts/shapes.test.ts adds a typings check.

…nd clamp options

Make the private pin() factory public with `relative`, `useModelGeometry`
and `clamp` options. With `useModelGeometry`, the offsets are measured
against the element's (or port's) model bbox - the same box the anchor
resolves them against - instead of the rendered magnet. With `clamp`, a
point outside the element is moved onto its edge.

pinAbsolute and pinRelative are now pin() and pin({ relative: true }).

Closes clientIO#3531

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Geliogabalus
Geliogabalus force-pushed the feat/connection-strategies-pin branch from c37d0b2 to 29cbf71 Compare October 29, 2026 10:32
@Geliogabalus
Geliogabalus changed the base branch from master to dev October 29, 2026 10:48
The strategy created by pin() kept a reference to the options object, so
modifying it afterwards changed the strategy. Copy the options, with
their defaults, when the strategy is created.

Document the defaults and the port and link-end behavior in PinOptions.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@kumilingus
kumilingus requested a balanced review from Copilot October 29, 2026 14:27

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has insufficient remaining quota.

An organization owner can choose the repository organization as the billing source for reviews requested by members with a paid Copilot license. Learn about Copilot code review billing.

@Geliogabalus
Geliogabalus requested a balanced review from Copilot October 29, 2026 14:31

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has insufficient remaining quota.

An organization owner can choose the repository organization as the billing source for reviews requested by members with a paid Copilot license. Learn about Copilot code review billing.

@kumilingus
kumilingus merged commit cbdcefb into clientIO:dev Oct 29, 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.

connectionStrategies: a pin() factory with useModelGeometry and clamp options

3 participants