From 0e8f02f32f98041719901c500e3b8ffb95832404 Mon Sep 17 00:00:00 2001 From: ArtificialLab <2308123+dmx974@users.noreply.github.com> Date: Sat, 16 Nov 2024 07:01:59 +0400 Subject: [PATCH] Add canvas update events (#297) * (add) onNodeUpdated, onPositionChanged and onZoomChanged * (fix) onPositionChanged * (add) onNodeWidgetChanged callback --- src/LGraph.ts | 17 +++++++++++------ src/LGraphCanvas.ts | 32 +++++++++++++++++++++++++++++++- 2 files changed, 42 insertions(+), 7 deletions(-) diff --git a/src/LGraph.ts b/src/LGraph.ts index d74bf2e0..900a8547 100644 --- a/src/LGraph.ts +++ b/src/LGraph.ts @@ -137,6 +137,7 @@ export class LGraph implements LinkNetwork, Serialisable { onExecuteStep?(): void onNodeAdded?(node: LGraphNode): void onNodeRemoved?(node: LGraphNode): void + onNodeUpdated?(node: LGraphNode): void onTrigger?(action: string, param: unknown): void onInputRenamed?(old_name: string, name: string): void onInputTypeChanged?(name: string, type: string): void @@ -145,8 +146,8 @@ export class LGraph implements LinkNetwork, Serialisable { onOutputRenamed?(old_name: string, name: string): void onOutputTypeChanged?(name: string, type: string): void onOutputRemoved?(name: string): void - onBeforeChange?(graph: LGraph, info?: LGraphNode): void - onAfterChange?(graph: LGraph, info?: LGraphNode): void + onBeforeChange?(graph: LGraph, node?: LGraphNode): void + onAfterChange?(graph: LGraph, node?: LGraphNode): void onConnectionChange?(node: LGraphNode): void on_change?(graph: LGraph): void onSerialize?(data: ISerialisedGraph | SerialisableGraph): void @@ -1205,15 +1206,19 @@ export class LGraph implements LinkNetwork, Serialisable { } } //used for undo, called before any change is made to the graph - beforeChange(info?: LGraphNode): void { - this.onBeforeChange?.(this, info) + beforeChange(node?: LGraphNode): void { + this.onBeforeChange?.(this, node) this.canvasAction(c => c.onBeforeChange?.(this)) } //used to resend actions, called after any change is made to the graph - afterChange(info?: LGraphNode): void { - this.onAfterChange?.(this, info) + afterChange(node?: LGraphNode): void { + this.onAfterChange?.(this, node) this.canvasAction(c => c.onAfterChange?.(this)) } + nodeUpdate(node?: LGraphNode): void { + this.onNodeUpdated?.(node) + this.canvasAction(c => c.onNodeUpdated?.(node)) + } connectionChange(node: LGraphNode): void { this.updateExecutionOrder() this.onConnectionChange?.(node) diff --git a/src/LGraphCanvas.ts b/src/LGraphCanvas.ts index 52711265..da536a51 100644 --- a/src/LGraphCanvas.ts +++ b/src/LGraphCanvas.ts @@ -370,6 +370,8 @@ export class LGraphCanvas { onBeforeChange?(graph: LGraph): void /** called after modifying the graph */ onAfterChange?(graph: LGraph): void + onPositionChanged?: (offset: Point) => void + onZoomChanged?: (scale: number) => void onClear?: () => void /** called after moving a node */ onNodeMoved?: (node_dragged: LGraphNode) => void @@ -384,6 +386,8 @@ export class LGraphCanvas { onShowNodePanel?: (n: LGraphNode) => void onNodeSelected?: (node: LGraphNode) => void onNodeDeselected?: (node: LGraphNode) => void + onNodeUpdated?: (node: LGraphNode) => void + onNodeWidgetChanged?: (node: LGraphNode, name: string, value: unknown, widget: IWidget) => void onRender?: (canvas: HTMLCanvasElement, ctx: CanvasRenderingContext2D) => void /** Implement this function to allow conversion of widget types to input types, e.g. number -> INT or FLOAT for widget link validation checks */ getWidgetLinkType?: (widget: IWidget, node: LGraphNode) => string | null | undefined @@ -2357,6 +2361,10 @@ export class LGraphCanvas { this.ds.offset[0] += delta[0] / this.ds.scale this.ds.offset[1] += delta[1] / this.ds.scale this.#dirty() + + if (this.onPositionChanged) { + this.onPositionChanged(this.ds.offset) + } } else if ((this.allow_interaction || (node && node.flags.allow_interaction)) && !this.read_only) { if (this.connecting_links) this.dirty_canvas = true @@ -2800,6 +2808,14 @@ export class LGraphCanvas { this.ds.changeScale(scale, [e.clientX, e.clientY]) + if (this.onZoomChanged) { + this.onZoomChanged(scale) + } + + if (this.onPositionChanged) { + this.onPositionChanged(this.ds.offset) + } + this.graph.change() e.preventDefault() @@ -3494,6 +3510,10 @@ export class LGraphCanvas { node.size[1] * 0.5 + (this.canvas.height * 0.5) / (this.ds.scale * dpi) this.setDirty(true, true) + + if (this.onPositionChanged) { + this.onPositionChanged(this.ds.offset) + } } /** * adds some useful properties to a mouse event, like the position in graph coordinates @@ -5927,7 +5947,9 @@ export class LGraphCanvas { if (event.type === LiteGraph.pointerevents_method + "down") { if (w.callback) { setTimeout(function () { - w.callback(w, that, node, pos, event) + that.onNodeWidgetChanged?.(node, w.name, w.value, w) + node.onWidgetChanged?.(w.name, w.value, old_value, w) + w.callback(w, that, node, pos, event) }, 20) } w.clicked = true @@ -6067,6 +6089,7 @@ export class LGraphCanvas { //value changed if (old_value != w.value) { + that.onNodeWidgetChanged?.(node, w.name, w.value, w) node.onWidgetChanged?.(w.name, w.value, old_value, w) node.graph._version++ } @@ -6077,6 +6100,9 @@ export class LGraphCanvas { function inner_value_change(widget: IWidget, value: TWidgetValue) { const v = widget.type === "number" ? Number(value) : value widget.value = v + + that.onNodeWidgetChanged?.(node, widget.name, widget.value, widget) + if (widget.options?.property && node.properties[widget.options.property] !== undefined) { node.setProperty(widget.options.property, v) } @@ -8163,6 +8189,10 @@ export class LGraphCanvas { this.setDirty(true, true) + if (this.onPositionChanged) { + this.onPositionChanged(this.ds.offset) + } + if (progress < 1) { animationId = requestAnimationFrame(animate) } else {