-
Notifications
You must be signed in to change notification settings - Fork 28
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ADD: Automatically move the viewport when dragging an item close to t… #517
base: master
Are you sure you want to change the base?
Conversation
…he canvas borders
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi there, thanks for the PR! The idea seems sound.
I think this feature should be opt-in for users, and if it's not enabled, everything should be bypassed (so no overhead).
If you're interested in making these changes yourself, please feel free!
src/DragAndScale.ts
Outdated
/** | ||
* Calculates the clamped vector between two points. | ||
* @param pointA The first point | ||
* @param pointB The second point | ||
* @returns Vector2 {@link Point} of pointA to pointB, clamped to the range [-1, 1] | ||
* @remarks Calculates a pseudo "normalized" Vector2 by clamping it in range. Faster than using SQRT for truly normalized vectors. DO NOT use as a true unit vector. | ||
* */ | ||
getVector2Clamped(pointA: Point, pointB: Point): Point { | ||
const tempVector: Point = [ | ||
(pointA[0] - pointB[0]) / pointB[0], | ||
(pointA[1] - pointB[1]) / pointB[1] | ||
] | ||
return [ | ||
Math.max(-1, Math.min(1, tempVector[0])), | ||
Math.max(-1, Math.min(1, tempVector[1])) | ||
] | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks like it should live in measure.ts
/ some other utility function module.
I'd also recommend just using two consts instead of making a Point
for one calculation; it'd actually be more concise.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've seen the measure.ts
and had the function placed there to begin with but got a bit unsure. Now I know. I'll move it.
src/DragAndScale.ts
Outdated
/** | ||
* Automatically moves the canvas to follow the mouse. | ||
* @param deltaT Time difference since last frame | ||
* @param mouse Current mouse position | ||
* @param canvasCenter Center of the canvas | ||
* @param selectedItems Items that should be moved with the canvas when moving | ||
* @remarks Does not require items to be selected to work properly. Could add ramp up/down for smoother movement transition. | ||
* */ | ||
autoMoveCanvas(deltaT: number, mouse: Point, canvasCenter: Point, selectedItems: Set<Positionable> = null): void { | ||
const moveDirection = this.getVector2Clamped(mouse, canvasCenter) | ||
if (Math.abs(moveDirection[0]) > this.move_threshold || Math.abs(moveDirection[1]) > this.move_threshold) { | ||
const newOffset = [ | ||
moveDirection[0] * deltaT * this.move_factor, | ||
moveDirection[1] * deltaT * this.move_factor, | ||
] | ||
this.offset[0] -= newOffset[0] / this.scale | ||
this.offset[1] -= newOffset[1] / this.scale | ||
|
||
if (!selectedItems) return | ||
for (const item of selectedItems) { | ||
item.move(newOffset[0] / this.scale, newOffset[1] / this.scale, false) | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The DragAndScale
object is a subordinate object of the canvas - it is more "do what you're told" than "make decisions". Movement of items is generally performed by the canvas or graph.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I could adapt the function and move it to the LGraphCanvas.ts
.
@webfiltered or would you prefer it in any other location? LGraphCanvas kinda makes sense.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I am loathe to recommend adding more to LGraphCanvas, but it is definitely the only logical choice right now. Thank you!
src/LGraphCanvas.ts
Outdated
if (this.isDragging || this.connecting_links) { | ||
const canvasCenter: Point = [ | ||
this.canvas.clientWidth / 2, | ||
this.canvas.clientHeight / 2 | ||
] | ||
const selected = this.connecting_links ? null : this.selectedItems // Prevent selected items from being moved when dragging a connector | ||
this.ds.autoMoveCanvas(this.render_time, this.mouse, canvasCenter, selected) | ||
this.#dirty() | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this belongs in a CanvasPointer callback, like other movement calculations. If there's a reason it's in the measure pass, please let us know.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If I'm not mistaken most CanvasPointer
events only trigger when actually doing something with the pointer/mouse like down, up, drag, etc. This way the auto move would become a bit janky. It'll work but not as expected.
Let's say I'll use a move
event for updating the viewport position. It'll work for sure but you gotta wiggle around the mouse to keep it working otherwise it'll just stop moving. By using a tick event like the draw
loop we'll make sure the viewport keeps moving as long as the Positionable
is close enough to the bounds even when dragging
but not moving the mouse anymore.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You are not mistaken at all! I just need to expand a little:
- Use
CanvasPointer
events to monitor the mouse movement (performant and keeps concerns separate) - Keep state on the CanvasPointer object, e.g. when the pointer gets to the edge, is dragging stuff, and should start panning
pointer.atEdgeOfScreenAndDraggingStuff = true
(please don't use this name though haha)
- I think a short interval may be better for movement at lower FPS, provided the thread isn't blocked elsewhere in the pipeline; changing the canvas offset between frames has almost no cost.
If point 3 doesn't work or seems like too much effort, you can insert a call to a function that does the above checks below the draw call here:
litegraph.js/src/LGraphCanvas.ts
Lines 1893 to 1896 in 4cee8ca
function renderFrame(this: LGraphCanvas) { | |
if (!this.pause_rendering) { | |
this.draw() | |
} |
Hey @webfiltered, Thanks for the fast reply. I'll make the changes based on your feedback and get back to you. |
…terval, changed Point to const number for calculations, set up variables for UI (threshold, speed, enable)
Hey @webfiltered, Here's a quick rundown:
I totally understand why you loathe the Let me know what you think. |
…ning as an interval to prevent speed from varying based on fps
… (fixed failing tests)
Refers to issue #516