//basic nodes (function(global) { var LiteGraph = global.LiteGraph; //Constant function Time() { this.addOutput("in ms", "number"); this.addOutput("in sec", "number"); } Time.title = "Time"; Time.desc = "Time"; Time.prototype.onExecute = function() { this.setOutputData(0, this.graph.globaltime * 1000); this.setOutputData(1, this.graph.globaltime); }; LiteGraph.registerNodeType("basic/time", Time); //Subgraph: a node that contains a graph function Subgraph() { var that = this; this.size = [140, 80]; this.properties = { enabled: true }; this.enabled = true; //create inner graph this.subgraph = new LGraph(); this.subgraph._subgraph_node = this; this.subgraph._is_subgraph = true; this.subgraph.onTrigger = this.onSubgraphTrigger.bind(this); this.subgraph.onInputAdded = this.onSubgraphNewInput.bind(this); this.subgraph.onInputRenamed = this.onSubgraphRenamedInput.bind(this); this.subgraph.onInputTypeChanged = this.onSubgraphTypeChangeInput.bind( this ); this.subgraph.onInputRemoved = this.onSubgraphRemovedInput.bind(this); this.subgraph.onOutputAdded = this.onSubgraphNewOutput.bind(this); this.subgraph.onOutputRenamed = this.onSubgraphRenamedOutput.bind(this); this.subgraph.onOutputTypeChanged = this.onSubgraphTypeChangeOutput.bind( this ); this.subgraph.onOutputRemoved = this.onSubgraphRemovedOutput.bind(this); } Subgraph.title = "Subgraph"; Subgraph.desc = "Graph inside a node"; Subgraph.title_color = "#334"; Subgraph.prototype.onGetInputs = function() { return [["enabled", "boolean"]]; }; Subgraph.prototype.onDrawTitle = function(ctx) { if (this.flags.collapsed) return; ctx.fillStyle = "#555"; var w = LiteGraph.NODE_TITLE_HEIGHT; var x = this.size[0] - w; ctx.fillRect(x, -w, w, w); ctx.fillStyle = "#333"; ctx.beginPath(); ctx.moveTo(x + w * 0.2, -w * 0.6); ctx.lineTo(x + w * 0.8, -w * 0.6); ctx.lineTo(x + w * 0.5, -w * 0.3); ctx.fill(); }; Subgraph.prototype.onDblClick = function(e, pos, graphcanvas) { var that = this; setTimeout(function() { graphcanvas.openSubgraph(that.subgraph); }, 10); }; Subgraph.prototype.onMouseDown = function(e, pos, graphcanvas) { if ( !this.flags.collapsed && pos[0] > this.size[0] - LiteGraph.NODE_TITLE_HEIGHT && pos[1] < 0 ) { var that = this; setTimeout(function() { graphcanvas.openSubgraph(that.subgraph); }, 10); } }; Subgraph.prototype.onAction = function(action, param) { this.subgraph.onAction(action, param); }; Subgraph.prototype.onExecute = function() { this.enabled = this.getInputOrProperty("enabled"); if (!this.enabled) return; //send inputs to subgraph global inputs if (this.inputs) for (var i = 0; i < this.inputs.length; i++) { var input = this.inputs[i]; var value = this.getInputData(i); this.subgraph.setInputData(input.name, value); } //execute this.subgraph.runStep(); //send subgraph global outputs to outputs if (this.outputs) for (var i = 0; i < this.outputs.length; i++) { var output = this.outputs[i]; var value = this.subgraph.getOutputData(output.name); this.setOutputData(i, value); } }; Subgraph.prototype.sendEventToAllNodes = function(eventname, param, mode) { if (this.enabled) this.subgraph.sendEventToAllNodes(eventname, param, mode); }; //**** INPUTS *********************************** Subgraph.prototype.onSubgraphTrigger = function(event, param) { var slot = this.findOutputSlot(event); if (slot != -1) this.triggerSlot(slot); }; Subgraph.prototype.onSubgraphNewInput = function(name, type) { var slot = this.findInputSlot(name); if (slot == -1) //add input to the node this.addInput(name, type); }; Subgraph.prototype.onSubgraphRenamedInput = function(oldname, name) { var slot = this.findInputSlot(oldname); if (slot == -1) return; var info = this.getInputInfo(slot); info.name = name; }; Subgraph.prototype.onSubgraphTypeChangeInput = function(name, type) { var slot = this.findInputSlot(name); if (slot == -1) return; var info = this.getInputInfo(slot); info.type = type; }; Subgraph.prototype.onSubgraphRemovedInput = function(name) { var slot = this.findInputSlot(name); if (slot == -1) return; this.removeInput(slot); }; //**** OUTPUTS *********************************** Subgraph.prototype.onSubgraphNewOutput = function(name, type) { var slot = this.findOutputSlot(name); if (slot == -1) this.addOutput(name, type); }; Subgraph.prototype.onSubgraphRenamedOutput = function(oldname, name) { var slot = this.findOutputSlot(oldname); if (slot == -1) return; var info = this.getOutputInfo(slot); info.name = name; }; Subgraph.prototype.onSubgraphTypeChangeOutput = function(name, type) { var slot = this.findOutputSlot(name); if (slot == -1) return; var info = this.getOutputInfo(slot); info.type = type; }; Subgraph.prototype.onSubgraphRemovedOutput = function(name) { var slot = this.findInputSlot(name); if (slot == -1) return; this.removeOutput(slot); }; // ***************************************************** Subgraph.prototype.getExtraMenuOptions = function(graphcanvas) { var that = this; return [ { content: "Open", callback: function() { graphcanvas.openSubgraph(that.subgraph); } } ]; }; Subgraph.prototype.onResize = function(size) { size[1] += 20; }; Subgraph.prototype.serialize = function() { var data = LGraphNode.prototype.serialize.call(this); data.subgraph = this.subgraph.serialize(); return data; }; //no need to define node.configure, the default method detects node.subgraph and passes the object to node.subgraph.configure() Subgraph.prototype.clone = function() { var node = LiteGraph.createNode(this.type); var data = this.serialize(); delete data["id"]; delete data["inputs"]; delete data["outputs"]; node.configure(data); return node; }; LiteGraph.Subgraph = Subgraph; LiteGraph.registerNodeType("graph/subgraph", Subgraph); //Input for a subgraph function GraphInput() { this.addOutput("", ""); this.name_in_graph = ""; this.properties = {}; var that = this; Object.defineProperty(this.properties, "name", { get: function() { return that.name_in_graph; }, set: function(v) { if (v == "" || v == that.name_in_graph || v == "enabled") return; if (that.name_in_graph) //already added that.graph.renameInput(that.name_in_graph, v); else that.graph.addInput(v, that.properties.type); that.name_widget.value = v; that.name_in_graph = v; }, enumerable: true }); Object.defineProperty(this.properties, "type", { get: function() { return that.outputs[0].type; }, set: function(v) { if (v == "event") v = LiteGraph.EVENT; that.outputs[0].type = v; if (that.name_in_graph) //already added that.graph.changeInputType( that.name_in_graph, that.outputs[0].type ); that.type_widget.value = v; }, enumerable: true }); this.name_widget = this.addWidget( "text", "Name", this.properties.name, function(v) { if (!v) return; that.properties.name = v; } ); this.type_widget = this.addWidget( "text", "Type", this.properties.type, function(v) { v = v || ""; that.properties.type = v; } ); this.widgets_up = true; this.size = [180, 60]; } GraphInput.title = "Input"; GraphInput.desc = "Input of the graph"; GraphInput.prototype.getTitle = function() { if (this.flags.collapsed) return this.properties.name; return this.title; }; GraphInput.prototype.onAction = function(action, param) { if (this.properties.type == LiteGraph.EVENT) this.triggerSlot(0, param); }; GraphInput.prototype.onExecute = function() { var name = this.properties.name; //read from global input var data = this.graph.inputs[name]; if (!data) return; //put through output this.setOutputData(0, data.value); }; GraphInput.prototype.onRemoved = function() { if (this.name_in_graph) this.graph.removeInput(this.name_in_graph); }; LiteGraph.GraphInput = GraphInput; LiteGraph.registerNodeType("graph/input", GraphInput); //Output for a subgraph function GraphOutput() { this.addInput("", ""); this.name_in_graph = ""; this.properties = {}; var that = this; Object.defineProperty(this.properties, "name", { get: function() { return that.name_in_graph; }, set: function(v) { if (v == "" || v == that.name_in_graph) return; if (that.name_in_graph) //already added that.graph.renameOutput(that.name_in_graph, v); else that.graph.addOutput(v, that.properties.type); that.name_widget.value = v; that.name_in_graph = v; }, enumerable: true }); Object.defineProperty(this.properties, "type", { get: function() { return that.inputs[0].type; }, set: function(v) { if (v == "action" || v == "event") v = LiteGraph.ACTION; that.inputs[0].type = v; if (that.name_in_graph) //already added that.graph.changeOutputType( that.name_in_graph, that.inputs[0].type ); that.type_widget.value = v || ""; }, enumerable: true }); this.name_widget = this.addWidget( "text", "Name", this.properties.name, function(v) { if (!v) return; that.properties.name = v; } ); this.type_widget = this.addWidget( "text", "Type", this.properties.type, function(v) { v = v || ""; that.properties.type = v; } ); this.widgets_up = true; this.size = [180, 60]; } GraphOutput.title = "Output"; GraphOutput.desc = "Output of the graph"; GraphOutput.prototype.onExecute = function() { this._value = this.getInputData(0); this.graph.setOutputData(this.properties.name, this._value); }; GraphOutput.prototype.onAction = function(action, param) { if (this.properties.type == LiteGraph.ACTION) this.graph.trigger(this.properties.name, param); }; GraphOutput.prototype.onRemoved = function() { if (this.name_in_graph) this.graph.removeOutput(this.name_in_graph); }; GraphOutput.prototype.getTitle = function() { if (this.flags.collapsed) return this.properties.name; return this.title; }; LiteGraph.GraphOutput = GraphOutput; LiteGraph.registerNodeType("graph/output", GraphOutput); //Constant function ConstantNumber() { this.addOutput("value", "number"); this.addProperty("value", 1.0); } ConstantNumber.title = "Const Number"; ConstantNumber.desc = "Constant number"; ConstantNumber.prototype.onExecute = function() { this.setOutputData(0, parseFloat(this.properties["value"])); }; ConstantNumber.prototype.getTitle = function() { if (this.flags.collapsed) return this.properties.value; return this.title; }; ConstantNumber.prototype.setValue = function(v) { this.properties.value = v; }; ConstantNumber.prototype.onDrawBackground = function(ctx) { //show the current value this.outputs[0].label = this.properties["value"].toFixed(3); }; LiteGraph.registerNodeType("basic/const", ConstantNumber); function ConstantString() { this.addOutput("", "string"); this.addProperty("value", ""); this.widget = this.addWidget( "text", "value", "", this.setValue.bind(this) ); this.widgets_up = true; this.size = [100, 30]; } ConstantString.title = "Const String"; ConstantString.desc = "Constant string"; ConstantString.prototype.setValue = function(v) { this.properties.value = v; }; ConstantString.prototype.onPropertyChanged = function(name, value) { this.widget.value = value; }; ConstantString.prototype.getTitle = ConstantNumber.prototype.getTitle; ConstantString.prototype.onExecute = function() { this.setOutputData(0, this.properties["value"]); }; LiteGraph.registerNodeType("basic/string", ConstantString); function ConstantData() { this.addOutput("", ""); this.addProperty("value", ""); this.widget = this.addWidget( "text", "json", "", this.setValue.bind(this) ); this.widgets_up = true; this.size = [140, 30]; this._value = null; } ConstantData.title = "Const Data"; ConstantData.desc = "Constant Data"; ConstantData.prototype.setValue = function(v) { this.properties.value = v; this.onPropertyChanged("value", v); }; ConstantData.prototype.onPropertyChanged = function(name, value) { this.widget.value = value; if (value == null || value == "") return; try { this._value = JSON.parse(value); this.boxcolor = "#AEA"; } catch (err) { this.boxcolor = "red"; } }; ConstantData.prototype.onExecute = function() { this.setOutputData(0, this._value); }; LiteGraph.registerNodeType("basic/data", ConstantData); function ObjectProperty() { this.addInput("obj", ""); this.addOutput("", ""); this.addProperty("value", ""); this.widget = this.addWidget( "text", "prop.", "", this.setValue.bind(this) ); this.widgets_up = true; this.size = [140, 30]; this._value = null; } ObjectProperty.title = "Object property"; ObjectProperty.desc = "Outputs the property of an object"; ObjectProperty.prototype.setValue = function(v) { this.properties.value = v; this.widget.value = v; }; ObjectProperty.prototype.getTitle = function() { if (this.flags.collapsed) return "in." + this.properties.value; return this.title; }; ObjectProperty.prototype.onPropertyChanged = function(name, value) { this.widget.value = value; }; ObjectProperty.prototype.onExecute = function() { var data = this.getInputData(0); if (data != null) this.setOutputData(0, data[this.properties.value]); }; LiteGraph.registerNodeType("basic/object_property", ObjectProperty); //Watch a value in the editor function Watch() { this.size = [60, 20]; this.addInput("value", 0, { label: "" }); this.value = 0; } Watch.title = "Watch"; Watch.desc = "Show value of input"; Watch.prototype.onExecute = function() { if (this.inputs[0]) this.value = this.getInputData(0); }; Watch.prototype.getTitle = function() { if (this.flags.collapsed) return this.inputs[0].label; return this.title; }; Watch.toString = function(o) { if (o == null) return "null"; else if (o.constructor === Number) return o.toFixed(3); else if (o.constructor === Array) { var str = "["; for (var i = 0; i < o.length; ++i) str += Watch.toString(o[i]) + (i + 1 != o.length ? "," : ""); str += "]"; return str; } else return String(o); }; Watch.prototype.onDrawBackground = function(ctx) { //show the current value this.inputs[0].label = Watch.toString(this.value); }; LiteGraph.registerNodeType("basic/watch", Watch); //in case one type doesnt match other type but you want to connect them anyway function Cast() { this.addInput("in", 0); this.addOutput("out", 0); this.size = [40, 20]; } Cast.title = "Cast"; Cast.desc = "Allows to connect different types"; Cast.prototype.onExecute = function() { this.setOutputData(0, this.getInputData(0)); }; LiteGraph.registerNodeType("basic/cast", Cast); //Show value inside the debug console function Console() { this.mode = LiteGraph.ON_EVENT; this.size = [80, 30]; this.addProperty("msg", ""); this.addInput("log", LiteGraph.EVENT); this.addInput("msg", 0); } Console.title = "Console"; Console.desc = "Show value inside the console"; Console.prototype.onAction = function(action, param) { if (action == "log") console.log(param); else if (action == "warn") console.warn(param); else if (action == "error") console.error(param); }; Console.prototype.onExecute = function() { var msg = this.getInputData(1); if (msg !== null) this.properties.msg = msg; console.log(msg); }; Console.prototype.onGetInputs = function() { return [ ["log", LiteGraph.ACTION], ["warn", LiteGraph.ACTION], ["error", LiteGraph.ACTION] ]; }; LiteGraph.registerNodeType("basic/console", Console); //Show value inside the debug console function Alert() { this.mode = LiteGraph.ON_EVENT; this.addProperty("msg", ""); this.addInput("", LiteGraph.EVENT); var that = this; this.widget = this.addWidget("text", "Text", "", function(v) { that.properties.msg = v; }); this.widgets_up = true; this.size = [200, 30]; } Alert.title = "Alert"; Alert.desc = "Show an alert window"; Alert.color = "#510"; Alert.prototype.onConfigure = function(o) { this.widget.value = o.properties.msg; }; Alert.prototype.onAction = function(action, param) { var msg = this.properties.msg; setTimeout(function() { alert(msg); }, 10); }; LiteGraph.registerNodeType("basic/alert", Alert); //Execites simple code function NodeScript() { this.size = [60, 20]; this.addProperty("onExecute", "return A;"); this.addInput("A", ""); this.addInput("B", ""); this.addOutput("out", ""); this._func = null; this.data = {}; } NodeScript.prototype.onConfigure = function(o) { if (o.properties.onExecute) this.compileCode(o.properties.onExecute); }; NodeScript.title = "Script"; NodeScript.desc = "executes a code (max 100 characters)"; NodeScript.widgets_info = { onExecute: { type: "code" } }; NodeScript.prototype.onPropertyChanged = function(name, value) { if (name == "onExecute" && LiteGraph.allow_scripts) { this.compileCode(value); } }; NodeScript.prototype.compileCode = function(code) { this._func = null; if (code.length > 100) console.warn("Script too long, max 100 chars"); else { var code_low = code.toLowerCase(); var forbidden_words = [ "script", "body", "document", "eval", "nodescript", "function" ]; //bad security solution for (var i = 0; i < forbidden_words.length; ++i) if (code_low.indexOf(forbidden_words[i]) != -1) { console.warn("invalid script"); return; } try { this._func = new Function("A", "B", "C", "DATA", "node", code); } catch (err) { console.error("Error parsing script"); console.error(err); } } }; NodeScript.prototype.onExecute = function() { if (!this._func) return; try { var A = this.getInputData(0); var B = this.getInputData(1); var C = this.getInputData(2); this.setOutputData(0, this._func(A, B, C, this.data, this)); } catch (err) { console.error("Error in script"); console.error(err); } }; NodeScript.prototype.onGetOutputs = function() { return [["C", ""]]; }; LiteGraph.registerNodeType("basic/script", NodeScript); })(this);