Skip to content

Conversation

AustinMroz
Copy link
Collaborator

@AustinMroz AustinMroz commented Aug 29, 2025

DOMWidgets do not perfectly align with their allocated space on a node.
Clicks on the element proper are never seen by litegraph, but there's a small border region where the LegacyWidget onClick method is called (See LGraphNode.getWidgetOnPos). To end users who will not see the console warning, it appears the click just gets swallowed.

This PR addresses the issue in two parts:

  • It provides a method on canvas to set a pointer event to be handled as a passthrough
  • It sets DOMWidgets to use this method for clicks that are not handled by the element itself

┆Issue is synchronized with this Notion page by Unito

@AustinMroz AustinMroz requested a review from a team as a code owner August 29, 2025 18:41
@dosubot dosubot bot added the size:S This PR changes 10-29 lines, ignoring generated files. label Aug 29, 2025
Copy link

github-actions bot commented Aug 29, 2025

🎭 Playwright Test Results

All tests passed across all browsers!

⏰ Completed at: 08/31/2025, 03:48:01 AM UTC

📊 Test Reports by Browser


🎉 Your tests are passing across all browsers!

@DrJKL DrJKL self-assigned this Aug 29, 2025
Comment on lines 2855 to 2856
pointer.onDragStart = () => this.#startDraggingItems(node, pointer)
pointer.onDragEnd = (e) => this.#processDraggedItems(e)
Copy link
Contributor

Choose a reason for hiding this comment

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

Any chance this could be clobbering something?

@@ -2851,6 +2851,12 @@ export class LGraphCanvas

this.dirty_canvas = true
}
passPointerEvent(pointer: CanvasPointer, node: LGraphNode): boolean {
Copy link
Contributor

Choose a reason for hiding this comment

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

If it's an intentional mutation, I usually like to note that in the function name.
Something like augmentPointerDragEvents maybe?

pointer: CanvasPointer,
node: LGraphNode,
canvas: LGraphCanvas
): boolean {
Copy link
Contributor

Choose a reason for hiding this comment

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

Complete side-note, what does the return boolean indicate?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

It indicates that the pointer event is handled and no more processing should be performed. Here, it just skips a bunch of legacy mouse event handling code and prevents a warning message from being printed in the console about the legacy code.

Copy link
Contributor

Choose a reason for hiding this comment

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

So it kind of emulates preventDefault or cancel on a true event?

node: LGraphNode,
canvas: LGraphCanvas
): boolean {
return canvas.passPointerEvent(pointer, node)
Copy link
Contributor

Choose a reason for hiding this comment

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

It feels weird to add listeners as a result of a different event here.

@DrJKL DrJKL assigned AustinMroz and unassigned DrJKL Aug 29, 2025
Copy link
Contributor

@christian-byrne christian-byrne left a comment

Choose a reason for hiding this comment

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

Not to say this change is not good in its own right, but I wonder if there's also a bonafide bug/regression in the hit-testing? (Or maybe the cause is stated elsewhere and I am missing it -- apologies if so.)

It seems this line is using 6px:

if (
widget.last_y !== undefined &&
isInRectangle(x, y, 6, widget.last_y, w - 12, h)
) {

Would the issue be solved by doing something like this:

getWidgetOnPos(canvasX: number, canvasY: number, includeDisabled = false): IBaseWidget | undefined {
  // ... existing code ...

  for (const widget of widgets) {
    // ... visibility checks ...

    // Use DOM widget margin instead of hardcoded 6px
    const margin = widget.margin ?? 6  // DOM widgets have margin property
    
    // ... other code ..

    if (
      widget.last_y !== undefined &&
      isInRectangle(x, y, margin, widget.last_y, w - margin * 2, h)  
    ) {
      return widget
    }
  }
}

@AustinMroz
Copy link
Collaborator Author

Will do some testing. I would also prefer this as I'm not completely confident about custom nodes using both domWidget + legacy mouse method. Code search was inconclusive.

IIRC, the space between widgets will always be assigned to a widget, but the primary annoyance was clicks above the first widget.

@AustinMroz
Copy link
Collaborator Author

After investigating, this works much better than expected.

  • The margin attribute on DOMwidgets works fabulously, The widget fills last_y + margin to h - 2*margin cleanly
  • Normal widgets have 4 pixels height margin, but an inconvenient height offset.
    • Since the gap between widgets is small, it may be worth fixing the height offset, but setting margins to 0 for QOL: No one wants to select or drag a node by clicking between normal widgets.
widget-hit-detection-offset

@webfiltered
Copy link
Contributor

  • No one wants to select or drag a node by clicking between normal widgets.

The removal of gap between widgets was intentional; it always felt like it was a bug to me.

The glitchy feeling of it intensified when we added "drag link on widget => auto-convert to input" - caused flickering when you dragged a link over a node. After I added snap highlighting on the widgets, it -really- needed to go.

@AustinMroz AustinMroz force-pushed the austin/fix-domwidget-pointer-events branch from bafdab8 to 506219d Compare August 31, 2025 03:24
Copy link

github-actions bot commented Aug 31, 2025

🎨 Storybook Build Status

Build failed!

⏰ Completed at: 08/31/2025, 03:24:52 AM UTC

🔗 Links


⚠️ Please check the workflow logs for error details.

Copy link
Contributor

@christian-byrne christian-byrne left a comment

Choose a reason for hiding this comment

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

LGTM!

@christian-byrne christian-byrne merged commit c4bb8a1 into main Sep 3, 2025
11 checks passed
@christian-byrne christian-byrne deleted the austin/fix-domwidget-pointer-events branch September 3, 2025 19:44
@benceruleanlu benceruleanlu mentioned this pull request Sep 4, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area:dom-widgets size:S This PR changes 10-29 lines, ignoring generated files.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants