mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-02-02 22:37:32 +00:00
1346 lines
37 KiB
JavaScript
Executable File
1346 lines
37 KiB
JavaScript
Executable File
//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 LiteGraph.LGraph();
|
|
this.subgraph._subgraph_node = this;
|
|
this.subgraph._is_subgraph = true;
|
|
|
|
this.subgraph.onTrigger = this.onSubgraphTrigger.bind(this);
|
|
|
|
//nodes input node added inside
|
|
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);
|
|
}
|
|
};
|
|
|
|
Subgraph.prototype.onDrawBackground = function(ctx, graphcanvas, canvas, pos)
|
|
{
|
|
if(this.flags.collapsed)
|
|
return;
|
|
|
|
var y = this.size[1] - LiteGraph.NODE_TITLE_HEIGHT + 0.5;
|
|
|
|
//button
|
|
var over = LiteGraph.isInsideRectangle(pos[0],pos[1],this.pos[0],this.pos[1] + y,this.size[0],LiteGraph.NODE_TITLE_HEIGHT);
|
|
ctx.fillStyle = over ? "#555" : "#222";
|
|
ctx.beginPath();
|
|
ctx.roundRect( 0, y, this.size[0]+1, LiteGraph.NODE_TITLE_HEIGHT, 0, 8);
|
|
ctx.fill();
|
|
|
|
//button
|
|
ctx.textAlign = "center";
|
|
ctx.font = "24px Arial";
|
|
ctx.fillStyle = over ? "#DDD" : "#999";
|
|
ctx.fillText( "+", this.size[0] * 0.5, y + 24 );
|
|
}
|
|
|
|
Subgraph.prototype.onMouseDown = function(e, localpos, graphcanvas)
|
|
{
|
|
var y = this.size[1] - LiteGraph.NODE_TITLE_HEIGHT + 0.5;
|
|
if(localpos[1] > y)
|
|
{
|
|
graphcanvas.showSubgraphPropertiesDialog(this);
|
|
}
|
|
}
|
|
|
|
Subgraph.prototype.computeSize = function()
|
|
{
|
|
var num_inputs = this.inputs ? this.inputs.length : 0;
|
|
var num_outputs = this.outputs ? this.outputs.length : 0;
|
|
return [ 200, Math.max(num_inputs,num_outputs) * LiteGraph.NODE_SLOT_HEIGHT + LiteGraph.NODE_TITLE_HEIGHT ];
|
|
}
|
|
|
|
//**** 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 = LiteGraph.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;
|
|
};
|
|
|
|
Subgraph.prototype.buildFromNodes = function(nodes)
|
|
{
|
|
//clear all?
|
|
//TODO
|
|
|
|
//nodes that connect data between parent graph and subgraph
|
|
var subgraph_inputs = [];
|
|
var subgraph_outputs = [];
|
|
|
|
//mark inner nodes
|
|
var ids = {};
|
|
var min_x = 0;
|
|
var max_x = 0;
|
|
for(var i = 0; i < nodes.length; ++i)
|
|
{
|
|
var node = nodes[i];
|
|
ids[ node.id ] = node;
|
|
min_x = Math.min( node.pos[0], min_x );
|
|
max_x = Math.max( node.pos[0], min_x );
|
|
}
|
|
|
|
var last_input_y = 0;
|
|
var last_output_y = 0;
|
|
|
|
for(var i = 0; i < nodes.length; ++i)
|
|
{
|
|
var node = nodes[i];
|
|
//check inputs
|
|
if( node.inputs )
|
|
for(var j = 0; j < node.inputs.length; ++j)
|
|
{
|
|
var input = node.inputs[j];
|
|
if( !input || !input.link )
|
|
continue;
|
|
var link = node.graph.links[ input.link ];
|
|
if(!link)
|
|
continue;
|
|
if( ids[ link.origin_id ] )
|
|
continue;
|
|
//this.addInput(input.name,link.type);
|
|
this.subgraph.addInput(input.name,link.type);
|
|
/*
|
|
var input_node = LiteGraph.createNode("graph/input");
|
|
this.subgraph.add( input_node );
|
|
input_node.pos = [min_x - 200, last_input_y ];
|
|
last_input_y += 100;
|
|
*/
|
|
}
|
|
|
|
//check outputs
|
|
if( node.outputs )
|
|
for(var j = 0; j < node.outputs.length; ++j)
|
|
{
|
|
var output = node.outputs[j];
|
|
if( !output || !output.links || !output.links.length )
|
|
continue;
|
|
var is_external = false;
|
|
for(var k = 0; k < output.links.length; ++k)
|
|
{
|
|
var link = node.graph.links[ output.links[k] ];
|
|
if(!link)
|
|
continue;
|
|
if( ids[ link.target_id ] )
|
|
continue;
|
|
is_external = true;
|
|
break;
|
|
}
|
|
if(!is_external)
|
|
continue;
|
|
//this.addOutput(output.name,output.type);
|
|
/*
|
|
var output_node = LiteGraph.createNode("graph/output");
|
|
this.subgraph.add( output_node );
|
|
output_node.pos = [max_x + 50, last_output_y ];
|
|
last_output_y += 100;
|
|
*/
|
|
}
|
|
}
|
|
|
|
//detect inputs and outputs
|
|
//split every connection in two data_connection nodes
|
|
//keep track of internal connections
|
|
//connect external connections
|
|
|
|
//clone nodes inside subgraph and try to reconnect them
|
|
|
|
//connect edge subgraph nodes to extarnal connections nodes
|
|
}
|
|
|
|
LiteGraph.Subgraph = Subgraph;
|
|
LiteGraph.registerNodeType("graph/subgraph", Subgraph);
|
|
|
|
//Input for a subgraph
|
|
function GraphInput() {
|
|
this.addOutput("", "number");
|
|
|
|
this.name_in_graph = "";
|
|
this.properties = {
|
|
name: "",
|
|
type: "number",
|
|
value: 0
|
|
};
|
|
|
|
var that = this;
|
|
|
|
this.name_widget = this.addWidget(
|
|
"text",
|
|
"Name",
|
|
this.properties.name,
|
|
function(v) {
|
|
if (!v) {
|
|
return;
|
|
}
|
|
that.setProperty("name",v);
|
|
}
|
|
);
|
|
this.type_widget = this.addWidget(
|
|
"text",
|
|
"Type",
|
|
this.properties.type,
|
|
function(v) {
|
|
that.setProperty("type",v);
|
|
}
|
|
);
|
|
|
|
this.value_widget = this.addWidget(
|
|
"number",
|
|
"Value",
|
|
this.properties.value,
|
|
function(v) {
|
|
that.setProperty("value",v);
|
|
}
|
|
);
|
|
|
|
this.widgets_up = true;
|
|
this.size = [180, 90];
|
|
}
|
|
|
|
GraphInput.title = "Input";
|
|
GraphInput.desc = "Input of the graph";
|
|
|
|
GraphInput.prototype.onConfigure = function()
|
|
{
|
|
this.updateType();
|
|
}
|
|
|
|
GraphInput.prototype.updateType = function()
|
|
{
|
|
var type = this.properties.type;
|
|
this.type_widget.value = type;
|
|
if(this.outputs[0].type != type)
|
|
{
|
|
this.outputs[0].type = type;
|
|
this.disconnectOutput(0);
|
|
}
|
|
if(type == "number")
|
|
{
|
|
this.value_widget.type = "number";
|
|
this.value_widget.value = 0;
|
|
}
|
|
else if(type == "boolean")
|
|
{
|
|
this.value_widget.type = "toggle";
|
|
this.value_widget.value = true;
|
|
}
|
|
else if(type == "string")
|
|
{
|
|
this.value_widget.type = "text";
|
|
this.value_widget.value = "";
|
|
}
|
|
else
|
|
{
|
|
this.value_widget.type = null;
|
|
this.value_widget.value = null;
|
|
}
|
|
this.properties.value = this.value_widget.value;
|
|
}
|
|
|
|
GraphInput.prototype.onPropertyChanged = function(name,v)
|
|
{
|
|
if( name == "name" )
|
|
{
|
|
if (v == "" || v == this.name_in_graph || v == "enabled") {
|
|
return false;
|
|
}
|
|
if(this.graph)
|
|
{
|
|
if (this.name_in_graph) {
|
|
//already added
|
|
this.graph.renameInput( this.name_in_graph, v );
|
|
} else {
|
|
this.graph.addInput( v, this.properties.type );
|
|
}
|
|
} //what if not?!
|
|
this.name_widget.value = v;
|
|
this.name_in_graph = v;
|
|
}
|
|
else if( name == "type" )
|
|
{
|
|
v = v || "";
|
|
this.updateType(v);
|
|
}
|
|
else if( name == "value" )
|
|
{
|
|
}
|
|
}
|
|
|
|
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) {
|
|
this.setOutputData(0, this.properties.value );
|
|
return;
|
|
}
|
|
|
|
this.setOutputData(0, data.value !== undefined ? data.value : this.properties.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,"name");
|
|
this.type_widget = this.addWidget("text","Type",this.properties.type,"type");
|
|
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);
|
|
this.widget = this.addWidget("number","value",1,"value");
|
|
this.widgets_up = true;
|
|
this.size = [180, 30];
|
|
}
|
|
|
|
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.setProperty("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 ConstantBoolean() {
|
|
this.addOutput("", "boolean");
|
|
this.addProperty("value", true);
|
|
this.widget = this.addWidget("toggle","value",true,"value");
|
|
this.widgets_up = true;
|
|
this.size = [140, 30];
|
|
}
|
|
|
|
ConstantBoolean.title = "Const Boolean";
|
|
ConstantBoolean.desc = "Constant boolean";
|
|
ConstantBoolean.prototype.getTitle = ConstantNumber.prototype.getTitle;
|
|
|
|
ConstantBoolean.prototype.onExecute = function() {
|
|
this.setOutputData(0, this.properties["value"]);
|
|
};
|
|
|
|
ConstantBoolean.prototype.setValue = ConstantNumber.prototype.setValue;
|
|
|
|
ConstantBoolean.prototype.onGetInputs = function() {
|
|
return [["toggle", LiteGraph.ACTION]];
|
|
};
|
|
|
|
ConstantBoolean.prototype.onAction = function(action)
|
|
{
|
|
this.setValue( !this.properties.value );
|
|
}
|
|
|
|
LiteGraph.registerNodeType("basic/boolean", ConstantBoolean);
|
|
|
|
function ConstantString() {
|
|
this.addOutput("", "string");
|
|
this.addProperty("value", "");
|
|
this.widget = this.addWidget("text","value","","value"); //link to property value
|
|
this.widgets_up = true;
|
|
this.size = [180, 30];
|
|
}
|
|
|
|
ConstantString.title = "Const String";
|
|
ConstantString.desc = "Constant string";
|
|
|
|
ConstantString.prototype.getTitle = ConstantNumber.prototype.getTitle;
|
|
|
|
ConstantString.prototype.onExecute = function() {
|
|
this.setOutputData(0, this.properties["value"]);
|
|
};
|
|
|
|
ConstantString.prototype.setValue = ConstantNumber.prototype.setValue;
|
|
|
|
ConstantString.prototype.onDropFile = function(file)
|
|
{
|
|
var that = this;
|
|
var reader = new FileReader();
|
|
reader.onload = function(e)
|
|
{
|
|
that.setProperty("value",e.target.result);
|
|
}
|
|
reader.readAsText(file);
|
|
}
|
|
|
|
LiteGraph.registerNodeType("basic/string", ConstantString);
|
|
|
|
function ConstantFile() {
|
|
this.addInput("url", "");
|
|
this.addOutput("", "");
|
|
this.addProperty("url", "");
|
|
this.addProperty("type", "text");
|
|
this.widget = this.addWidget("text","url","","url");
|
|
this._data = null;
|
|
}
|
|
|
|
ConstantFile.title = "Const File";
|
|
ConstantFile.desc = "Fetches a file from an url";
|
|
ConstantFile["@type"] = { type: "enum", values: ["text","arraybuffer","blob","json"] };
|
|
|
|
ConstantFile.prototype.onPropertyChanged = function(name, value) {
|
|
if (name == "url")
|
|
{
|
|
if( value == null || value == "")
|
|
this._data = null;
|
|
else
|
|
{
|
|
this.fetchFile(value);
|
|
}
|
|
}
|
|
}
|
|
|
|
ConstantFile.prototype.onExecute = function() {
|
|
var url = this.getInputData(0) || this.properties.url;
|
|
if(url && (url != this._url || this._type != this.properties.type))
|
|
this.fetchFile(url);
|
|
this.setOutputData(0, this._data );
|
|
};
|
|
|
|
ConstantFile.prototype.setValue = ConstantNumber.prototype.setValue;
|
|
|
|
ConstantFile.prototype.fetchFile = function(url) {
|
|
var that = this;
|
|
if(!url || url.constructor !== String)
|
|
{
|
|
that._data = null;
|
|
that.boxcolor = null;
|
|
return;
|
|
}
|
|
|
|
this._url = url;
|
|
this._type = this.properties.type;
|
|
if (url.substr(0, 4) == "http" && LiteGraph.proxy) {
|
|
url = LiteGraph.proxy + url.substr(url.indexOf(":") + 3);
|
|
}
|
|
fetch(url)
|
|
.then(function(response) {
|
|
if(!response.ok)
|
|
throw new Error("File not found");
|
|
|
|
if(that.properties.type == "arraybuffer")
|
|
return response.arrayBuffer();
|
|
else if(that.properties.type == "text")
|
|
return response.text();
|
|
else if(that.properties.type == "json")
|
|
return response.json();
|
|
else if(that.properties.type == "blob")
|
|
return response.blob();
|
|
})
|
|
.then(function(data) {
|
|
that._data = data;
|
|
that.boxcolor = "#AEA";
|
|
})
|
|
.catch(function(error) {
|
|
that._data = null;
|
|
that.boxcolor = "red";
|
|
console.error("error fetching file:",url);
|
|
});
|
|
};
|
|
|
|
ConstantFile.prototype.onDropFile = function(file)
|
|
{
|
|
var that = this;
|
|
this._url = file.name;
|
|
this._type = this.properties.type;
|
|
this.properties.url = file.name;
|
|
var reader = new FileReader();
|
|
reader.onload = function(e)
|
|
{
|
|
that.boxcolor = "#AEA";
|
|
var v = e.target.result;
|
|
if( that.properties.type == "json" )
|
|
v = JSON.parse(v);
|
|
that._data = v;
|
|
}
|
|
if(that.properties.type == "arraybuffer")
|
|
reader.readAsArrayBuffer(file);
|
|
else if(that.properties.type == "text" || that.properties.type == "json")
|
|
reader.readAsText(file);
|
|
else if(that.properties.type == "blob")
|
|
return reader.readAsBinaryString(file);
|
|
}
|
|
|
|
LiteGraph.registerNodeType("basic/file", ConstantFile);
|
|
|
|
//to store json objects
|
|
function ConstantData() {
|
|
this.addOutput("", "");
|
|
this.addProperty("value", "");
|
|
this.widget = this.addWidget("text","json","","value");
|
|
this.widgets_up = true;
|
|
this.size = [140, 30];
|
|
this._value = null;
|
|
}
|
|
|
|
ConstantData.title = "Const Data";
|
|
ConstantData.desc = "Constant Data";
|
|
|
|
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);
|
|
};
|
|
|
|
ConstantData.prototype.setValue = ConstantNumber.prototype.setValue;
|
|
|
|
LiteGraph.registerNodeType("basic/data", ConstantData);
|
|
|
|
//to store json objects
|
|
function ConstantArray() {
|
|
this.addInput("", "");
|
|
this.addOutput("", "array");
|
|
this.addOutput("length", "number");
|
|
this.addProperty("value", "");
|
|
this.widget = this.addWidget("text","array","","value");
|
|
this.widgets_up = true;
|
|
this.size = [140, 50];
|
|
this._value = null;
|
|
}
|
|
|
|
ConstantArray.title = "Const Array";
|
|
ConstantArray.desc = "Constant Array";
|
|
|
|
ConstantArray.prototype.onPropertyChanged = function(name, value) {
|
|
this.widget.value = value;
|
|
if (value == null || value == "") {
|
|
return;
|
|
}
|
|
|
|
try {
|
|
if(value[0] != "[")
|
|
this._value = JSON.parse("[" + value + "]");
|
|
else
|
|
this._value = JSON.parse(value);
|
|
this.boxcolor = "#AEA";
|
|
} catch (err) {
|
|
this.boxcolor = "red";
|
|
}
|
|
};
|
|
|
|
ConstantArray.prototype.onExecute = function() {
|
|
var v = this.getInputData(0);
|
|
if(v && v.length) //clone
|
|
{
|
|
if(!this._value)
|
|
this._value = new Array();
|
|
this._value.length = v.length;
|
|
for(var i = 0; i < v.length; ++i)
|
|
this._value[i] = v[i];
|
|
}
|
|
this.setOutputData(0, this._value);
|
|
this.setOutputData(1, this._value ? ( this._value.length || 0) : 0 );
|
|
};
|
|
|
|
ConstantArray.prototype.setValue = ConstantNumber.prototype.setValue;
|
|
|
|
LiteGraph.registerNodeType("basic/array", ConstantArray);
|
|
|
|
function ArrayElement() {
|
|
this.addInput("array", "array,table,string");
|
|
this.addInput("index", "number");
|
|
this.addOutput("value", "");
|
|
this.addProperty("index",0);
|
|
}
|
|
|
|
ArrayElement.title = "Array[i]";
|
|
ArrayElement.desc = "Returns an element from an array";
|
|
|
|
ArrayElement.prototype.onExecute = function() {
|
|
var array = this.getInputData(0);
|
|
var index = this.getInputData(1);
|
|
if(index == null)
|
|
index = this.properties.index;
|
|
if(array == null || index == null )
|
|
return;
|
|
this.setOutputData(0, array[Math.floor(Number(index))] );
|
|
};
|
|
|
|
LiteGraph.registerNodeType("basic/array[]", ArrayElement);
|
|
|
|
|
|
|
|
function TableElement() {
|
|
this.addInput("table", "table");
|
|
this.addInput("row", "number");
|
|
this.addInput("col", "number");
|
|
this.addOutput("value", "");
|
|
this.addProperty("row",0);
|
|
this.addProperty("column",0);
|
|
}
|
|
|
|
TableElement.title = "Table[row][col]";
|
|
TableElement.desc = "Returns an element from a table";
|
|
|
|
TableElement.prototype.onExecute = function() {
|
|
var table = this.getInputData(0);
|
|
var row = this.getInputData(1);
|
|
var col = this.getInputData(2);
|
|
if(row == null)
|
|
row = this.properties.row;
|
|
if(col == null)
|
|
col = this.properties.column;
|
|
if(table == null || row == null || col == null)
|
|
return;
|
|
var row = table[Math.floor(Number(row))];
|
|
if(row)
|
|
this.setOutputData(0, row[Math.floor(Number(col))] );
|
|
else
|
|
this.setOutputData(0, null );
|
|
};
|
|
|
|
LiteGraph.registerNodeType("basic/table[][]", TableElement);
|
|
|
|
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);
|
|
|
|
function ObjectKeys() {
|
|
this.addInput("obj", "");
|
|
this.addOutput("keys", "array");
|
|
this.size = [140, 30];
|
|
}
|
|
|
|
ObjectKeys.title = "Object keys";
|
|
ObjectKeys.desc = "Outputs an array with the keys of an object";
|
|
|
|
ObjectKeys.prototype.onExecute = function() {
|
|
var data = this.getInputData(0);
|
|
if (data != null) {
|
|
this.setOutputData(0, Object.keys(data) );
|
|
}
|
|
};
|
|
|
|
LiteGraph.registerNodeType("basic/object_keys", ObjectKeys);
|
|
|
|
function MergeObjects() {
|
|
this.addInput("A", "object");
|
|
this.addInput("B", "object");
|
|
this.addOutput("", "object");
|
|
this._result = {};
|
|
var that = this;
|
|
this.addWidget("button","clear","",function(){
|
|
that._result = {};
|
|
});
|
|
this.size = this.computeSize();
|
|
}
|
|
|
|
MergeObjects.title = "Merge Objects";
|
|
MergeObjects.desc = "Creates an object copying properties from others";
|
|
|
|
MergeObjects.prototype.onExecute = function() {
|
|
var A = this.getInputData(0);
|
|
var B = this.getInputData(1);
|
|
var C = this._result;
|
|
if(A)
|
|
for(var i in A)
|
|
C[i] = A[i];
|
|
if(B)
|
|
for(var i in B)
|
|
C[i] = B[i];
|
|
this.setOutputData(0,C);
|
|
};
|
|
|
|
LiteGraph.registerNodeType("basic/merge_objects", MergeObjects );
|
|
|
|
//Store as variable
|
|
function Variable() {
|
|
this.size = [60, 30];
|
|
this.addInput("in");
|
|
this.addOutput("out");
|
|
this.properties = { varname: "myname", global: false };
|
|
this.value = null;
|
|
}
|
|
|
|
Variable.title = "Variable";
|
|
Variable.desc = "store/read variable value";
|
|
|
|
Variable.prototype.onExecute = function() {
|
|
this.value = this.getInputData(0);
|
|
if(this.graph)
|
|
this.graph.vars[ this.properties.varname ] = this.value;
|
|
if(this.properties.global)
|
|
global[this.properties.varname] = this.value;
|
|
this.setOutputData(0, this.value );
|
|
};
|
|
|
|
Variable.prototype.getTitle = function() {
|
|
return this.properties.varname;
|
|
};
|
|
|
|
LiteGraph.registerNodeType("basic/variable", Variable);
|
|
|
|
function length(v) {
|
|
if(v && v.length != null)
|
|
return Number(v.length);
|
|
return 0;
|
|
}
|
|
|
|
LiteGraph.wrapFunctionAsNode(
|
|
"basic/length",
|
|
length,
|
|
[""],
|
|
"number"
|
|
);
|
|
|
|
function DownloadData() {
|
|
this.size = [60, 30];
|
|
this.addInput("data", 0 );
|
|
this.addInput("download", LiteGraph.ACTION );
|
|
this.properties = { filename: "data.json" };
|
|
this.value = null;
|
|
var that = this;
|
|
this.addWidget("button","Download","", function(v){
|
|
if(!that.value)
|
|
return;
|
|
that.downloadAsFile();
|
|
});
|
|
}
|
|
|
|
DownloadData.title = "Download";
|
|
DownloadData.desc = "Download some data";
|
|
|
|
DownloadData.prototype.downloadAsFile = function()
|
|
{
|
|
if(this.value == null)
|
|
return;
|
|
|
|
var str = null;
|
|
if(this.value.constructor === String)
|
|
str = this.value;
|
|
else
|
|
str = JSON.stringify(this.value);
|
|
|
|
var file = new Blob([str]);
|
|
var url = URL.createObjectURL( file );
|
|
var element = document.createElement("a");
|
|
element.setAttribute('href', url);
|
|
element.setAttribute('download', this.properties.filename );
|
|
element.style.display = 'none';
|
|
document.body.appendChild(element);
|
|
element.click();
|
|
document.body.removeChild(element);
|
|
setTimeout( function(){ URL.revokeObjectURL( url ); }, 1000*60 ); //wait one minute to revoke url
|
|
}
|
|
|
|
DownloadData.prototype.onAction = function(action, param) {
|
|
var that = this;
|
|
setTimeout( function(){ that.downloadAsFile(); }, 100); //deferred to avoid blocking the renderer with the popup
|
|
}
|
|
|
|
DownloadData.prototype.onExecute = function() {
|
|
if (this.inputs[0]) {
|
|
this.value = this.getInputData(0);
|
|
}
|
|
};
|
|
|
|
DownloadData.prototype.getTitle = function() {
|
|
if (this.flags.collapsed) {
|
|
return this.properties.filename;
|
|
}
|
|
return this.title;
|
|
};
|
|
|
|
LiteGraph.registerNodeType("basic/download", DownloadData);
|
|
|
|
|
|
|
|
//Watch a value in the editor
|
|
function Watch() {
|
|
this.size = [60, 30];
|
|
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, 30];
|
|
}
|
|
|
|
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, 30];
|
|
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 && LiteGraph.allow_scripts)
|
|
this.compileCode(o.properties.onExecute);
|
|
else
|
|
console.warn("Script not compiled, LiteGraph.allow_scripts is false");
|
|
};
|
|
|
|
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);
|
|
else
|
|
console.warn("Script not compiled, LiteGraph.allow_scripts is false");
|
|
};
|
|
|
|
NodeScript.prototype.compileCode = function(code) {
|
|
this._func = null;
|
|
if (code.length > 256) {
|
|
console.warn("Script too long, max 256 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);
|