//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);