litegraph.js icon indicating copy to clipboard operation
litegraph.js copied to clipboard

is there an onGraphChange() or onCanvasChange() event?

Open Weixuanf opened this issue 1 year ago • 2 comments

I need to listen for when user change the graph or canvas. If an event can be emitted and listened for it would be great!

Weixuanf avatar Mar 14 '24 11:03 Weixuanf

LGraph.onchange() will be fired even when zooming and dragging canvas, without graph nodes values change

LGraph.onAfterChange() will not be fired when a node widget value change, either not fired when configure() a new graph....🫠

this is what I'm doing now but I don't think this is accurate:

    document.addEventListener("click", (e) => {
      if (
        app.canvas.node_over != null ||
        app.canvas.node_capturing_input != null ||
        app.canvas.node_widget != null
      ) {
        onIsDirty();
      }
    });
    document.addEventListener("keydown", async function (event) {
      if (document.visibilityState === "hidden") return;
      const matchResult = await matchShortcut(event);
      if (matchResult) {
        shortcutListener(matchResult);
      } else if (
        // @ts-expect-error
        event.target?.matches("input, textarea") &&
        Object.keys(app.canvas.selected_nodes ?? {}).length
      ) {
        onIsDirty();
      }
    });
    ```

Weixuanf avatar Mar 18 '24 11:03 Weixuanf

Perhaps someone needs it, I'll leave the code here that I'm sure can be used (there might be performance issues, but it can ensure that the graph change event is triggered correctly):

class LGraphPro extends LGraph {
  private _graph_cache = {} as serializedLGraph;

  emit(...args: any[]) { /* ... */ }

  change(): void {
    super.change();
    this.emit("change");

    this.checkGraphChange();
  }

  connectionChange(node: LGraphNode): void {
    super.connectionChange?.(node);
    this.emit("connection_change", node);

    this.checkGraphChange();
  }

  serializeDeep(options?: {
    skip_inputs?: boolean;
    skip_outputs?: boolean;
    skip_properties?: boolean;
    skip_links?: boolean;
    skip_nodes?: boolean;
  }) {
    const graph_obj = this.serialize();
    graph_obj.nodes.sort((a, b) => a.id - b.id);

    if (options?.skip_inputs) {
      graph_obj.nodes.map((x) => (x.inputs = []));
    }
    if (options?.skip_outputs) {
      graph_obj.nodes.map((x) => (x.outputs = []));
    }
    if (options?.skip_properties) {
      graph_obj.nodes.map((x) => (x.properties = {}));
    }
    if (options?.skip_links) {
      graph_obj.links = [];
    }
    if (options?.skip_nodes) {
      graph_obj.nodes = [];
    }

    return cloneDeep(graph_obj);
  }

  private checkGraphChange() {
    const graph_obj = this.serializeDeep({
      skip_inputs: true,
      skip_outputs: true,
      skip_properties: true,
    });
    if (deepEqual(graph_obj, this._graph_cache)) {
      return;
    }
    this._graph_cache = graph_obj;
    this.events?.emit("graph_change", this.serializeDeep());
  }
}

zhzLuke96 avatar May 17 '24 16:05 zhzLuke96