This guide will walk you through creating a custom node in litegraph.js that dynamically adds a new input when the last input is filled. This can be useful for creating nodes that can handle a variable number of inputs, depending on the user's connections.
Before you begin, make sure you have a basic understanding of:
- JavaScript: The primary language used for
litegraph.js. - litegraph.js: Familiarity with the core concepts of
litegraph.js, such as nodes, inputs, outputs, and the graph canvas.
Sometimes, you might need a node in your visual graph editor that can accept a varying number of inputs. For example, you might want a node that combines multiple values, and the number of values to combine isn't fixed beforehand. Instead of predefining a large number of potential inputs, it's more user-friendly to add new inputs as the existing ones are connected.
We'll create a custom node class that extends LGraphNode and implements the logic to add new inputs dynamically.
class DynamicInputNode extends LGraphNode {
constructor() {
super();
this.title = "Dynamic Inputs";
this.color = "#AA33AA";
this.inputs = [["Input 1", ""]]; // Initialize with one input
this.input_count = 1;
}
// This method is called when an input gets connected
onInputConnected(slot, node, output_slot) {
// Check if the connected slot is the last available input
if (slot === this.input_count - 1) {
// Add a new input
this.addInput(`Input ${this.input_count + 1}`, "");
this.input_count++;
// Trigger a redraw of the canvas to show the new input
this.setDirtyCanvas(true);
}
}
// Optional: You might want to handle the case where an input is disconnected
// onInputDisconnected(slot, node, output_slot) {
// // Implement logic here to remove inputs if needed potentially.
// }
// Optional: You might want to provide a method to get the data from the inputs
onExecute() {
this.inputs_data = [];
for (let i = 0; i < this.inputs.length; ++i) {
this.inputs_data.push(this.getInputData(i));
}
// You can now work with the this.inputs_data array
// console.log("Input data:", this.inputs_data);
}
// Define the output if your node produces any
// onGetOutput(slot) {
// return this.some_output_data;
// }
}
// Register your custom node type with LiteGraph
LiteGraph.registerNodeType("my_nodes/dynamic_input", DynamicInputNode);Let's break down the code step by step:
-
class DynamicInputNode extends LGraphNode:- We define a new JavaScript class named
DynamicInputNodethat inherits fromLGraphNode. This is the foundation for our custom node.
- We define a new JavaScript class named
-
constructor():super();: Calls the constructor of the parent class (LGraphNode) to initialize the base properties of the node.this.title = "Dynamic Inputs";: Sets the title that will be displayed on the node in the editor.this.color = "#AA33AA";: Sets the background color of the node for visual identification.this.inputs = [["Input 1", ""]];: Initializes the node with a single input named "Input 1". The array structure[["name", "type"]]defines the input. An empty string for the type means it can accept any data type.this.input_count = 1;: This variable keeps track of the current number of input slots the node has. We initialize it to 1 since we start with one input.
-
onInputConnected(slot, node, output_slot):- This is a crucial method in
litegraph.js. It's a callback function that gets automatically called whenever an input on your node is successfully connected to the output of another node in the graph. slot: This argument represents the index of the input slot that was just connected (starting from 0 for the first input).node: This is the instance of the node that is providing the output connection.output_slot: This is the index of the output slot on the providing node that was connected.if (slot === this.input_count - 1): This condition checks if the connected input is the last currently available input on our dynamic node. Sincethis.input_countholds the total number of inputs, the index of the last input is alwaysthis.input_count - 1.this.addInput(\Input ${this.input_count + 1}`, "");: If the last input was connected, we call theaddInput()method of theLGraphNode` class to add a new input slot to our node. We dynamically name the new input as "Input 2", "Input 3", and so on.this.input_count++;: We increment ourinput_countto reflect the addition of the new input.this.setDirtyCanvas(true);: This is very important. After modifying the node's interface (by adding a new input), we need to tell thelitegraph.jscanvas that the node has changed and needs to be redrawn. This will make the newly added input visible in the editor.
- This is a crucial method in
-
onInputDisconnected(slot, node, output_slot)(Optional):- This method is the counterpart to
onInputConnected. It's called when an input is disconnected. To keep the node tidy, you could implement logic here to remove inputs if the last one is disconnected. You would need to be careful about the logic for removing inputs, especially if data flow depends on the order of inputs.
- This method is the counterpart to
-
onExecute()(Optional):- This method is called when the graph is being executed. Here, we demonstrate how you can access the data from all the dynamically added inputs.
- We loop through the
this.inputsarray (which holds the definitions of all inputs) and usethis.getInputData(i)to retrieve the data that is connected to each input slot. This data is then stored in thethis.inputs_dataarray. You would typically perform your node's main logic within this method.
-
onGetOutput(slot)(Optional):- If your dynamic input node is also meant to produce some output based on the connected inputs, you would implement the
onGetOutput(slot)method.
- If your dynamic input node is also meant to produce some output based on the connected inputs, you would implement the
-
LiteGraph.registerNodeType("my_nodes/dynamic_input", DynamicInputNode);:- This line is essential for making your custom node available in the
litegraph.jseditor. "my_nodes/dynamic_input": This is a unique string identifier for your node type. You can choose your own namespace and name for your node. Using a namespace (like"my_nodes/") is common practice to organize your custom nodes.DynamicInputNode: This is the constructor of the custom node class we defined.
- This line is essential for making your custom node available in the
To use this dynamic input node in your litegraph.js project, follow these steps:
-
Ensure litegraph.js is included: Ensure you include the
litegraph.jslibrary in your HTML file. -
Register the node: Include the JavaScript code for the
DynamicInputNodeclass in your script. This will automatically register the node type withLiteGraph. -
Create a graph and canvas: Set up your
LGraphandLGraphCanvasinstances as usual. -
Create an instance of your dynamic node:
const graph = new LiteGraph.LGraph(); const canvas = new LiteGraph.LGraphCanvas("#mycanvas", graph); const dynamicNode = LiteGraph.createNode("my_nodes/dynamic_input"); dynamicNode.pos = [100, 100]; // Set the position of the node graph.addNode(dynamicNode);
-
Connect to the inputs: When you connect an output from another node to the first input of your "Dynamic Inputs" node, you will see that a second input automatically appears. This process will repeat each time you connect to the last available input on the node.
- Removing Inputs: The current implementation only adds inputs. To keep the node interface clean, you might want to implement the
onInputDisconnectedmethod to potentially remove inputs if the last one is disconnected. You would need to be careful about the logic for removing inputs, especially if data flow depends on the order of inputs. - Maximum Number of Inputs: To prevent the node from growing indefinitely, you might want to set a maximum number of inputs that can be added. To enforce this limit, you can add a check in the
onInputConnectedmethod. - Input Types: In this example, all inputs are of the generic type "". If needed, you could modify the
addInput()calls to specify different input types.
This guide provides a solid foundation for creating dynamic input nodes in litegraph.js. You can adapt and extend this example to create more complex and flexible nodes for your visual graph editing applications.