Skip to content

fix(camera): restore pan on non-draggable graph components#309

Merged
draedful merged 2 commits into
mainfrom
cursor/fix-camera-pan-on-non-draggable-blocks
Jul 8, 2026
Merged

fix(camera): restore pan on non-draggable graph components#309
draedful merged 2 commits into
mainfrom
cursor/fix-camera-pan-on-non-draggable-blocks

Conversation

@draedful

@draedful draedful commented Jul 7, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Restore camera pan when clicking graph components that are not draggable (e.g. canDrag: NONE or unselected blocks in ONLY_SELECTED mode)
  • Defer pan only when the mousedown target is a GraphComponent with isDraggable() === true, matching DragService behavior

Test plan

  • Manual: pan works when dragging over blocks with canDrag: NONE
  • Manual: blocks still drag when canDrag: ALL
  • Manual: middle-click pan on blocks still works
  • Manual: anchor/connection interactions are unaffected

Made with Cursor

Summary by Sourcery

Adjust camera and connection interaction to restore panning on non-draggable graph components while tightening port snapping behavior.

Bug Fixes:

  • Allow camera panning when clicking graph components that are not draggable, while still deferring to DragService for draggable components.
  • Prevent connection and port creation handlers from blocking camera panning when the mouse interaction does not target a valid, snappable port.

Enhancements:

  • Restrict connection creation and snapping logic to ports marked as snappable, using a shared helper for port metadata checks.
  • Resolve ports for new connections at mousedown time using screen-to-world coordinate conversion for more accurate hit testing.
  • Register connection layer mousedown handling in the capture phase to ensure consistent interception and propagation control of graph events.

Allow camera pan when clicking blocks with canDrag disabled by deferring
only to GraphComponent.isDraggable(), matching DragService behavior.

Co-authored-by: Cursor <cursoragent@cursor.com>
@sourcery-ai

sourcery-ai Bot commented Jul 7, 2026

Copy link
Copy Markdown

Reviewer's Guide

Adjusts camera panning to only defer to DragService when the mousedown target is a draggable GraphComponent, and tightens connection creation logic so only snappable ports participate while initiating connection drags earlier in the event phase.

File-Level Changes

Change Details Files
Restrict camera pan deferral to draggable graph components so panning works over non-draggable blocks and respects prevented graph events.
  • Import GraphComponent and isGraphEvent into the Camera service to reason about targets and default-prevented events.
  • Early-return from camera mousedown when a GraphMouseEvent has default prevented, aligning with other handlers that claim the event.
  • Treat left-button mousedowns on non-draggable GraphComponents like empty canvas by allowing camera pan to start, while still deferring to DragService when the target is a draggable GraphComponent.
  • Factor target-draggability check into a dedicated isTargetDraggable helper for clarity and reuse.
src/services/camera/Camera.ts
Make connection creation use only snappable ports and resolve the source port before starting a drag, using screen-to-world conversion at mousedown time.
  • Introduce a reusable isSnappablePort helper that inspects per-port connection meta for the snappable flag.
  • Compute world coordinates from the native mousedown event via getXY and cameraService.applyToPoint before starting drag, and find the nearest snappable port on the initial component at that point.
  • Abort port-connection handling for non-left mouse buttons and when no snappable port is found at mousedown, preventing unnecessary drag setup.
  • Simplify drag start logic by reusing the port resolved at mousedown rather than re-searching during onStart.
  • Tighten target port lookup for snapping and drop by filtering candidate ports through isSnappablePort and existing ownership/id checks.
  • Reuse isSnappablePort when computing snapping boxes, eliminating duplicated meta access logic.
src/components/canvas/layers/portConnectionLayer/PortConnectionLayer.ts
Ensure connection creation mousedown is captured early and claims the event when appropriate, preventing camera pan from starting when a valid connection drag begins.
  • Register the ConnectionLayer mousedown handler in the capture phase so it can intercept events before bubbling handlers like the camera.
  • Ignore non-left mouse buttons when considering connection creation to avoid interfering with middle-click panning and other interactions.
  • When a connection creation should start, prevent the graph event default and stop propagation so DragService owns the drag sequence and camera panning does not trigger.
src/components/canvas/layers/connectionLayer/ConnectionLayer.ts

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@gravity-ui-bot

Copy link
Copy Markdown
Contributor

Preview is ready.

…dling

Respect preventGraphEventDefault from connection layers, restrict connection
drag to left-click and snappable ports, and avoid blocking block drag in
PortConnectionLayer when the pointer is not on a port.

Co-authored-by: Cursor <cursoragent@cursor.com>
@draedful

draedful commented Jul 7, 2026

Copy link
Copy Markdown
Collaborator Author

@sourcery-ai review

@draedful draedful marked this pull request as ready for review July 7, 2026 20:41
@draedful draedful requested a review from Antamansid as a code owner July 7, 2026 20:41

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Hey - I've left some high level feedback:

  • In Camera.handleMouseDown, isTargetDraggable only recognizes GraphComponent as draggable; if other EventedComponent subclasses can be draggable now or in the future, it may be safer for them to expose a common isDraggable API or marker interface instead of hard-coding the type check.
  • Both PortConnectionLayer.handleMouseDown and ConnectionLayer.handleMouseDown now include explicit button !== 0 early returns; consider centralizing this left-button-only guard (and possibly the preventGraphEventDefault behavior) in a shared helper to keep mouse handling consistent across layers.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In `Camera.handleMouseDown`, `isTargetDraggable` only recognizes `GraphComponent` as draggable; if other `EventedComponent` subclasses can be draggable now or in the future, it may be safer for them to expose a common `isDraggable` API or marker interface instead of hard-coding the type check.
- Both `PortConnectionLayer.handleMouseDown` and `ConnectionLayer.handleMouseDown` now include explicit `button !== 0` early returns; consider centralizing this left-button-only guard (and possibly the `preventGraphEventDefault` behavior) in a shared helper to keep mouse handling consistent across layers.

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Hey - I've reviewed your changes and they look great!


Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@draedful draedful merged commit 25021a7 into main Jul 8, 2026
10 checks passed
@draedful draedful deleted the cursor/fix-camera-pan-on-non-draggable-blocks branch July 8, 2026 11:16
@gravity-ui gravity-ui Bot mentioned this pull request Jul 8, 2026
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