diff --git a/build/litegraph.js b/build/litegraph.js
index 94a243de8..799f36f70 100644
--- a/build/litegraph.js
+++ b/build/litegraph.js
@@ -30,7 +30,6 @@ var LiteGraph = {
debug: false,
registered_node_types: {},
- graphs: [],
/**
* Register a node class so it can be listed when the user wants to create a new one
@@ -233,28 +232,19 @@ var LiteGraph = {
}
}
- for (var i in LiteGraph.graphs)
- {
- for (var j in LiteGraph.graphs[i].nodes)
- {
- var m = LiteGraph.graphs[i].nodes[j];
- var t = LiteGraph.getNodeType(n.type);
- if(!t) continue;
-
- for (var k in t)
- if( typeof(t[k]) == "function" )
- m[k] = t[k];
- }
- }
-
if(LiteGraph.debug)
console.log("Nodes reloaded");
},
//separated just to improve if it doesnt work
- cloneObject: function(obj)
+ cloneObject: function(obj, target)
{
- return JSON.parse( JSON.stringify( obj ) );
+ var r = JSON.parse( JSON.stringify( obj ) );
+ if(!target) return r;
+
+ for(var i in r)
+ target[i] = r[i];
+ return target;
}
/*
@@ -263,11 +253,11 @@ var LiteGraph = {
mode = mode || "all";
trace("Benchmarking " + mode + "...");
- trace(" Num. nodes: " + this.nodes.length );
+ trace(" Num. nodes: " + this._nodes.length );
var links = 0;
- for(var i in this.nodes)
- for(var j in this.nodes[i].outputs)
- if(this.nodes[i].outputs[j].node_id != null)
+ for(var i in this._nodes)
+ for(var j in this._nodes[i].outputs)
+ if(this._nodes[i].outputs[j].node_id != null)
links++;
trace(" Num. links: " + links );
@@ -318,8 +308,7 @@ function LGraph()
{
if (LiteGraph.debug)
console.log("Graph created");
- this.canvas = null;
- LiteGraph.graphs.push(this);
+ this.list_of_graphcanvas = null;
this.clear();
}
@@ -338,8 +327,8 @@ LGraph.prototype.clear = function()
this.last_node_id = 0;
//nodes
- this.nodes = [];
- this.nodes_by_id = {};
+ this._nodes = [];
+ this._nodes_by_id = {};
//links
this.last_link_id = 0;
@@ -349,8 +338,6 @@ LGraph.prototype.clear = function()
this.iteration = 0;
this.config = {
- canvas_offset: [0,0],
- canvas_scale: 1.0
};
//timing
@@ -361,12 +348,48 @@ LGraph.prototype.clear = function()
this.elapsed_time = 0.01;
this.starttime = 0;
+ //globals
+ this.globals = {};
+
this.graph = {};
this.debug = true;
this.change();
- if(this.canvas)
- this.canvas.clear();
+
+ this.sendActionToCanvas("clear");
+}
+
+/**
+* Attach Canvas to this graph
+* @method attachCanvas
+* @param {GraphCanvas} graph_canvas
+*/
+
+LGraph.prototype.attachCanvas = function(graphcanvas)
+{
+ if(graphcanvas.constructor != LGraphCanvas)
+ throw("attachCanvas expects a LGraphCanvas instance");
+ if(graphcanvas.graph && graphcanvas.graph != this)
+ graphcanvas.graph.detachCanvas( graphcanvas );
+
+ graphcanvas.graph = this;
+ if(!this.list_of_graphcanvas)
+ this.list_of_graphcanvas = [];
+ this.list_of_graphcanvas.push(graphcanvas);
+}
+
+/**
+* Detach Canvas from this graph
+* @method detachCanvas
+* @param {GraphCanvas} graph_canvas
+*/
+
+LGraph.prototype.detachCanvas = function(graphcanvas)
+{
+ var pos = this.list_of_graphcanvas.indexOf(graphcanvas);
+ if(pos == -1) return;
+ graphcanvas.graph = null;
+ this.list_of_graphcanvas.splice(pos,1);
}
/**
@@ -386,7 +409,7 @@ LGraph.prototype.start = function(interval)
this.sendEventToAllNodes("onStart");
//launch
- this.starttime = new Date().getTime();
+ this.starttime = window.performance.now();
interval = interval || 1;
var that = this;
@@ -398,7 +421,7 @@ LGraph.prototype.start = function(interval)
/**
* Stops the execution loop of the graph
-* @method stop
+* @method stop execution
*/
LGraph.prototype.stop = function()
@@ -428,7 +451,7 @@ LGraph.prototype.runStep = function(num)
{
num = num || 1;
- var start = new Date().getTime();
+ var start = window.performance.now();
this.globaltime = 0.001 * (start - this.starttime);
try
@@ -455,7 +478,7 @@ LGraph.prototype.runStep = function(num)
this.stop();
}
- var elapsed = (new Date().getTime()) - start;
+ var elapsed = window.performance.now() - start;
if (elapsed == 0) elapsed = 1;
this.elapsed_time = 0.001 * elapsed;
this.globaltime += 0.001 * elapsed;
@@ -470,7 +493,7 @@ LGraph.prototype.runStep = function(num)
LGraph.prototype.updateExecutionOrder = function()
{
- this.nodes_in_order = this.computeExecutionOrder();
+ this._nodes_in_order = this.computeExecutionOrder();
}
//This is more internal, it computes the order and returns it
@@ -483,9 +506,9 @@ LGraph.prototype.computeExecutionOrder = function()
var remaining_links = {}; //to a
//search for the nodes without inputs (starting nodes)
- for (var i in this.nodes)
+ for (var i in this._nodes)
{
- var n = this.nodes[i];
+ var n = this._nodes[i];
M[n.id] = n; //add to pending nodes
var num = 0; //num of input connections
@@ -547,7 +570,7 @@ LGraph.prototype.computeExecutionOrder = function()
for(var i in M)
L.push(M[i]);
- if(L.length != this.nodes.length && LiteGraph.debug)
+ if(L.length != this._nodes.length && LiteGraph.debug)
console.log("something went wrong, nodes missing");
//save order number in the node
@@ -601,12 +624,25 @@ LGraph.prototype.getElapsedTime = function()
LGraph.prototype.sendEventToAllNodes = function(eventname, param)
{
- var M = this.nodes_in_order ? this.nodes_in_order : this.nodes;
+ var M = this._nodes_in_order ? this._nodes_in_order : this._nodes;
for(var j in M)
if(M[j][eventname])
M[j][eventname](param);
}
+LGraph.prototype.sendActionToCanvas = function(action, params)
+{
+ if(!this.list_of_graphcanvas)
+ return;
+
+ for(var i in this.list_of_graphcanvas)
+ {
+ var c = this.list_of_graphcanvas[i];
+ if( c[action] )
+ c[action].apply(c, params);
+ }
+}
+
/**
* Adds a new node instasnce to this graph
* @method add
@@ -615,10 +651,10 @@ LGraph.prototype.sendEventToAllNodes = function(eventname, param)
LGraph.prototype.add = function(node)
{
- if(!node || (node.id != -1 && this.nodes_by_id[node.id] != null))
+ if(!node || (node.id != -1 && this._nodes_by_id[node.id] != null))
return; //already added
- if(this.nodes.length >= LiteGraph.MAX_NUMBER_OF_NODES)
+ if(this._nodes.length >= LiteGraph.MAX_NUMBER_OF_NODES)
throw("LiteGraph: max number of nodes in a graph reached");
//give him an id
@@ -627,8 +663,8 @@ LGraph.prototype.add = function(node)
node.graph = this;
- this.nodes.push(node);
- this.nodes_by_id[node.id] = node;
+ this._nodes.push(node);
+ this._nodes_by_id[node.id] = node;
/*
// rendering stuf...
@@ -660,7 +696,7 @@ LGraph.prototype.add = function(node)
LGraph.prototype.remove = function(node)
{
- if(this.nodes_by_id[node.id] == null)
+ if(this._nodes_by_id[node.id] == null)
return; //not found
if(node.ignore_remove)
@@ -700,10 +736,10 @@ LGraph.prototype.remove = function(node)
}
//remove from containers
- var pos = this.nodes.indexOf(node);
+ var pos = this._nodes.indexOf(node);
if(pos != -1)
- this.nodes.splice(pos,1);
- delete this.nodes_by_id[node.id];
+ this._nodes.splice(pos,1);
+ delete this._nodes_by_id[node.id];
if(this.canvas)
this.canvas.setDirty(true,true);
@@ -722,7 +758,7 @@ LGraph.prototype.remove = function(node)
LGraph.prototype.getNodeById = function(id)
{
if(id==null) return null;
- return this.nodes_by_id[id];
+ return this._nodes_by_id[id];
}
@@ -736,9 +772,9 @@ LGraph.prototype.getNodeById = function(id)
LGraph.prototype.findNodesByType = function(type)
{
var r = [];
- for(var i in this.nodes)
- if(this.nodes[i].type == type)
- r.push(this.nodes[i]);
+ for(var i in this._nodes)
+ if(this._nodes[i].type == type)
+ r.push(this._nodes[i]);
return r;
}
@@ -752,9 +788,9 @@ LGraph.prototype.findNodesByType = function(type)
LGraph.prototype.findNodesByName = function(name)
{
var result = [];
- for (var i in this.nodes)
- if(this.nodes[i].name == name)
- result.push(this.nodes[i]);
+ for (var i in this._nodes)
+ if(this._nodes[i].name == name)
+ result.push(this._nodes[i]);
return result;
}
@@ -769,7 +805,7 @@ LGraph.prototype.findNodesByName = function(name)
LGraph.prototype.getNodeOnPos = function(x,y, nodes_list)
{
- nodes_list = nodes_list || this.nodes;
+ nodes_list = nodes_list || this._nodes;
for (var i = nodes_list.length - 1; i >= 0; i--)
{
var n = nodes_list[i];
@@ -825,39 +861,46 @@ LGraph.prototype.setCallback = function(name,func)
m[i].setTrigger(func);
}
-//**********
-
LGraph.prototype.onConnectionChange = function()
{
this.updateExecutionOrder();
}
+/**
+* returns if the graph is in live mode
+* @method isLive
+*/
+
LGraph.prototype.isLive = function()
{
if(!this.canvas) return false;
return this.canvas.live_mode;
}
+/* Called when something visually changed */
LGraph.prototype.change = function()
{
if(LiteGraph.debug)
console.log("Graph changed");
+
+ this.sendActionToCanvas("setDirty",[true,true]);
+
if(this.on_change)
this.on_change(this);
}
//save and recover app state ***************************************
/**
-* Creates a JSON String containing all the info about this graph
+* Creates a Object containing all the info about this graph, it can be serialized
* @method serialize
-* @return {String} value of the node
+* @return {Object} value of the node
*/
LGraph.prototype.serialize = function()
{
var nodes_info = [];
- for (var i in this.nodes)
- nodes_info.push( this.nodes[i].objectivize() );
+ for (var i in this._nodes)
+ nodes_info.push( this._nodes[i].serialize() );
var data = {
graph: this.graph,
@@ -871,20 +914,20 @@ LGraph.prototype.serialize = function()
nodes: nodes_info
};
- return JSON.stringify(data);
+ return data;
}
+
/**
* Configure a graph from a JSON string
-* @method unserialize
+* @method configure
* @param {String} str configure a graph from a JSON string
*/
-LGraph.prototype.unserialize = function(str, keep_old)
+LGraph.prototype.configure = function(data, keep_old)
{
if(!keep_old)
this.clear();
- var data = JSON.parse(str);
var nodes = data.nodes;
//copy all stored fields
@@ -894,7 +937,7 @@ LGraph.prototype.unserialize = function(str, keep_old)
var error = false;
//create nodes
- this.nodes = [];
+ this._nodes = [];
for (var i in nodes)
{
var n_info = nodes[i]; //stored info
@@ -907,7 +950,7 @@ LGraph.prototype.unserialize = function(str, keep_old)
continue;
}
- n.copyFromObject(n_info);
+ n.configure(n_info);
this.add(n);
}
@@ -981,9 +1024,59 @@ function LGraphNode(name)
};
}
-//serialization *************************
+/**
+* configure a node from an object
+* @method configure
+*/
+LGraphNode.prototype.configure = function(info)
+{
+ for (var j in info)
+ {
+ if(j == "console") continue;
-LGraphNode.prototype.objectivize = function()
+ if(info[j] == null)
+ continue;
+ else if( info[j].concat ) //array
+ this[j] = info[j].concat();
+ else if (typeof(info[j]) == 'object') //object
+ this[j] = LiteGraph.cloneObject(info[j], this[j] || {} );
+ else //value
+ this[j] = info[j];
+ }
+}
+
+/* Copy all the info from one object to this node (used for serialization) */
+LGraphNode.prototype.copyFromObject = function(info, ignore_connections)
+{
+ var outputs = null;
+ var inputs = null;
+ var properties = null;
+ var local_data = null;
+
+ for (var j in info)
+ {
+ if(ignore_connections && (j == "outputs" || j == "inputs"))
+ continue;
+
+ if(j == "console") continue;
+
+ if(info[j] == null)
+ continue;
+ else if( info[j].concat ) //array
+ this[j] = info[j].concat();
+ else if (typeof(info[j]) == 'object') //object
+ this[j] = LiteGraph.cloneObject(info[j]);
+ else //value
+ this[j] = info[j];
+ }
+}
+
+/**
+* serialize the content
+* @method serialize
+*/
+
+LGraphNode.prototype.serialize = function()
{
var o = {
id: this.id,
@@ -1010,10 +1103,14 @@ LGraphNode.prototype.objectivize = function()
if(this.shape)
o.shape = this.shape;
+ if(this.onSerialize)
+ this.onSerialize(o);
+
return o;
}
//reduced version of objectivize: NOT FINISHED
+/*
LGraphNode.prototype.reducedObjectivize = function()
{
var o = this.objectivize();
@@ -1031,19 +1128,27 @@ LGraphNode.prototype.reducedObjectivize = function()
return o;
}
+*/
+/**
+* serialize and stringify
+* @method toString
+*/
-LGraphNode.prototype.serialize = function()
+LGraphNode.prototype.toString = function()
{
- if(this.onSerialize)
- this.onSerialize();
- return JSON.stringify( this.reducedObjectivize() );
+ return JSON.stringify( this.serialize() );
}
//LGraphNode.prototype.unserialize = function(info) {} //this cannot be done from within, must be done in LiteGraph
// Execution *************************
-
+/**
+* sets the output data
+* @method setOutputData
+* @param {number} slot
+* @param {*} data
+*/
LGraphNode.prototype.setOutputData = function(slot,data)
{
if(!this.outputs) return;
@@ -1054,6 +1159,12 @@ LGraphNode.prototype.setOutputData = function(slot,data)
}
}
+/**
+* retrieves the input data from one slot
+* @method getInputData
+* @param {number} slot
+* @return {*} data
+*/
LGraphNode.prototype.getInputData = function(slot)
{
if(!this.inputs) return null;
@@ -1062,12 +1173,24 @@ LGraphNode.prototype.getInputData = function(slot)
return null;
}
+/**
+* tells you if there is a connection in one input slot
+* @method isInputConnected
+* @param {number} slot
+* @return {boolean}
+*/
LGraphNode.prototype.isInputConnected = function(slot)
{
if(!this.inputs) return null;
return (slot < this.inputs.length && this.inputs[slot].link != null);
}
+/**
+* tells you info about an input connection (which node, type, etc)
+* @method getInputInfo
+* @param {number} slot
+* @return {Object}
+*/
LGraphNode.prototype.getInputInfo = function(slot)
{
if(!this.inputs) return null;
@@ -1077,6 +1200,12 @@ LGraphNode.prototype.getInputInfo = function(slot)
}
+/**
+* tells you info about an output connection (which node, type, etc)
+* @method getOutputInfo
+* @param {number} slot
+* @return {Object}
+*/
LGraphNode.prototype.getOutputInfo = function(slot)
{
if(!this.outputs) return null;
@@ -1085,12 +1214,25 @@ LGraphNode.prototype.getOutputInfo = function(slot)
return null;
}
+
+/**
+* tells you if there is a connection in one output slot
+* @method isOutputConnected
+* @param {number} slot
+* @return {boolean}
+*/
LGraphNode.prototype.isOutputConnected = function(slot)
{
if(!this.outputs) return null;
return (slot < this.outputs.length && this.outputs[slot].links && this.outputs[slot].links.length);
}
+/**
+* retrieves all the nodes connected to this output slot
+* @method getOutputNodes
+* @param {number} slot
+* @return {array}
+*/
LGraphNode.prototype.getOutputNodes = function(slot)
{
if(!this.outputs || this.outputs.length == 0) return null;
@@ -1114,6 +1256,13 @@ LGraphNode.prototype.triggerOutput = function(slot,param)
//connections
+/**
+* add a new output slot to use in this node
+* @method addOutput
+* @param {string} name
+* @param {string} type string defining the output type ("vec3","number",...)
+* @param {Object} extra_info this can be used to have special properties of an output (special color, position, etc)
+*/
LGraphNode.prototype.addOutput = function(name,type,extra_info)
{
var o = {name:name,type:type,links:null};
@@ -1126,6 +1275,11 @@ LGraphNode.prototype.addOutput = function(name,type,extra_info)
this.size = this.computeSize();
}
+/**
+* remove an existing output slot
+* @method removeOutput
+* @param {number} slot
+*/
LGraphNode.prototype.removeOutput = function(slot)
{
this.disconnectOutput(slot);
@@ -1133,6 +1287,13 @@ LGraphNode.prototype.removeOutput = function(slot)
this.size = this.computeSize();
}
+/**
+* add a new input slot to use in this node
+* @method addInput
+* @param {string} name
+* @param {string} type string defining the input type ("vec3","number",...)
+* @param {Object} extra_info this can be used to have special properties of an input (special color, position, etc)
+*/
LGraphNode.prototype.addInput = function(name,type,extra_info)
{
var o = {name:name,type:type,link:null};
@@ -1145,6 +1306,11 @@ LGraphNode.prototype.addInput = function(name,type,extra_info)
this.size = this.computeSize();
}
+/**
+* remove an existing input slot
+* @method removeInput
+* @param {number} slot
+*/
LGraphNode.prototype.removeInput = function(slot)
{
this.disconnectInput(slot);
@@ -1152,13 +1318,25 @@ LGraphNode.prototype.removeInput = function(slot)
this.size = this.computeSize();
}
-//trigger connection
+/**
+* add an special connection to this node (used for special kinds of graphs)
+* @method addConnection
+* @param {string} name
+* @param {string} type string defining the input type ("vec3","number",...)
+* @param {[x,y]} pos position of the connection inside the node
+* @param {string} direction if is input or output
+*/
LGraphNode.prototype.addConnection = function(name,type,pos,direction)
{
this.connections.push( {name:name,type:type,pos:pos,direction:direction,links:null});
}
-
+/**
+* computes the size of a node according to its inputs and output slots
+* @method computeSize
+* @param {number} minHeight
+* @return {number} the total size
+*/
LGraphNode.prototype.computeSize = function(minHeight)
{
var rows = Math.max( this.inputs ? this.inputs.length : 1, this.outputs ? this.outputs.length : 1);
@@ -1171,13 +1349,23 @@ LGraphNode.prototype.computeSize = function(minHeight)
return size;
}
-//returns the bounding of the object, used for rendering purposes
+/**
+* returns the bounding of the object, used for rendering purposes
+* @method getBounding
+* @return {Float32Array[4]} the total size
+*/
LGraphNode.prototype.getBounding = function()
{
return new Float32Array([this.pos[0] - 4, this.pos[1] - LiteGraph.NODE_TITLE_HEIGHT, this.pos[0] + this.size[0] + 4, this.pos[1] + this.size[1] + LGraph.NODE_TITLE_HEIGHT]);
}
-//checks if a point is inside the shape of a node
+/**
+* checks if a point is inside the shape of a node
+* @method isPointInsideNode
+* @param {number} x
+* @param {number} y
+* @return {boolean}
+*/
LGraphNode.prototype.isPointInsideNode = function(x,y)
{
var margin_top = this.graph.isLive() ? 0 : 20;
@@ -1211,7 +1399,14 @@ LGraphNode.prototype.findOutputSlot = function(name)
return -1;
}
-//connect this node output to the input of another node
+/**
+* connect this node output to the input of another node
+* @method connect
+* @param {number_or_string} slot (could be the number of the slot or the string with the name of the slot)
+* @param {LGraphNode} node the target node
+* @param {number_or_string} target_slot the input slot of the target node (could be the number of the slot or the string with the name of the slot)
+* @return {boolean} if it was connected succesfully
+*/
LGraphNode.prototype.connect = function(slot, node, target_slot)
{
target_slot = target_slot || 0;
@@ -1285,6 +1480,13 @@ LGraphNode.prototype.connect = function(slot, node, target_slot)
return true;
}
+/**
+* disconnect one output to an specific node
+* @method disconnectOutput
+* @param {number_or_string} slot (could be the number of the slot or the string with the name of the slot)
+* @param {LGraphNode} target_node the target node to which this slot is connected [Optional, if not target_node is specified all nodes will be disconnected]
+* @return {boolean} if it was disconnected succesfully
+*/
LGraphNode.prototype.disconnectOutput = function(slot, target_node)
{
if( slot.constructor === String )
@@ -1341,6 +1543,12 @@ LGraphNode.prototype.disconnectOutput = function(slot, target_node)
return true;
}
+/**
+* disconnect one input
+* @method disconnectInput
+* @param {number_or_string} slot (could be the number of the slot or the string with the name of the slot)
+* @return {boolean} if it was disconnected succesfully
+*/
LGraphNode.prototype.disconnectInput = function(slot)
{
//seek for the output slot
@@ -1389,7 +1597,13 @@ LGraphNode.prototype.disconnectInput = function(slot)
return true;
}
-//returns the center of a connection point in canvas coords
+/**
+* returns the center of a connection point in canvas coords
+* @method getConnectionPos
+* @param {boolean} is_input true if if a input slot, false if it is an output
+* @param {number_or_string} slot (could be the number of the slot or the string with the name of the slot)
+* @return {[x,y]} the position
+**/
LGraphNode.prototype.getConnectionPos = function(is_input,slot_number)
{
if(this.flags.collapsed)
@@ -1423,50 +1637,6 @@ LGraphNode.prototype.alignToGrid = function()
this.pos[1] = LiteGraph.CANVAS_GRID_SIZE * Math.round(this.pos[1] / LiteGraph.CANVAS_GRID_SIZE);
}
-/* Copy all the info from one object to this node (used for serialization) */
-LGraphNode.prototype.copyFromObject = function(info, ignore_connections)
-{
- var outputs = null;
- var inputs = null;
- var properties = null;
- var local_data = null;
-
- for (var j in info)
- {
- if(ignore_connections && (j == "outputs" || j == "inputs"))
- continue;
-
- if(j == "console") continue;
-
- if(info[j] == null)
- continue;
- else if( info[j].concat ) //array
- this[j] = info[j].concat();
- else if (typeof(info[j]) == 'object') //object
- this[j] = LiteGraph.cloneObject(info[j]);
- else //value
- this[j] = info[j];
- }
-
- //redo the connections
- /*
- if(outputs)
- this.outputs = outputs.concat();
- if(inputs)
- this.inputs = inputs.concat();
-
- if(local_data)
- this.data = local_data;
- if(properties)
- {
- //copy only the ones defined
- for (var j in properties)
- if (this.properties[j] != null)
- this.properties[j] = properties[j];
- }
- */
-}
-
/* Creates a clone of this node */
LGraphNode.prototype.clone = function()
{
@@ -1506,13 +1676,9 @@ LGraphNode.prototype.trace = function(msg)
/* Forces to redraw or the main canvas (LGraphNode) or the bg canvas (links) */
LGraphNode.prototype.setDirtyCanvas = function(dirty_foreground, dirty_background)
{
- if(!this.graph || !this.graph.canvas)
+ if(!this.graph)
return;
-
- if(dirty_foreground)
- this.graph.canvas.dirty_canvas = true;
- if(dirty_background)
- this.graph.canvas.dirty_bgcanvas = true;
+ this.graph.sendActionToCanvas("setDirty",[dirty_foreground, dirty_background]);
}
LGraphNode.prototype.loadImage = function(url)
@@ -1569,20 +1735,29 @@ LGraphNode.prototype.executeAction = function(action)
/* Allows to get onMouseMove and onMouseUp events even if the mouse is out of focus */
LGraphNode.prototype.captureInput = function(v)
{
- if(!this.graph || !this.graph.canvas)
+ if(!this.graph || !this.graph.list_of_graphcanvas)
return;
- //releasing somebody elses capture?!
- if(!v && this.graph.canvas.node_capturing_input != this)
- return;
+ var list = this.graph.list_of_graphcanvas;
- //change
- this.graph.canvas.node_capturing_input = v ? this : null;
- if(this.graph.debug)
- console.log(this.name + ": Capturing input " + (v?"ON":"OFF"));
+ for(var i in list)
+ {
+ var c = list[i];
+ //releasing somebody elses capture?!
+ if(!v && c.node_capturing_input != this)
+ continue;
+
+ //change
+ c.node_capturing_input = v ? this : null;
+ if(this.graph.debug)
+ console.log(this.name + ": Capturing input " + (v?"ON":"OFF"));
+ }
}
-/* Collapse the node */
+/**
+* Collapse the node to make it smaller on the canvas
+* @method collapse
+**/
LGraphNode.prototype.collapse = function()
{
if(!this.flags.collapsed)
@@ -1592,19 +1767,23 @@ LGraphNode.prototype.collapse = function()
this.setDirtyCanvas(true,true);
}
-/* Forces the node to do not move or realign on Z */
-LGraphNode.prototype.pin = function()
+/**
+* Forces the node to do not move or realign on Z
+* @method pin
+**/
+
+LGraphNode.prototype.pin = function(v)
{
- if(!this.flags.pinned)
- this.flags.pinned = true;
+ if(v === undefined)
+ this.flags.pinned = !this.flags.pinned;
else
- this.flags.pinned = false;
+ this.flags.pinned = v;
}
-LGraphNode.prototype.localToScreen = function(x,y)
+LGraphNode.prototype.localToScreen = function(x,y, graphcanvas)
{
- return [(x + this.pos[0]) * this.graph.config.canvas_scale + this.graph.config.canvas_offset[0],
- (y + this.pos[1]) * this.graph.config.canvas_scale + this.graph.config.canvas_offset[1]];
+ return [(x + this.pos[0]) * graphcanvas.scale + graphcanvas.offset[0],
+ (y + this.pos[1]) * graphcanvas.scale + graphcanvas.offset[1]];
}
@@ -1613,27 +1792,28 @@ LGraphNode.prototype.localToScreen = function(x,y)
// LGraphCanvas: LGraph renderer CLASS
//*********************************************************************************
+/**
+* The Global Scope. It contains all the registered node classes.
+*
+* @class LGraphCanvas
+* @constructor
+* @param {HTMLCanvas} canvas the canvas where you want to render (it accepts a selector in string format)
+* @param {LGraph} graph
+*/
function LGraphCanvas(canvas, graph)
{
- if(graph === undefined)
- throw ("No graph assigned");
+ //if(graph === undefined)
+ // throw ("No graph assigned");
- if( typeof(window) != "undefined" )
- {
- window.requestAnimFrame = (function(){
- return window.requestAnimationFrame ||
- window.webkitRequestAnimationFrame ||
- window.mozRequestAnimationFrame ||
- function( callback ){
- window.setTimeout(callback, 1000 / 60);
- };
- })();
- }
+ if(typeof(canvas) == "string")
+ canvas = document.querySelector(canvas);
+
+ if(!canvas)
+ throw("no canvas found");
//link canvas and graph
- this.graph = graph;
if(graph)
- graph.canvas = this;
+ graph.attachCanvas(this);
this.setCanvas(canvas);
this.clear();
@@ -1642,7 +1822,6 @@ function LGraphCanvas(canvas, graph)
}
LGraphCanvas.link_type_colors = {'number':"#AAC",'node':"#DCA"};
-LGraphCanvas.link_width = 2;
LGraphCanvas.prototype.clear = function()
{
@@ -1651,6 +1830,9 @@ LGraphCanvas.prototype.clear = function()
this.render_time = 0;
this.fps = 0;
+ this.scale = 1;
+ this.offset = [0,0];
+
this.selected_nodes = {};
this.node_dragged = null;
this.node_over = null;
@@ -1658,6 +1840,7 @@ LGraphCanvas.prototype.clear = function()
this.connecting_node = null;
this.highquality_render = true;
+ this.editor_alpha = 1; //used for transition
this.pause_rendering = false;
this.render_shadows = true;
this.dirty_canvas = true;
@@ -1675,6 +1858,16 @@ LGraphCanvas.prototype.clear = function()
this.last_mouse = [0,0];
this.last_mouseclick = 0;
+ this.title_text_font = "bold 14px Arial";
+ this.inner_text_font = "normal 12px Arial";
+
+ this.render_connections_shadows = false; //too much cpu
+ this.render_connections_border = true;
+ this.render_curved_connections = true;
+ this.render_connection_arrows = true;
+
+ this.connections_width = 4;
+
if(this.onClear) this.onClear();
//this.UIinit();
}
@@ -1682,29 +1875,25 @@ LGraphCanvas.prototype.clear = function()
LGraphCanvas.prototype.setGraph = function(graph)
{
if(this.graph == graph) return;
-
this.clear();
+
+ if(!graph && this.graph)
+ {
+ this.graph.detachCanvas(this);
+ return;
+ }
+
+ /*
if(this.graph)
this.graph.canvas = null; //remove old graph link to the canvas
this.graph = graph;
if(this.graph)
this.graph.canvas = this;
+ */
+ graph.attachCanvas(this);
this.setDirty(true,true);
}
-LGraphCanvas.prototype.resize = function(width, height)
-{
- if(this.canvas.width == width && this.canvas.height == height)
- return;
-
- this.canvas.width = width;
- this.canvas.height = height;
- this.bgcanvas.width = this.canvas.width;
- this.bgcanvas.height = this.canvas.height;
- this.setDirty(true,true);
-}
-
-
LGraphCanvas.prototype.setCanvas = function(canvas)
{
var that = this;
@@ -1829,6 +2018,13 @@ LGraphCanvas.prototype.setDirty = function(fgcanvas,bgcanvas)
this.dirty_bgcanvas = true;
}
+//Used to attach the canvas in a popup
+LGraphCanvas.prototype.getCanvasWindow = function()
+{
+ var doc = this.canvas.ownerDocument;
+ return doc.defaultView || doc.parentWindow;
+}
+
LGraphCanvas.prototype.startRendering = function()
{
if(this.is_rendering) return; //already rendering
@@ -1841,8 +2037,9 @@ LGraphCanvas.prototype.startRendering = function()
if(!this.pause_rendering)
this.draw();
+ var window = this.getCanvasWindow();
if(this.is_rendering)
- window.requestAnimFrame( renderFrame.bind(this) );
+ window.requestAnimationFrame( renderFrame.bind(this) );
}
@@ -1874,9 +2071,12 @@ LGraphCanvas.prototype.processMouseDown = function(e)
this.adjustMouseEvent(e);
+ var ref_window = this.getCanvasWindow();
+ var document = ref_window.document;
+
this.canvas.removeEventListener("mousemove", this._mousemove_callback );
- document.addEventListener("mousemove", this._mousemove_callback );
- document.addEventListener("mouseup", this._mouseup_callback );
+ ref_window.document.addEventListener("mousemove", this._mousemove_callback ); //catch for the entire window
+ ref_window.document.addEventListener("mouseup", this._mouseup_callback );
var n = this.graph.getNodeOnPos(e.canvasX, e.canvasY, this.visible_nodes);
var skip_dragging = false;
@@ -1957,7 +2157,7 @@ LGraphCanvas.prototype.processMouseDown = function(e)
var block_drag_node = false;
//double clicking
- var now = new Date().getTime();
+ var now = window.performance.now();
if ((now - this.last_mouseclick) < 300 && this.selected_nodes[n.id])
{
//double click node
@@ -2012,7 +2212,7 @@ LGraphCanvas.prototype.processMouseDown = function(e)
this.last_mouse[0] = e.localX;
this.last_mouse[1] = e.localY;
- this.last_mouseclick = new Date().getTime();
+ this.last_mouseclick = window.performance.now();
this.canvas_mouse = [e.canvasX, e.canvasY];
/*
@@ -2023,7 +2223,7 @@ LGraphCanvas.prototype.processMouseDown = function(e)
this.graph.change();
//this is to ensure to defocus(blur) if a text input element is on focus
- if(!document.activeElement || (document.activeElement.nodeName.toLowerCase() != "input" && document.activeElement.nodeName.toLowerCase() != "textarea"))
+ if(!ref_window.document.activeElement || (ref_window.document.activeElement.nodeName.toLowerCase() != "input" && ref_window.document.activeElement.nodeName.toLowerCase() != "textarea"))
e.preventDefault();
e.stopPropagation();
return false;
@@ -2041,8 +2241,8 @@ LGraphCanvas.prototype.processMouseMove = function(e)
if(this.dragging_canvas)
{
- this.graph.config.canvas_offset[0] += delta[0] / this.graph.config.canvas_scale;
- this.graph.config.canvas_offset[1] += delta[1] / this.graph.config.canvas_scale;
+ this.offset[0] += delta[0] / this.scale;
+ this.offset[1] += delta[1] / this.scale;
this.dirty_canvas = true;
this.dirty_bgcanvas = true;
}
@@ -2055,12 +2255,12 @@ LGraphCanvas.prototype.processMouseMove = function(e)
var n = this.graph.getNodeOnPos(e.canvasX, e.canvasY, this.visible_nodes);
//remove mouseover flag
- for(var i in this.graph.nodes)
+ for(var i in this.graph._nodes)
{
- if(this.graph.nodes[i].mouseOver && n != this.graph.nodes[i])
+ if(this.graph._nodes[i].mouseOver && n != this.graph._nodes[i])
{
//mouse leave
- this.graph.nodes[i].mouseOver = false;
+ this.graph._nodes[i].mouseOver = false;
if(this.node_over && this.node_over.onMouseLeave)
this.node_over.onMouseLeave(e);
this.node_over = null;
@@ -2117,8 +2317,8 @@ LGraphCanvas.prototype.processMouseMove = function(e)
if(this.node_dragged && !this.live_mode)
{
/*
- this.node_dragged.pos[0] += delta[0] / this.graph.config.canvas_scale;
- this.node_dragged.pos[1] += delta[1] / this.graph.config.canvas_scale;
+ this.node_dragged.pos[0] += delta[0] / this.scale;
+ this.node_dragged.pos[1] += delta[1] / this.scale;
this.node_dragged.pos[0] = Math.round(this.node_dragged.pos[0]);
this.node_dragged.pos[1] = Math.round(this.node_dragged.pos[1]);
*/
@@ -2127,8 +2327,8 @@ LGraphCanvas.prototype.processMouseMove = function(e)
{
var n = this.selected_nodes[i];
- n.pos[0] += delta[0] / this.graph.config.canvas_scale;
- n.pos[1] += delta[1] / this.graph.config.canvas_scale;
+ n.pos[0] += delta[0] / this.scale;
+ n.pos[1] += delta[1] / this.scale;
n.pos[0] = Math.round(n.pos[0]);
n.pos[1] = Math.round(n.pos[1]);
}
@@ -2139,8 +2339,8 @@ LGraphCanvas.prototype.processMouseMove = function(e)
if(this.resizing_node && !this.live_mode)
{
- this.resizing_node.size[0] += delta[0] / this.graph.config.canvas_scale;
- this.resizing_node.size[1] += delta[1] / this.graph.config.canvas_scale;
+ this.resizing_node.size[0] += delta[0] / this.scale;
+ this.resizing_node.size[1] += delta[1] / this.scale;
var max_slots = Math.max( this.resizing_node.inputs ? this.resizing_node.inputs.length : 0, this.resizing_node.outputs ? this.resizing_node.outputs.length : 0);
if(this.resizing_node.size[1] < max_slots * LiteGraph.NODE_SLOT_HEIGHT + 4)
this.resizing_node.size[1] = max_slots * LiteGraph.NODE_SLOT_HEIGHT + 4;
@@ -2169,6 +2369,9 @@ LGraphCanvas.prototype.processMouseUp = function(e)
{
if(!this.graph) return;
+ var window = this.getCanvasWindow();
+ var document = window.document;
+
document.removeEventListener("mousemove", this._mousemove_callback, true );
this.canvas.addEventListener("mousemove", this._mousemove_callback, true);
document.removeEventListener("mouseup", this._mouseup_callback, true );
@@ -2334,7 +2537,7 @@ LGraphCanvas.prototype.processMouseWheel = function(e)
this.adjustMouseEvent(e);
- var zoom = this.graph.config.canvas_scale;
+ var zoom = this.scale;
if (delta > 0)
zoom *= 1.1;
@@ -2419,13 +2622,13 @@ LGraphCanvas.prototype.selectNode = function(node)
LGraphCanvas.prototype.selectAllNodes = function()
{
- for(var i in this.graph.nodes)
+ for(var i in this.graph._nodes)
{
- var n = this.graph.nodes[i];
+ var n = this.graph._nodes[i];
if(!n.selected && n.onSelected)
n.onSelected();
n.selected = true;
- this.selected_nodes[this.graph.nodes[i].id] = n;
+ this.selected_nodes[this.graph._nodes[i].id] = n;
}
this.setDirty(true);
@@ -2458,8 +2661,8 @@ LGraphCanvas.prototype.deleteSelectedNodes = function()
LGraphCanvas.prototype.centerOnNode = function(node)
{
- this.graph.config.canvas_offset[0] = -node.pos[0] - node.size[0] * 0.5 + (this.canvas.width * 0.5 / this.graph.config.canvas_scale);
- this.graph.config.canvas_offset[1] = -node.pos[1] - node.size[1] * 0.5 + (this.canvas.height * 0.5 / this.graph.config.canvas_scale);
+ this.offset[0] = -node.pos[0] - node.size[0] * 0.5 + (this.canvas.width * 0.5 / this.scale);
+ this.offset[1] = -node.pos[1] - node.size[1] * 0.5 + (this.canvas.height * 0.5 / this.scale);
this.setDirty(true,true);
}
@@ -2469,8 +2672,8 @@ LGraphCanvas.prototype.adjustMouseEvent = function(e)
e.localX = e.pageX - b.left;
e.localY = e.pageY - b.top;
- e.canvasX = e.localX / this.graph.config.canvas_scale - this.graph.config.canvas_offset[0];
- e.canvasY = e.localY / this.graph.config.canvas_scale - this.graph.config.canvas_offset[1];
+ e.canvasX = e.localX / this.scale - this.offset[0];
+ e.canvasY = e.localY / this.scale - this.offset[1];
}
LGraphCanvas.prototype.setZoom = function(value, zooming_center)
@@ -2480,18 +2683,18 @@ LGraphCanvas.prototype.setZoom = function(value, zooming_center)
var center = this.convertOffsetToCanvas( zooming_center );
- this.graph.config.canvas_scale = value;
+ this.scale = value;
- if(this.graph.config.canvas_scale > 4)
- this.graph.config.canvas_scale = 4;
- else if(this.graph.config.canvas_scale < 0.1)
- this.graph.config.canvas_scale = 0.1;
+ if(this.scale > 4)
+ this.scale = 4;
+ else if(this.scale < 0.1)
+ this.scale = 0.1;
var new_center = this.convertOffsetToCanvas( zooming_center );
var delta_offset = [new_center[0] - center[0], new_center[1] - center[1]];
- this.graph.config.canvas_offset[0] += delta_offset[0];
- this.graph.config.canvas_offset[1] += delta_offset[1];
+ this.offset[0] += delta_offset[0];
+ this.offset[1] += delta_offset[1];
this.dirty_canvas = true;
this.dirty_bgcanvas = true;
@@ -2499,13 +2702,13 @@ LGraphCanvas.prototype.setZoom = function(value, zooming_center)
LGraphCanvas.prototype.convertOffsetToCanvas = function(pos)
{
- return [pos[0] / this.graph.config.canvas_scale - this.graph.config.canvas_offset[0], pos[1] / this.graph.config.canvas_scale - this.graph.config.canvas_offset[1]];
+ return [pos[0] / this.scale - this.offset[0], pos[1] / this.scale - this.offset[1]];
}
LGraphCanvas.prototype.convertCanvasToOffset = function(pos)
{
- return [(pos[0] + this.graph.config.canvas_offset[0]) * this.graph.config.canvas_scale,
- (pos[1] + this.graph.config.canvas_offset[1]) * this.graph.config.canvas_scale ];
+ return [(pos[0] + this.offset[0]) * this.scale,
+ (pos[1] + this.offset[1]) * this.scale ];
}
LGraphCanvas.prototype.convertEventToCanvas = function(e)
@@ -2516,20 +2719,20 @@ LGraphCanvas.prototype.convertEventToCanvas = function(e)
LGraphCanvas.prototype.bringToFront = function(n)
{
- var i = this.graph.nodes.indexOf(n);
+ var i = this.graph._nodes.indexOf(n);
if(i == -1) return;
- this.graph.nodes.splice(i,1);
- this.graph.nodes.push(n);
+ this.graph._nodes.splice(i,1);
+ this.graph._nodes.push(n);
}
LGraphCanvas.prototype.sendToBack = function(n)
{
- var i = this.graph.nodes.indexOf(n);
+ var i = this.graph._nodes.indexOf(n);
if(i == -1) return;
- this.graph.nodes.splice(i,1);
- this.graph.nodes.unshift(n);
+ this.graph._nodes.splice(i,1);
+ this.graph._nodes.unshift(n);
}
/* Interaction */
@@ -2541,9 +2744,9 @@ LGraphCanvas.prototype.sendToBack = function(n)
LGraphCanvas.prototype.computeVisibleNodes = function()
{
var visible_nodes = [];
- for (var i in this.graph.nodes)
+ for (var i in this.graph._nodes)
{
- var n = this.graph.nodes[i];
+ var n = this.graph._nodes[i];
//skip rendering nodes in live mode
if(this.live_mode && !n.onDrawBackground && !n.onDrawForeground)
@@ -2560,14 +2763,14 @@ LGraphCanvas.prototype.computeVisibleNodes = function()
LGraphCanvas.prototype.draw = function(force_canvas, force_bgcanvas)
{
//fps counting
- var now = new Date().getTime();
+ var now = window.performance.now();
this.render_time = (now - this.last_draw_time)*0.001;
this.last_draw_time = now;
if(this.graph)
{
- var start = [-this.graph.config.canvas_offset[0], -this.graph.config.canvas_offset[1] ];
- var end = [start[0] + this.canvas.width / this.graph.config.canvas_scale, start[1] + this.canvas.height / this.graph.config.canvas_scale];
+ var start = [-this.offset[0], -this.offset[1] ];
+ var end = [start[0] + this.canvas.width / this.scale, start[1] + this.canvas.height / this.scale];
this.visible_area = new Float32Array([start[0],start[1],end[0],end[1]]);
}
@@ -2626,8 +2829,8 @@ LGraphCanvas.prototype.drawFrontCanvas = function()
{
//apply transformations
ctx.save();
- ctx.scale(this.graph.config.canvas_scale,this.graph.config.canvas_scale);
- ctx.translate(this.graph.config.canvas_offset[0],this.graph.config.canvas_offset[1]);
+ ctx.scale(this.scale,this.scale);
+ ctx.translate(this.offset[0],this.offset[1]);
//draw nodes
var drawn_nodes = 0;
@@ -2658,10 +2861,9 @@ LGraphCanvas.prototype.drawFrontCanvas = function()
//current connection
if(this.connecting_pos != null)
{
- ctx.lineWidth = LGraphCanvas.link_width;
- ctx.fillStyle = this.connecting_output.type == 'node' ? "#F85" : "#AFA";
- ctx.strokeStyle = ctx.fillStyle;
- this.renderLink(ctx, this.connecting_pos, [this.canvas_mouse[0],this.canvas_mouse[1]] );
+ ctx.lineWidth = this.connections_width;
+ var link_color = this.connecting_output.type == 'node' ? "#F85" : "#AFA";
+ this.renderLink(ctx, this.connecting_pos, [this.canvas_mouse[0],this.canvas_mouse[1]], link_color );
ctx.beginPath();
ctx.arc( this.connecting_pos[0], this.connecting_pos[1],4,0,Math.PI*2);
@@ -2710,13 +2912,13 @@ LGraphCanvas.prototype.drawBgcanvas = function()
{
//apply transformations
ctx.save();
- ctx.scale(this.graph.config.canvas_scale,this.graph.config.canvas_scale);
- ctx.translate(this.graph.config.canvas_offset[0],this.graph.config.canvas_offset[1]);
+ ctx.scale(this.scale,this.scale);
+ ctx.translate(this.offset[0],this.offset[1]);
//render BG
- if(this.background_image && this.graph.config.canvas_scale > 0.5)
+ if(this.background_image && this.scale > 0.5)
{
- ctx.globalAlpha = 1.0 - 0.5 / this.graph.config.canvas_scale;
+ ctx.globalAlpha = (1.0 - 0.5 / this.scale) * this.editor_alpha;
ctx.webkitImageSmoothingEnabled = ctx.mozImageSmoothingEnabled = ctx.imageSmoothingEnabled = false
if(!this._bg_img || this._bg_img.name != this.background_image)
{
@@ -2756,8 +2958,7 @@ LGraphCanvas.prototype.drawBgcanvas = function()
ctx.strokeStyle = "#235";
ctx.strokeRect(0,0,canvas.width,canvas.height);
- /*
- if(this.render_shadows)
+ if(this.render_connections_shadows)
{
ctx.shadowColor = "#000";
ctx.shadowOffsetX = 0;
@@ -2766,12 +2967,13 @@ LGraphCanvas.prototype.drawBgcanvas = function()
}
else
ctx.shadowColor = "rgba(0,0,0,0)";
- */
//draw connections
if(!this.live_mode)
this.drawConnections(ctx);
+ ctx.shadowColor = "rgba(0,0,0,0)";
+
//restore state
ctx.restore();
}
@@ -2822,8 +3024,8 @@ LGraphCanvas.prototype.drawNode = function(node, ctx )
if(!node.flags.collapsed)
{
ctx.shadowColor = "transparent";
- if(node.onDrawBackground)
- node.onDrawBackground(ctx);
+ //if(node.onDrawBackground)
+ // node.onDrawBackground(ctx);
if(node.onDrawForeground)
node.onDrawForeground(ctx);
}
@@ -2841,13 +3043,16 @@ LGraphCanvas.prototype.drawNode = function(node, ctx )
}
*/
+ var editor_alpha = this.editor_alpha;
+ ctx.globalAlpha = editor_alpha;
+
//clip if required (mask)
var shape = node.shape || "box";
var size = new Float32Array(node.size);
if(node.flags.collapsed)
size.set([LiteGraph.NODE_COLLAPSED_WIDTH, 0]);
- //Start cliping
+ //Start clipping
if(node.flags.clip_area)
{
ctx.save();
@@ -2874,9 +3079,9 @@ LGraphCanvas.prototype.drawNode = function(node, ctx )
//connection slots
ctx.textAlign = "left";
- ctx.font = "12px Arial";
+ ctx.font = this.inner_text_font;
- var render_text = node.graph.config.canvas_scale > 0.6;
+ var render_text = this.scale > 0.6;
//render inputs and outputs
if(!node.flags.collapsed)
@@ -2887,9 +3092,9 @@ LGraphCanvas.prototype.drawNode = function(node, ctx )
{
var slot = node.inputs[i];
- ctx.globalAlpha = 1.0;
+ ctx.globalAlpha = editor_alpha;
if (this.connecting_node != null && this.connecting_output.type != 0 && node.inputs[i].type != 0 && this.connecting_output.type != node.inputs[i].type)
- ctx.globalAlpha = 0.4;
+ ctx.globalAlpha = 0.4 * editor_alpha;
ctx.fillStyle = slot.link != null ? "#7F7" : "#AAA";
@@ -2920,7 +3125,7 @@ LGraphCanvas.prototype.drawNode = function(node, ctx )
//output connection slots
if(this.connecting_node)
- ctx.globalAlpha = 0.4;
+ ctx.globalAlpha = 0.4 * editor_alpha;
ctx.lineWidth = 1;
@@ -2965,7 +3170,7 @@ LGraphCanvas.prototype.drawNode = function(node, ctx )
}
ctx.textAlign = "left";
- ctx.globalAlpha = 1.0;
+ ctx.globalAlpha = 1;
if(node.onDrawForeground)
node.onDrawForeground(ctx);
@@ -2973,6 +3178,8 @@ LGraphCanvas.prototype.drawNode = function(node, ctx )
if(node.flags.clip_area)
ctx.restore();
+
+ ctx.globalAlpha = 1.0;
}
/* Renders the node shape */
@@ -2988,7 +3195,7 @@ LGraphCanvas.prototype.drawNodeShape = function(node, ctx, size, fgcolor, bgcolo
grad.addColorStop(0.5, fgcolor || LiteGraph.NODE_DEFAULT_COLOR);
grad.addColorStop(1, bgcolor || LiteGraph.NODE_DEFAULT_BGCOLOR);
ctx.fillStyle = grad;
- */
+ //*/
var title_height = LiteGraph.NODE_TITLE_HEIGHT;
@@ -3004,7 +3211,7 @@ LGraphCanvas.prototype.drawNodeShape = function(node, ctx, size, fgcolor, bgcolo
}
ctx.beginPath();
- ctx.rect(0,no_title ? 0.5 : -title_height + 1,size[0]+1, no_title ? size[1] : size[1] + title_height);
+ ctx.rect(0,no_title ? 0.5 : -title_height + 0.5,size[0]+1, no_title ? size[1] : size[1] + title_height);
}
else if (node.shape == "round")
{
@@ -3035,7 +3242,8 @@ LGraphCanvas.prototype.drawNodeShape = function(node, ctx, size, fgcolor, bgcolo
if(!no_title)
{
ctx.fillStyle = fgcolor || LiteGraph.NODE_DEFAULT_COLOR;
-
+ var old_alpha = ctx.globalAlpha;
+ ctx.globalAlpha = 0.5 * old_alpha;
if(shape == "box")
{
ctx.beginPath();
@@ -3058,10 +3266,11 @@ LGraphCanvas.prototype.drawNodeShape = function(node, ctx, size, fgcolor, bgcolo
else
ctx.rect(3,-title_height + 3,title_height - 6,title_height - 6);
ctx.fill();
+ ctx.globalAlpha = old_alpha;
//title text
- ctx.font = "bold 12px Arial";
- if(node.name != "" && node.graph.config.canvas_scale > 0.8)
+ ctx.font = this.title_text_font;
+ if(node.name != "" && this.scale > 0.8)
{
ctx.fillStyle = "#222";
ctx.fillText(node.name,16,13-title_height );
@@ -3128,14 +3337,15 @@ LGraphCanvas.link_colors = ["#AAC","#ACA","#CAA"];
LGraphCanvas.prototype.drawConnections = function(ctx)
{
//draw connections
- ctx.lineWidth = LGraphCanvas.link_width;
+ ctx.lineWidth = this.connections_width;
ctx.fillStyle = "#AAA";
ctx.strokeStyle = "#AAA";
+ ctx.globalAlpha = this.editor_alpha;
//for every node
- for (var n in this.graph.nodes)
+ for (var n in this.graph._nodes)
{
- var node = this.graph.nodes[n];
+ var node = this.graph._nodes[n];
//for every input (we render just inputs because it is easier as every slot can only have one input)
if(node.inputs && node.inputs.length)
for(var i in node.inputs)
@@ -3157,16 +3367,14 @@ LGraphCanvas.prototype.drawConnections = function(ctx)
var color = LGraphCanvas.link_type_colors[node.inputs[i].type];
if(color == null)
color = LGraphCanvas.link_colors[node.id % LGraphCanvas.link_colors.length];
- ctx.fillStyle = ctx.strokeStyle = color;
- this.renderLink(ctx, start_node_slotpos, node.getConnectionPos(true,i) );
+ this.renderLink(ctx, start_node_slotpos, node.getConnectionPos(true,i), color );
}
}
+ ctx.globalAlpha = 1;
}
-LGraphCanvas.prototype.renderLink = function(ctx,a,b)
+LGraphCanvas.prototype.renderLink = function(ctx,a,b,color)
{
- var curved_lines = true;
-
if(!this.highquality_render)
{
ctx.beginPath();
@@ -3178,32 +3386,44 @@ LGraphCanvas.prototype.renderLink = function(ctx,a,b)
var dist = distance(a,b);
+ if(this.render_connections_border)
+ ctx.lineWidth = this.connections_width + 4;
+
ctx.beginPath();
- if(curved_lines)
+ if(this.render_curved_connections) //splines
{
ctx.moveTo(a[0],a[1]);
ctx.bezierCurveTo(a[0] + dist*0.25, a[1],
b[0] - dist*0.25 , b[1],
b[0] ,b[1] );
}
- else
+ else //lines
{
ctx.moveTo(a[0]+10,a[1]);
ctx.lineTo(((a[0]+10) + (b[0]-10))*0.5,a[1]);
ctx.lineTo(((a[0]+10) + (b[0]-10))*0.5,b[1]);
ctx.lineTo(b[0]-10,b[1]);
}
+
+ if(this.render_connections_border)
+ {
+ ctx.strokeStyle = "rgba(0,0,0,0.5)";
+ ctx.stroke();
+ }
+
+ ctx.lineWidth = this.connections_width;
+ ctx.fillStyle = ctx.strokeStyle = color;
ctx.stroke();
//render arrow
- if(this.graph.config.canvas_scale > 0.6)
+ if(this.render_connection_arrows && this.scale > 0.6)
{
//get two points in the bezier curve
var pos = this.computeConnectionPoint(a,b,0.5);
var pos2 = this.computeConnectionPoint(a,b,0.51);
var angle = 0;
- if(curved_lines)
+ if(this.render_curved_connections)
angle = -Math.atan2( pos2[0] - pos[0], pos2[1] - pos[1]);
else
angle = b[1] > a[1] ? 0 : Math.PI;
@@ -3238,6 +3458,7 @@ LGraphCanvas.prototype.computeConnectionPoint = function(a,b,t)
return [x,y];
}
+/*
LGraphCanvas.prototype.resizeCanvas = function(width,height)
{
this.canvas.width = width;
@@ -3248,12 +3469,63 @@ LGraphCanvas.prototype.resizeCanvas = function(width,height)
this.bgcanvas.height = this.canvas.height;
this.draw(true,true);
}
+*/
-LGraphCanvas.prototype.switchLiveMode = function()
+LGraphCanvas.prototype.resize = function(width, height)
{
- this.live_mode = !this.live_mode;
- this.dirty_canvas = true;
- this.dirty_bgcanvas = true;
+ if(!width && !height)
+ {
+ var parent = this.canvas.parentNode;
+ width = parent.offsetWidth;
+ height = parent.offsetHeight;
+ }
+
+ if(this.canvas.width == width && this.canvas.height == height)
+ return;
+
+ this.canvas.width = width;
+ this.canvas.height = height;
+ this.bgcanvas.width = this.canvas.width;
+ this.bgcanvas.height = this.canvas.height;
+ this.setDirty(true,true);
+}
+
+
+LGraphCanvas.prototype.switchLiveMode = function(transition)
+{
+ if(!transition)
+ {
+ this.live_mode = !this.live_mode;
+ this.dirty_canvas = true;
+ this.dirty_bgcanvas = true;
+ return;
+ }
+
+ var self = this;
+ var delta = this.live_mode ? 1.1 : 0.9;
+ if(this.live_mode)
+ {
+ this.live_mode = false;
+ this.editor_alpha = 0.1;
+ }
+
+ var t = setInterval(function() {
+ self.editor_alpha *= delta;
+ self.dirty_canvas = true;
+ self.dirty_bgcanvas = true;
+
+ if(delta < 1 && self.editor_alpha < 0.01)
+ {
+ clearInterval(t);
+ if(delta < 1)
+ self.live_mode = true;
+ }
+ if(delta > 1 && self.editor_alpha > 0.99)
+ {
+ clearInterval(t);
+ self.editor_alpha = 1;
+ }
+ },1);
}
LGraphCanvas.prototype.onNodeSelectionChange = function(node)
@@ -3280,6 +3552,9 @@ LGraphCanvas.prototype.touchHandler = function(event)
//initMouseEvent(type, canBubble, cancelable, view, clickCount,
// screenX, screenY, clientX, clientY, ctrlKey,
// altKey, shiftKey, metaKey, button, relatedTarget);
+
+ var window = this.getCanvasWindow();
+ var document = window.document;
var simulatedEvent = document.createEvent("MouseEvent");
simulatedEvent.initMouseEvent(type, true, true, window, 1,
@@ -3294,13 +3569,15 @@ LGraphCanvas.prototype.touchHandler = function(event)
LGraphCanvas.onMenuAdd = function(node, e, prev_menu, canvas, first_event )
{
+ var window = canvas.getCanvasWindow();
+
var values = LiteGraph.getNodeTypesCategories();
var entries = {};
for(var i in values)
if(values[i])
entries[ i ] = { value: values[i], content: values[i] , is_menu: true };
- var menu = LiteGraph.createContextualMenu(entries, {event: e, callback: inner_clicked, from: prev_menu});
+ var menu = LiteGraph.createContextualMenu(entries, {event: e, callback: inner_clicked, from: prev_menu}, window);
function inner_clicked(v, e)
{
@@ -3310,7 +3587,7 @@ LGraphCanvas.onMenuAdd = function(node, e, prev_menu, canvas, first_event )
for(var i in node_types)
values.push( { content: node_types[i].title, value: node_types[i].type });
- LiteGraph.createContextualMenu(values, {event: e, callback: inner_create, from: menu});
+ LiteGraph.createContextualMenu(values, {event: e, callback: inner_create, from: menu}, window);
return false;
}
@@ -3391,7 +3668,19 @@ LGraphCanvas.onMenuNodeOutputs = function(node, e, prev_menu)
function inner_clicked(v)
{
if(!node) return;
- node.addOutput(v.value[0],v.value[1]);
+
+ var value = v.value[1];
+
+ if(value && (value.constructor === Object || value.constructor === Array)) //submenu
+ {
+ var entries = [];
+ for(var i in value)
+ entries.push({content: i, value: value[i]});
+ LiteGraph.createContextualMenu(entries, {event: e, callback: inner_clicked, from: prev_menu});
+ return false;
+ }
+ else
+ node.addOutput(v.value[0],v.value[1]);
}
return false;
@@ -3403,6 +3692,11 @@ LGraphCanvas.onMenuNodeCollapse = function(node)
node.graph.canvas.setDirty(true,true);
}
+LGraphCanvas.onMenuNodePin = function(node)
+{
+ node.pin();
+}
+
LGraphCanvas.onMenuNodeColors = function(node, e, prev_menu)
{
var values = [];
@@ -3482,6 +3776,7 @@ LGraphCanvas.prototype.getNodeMenuOptions = function(node)
{content:"Outputs", is_menu: true, disabled:true, callback: LGraphCanvas.onMenuNodeOutputs },
null,
{content:"Collapse", callback: LGraphCanvas.onMenuNodeCollapse },
+ {content:"Pin", callback: LGraphCanvas.onMenuNodePin },
{content:"Colors", is_menu: true, callback: LGraphCanvas.onMenuNodeColors },
{content:"Shapes", is_menu: true, callback: LGraphCanvas.onMenuNodeShapes },
null,
@@ -3506,7 +3801,9 @@ LGraphCanvas.prototype.getNodeMenuOptions = function(node)
LGraphCanvas.prototype.processContextualMenu = function(node,event)
{
var that = this;
- var menu = LiteGraph.createContextualMenu(node ? this.getNodeMenuOptions(node) : this.getCanvasMenuOptions(), {event: event, callback: inner_option_clicked});
+ var win = this.getCanvasWindow();
+
+ var menu = LiteGraph.createContextualMenu(node ? this.getNodeMenuOptions(node) : this.getCanvasMenuOptions(), {event: event, callback: inner_option_clicked}, win);
function inner_option_clicked(v,e)
{
@@ -3642,15 +3939,18 @@ function num2hex(triplet) {
/* LiteGraph GUI elements *************************************/
-LiteGraph.createContextualMenu = function(values,options)
+LiteGraph.createContextualMenu = function(values,options, ref_window)
{
options = options || {};
this.options = options;
+ //allows to create graph canvas in separate window
+ ref_window = ref_window || window;
+
if(!options.from)
LiteGraph.closeAllContextualMenus();
- var root = document.createElement("div");
+ var root = ref_window.document.createElement("div");
root.className = "litecontextualmenu litemenubar-panel";
this.root = root;
var style = root.style;
@@ -3672,7 +3972,7 @@ LiteGraph.createContextualMenu = function(values,options)
for(var i in values)
{
var item = values[i];
- var element = document.createElement("div");
+ var element = ref_window.document.createElement("div");
element.className = "litemenu-entry";
if(item == null)
@@ -3707,7 +4007,7 @@ LiteGraph.createContextualMenu = function(values,options)
root.addEventListener("mouseout", function(e) {
//console.log("OUT!");
var aux = e.toElement;
- while(aux != this && aux != document)
+ while(aux != this && aux != ref_window.document)
aux = aux.parentNode;
if(aux == this) return;
@@ -3716,17 +4016,8 @@ LiteGraph.createContextualMenu = function(values,options)
this.closeMenu();
});
- /* MS specific
- root.addEventListener("mouseleave", function(e) {
-
- this.mouse_inside = false;
- if(!this.block_close)
- this.closeMenu();
- });
- */
-
//insert before checking position
- document.body.appendChild(root);
+ ref_window.document.body.appendChild(root);
var root_rect = root.getClientRects()[0];
@@ -3745,7 +4036,7 @@ LiteGraph.createContextualMenu = function(values,options)
if(options.left)
left = options.left;
- var rect = document.body.getClientRects()[0];
+ var rect = ref_window.document.body.getClientRects()[0];
if(options.from)
{
@@ -3786,7 +4077,7 @@ LiteGraph.createContextualMenu = function(values,options)
options.from.closeMenu();
}
if(this.parentNode)
- document.body.removeChild(this);
+ ref_window.document.body.removeChild(this);
};
return root;
@@ -3813,7 +4104,27 @@ LiteGraph.extendClass = function(origin, target)
if(origin.prototype) //copy prototype properties
for(var i in origin.prototype)
target.prototype[i] = origin.prototype[i];
-}
+}
+
+/*
+LiteGraph.createNodetypeWrapper = function( class_object )
+{
+ //create Nodetype object
+}
+//LiteGraph.registerNodeType("scene/global", LGraphGlobal );
+*/
+
+if( !window["requestAnimationFrame"] )
+{
+ window.requestAnimationFrame = window.webkitRequestAnimationFrame ||
+ window.mozRequestAnimationFrame ||
+ (function( callback ){
+ window.setTimeout(callback, 1000 / 60);
+ });
+}
+
+
+
//basic nodes
LiteGraph.registerNodeType("basic/const",{
@@ -4633,7 +4944,7 @@ LiteGraph.registerNodeType("network/network_callback",{
ctx.textAlign = "left";
},
- onDrawBackground: function(ctx)
+ onDrawForeground: function(ctx)
{
this.onDrawImageKnob(ctx);
},
@@ -4781,7 +5092,7 @@ LiteGraph.registerNodeType("network/network_callback",{
ctx.drawImage(this.imgfg, 2+(this.size[0]-4)*this.value - this.imgfg.width*0.5,-this.imgfg.height*0.5 + 10);
},
- onDrawBackground: function(ctx)
+ onDrawForeground: function(ctx)
{
this.onDrawImage(ctx);
},
@@ -5005,7 +5316,7 @@ LiteGraph.registerNodeType("network/network_callback",{
ctx.textAlign = "left";
},
- onDrawBackground: function(ctx)
+ onDrawForeground: function(ctx)
{
this.drawBevelShape(ctx);
},
@@ -5069,7 +5380,7 @@ LiteGraph.registerNodeType("network/network_callback",{
if( v != undefined )
this.properties["value"] = v;
},
- onDrawBackground: function(ctx)
+ onDrawForeground: function(ctx)
{
//border
ctx.lineWidth = 1;
@@ -5089,7 +5400,7 @@ LiteGraph.registerNodeType("network/network_callback",{
inputs: [["",0]],
properties:{value:"...",font:"Arial", fontsize:18, color:"#AAA", align:"left", glowSize:0, decimals:1},
- onDrawBackground: function(ctx)
+ onDrawForeground: function(ctx)
{
//ctx.fillStyle="#000";
//ctx.fillRect(0,0,100,60);
@@ -5199,7 +5510,7 @@ LiteGraph.registerNodeType("network/network_callback",{
this.lineargradient.addColorStop(1,this.properties["bgcolorBottom"]);
},
- onDrawBackground: function(ctx)
+ onDrawForeground: function(ctx)
{
if(this.lineargradient == null)
this.createGradient(ctx);
diff --git a/build/litegraph.min.js b/build/litegraph.min.js
index 5b884266d..f3387ecb4 100644
--- a/build/litegraph.min.js
+++ b/build/litegraph.min.js
@@ -1,28 +1,29 @@
-var LiteGraph={NODE_TITLE_HEIGHT:16,NODE_SLOT_HEIGHT:15,NODE_WIDTH:140,NODE_MIN_WIDTH:50,NODE_COLLAPSED_RADIUS:10,NODE_COLLAPSED_WIDTH:80,CANVAS_GRID_SIZE:10,NODE_DEFAULT_COLOR:"#999",NODE_DEFAULT_BGCOLOR:"#444",NODE_DEFAULT_BOXCOLOR:"#AEF",NODE_DEFAULT_SHAPE:"box",MAX_NUMBER_OF_NODES:1E3,DEFAULT_POSITION:[100,100],node_images_path:"",debug:!1,registered_node_types:{},graphs:[],registerNodeType:function(a,b){b.type=a;LiteGraph.debug&&console.log("Node registered: "+a);a.split("/");var c=a.lastIndexOf("/");
+var LiteGraph={NODE_TITLE_HEIGHT:16,NODE_SLOT_HEIGHT:15,NODE_WIDTH:140,NODE_MIN_WIDTH:50,NODE_COLLAPSED_RADIUS:10,NODE_COLLAPSED_WIDTH:80,CANVAS_GRID_SIZE:10,NODE_DEFAULT_COLOR:"#999",NODE_DEFAULT_BGCOLOR:"#444",NODE_DEFAULT_BOXCOLOR:"#AEF",NODE_DEFAULT_SHAPE:"box",MAX_NUMBER_OF_NODES:1E3,DEFAULT_POSITION:[100,100],node_images_path:"",debug:!1,registered_node_types:{},registerNodeType:function(a,b){b.type=a;LiteGraph.debug&&console.log("Node registered: "+a);a.split("/");var c=a.lastIndexOf("/");
b.category=a.substr(0,c);if(b.prototype)for(var d in LGraphNode.prototype)b.prototype[d]||(b.prototype[d]=LGraphNode.prototype[d]);this.registered_node_types[a]=b},createNode:function(a,b,c){var d=this.registered_node_types[a];if(!d)return LiteGraph.debug&&console.log('GraphNode type "'+a+'" not registered.'),null;var e=d.prototype||d;b=b||e.title||d.title||a;var f=null;if(d.prototype)f=new d(b);else{f=new LGraphNode(b);f.inputs=[];f.outputs=[];for(var g in e)if("inputs"==g)for(var h in e[g])f.addInput(e[g][h][0],
e[g][h][1],e[g][h][2]);else if("outputs"==g)for(h in e[g])f.addOutput(e[g][h][0],e[g][h][1],e[g][h][2]);else f[g]=e[g].concat?e[g].concat():"object"==typeof e[g]?LiteGraph.cloneObject(e[g]):e[g];d.size&&(f.size=d.size.concat())}f.type=a;f.name||(f.name=b);f.flags||(f.flags={});f.size||(f.size=f.computeSize());f.pos||(f.pos=LiteGraph.DEFAULT_POSITION.concat());if(c)for(g in c)f[g]=c[g];return f},getNodeType:function(a){return this.registered_node_types[a]},getNodeTypesInCategory:function(a){var b=
[],c;for(c in this.registered_node_types)""==a?null==this.registered_node_types[c].category&&b.push(this.registered_node_types[c]):this.registered_node_types[c].category==a&&b.push(this.registered_node_types[c]);return b},getNodeTypesCategories:function(){var a={"":1},b;for(b in this.registered_node_types)this.registered_node_types[b].category&&!this.registered_node_types[b].skip_list&&(a[this.registered_node_types[b].category]=1);var c=[];for(b in a)c.push(b);return c},reloadNodes:function(a){var b=
-document.getElementsByTagName("script"),c=[],d;for(d in b)c.push(b[d]);b=document.getElementsByTagName("head")[0];a=document.location.href+a;for(d in c){var e=c[d].src;if(e&&e.substr(0,a.length)==a)try{LiteGraph.debug&&console.log("Reloading: "+e);var f=document.createElement("script");f.type="text/javascript";f.src=e;b.appendChild(f);b.removeChild(c[d])}catch(g){if(LiteGraph.throw_errors)throw g;LiteGraph.debug&&console.log("Error while reloading "+e)}}for(d in LiteGraph.graphs)for(var h in LiteGraph.graphs[d].nodes)if(a=
-LiteGraph.graphs[d].nodes[h],c=LiteGraph.getNodeType(n.type))for(var k in c)"function"==typeof c[k]&&(a[k]=c[k]);LiteGraph.debug&&console.log("Nodes reloaded")},cloneObject:function(a){return JSON.parse(JSON.stringify(a))}};function LGraph(){LiteGraph.debug&&console.log("Graph created");this.canvas=null;LiteGraph.graphs.push(this);this.clear()}LGraph.STATUS_STOPPED=1;LGraph.STATUS_RUNNING=2;
-LGraph.prototype.clear=function(){this.stop();this.status=LGraph.STATUS_STOPPED;this.last_node_id=0;this.nodes=[];this.nodes_by_id={};this.last_link_id=0;this.links={};this.iteration=0;this.config={canvas_offset:[0,0],canvas_scale:1};this.fixedtime=this.runningtime=this.globaltime=0;this.elapsed_time=this.fixedtime_lapse=0.01;this.starttime=0;this.graph={};this.debug=!0;this.change();this.canvas&&this.canvas.clear()};
-LGraph.prototype.start=function(a){if(this.status!=LGraph.STATUS_RUNNING){this.status=LGraph.STATUS_RUNNING;if(this.onPlayEvent)this.onPlayEvent();this.sendEventToAllNodes("onStart");this.starttime=(new Date).getTime();var b=this;this.execution_timer_id=setInterval(function(){b.runStep(1)},a||1)}};
+document.getElementsByTagName("script"),c=[],d;for(d in b)c.push(b[d]);b=document.getElementsByTagName("head")[0];a=document.location.href+a;for(d in c){var e=c[d].src;if(e&&e.substr(0,a.length)==a)try{LiteGraph.debug&&console.log("Reloading: "+e);var f=document.createElement("script");f.type="text/javascript";f.src=e;b.appendChild(f);b.removeChild(c[d])}catch(g){if(LiteGraph.throw_errors)throw g;LiteGraph.debug&&console.log("Error while reloading "+e)}}LiteGraph.debug&&console.log("Nodes reloaded")},
+cloneObject:function(a,b){var c=JSON.parse(JSON.stringify(a));if(!b)return c;for(var d in c)b[d]=c[d];return b}};function LGraph(){LiteGraph.debug&&console.log("Graph created");this.list_of_graphcanvas=null;this.clear()}LGraph.STATUS_STOPPED=1;LGraph.STATUS_RUNNING=2;
+LGraph.prototype.clear=function(){this.stop();this.status=LGraph.STATUS_STOPPED;this.last_node_id=0;this._nodes=[];this._nodes_by_id={};this.last_link_id=0;this.links={};this.iteration=0;this.config={};this.fixedtime=this.runningtime=this.globaltime=0;this.elapsed_time=this.fixedtime_lapse=0.01;this.starttime=0;this.globals={};this.graph={};this.debug=!0;this.change();this.sendActionToCanvas("clear")};
+LGraph.prototype.attachCanvas=function(a){if(a.constructor!=LGraphCanvas)throw"attachCanvas expects a LGraphCanvas instance";a.graph&&a.graph!=this&&a.graph.detachCanvas(a);a.graph=this;this.list_of_graphcanvas||(this.list_of_graphcanvas=[]);this.list_of_graphcanvas.push(a)};LGraph.prototype.detachCanvas=function(a){var b=this.list_of_graphcanvas.indexOf(a);-1!=b&&(a.graph=null,this.list_of_graphcanvas.splice(b,1))};
+LGraph.prototype.start=function(a){if(this.status!=LGraph.STATUS_RUNNING){this.status=LGraph.STATUS_RUNNING;if(this.onPlayEvent)this.onPlayEvent();this.sendEventToAllNodes("onStart");this.starttime=window.performance.now();var b=this;this.execution_timer_id=setInterval(function(){b.runStep(1)},a||1)}};
LGraph.prototype.stop=function(){if(this.status!=LGraph.STATUS_STOPPED){this.status=LGraph.STATUS_STOPPED;if(this.onStopEvent)this.onStopEvent();null!=this.execution_timer_id&&clearInterval(this.execution_timer_id);this.execution_timer_id=null;this.sendEventToAllNodes("onStop")}};
-LGraph.prototype.runStep=function(a){a=a||1;var b=(new Date).getTime();this.globaltime=0.001*(b-this.starttime);try{for(var c=0;c=LiteGraph.MAX_NUMBER_OF_NODES)throw"LiteGraph: max number of nodes in a graph reached";if(null==a.id||-1==a.id)a.id=this.last_node_id++;a.graph=this;this.nodes.push(a);this.nodes_by_id[a.id]=a;if(a.onInit)a.onInit();this.config.align_to_grid&&a.alignToGrid();this.updateExecutionOrder();this.canvas&&(this.canvas.dirty_canvas=!0);this.change();return a}};
-LGraph.prototype.remove=function(a){if(null!=this.nodes_by_id[a.id]&&!a.ignore_remove){if(a.inputs)for(var b=0;b =LiteGraph.MAX_NUMBER_OF_NODES)throw"LiteGraph: max number of nodes in a graph reached";if(null==a.id||-1==a.id)a.id=this.last_node_id++;a.graph=this;this._nodes.push(a);this._nodes_by_id[a.id]=a;if(a.onInit)a.onInit();this.config.align_to_grid&&a.alignToGrid();this.updateExecutionOrder();this.canvas&&(this.canvas.dirty_canvas=!0);this.change();return a}};
+LGraph.prototype.remove=function(a){if(null!=this._nodes_by_id[a.id]&&!a.ignore_remove){if(a.inputs)for(var b=0;bb&&this.inputs[b].pos?[this.pos[0]+this.inputs[b].pos[0],this.pos[1]+this.inputs[b].pos[1]]:!a&&this.outputs.length>b&&this.outputs[b].pos?[this.pos[0]+this.outputs[b].pos[0],this.pos[1]+this.outputs[b].pos[1]]:
a?[this.pos[0],this.pos[1]+10+b*LiteGraph.NODE_SLOT_HEIGHT]:[this.pos[0]+this.size[0]+1,this.pos[1]+10+b*LiteGraph.NODE_SLOT_HEIGHT]};LGraphNode.prototype.alignToGrid=function(){this.pos[0]=LiteGraph.CANVAS_GRID_SIZE*Math.round(this.pos[0]/LiteGraph.CANVAS_GRID_SIZE);this.pos[1]=LiteGraph.CANVAS_GRID_SIZE*Math.round(this.pos[1]/LiteGraph.CANVAS_GRID_SIZE)};
-LGraphNode.prototype.copyFromObject=function(a,b){for(var c in a)(!b||"outputs"!=c&&"inputs"!=c)&&"console"!=c&&null!=a[c]&&(this[c]=a[c].concat?a[c].concat():"object"==typeof a[c]?LiteGraph.cloneObject(a[c]):a[c])};
LGraphNode.prototype.clone=function(){var a=LiteGraph.createNode(this.type);a.size=this.size.concat();if(this.inputs)for(var b=0,c=this.inputs.length;bLGraphNode.MAX_CONSOLE&&this.console.shift();this.graph.onNodeTrace(this,a)};LGraphNode.prototype.setDirtyCanvas=function(a,b){this.graph&&this.graph.canvas&&(a&&(this.graph.canvas.dirty_canvas=!0),b&&(this.graph.canvas.dirty_bgcanvas=!0))};
-LGraphNode.prototype.loadImage=function(a){var b=new Image;b.src=LiteGraph.node_images_path+a;b.ready=!1;var c=this;b.onload=function(){this.ready=!0;c.setDirtyCanvas(!0)};return b};
+LGraphNode.prototype.trace=function(a){this.console||(this.console=[]);this.console.push(a);this.console.length>LGraphNode.MAX_CONSOLE&&this.console.shift();this.graph.onNodeTrace(this,a)};LGraphNode.prototype.setDirtyCanvas=function(a,b){this.graph&&this.graph.sendActionToCanvas("setDirty",[a,b])};LGraphNode.prototype.loadImage=function(a){var b=new Image;b.src=LiteGraph.node_images_path+a;b.ready=!1;var c=this;b.onload=function(){this.ready=!0;c.setDirtyCanvas(!0)};return b};
LGraphNode.prototype.executeAction=function(a){if(""==a)return!1;if(-1!=a.indexOf(";")||-1!=a.indexOf("}"))return this.trace("Error: Action contains unsafe characters"),!1;var b=a.split("(")[0];if("function"!=typeof this[b])return this.trace("Error: Action not found on node: "+b),!1;try{b=eval,eval=null,(new Function("with(this) { "+a+"}")).call(this),eval=b}catch(c){return this.trace("Error executing action {"+a+"} :"+c),!1}return!0};
-LGraphNode.prototype.captureInput=function(a){this.graph&&this.graph.canvas&&(a||this.graph.canvas.node_capturing_input==this)&&(this.graph.canvas.node_capturing_input=a?this:null,this.graph.debug&&console.log(this.name+": Capturing input "+(a?"ON":"OFF")))};LGraphNode.prototype.collapse=function(){this.flags.collapsed=this.flags.collapsed?!1:!0;this.setDirtyCanvas(!0,!0)};LGraphNode.prototype.pin=function(){this.flags.pinned=this.flags.pinned?!1:!0};
-LGraphNode.prototype.localToScreen=function(a,b){return[(a+this.pos[0])*this.graph.config.canvas_scale+this.graph.config.canvas_offset[0],(b+this.pos[1])*this.graph.config.canvas_scale+this.graph.config.canvas_offset[1]]};
-function LGraphCanvas(a,b){if(void 0===b)throw"No graph assigned";"undefined"!=typeof window&&(window.requestAnimFrame=function(){return window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||function(a){window.setTimeout(a,1E3/60)}}());if(this.graph=b)b.canvas=this;this.setCanvas(a);this.clear();this.startRendering()}LGraphCanvas.link_type_colors={number:"#AAC",node:"#DCA"};LGraphCanvas.link_width=2;
-LGraphCanvas.prototype.clear=function(){this.fps=this.render_time=this.last_draw_time=this.frame=0;this.selected_nodes={};this.connecting_node=this.node_capturing_input=this.node_over=this.node_dragged=null;this.highquality_render=!0;this.pause_rendering=!1;this.dirty_bgcanvas=this.dirty_canvas=this.render_shadows=!0;this.dirty_area=null;this.render_only_selected=!0;this.live_mode=!1;this.allow_dragnodes=this.allow_dragcanvas=this.show_info=!0;this.node_in_panel=null;this.last_mouse=[0,0];this.last_mouseclick=
-0;if(this.onClear)this.onClear()};LGraphCanvas.prototype.setGraph=function(a){if(this.graph!=a){this.clear();this.graph&&(this.graph.canvas=null);if(this.graph=a)this.graph.canvas=this;this.setDirty(!0,!0)}};LGraphCanvas.prototype.resize=function(a,b){if(this.canvas.width!=a||this.canvas.height!=b)this.canvas.width=a,this.canvas.height=b,this.bgcanvas.width=this.canvas.width,this.bgcanvas.height=this.canvas.height,this.setDirty(!0,!0)};
+LGraphNode.prototype.captureInput=function(a){if(this.graph&&this.graph.list_of_graphcanvas){var b=this.graph.list_of_graphcanvas,c;for(c in b){var d=b[c];if(a||d.node_capturing_input==this)d.node_capturing_input=a?this:null,this.graph.debug&&console.log(this.name+": Capturing input "+(a?"ON":"OFF"))}}};LGraphNode.prototype.collapse=function(){this.flags.collapsed=this.flags.collapsed?!1:!0;this.setDirtyCanvas(!0,!0)};
+LGraphNode.prototype.pin=function(a){this.flags.pinned=void 0===a?!this.flags.pinned:a};LGraphNode.prototype.localToScreen=function(a,b,c){return[(a+this.pos[0])*c.scale+c.offset[0],(b+this.pos[1])*c.scale+c.offset[1]]};function LGraphCanvas(a,b){"string"==typeof a&&(a=document.querySelector(a));if(!a)throw"no canvas found";b&&b.attachCanvas(this);this.setCanvas(a);this.clear();this.startRendering()}LGraphCanvas.link_type_colors={number:"#AAC",node:"#DCA"};
+LGraphCanvas.prototype.clear=function(){this.fps=this.render_time=this.last_draw_time=this.frame=0;this.scale=1;this.offset=[0,0];this.selected_nodes={};this.connecting_node=this.node_capturing_input=this.node_over=this.node_dragged=null;this.highquality_render=!0;this.editor_alpha=1;this.pause_rendering=!1;this.dirty_bgcanvas=this.dirty_canvas=this.render_shadows=!0;this.dirty_area=null;this.render_only_selected=!0;this.live_mode=!1;this.allow_dragnodes=this.allow_dragcanvas=this.show_info=!0;this.node_in_panel=
+null;this.last_mouse=[0,0];this.last_mouseclick=0;this.title_text_font="bold 14px Arial";this.inner_text_font="normal 12px Arial";this.render_connections_shadows=!1;this.render_connection_arrows=this.render_curved_connections=this.render_connections_border=!0;this.connections_width=4;if(this.onClear)this.onClear()};LGraphCanvas.prototype.setGraph=function(a){this.graph!=a&&(this.clear(),!a&&this.graph?this.graph.detachCanvas(this):(a.attachCanvas(this),this.setDirty(!0,!0)))};
LGraphCanvas.prototype.setCanvas=function(a){var b=this;"string"==typeof a&&(a=document.getElementById(a));if(null==a)throw"Error creating LiteGraph canvas: Canvas not found";if(a!=this.canvas){this.canvas=a;this.canvas.className+=" lgraphcanvas";this.canvas.data=this;this.bgcanvas=null;this.bgcanvas||(this.bgcanvas=document.createElement("canvas"),this.bgcanvas.width=this.canvas.width,this.bgcanvas.height=this.canvas.height);if(null==this.canvas.getContext)throw"This browser doesnt support Canvas";
this.ctx=this.canvas.getContext("2d");this.bgctx=this.bgcanvas.getContext("2d");this._mousemove_callback=this.processMouseMove.bind(this);this._mouseup_callback=this.processMouseUp.bind(this);this.canvas.addEventListener("mousedown",this.processMouseDown.bind(this));this.canvas.addEventListener("mousemove",this._mousemove_callback);this.canvas.addEventListener("contextmenu",function(a){a.preventDefault();return!1});this.canvas.addEventListener("mousewheel",this.processMouseWheel.bind(this),!1);this.canvas.addEventListener("DOMMouseScroll",
this.processMouseWheel.bind(this),!1);this.canvas.addEventListener("touchstart",this.touchHandler,!0);this.canvas.addEventListener("touchmove",this.touchHandler,!0);this.canvas.addEventListener("touchend",this.touchHandler,!0);this.canvas.addEventListener("touchcancel",this.touchHandler,!0);this.canvas.addEventListener("keydown",function(a){b.processKeyDown(a)});this.canvas.addEventListener("keyup",function(a){b.processKeyUp(a)})}};
-LGraphCanvas.prototype.setDirty=function(a,b){a&&(this.dirty_canvas=!0);b&&(this.dirty_bgcanvas=!0)};LGraphCanvas.prototype.startRendering=function(){function a(){this.pause_rendering||this.draw();this.is_rendering&&window.requestAnimFrame(a.bind(this))}this.is_rendering||(this.is_rendering=!0,a.call(this))};LGraphCanvas.prototype.stopRendering=function(){this.is_rendering=!1};
-LGraphCanvas.prototype.processMouseDown=function(a){if(this.graph){this.adjustMouseEvent(a);this.canvas.removeEventListener("mousemove",this._mousemove_callback);document.addEventListener("mousemove",this._mousemove_callback);document.addEventListener("mouseup",this._mouseup_callback);var b=this.graph.getNodeOnPos(a.canvasX,a.canvasY,this.visible_nodes);if(1==a.which){if(!a.shiftKey){var c=[],d;for(d in this.selected_nodes)this.selected_nodes[d]!=b&&c.push(this.selected_nodes[d]);for(d in c)this.processNodeDeselected(c[d])}c=
-!1;if(b){this.live_mode||b.flags.pinned||this.bringToFront(b);var e=!1;if(!this.connecting_node&&!b.flags.collapsed&&!this.live_mode){if(b.outputs){d=0;for(var f=b.outputs.length;d(new Date).getTime()-this.last_mouseclick&&this.selected_nodes[b.id]){if(b.onDblClick)b.onDblClick(a);this.processNodeDblClicked(b);d=!0}b.onMouseDown&&b.onMouseDown(a)?d=!0:this.live_mode&&(d=c=!0);d||(this.allow_dragnodes&&
-(this.node_dragged=b),this.selected_nodes[b.id]||this.processNodeSelected(b,a));this.dirty_canvas=!0}}else c=!0;c&&this.allow_dragcanvas&&(this.dragging_canvas=!0)}else 2!=a.which&&3==a.which&&this.processContextualMenu(b,a);this.last_mouse[0]=a.localX;this.last_mouse[1]=a.localY;this.last_mouseclick=(new Date).getTime();this.canvas_mouse=[a.canvasX,a.canvasY];this.graph.change();(!document.activeElement||"input"!=document.activeElement.nodeName.toLowerCase()&&"textarea"!=document.activeElement.nodeName.toLowerCase())&&
-a.preventDefault();a.stopPropagation();return!1}};
-LGraphCanvas.prototype.processMouseMove=function(a){if(this.graph){this.adjustMouseEvent(a);var b=[a.localX,a.localY],c=[b[0]-this.last_mouse[0],b[1]-this.last_mouse[1]];this.last_mouse=b;this.canvas_mouse=[a.canvasX,a.canvasY];if(this.dragging_canvas)this.graph.config.canvas_offset[0]+=c[0]/this.graph.config.canvas_scale,this.graph.config.canvas_offset[1]+=c[1]/this.graph.config.canvas_scale,this.dirty_bgcanvas=this.dirty_canvas=!0;else{this.connecting_node&&(this.dirty_canvas=!0);var b=this.graph.getNodeOnPos(a.canvasX,
-a.canvasY,this.visible_nodes),d;for(d in this.graph.nodes)if(this.graph.nodes[d].mouseOver&&b!=this.graph.nodes[d]){this.graph.nodes[d].mouseOver=!1;if(this.node_over&&this.node_over.onMouseLeave)this.node_over.onMouseLeave(a);this.node_over=null;this.dirty_canvas=!0}if(b){if(!b.mouseOver&&(b.mouseOver=!0,this.node_over=b,this.dirty_canvas=!0,b.onMouseEnter))b.onMouseEnter(a);if(b.onMouseMove)b.onMouseMove(a);if(this.connecting_node){var e=this._highlight_input||[0,0],f=this.isOverNodeInput(b,a.canvasX,
-a.canvasY,e);if(-1!=f&&b.inputs[f]){if(f=b.inputs[f].type,f==this.connecting_output.type||"*"==f||"*"==this.connecting_output.type)this._highlight_input=e}else this._highlight_input=null}isInsideRectangle(a.canvasX,a.canvasY,b.pos[0]+b.size[0]-5,b.pos[1]+b.size[1]-5,5,5)?this.canvas.style.cursor="se-resize":this.canvas.style.cursor=null}else this.canvas.style.cursor=null;if(this.node_capturing_input&&this.node_capturing_input!=b&&this.node_capturing_input.onMouseMove)this.node_capturing_input.onMouseMove(a);
-if(this.node_dragged&&!this.live_mode){for(d in this.selected_nodes)b=this.selected_nodes[d],b.pos[0]+=c[0]/this.graph.config.canvas_scale,b.pos[1]+=c[1]/this.graph.config.canvas_scale,b.pos[0]=Math.round(b.pos[0]),b.pos[1]=Math.round(b.pos[1]);this.dirty_bgcanvas=this.dirty_canvas=!0}this.resizing_node&&!this.live_mode&&(this.resizing_node.size[0]+=c[0]/this.graph.config.canvas_scale,this.resizing_node.size[1]+=c[1]/this.graph.config.canvas_scale,c=Math.max(this.resizing_node.inputs?this.resizing_node.inputs.length:
-0,this.resizing_node.outputs?this.resizing_node.outputs.length:0),this.resizing_node.size[1]window.performance.now()-this.last_mouseclick&&this.selected_nodes[c.id]){if(c.onDblClick)c.onDblClick(a);this.processNodeDblClicked(c);e=!0}c.onMouseDown&&c.onMouseDown(a)?
+e=!0:this.live_mode&&(e=d=!0);e||(this.allow_dragnodes&&(this.node_dragged=c),this.selected_nodes[c.id]||this.processNodeSelected(c,a));this.dirty_canvas=!0}}else d=!0;d&&this.allow_dragcanvas&&(this.dragging_canvas=!0)}else 2!=a.which&&3==a.which&&this.processContextualMenu(c,a);this.last_mouse[0]=a.localX;this.last_mouse[1]=a.localY;this.last_mouseclick=window.performance.now();this.canvas_mouse=[a.canvasX,a.canvasY];this.graph.change();(!b.document.activeElement||"input"!=b.document.activeElement.nodeName.toLowerCase()&&
+"textarea"!=b.document.activeElement.nodeName.toLowerCase())&&a.preventDefault();a.stopPropagation();return!1}};
+LGraphCanvas.prototype.processMouseMove=function(a){if(this.graph){this.adjustMouseEvent(a);var b=[a.localX,a.localY],c=[b[0]-this.last_mouse[0],b[1]-this.last_mouse[1]];this.last_mouse=b;this.canvas_mouse=[a.canvasX,a.canvasY];if(this.dragging_canvas)this.offset[0]+=c[0]/this.scale,this.offset[1]+=c[1]/this.scale,this.dirty_bgcanvas=this.dirty_canvas=!0;else{this.connecting_node&&(this.dirty_canvas=!0);var b=this.graph.getNodeOnPos(a.canvasX,a.canvasY,this.visible_nodes),d;for(d in this.graph._nodes)if(this.graph._nodes[d].mouseOver&&
+b!=this.graph._nodes[d]){this.graph._nodes[d].mouseOver=!1;if(this.node_over&&this.node_over.onMouseLeave)this.node_over.onMouseLeave(a);this.node_over=null;this.dirty_canvas=!0}if(b){if(!b.mouseOver&&(b.mouseOver=!0,this.node_over=b,this.dirty_canvas=!0,b.onMouseEnter))b.onMouseEnter(a);if(b.onMouseMove)b.onMouseMove(a);if(this.connecting_node){var e=this._highlight_input||[0,0],f=this.isOverNodeInput(b,a.canvasX,a.canvasY,e);if(-1!=f&&b.inputs[f]){if(f=b.inputs[f].type,f==this.connecting_output.type||
+"*"==f||"*"==this.connecting_output.type)this._highlight_input=e}else this._highlight_input=null}isInsideRectangle(a.canvasX,a.canvasY,b.pos[0]+b.size[0]-5,b.pos[1]+b.size[1]-5,5,5)?this.canvas.style.cursor="se-resize":this.canvas.style.cursor=null}else this.canvas.style.cursor=null;if(this.node_capturing_input&&this.node_capturing_input!=b&&this.node_capturing_input.onMouseMove)this.node_capturing_input.onMouseMove(a);if(this.node_dragged&&!this.live_mode){for(d in this.selected_nodes)b=this.selected_nodes[d],
+b.pos[0]+=c[0]/this.scale,b.pos[1]+=c[1]/this.scale,b.pos[0]=Math.round(b.pos[0]),b.pos[1]=Math.round(b.pos[1]);this.dirty_bgcanvas=this.dirty_canvas=!0}this.resizing_node&&!this.live_mode&&(this.resizing_node.size[0]+=c[0]/this.scale,this.resizing_node.size[1]+=c[1]/this.scale,c=Math.max(this.resizing_node.inputs?this.resizing_node.inputs.length:0,this.resizing_node.outputs?this.resizing_node.outputs.length:0),this.resizing_node.size[1]b&&(c*=1/1.1);this.setZoom(c,[a.localX,a.localY]);this.graph.change();a.preventDefault();return!1}};
+LGraphCanvas.prototype.processKeyUp=function(a){if(this.graph){if(this.selected_nodes)for(var b in this.selected_nodes)if(this.selected_nodes[b].onKeyUp)this.selected_nodes[b].onKeyUp(a);this.graph.change()}};LGraphCanvas.prototype.processMouseWheel=function(a){if(this.graph&&this.allow_dragcanvas){var b=null!=a.wheelDeltaY?a.wheelDeltaY:-60*a.detail;this.adjustMouseEvent(a);var c=this.scale;0b&&(c*=1/1.1);this.setZoom(c,[a.localX,a.localY]);this.graph.change();a.preventDefault();return!1}};
LGraphCanvas.prototype.processNodeSelected=function(a,b){a.selected=!0;if(a.onSelected)a.onSelected();b&&b.shiftKey||(this.selected_nodes={});this.selected_nodes[a.id]=a;this.dirty_canvas=!0;if(this.onNodeSelected)this.onNodeSelected(a)};LGraphCanvas.prototype.processNodeDeselected=function(a){a.selected=!1;if(a.onDeselected)a.onDeselected();delete this.selected_nodes[a.id];if(this.onNodeDeselected)this.onNodeDeselected();this.dirty_canvas=!0};
LGraphCanvas.prototype.processNodeDblClicked=function(a){if(this.onShowNodePanel)this.onShowNodePanel(a);if(this.onNodeDblClicked)this.onNodeDblClicked(a);this.setDirty(!0)};LGraphCanvas.prototype.selectNode=function(a){this.deselectAllNodes();if(a){if(!a.selected&&a.onSelected)a.onSelected();a.selected=!0;this.selected_nodes[a.id]=a;this.setDirty(!0)}};
-LGraphCanvas.prototype.selectAllNodes=function(){for(var a in this.graph.nodes){var b=this.graph.nodes[a];if(!b.selected&&b.onSelected)b.onSelected();b.selected=!0;this.selected_nodes[this.graph.nodes[a].id]=b}this.setDirty(!0)};LGraphCanvas.prototype.deselectAllNodes=function(){for(var a in this.selected_nodes){var b=this.selected_nodes;if(b.onDeselected)b.onDeselected();b.selected=!1}this.selected_nodes={};this.setDirty(!0)};
-LGraphCanvas.prototype.deleteSelectedNodes=function(){for(var a in this.selected_nodes)this.graph.remove(this.selected_nodes[a]);this.selected_nodes={};this.setDirty(!0)};LGraphCanvas.prototype.centerOnNode=function(a){this.graph.config.canvas_offset[0]=-a.pos[0]-0.5*a.size[0]+0.5*this.canvas.width/this.graph.config.canvas_scale;this.graph.config.canvas_offset[1]=-a.pos[1]-0.5*a.size[1]+0.5*this.canvas.height/this.graph.config.canvas_scale;this.setDirty(!0,!0)};
-LGraphCanvas.prototype.adjustMouseEvent=function(a){var b=this.canvas.getBoundingClientRect();a.localX=a.pageX-b.left;a.localY=a.pageY-b.top;a.canvasX=a.localX/this.graph.config.canvas_scale-this.graph.config.canvas_offset[0];a.canvasY=a.localY/this.graph.config.canvas_scale-this.graph.config.canvas_offset[1]};
-LGraphCanvas.prototype.setZoom=function(a,b){b||(b=[0.5*this.canvas.width,0.5*this.canvas.height]);var c=this.convertOffsetToCanvas(b);this.graph.config.canvas_scale=a;4this.graph.config.canvas_scale&&(this.graph.config.canvas_scale=0.1);var d=this.convertOffsetToCanvas(b),c=[d[0]-c[0],d[1]-c[1]];this.graph.config.canvas_offset[0]+=c[0];this.graph.config.canvas_offset[1]+=c[1];this.dirty_bgcanvas=this.dirty_canvas=!0};
-LGraphCanvas.prototype.convertOffsetToCanvas=function(a){return[a[0]/this.graph.config.canvas_scale-this.graph.config.canvas_offset[0],a[1]/this.graph.config.canvas_scale-this.graph.config.canvas_offset[1]]};LGraphCanvas.prototype.convertCanvasToOffset=function(a){return[(a[0]+this.graph.config.canvas_offset[0])*this.graph.config.canvas_scale,(a[1]+this.graph.config.canvas_offset[1])*this.graph.config.canvas_scale]};
-LGraphCanvas.prototype.convertEventToCanvas=function(a){var b=this.canvas.getClientRects()[0];return this.convertOffsetToCanvas([a.pageX-b.left,a.pageY-b.top])};LGraphCanvas.prototype.bringToFront=function(a){var b=this.graph.nodes.indexOf(a);-1!=b&&(this.graph.nodes.splice(b,1),this.graph.nodes.push(a))};LGraphCanvas.prototype.sendToBack=function(a){var b=this.graph.nodes.indexOf(a);-1!=b&&(this.graph.nodes.splice(b,1),this.graph.nodes.unshift(a))};
-LGraphCanvas.prototype.computeVisibleNodes=function(){var a=[],b;for(b in this.graph.nodes){var c=this.graph.nodes[b];(!this.live_mode||c.onDrawBackground||c.onDrawForeground)&&overlapBounding(this.visible_area,c.getBounding())&&a.push(c)}return a};
-LGraphCanvas.prototype.draw=function(a,b){var c=(new Date).getTime();this.render_time=0.001*(c-this.last_draw_time);this.last_draw_time=c;if(this.graph){var c=[-this.graph.config.canvas_offset[0],-this.graph.config.canvas_offset[1]],d=[c[0]+this.canvas.width/this.graph.config.canvas_scale,c[1]+this.canvas.height/this.graph.config.canvas_scale];this.visible_area=new Float32Array([c[0],c[1],d[0],d[1]])}(this.dirty_bgcanvas||b)&&this.drawBgcanvas();(this.dirty_canvas||a)&&this.drawFrontCanvas();this.fps=
-this.render_time?1/this.render_time:0;this.frame+=1};
+LGraphCanvas.prototype.selectAllNodes=function(){for(var a in this.graph._nodes){var b=this.graph._nodes[a];if(!b.selected&&b.onSelected)b.onSelected();b.selected=!0;this.selected_nodes[this.graph._nodes[a].id]=b}this.setDirty(!0)};LGraphCanvas.prototype.deselectAllNodes=function(){for(var a in this.selected_nodes){var b=this.selected_nodes;if(b.onDeselected)b.onDeselected();b.selected=!1}this.selected_nodes={};this.setDirty(!0)};
+LGraphCanvas.prototype.deleteSelectedNodes=function(){for(var a in this.selected_nodes)this.graph.remove(this.selected_nodes[a]);this.selected_nodes={};this.setDirty(!0)};LGraphCanvas.prototype.centerOnNode=function(a){this.offset[0]=-a.pos[0]-0.5*a.size[0]+0.5*this.canvas.width/this.scale;this.offset[1]=-a.pos[1]-0.5*a.size[1]+0.5*this.canvas.height/this.scale;this.setDirty(!0,!0)};
+LGraphCanvas.prototype.adjustMouseEvent=function(a){var b=this.canvas.getBoundingClientRect();a.localX=a.pageX-b.left;a.localY=a.pageY-b.top;a.canvasX=a.localX/this.scale-this.offset[0];a.canvasY=a.localY/this.scale-this.offset[1]};
+LGraphCanvas.prototype.setZoom=function(a,b){b||(b=[0.5*this.canvas.width,0.5*this.canvas.height]);var c=this.convertOffsetToCanvas(b);this.scale=a;4this.scale&&(this.scale=0.1);var d=this.convertOffsetToCanvas(b),c=[d[0]-c[0],d[1]-c[1]];this.offset[0]+=c[0];this.offset[1]+=c[1];this.dirty_bgcanvas=this.dirty_canvas=!0};LGraphCanvas.prototype.convertOffsetToCanvas=function(a){return[a[0]/this.scale-this.offset[0],a[1]/this.scale-this.offset[1]]};
+LGraphCanvas.prototype.convertCanvasToOffset=function(a){return[(a[0]+this.offset[0])*this.scale,(a[1]+this.offset[1])*this.scale]};LGraphCanvas.prototype.convertEventToCanvas=function(a){var b=this.canvas.getClientRects()[0];return this.convertOffsetToCanvas([a.pageX-b.left,a.pageY-b.top])};LGraphCanvas.prototype.bringToFront=function(a){var b=this.graph._nodes.indexOf(a);-1!=b&&(this.graph._nodes.splice(b,1),this.graph._nodes.push(a))};
+LGraphCanvas.prototype.sendToBack=function(a){var b=this.graph._nodes.indexOf(a);-1!=b&&(this.graph._nodes.splice(b,1),this.graph._nodes.unshift(a))};LGraphCanvas.prototype.computeVisibleNodes=function(){var a=[],b;for(b in this.graph._nodes){var c=this.graph._nodes[b];(!this.live_mode||c.onDrawBackground||c.onDrawForeground)&&overlapBounding(this.visible_area,c.getBounding())&&a.push(c)}return a};
+LGraphCanvas.prototype.draw=function(a,b){var c=window.performance.now();this.render_time=0.001*(c-this.last_draw_time);this.last_draw_time=c;if(this.graph){var c=[-this.offset[0],-this.offset[1]],d=[c[0]+this.canvas.width/this.scale,c[1]+this.canvas.height/this.scale];this.visible_area=new Float32Array([c[0],c[1],d[0],d[1]])}(this.dirty_bgcanvas||b)&&this.drawBgcanvas();(this.dirty_canvas||a)&&this.drawFrontCanvas();this.fps=this.render_time?1/this.render_time:0;this.frame+=1};
LGraphCanvas.prototype.drawFrontCanvas=function(){var a=this.ctx,b=this.canvas;a.restore();a.setTransform(1,0,0,1,0,0);this.dirty_area&&(a.save(),a.beginPath(),a.rect(this.dirty_area[0],this.dirty_area[1],this.dirty_area[2],this.dirty_area[3]),a.clip());a.clearRect(0,0,b.width,b.height);a.drawImage(this.bgcanvas,0,0);this.show_info&&(a.font="10px Arial",a.fillStyle="#888",this.graph?(a.fillText("T: "+this.graph.globaltime.toFixed(2)+"s",5,13),a.fillText("I: "+this.graph.iteration,5,26),a.fillText("F: "+
-this.frame,5,39),a.fillText("FPS:"+this.fps.toFixed(2),5,52)):a.fillText("No graph selected",5,13));if(this.graph){a.save();a.scale(this.graph.config.canvas_scale,this.graph.config.canvas_scale);a.translate(this.graph.config.canvas_offset[0],this.graph.config.canvas_offset[1]);this.visible_nodes=b=this.computeVisibleNodes();for(var c in b){var d=b[c];a.save();a.translate(d.pos[0],d.pos[1]);this.drawNode(d,a);a.restore()}this.graph.config.links_ontop&&(this.live_mode||this.drawConnections(a));null!=
-this.connecting_pos&&(a.lineWidth=LGraphCanvas.link_width,a.fillStyle="node"==this.connecting_output.type?"#F85":"#AFA",a.strokeStyle=a.fillStyle,this.renderLink(a,this.connecting_pos,[this.canvas_mouse[0],this.canvas_mouse[1]]),a.beginPath(),a.arc(this.connecting_pos[0],this.connecting_pos[1],4,0,2*Math.PI),a.fill(),a.fillStyle="#ffcc00",this._highlight_input&&(a.beginPath(),a.arc(this._highlight_input[0],this._highlight_input[1],6,0,2*Math.PI),a.fill()));a.restore()}this.dirty_area&&a.restore();
-this.dirty_canvas=!1};
-LGraphCanvas.prototype.drawBgcanvas=function(){var a=this.bgcanvas,b=this.bgctx;a.width=a.width;b.restore();b.setTransform(1,0,0,1,0,0);if(this.graph){b.save();b.scale(this.graph.config.canvas_scale,this.graph.config.canvas_scale);b.translate(this.graph.config.canvas_offset[0],this.graph.config.canvas_offset[1]);if(this.background_image&&0.5b[1]?0:Math.PI;a.save();a.translate(d[0],d[1]);a.rotate(f);a.beginPath();a.moveTo(-5,-5);a.lineTo(0,5);a.lineTo(5,-5);a.fill();a.restore()}}else a.beginPath(),a.moveTo(b[0],b[1]),a.lineTo(c[0],c[1]),a.stroke()};
+LGraphCanvas.prototype.computeConnectionPoint=function(a,b,c){var d=distance(a,b),e=[a[0]+0.25*d,a[1]],d=[b[0]-0.25*d,b[1]],f=(1-c)*(1-c)*(1-c),g=3*(1-c)*(1-c)*c,h=3*(1-c)*c*c;c*=c*c;return[f*a[0]+g*e[0]+h*d[0]+c*b[0],f*a[1]+g*e[1]+h*d[1]+c*b[1]]};
+LGraphCanvas.prototype.resize=function(a,b){if(!a&&!b){var c=this.canvas.parentNode;a=c.offsetWidth;b=c.offsetHeight}if(this.canvas.width!=a||this.canvas.height!=b)this.canvas.width=a,this.canvas.height=b,this.bgcanvas.width=this.canvas.width,this.bgcanvas.height=this.canvas.height,this.setDirty(!0,!0)};
+LGraphCanvas.prototype.switchLiveMode=function(a){if(a){var b=this,c=this.live_mode?1.1:0.9;this.live_mode&&(this.live_mode=!1,this.editor_alpha=0.1);var d=setInterval(function(){b.editor_alpha*=c;b.dirty_canvas=!0;b.dirty_bgcanvas=!0;1>c&&0.01>b.editor_alpha&&(clearInterval(d),1>c&&(b.live_mode=!0));1"+e+""})}LiteGraph.createContextualMenu(d,{event:b,callback:function(b){a&&(b=LGraphCanvas.node_colors[b.value])&&(a.color=b.color,a.bgcolor=b.bgcolor,a.graph.canvas.setDirty(!0))},from:c});return!1};
LGraphCanvas.onMenuNodeShapes=function(a,b){LiteGraph.createContextualMenu(["box","round"],{event:b,callback:function(b){a&&(a.shape=b,a.graph.canvas.setDirty(!0))}});return!1};LGraphCanvas.onMenuNodeRemove=function(a){!1!=a.removable&&(a.graph.remove(a),a.graph.canvas.setDirty(!0,!0))};LGraphCanvas.onMenuNodeClone=function(a){if(!1!=a.clonable){var b=a.clone();b&&(b.pos=[a.pos[0]+5,a.pos[1]+5],a.graph.add(b),a.graph.canvas.setDirty(!0,!0))}};
LGraphCanvas.node_colors={red:{color:"#FAA",bgcolor:"#A44"},green:{color:"#AFA",bgcolor:"#4A4"},blue:{color:"#AAF",bgcolor:"#44A"},white:{color:"#FFF",bgcolor:"#AAA"}};LGraphCanvas.prototype.getCanvasMenuOptions=function(){return[{content:"Add Node",is_menu:!0,callback:LGraphCanvas.onMenuAdd}]};
-LGraphCanvas.prototype.getNodeMenuOptions=function(a){var b=[{content:"Inputs",is_menu:!0,disabled:!0,callback:LGraphCanvas.onMenuNodeInputs},{content:"Outputs",is_menu:!0,disabled:!0,callback:LGraphCanvas.onMenuNodeOutputs},null,{content:"Collapse",callback:LGraphCanvas.onMenuNodeCollapse},{content:"Colors",is_menu:!0,callback:LGraphCanvas.onMenuNodeColors},{content:"Shapes",is_menu:!0,callback:LGraphCanvas.onMenuNodeShapes},null,{content:"Clone",callback:LGraphCanvas.onMenuNodeClone},null,{content:"Remove",
-callback:LGraphCanvas.onMenuNodeRemove}];!1==a.clonable&&(b[7].disabled=!0);!1==a.removable&&(b[9].disabled=!0);a.onGetInputs&&a.onGetInputs().length&&(b[0].disabled=!1);a.onGetOutputs&&a.onGetOutputs().length&&(b[1].disabled=!1);return b};LGraphCanvas.prototype.processContextualMenu=function(a,b){var c=this,d=LiteGraph.createContextualMenu(a?this.getNodeMenuOptions(a):this.getCanvasMenuOptions(),{event:b,callback:function(e,f){if(e&&e.callback)return e.callback(a,f,d,c,b)}})};
+LGraphCanvas.prototype.getNodeMenuOptions=function(a){var b=[{content:"Inputs",is_menu:!0,disabled:!0,callback:LGraphCanvas.onMenuNodeInputs},{content:"Outputs",is_menu:!0,disabled:!0,callback:LGraphCanvas.onMenuNodeOutputs},null,{content:"Collapse",callback:LGraphCanvas.onMenuNodeCollapse},{content:"Pin",callback:LGraphCanvas.onMenuNodePin},{content:"Colors",is_menu:!0,callback:LGraphCanvas.onMenuNodeColors},{content:"Shapes",is_menu:!0,callback:LGraphCanvas.onMenuNodeShapes},null,{content:"Clone",
+callback:LGraphCanvas.onMenuNodeClone},null,{content:"Remove",callback:LGraphCanvas.onMenuNodeRemove}];!1==a.clonable&&(b[7].disabled=!0);!1==a.removable&&(b[9].disabled=!0);a.onGetInputs&&a.onGetInputs().length&&(b[0].disabled=!1);a.onGetOutputs&&a.onGetOutputs().length&&(b[1].disabled=!1);return b};
+LGraphCanvas.prototype.processContextualMenu=function(a,b){var c=this,d=this.getCanvasWindow(),e=LiteGraph.createContextualMenu(a?this.getNodeMenuOptions(a):this.getCanvasMenuOptions(),{event:b,callback:function(d,g){if(d&&d.callback)return d.callback(a,g,e,c,b)}},d)};
CanvasRenderingContext2D.prototype.roundRect=function(a,b,c,d,e,f){void 0===e&&(e=5);void 0===f&&(f=e);this.beginPath();this.moveTo(a+e,b);this.lineTo(a+c-e,b);this.quadraticCurveTo(a+c,b,a+c,b+e);this.lineTo(a+c,b+d-f);this.quadraticCurveTo(a+c,b+d,a+c-f,b+d);this.lineTo(a+f,b+d);this.quadraticCurveTo(a,b+d,a,b+d-f);this.lineTo(a,b+e);this.quadraticCurveTo(a,b,a+e,b)};function compareObjects(a,b){for(var c in a)if(a[c]!=b[c])return!1;return!0}
function distance(a,b){return Math.sqrt((b[0]-a[0])*(b[0]-a[0])+(b[1]-a[1])*(b[1]-a[1]))}function colorToString(a){return"rgba("+Math.round(255*a[0]).toFixed()+","+Math.round(255*a[1]).toFixed()+","+Math.round(255*a[2]).toFixed()+","+(4==a.length?a[3].toFixed(2):"1.0")+")"}function isInsideRectangle(a,b,c,d,e,f){return ca&&db?!0:!1}function growBounding(a,b,c){ba[2]&&(a[2]=b);c a[3]&&(a[3]=c)}
function isInsideBounding(a,b){return a[0]b[1][0]||a[1]>b[1][1]?!1:!0}function overlapBounding(a,b){return a[0]>b[2]||a[1]>b[3]||a[2]f;f+=2)d="0123456789ABCDEF".indexOf(a.charAt(f)),e="0123456789ABCDEF".indexOf(a.charAt(f+1)),b[c]=16*d+e,c++;return b}
function num2hex(a){for(var b="#",c,d,e=0;3>e;e++)c=a[e]/16,d=a[e]%16,b+="0123456789ABCDEF".charAt(c)+"0123456789ABCDEF".charAt(d);return b}
-LiteGraph.createContextualMenu=function(a,b){function c(a){var c=!0;b.callback&&(a=b.callback.call(d,this.data,a),void 0!=a&&(c=a));c&&LiteGraph.closeAllContextualMenus()}this.options=b=b||{};b.from||LiteGraph.closeAllContextualMenus();var d=document.createElement("div");d.className="litecontextualmenu litemenubar-panel";this.root=d;var e=d.style;e.minWidth="100px";e.minHeight="20px";e.position="fixed";e.top="100px";e.left="100px";e.color="#AAF";e.padding="2px";e.borderBottom="2px solid #AAF";e.backgroundColor=
-"#444";d.addEventListener("contextmenu",function(a){a.preventDefault();return!1});for(var f in a){var e=a[f],g=document.createElement("div");g.className="litemenu-entry";null==e?g.className="litemenu-entry separator":(e.is_menu&&(g.className+=" submenu"),e.disabled&&(g.className+=" disabled"),g.style.cursor="pointer",g.dataset.value="string"==typeof e?e:e.value,g.data=e,g.innerHTML="string"==typeof e?a.constructor==Array?a[f]:f:e.content?e.content:f,g.addEventListener("click",c));d.appendChild(g)}d.addEventListener("mouseover",
-function(a){this.mouse_inside=!0});d.addEventListener("mouseout",function(a){for(a=a.toElement;a!=this&&a!=document;)a=a.parentNode;a!=this&&(this.mouse_inside=!1,this.block_close||this.closeMenu())});document.body.appendChild(d);f=d.getClientRects()[0];b.from&&(b.from.block_close=!0);var h=b.left||0,e=b.top||0;b.event&&(h=b.event.pageX-10,e=b.event.pageY-10,b.left&&(h=b.left),g=document.body.getClientRects()[0],b.from&&(h=b.from.getClientRects()[0],h=h.left+h.width),h>g.width-f.width-10&&(h=g.width-
-f.width-10),e>g.height-f.height-10&&(e=g.height-f.height-10));d.style.left=h+"px";d.style.top=e+"px";d.closeMenu=function(){b.from&&(b.from.block_close=!1,b.from.mouse_inside||b.from.closeMenu());this.parentNode&&document.body.removeChild(this)};return d};LiteGraph.closeAllContextualMenus=function(){var a=document.querySelectorAll(".litecontextualmenu");if(a.length){for(var b=[],c=0;cf.width-a.width-10&&(h=f.width-a.width-10),g>f.height-a.height-10&&(g=f.height-a.height-10));e.style.left=h+"px";e.style.top=g+"px";e.closeMenu=function(){b.from&&(b.from.block_close=!1,b.from.mouse_inside||b.from.closeMenu());this.parentNode&&c.document.body.removeChild(this)};return e};LiteGraph.closeAllContextualMenus=function(){var a=document.querySelectorAll(".litecontextualmenu");if(a.length){for(var b=[],c=0;c
null==b&&(b=this.properties.axis);a=quat.setAxisAngle(quat.create(),b,0.0174532925*a);this.setOutputData(0,a)}}),LiteGraph.registerNodeType("math3d/rotate_vec3",{title:"Rot. Vec3",desc:"rotate a point",inputs:[["vec3","vec3"],["quat","quat"]],outputs:[["result","vec3"]],properties:{vec:[0,0,1]},onExecute:function(){var a=this.getInputData(0);null==a&&(a=this.properties.vec);var b=this.getInputData(1);null==b?this.setOutputData(a):this.setOutputData(0,vec3.transformQuat(vec3.create(),a,b))}}),LiteGraph.registerNodeType("math3d/mult-quat",
{title:"Mult. Quat",desc:"rotate quaternion",inputs:[["A","quat"],["B","quat"]],outputs:[["A*B","quat"]],onExecute:function(){var a=this.getInputData(0);if(null!=a){var b=this.getInputData(1);null!=b&&(a=quat.multiply(quat.create(),a,b),this.setOutputData(0,a))}}}));
LiteGraph.registerNodeType("widget/knob",{title:"Knob",desc:"Circular controller",size:[64,84],outputs:[["","number"]],properties:{min:0,max:1,value:0.5,wcolor:"#7AF",size:50},widgets:[{name:"increase",text:"+",type:"minibutton"},{name:"decrease",text:"-",type:"minibutton"}],onInit:function(){this.value=(this.properties.value-this.properties.min)/(this.properties.max-this.properties.min);this.imgbg=this.loadImage("imgs/knob_bg.png");this.imgfg=this.loadImage("imgs/knob_fg.png")},onDrawImageKnob:function(a){if(this.imgfg&&
-this.imgfg.width){var b=0.5*this.imgbg.width,c=this.size[0]/this.imgfg.width;a.save();a.translate(0,20);a.scale(c,c);a.drawImage(this.imgbg,0,0);a.translate(b,b);a.rotate(12*this.value*Math.PI/8+10*Math.PI/8);a.translate(-b,-b);a.drawImage(this.imgfg,0,0);a.restore();a.font="bold 16px Criticized,Tahoma";a.fillStyle="rgba(100,100,100,0.8)";a.textAlign="center";a.fillText(this.name.toUpperCase(),0.5*this.size[0],18);a.textAlign="left"}},onDrawVectorKnob:function(a){if(this.imgfg&&this.imgfg.width){a.lineWidth=
+this.imgfg.width){var b=0.5*this.imgbg.width,c=this.size[0]/this.imgfg.width;a.save();a.translate(0,20);a.scale(c,c);a.drawImage(this.imgbg,0,0);a.translate(b,b);a.rotate(2*this.value*Math.PI*6/8+10*Math.PI/8);a.translate(-b,-b);a.drawImage(this.imgfg,0,0);a.restore();a.font="bold 16px Criticized,Tahoma";a.fillStyle="rgba(100,100,100,0.8)";a.textAlign="center";a.fillText(this.name.toUpperCase(),0.5*this.size[0],18);a.textAlign="left"}},onDrawVectorKnob:function(a){if(this.imgfg&&this.imgfg.width){a.lineWidth=
1;a.strokeStyle=this.mouseOver?"#FFF":"#AAA";a.fillStyle="#000";a.beginPath();a.arc(0.5*this.size[0],0.5*this.size[1]+10,0.5*this.properties.size,0,2*Math.PI,!0);a.stroke();0a.canvasY-this.pos[1]||distance([a.canvasX,
+var b=this.properties.value;"number"==typeof b&&(b=b.toFixed(2));a.fillText(b,0.5*this.size[0],0.65*this.size[1]);a.textAlign="left"}},onDrawForeground:function(a){this.onDrawImageKnob(a)},onExecute:function(){this.setOutputData(0,this.properties.value);this.boxcolor=colorToString([this.value,this.value,this.value])},onMouseDown:function(a){if(this.imgfg&&this.imgfg.width){this.center=[0.5*this.size[0],0.5*this.size[1]+20];this.radius=0.5*this.size[0];if(20>a.canvasY-this.pos[1]||distance([a.canvasX,
a.canvasY],[this.pos[0]+this.center[0],this.pos[1]+this.center[1]])>this.radius)return!1;this.oldmouse=[a.canvasX-this.pos[0],a.canvasY-this.pos[1]];this.captureInput(!0);return!0}},onMouseMove:function(a){if(this.oldmouse){a=[a.canvasX-this.pos[0],a.canvasY-this.pos[1]];var b=this.value,b=b-0.01*(a[1]-this.oldmouse[1]);1b&&(b=0);this.value=b;this.properties.value=this.properties.min+(this.properties.max-this.properties.min)*this.value;this.oldmouse=a;this.setDirtyCanvas(!0)}},onMouseUp:function(a){this.oldmouse&&
(this.oldmouse=null,this.captureInput(!1))},onMouseLeave:function(a){},onWidget:function(a,b){if("increase"==b.name)this.onPropertyChange("size",this.properties.size+10);else if("decrease"==b.name)this.onPropertyChange("size",this.properties.size-10)},onPropertyChange:function(a,b){if("wcolor"==a)this.properties[a]=b;else if("size"==a)b=parseInt(b),this.properties[a]=b,this.size=[b+4,b+24],this.setDirtyCanvas(!0,!0);else if("min"==a||"max"==a||"value"==a)this.properties[a]=parseFloat(b);else return!1;
return!0}});
LiteGraph.registerNodeType("widget/hslider",{title:"H.Slider",desc:"Linear slider controller",size:[160,26],outputs:[["","number"]],properties:{wcolor:"#7AF",min:0,max:1,value:0.5},onInit:function(){this.value=0.5;this.imgfg=this.loadImage("imgs/slider_fg.png")},onDrawVectorial:function(a){this.imgfg&&this.imgfg.width&&(a.lineWidth=1,a.strokeStyle=this.mouseOver?"#FFF":"#AAA",a.fillStyle="#000",a.beginPath(),a.rect(2,0,this.size[0]-4,20),a.stroke(),a.fillStyle=this.properties.wcolor,a.beginPath(),a.rect(2+
-(this.size[0]-4-20)*this.value,0,20,20),a.fill())},onDrawImage:function(a){this.imgfg&&this.imgfg.width&&(a.lineWidth=1,a.fillStyle="#000",a.fillRect(2,9,this.size[0]-4,2),a.strokeStyle="#333",a.beginPath(),a.moveTo(2,9),a.lineTo(this.size[0]-4,9),a.stroke(),a.strokeStyle="#AAA",a.beginPath(),a.moveTo(2,11),a.lineTo(this.size[0]-4,11),a.stroke(),a.drawImage(this.imgfg,2+(this.size[0]-4)*this.value-0.5*this.imgfg.width,0.5*-this.imgfg.height+10))},onDrawBackground:function(a){this.onDrawImage(a)},
+(this.size[0]-4-20)*this.value,0,20,20),a.fill())},onDrawImage:function(a){this.imgfg&&this.imgfg.width&&(a.lineWidth=1,a.fillStyle="#000",a.fillRect(2,9,this.size[0]-4,2),a.strokeStyle="#333",a.beginPath(),a.moveTo(2,9),a.lineTo(this.size[0]-4,9),a.stroke(),a.strokeStyle="#AAA",a.beginPath(),a.moveTo(2,11),a.lineTo(this.size[0]-4,11),a.stroke(),a.drawImage(this.imgfg,2+(this.size[0]-4)*this.value-0.5*this.imgfg.width,0.5*-this.imgfg.height+10))},onDrawForeground:function(a){this.onDrawImage(a)},
onExecute:function(){this.properties.value=this.properties.min+(this.properties.max-this.properties.min)*this.value;this.setOutputData(0,this.properties.value);this.boxcolor=colorToString([this.value,this.value,this.value])},onMouseDown:function(a){if(0>a.canvasY-this.pos[1])return!1;this.oldmouse=[a.canvasX-this.pos[0],a.canvasY-this.pos[1]];this.captureInput(!0);return!0},onMouseMove:function(a){if(this.oldmouse){a=[a.canvasX-this.pos[0],a.canvasY-this.pos[1]];var b=this.value,b=b+(a[0]-this.oldmouse[0])/
this.size[0];1b&&(b=0);this.value=b;this.oldmouse=a;this.setDirtyCanvas(!0)}},onMouseUp:function(a){this.oldmouse=null;this.captureInput(!1)},onMouseLeave:function(a){},onPropertyChange:function(a,b){if("wcolor"==a)this.properties[a]=b;else return!1;return!0}});
LiteGraph.registerNodeType("widget/kpad",{title:"KPad",desc:"bidimensional slider",size:[200,200],outputs:[["x","number"],["y","number"]],properties:{x:0,y:0,borderColor:"#333",bgcolorTop:"#444",bgcolorBottom:"#000",shadowSize:1,borderRadius:2},createGradient:function(a){this.lineargradient=a.createLinearGradient(0,0,0,this.size[1]);this.lineargradient.addColorStop(0,this.properties.bgcolorTop);this.lineargradient.addColorStop(1,this.properties.bgcolorBottom)},onDrawBackground:function(a){this.lineargradient||
@@ -156,16 +155,16 @@ this.properties.y=1:0>this.properties.y&&(this.properties.y=0),this.oldmouse=a,t
LiteGraph.registerNodeType("widget/button",{title:"Button",desc:"A send command button",widgets:[{name:"test",text:"Test Button",type:"button"}],size:[100,40],properties:{text:"clickme",command:"",color:"#7AF",bgcolorTop:"#f0f0f0",bgcolorBottom:"#e0e0e0",fontsize:"16"},outputs:[["M","module"]],createGradient:function(a){this.lineargradient=a.createLinearGradient(0,0,0,this.size[1]);this.lineargradient.addColorStop(0,this.properties.bgcolorTop);this.lineargradient.addColorStop(1,this.properties.bgcolorBottom)},
drawVectorShape:function(a){a.fillStyle=this.mouseOver?this.properties.color:"#AAA";this.clicking&&(a.fillStyle="#FFF");a.strokeStyle="#AAA";a.roundRect(5,5,this.size[0]-10,this.size[1]-10,4);a.stroke();this.mouseOver&&a.fill();a.fillStyle=this.mouseOver?"#000":"#AAA";a.font="bold "+this.properties.fontsize+"px Criticized,Tahoma";a.textAlign="center";a.fillText(this.properties.text,0.5*this.size[0],0.5*this.size[1]+0.5*parseInt(this.properties.fontsize));a.textAlign="left"},drawBevelShape:function(a){a.shadowColor=
"#000";a.shadowOffsetX=0;a.shadowOffsetY=0;a.shadowBlur=this.properties.shadowSize;this.lineargradient||this.createGradient(a);a.fillStyle=this.mouseOver?this.properties.color:this.lineargradient;this.clicking&&(a.fillStyle="#444");a.strokeStyle="#FFF";a.roundRect(5,5,this.size[0]-10,this.size[1]-10,4);a.fill();a.shadowColor="rgba(0,0,0,0)";a.stroke();a.fillStyle=this.mouseOver?"#000":"#444";a.font="bold "+this.properties.fontsize+"px Century Gothic";a.textAlign="center";a.fillText(this.properties.text,
-0.5*this.size[0],0.5*this.size[1]+0.4*parseInt(this.properties.fontsize));a.textAlign="left"},onDrawBackground:function(a){this.drawBevelShape(a)},clickButton:function(){var a=this.getOutputModule(0);if(this.properties.command&&""!=this.properties.command)a.executeAction(this.properties.command)||this.trace("Error executing action in other module");else if(a&&a.onTrigger)a.onTrigger()},onMouseDown:function(a){if(2>a.canvasY-this.pos[1])return!1;this.clickButton();return this.clicking=!0},onMouseUp:function(a){this.clicking=
+0.5*this.size[0],0.5*this.size[1]+0.4*parseInt(this.properties.fontsize));a.textAlign="left"},onDrawForeground:function(a){this.drawBevelShape(a)},clickButton:function(){var a=this.getOutputModule(0);if(this.properties.command&&""!=this.properties.command)a.executeAction(this.properties.command)||this.trace("Error executing action in other module");else if(a&&a.onTrigger)a.onTrigger()},onMouseDown:function(a){if(2>a.canvasY-this.pos[1])return!1;this.clickButton();return this.clicking=!0},onMouseUp:function(a){this.clicking=
!1},onExecute:function(){},onWidget:function(a,b){"test"==b.name&&this.clickButton()},onPropertyChange:function(a,b){this.properties[a]=b;return!0}});
-LiteGraph.registerNodeType("widget/progress",{title:"Progress",desc:"Shows data in linear progress",size:[160,26],inputs:[["","number"]],properties:{min:0,max:1,value:0,wcolor:"#AAF"},onExecute:function(){var a=this.getInputData(0);void 0!=a&&(this.properties.value=a)},onDrawBackground:function(a){a.lineWidth=1;a.fillStyle=this.properties.wcolor;var b=(this.properties.value-this.properties.min)/(this.properties.max-this.properties.min),b=Math.min(1,b),b=Math.max(0,b);a.fillRect(2,2,(this.size[0]-
+LiteGraph.registerNodeType("widget/progress",{title:"Progress",desc:"Shows data in linear progress",size:[160,26],inputs:[["","number"]],properties:{min:0,max:1,value:0,wcolor:"#AAF"},onExecute:function(){var a=this.getInputData(0);void 0!=a&&(this.properties.value=a)},onDrawForeground:function(a){a.lineWidth=1;a.fillStyle=this.properties.wcolor;var b=(this.properties.value-this.properties.min)/(this.properties.max-this.properties.min),b=Math.min(1,b),b=Math.max(0,b);a.fillRect(2,2,(this.size[0]-
4)*b,this.size[1]-4)}});
-LiteGraph.registerNodeType("widget/text",{title:"Text",desc:"Shows the input value",widgets:[{name:"resize",text:"Resize box",type:"button"},{name:"led_text",text:"LED",type:"minibutton"},{name:"normal_text",text:"Normal",type:"minibutton"}],inputs:[["",0]],properties:{value:"...",font:"Arial",fontsize:18,color:"#AAA",align:"left",glowSize:0,decimals:1},onDrawBackground:function(a){a.fillStyle=this.properties.color;var b=this.properties.value;this.properties.glowSize?(a.shadowColor=this.properties.color,
+LiteGraph.registerNodeType("widget/text",{title:"Text",desc:"Shows the input value",widgets:[{name:"resize",text:"Resize box",type:"button"},{name:"led_text",text:"LED",type:"minibutton"},{name:"normal_text",text:"Normal",type:"minibutton"}],inputs:[["",0]],properties:{value:"...",font:"Arial",fontsize:18,color:"#AAA",align:"left",glowSize:0,decimals:1},onDrawForeground:function(a){a.fillStyle=this.properties.color;var b=this.properties.value;this.properties.glowSize?(a.shadowColor=this.properties.color,
a.shadowOffsetX=0,a.shadowOffsetY=0,a.shadowBlur=this.properties.glowSize):a.shadowColor="transparent";var c=this.properties.fontsize;a.textAlign=this.properties.align;a.font=c.toString()+"px "+this.properties.font;this.str="number"==typeof b?b.toFixed(this.properties.decimals):b;if("string"==typeof this.str){var b=this.str.split("\\n"),d;for(d in b)a.fillText(b[d],"left"==this.properties.align?15:this.size[0]-15,-0.15*c+c*(parseInt(d)+1))}a.shadowColor="transparent";this.last_ctx=a;a.textAlign="left"},
onExecute:function(){var a=this.getInputData(0);this.properties.value=null!=a?a:"";this.setDirtyCanvas(!0)},resize:function(){if(this.last_ctx){var a=this.str.split("\\n");this.last_ctx.font=this.properties.fontsize+"px "+this.properties.font;var b=0,c;for(c in a){var d=this.last_ctx.measureText(a[c]).width;bb&&(b=0);if(0!=a.length){var c=[0,0,0];if(0==b)c=a[0];else if(1==b)c=a[a.length-1];else{var d=(a.length-1)*b,b=a[Math.floor(d)],a=a[Math.floor(d)+1],d=d-Math.floor(d);c[0]=b[0]*(1-d)+a[0]*d;c[1]=b[1]*(1-d)+a[1]*d;c[2]=b[2]*(1-d)+a[2]*d}for(var e in c)c[e]/=255;this.boxcolor=colorToString(c);this.setOutputData(0,c)}}});
diff --git a/css/litegraph-editor.css b/css/litegraph-editor.css
new file mode 100644
index 000000000..4147d4b87
--- /dev/null
+++ b/css/litegraph-editor.css
@@ -0,0 +1,187 @@
+.litegraph-editor {
+ width: 100%;
+ height: 100%;
+ margin: 0;
+ padding: 0;
+
+ background-color: #333;
+ color: #EEE;
+ font: 14px Tahoma;
+
+ position: relative;
+}
+
+.litegraph-editor h1 {
+ font-family: "Metro Light",Tahoma;
+ color: #DDD;
+ font-size: 28px;
+ padding-left: 10px;
+ /*text-shadow: 0 1px 1px #333, 0 -1px 1px #777;*/
+ margin: 0;
+ font-weight: normal;
+}
+
+.litegraph-editor h1 span {
+ font-family: "Arial";
+ font-size: 14px;
+ font-weight: normal;
+ color: #AAA;
+}
+
+.litegraph-editor h2 {
+ font-family: "Metro Light";
+ padding: 5px;
+ margin-left: 10px;
+}
+
+
+.litegraph-editor * {
+ box-sizing: border-box;
+ -moz-box-sizing: border-box;
+}
+
+.litegraph-editor .content {
+ position: relative;
+ width: 100%;
+ height: calc( 100% - 80px );
+ background-color: #292929;
+}
+
+.litegraph-editor .header, .litegraph-editor .footer {
+ position: relative;
+ height: 40px;
+ background-color: #333;
+ /*border-radius: 10px 10px 0 0;*/
+}
+
+.litegraph-editor .tools, .litegraph-editor .tools-left, .litegraph-editor .tools-right {
+ position: absolute;
+ top: 2px;
+ right: 0px;
+ vertical-align: top;
+
+ margin: 2px 5px 0 0px;
+}
+
+.litegraph-editor .tools-left {
+ right: auto;
+ left: 4px;
+}
+
+.litegraph-editor .footer {
+ height: 40px;
+ position: relative;
+ /*border-radius: 0 0 10px 10px;*/
+}
+
+.litegraph-editor .miniwindow {
+ background-color: #333;
+ border: 1px solid #111;
+}
+
+.litegraph-editor .miniwindow .corner-button {
+ position: absolute;
+ top: 2px;
+ right: 2px;
+ font-family: "Tahoma";
+ font-size: 14px;
+ color: #AAA;
+ cursor: pointer;
+}
+
+
+/* BUTTONS **********************/
+
+.litegraph-editor button {
+ /*font-family: "Metro Light";*/
+ color: #CCC;
+ font-size: 20px;
+ min-width: 30px;
+ /*border-radius: 0.3em;*/
+ border: 0 solid #666;
+ background-color: #3F3F3F;
+ /*box-shadow: 0 0 3px black;*/
+ padding: 4px 10px;
+ line-height: 20px;
+ cursor: pointer;
+ transition: all 1s;
+ -moz-transition: all 1s;
+ -webkit-transition: all 0.4s;
+}
+
+.litegraph-editor button:hover {
+ background-color: #999;
+ color: #FFF;
+ transition: all 1s;
+ -moz-transition: all 1s;
+ -webkit-transition: all 0.4s;
+}
+
+.litegraph-editor button:active {
+ background-color: white;
+}
+
+.litegraph-editor button.fixed {
+ position: absolute;
+ top: 5px;
+ right: 5px;
+ font-size: 1.2em;
+}
+
+.litegraph-editor button img {
+ margin: -4px;
+ vertical-align: top;
+}
+
+.litegraph-editor .header button {
+ height: 32px;
+ vertical-align: top;
+}
+
+.litegraph-editor .footer button {
+ /*font-size: 16px;*/
+}
+
+.litegraph-editor .toolbar-widget {
+ display: inline-block;
+}
+
+.litegraph-editor .editor-area {
+ width: 100%;
+ height: 100%;
+}
+
+/* METER *********************/
+
+.litegraph-editor .loadmeter {
+ font-family: "Tahoma";
+ color: #AAA;
+ font-size: 12px;
+ border-radius: 2px;
+ width: 130px;
+ vertical-align: top;
+}
+
+.litegraph-editor .strong {
+ vertical-align: top;
+ padding: 3px;
+ width: 30px;
+ display: inline-block;
+ line-height: 8px;
+}
+
+.litegraph-editor .cpuload .bgload, .litegraph-editor .gpuload .bgload {
+ display: inline-block;
+ width: 90px;
+ height: 15px;
+ background-image: url('../demo/imgs/load-progress-empty.png');
+}
+
+.litegraph-editor .cpuload .fgload, .litegraph-editor .gpuload .fgload {
+ display: inline-block;
+ width: 4px;
+ height: 15px;
+ max-width: 90px;
+ background-image: url('../demo/imgs/load-progress-full.png');
+}
+
diff --git a/demo/code.js b/demo/code.js
index face0b02e..f0d4d6c4b 100644
--- a/demo/code.js
+++ b/demo/code.js
@@ -1,544 +1,9 @@
-var graph = null;
-var graphcanvas = null;
-$(window).load(function() {
-
- var id = null;
- if ($.getUrlVar("id") != null)
- id = parseInt($.getUrlVar("id"));
- else if (self.document.location.hash)
- id = parseInt( self.document.location.hash.substr(1) );
-
- $("#settings_button").click( function() { $("#settings-panel").toggle(); });
- $("#addnode_button").click( function() { onShowNodes() });
- $("#deletenode_button").click( function() { onDeleteNode() });
- $("#clonenode_button").click( function() { onCloneNode() });
-
- $("#playnode_button").click( function() {
- if(graph.status == LGraph.STATUS_STOPPED)
- {
- $(this).html(" Stop");
- graph.start(1);
- }
- else
- {
- $(this).html(" Play");
- graph.stop();
- }
- });
-
- $("#playstepnode_button").click( function() {
- graph.runStep(1);
- graphcanvas.draw(true,true);
- });
-
- $("#playfastnode_button").click( function() {
- graph.runStep(5000);
- graphcanvas.draw(true,true);
- });
-
- $("#collapsenode_button").click( function() {
- /*
- for(var i in graphcanvas.nodes_selected)
- graphcanvas.nodes_selected[i].collapse();
- */
- if( graphcanvas.node_in_panel )
- graphcanvas.node_in_panel.collapse();
-
- graphcanvas.draw();
- });
-
- $("#pinnode_button").click( function() {
- if( graphcanvas.node_in_panel )
- graphcanvas.node_in_panel.pin();
- });
-
- $("#sendtobacknode_button").click( function() {
- if( graphcanvas.node_in_panel )
- graphcanvas.sendToBack( graphcanvas.node_in_panel );
- graphcanvas.draw(true);
- });
-
-
-
- $("#confirm-createnode_button").click(function() {
- var element = $(".node-type.selected")[0];
- var name = element.data;
- var n = LiteGraph.createNode(name);
- graph.add(n);
- n.pos = graphcanvas.convertOffsetToCanvas([30,30]);
- graphcanvas.draw(true,true);
- $("#modal-blocking-box").hide();
- $("#nodes-browser").hide();
- });
-
- $("#cancel-createnode_button").click(function() {
- $("#modal-blocking-box").hide();
- $("#nodes-browser").hide();
- });
-
- $("#close-area_button").click(function() {
- $("#modal-blocking-box").hide();
- $("#data-visor").hide();
- });
-
- $("#confirm-loadsession_button").click(function() {
- var element = $(".session-item.selected")[0];
- var info = element.data;
-
- var str = localStorage.getItem("graph_session_" + info.id );
- graph.stop();
- graph.unserialize(str);
-
- graphcanvas.draw(true,true);
- $("#modal-blocking-box").hide();
- $("#sessions-browser").hide();
- });
-
- $("#cancel-loadsession_button").click(function() {
- $("#modal-blocking-box").hide();
- $("#sessions-browser").hide();
- });
-
- $("#livemode_button").click( function() {
- graphcanvas.switchLiveMode();
- graphcanvas.draw();
- var url = graphcanvas.live_mode ? "imgs/gauss_bg_medium.jpg" : "imgs/gauss_bg.jpg";
- $("#livemode_button").html(!graphcanvas.live_mode ? " Live" : " Edit" );
- //$("canvas").css("background-image","url('"+url+"')");
- });
-
- $("#newsession_button").click( function() {
- $("#main-area").hide();
- graph.clear();
- graphcanvas.draw();
- $("#main-area").show();
- });
-
- $("#savesession_button").click( function() {
- onSaveSession();
- });
-
- $("#loadsession_button").click( function() {
- onLoadSession();
- });
-
- $("#cancelsession-dialog_button").click(function()
- {
- $("#modal-blocking-box").hide();
- $("#savesession-dialog").hide();
- });
-
- $("#savesession-dialog_button").click(function()
- {
- var name = $("#session-name-input").val();
- var desc = $("#session-description-input").val();
-
- saveSession(name,desc);
-
- $("#modal-blocking-box").hide();
- $("#savesession-dialog").hide();
-
- });
-
- $("#closepanel_button").click(function()
- {
- graphcanvas.showNodePanel(null);
- });
-
- $("#maximize_button").click(function()
- {
- if($("#main").width() != window.innerWidth)
- {
- $("#main").width( (window.innerWidth).toString() + "px");
- $("#main").height( (window.innerHeight - 40).toString() + "px");
- graphcanvas.resizeCanvas(window.innerWidth,window.innerHeight - 100);
- }
- else
- {
- $("#main").width("800px");
- $("#main").height("660px");
- graphcanvas.resizeCanvas(800,600);
- }
- });
-
- $("#resetscale_button").click(function()
- {
- graph.config.canvas_scale = 1.0;
- graphcanvas.draw(true,true);
- });
-
- $("#resetpos_button").click(function()
- {
- graph.config.canvas_offset = [0,0];
- graphcanvas.draw(true,true);
- });
-
- $(".nodecolorbutton").click(function()
- {
- if( graphcanvas.node_in_panel )
- {
- graphcanvas.node_in_panel.color = this.getAttribute("data-color");
- graphcanvas.node_in_panel.bgcolor = this.getAttribute("data-bgcolor");
- }
- graphcanvas.draw(true,true);
- });
-
-
- if ("onhashchange" in window) // does the browser support the hashchange event?
- {
- window.onhashchange = function () {
- var h = window.location.hash.substr(1);
- //action
- return false;
- }
- }
-
- LiteGraph.node_images_path = "../nodes_data/";
- graph = new LGraph();
- graphcanvas = new LGraphCanvas("graphcanvas",graph);
- graphcanvas.background_image = "imgs/grid.png";
-
- graph.onAfterExecute = function() { graphcanvas.draw(true) };
- demo();
-
- graph.onPlayEvent = function()
- {
- $("#playnode_button").addClass("playing");
- $("#playnode_button").removeClass("stopped");
- }
-
- graph.onStopEvent = function()
- {
- $("#playnode_button").addClass("stopped");
- $("#playnode_button").removeClass("playing");
- }
-
- graphcanvas.draw();
-
- //update load counter
- setInterval(function() {
- $("#cpuload .fgload").width( (2*graph.elapsed_time) * 90);
- if(graph.status == LGraph.STATUS_RUNNING)
- $("#gpuload .fgload").width( (graphcanvas.render_time*10) * 90);
- else
- $("#gpuload .fgload").width( 4 );
- },200);
-
- //LiteGraph.run(100);
-});
-
-
-function onShowNodes()
-{
- $("#nodes-list").empty();
-
- for (var i in LiteGraph.registered_node_types)
- {
- var node = LiteGraph.registered_node_types[i];
- var categories = node.category.split("/");
-
- //create categories and find the propper one
- var root = $("#nodes-list")[0];
- for(var i in categories)
- {
- var result = $(root).find("#node-category_" + categories[i] + " .container");
- if (result.length == 0)
- {
- var element = document.createElement("div");
- element.id = "node-category_" + categories[i];
- element.className = "node-category";
- element.data = categories[i];
- element.innerHTML = ""+categories[i]+" ";
- root.appendChild(element);
-
- $(element).find(".title").click(function(e){
- var element = $("#node-category_" + this.parentNode.data + " .container");
- $(element[0]).toggle();
- });
-
-
- var container = document.createElement("div");
- container.className = "container";
- element.appendChild(container);
-
- root = container;
- }
- else
- root = result[0];
- }
-
- //create entry
- var type = node.type;
- var element = document.createElement("div");
- element.innerHTML = ""+node.title+" " + (node.desc? node.desc : "");
- element.className = "node-type";
- element.id = "node-type-" + node.name;
- element.data = type;
- root.appendChild(element);
- }
-
- $(".node-type").click( function() {
- $(".node-type.selected").removeClass("selected");
- $(this).addClass("selected");
- $("#confirm-createnode_button").attr("disabled",false);
- });
-
- $(".node-type").dblclick( function() {
- $("#confirm-createnode_button").click();
- });
-
- $("#confirm-createnode_button").attr("disabled",true);
-
- $("#modal-blocking-box").show();
- $("#nodes-browser").show();
-}
-
-function onDeleteNode()
-{
- if(!graphcanvas.node_in_panel) return;
-
- graph.remove( graphcanvas.node_in_panel );
- graphcanvas.draw();
- $("#node-panel").hide();
- graphcanvas.node_in_panel = null;
-}
-
-function onCloneNode()
-{
- if(!graphcanvas.node_in_panel) return;
-
- var n = graphcanvas.node_in_panel.clone();
- n.pos[0] += 10;
- n.pos[1] += 10;
-
- graph.add(n);
- graphcanvas.draw();
-}
-
-function onSaveSession()
-{
- if(graph.session["name"])
- $("#session-name-input").val(graph.session["name"]);
-
- if(graph.session["description"])
- $("#session-desc-input").val(graph.session["description"]);
-
- $("#modal-blocking-box").show();
- $("#savesession-dialog").show();
- //var str = LiteGraph.serialize();
- //localStorage.setItem("graph_session",str);
-}
-
-function saveSession(name,desc)
-{
- desc = desc || "";
-
- graph.session["name"] = name;
- graph.session["description"] = desc;
- if(!graph.session["id"])
- graph.session["id"] = new Date().getTime();
-
- var str = graph.serializeSession();
- localStorage.setItem("graph_session_" + graph.session["id"],str);
-
- var sessions_str = localStorage.getItem("node_sessions");
- var sessions = [];
-
- if(sessions_str)
- sessions = JSON.parse(sessions_str);
-
- var pos = -1;
- for(var i = 0; i < sessions.length; i++)
- if( sessions[i].id == graph.session["id"] && sessions[i].name == name)
- {
- pos = i;
- break;
- }
-
- if(pos != -1)
- {
- //already on the list
- }
- else
- {
- var current_session = {name:name, desc:desc, id:graph.session["id"]};
- sessions.unshift(current_session);
- localStorage.setItem("graph_sessions", JSON.stringify(sessions));
- }
-}
-
-function onLoadSession()
-{
- $("#sessions-browser-list").empty();
-
- $("#modal-blocking-box").show();
- $("#sessions-browser").show();
-
- var sessions_str = localStorage.getItem("graph_sessions");
- var sessions = [];
-
- if(sessions_str)
- sessions = JSON.parse(sessions_str);
-
- for(var i in sessions)
- {
- var element = document.createElement("div");
- element.className = "session-item";
- element.data = sessions[i];
- $(element).html(""+sessions[i].name+" "+sessions[i].desc+" x ");
- $("#sessions-browser-list").append(element);
- }
-
- $(".session-item").click( function() {
- $(".session-item.selected").removeClass("selected");
- $(this).addClass("selected");
- $("#confirm-loadsession_button").attr("disabled",false);
- });
-
- $(".session-item").dblclick( function() {
- $("#confirm-loadsession_button").click();
- });
-
- $(".delete_session").click(function(e) {
- var root = $(this).parent();
- var info = root[0].data;
-
- var sessions_str = localStorage.getItem("graph_sessions");
- var sessions = [];
- if(sessions_str)
- sessions = JSON.parse(sessions_str);
- var pos = -1;
- for(var i = 0; i < sessions.length; i++)
- if( sessions[i].id == info.id )
- {
- pos = i;
- break;
- }
-
- if(pos != -1)
- {
- sessions.splice(pos,1);
- localStorage.setItem("graph_sessions", JSON.stringify(sessions));
- }
-
- root.remove();
- });
-
- $("#confirm-loadsession_button").attr("disabled",true);
-
- /*
- LiteGraph.stop();
- var str = localStorage.getItem("graph_session");
- LiteGraph.unserialize(str);
- LiteGraph.draw();
- */
-}
-
-function onShagraph()
-{
-
-}
-
-function showImage(data)
-{
- var img = new Image();
- img.src = data;
- $("#data-visor .content").empty();
- $("#data-visor .content").append(img);
- $("#modal-blocking-box").show();
- $("#data-visor").show();
-}
-
-function showElement(data)
-{
- setTimeout(function(){
- $("#data-visor .content").empty();
- $("#data-visor .content").append(data);
- $("#modal-blocking-box").show();
- $("#data-visor").show();
- },100);
-}
-
-
-// ********* SEEDED RANDOM ******************************
-function RandomNumberGenerator(seed)
-{
- if (typeof(seed) == 'undefined')
- {
- var d = new Date();
- this.seed = 2345678901 + (d.getSeconds() * 0xFFFFFF) + (d.getMinutes() * 0xFFFF);
- }
- else
- this.seed = seed;
-
- this.A = 48271;
- this.M = 2147483647;
- this.Q = this.M / this.A;
- this.R = this.M % this.A;
- this.oneOverM = 1.0 / this.M;
- this.next = nextRandomNumber;
- return this;
-}
-
-function nextRandomNumber(){
- var hi = this.seed / this.Q;
- var lo = this.seed % this.Q;
- var test = this.A * lo - this.R * hi;
- if(test > 0){
- this.seed = test;
- } else {
- this.seed = test + this.M;
- }
- return (this.seed * this.oneOverM);
-}
-
-var RAND_GEN = RandomNumberGenerator(0);
-
-function RandomSeed(s) { RAND_GEN = RandomNumberGenerator(s); };
-
-function myrand(Min, Max){
- return Math.round((Max-Min) * RAND_GEN.next() + Min);
-}
-
-function myrandom() { return myrand(0,100000) / 100000; }
-
-// @format (hex|rgb|null) : Format to return, default is integer
-function random_color(format)
-{
- var rint = Math.round(0xffffff * myrandom());
- switch(format)
- {
- case 'hex':
- return ('#0' + rint.toString(16)).replace(/^#0([0-9a-f]{6})$/i, '#$1');
- break;
-
- case 'rgb':
- return 'rgb(' + (rint >> 16) + ',' + (rint >> 8 & 255) + ',' + (rint & 255) + ')';
- break;
-
- default:
- return rint;
- break;
- }
-}
-
-$.extend({
- getUrlVars: function(){
- var vars = [], hash;
- var hashes = window.location.href.slice(window.location.href.indexOf('?') + 1).split('&');
- for(var i = 0; i < hashes.length; i++)
- {
- hash = hashes[i].split('=');
- vars.push(hash[0]);
- vars[hash[0]] = hash[1];
- }
- return vars;
- },
- getUrlVar: function(name){
- return $.getUrlVars()[name];
- }
-});
+LiteGraph.node_images_path = "../nodes_data/";
+var editor = new LiteGraph.Editor("main");
+window.graph = editor.graph;
+window.addEventListener("resize", function() { editor.graphcanvas.resize(); } );
+demo();
function trace(a)
{
diff --git a/demo/code_old.js b/demo/code_old.js
new file mode 100644
index 000000000..7f00dea51
--- /dev/null
+++ b/demo/code_old.js
@@ -0,0 +1,547 @@
+var graph = null;
+var graphcanvas = null;
+
+$(window).load(function() {
+
+ var id = null;
+ if ($.getUrlVar("id") != null)
+ id = parseInt($.getUrlVar("id"));
+ else if (self.document.location.hash)
+ id = parseInt( self.document.location.hash.substr(1) );
+
+ $("#settings_button").click( function() { $("#settings-panel").toggle(); });
+ $("#addnode_button").click( function() { onShowNodes() });
+ $("#deletenode_button").click( function() { onDeleteNode() });
+ $("#clonenode_button").click( function() { onCloneNode() });
+
+ $("#playnode_button").click( function() {
+ if(graph.status == LGraph.STATUS_STOPPED)
+ {
+ $(this).html(" Stop");
+ graph.start(1);
+ }
+ else
+ {
+ $(this).html(" Play");
+ graph.stop();
+ }
+ });
+
+ $("#playstepnode_button").click( function() {
+ graph.runStep(1);
+ graphcanvas.draw(true,true);
+ });
+
+ $("#playfastnode_button").click( function() {
+ graph.runStep(5000);
+ graphcanvas.draw(true,true);
+ });
+
+ $("#collapsenode_button").click( function() {
+ /*
+ for(var i in graphcanvas.nodes_selected)
+ graphcanvas.nodes_selected[i].collapse();
+ */
+ if( graphcanvas.node_in_panel )
+ graphcanvas.node_in_panel.collapse();
+
+ graphcanvas.draw();
+ });
+
+ $("#pinnode_button").click( function() {
+ if( graphcanvas.node_in_panel )
+ graphcanvas.node_in_panel.pin();
+ });
+
+ $("#sendtobacknode_button").click( function() {
+ if( graphcanvas.node_in_panel )
+ graphcanvas.sendToBack( graphcanvas.node_in_panel );
+ graphcanvas.draw(true);
+ });
+
+
+
+ $("#confirm-createnode_button").click(function() {
+ var element = $(".node-type.selected")[0];
+ var name = element.data;
+ var n = LiteGraph.createNode(name);
+ graph.add(n);
+ n.pos = graphcanvas.convertOffsetToCanvas([30,30]);
+ graphcanvas.draw(true,true);
+ $("#modal-blocking-box").hide();
+ $("#nodes-browser").hide();
+ });
+
+ $("#cancel-createnode_button").click(function() {
+ $("#modal-blocking-box").hide();
+ $("#nodes-browser").hide();
+ });
+
+ $("#close-area_button").click(function() {
+ $("#modal-blocking-box").hide();
+ $("#data-visor").hide();
+ });
+
+ $("#confirm-loadsession_button").click(function() {
+ var element = $(".session-item.selected")[0];
+ var info = element.data;
+
+ var str = localStorage.getItem("graph_session_" + info.id );
+ graph.stop();
+ graph.unserialize(str);
+
+ graphcanvas.draw(true,true);
+ $("#modal-blocking-box").hide();
+ $("#sessions-browser").hide();
+ });
+
+ $("#cancel-loadsession_button").click(function() {
+ $("#modal-blocking-box").hide();
+ $("#sessions-browser").hide();
+ });
+
+ $("#livemode_button").click( function() {
+ graphcanvas.switchLiveMode(true);
+ graphcanvas.draw();
+ var url = graphcanvas.live_mode ? "imgs/gauss_bg_medium.jpg" : "imgs/gauss_bg.jpg";
+ $("#livemode_button").html(!graphcanvas.live_mode ? " Live" : " Edit" );
+ //$("canvas").css("background-image","url('"+url+"')");
+ });
+
+ $("#newsession_button").click( function() {
+ $("#main-area").hide();
+ graph.clear();
+ graphcanvas.draw();
+ $("#main-area").show();
+ });
+
+ $("#savesession_button").click( function() {
+ onSaveSession();
+ });
+
+ $("#loadsession_button").click( function() {
+ onLoadSession();
+ });
+
+ $("#cancelsession-dialog_button").click(function()
+ {
+ $("#modal-blocking-box").hide();
+ $("#savesession-dialog").hide();
+ });
+
+ $("#savesession-dialog_button").click(function()
+ {
+ var name = $("#session-name-input").val();
+ var desc = $("#session-description-input").val();
+
+ saveSession(name,desc);
+
+ $("#modal-blocking-box").hide();
+ $("#savesession-dialog").hide();
+
+ });
+
+ $("#closepanel_button").click(function()
+ {
+ graphcanvas.showNodePanel(null);
+ });
+
+ $("#maximize_button").click(function()
+ {
+ if($("#main").width() != window.innerWidth)
+ {
+ $("#main").width( (window.innerWidth).toString() + "px");
+ $("#main").height( (window.innerHeight - 40).toString() + "px");
+ graphcanvas.resizeCanvas(window.innerWidth,window.innerHeight - 100);
+ }
+ else
+ {
+ $("#main").width("800px");
+ $("#main").height("660px");
+ graphcanvas.resizeCanvas(800,600);
+ }
+ });
+
+ $("#resetscale_button").click(function()
+ {
+ graph.config.canvas_scale = 1.0;
+ graphcanvas.draw(true,true);
+ });
+
+ $("#resetpos_button").click(function()
+ {
+ graph.config.canvas_offset = [0,0];
+ graphcanvas.draw(true,true);
+ });
+
+ $(".nodecolorbutton").click(function()
+ {
+ if( graphcanvas.node_in_panel )
+ {
+ graphcanvas.node_in_panel.color = this.getAttribute("data-color");
+ graphcanvas.node_in_panel.bgcolor = this.getAttribute("data-bgcolor");
+ }
+ graphcanvas.draw(true,true);
+ });
+
+
+ if ("onhashchange" in window) // does the browser support the hashchange event?
+ {
+ window.onhashchange = function () {
+ var h = window.location.hash.substr(1);
+ //action
+ return false;
+ }
+ }
+
+ LiteGraph.node_images_path = "../nodes_data/";
+ graph = new LGraph();
+ graphcanvas = new LGraphCanvas("graphcanvas",graph);
+ graphcanvas.background_image = "imgs/grid.png";
+
+ graph.onAfterExecute = function() { graphcanvas.draw(true) };
+ demo();
+
+ graph.onPlayEvent = function()
+ {
+ $("#playnode_button").addClass("playing");
+ $("#playnode_button").removeClass("stopped");
+ }
+
+ graph.onStopEvent = function()
+ {
+ $("#playnode_button").addClass("stopped");
+ $("#playnode_button").removeClass("playing");
+ }
+
+ graphcanvas.draw();
+
+ //update load counter
+ setInterval(function() {
+ $("#cpuload .fgload").width( (2*graph.elapsed_time) * 90);
+ if(graph.status == LGraph.STATUS_RUNNING)
+ $("#gpuload .fgload").width( (graphcanvas.render_time*10) * 90);
+ else
+ $("#gpuload .fgload").width( 4 );
+ },200);
+
+ //LiteGraph.run(100);
+});
+
+
+function onShowNodes()
+{
+ $("#nodes-list").empty();
+
+ for (var i in LiteGraph.registered_node_types)
+ {
+ var node = LiteGraph.registered_node_types[i];
+ var categories = node.category.split("/");
+
+ //create categories and find the propper one
+ var root = $("#nodes-list")[0];
+ for(var i in categories)
+ {
+ var result = $(root).find("#node-category_" + categories[i] + " .container");
+ if (result.length == 0)
+ {
+ var element = document.createElement("div");
+ element.id = "node-category_" + categories[i];
+ element.className = "node-category";
+ element.data = categories[i];
+ element.innerHTML = ""+categories[i]+" ";
+ root.appendChild(element);
+
+ $(element).find(".title").click(function(e){
+ var element = $("#node-category_" + this.parentNode.data + " .container");
+ $(element[0]).toggle();
+ });
+
+
+ var container = document.createElement("div");
+ container.className = "container";
+ element.appendChild(container);
+
+ root = container;
+ }
+ else
+ root = result[0];
+ }
+
+ //create entry
+ var type = node.type;
+ var element = document.createElement("div");
+ element.innerHTML = ""+node.title+" " + (node.desc? node.desc : "");
+ element.className = "node-type";
+ element.id = "node-type-" + node.name;
+ element.data = type;
+ root.appendChild(element);
+ }
+
+ $(".node-type").click( function() {
+ $(".node-type.selected").removeClass("selected");
+ $(this).addClass("selected");
+ $("#confirm-createnode_button").attr("disabled",false);
+ });
+
+ $(".node-type").dblclick( function() {
+ $("#confirm-createnode_button").click();
+ });
+
+ $("#confirm-createnode_button").attr("disabled",true);
+
+ $("#modal-blocking-box").show();
+ $("#nodes-browser").show();
+}
+
+function onDeleteNode()
+{
+ if(!graphcanvas.node_in_panel) return;
+
+ graph.remove( graphcanvas.node_in_panel );
+ graphcanvas.draw();
+ $("#node-panel").hide();
+ graphcanvas.node_in_panel = null;
+}
+
+function onCloneNode()
+{
+ if(!graphcanvas.node_in_panel) return;
+
+ var n = graphcanvas.node_in_panel.clone();
+ n.pos[0] += 10;
+ n.pos[1] += 10;
+
+ graph.add(n);
+ graphcanvas.draw();
+}
+
+function onSaveSession()
+{
+ if(graph.session["name"])
+ $("#session-name-input").val(graph.session["name"]);
+
+ if(graph.session["description"])
+ $("#session-desc-input").val(graph.session["description"]);
+
+ $("#modal-blocking-box").show();
+ $("#savesession-dialog").show();
+ //var str = LiteGraph.serialize();
+ //localStorage.setItem("graph_session",str);
+}
+
+function saveSession(name,desc)
+{
+ desc = desc || "";
+
+ graph.session["name"] = name;
+ graph.session["description"] = desc;
+ if(!graph.session["id"])
+ graph.session["id"] = new Date().getTime();
+
+ var str = graph.serializeSession();
+ localStorage.setItem("graph_session_" + graph.session["id"],str);
+
+ var sessions_str = localStorage.getItem("node_sessions");
+ var sessions = [];
+
+ if(sessions_str)
+ sessions = JSON.parse(sessions_str);
+
+ var pos = -1;
+ for(var i = 0; i < sessions.length; i++)
+ if( sessions[i].id == graph.session["id"] && sessions[i].name == name)
+ {
+ pos = i;
+ break;
+ }
+
+ if(pos != -1)
+ {
+ //already on the list
+ }
+ else
+ {
+ var current_session = {name:name, desc:desc, id:graph.session["id"]};
+ sessions.unshift(current_session);
+ localStorage.setItem("graph_sessions", JSON.stringify(sessions));
+ }
+}
+
+function onLoadSession()
+{
+ $("#sessions-browser-list").empty();
+
+ $("#modal-blocking-box").show();
+ $("#sessions-browser").show();
+
+ var sessions_str = localStorage.getItem("graph_sessions");
+ var sessions = [];
+
+ if(sessions_str)
+ sessions = JSON.parse(sessions_str);
+
+ for(var i in sessions)
+ {
+ var element = document.createElement("div");
+ element.className = "session-item";
+ element.data = sessions[i];
+ $(element).html(""+sessions[i].name+" "+sessions[i].desc+" x ");
+ $("#sessions-browser-list").append(element);
+ }
+
+ $(".session-item").click( function() {
+ $(".session-item.selected").removeClass("selected");
+ $(this).addClass("selected");
+ $("#confirm-loadsession_button").attr("disabled",false);
+ });
+
+ $(".session-item").dblclick( function() {
+ $("#confirm-loadsession_button").click();
+ });
+
+ $(".delete_session").click(function(e) {
+ var root = $(this).parent();
+ var info = root[0].data;
+
+ var sessions_str = localStorage.getItem("graph_sessions");
+ var sessions = [];
+ if(sessions_str)
+ sessions = JSON.parse(sessions_str);
+ var pos = -1;
+ for(var i = 0; i < sessions.length; i++)
+ if( sessions[i].id == info.id )
+ {
+ pos = i;
+ break;
+ }
+
+ if(pos != -1)
+ {
+ sessions.splice(pos,1);
+ localStorage.setItem("graph_sessions", JSON.stringify(sessions));
+ }
+
+ root.remove();
+ });
+
+ $("#confirm-loadsession_button").attr("disabled",true);
+
+ /*
+ LiteGraph.stop();
+ var str = localStorage.getItem("graph_session");
+ LiteGraph.unserialize(str);
+ LiteGraph.draw();
+ */
+}
+
+function onShagraph()
+{
+
+}
+
+function showImage(data)
+{
+ var img = new Image();
+ img.src = data;
+ $("#data-visor .content").empty();
+ $("#data-visor .content").append(img);
+ $("#modal-blocking-box").show();
+ $("#data-visor").show();
+}
+
+function showElement(data)
+{
+ setTimeout(function(){
+ $("#data-visor .content").empty();
+ $("#data-visor .content").append(data);
+ $("#modal-blocking-box").show();
+ $("#data-visor").show();
+ },100);
+}
+
+
+// ********* SEEDED RANDOM ******************************
+function RandomNumberGenerator(seed)
+{
+ if (typeof(seed) == 'undefined')
+ {
+ var d = new Date();
+ this.seed = 2345678901 + (d.getSeconds() * 0xFFFFFF) + (d.getMinutes() * 0xFFFF);
+ }
+ else
+ this.seed = seed;
+
+ this.A = 48271;
+ this.M = 2147483647;
+ this.Q = this.M / this.A;
+ this.R = this.M % this.A;
+ this.oneOverM = 1.0 / this.M;
+ this.next = nextRandomNumber;
+ return this;
+}
+
+function nextRandomNumber(){
+ var hi = this.seed / this.Q;
+ var lo = this.seed % this.Q;
+ var test = this.A * lo - this.R * hi;
+ if(test > 0){
+ this.seed = test;
+ } else {
+ this.seed = test + this.M;
+ }
+ return (this.seed * this.oneOverM);
+}
+
+var RAND_GEN = RandomNumberGenerator(0);
+
+function RandomSeed(s) { RAND_GEN = RandomNumberGenerator(s); };
+
+function myrand(Min, Max){
+ return Math.round((Max-Min) * RAND_GEN.next() + Min);
+}
+
+function myrandom() { return myrand(0,100000) / 100000; }
+
+// @format (hex|rgb|null) : Format to return, default is integer
+function random_color(format)
+{
+ var rint = Math.round(0xffffff * myrandom());
+ switch(format)
+ {
+ case 'hex':
+ return ('#0' + rint.toString(16)).replace(/^#0([0-9a-f]{6})$/i, '#$1');
+ break;
+
+ case 'rgb':
+ return 'rgb(' + (rint >> 16) + ',' + (rint >> 8 & 255) + ',' + (rint & 255) + ')';
+ break;
+
+ default:
+ return rint;
+ break;
+ }
+}
+
+$.extend({
+ getUrlVars: function(){
+ var vars = [], hash;
+ var hashes = window.location.href.slice(window.location.href.indexOf('?') + 1).split('&');
+ for(var i = 0; i < hashes.length; i++)
+ {
+ hash = hashes[i].split('=');
+ vars.push(hash[0]);
+ vars[hash[0]] = hash[1];
+ }
+ return vars;
+ },
+ getUrlVar: function(name){
+ return $.getUrlVars()[name];
+ }
+});
+
+function trace(a)
+{
+ if(typeof(console) == "object")
+ console.log(a);
+}
\ No newline at end of file
diff --git a/demo/index.html b/demo/index.html
index 746bfc2f7..ef592e175 100644
--- a/demo/index.html
+++ b/demo/index.html
@@ -6,9 +6,11 @@
+
+
+
+
diff --git a/demo/style.css b/demo/style.css
index 76fdbb897..898865354 100644
--- a/demo/style.css
+++ b/demo/style.css
@@ -13,76 +13,18 @@ body {
h1 {
font-family: "Metro Light",Tahoma;
- color: #DDD;
- font-size: 28px;
- padding-left: 10px;
- /*text-shadow: 0 1px 1px #333, 0 -1px 1px #777;*/
- margin: 0;
- font-weight: normal;
-}
-
-h1 span {
- font-family: "Arial";
- font-size: 14px;
- font-weight: normal;
- color: #AAA;
}
h2 {
font-family: "Metro Light";
- padding: 5px;
- margin-left: 10px;
}
#main {
- width: 1000px;
- min-height: 540px;
- margin: auto;
- background-color: #222;
- /*border-radius: 10px;*/
-}
-
-#main.fullscreen {
width: 100%;
height: 100%;
+ background-color: #222;
}
-#header, #footer {
- position: relative;
- height: 40px;
- background-color: #333;
- /*border-radius: 10px 10px 0 0;*/
-}
-
-.tools, #tools-left, #tools-right {
- position: absolute;
- top: 2px;
- right: 0px;
- vertical-align: top;
-
- margin: 2px 5px 0 0px;
-}
-
-#header button {
- height: 32px;
- vertical-align: top;
-}
-
-#footer button {
- /*font-size: 16px;*/
-}
-
-#tools-left {
- right: auto;
- left: 4px;
-}
-
-
-#footer {
- height: 40px;
- position: relative;
- /*border-radius: 0 0 10px 10px;*/
-}
#status {
position: absolute;
@@ -135,55 +77,6 @@ h2 {
height: 100%;
}
-button {
- /*font-family: "Metro Light";*/
- color: #CCC;
- font-size: 20px;
- min-width: 30px;
- /*border-radius: 0.3em;*/
- border: 0 solid #666;
- background-color: #3F3F3F;
- /*box-shadow: 0 0 3px black;*/
- padding: 4px 10px;
- line-height: 20px;
- cursor: pointer;
- transition: all 1s;
- -moz-transition: all 1s;
- -webkit-transition: all 0.4s;
-}
-
-button:hover {
- background-color: #999;
- color: #FFF;
- transition: all 1s;
- -moz-transition: all 1s;
- -webkit-transition: all 0.4s;
-}
-
-button:active {
- background-color: white;
-}
-
-button.fixed {
- position: absolute;
- top: 5px;
- right: 5px;
- font-size: 1.2em;
-}
-
-button img {
- margin: -4px;
- vertical-align: top;
-}
-
-#play_button {
- background-color: #446;
- margin-right: 30px;
-}
-
-#play_button:hover {
- background-color: #AAF;
-}
.item-list .item {
margin: 5px;
@@ -348,40 +241,3 @@ textarea {
margin: 10px;
}
-#loadmeter {
- font-family: "Tahoma";
- display: inline-block;
- position: absolute;
- top: 0;
- left: 300px;
- color: #AAA;
- font-size: 12px;
- border-radius: 2px;
- width: 130px;
- margin: 3px;
- padding: 2px;
- vertical-align: top;
-}
-
-#loadmeter strong {
- vertical-align: top;
- padding: 3px;
- width: 30px;
- display: inline-block;
- line-height: 8px;
-}
-
-#cpuload .bgload, #gpuload .bgload {
- display: inline-block;
- width: 90px;
- height: 15px;
- background-image: url('imgs/load-progress-empty.png');
-}
-
-#cpuload .fgload, #gpuload .fgload {
- display: inline-block;
- width: 4px;
- height: 15px;
- max-width: 90px;
- background-image: url('imgs/load-progress-full.png');
-}
diff --git a/doc/api.js b/doc/api.js
index 8f212c487..18d6f246a 100644
--- a/doc/api.js
+++ b/doc/api.js
@@ -2,6 +2,7 @@ YUI.add("yuidoc-meta", function(Y) {
Y.YUIDoc = { meta: {
"classes": [
"LGraph",
+ "LGraphCanvas",
"LGraphNode",
"LiteGraph"
],
diff --git a/doc/classes/LGraph.html b/doc/classes/LGraph.html
index 9f8bfb531..561b624fb 100644
--- a/doc/classes/LGraph.html
+++ b/doc/classes/LGraph.html
@@ -43,6 +43,8 @@
LGraph
+ LGraphCanvas
+
LGraphNode
LiteGraph
@@ -94,7 +96,7 @@
@@ -145,7 +147,7 @@
- ../src/litegraph.js:302
+ ../src/litegraph.js:299
@@ -196,6 +198,13 @@
+
+
+
+ attachCanvas
+
+
+
@@ -203,6 +212,20 @@
+
+
+
+ configure
+
+
+
+
+
+
+ detachCanvas
+
+
+
@@ -252,6 +275,13 @@
+
+
+
+ isLive
+
+
+
@@ -304,14 +334,7 @@
- stop
-
-
-
-
-
-
- unserialize
+ stop execution
@@ -382,7 +405,7 @@
- ../src/litegraph.js:602
+ ../src/litegraph.js:645
@@ -426,6 +449,94 @@
+
+
+
+
+
attachCanvas
+
+
+
+
(
+
+
+
+ graph_canvas
+
+
+
+ )
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Attach Canvas to this graph
+
+
+
+
+
+
Parameters:
+
+
+
+
+
+ graph_canvas
+ GraphCanvas
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -461,7 +572,7 @@
- ../src/litegraph.js:321
+ ../src/litegraph.js:317
@@ -481,6 +592,183 @@
+
+
+
+
+
+
+
+
detachCanvas
+
+
+
+
(
+
+
+
+ graph_canvas
+
+
+
+ )
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Detach Canvas from this graph
+
+
+
+
+
+
Parameters:
+
+
+
+
+
+ graph_canvas
+ GraphCanvas
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -530,7 +818,7 @@
- ../src/litegraph.js:737
+ ../src/litegraph.js:780
@@ -637,7 +925,7 @@
- ../src/litegraph.js:721
+ ../src/litegraph.js:764
@@ -734,7 +1022,7 @@
- ../src/litegraph.js:575
+ ../src/litegraph.js:605
@@ -808,7 +1096,7 @@ if the nodes are using graphical actions
- ../src/litegraph.js:564
+ ../src/litegraph.js:594
@@ -887,7 +1175,7 @@ if the nodes are using graphical actions
- ../src/litegraph.js:708
+ ../src/litegraph.js:751
@@ -991,7 +1279,7 @@ if the nodes are using graphical actions
- ../src/litegraph.js:753
+ ../src/litegraph.js:796
@@ -1120,7 +1408,7 @@ if the nodes are using graphical actions
- ../src/litegraph.js:553
+ ../src/litegraph.js:583
@@ -1154,6 +1442,61 @@ if the nodes are using graphical actions
+
+
+
+
+
isLive
+
+
+
()
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
returns if the graph is in live mode
+
+
+
+
+
+
+
+
@@ -1199,7 +1542,7 @@ if the nodes are using graphical actions
- ../src/litegraph.js:647
+ ../src/litegraph.js:690
@@ -1288,7 +1631,7 @@ if the nodes are using graphical actions
- ../src/litegraph.js:413
+ ../src/litegraph.js:443
@@ -1383,7 +1726,7 @@ if the nodes are using graphical actions
- ../src/litegraph.js:587
+ ../src/litegraph.js:617
@@ -1455,7 +1798,7 @@ if the nodes are using graphical actions
- String
+ Object
@@ -1482,7 +1825,7 @@ if the nodes are using graphical actions
- ../src/litegraph.js:843
+ ../src/litegraph.js:893
@@ -1493,7 +1836,7 @@ if the nodes are using graphical actions
-
Creates a JSON String containing all the info about this graph
+
Creates a Object containing all the info about this graph, it can be serialized
@@ -1506,7 +1849,7 @@ if the nodes are using graphical actions
-
-
stop
+
-
-
-
-
unserialize
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Configure a graph from a JSON string
-
-
-
-
-
-
Parameters:
-
-
-
-
-
- str
- String
-
-
-
-
-
-
configure a graph from a JSON string
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -2003,7 +2257,7 @@ can be easily accesed from the outside of the graph
-
../src/litegraph.js:457
+
../src/litegraph.js:487
diff --git a/doc/classes/LGraphCanvas.html b/doc/classes/LGraphCanvas.html
new file mode 100644
index 000000000..fcb197b6b
--- /dev/null
+++ b/doc/classes/LGraphCanvas.html
@@ -0,0 +1,277 @@
+
+
+
+
+
LGraphCanvas
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Show:
+
+
+ Inherited
+
+
+
+
+ Protected
+
+
+
+
+ Private
+
+
+
+ Deprecated
+
+
+
+
+
+
+
+
+
LGraphCanvas Class
+
+
+
+
+
+
The Global Scope. It contains all the registered node classes.
+
+
+
+
+
+
Constructor
+
+
LGraphCanvas
+
+
+
+
(
+
+
+
+ canvas
+
+
+
+
+
+ graph
+
+
+
+ )
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Parameters:
+
+
+
+
+
+ canvas
+ HTMLCanvas
+
+
+
+
+
+
the canvas where you want to render (it accepts a selector in string format)
+
+
+
+
+
+
+
+
+ graph
+ LGraph
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Item Index
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/doc/classes/LGraphNode.html b/doc/classes/LGraphNode.html
index ea04b3c2e..7d966a3da 100644
--- a/doc/classes/LGraphNode.html
+++ b/doc/classes/LGraphNode.html
@@ -43,6 +43,8 @@
LGraph
+
LGraphCanvas
+
LGraphNode
LiteGraph
@@ -94,7 +96,7 @@
@@ -117,6 +119,8 @@
Index
+
Methods
+
@@ -127,6 +131,182 @@
Item Index
+
+
@@ -136,6 +316,2436 @@
+
+
Methods
+
+
+
+
addConnection
+
+
+
+
(
+
+
+
+ name
+
+
+
+
+
+ type
+
+
+
+
+
+ pos
+
+
+
+
+
+ direction
+
+
+
+ )
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
add an special connection to this node (used for special kinds of graphs)
+
+
+
+
+
+
Parameters:
+
+
+
+
+
+ name
+ String
+
+
+
+
+
+
+
+
+
+
+
+
+
+ type
+ String
+
+
+
+
+
+
string defining the input type ("vec3","number",...)
+
+
+
+
+
+
+
+
+ pos
+ x,y
+
+
+
+
+
+
position of the connection inside the node
+
+
+
+
+
+
+
+
+ direction
+ String
+
+
+
+
+
+
if is input or output
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
addOutput
+
+
+
+
(
+
+
+
+ name
+
+
+
+
+
+ type
+
+
+
+
+
+ extra_info
+
+
+
+ )
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
add a new output slot to use in this node
+
+
+
+
+
+
Parameters:
+
+
+
+
+
+ name
+ String
+
+
+
+
+
+
+
+
+
+
+
+
+
+ type
+ String
+
+
+
+
+
+
string defining the output type ("vec3","number",...)
+
+
+
+
+
+
+
+
+ extra_info
+ Object
+
+
+
+
+
+
this can be used to have special properties of an output (special color, position, etc)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
collapse
+
+
+
()
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Collapse the node to make it smaller on the canvas
+
+
+
+
+
+
+
+
+
+
+
+
+
computeSize
+
+
+
+
(
+
+
+
+ minHeight
+
+
+
+ )
+
+
+
+
+
+ Number
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
computes the size of a node according to its inputs and output slots
+
+
+
+
+
+
Parameters:
+
+
+
+
+
+ minHeight
+ Number
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Returns:
+
+
+
+
+
Number :
+
+
the total size
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
connect
+
+
+
+
(
+
+
+
+ slot
+
+
+
+
+
+ node
+
+
+
+
+
+ target_slot
+
+
+
+ )
+
+
+
+
+
+ Boolean
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
connect this node output to the input of another node
+
+
+
+
+
+
Parameters:
+
+
+
+
+
+ slot
+ Number_or_string
+
+
+
+
+
+
(could be the number of the slot or the string with the name of the slot)
+
+
+
+
+
+
+
+
+ node
+ LGraphNode
+
+
+
+
+
+
+
+
+
+
+
+ target_slot
+ Number_or_string
+
+
+
+
+
+
the input slot of the target node (could be the number of the slot or the string with the name of the slot)
+
+
+
+
+
+
+
+
+
+
+
+
+
Returns:
+
+
+
+
+
Boolean :
+
+
if it was connected succesfully
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
disconnectOutput
+
+
+
+
(
+
+
+
+ slot
+
+
+
+
+
+ target_node
+
+
+
+ )
+
+
+
+
+
+ Boolean
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
disconnect one output to an specific node
+
+
+
+
+
+
Parameters:
+
+
+
+
+
+ slot
+ Number_or_string
+
+
+
+
+
+
(could be the number of the slot or the string with the name of the slot)
+
+
+
+
+
+
+
+
+ target_node
+ LGraphNode
+
+
+
+
+
+
the target node to which this slot is connected [Optional, if not target_node is specified all nodes will be disconnected]
+
+
+
+
+
+
+
+
+
+
+
+
+
Returns:
+
+
+
+
+
Boolean :
+
+
if it was disconnected succesfully
+
+
+
+
+
+
+
+
+
+
+
+
getBounding
+
+
+
()
+
+
+
+
+ Float32Array4
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
returns the bounding of the object, used for rendering purposes
+
+
+
+
+
+
+
+
Returns:
+
+
+
+
+
Float32Array4 :
+
+
the total size
+
+
+
+
+
+
+
+
+
+
+
+
getConnectionPos
+
+
+
+
(
+
+
+
+ is_input
+
+
+
+
+
+ slot
+
+
+
+ )
+
+
+
+
+
+ x,y
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
returns the center of a connection point in canvas coords
+
+
+
+
+
+
Parameters:
+
+
+
+
+
+ is_input
+ Boolean
+
+
+
+
+
+
true if if a input slot, false if it is an output
+
+
+
+
+
+
+
+
+ slot
+ Number_or_string
+
+
+
+
+
+
(could be the number of the slot or the string with the name of the slot)
+
+
+
+
+
+
+
+
+
+
+
+
+
Returns:
+
+
+
+
+
x,y :
+
+
the position
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
getOutputInfo
+
+
+
+
+
+
+
+ Object
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
tells you info about an output connection (which node, type, etc)
+
+
+
+
+
+
Parameters:
+
+
+
+
+
+ slot
+ Number
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Returns:
+
+
+
+
+ Object :
+
+
+
+
+
+
+
+
+
+
+
+
getOutputNodes
+
+
+
+
+
+
+
+ Array
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
retrieves all the nodes connected to this output slot
+
+
+
+
+
+
Parameters:
+
+
+
+
+
+ slot
+ Number
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Returns:
+
+
+
+
+ Array :
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
isOutputConnected
+
+
+
+
+
+
+
+ Boolean
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
tells you if there is a connection in one output slot
+
+
+
+
+
+
Parameters:
+
+
+
+
+
+ slot
+ Number
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Returns:
+
+
+
+
+ Boolean :
+
+
+
+
+
+
+
+
+
+
+
+
isPointInsideNode
+
+
+
+
(
+
+
+
+ x
+
+
+
+
+
+ y
+
+
+
+ )
+
+
+
+
+
+ Boolean
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
checks if a point is inside the shape of a node
+
+
+
+
+
+
Parameters:
+
+
+
+
+
+ x
+ Number
+
+
+
+
+
+
+
+
+
+
+
+
+
+ y
+ Number
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Returns:
+
+
+
+
+ Boolean :
+
+
+
+
+
+
+
+
+
+
+
+
pin
+
+
+
()
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Forces the node to do not move or realign on Z
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
removeOutput
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
remove an existing output slot
+
+
+
+
+
+
Parameters:
+
+
+
+
+
+ slot
+ Number
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
serialize
+
+
+
()
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
serialize the content
+
+
+
+
+
+
+
+
+
+
+
+
+
setOutputData
+
+
+
+
(
+
+
+
+ slot
+
+
+
+
+
+ data
+
+
+
+ )
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
sets the output data
+
+
+
+
+
+
Parameters:
+
+
+
+
+
+ slot
+ Number
+
+
+
+
+
+
+
+
+
+
+
+
+
+ data
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
toString
+
+
+
()
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
serialize and stringify
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/doc/classes/LiteGraph.html b/doc/classes/LiteGraph.html
index f7132dbab..e2709b8d7 100644
--- a/doc/classes/LiteGraph.html
+++ b/doc/classes/LiteGraph.html
@@ -43,6 +43,8 @@
LGraph
+ LGraphCanvas
+
LGraphNode
LiteGraph
diff --git a/doc/data.json b/doc/data.json
index cfce2454f..ca7f52bba 100644
--- a/doc/data.json
+++ b/doc/data.json
@@ -7,7 +7,8 @@
"classes": {
"LiteGraph": 1,
"LGraph": 1,
- "LGraphNode": 1
+ "LGraphNode": 1,
+ "LGraphCanvas": 1
},
"fors": {},
"namespaces": {}
@@ -37,7 +38,7 @@
"plugin_for": [],
"extension_for": [],
"file": "../src/litegraph.js",
- "line": 302,
+ "line": 299,
"description": "LGraph is the class that contain a full graph. We instantiate one and add nodes to it, and then we can run the execution loop.",
"is_constructor": 1
},
@@ -50,7 +51,7 @@
"plugin_for": [],
"extension_for": [],
"file": "../src/litegraph.js",
- "line": 947,
+ "line": 997,
"description": "Base Class for all the node type classes",
"params": [
{
@@ -59,6 +60,31 @@
"type": "String"
}
]
+ },
+ "LGraphCanvas": {
+ "name": "LGraphCanvas",
+ "shortname": "LGraphCanvas",
+ "classitems": [],
+ "plugins": [],
+ "extensions": [],
+ "plugin_for": [],
+ "extension_for": [],
+ "file": "../src/litegraph.js",
+ "line": 1794,
+ "description": "The Global Scope. It contains all the registered node classes.",
+ "is_constructor": 1,
+ "params": [
+ {
+ "name": "canvas",
+ "description": "the canvas where you want to render (it accepts a selector in string format)",
+ "type": "HTMLCanvas"
+ },
+ {
+ "name": "graph",
+ "description": "",
+ "type": "LGraph"
+ }
+ ]
}
},
"classitems": [
@@ -159,7 +185,7 @@
},
{
"file": "../src/litegraph.js",
- "line": 321,
+ "line": 317,
"description": "Removes all nodes from this graph",
"itemtype": "method",
"name": "clear",
@@ -167,7 +193,37 @@
},
{
"file": "../src/litegraph.js",
- "line": 364,
+ "line": 361,
+ "description": "Attach Canvas to this graph",
+ "itemtype": "method",
+ "name": "attachCanvas",
+ "params": [
+ {
+ "name": "graph_canvas",
+ "description": "",
+ "type": "GraphCanvas"
+ }
+ ],
+ "class": "LGraph"
+ },
+ {
+ "file": "../src/litegraph.js",
+ "line": 380,
+ "description": "Detach Canvas from this graph",
+ "itemtype": "method",
+ "name": "detachCanvas",
+ "params": [
+ {
+ "name": "graph_canvas",
+ "description": "",
+ "type": "GraphCanvas"
+ }
+ ],
+ "class": "LGraph"
+ },
+ {
+ "file": "../src/litegraph.js",
+ "line": 394,
"description": "Starts running this graph every interval milliseconds.",
"itemtype": "method",
"name": "start",
@@ -182,15 +238,15 @@
},
{
"file": "../src/litegraph.js",
- "line": 391,
+ "line": 421,
"description": "Stops the execution loop of the graph",
"itemtype": "method",
- "name": "stop",
+ "name": "stop execution",
"class": "LGraph"
},
{
"file": "../src/litegraph.js",
- "line": 413,
+ "line": 443,
"description": "Run N steps (cycles) of the graph",
"itemtype": "method",
"name": "runStep",
@@ -205,7 +261,7 @@
},
{
"file": "../src/litegraph.js",
- "line": 457,
+ "line": 487,
"description": "Updates the graph execution order according to relevance of the nodes (nodes with only outputs have more relevance than\nnodes with only inputs.",
"itemtype": "method",
"name": "updateExecutionOrder",
@@ -213,7 +269,7 @@
},
{
"file": "../src/litegraph.js",
- "line": 553,
+ "line": 583,
"description": "Returns the amount of time the graph has been running in milliseconds",
"itemtype": "method",
"name": "getTime",
@@ -225,7 +281,7 @@
},
{
"file": "../src/litegraph.js",
- "line": 564,
+ "line": 594,
"description": "Returns the amount of time accumulated using the fixedtime_lapse var. This is used in context where the time increments should be constant",
"itemtype": "method",
"name": "getFixedTime",
@@ -237,7 +293,7 @@
},
{
"file": "../src/litegraph.js",
- "line": 575,
+ "line": 605,
"description": "Returns the amount of time it took to compute the latest iteration. Take into account that this number could be not correct\nif the nodes are using graphical actions",
"itemtype": "method",
"name": "getElapsedTime",
@@ -249,7 +305,7 @@
},
{
"file": "../src/litegraph.js",
- "line": 587,
+ "line": 617,
"description": "Sends an event to all the nodes, useful to trigger stuff",
"itemtype": "method",
"name": "sendEventToAllNodes",
@@ -269,7 +325,7 @@
},
{
"file": "../src/litegraph.js",
- "line": 602,
+ "line": 645,
"description": "Adds a new node instasnce to this graph",
"itemtype": "method",
"name": "add",
@@ -284,7 +340,7 @@
},
{
"file": "../src/litegraph.js",
- "line": 647,
+ "line": 690,
"description": "Removes a node from the graph",
"itemtype": "method",
"name": "remove",
@@ -299,7 +355,7 @@
},
{
"file": "../src/litegraph.js",
- "line": 708,
+ "line": 751,
"description": "Returns a node by its id.",
"itemtype": "method",
"name": "getNodeById",
@@ -314,7 +370,7 @@
},
{
"file": "../src/litegraph.js",
- "line": 721,
+ "line": 764,
"description": "Returns a list of nodes that matches a type",
"itemtype": "method",
"name": "findNodesByType",
@@ -333,7 +389,7 @@
},
{
"file": "../src/litegraph.js",
- "line": 737,
+ "line": 780,
"description": "Returns a list of nodes that matches a name",
"itemtype": "method",
"name": "findNodesByName",
@@ -352,7 +408,7 @@
},
{
"file": "../src/litegraph.js",
- "line": 753,
+ "line": 796,
"description": "Returns the top-most node in this position of the canvas",
"itemtype": "method",
"name": "getNodeOnPos",
@@ -381,7 +437,7 @@
},
{
"file": "../src/litegraph.js",
- "line": 774,
+ "line": 817,
"description": "Assigns a value to all the nodes that matches this name. This is used to create global variables of the node that\ncan be easily accesed from the outside of the graph",
"itemtype": "method",
"name": "setInputData",
@@ -401,7 +457,7 @@
},
{
"file": "../src/litegraph.js",
- "line": 789,
+ "line": 832,
"description": "Returns the value of the first node with this name. This is used to access global variables of the graph from the outside",
"itemtype": "method",
"name": "setInputData",
@@ -420,22 +476,30 @@
},
{
"file": "../src/litegraph.js",
- "line": 843,
- "description": "Creates a JSON String containing all the info about this graph",
+ "line": 869,
+ "description": "returns if the graph is in live mode",
+ "itemtype": "method",
+ "name": "isLive",
+ "class": "LGraph"
+ },
+ {
+ "file": "../src/litegraph.js",
+ "line": 893,
+ "description": "Creates a Object containing all the info about this graph, it can be serialized",
"itemtype": "method",
"name": "serialize",
"return": {
"description": "value of the node",
- "type": "String"
+ "type": "Object"
},
"class": "LGraph"
},
{
"file": "../src/litegraph.js",
- "line": 869,
+ "line": 920,
"description": "Configure a graph from a JSON string",
"itemtype": "method",
- "name": "unserialize",
+ "name": "configure",
"params": [
{
"name": "str",
@@ -444,6 +508,441 @@
}
],
"class": "LGraph"
+ },
+ {
+ "file": "../src/litegraph.js",
+ "line": 1026,
+ "description": "configure a node from an object",
+ "itemtype": "method",
+ "name": "configure",
+ "class": "LGraphNode"
+ },
+ {
+ "file": "../src/litegraph.js",
+ "line": 1073,
+ "description": "serialize the content",
+ "itemtype": "method",
+ "name": "serialize",
+ "class": "LGraphNode"
+ },
+ {
+ "file": "../src/litegraph.js",
+ "line": 1132,
+ "description": "serialize and stringify",
+ "itemtype": "method",
+ "name": "toString",
+ "class": "LGraphNode"
+ },
+ {
+ "file": "../src/litegraph.js",
+ "line": 1145,
+ "description": "sets the output data",
+ "itemtype": "method",
+ "name": "setOutputData",
+ "params": [
+ {
+ "name": "slot",
+ "description": "",
+ "type": "Number"
+ },
+ {
+ "name": "data",
+ "description": "",
+ "type": "*"
+ }
+ ],
+ "class": "LGraphNode"
+ },
+ {
+ "file": "../src/litegraph.js",
+ "line": 1161,
+ "description": "retrieves the input data from one slot",
+ "itemtype": "method",
+ "name": "getInputData",
+ "params": [
+ {
+ "name": "slot",
+ "description": "",
+ "type": "Number"
+ }
+ ],
+ "return": {
+ "description": "data",
+ "type": "*"
+ },
+ "class": "LGraphNode"
+ },
+ {
+ "file": "../src/litegraph.js",
+ "line": 1175,
+ "description": "tells you if there is a connection in one input slot",
+ "itemtype": "method",
+ "name": "isInputConnected",
+ "params": [
+ {
+ "name": "slot",
+ "description": "",
+ "type": "Number"
+ }
+ ],
+ "return": {
+ "description": "",
+ "type": "Boolean"
+ },
+ "class": "LGraphNode"
+ },
+ {
+ "file": "../src/litegraph.js",
+ "line": 1187,
+ "description": "tells you info about an input connection (which node, type, etc)",
+ "itemtype": "method",
+ "name": "getInputInfo",
+ "params": [
+ {
+ "name": "slot",
+ "description": "",
+ "type": "Number"
+ }
+ ],
+ "return": {
+ "description": "",
+ "type": "Object"
+ },
+ "class": "LGraphNode"
+ },
+ {
+ "file": "../src/litegraph.js",
+ "line": 1202,
+ "description": "tells you info about an output connection (which node, type, etc)",
+ "itemtype": "method",
+ "name": "getOutputInfo",
+ "params": [
+ {
+ "name": "slot",
+ "description": "",
+ "type": "Number"
+ }
+ ],
+ "return": {
+ "description": "",
+ "type": "Object"
+ },
+ "class": "LGraphNode"
+ },
+ {
+ "file": "../src/litegraph.js",
+ "line": 1217,
+ "description": "tells you if there is a connection in one output slot",
+ "itemtype": "method",
+ "name": "isOutputConnected",
+ "params": [
+ {
+ "name": "slot",
+ "description": "",
+ "type": "Number"
+ }
+ ],
+ "return": {
+ "description": "",
+ "type": "Boolean"
+ },
+ "class": "LGraphNode"
+ },
+ {
+ "file": "../src/litegraph.js",
+ "line": 1229,
+ "description": "retrieves all the nodes connected to this output slot",
+ "itemtype": "method",
+ "name": "getOutputNodes",
+ "params": [
+ {
+ "name": "slot",
+ "description": "",
+ "type": "Number"
+ }
+ ],
+ "return": {
+ "description": "",
+ "type": "Array"
+ },
+ "class": "LGraphNode"
+ },
+ {
+ "file": "../src/litegraph.js",
+ "line": 1258,
+ "description": "add a new output slot to use in this node",
+ "itemtype": "method",
+ "name": "addOutput",
+ "params": [
+ {
+ "name": "name",
+ "description": "",
+ "type": "String"
+ },
+ {
+ "name": "type",
+ "description": "string defining the output type (\"vec3\",\"number\",...)",
+ "type": "String"
+ },
+ {
+ "name": "extra_info",
+ "description": "this can be used to have special properties of an output (special color, position, etc)",
+ "type": "Object"
+ }
+ ],
+ "class": "LGraphNode"
+ },
+ {
+ "file": "../src/litegraph.js",
+ "line": 1277,
+ "description": "remove an existing output slot",
+ "itemtype": "method",
+ "name": "removeOutput",
+ "params": [
+ {
+ "name": "slot",
+ "description": "",
+ "type": "Number"
+ }
+ ],
+ "class": "LGraphNode"
+ },
+ {
+ "file": "../src/litegraph.js",
+ "line": 1289,
+ "description": "add a new input slot to use in this node",
+ "itemtype": "method",
+ "name": "addInput",
+ "params": [
+ {
+ "name": "name",
+ "description": "",
+ "type": "String"
+ },
+ {
+ "name": "type",
+ "description": "string defining the input type (\"vec3\",\"number\",...)",
+ "type": "String"
+ },
+ {
+ "name": "extra_info",
+ "description": "this can be used to have special properties of an input (special color, position, etc)",
+ "type": "Object"
+ }
+ ],
+ "class": "LGraphNode"
+ },
+ {
+ "file": "../src/litegraph.js",
+ "line": 1308,
+ "description": "remove an existing input slot",
+ "itemtype": "method",
+ "name": "removeInput",
+ "params": [
+ {
+ "name": "slot",
+ "description": "",
+ "type": "Number"
+ }
+ ],
+ "class": "LGraphNode"
+ },
+ {
+ "file": "../src/litegraph.js",
+ "line": 1320,
+ "description": "add an special connection to this node (used for special kinds of graphs)",
+ "itemtype": "method",
+ "name": "addConnection",
+ "params": [
+ {
+ "name": "name",
+ "description": "",
+ "type": "String"
+ },
+ {
+ "name": "type",
+ "description": "string defining the input type (\"vec3\",\"number\",...)",
+ "type": "String"
+ },
+ {
+ "name": "pos",
+ "description": "position of the connection inside the node",
+ "type": "[x,y]"
+ },
+ {
+ "name": "direction",
+ "description": "if is input or output",
+ "type": "String"
+ }
+ ],
+ "class": "LGraphNode"
+ },
+ {
+ "file": "../src/litegraph.js",
+ "line": 1333,
+ "description": "computes the size of a node according to its inputs and output slots",
+ "itemtype": "method",
+ "name": "computeSize",
+ "params": [
+ {
+ "name": "minHeight",
+ "description": "",
+ "type": "Number"
+ }
+ ],
+ "return": {
+ "description": "the total size",
+ "type": "Number"
+ },
+ "class": "LGraphNode"
+ },
+ {
+ "file": "../src/litegraph.js",
+ "line": 1351,
+ "description": "returns the bounding of the object, used for rendering purposes",
+ "itemtype": "method",
+ "name": "getBounding",
+ "return": {
+ "description": "the total size",
+ "type": "Float32Array[4]"
+ },
+ "class": "LGraphNode"
+ },
+ {
+ "file": "../src/litegraph.js",
+ "line": 1361,
+ "description": "checks if a point is inside the shape of a node",
+ "itemtype": "method",
+ "name": "isPointInsideNode",
+ "params": [
+ {
+ "name": "x",
+ "description": "",
+ "type": "Number"
+ },
+ {
+ "name": "y",
+ "description": "",
+ "type": "Number"
+ }
+ ],
+ "return": {
+ "description": "",
+ "type": "Boolean"
+ },
+ "class": "LGraphNode"
+ },
+ {
+ "file": "../src/litegraph.js",
+ "line": 1401,
+ "description": "connect this node output to the input of another node",
+ "itemtype": "method",
+ "name": "connect",
+ "params": [
+ {
+ "name": "slot",
+ "description": "(could be the number of the slot or the string with the name of the slot)",
+ "type": "Number_or_string"
+ },
+ {
+ "name": "node",
+ "description": "the target node",
+ "type": "LGraphNode"
+ },
+ {
+ "name": "target_slot",
+ "description": "the input slot of the target node (could be the number of the slot or the string with the name of the slot)",
+ "type": "Number_or_string"
+ }
+ ],
+ "return": {
+ "description": "if it was connected succesfully",
+ "type": "Boolean"
+ },
+ "class": "LGraphNode"
+ },
+ {
+ "file": "../src/litegraph.js",
+ "line": 1482,
+ "description": "disconnect one output to an specific node",
+ "itemtype": "method",
+ "name": "disconnectOutput",
+ "params": [
+ {
+ "name": "slot",
+ "description": "(could be the number of the slot or the string with the name of the slot)",
+ "type": "Number_or_string"
+ },
+ {
+ "name": "target_node",
+ "description": "the target node to which this slot is connected [Optional, if not target_node is specified all nodes will be disconnected]",
+ "type": "LGraphNode"
+ }
+ ],
+ "return": {
+ "description": "if it was disconnected succesfully",
+ "type": "Boolean"
+ },
+ "class": "LGraphNode"
+ },
+ {
+ "file": "../src/litegraph.js",
+ "line": 1545,
+ "description": "disconnect one input",
+ "itemtype": "method",
+ "name": "disconnectInput",
+ "params": [
+ {
+ "name": "slot",
+ "description": "(could be the number of the slot or the string with the name of the slot)",
+ "type": "Number_or_string"
+ }
+ ],
+ "return": {
+ "description": "if it was disconnected succesfully",
+ "type": "Boolean"
+ },
+ "class": "LGraphNode"
+ },
+ {
+ "file": "../src/litegraph.js",
+ "line": 1599,
+ "description": "returns the center of a connection point in canvas coords",
+ "itemtype": "method",
+ "name": "getConnectionPos",
+ "params": [
+ {
+ "name": "is_input",
+ "description": "true if if a input slot, false if it is an output",
+ "type": "Boolean"
+ },
+ {
+ "name": "slot",
+ "description": "(could be the number of the slot or the string with the name of the slot)",
+ "type": "Number_or_string"
+ }
+ ],
+ "return": {
+ "description": "the position",
+ "type": "[x,y]"
+ },
+ "class": "LGraphNode"
+ },
+ {
+ "file": "../src/litegraph.js",
+ "line": 1756,
+ "description": "Collapse the node to make it smaller on the canvas",
+ "itemtype": "method",
+ "name": "collapse",
+ "class": "LGraphNode"
+ },
+ {
+ "file": "../src/litegraph.js",
+ "line": 1769,
+ "description": "Forces the node to do not move or realign on Z",
+ "itemtype": "method",
+ "name": "pin",
+ "class": "LGraphNode"
}
],
"warnings": []
diff --git a/doc/files/.._src_litegraph.js.html b/doc/files/.._src_litegraph.js.html
index 49442c502..50a66387c 100644
--- a/doc/files/.._src_litegraph.js.html
+++ b/doc/files/.._src_litegraph.js.html
@@ -43,6 +43,8 @@
LGraph
+ LGraphCanvas
+
LGraphNode
LiteGraph
@@ -109,9 +111,10 @@ var LiteGraph = {
NODE_WIDTH: 140,
NODE_MIN_WIDTH: 50,
NODE_COLLAPSED_RADIUS: 10,
+ NODE_COLLAPSED_WIDTH: 80,
CANVAS_GRID_SIZE: 10,
- NODE_DEFAULT_COLOR: "#888",
- NODE_DEFAULT_BGCOLOR: "#333",
+ NODE_DEFAULT_COLOR: "#999",
+ NODE_DEFAULT_BGCOLOR: "#444",
NODE_DEFAULT_BOXCOLOR: "#AEF",
NODE_DEFAULT_SHAPE: "box",
MAX_NUMBER_OF_NODES: 1000, //avoid infinite loops
@@ -120,7 +123,6 @@ var LiteGraph = {
debug: false,
registered_node_types: {},
- graphs: [],
/**
* Register a node class so it can be listed when the user wants to create a new one
@@ -207,7 +209,7 @@ var LiteGraph = {
if( prototype[i].concat ) //array
node[i] = prototype[i].concat();
else if (typeof(prototype[i]) == 'object')
- node[i] = jQuery.extend({}, prototype[i]);
+ node[i] = LiteGraph.cloneObject(prototype[i]); //slow but safe
else
node[i] = prototype[i];
}
@@ -323,22 +325,19 @@ var LiteGraph = {
}
}
- for (var i in LiteGraph.graphs)
- {
- for (var j in LiteGraph.graphs[i].nodes)
- {
- var m = LiteGraph.graphs[i].nodes[j];
- var t = LiteGraph.getNodeType(n.type);
- if(!t) continue;
-
- for (var k in t)
- if( typeof(t[k]) == "function" )
- m[k] = t[k];
- }
- }
-
if(LiteGraph.debug)
console.log("Nodes reloaded");
+ },
+
+ //separated just to improve if it doesnt work
+ cloneObject: function(obj, target)
+ {
+ var r = JSON.parse( JSON.stringify( obj ) );
+ if(!target) return r;
+
+ for(var i in r)
+ target[i] = r[i];
+ return target;
}
/*
@@ -347,11 +346,11 @@ var LiteGraph = {
mode = mode || "all";
trace("Benchmarking " + mode + "...");
- trace(" Num. nodes: " + this.nodes.length );
+ trace(" Num. nodes: " + this._nodes.length );
var links = 0;
- for(var i in this.nodes)
- for(var j in this.nodes[i].outputs)
- if(this.nodes[i].outputs[j].node_id != null)
+ for(var i in this._nodes)
+ for(var j in this._nodes[i].outputs)
+ if(this._nodes[i].outputs[j].node_id != null)
links++;
trace(" Num. links: " + links );
@@ -402,8 +401,7 @@ function LGraph()
{
if (LiteGraph.debug)
console.log("Graph created");
- this.canvas = null;
- LiteGraph.graphs.push(this);
+ this.list_of_graphcanvas = null;
this.clear();
}
@@ -422,8 +420,8 @@ LGraph.prototype.clear = function()
this.last_node_id = 0;
//nodes
- this.nodes = [];
- this.nodes_by_id = {};
+ this._nodes = [];
+ this._nodes_by_id = {};
//links
this.last_link_id = 0;
@@ -433,8 +431,6 @@ LGraph.prototype.clear = function()
this.iteration = 0;
this.config = {
- canvas_offset: [0,0],
- canvas_scale: 1.0
};
//timing
@@ -445,12 +441,48 @@ LGraph.prototype.clear = function()
this.elapsed_time = 0.01;
this.starttime = 0;
+ //globals
+ this.globals = {};
+
this.graph = {};
this.debug = true;
this.change();
- if(this.canvas)
- this.canvas.clear();
+
+ this.sendActionToCanvas("clear");
+}
+
+/**
+* Attach Canvas to this graph
+* @method attachCanvas
+* @param {GraphCanvas} graph_canvas
+*/
+
+LGraph.prototype.attachCanvas = function(graphcanvas)
+{
+ if(graphcanvas.constructor != LGraphCanvas)
+ throw("attachCanvas expects a LGraphCanvas instance");
+ if(graphcanvas.graph && graphcanvas.graph != this)
+ graphcanvas.graph.detachCanvas( graphcanvas );
+
+ graphcanvas.graph = this;
+ if(!this.list_of_graphcanvas)
+ this.list_of_graphcanvas = [];
+ this.list_of_graphcanvas.push(graphcanvas);
+}
+
+/**
+* Detach Canvas from this graph
+* @method detachCanvas
+* @param {GraphCanvas} graph_canvas
+*/
+
+LGraph.prototype.detachCanvas = function(graphcanvas)
+{
+ var pos = this.list_of_graphcanvas.indexOf(graphcanvas);
+ if(pos == -1) return;
+ graphcanvas.graph = null;
+ this.list_of_graphcanvas.splice(pos,1);
}
/**
@@ -470,7 +502,7 @@ LGraph.prototype.start = function(interval)
this.sendEventToAllNodes("onStart");
//launch
- this.starttime = new Date().getTime();
+ this.starttime = window.performance.now();
interval = interval || 1;
var that = this;
@@ -482,7 +514,7 @@ LGraph.prototype.start = function(interval)
/**
* Stops the execution loop of the graph
-* @method stop
+* @method stop execution
*/
LGraph.prototype.stop = function()
@@ -512,7 +544,7 @@ LGraph.prototype.runStep = function(num)
{
num = num || 1;
- var start = new Date().getTime();
+ var start = window.performance.now();
this.globaltime = 0.001 * (start - this.starttime);
try
@@ -539,7 +571,7 @@ LGraph.prototype.runStep = function(num)
this.stop();
}
- var elapsed = (new Date().getTime()) - start;
+ var elapsed = window.performance.now() - start;
if (elapsed == 0) elapsed = 1;
this.elapsed_time = 0.001 * elapsed;
this.globaltime += 0.001 * elapsed;
@@ -554,7 +586,7 @@ LGraph.prototype.runStep = function(num)
LGraph.prototype.updateExecutionOrder = function()
{
- this.nodes_in_order = this.computeExecutionOrder();
+ this._nodes_in_order = this.computeExecutionOrder();
}
//This is more internal, it computes the order and returns it
@@ -567,9 +599,9 @@ LGraph.prototype.computeExecutionOrder = function()
var remaining_links = {}; //to a
//search for the nodes without inputs (starting nodes)
- for (var i in this.nodes)
+ for (var i in this._nodes)
{
- var n = this.nodes[i];
+ var n = this._nodes[i];
M[n.id] = n; //add to pending nodes
var num = 0; //num of input connections
@@ -631,7 +663,7 @@ LGraph.prototype.computeExecutionOrder = function()
for(var i in M)
L.push(M[i]);
- if(L.length != this.nodes.length && LiteGraph.debug)
+ if(L.length != this._nodes.length && LiteGraph.debug)
console.log("something went wrong, nodes missing");
//save order number in the node
@@ -685,12 +717,25 @@ LGraph.prototype.getElapsedTime = function()
LGraph.prototype.sendEventToAllNodes = function(eventname, param)
{
- var M = this.nodes_in_order ? this.nodes_in_order : this.nodes;
+ var M = this._nodes_in_order ? this._nodes_in_order : this._nodes;
for(var j in M)
if(M[j][eventname])
M[j][eventname](param);
}
+LGraph.prototype.sendActionToCanvas = function(action, params)
+{
+ if(!this.list_of_graphcanvas)
+ return;
+
+ for(var i in this.list_of_graphcanvas)
+ {
+ var c = this.list_of_graphcanvas[i];
+ if( c[action] )
+ c[action].apply(c, params);
+ }
+}
+
/**
* Adds a new node instasnce to this graph
* @method add
@@ -699,10 +744,10 @@ LGraph.prototype.sendEventToAllNodes = function(eventname, param)
LGraph.prototype.add = function(node)
{
- if(!node || (node.id != -1 && this.nodes_by_id[node.id] != null))
+ if(!node || (node.id != -1 && this._nodes_by_id[node.id] != null))
return; //already added
- if(this.nodes.length >= LiteGraph.MAX_NUMBER_OF_NODES)
+ if(this._nodes.length >= LiteGraph.MAX_NUMBER_OF_NODES)
throw("LiteGraph: max number of nodes in a graph reached");
//give him an id
@@ -711,8 +756,8 @@ LGraph.prototype.add = function(node)
node.graph = this;
- this.nodes.push(node);
- this.nodes_by_id[node.id] = node;
+ this._nodes.push(node);
+ this._nodes_by_id[node.id] = node;
/*
// rendering stuf...
@@ -744,7 +789,7 @@ LGraph.prototype.add = function(node)
LGraph.prototype.remove = function(node)
{
- if(this.nodes_by_id[node.id] == null)
+ if(this._nodes_by_id[node.id] == null)
return; //not found
if(node.ignore_remove)
@@ -784,10 +829,10 @@ LGraph.prototype.remove = function(node)
}
//remove from containers
- var pos = this.nodes.indexOf(node);
+ var pos = this._nodes.indexOf(node);
if(pos != -1)
- this.nodes.splice(pos,1);
- delete this.nodes_by_id[node.id];
+ this._nodes.splice(pos,1);
+ delete this._nodes_by_id[node.id];
if(this.canvas)
this.canvas.setDirty(true,true);
@@ -806,7 +851,7 @@ LGraph.prototype.remove = function(node)
LGraph.prototype.getNodeById = function(id)
{
if(id==null) return null;
- return this.nodes_by_id[id];
+ return this._nodes_by_id[id];
}
@@ -820,9 +865,9 @@ LGraph.prototype.getNodeById = function(id)
LGraph.prototype.findNodesByType = function(type)
{
var r = [];
- for(var i in this.nodes)
- if(this.nodes[i].type == type)
- r.push(this.nodes[i]);
+ for(var i in this._nodes)
+ if(this._nodes[i].type == type)
+ r.push(this._nodes[i]);
return r;
}
@@ -836,9 +881,9 @@ LGraph.prototype.findNodesByType = function(type)
LGraph.prototype.findNodesByName = function(name)
{
var result = [];
- for (var i in this.nodes)
- if(this.nodes[i].name == name)
- result.push(this.nodes[i]);
+ for (var i in this._nodes)
+ if(this._nodes[i].name == name)
+ result.push(this._nodes[i]);
return result;
}
@@ -853,7 +898,7 @@ LGraph.prototype.findNodesByName = function(name)
LGraph.prototype.getNodeOnPos = function(x,y, nodes_list)
{
- nodes_list = nodes_list || this.nodes;
+ nodes_list = nodes_list || this._nodes;
for (var i = nodes_list.length - 1; i >= 0; i--)
{
var n = nodes_list[i];
@@ -909,39 +954,46 @@ LGraph.prototype.setCallback = function(name,func)
m[i].setTrigger(func);
}
-//**********
-
LGraph.prototype.onConnectionChange = function()
{
this.updateExecutionOrder();
}
+/**
+* returns if the graph is in live mode
+* @method isLive
+*/
+
LGraph.prototype.isLive = function()
{
if(!this.canvas) return false;
return this.canvas.live_mode;
}
+/* Called when something visually changed */
LGraph.prototype.change = function()
{
if(LiteGraph.debug)
console.log("Graph changed");
+
+ this.sendActionToCanvas("setDirty",[true,true]);
+
if(this.on_change)
this.on_change(this);
}
//save and recover app state ***************************************
/**
-* Creates a JSON String containing all the info about this graph
+* Creates a Object containing all the info about this graph, it can be serialized
* @method serialize
-* @return {String} value of the node
+* @return {Object} value of the node
*/
LGraph.prototype.serialize = function()
{
var nodes_info = [];
- for (var i in this.nodes)
- nodes_info.push( this.nodes[i].objectivize() );
+ for (var i in this._nodes)
+ nodes_info.push( this._nodes[i].serialize() );
var data = {
graph: this.graph,
@@ -955,20 +1007,20 @@ LGraph.prototype.serialize = function()
nodes: nodes_info
};
- return JSON.stringify(data);
+ return data;
}
+
/**
* Configure a graph from a JSON string
-* @method unserialize
+* @method configure
* @param {String} str configure a graph from a JSON string
*/
-LGraph.prototype.unserialize = function(str, keep_old)
+LGraph.prototype.configure = function(data, keep_old)
{
if(!keep_old)
this.clear();
- var data = JSON.parse(str);
var nodes = data.nodes;
//copy all stored fields
@@ -978,7 +1030,7 @@ LGraph.prototype.unserialize = function(str, keep_old)
var error = false;
//create nodes
- this.nodes = [];
+ this._nodes = [];
for (var i in nodes)
{
var n_info = nodes[i]; //stored info
@@ -991,7 +1043,7 @@ LGraph.prototype.unserialize = function(str, keep_old)
continue;
}
- n.copyFromObject(n_info);
+ n.configure(n_info);
this.add(n);
}
@@ -1065,9 +1117,59 @@ function LGraphNode(name)
};
}
-//serialization *************************
+/**
+* configure a node from an object
+* @method configure
+*/
+LGraphNode.prototype.configure = function(info)
+{
+ for (var j in info)
+ {
+ if(j == "console") continue;
-LGraphNode.prototype.objectivize = function()
+ if(info[j] == null)
+ continue;
+ else if( info[j].concat ) //array
+ this[j] = info[j].concat();
+ else if (typeof(info[j]) == 'object') //object
+ this[j] = LiteGraph.cloneObject(info[j], this[j] || {} );
+ else //value
+ this[j] = info[j];
+ }
+}
+
+/* Copy all the info from one object to this node (used for serialization) */
+LGraphNode.prototype.copyFromObject = function(info, ignore_connections)
+{
+ var outputs = null;
+ var inputs = null;
+ var properties = null;
+ var local_data = null;
+
+ for (var j in info)
+ {
+ if(ignore_connections && (j == "outputs" || j == "inputs"))
+ continue;
+
+ if(j == "console") continue;
+
+ if(info[j] == null)
+ continue;
+ else if( info[j].concat ) //array
+ this[j] = info[j].concat();
+ else if (typeof(info[j]) == 'object') //object
+ this[j] = LiteGraph.cloneObject(info[j]);
+ else //value
+ this[j] = info[j];
+ }
+}
+
+/**
+* serialize the content
+* @method serialize
+*/
+
+LGraphNode.prototype.serialize = function()
{
var o = {
id: this.id,
@@ -1076,8 +1178,8 @@ LGraphNode.prototype.objectivize = function()
pos: this.pos,
size: this.size,
data: this.data,
- properties: jQuery.extend({}, this.properties),
- flags: jQuery.extend({}, this.flags),
+ properties: LiteGraph.cloneObject(this.properties),
+ flags: LiteGraph.cloneObject(this.flags),
inputs: this.inputs,
outputs: this.outputs
};
@@ -1094,10 +1196,14 @@ LGraphNode.prototype.objectivize = function()
if(this.shape)
o.shape = this.shape;
+ if(this.onSerialize)
+ this.onSerialize(o);
+
return o;
}
//reduced version of objectivize: NOT FINISHED
+/*
LGraphNode.prototype.reducedObjectivize = function()
{
var o = this.objectivize();
@@ -1115,19 +1221,27 @@ LGraphNode.prototype.reducedObjectivize = function()
return o;
}
+*/
+/**
+* serialize and stringify
+* @method toString
+*/
-LGraphNode.prototype.serialize = function()
+LGraphNode.prototype.toString = function()
{
- if(this.onSerialize)
- this.onSerialize();
- return JSON.stringify( this.reducedObjectivize() );
+ return JSON.stringify( this.serialize() );
}
//LGraphNode.prototype.unserialize = function(info) {} //this cannot be done from within, must be done in LiteGraph
// Execution *************************
-
+/**
+* sets the output data
+* @method setOutputData
+* @param {number} slot
+* @param {*} data
+*/
LGraphNode.prototype.setOutputData = function(slot,data)
{
if(!this.outputs) return;
@@ -1138,6 +1252,12 @@ LGraphNode.prototype.setOutputData = function(slot,data)
}
}
+/**
+* retrieves the input data from one slot
+* @method getInputData
+* @param {number} slot
+* @return {*} data
+*/
LGraphNode.prototype.getInputData = function(slot)
{
if(!this.inputs) return null;
@@ -1146,12 +1266,24 @@ LGraphNode.prototype.getInputData = function(slot)
return null;
}
+/**
+* tells you if there is a connection in one input slot
+* @method isInputConnected
+* @param {number} slot
+* @return {boolean}
+*/
LGraphNode.prototype.isInputConnected = function(slot)
{
if(!this.inputs) return null;
return (slot < this.inputs.length && this.inputs[slot].link != null);
}
+/**
+* tells you info about an input connection (which node, type, etc)
+* @method getInputInfo
+* @param {number} slot
+* @return {Object}
+*/
LGraphNode.prototype.getInputInfo = function(slot)
{
if(!this.inputs) return null;
@@ -1161,6 +1293,12 @@ LGraphNode.prototype.getInputInfo = function(slot)
}
+/**
+* tells you info about an output connection (which node, type, etc)
+* @method getOutputInfo
+* @param {number} slot
+* @return {Object}
+*/
LGraphNode.prototype.getOutputInfo = function(slot)
{
if(!this.outputs) return null;
@@ -1169,12 +1307,25 @@ LGraphNode.prototype.getOutputInfo = function(slot)
return null;
}
+
+/**
+* tells you if there is a connection in one output slot
+* @method isOutputConnected
+* @param {number} slot
+* @return {boolean}
+*/
LGraphNode.prototype.isOutputConnected = function(slot)
{
if(!this.outputs) return null;
return (slot < this.outputs.length && this.outputs[slot].links && this.outputs[slot].links.length);
}
+/**
+* retrieves all the nodes connected to this output slot
+* @method getOutputNodes
+* @param {number} slot
+* @return {array}
+*/
LGraphNode.prototype.getOutputNodes = function(slot)
{
if(!this.outputs || this.outputs.length == 0) return null;
@@ -1198,6 +1349,13 @@ LGraphNode.prototype.triggerOutput = function(slot,param)
//connections
+/**
+* add a new output slot to use in this node
+* @method addOutput
+* @param {string} name
+* @param {string} type string defining the output type ("vec3","number",...)
+* @param {Object} extra_info this can be used to have special properties of an output (special color, position, etc)
+*/
LGraphNode.prototype.addOutput = function(name,type,extra_info)
{
var o = {name:name,type:type,links:null};
@@ -1210,6 +1368,11 @@ LGraphNode.prototype.addOutput = function(name,type,extra_info)
this.size = this.computeSize();
}
+/**
+* remove an existing output slot
+* @method removeOutput
+* @param {number} slot
+*/
LGraphNode.prototype.removeOutput = function(slot)
{
this.disconnectOutput(slot);
@@ -1217,6 +1380,13 @@ LGraphNode.prototype.removeOutput = function(slot)
this.size = this.computeSize();
}
+/**
+* add a new input slot to use in this node
+* @method addInput
+* @param {string} name
+* @param {string} type string defining the input type ("vec3","number",...)
+* @param {Object} extra_info this can be used to have special properties of an input (special color, position, etc)
+*/
LGraphNode.prototype.addInput = function(name,type,extra_info)
{
var o = {name:name,type:type,link:null};
@@ -1229,6 +1399,11 @@ LGraphNode.prototype.addInput = function(name,type,extra_info)
this.size = this.computeSize();
}
+/**
+* remove an existing input slot
+* @method removeInput
+* @param {number} slot
+*/
LGraphNode.prototype.removeInput = function(slot)
{
this.disconnectInput(slot);
@@ -1236,13 +1411,25 @@ LGraphNode.prototype.removeInput = function(slot)
this.size = this.computeSize();
}
-//trigger connection
+/**
+* add an special connection to this node (used for special kinds of graphs)
+* @method addConnection
+* @param {string} name
+* @param {string} type string defining the input type ("vec3","number",...)
+* @param {[x,y]} pos position of the connection inside the node
+* @param {string} direction if is input or output
+*/
LGraphNode.prototype.addConnection = function(name,type,pos,direction)
{
this.connections.push( {name:name,type:type,pos:pos,direction:direction,links:null});
}
-
+/**
+* computes the size of a node according to its inputs and output slots
+* @method computeSize
+* @param {number} minHeight
+* @return {number} the total size
+*/
LGraphNode.prototype.computeSize = function(minHeight)
{
var rows = Math.max( this.inputs ? this.inputs.length : 1, this.outputs ? this.outputs.length : 1);
@@ -1255,19 +1442,30 @@ LGraphNode.prototype.computeSize = function(minHeight)
return size;
}
-//returns the bounding of the object, used for rendering purposes
+/**
+* returns the bounding of the object, used for rendering purposes
+* @method getBounding
+* @return {Float32Array[4]} the total size
+*/
LGraphNode.prototype.getBounding = function()
{
- return new Float32Array([this.pos[0] - 4, this.pos[1] - LGraph.NODE_TITLE_HEIGHT, this.pos[0] + this.size[0] + 4, this.pos[1] + this.size[1] + LGraph.NODE_TITLE_HEIGHT]);
+ return new Float32Array([this.pos[0] - 4, this.pos[1] - LiteGraph.NODE_TITLE_HEIGHT, this.pos[0] + this.size[0] + 4, this.pos[1] + this.size[1] + LGraph.NODE_TITLE_HEIGHT]);
}
-//checks if a point is inside the shape of a node
+/**
+* checks if a point is inside the shape of a node
+* @method isPointInsideNode
+* @param {number} x
+* @param {number} y
+* @return {boolean}
+*/
LGraphNode.prototype.isPointInsideNode = function(x,y)
{
var margin_top = this.graph.isLive() ? 0 : 20;
if(this.flags.collapsed)
{
- if ( distance([x,y], [this.pos[0] + this.size[0]*0.5, this.pos[1] + this.size[1]*0.5]) < LiteGraph.NODE_COLLAPSED_RADIUS)
+ //if ( distance([x,y], [this.pos[0] + this.size[0]*0.5, this.pos[1] + this.size[1]*0.5]) < LiteGraph.NODE_COLLAPSED_RADIUS)
+ if( isInsideRectangle(x,y, this.pos[0], this.pos[1] - LiteGraph.NODE_TITLE_HEIGHT, LiteGraph.NODE_COLLAPSED_WIDTH, LiteGraph.NODE_TITLE_HEIGHT) )
return true;
}
else if (this.pos[0] - 4 < x && (this.pos[0] + this.size[0] + 4) > x
@@ -1294,7 +1492,14 @@ LGraphNode.prototype.findOutputSlot = function(name)
return -1;
}
-//connect this node output to the input of another node
+/**
+* connect this node output to the input of another node
+* @method connect
+* @param {number_or_string} slot (could be the number of the slot or the string with the name of the slot)
+* @param {LGraphNode} node the target node
+* @param {number_or_string} target_slot the input slot of the target node (could be the number of the slot or the string with the name of the slot)
+* @return {boolean} if it was connected succesfully
+*/
LGraphNode.prototype.connect = function(slot, node, target_slot)
{
target_slot = target_slot || 0;
@@ -1368,6 +1573,13 @@ LGraphNode.prototype.connect = function(slot, node, target_slot)
return true;
}
+/**
+* disconnect one output to an specific node
+* @method disconnectOutput
+* @param {number_or_string} slot (could be the number of the slot or the string with the name of the slot)
+* @param {LGraphNode} target_node the target node to which this slot is connected [Optional, if not target_node is specified all nodes will be disconnected]
+* @return {boolean} if it was disconnected succesfully
+*/
LGraphNode.prototype.disconnectOutput = function(slot, target_node)
{
if( slot.constructor === String )
@@ -1424,6 +1636,12 @@ LGraphNode.prototype.disconnectOutput = function(slot, target_node)
return true;
}
+/**
+* disconnect one input
+* @method disconnectInput
+* @param {number_or_string} slot (could be the number of the slot or the string with the name of the slot)
+* @return {boolean} if it was disconnected succesfully
+*/
LGraphNode.prototype.disconnectInput = function(slot)
{
//seek for the output slot
@@ -1472,11 +1690,23 @@ LGraphNode.prototype.disconnectInput = function(slot)
return true;
}
-//returns the center of a connection point in canvas coords
+/**
+* returns the center of a connection point in canvas coords
+* @method getConnectionPos
+* @param {boolean} is_input true if if a input slot, false if it is an output
+* @param {number_or_string} slot (could be the number of the slot or the string with the name of the slot)
+* @return {[x,y]} the position
+**/
LGraphNode.prototype.getConnectionPos = function(is_input,slot_number)
{
if(this.flags.collapsed)
- return [this.pos[0] + this.size[0] * 0.5, this.pos[1] + this.size[1] * 0.5];
+ {
+ if(is_input)
+ return [this.pos[0], this.pos[1] - LiteGraph.NODE_TITLE_HEIGHT * 0.5];
+ else
+ return [this.pos[0] + LiteGraph.NODE_COLLAPSED_WIDTH, this.pos[1] - LiteGraph.NODE_TITLE_HEIGHT * 0.5];
+ //return [this.pos[0] + this.size[0] * 0.5, this.pos[1] + this.size[1] * 0.5];
+ }
if(is_input && slot_number == -1)
{
@@ -1493,331 +1723,6 @@ LGraphNode.prototype.getConnectionPos = function(is_input,slot_number)
return [this.pos[0] , this.pos[1] + 10 + slot_number * LiteGraph.NODE_SLOT_HEIGHT];
}
-/* Renders the LGraphNode on the canvas */
-LGraphNode.prototype.draw = function(ctx, canvasrender)
-{
- var glow = false;
-
- var color = this.color || LiteGraph.NODE_DEFAULT_COLOR;
- //if (this.selected) color = "#88F";
-
- var render_title = true;
- if(this.flags.skip_title_render || this.graph.isLive())
- render_title = false;
- if(this.mouseOver)
- render_title = true;
-
- //shadow and glow
- if (this.mouseOver) glow = true;
-
- if(this.selected)
- {
- /*
- ctx.shadowColor = "#EEEEFF";//glow ? "#AAF" : "#000";
- ctx.shadowOffsetX = 0;
- ctx.shadowOffsetY = 0;
- ctx.shadowBlur = 1;
- */
- }
- else if(canvasrender.render_shadows)
- {
- ctx.shadowColor = "#111";
- ctx.shadowOffsetX = 2;
- ctx.shadowOffsetY = 2;
- ctx.shadowBlur = 4;
- }
- else
- ctx.shadowColor = "transparent";
-
- //only render if it forces it to do it
- if(canvasrender.live_mode)
- {
- if(!this.flags.collapsed)
- {
- ctx.shadowColor = "transparent";
- if(this.onDrawBackground)
- this.onDrawBackground(ctx);
- if(this.onDrawForeground)
- this.onDrawForeground(ctx);
- }
-
- return;
- }
-
- //draw in collapsed form
- if(this.flags.collapsed)
- {
- if(!this.onDrawCollapsed || this.onDrawCollapsed(ctx) == false)
- this.drawNodeCollapsed(ctx,color,this.bgcolor);
- return;
- }
-
- //clip if required (mask)
- if(this.flags.clip_area)
- {
- ctx.save();
- if(this.shape == null || this.shape == "box")
- {
- ctx.beginPath();
- ctx.rect(0,0,this.size[0], this.size[1]);
- }
- else if (this.shape == "round")
- {
- ctx.roundRect(0,0,this.size[0], this.size[1],10);
- }
- else if (this.shape == "circle")
- {
- ctx.beginPath();
- ctx.arc(this.size[0] * 0.5, this.size[1] * 0.5,this.size[0] * 0.5, 0, Math.PI*2);
- }
- ctx.clip();
- }
-
- //draw shape
- this.drawNodeShape(ctx,color, this.bgcolor, !render_title, this.selected );
- ctx.shadowColor = "transparent";
-
- //connection slots
- ctx.textAlign = "left";
- ctx.font = "12px Arial";
-
- var render_text = this.graph.config.canvas_scale > 0.6;
-
- //input connection slots
- if(this.inputs)
- for(var i = 0; i < this.inputs.length; i++)
- {
- var slot = this.inputs[i];
-
- ctx.globalAlpha = 1.0;
- if (canvasrender.connecting_node != null && canvasrender.connecting_output.type != 0 && this.inputs[i].type != 0 && canvasrender.connecting_output.type != this.inputs[i].type)
- ctx.globalAlpha = 0.4;
-
- ctx.fillStyle = slot.link != null ? "#7F7" : "#AAA";
-
- var pos = this.getConnectionPos(true,i);
- pos[0] -= this.pos[0];
- pos[1] -= this.pos[1];
-
- ctx.beginPath();
-
- if (1 || slot.round)
- ctx.arc(pos[0],pos[1],4,0,Math.PI*2);
- //else
- // ctx.rect((pos[0] - 6) + 0.5, (pos[1] - 5) + 0.5,14,10);
-
- ctx.fill();
-
- //render name
- if(render_text)
- {
- var text = slot.label != null ? slot.label : slot.name;
- if(text)
- {
- ctx.fillStyle = color;
- ctx.fillText(text,pos[0] + 10,pos[1] + 5);
- }
- }
- }
-
- //output connection slots
- if(canvasrender.connecting_node)
- ctx.globalAlpha = 0.4;
-
- ctx.lineWidth = 1;
-
- ctx.textAlign = "right";
- ctx.strokeStyle = "black";
- if(this.outputs)
- for(var i = 0; i < this.outputs.length; i++)
- {
- var slot = this.outputs[i];
-
- var pos = this.getConnectionPos(false,i);
- pos[0] -= this.pos[0];
- pos[1] -= this.pos[1];
-
- ctx.fillStyle = slot.links && slot.links.length ? "#7F7" : "#AAA";
- ctx.beginPath();
- //ctx.rect( this.size[0] - 14,i*14,10,10);
-
- if (1 || slot.round)
- ctx.arc(pos[0],pos[1],4,0,Math.PI*2);
- //else
- // ctx.rect((pos[0] - 6) + 0.5,(pos[1] - 5) + 0.5,14,10);
-
- //trigger
- //if(slot.node_id != null && slot.slot == -1)
- // ctx.fillStyle = "#F85";
-
- //if(slot.links != null && slot.links.length)
- ctx.fill();
- ctx.stroke();
-
- //render output name
- if(render_text)
- {
- var text = slot.label != null ? slot.label : slot.name;
- if(text)
- {
- ctx.fillStyle = color;
- ctx.fillText(text, pos[0] - 10,pos[1] + 5);
- }
- }
- }
-
- ctx.textAlign = "left";
- ctx.globalAlpha = 1.0;
-
- if(this.onDrawForeground)
- this.onDrawForeground(ctx);
-
- if(this.flags.clip_area)
- ctx.restore();
-}
-
-/* Renders the node shape */
-LGraphNode.prototype.drawNodeShape = function(ctx, fgcolor, bgcolor, no_title, selected )
-{
- //bg rect
- ctx.strokeStyle = fgcolor || LiteGraph.NODE_DEFAULT_COLOR;
- ctx.fillStyle = bgcolor || LiteGraph.NODE_DEFAULT_BGCOLOR;
-
- /* gradient test
- var grad = ctx.createLinearGradient(0,0,0,this.size[1]);
- grad.addColorStop(0, "#AAA");
- grad.addColorStop(0.5, fgcolor || LiteGraph.NODE_DEFAULT_COLOR);
- grad.addColorStop(1, bgcolor || LiteGraph.NODE_DEFAULT_BGCOLOR);
- ctx.fillStyle = grad;
- */
-
- var title_height = LiteGraph.NODE_TITLE_HEIGHT;
-
- //render depending on shape
- if(this.shape == null || this.shape == "box")
- {
- if(selected)
- {
- ctx.strokeStyle = "#CCC";
- ctx.strokeRect(-0.5,no_title ? -0.5 : -title_height + -0.5,this.size[0]+2, no_title ? (this.size[1]+2) : (this.size[1] + title_height+2) );
- ctx.strokeStyle = fgcolor;
- }
-
- ctx.beginPath();
- ctx.rect(0.5,no_title ? 0.5 : -title_height + 0.5,this.size[0], no_title ? this.size[1] : this.size[1] + title_height);
- }
- else if (this.shape == "round")
- {
- ctx.roundRect(0,no_title ? 0 : -title_height,this.size[0], no_title ? this.size[1] : this.size[1] + title_height, 10);
- }
- else if (this.shape == "circle")
- {
- ctx.beginPath();
- ctx.arc(this.size[0] * 0.5, this.size[1] * 0.5,this.size[0] * 0.5, 0, Math.PI*2);
- }
-
- ctx.fill();
- ctx.shadowColor = "transparent";
- ctx.stroke();
-
- //image
- if (this.bgImage && this.bgImage.width)
- ctx.drawImage( this.bgImage, (this.size[0] - this.bgImage.width) * 0.5 , (this.size[1] - this.bgImage.height) * 0.5);
-
- if(this.bgImageUrl && !this.bgImage)
- this.bgImage = this.loadImage(this.bgImageUrl);
-
- if(this.onDrawBackground)
- this.onDrawBackground(ctx);
-
- //title bg
- if(!no_title)
- {
- ctx.fillStyle = fgcolor || LiteGraph.NODE_DEFAULT_COLOR;
-
- if(this.shape == null || this.shape == "box")
- {
- ctx.fillRect(0,-title_height,this.size[0],title_height);
- ctx.stroke();
- }
- else if (this.shape == "round")
- {
- ctx.roundRect(0,-title_height,this.size[0], title_height,10,0);
- //ctx.fillRect(0,8,this.size[0],NODE_TITLE_HEIGHT - 12);
- ctx.fill();
- ctx.stroke();
- }
-
- //box
- ctx.fillStyle = this.boxcolor || LiteGraph.NODE_DEFAULT_BOXCOLOR;
- ctx.beginPath();
- if (this.shape == "round")
- ctx.arc(title_height *0.5, title_height * -0.5, (title_height - 6) *0.5,0,Math.PI*2);
- else
- ctx.rect(3,-title_height + 3,title_height - 6,title_height - 6);
- ctx.fill();
-
- //title text
- ctx.font = "bold 12px Arial";
- if(this.name != "" && this.graph.config.canvas_scale > 0.8)
- {
- ctx.fillStyle = "#222";
- ctx.fillText(this.name,16,13-title_height );
- }
- }
-}
-
-/* Renders the node when collapsed */
-LGraphNode.prototype.drawNodeCollapsed = function(ctx, fgcolor, bgcolor)
-{
- //draw default collapsed shape
- ctx.strokeStyle = fgcolor || LiteGraph.NODE_DEFAULT_COLOR;
- ctx.fillStyle = bgcolor || LiteGraph.NODE_DEFAULT_BGCOLOR;
-
- var collapsed_radius = LiteGraph.NODE_COLLAPSED_RADIUS;
-
- //circle shape
- if(this.shape == "circle")
- {
- ctx.beginPath();
- ctx.arc(this.size[0] * 0.5, this.size[1] * 0.5, collapsed_radius,0,Math.PI * 2);
- ctx.fill();
- ctx.shadowColor = "rgba(0,0,0,0)";
- ctx.stroke();
-
- ctx.fillStyle = this.boxcolor || LiteGraph.NODE_DEFAULT_BOXCOLOR;
- ctx.beginPath();
- ctx.arc(this.size[0] * 0.5, this.size[1] * 0.5, collapsed_radius * 0.5,0,Math.PI * 2);
- ctx.fill();
- }
- else if(this.shape == "round") //rounded box
- {
- ctx.beginPath();
- ctx.roundRect(this.size[0] * 0.5 - collapsed_radius, this.size[1] * 0.5 - collapsed_radius, 2*collapsed_radius,2*collapsed_radius,5);
- ctx.fill();
- ctx.shadowColor = "rgba(0,0,0,0)";
- ctx.stroke();
-
- ctx.fillStyle = this.boxcolor || LiteGraph.NODE_DEFAULT_BOXCOLOR;
- ctx.beginPath();
- ctx.roundRect(this.size[0] * 0.5 - collapsed_radius*0.5, this.size[1] * 0.5 - collapsed_radius*0.5, collapsed_radius,collapsed_radius,2);
- ctx.fill();
- }
- else //flat box
- {
- ctx.beginPath();
- ctx.rect(this.size[0] * 0.5 - collapsed_radius, this.size[1] * 0.5 - collapsed_radius, 2*collapsed_radius,2*collapsed_radius);
- ctx.fill();
- ctx.shadowColor = "rgba(0,0,0,0)";
- ctx.stroke();
-
- ctx.fillStyle = this.boxcolor || LiteGraph.NODE_DEFAULT_BOXCOLOR;
- ctx.beginPath();
- ctx.rect(this.size[0] * 0.5 - collapsed_radius*0.5, this.size[1] * 0.5 - collapsed_radius*0.5, collapsed_radius,collapsed_radius);
- ctx.fill();
- }
-}
-
/* Force align to grid */
LGraphNode.prototype.alignToGrid = function()
{
@@ -1825,50 +1730,6 @@ LGraphNode.prototype.alignToGrid = function()
this.pos[1] = LiteGraph.CANVAS_GRID_SIZE * Math.round(this.pos[1] / LiteGraph.CANVAS_GRID_SIZE);
}
-/* Copy all the info from one object to this node (used for serialization) */
-LGraphNode.prototype.copyFromObject = function(info, ignore_connections)
-{
- var outputs = null;
- var inputs = null;
- var properties = null;
- var local_data = null;
-
- for (var j in info)
- {
- if(ignore_connections && (j == "outputs" || j == "inputs"))
- continue;
-
- if(j == "console") continue;
-
- if(info[j] == null)
- continue;
- else if( info[j].concat ) //array
- this[j] = info[j].concat();
- else if (typeof(info[j]) == 'object') //object
- this[j] = jQuery.extend({}, info[j]);
- else //value
- this[j] = info[j];
- }
-
- //redo the connections
- /*
- if(outputs)
- this.outputs = outputs.concat();
- if(inputs)
- this.inputs = inputs.concat();
-
- if(local_data)
- this.data = local_data;
- if(properties)
- {
- //copy only the ones defined
- for (var j in properties)
- if (this.properties[j] != null)
- this.properties[j] = properties[j];
- }
- */
-}
-
/* Creates a clone of this node */
LGraphNode.prototype.clone = function()
{
@@ -1908,13 +1769,9 @@ LGraphNode.prototype.trace = function(msg)
/* Forces to redraw or the main canvas (LGraphNode) or the bg canvas (links) */
LGraphNode.prototype.setDirtyCanvas = function(dirty_foreground, dirty_background)
{
- if(!this.graph || !this.graph.canvas)
+ if(!this.graph)
return;
-
- if(dirty_foreground)
- this.graph.canvas.dirty_canvas = true;
- if(dirty_background)
- this.graph.canvas.dirty_bgcanvas = true;
+ this.graph.sendActionToCanvas("setDirty",[dirty_foreground, dirty_background]);
}
LGraphNode.prototype.loadImage = function(url)
@@ -1971,20 +1828,29 @@ LGraphNode.prototype.executeAction = function(action)
/* Allows to get onMouseMove and onMouseUp events even if the mouse is out of focus */
LGraphNode.prototype.captureInput = function(v)
{
- if(!this.graph || !this.graph.canvas)
+ if(!this.graph || !this.graph.list_of_graphcanvas)
return;
- //releasing somebody elses capture?!
- if(!v && this.graph.canvas.node_capturing_input != this)
- return;
+ var list = this.graph.list_of_graphcanvas;
- //change
- this.graph.canvas.node_capturing_input = v ? this : null;
- if(this.graph.debug)
- console.log(this.name + ": Capturing input " + (v?"ON":"OFF"));
+ for(var i in list)
+ {
+ var c = list[i];
+ //releasing somebody elses capture?!
+ if(!v && c.node_capturing_input != this)
+ continue;
+
+ //change
+ c.node_capturing_input = v ? this : null;
+ if(this.graph.debug)
+ console.log(this.name + ": Capturing input " + (v?"ON":"OFF"));
+ }
}
-/* Collapse the node */
+/**
+* Collapse the node to make it smaller on the canvas
+* @method collapse
+**/
LGraphNode.prototype.collapse = function()
{
if(!this.flags.collapsed)
@@ -1994,19 +1860,23 @@ LGraphNode.prototype.collapse = function()
this.setDirtyCanvas(true,true);
}
-/* Forces the node to do not move or realign on Z */
-LGraphNode.prototype.pin = function()
+/**
+* Forces the node to do not move or realign on Z
+* @method pin
+**/
+
+LGraphNode.prototype.pin = function(v)
{
- if(!this.flags.pinned)
- this.flags.pinned = true;
+ if(v === undefined)
+ this.flags.pinned = !this.flags.pinned;
else
- this.flags.pinned = false;
+ this.flags.pinned = v;
}
-LGraphNode.prototype.localToScreen = function(x,y)
+LGraphNode.prototype.localToScreen = function(x,y, graphcanvas)
{
- return [(x + this.pos[0]) * this.graph.config.canvas_scale + this.graph.config.canvas_offset[0],
- (y + this.pos[1]) * this.graph.config.canvas_scale + this.graph.config.canvas_offset[1]];
+ return [(x + this.pos[0]) * graphcanvas.scale + graphcanvas.offset[0],
+ (y + this.pos[1]) * graphcanvas.scale + graphcanvas.offset[1]];
}
@@ -2015,27 +1885,28 @@ LGraphNode.prototype.localToScreen = function(x,y)
// LGraphCanvas: LGraph renderer CLASS
//*********************************************************************************
+/**
+* The Global Scope. It contains all the registered node classes.
+*
+* @class LGraphCanvas
+* @constructor
+* @param {HTMLCanvas} canvas the canvas where you want to render (it accepts a selector in string format)
+* @param {LGraph} graph
+*/
function LGraphCanvas(canvas, graph)
{
- if(graph === undefined)
- throw ("No graph assigned");
+ //if(graph === undefined)
+ // throw ("No graph assigned");
- if( typeof(window) != "undefined" )
- {
- window.requestAnimFrame = (function(){
- return window.requestAnimationFrame ||
- window.webkitRequestAnimationFrame ||
- window.mozRequestAnimationFrame ||
- function( callback ){
- window.setTimeout(callback, 1000 / 60);
- };
- })();
- }
+ if(typeof(canvas) == "string")
+ canvas = document.querySelector(canvas);
+
+ if(!canvas)
+ throw("no canvas found");
//link canvas and graph
- this.graph = graph;
if(graph)
- graph.canvas = this;
+ graph.attachCanvas(this);
this.setCanvas(canvas);
this.clear();
@@ -2044,7 +1915,6 @@ function LGraphCanvas(canvas, graph)
}
LGraphCanvas.link_type_colors = {'number':"#AAC",'node':"#DCA"};
-LGraphCanvas.link_width = 2;
LGraphCanvas.prototype.clear = function()
{
@@ -2053,6 +1923,9 @@ LGraphCanvas.prototype.clear = function()
this.render_time = 0;
this.fps = 0;
+ this.scale = 1;
+ this.offset = [0,0];
+
this.selected_nodes = {};
this.node_dragged = null;
this.node_over = null;
@@ -2060,6 +1933,7 @@ LGraphCanvas.prototype.clear = function()
this.connecting_node = null;
this.highquality_render = true;
+ this.editor_alpha = 1; //used for transition
this.pause_rendering = false;
this.render_shadows = true;
this.dirty_canvas = true;
@@ -2077,6 +1951,16 @@ LGraphCanvas.prototype.clear = function()
this.last_mouse = [0,0];
this.last_mouseclick = 0;
+ this.title_text_font = "bold 14px Arial";
+ this.inner_text_font = "normal 12px Arial";
+
+ this.render_connections_shadows = false; //too much cpu
+ this.render_connections_border = true;
+ this.render_curved_connections = true;
+ this.render_connection_arrows = true;
+
+ this.connections_width = 4;
+
if(this.onClear) this.onClear();
//this.UIinit();
}
@@ -2084,29 +1968,25 @@ LGraphCanvas.prototype.clear = function()
LGraphCanvas.prototype.setGraph = function(graph)
{
if(this.graph == graph) return;
-
this.clear();
+
+ if(!graph && this.graph)
+ {
+ this.graph.detachCanvas(this);
+ return;
+ }
+
+ /*
if(this.graph)
this.graph.canvas = null; //remove old graph link to the canvas
this.graph = graph;
if(this.graph)
this.graph.canvas = this;
+ */
+ graph.attachCanvas(this);
this.setDirty(true,true);
}
-LGraphCanvas.prototype.resize = function(width, height)
-{
- if(this.canvas.width == width && this.canvas.height == height)
- return;
-
- this.canvas.width = width;
- this.canvas.height = height;
- this.bgcanvas.width = this.canvas.width;
- this.bgcanvas.height = this.canvas.height;
- this.setDirty(true,true);
-}
-
-
LGraphCanvas.prototype.setCanvas = function(canvas)
{
var that = this;
@@ -2231,6 +2111,13 @@ LGraphCanvas.prototype.setDirty = function(fgcanvas,bgcanvas)
this.dirty_bgcanvas = true;
}
+//Used to attach the canvas in a popup
+LGraphCanvas.prototype.getCanvasWindow = function()
+{
+ var doc = this.canvas.ownerDocument;
+ return doc.defaultView || doc.parentWindow;
+}
+
LGraphCanvas.prototype.startRendering = function()
{
if(this.is_rendering) return; //already rendering
@@ -2243,8 +2130,9 @@ LGraphCanvas.prototype.startRendering = function()
if(!this.pause_rendering)
this.draw();
+ var window = this.getCanvasWindow();
if(this.is_rendering)
- window.requestAnimFrame( renderFrame.bind(this) );
+ window.requestAnimationFrame( renderFrame.bind(this) );
}
@@ -2276,9 +2164,12 @@ LGraphCanvas.prototype.processMouseDown = function(e)
this.adjustMouseEvent(e);
+ var ref_window = this.getCanvasWindow();
+ var document = ref_window.document;
+
this.canvas.removeEventListener("mousemove", this._mousemove_callback );
- document.addEventListener("mousemove", this._mousemove_callback );
- document.addEventListener("mouseup", this._mouseup_callback );
+ ref_window.document.addEventListener("mousemove", this._mousemove_callback ); //catch for the entire window
+ ref_window.document.addEventListener("mouseup", this._mouseup_callback );
var n = this.graph.getNodeOnPos(e.canvasX, e.canvasY, this.visible_nodes);
var skip_dragging = false;
@@ -2359,7 +2250,7 @@ LGraphCanvas.prototype.processMouseDown = function(e)
var block_drag_node = false;
//double clicking
- var now = new Date().getTime();
+ var now = window.performance.now();
if ((now - this.last_mouseclick) < 300 && this.selected_nodes[n.id])
{
//double click node
@@ -2414,7 +2305,7 @@ LGraphCanvas.prototype.processMouseDown = function(e)
this.last_mouse[0] = e.localX;
this.last_mouse[1] = e.localY;
- this.last_mouseclick = new Date().getTime();
+ this.last_mouseclick = window.performance.now();
this.canvas_mouse = [e.canvasX, e.canvasY];
/*
@@ -2425,7 +2316,7 @@ LGraphCanvas.prototype.processMouseDown = function(e)
this.graph.change();
//this is to ensure to defocus(blur) if a text input element is on focus
- if(!document.activeElement || (document.activeElement.nodeName.toLowerCase() != "input" && document.activeElement.nodeName.toLowerCase() != "textarea"))
+ if(!ref_window.document.activeElement || (ref_window.document.activeElement.nodeName.toLowerCase() != "input" && ref_window.document.activeElement.nodeName.toLowerCase() != "textarea"))
e.preventDefault();
e.stopPropagation();
return false;
@@ -2443,8 +2334,8 @@ LGraphCanvas.prototype.processMouseMove = function(e)
if(this.dragging_canvas)
{
- this.graph.config.canvas_offset[0] += delta[0] / this.graph.config.canvas_scale;
- this.graph.config.canvas_offset[1] += delta[1] / this.graph.config.canvas_scale;
+ this.offset[0] += delta[0] / this.scale;
+ this.offset[1] += delta[1] / this.scale;
this.dirty_canvas = true;
this.dirty_bgcanvas = true;
}
@@ -2457,12 +2348,12 @@ LGraphCanvas.prototype.processMouseMove = function(e)
var n = this.graph.getNodeOnPos(e.canvasX, e.canvasY, this.visible_nodes);
//remove mouseover flag
- for(var i in this.graph.nodes)
+ for(var i in this.graph._nodes)
{
- if(this.graph.nodes[i].mouseOver && n != this.graph.nodes[i])
+ if(this.graph._nodes[i].mouseOver && n != this.graph._nodes[i])
{
//mouse leave
- this.graph.nodes[i].mouseOver = false;
+ this.graph._nodes[i].mouseOver = false;
if(this.node_over && this.node_over.onMouseLeave)
this.node_over.onMouseLeave(e);
this.node_over = null;
@@ -2519,8 +2410,8 @@ LGraphCanvas.prototype.processMouseMove = function(e)
if(this.node_dragged && !this.live_mode)
{
/*
- this.node_dragged.pos[0] += delta[0] / this.graph.config.canvas_scale;
- this.node_dragged.pos[1] += delta[1] / this.graph.config.canvas_scale;
+ this.node_dragged.pos[0] += delta[0] / this.scale;
+ this.node_dragged.pos[1] += delta[1] / this.scale;
this.node_dragged.pos[0] = Math.round(this.node_dragged.pos[0]);
this.node_dragged.pos[1] = Math.round(this.node_dragged.pos[1]);
*/
@@ -2529,8 +2420,8 @@ LGraphCanvas.prototype.processMouseMove = function(e)
{
var n = this.selected_nodes[i];
- n.pos[0] += delta[0] / this.graph.config.canvas_scale;
- n.pos[1] += delta[1] / this.graph.config.canvas_scale;
+ n.pos[0] += delta[0] / this.scale;
+ n.pos[1] += delta[1] / this.scale;
n.pos[0] = Math.round(n.pos[0]);
n.pos[1] = Math.round(n.pos[1]);
}
@@ -2541,8 +2432,8 @@ LGraphCanvas.prototype.processMouseMove = function(e)
if(this.resizing_node && !this.live_mode)
{
- this.resizing_node.size[0] += delta[0] / this.graph.config.canvas_scale;
- this.resizing_node.size[1] += delta[1] / this.graph.config.canvas_scale;
+ this.resizing_node.size[0] += delta[0] / this.scale;
+ this.resizing_node.size[1] += delta[1] / this.scale;
var max_slots = Math.max( this.resizing_node.inputs ? this.resizing_node.inputs.length : 0, this.resizing_node.outputs ? this.resizing_node.outputs.length : 0);
if(this.resizing_node.size[1] < max_slots * LiteGraph.NODE_SLOT_HEIGHT + 4)
this.resizing_node.size[1] = max_slots * LiteGraph.NODE_SLOT_HEIGHT + 4;
@@ -2571,6 +2462,9 @@ LGraphCanvas.prototype.processMouseUp = function(e)
{
if(!this.graph) return;
+ var window = this.getCanvasWindow();
+ var document = window.document;
+
document.removeEventListener("mousemove", this._mousemove_callback, true );
this.canvas.addEventListener("mousemove", this._mousemove_callback, true);
document.removeEventListener("mouseup", this._mouseup_callback, true );
@@ -2736,7 +2630,7 @@ LGraphCanvas.prototype.processMouseWheel = function(e)
this.adjustMouseEvent(e);
- var zoom = this.graph.config.canvas_scale;
+ var zoom = this.scale;
if (delta > 0)
zoom *= 1.1;
@@ -2821,13 +2715,13 @@ LGraphCanvas.prototype.selectNode = function(node)
LGraphCanvas.prototype.selectAllNodes = function()
{
- for(var i in this.graph.nodes)
+ for(var i in this.graph._nodes)
{
- var n = this.graph.nodes[i];
+ var n = this.graph._nodes[i];
if(!n.selected && n.onSelected)
n.onSelected();
n.selected = true;
- this.selected_nodes[this.graph.nodes[i].id] = n;
+ this.selected_nodes[this.graph._nodes[i].id] = n;
}
this.setDirty(true);
@@ -2860,8 +2754,8 @@ LGraphCanvas.prototype.deleteSelectedNodes = function()
LGraphCanvas.prototype.centerOnNode = function(node)
{
- this.graph.config.canvas_offset[0] = -node.pos[0] - node.size[0] * 0.5 + (this.canvas.width * 0.5 / this.graph.config.canvas_scale);
- this.graph.config.canvas_offset[1] = -node.pos[1] - node.size[1] * 0.5 + (this.canvas.height * 0.5 / this.graph.config.canvas_scale);
+ this.offset[0] = -node.pos[0] - node.size[0] * 0.5 + (this.canvas.width * 0.5 / this.scale);
+ this.offset[1] = -node.pos[1] - node.size[1] * 0.5 + (this.canvas.height * 0.5 / this.scale);
this.setDirty(true,true);
}
@@ -2871,8 +2765,8 @@ LGraphCanvas.prototype.adjustMouseEvent = function(e)
e.localX = e.pageX - b.left;
e.localY = e.pageY - b.top;
- e.canvasX = e.localX / this.graph.config.canvas_scale - this.graph.config.canvas_offset[0];
- e.canvasY = e.localY / this.graph.config.canvas_scale - this.graph.config.canvas_offset[1];
+ e.canvasX = e.localX / this.scale - this.offset[0];
+ e.canvasY = e.localY / this.scale - this.offset[1];
}
LGraphCanvas.prototype.setZoom = function(value, zooming_center)
@@ -2882,18 +2776,18 @@ LGraphCanvas.prototype.setZoom = function(value, zooming_center)
var center = this.convertOffsetToCanvas( zooming_center );
- this.graph.config.canvas_scale = value;
+ this.scale = value;
- if(this.graph.config.canvas_scale > 4)
- this.graph.config.canvas_scale = 4;
- else if(this.graph.config.canvas_scale < 0.1)
- this.graph.config.canvas_scale = 0.1;
+ if(this.scale > 4)
+ this.scale = 4;
+ else if(this.scale < 0.1)
+ this.scale = 0.1;
var new_center = this.convertOffsetToCanvas( zooming_center );
var delta_offset = [new_center[0] - center[0], new_center[1] - center[1]];
- this.graph.config.canvas_offset[0] += delta_offset[0];
- this.graph.config.canvas_offset[1] += delta_offset[1];
+ this.offset[0] += delta_offset[0];
+ this.offset[1] += delta_offset[1];
this.dirty_canvas = true;
this.dirty_bgcanvas = true;
@@ -2901,13 +2795,13 @@ LGraphCanvas.prototype.setZoom = function(value, zooming_center)
LGraphCanvas.prototype.convertOffsetToCanvas = function(pos)
{
- return [pos[0] / this.graph.config.canvas_scale - this.graph.config.canvas_offset[0], pos[1] / this.graph.config.canvas_scale - this.graph.config.canvas_offset[1]];
+ return [pos[0] / this.scale - this.offset[0], pos[1] / this.scale - this.offset[1]];
}
LGraphCanvas.prototype.convertCanvasToOffset = function(pos)
{
- return [(pos[0] + this.graph.config.canvas_offset[0]) * this.graph.config.canvas_scale,
- (pos[1] + this.graph.config.canvas_offset[1]) * this.graph.config.canvas_scale ];
+ return [(pos[0] + this.offset[0]) * this.scale,
+ (pos[1] + this.offset[1]) * this.scale ];
}
LGraphCanvas.prototype.convertEventToCanvas = function(e)
@@ -2918,20 +2812,20 @@ LGraphCanvas.prototype.convertEventToCanvas = function(e)
LGraphCanvas.prototype.bringToFront = function(n)
{
- var i = this.graph.nodes.indexOf(n);
+ var i = this.graph._nodes.indexOf(n);
if(i == -1) return;
- this.graph.nodes.splice(i,1);
- this.graph.nodes.push(n);
+ this.graph._nodes.splice(i,1);
+ this.graph._nodes.push(n);
}
LGraphCanvas.prototype.sendToBack = function(n)
{
- var i = this.graph.nodes.indexOf(n);
+ var i = this.graph._nodes.indexOf(n);
if(i == -1) return;
- this.graph.nodes.splice(i,1);
- this.graph.nodes.unshift(n);
+ this.graph._nodes.splice(i,1);
+ this.graph._nodes.unshift(n);
}
/* Interaction */
@@ -2943,9 +2837,9 @@ LGraphCanvas.prototype.sendToBack = function(n)
LGraphCanvas.prototype.computeVisibleNodes = function()
{
var visible_nodes = [];
- for (var i in this.graph.nodes)
+ for (var i in this.graph._nodes)
{
- var n = this.graph.nodes[i];
+ var n = this.graph._nodes[i];
//skip rendering nodes in live mode
if(this.live_mode && !n.onDrawBackground && !n.onDrawForeground)
@@ -2962,14 +2856,14 @@ LGraphCanvas.prototype.computeVisibleNodes = function()
LGraphCanvas.prototype.draw = function(force_canvas, force_bgcanvas)
{
//fps counting
- var now = new Date().getTime();
+ var now = window.performance.now();
this.render_time = (now - this.last_draw_time)*0.001;
this.last_draw_time = now;
if(this.graph)
{
- var start = [-this.graph.config.canvas_offset[0], -this.graph.config.canvas_offset[1] ];
- var end = [start[0] + this.canvas.width / this.graph.config.canvas_scale, start[1] + this.canvas.height / this.graph.config.canvas_scale];
+ var start = [-this.offset[0], -this.offset[1] ];
+ var end = [start[0] + this.canvas.width / this.scale, start[1] + this.canvas.height / this.scale];
this.visible_area = new Float32Array([start[0],start[1],end[0],end[1]]);
}
@@ -3028,8 +2922,8 @@ LGraphCanvas.prototype.drawFrontCanvas = function()
{
//apply transformations
ctx.save();
- ctx.scale(this.graph.config.canvas_scale,this.graph.config.canvas_scale);
- ctx.translate(this.graph.config.canvas_offset[0],this.graph.config.canvas_offset[1]);
+ ctx.scale(this.scale,this.scale);
+ ctx.translate(this.offset[0],this.offset[1]);
//draw nodes
var drawn_nodes = 0;
@@ -3038,14 +2932,14 @@ LGraphCanvas.prototype.drawFrontCanvas = function()
for (var i in visible_nodes)
{
- var n = visible_nodes[i];
+ var node = visible_nodes[i];
//transform coords system
ctx.save();
- ctx.translate( n.pos[0], n.pos[1] );
+ ctx.translate( node.pos[0], node.pos[1] );
//Draw
- n.draw(ctx,this);
+ this.drawNode(node, ctx );
drawn_nodes += 1;
//Restore
@@ -3060,10 +2954,9 @@ LGraphCanvas.prototype.drawFrontCanvas = function()
//current connection
if(this.connecting_pos != null)
{
- ctx.lineWidth = LGraphCanvas.link_width;
- ctx.fillStyle = this.connecting_output.type == 'node' ? "#F85" : "#AFA";
- ctx.strokeStyle = ctx.fillStyle;
- this.renderLink(ctx, this.connecting_pos, [this.canvas_mouse[0],this.canvas_mouse[1]] );
+ ctx.lineWidth = this.connections_width;
+ var link_color = this.connecting_output.type == 'node' ? "#F85" : "#AFA";
+ this.renderLink(ctx, this.connecting_pos, [this.canvas_mouse[0],this.canvas_mouse[1]], link_color );
ctx.beginPath();
ctx.arc( this.connecting_pos[0], this.connecting_pos[1],4,0,Math.PI*2);
@@ -3112,13 +3005,13 @@ LGraphCanvas.prototype.drawBgcanvas = function()
{
//apply transformations
ctx.save();
- ctx.scale(this.graph.config.canvas_scale,this.graph.config.canvas_scale);
- ctx.translate(this.graph.config.canvas_offset[0],this.graph.config.canvas_offset[1]);
+ ctx.scale(this.scale,this.scale);
+ ctx.translate(this.offset[0],this.offset[1]);
//render BG
- if(this.background_image && this.graph.config.canvas_scale > 0.5)
+ if(this.background_image && this.scale > 0.5)
{
- ctx.globalAlpha = 1.0 - 0.5 / this.graph.config.canvas_scale;
+ ctx.globalAlpha = (1.0 - 0.5 / this.scale) * this.editor_alpha;
ctx.webkitImageSmoothingEnabled = ctx.mozImageSmoothingEnabled = ctx.imageSmoothingEnabled = false
if(!this._bg_img || this._bg_img.name != this.background_image)
{
@@ -3158,8 +3051,7 @@ LGraphCanvas.prototype.drawBgcanvas = function()
ctx.strokeStyle = "#235";
ctx.strokeRect(0,0,canvas.width,canvas.height);
- /*
- if(this.render_shadows)
+ if(this.render_connections_shadows)
{
ctx.shadowColor = "#000";
ctx.shadowOffsetX = 0;
@@ -3168,12 +3060,13 @@ LGraphCanvas.prototype.drawBgcanvas = function()
}
else
ctx.shadowColor = "rgba(0,0,0,0)";
- */
//draw connections
if(!this.live_mode)
this.drawConnections(ctx);
+ ctx.shadowColor = "rgba(0,0,0,0)";
+
//restore state
ctx.restore();
}
@@ -3182,19 +3075,370 @@ LGraphCanvas.prototype.drawBgcanvas = function()
this.dirty_canvas = true; //to force to repaint the front canvas with the bgcanvas
}
+/* Renders the LGraphNode on the canvas */
+LGraphCanvas.prototype.drawNode = function(node, ctx )
+{
+ var glow = false;
+
+ var color = node.color || LiteGraph.NODE_DEFAULT_COLOR;
+ //if (this.selected) color = "#88F";
+
+ var render_title = true;
+ if(node.flags.skip_title_render || node.graph.isLive())
+ render_title = false;
+ if(node.mouseOver)
+ render_title = true;
+
+ //shadow and glow
+ if (node.mouseOver) glow = true;
+
+ if(node.selected)
+ {
+ /*
+ ctx.shadowColor = "#EEEEFF";//glow ? "#AAF" : "#000";
+ ctx.shadowOffsetX = 0;
+ ctx.shadowOffsetY = 0;
+ ctx.shadowBlur = 1;
+ */
+ }
+ else if(this.render_shadows)
+ {
+ ctx.shadowColor = "#111";
+ ctx.shadowOffsetX = 2;
+ ctx.shadowOffsetY = 2;
+ ctx.shadowBlur = 4;
+ }
+ else
+ ctx.shadowColor = "transparent";
+
+ //only render if it forces it to do it
+ if(this.live_mode)
+ {
+ if(!node.flags.collapsed)
+ {
+ ctx.shadowColor = "transparent";
+ //if(node.onDrawBackground)
+ // node.onDrawBackground(ctx);
+ if(node.onDrawForeground)
+ node.onDrawForeground(ctx);
+ }
+
+ return;
+ }
+
+ //draw in collapsed form
+ /*
+ if(node.flags.collapsed)
+ {
+ if(!node.onDrawCollapsed || node.onDrawCollapsed(ctx) == false)
+ this.drawNodeCollapsed(node, ctx, color, node.bgcolor);
+ return;
+ }
+ */
+
+ var editor_alpha = this.editor_alpha;
+ ctx.globalAlpha = editor_alpha;
+
+ //clip if required (mask)
+ var shape = node.shape || "box";
+ var size = new Float32Array(node.size);
+ if(node.flags.collapsed)
+ size.set([LiteGraph.NODE_COLLAPSED_WIDTH, 0]);
+
+ //Start clipping
+ if(node.flags.clip_area)
+ {
+ ctx.save();
+ if(shape == "box")
+ {
+ ctx.beginPath();
+ ctx.rect(0,0,size[0], size[1]);
+ }
+ else if (shape == "round")
+ {
+ ctx.roundRect(0,0,size[0], size[1],10);
+ }
+ else if (shape == "circle")
+ {
+ ctx.beginPath();
+ ctx.arc(size[0] * 0.5, size[1] * 0.5, size[0] * 0.5, 0, Math.PI*2);
+ }
+ ctx.clip();
+ }
+
+ //draw shape
+ this.drawNodeShape(node, ctx, size, color, node.bgcolor, !render_title, node.selected );
+ ctx.shadowColor = "transparent";
+
+ //connection slots
+ ctx.textAlign = "left";
+ ctx.font = this.inner_text_font;
+
+ var render_text = this.scale > 0.6;
+
+ //render inputs and outputs
+ if(!node.flags.collapsed)
+ {
+ //input connection slots
+ if(node.inputs)
+ for(var i = 0; i < node.inputs.length; i++)
+ {
+ var slot = node.inputs[i];
+
+ ctx.globalAlpha = editor_alpha;
+ if (this.connecting_node != null && this.connecting_output.type != 0 && node.inputs[i].type != 0 && this.connecting_output.type != node.inputs[i].type)
+ ctx.globalAlpha = 0.4 * editor_alpha;
+
+ ctx.fillStyle = slot.link != null ? "#7F7" : "#AAA";
+
+ var pos = node.getConnectionPos(true,i);
+ pos[0] -= node.pos[0];
+ pos[1] -= node.pos[1];
+
+ ctx.beginPath();
+
+ if (1 || slot.round)
+ ctx.arc(pos[0],pos[1],4,0,Math.PI*2);
+ //else
+ // ctx.rect((pos[0] - 6) + 0.5, (pos[1] - 5) + 0.5,14,10);
+
+ ctx.fill();
+
+ //render name
+ if(render_text)
+ {
+ var text = slot.label != null ? slot.label : slot.name;
+ if(text)
+ {
+ ctx.fillStyle = color;
+ ctx.fillText(text,pos[0] + 10,pos[1] + 5);
+ }
+ }
+ }
+
+ //output connection slots
+ if(this.connecting_node)
+ ctx.globalAlpha = 0.4 * editor_alpha;
+
+ ctx.lineWidth = 1;
+
+ ctx.textAlign = "right";
+ ctx.strokeStyle = "black";
+ if(node.outputs)
+ for(var i = 0; i < node.outputs.length; i++)
+ {
+ var slot = node.outputs[i];
+
+ var pos = node.getConnectionPos(false,i);
+ pos[0] -= node.pos[0];
+ pos[1] -= node.pos[1];
+
+ ctx.fillStyle = slot.links && slot.links.length ? "#7F7" : "#AAA";
+ ctx.beginPath();
+ //ctx.rect( node.size[0] - 14,i*14,10,10);
+
+ if (1 || slot.round)
+ ctx.arc(pos[0],pos[1],4,0,Math.PI*2);
+ //else
+ // ctx.rect((pos[0] - 6) + 0.5,(pos[1] - 5) + 0.5,14,10);
+
+ //trigger
+ //if(slot.node_id != null && slot.slot == -1)
+ // ctx.fillStyle = "#F85";
+
+ //if(slot.links != null && slot.links.length)
+ ctx.fill();
+ ctx.stroke();
+
+ //render output name
+ if(render_text)
+ {
+ var text = slot.label != null ? slot.label : slot.name;
+ if(text)
+ {
+ ctx.fillStyle = color;
+ ctx.fillText(text, pos[0] - 10,pos[1] + 5);
+ }
+ }
+ }
+
+ ctx.textAlign = "left";
+ ctx.globalAlpha = 1;
+
+ if(node.onDrawForeground)
+ node.onDrawForeground(ctx);
+ }//!collapsed
+
+ if(node.flags.clip_area)
+ ctx.restore();
+
+ ctx.globalAlpha = 1.0;
+}
+
+/* Renders the node shape */
+LGraphCanvas.prototype.drawNodeShape = function(node, ctx, size, fgcolor, bgcolor, no_title, selected )
+{
+ //bg rect
+ ctx.strokeStyle = fgcolor || LiteGraph.NODE_DEFAULT_COLOR;
+ ctx.fillStyle = bgcolor || LiteGraph.NODE_DEFAULT_BGCOLOR;
+
+ /* gradient test
+ var grad = ctx.createLinearGradient(0,0,0,node.size[1]);
+ grad.addColorStop(0, "#AAA");
+ grad.addColorStop(0.5, fgcolor || LiteGraph.NODE_DEFAULT_COLOR);
+ grad.addColorStop(1, bgcolor || LiteGraph.NODE_DEFAULT_BGCOLOR);
+ ctx.fillStyle = grad;
+ //*/
+
+ var title_height = LiteGraph.NODE_TITLE_HEIGHT;
+
+ //render depending on shape
+ var shape = node.shape || "box";
+ if(shape == "box")
+ {
+ if(selected)
+ {
+ ctx.strokeStyle = "#CCC";
+ ctx.strokeRect(-0.5,no_title ? -0.5 : -title_height + -0.5, size[0]+2, no_title ? (size[1]+2) : (size[1] + title_height+2) );
+ ctx.strokeStyle = fgcolor;
+ }
+
+ ctx.beginPath();
+ ctx.rect(0,no_title ? 0.5 : -title_height + 0.5,size[0]+1, no_title ? size[1] : size[1] + title_height);
+ }
+ else if (node.shape == "round")
+ {
+ ctx.roundRect(0,no_title ? 0 : -title_height,size[0], no_title ? size[1] : size[1] + title_height, 10);
+ }
+ else if (node.shape == "circle")
+ {
+ ctx.beginPath();
+ ctx.arc(size[0] * 0.5, size[1] * 0.5, size[0] * 0.5, 0, Math.PI*2);
+ }
+
+ ctx.fill();
+ ctx.shadowColor = "transparent";
+
+ //ctx.stroke();
+
+ //image
+ if (node.bgImage && node.bgImage.width)
+ ctx.drawImage( node.bgImage, (size[0] - node.bgImage.width) * 0.5 , (size[1] - node.bgImage.height) * 0.5);
+
+ if(node.bgImageUrl && !node.bgImage)
+ node.bgImage = node.loadImage(node.bgImageUrl);
+
+ if(node.onDrawBackground)
+ node.onDrawBackground(ctx);
+
+ //title bg
+ if(!no_title)
+ {
+ ctx.fillStyle = fgcolor || LiteGraph.NODE_DEFAULT_COLOR;
+ var old_alpha = ctx.globalAlpha;
+ ctx.globalAlpha = 0.5 * old_alpha;
+ if(shape == "box")
+ {
+ ctx.beginPath();
+ ctx.fillRect(0,-title_height,size[0]+1,title_height);
+ ctx.stroke();
+ }
+ else if (shape == "round")
+ {
+ ctx.roundRect(0,-title_height,size[0], title_height,10,0);
+ //ctx.fillRect(0,8,size[0],NODE_TITLE_HEIGHT - 12);
+ ctx.fill();
+ ctx.stroke();
+ }
+
+ //box
+ ctx.fillStyle = node.boxcolor || LiteGraph.NODE_DEFAULT_BOXCOLOR;
+ ctx.beginPath();
+ if (shape == "round")
+ ctx.arc(title_height *0.5, title_height * -0.5, (title_height - 6) *0.5,0,Math.PI*2);
+ else
+ ctx.rect(3,-title_height + 3,title_height - 6,title_height - 6);
+ ctx.fill();
+ ctx.globalAlpha = old_alpha;
+
+ //title text
+ ctx.font = this.title_text_font;
+ if(node.name != "" && this.scale > 0.8)
+ {
+ ctx.fillStyle = "#222";
+ ctx.fillText(node.name,16,13-title_height );
+ }
+ }
+}
+
+/* Renders the node when collapsed */
+LGraphCanvas.prototype.drawNodeCollapsed = function(node, ctx, fgcolor, bgcolor)
+{
+ //draw default collapsed shape
+ ctx.strokeStyle = fgcolor || LiteGraph.NODE_DEFAULT_COLOR;
+ ctx.fillStyle = bgcolor || LiteGraph.NODE_DEFAULT_BGCOLOR;
+
+ var collapsed_radius = LiteGraph.NODE_COLLAPSED_RADIUS;
+
+ //circle shape
+ var shape = node.shape || "box";
+ if(shape == "circle")
+ {
+ ctx.beginPath();
+ ctx.arc(node.size[0] * 0.5, node.size[1] * 0.5, collapsed_radius,0,Math.PI * 2);
+ ctx.fill();
+ ctx.shadowColor = "rgba(0,0,0,0)";
+ ctx.stroke();
+
+ ctx.fillStyle = node.boxcolor || LiteGraph.NODE_DEFAULT_BOXCOLOR;
+ ctx.beginPath();
+ ctx.arc(node.size[0] * 0.5, node.size[1] * 0.5, collapsed_radius * 0.5,0,Math.PI * 2);
+ ctx.fill();
+ }
+ else if(shape == "round") //rounded box
+ {
+ ctx.beginPath();
+ ctx.roundRect(node.size[0] * 0.5 - collapsed_radius, node.size[1] * 0.5 - collapsed_radius, 2*collapsed_radius,2*collapsed_radius,5);
+ ctx.fill();
+ ctx.shadowColor = "rgba(0,0,0,0)";
+ ctx.stroke();
+
+ ctx.fillStyle = node.boxcolor || LiteGraph.NODE_DEFAULT_BOXCOLOR;
+ ctx.beginPath();
+ ctx.roundRect(node.size[0] * 0.5 - collapsed_radius*0.5, node.size[1] * 0.5 - collapsed_radius*0.5, collapsed_radius,collapsed_radius,2);
+ ctx.fill();
+ }
+ else //flat box
+ {
+ ctx.beginPath();
+ //ctx.rect(node.size[0] * 0.5 - collapsed_radius, node.size[1] * 0.5 - collapsed_radius, 2*collapsed_radius, 2*collapsed_radius);
+ ctx.rect(0, 0, node.size[0], collapsed_radius * 2 );
+ ctx.fill();
+ ctx.shadowColor = "rgba(0,0,0,0)";
+ ctx.stroke();
+
+ ctx.fillStyle = node.boxcolor || LiteGraph.NODE_DEFAULT_BOXCOLOR;
+ ctx.beginPath();
+ //ctx.rect(node.size[0] * 0.5 - collapsed_radius*0.5, node.size[1] * 0.5 - collapsed_radius*0.5, collapsed_radius,collapsed_radius);
+ ctx.rect(collapsed_radius*0.5, collapsed_radius*0.5, collapsed_radius, collapsed_radius);
+ ctx.fill();
+ }
+}
+
LGraphCanvas.link_colors = ["#AAC","#ACA","#CAA"];
LGraphCanvas.prototype.drawConnections = function(ctx)
{
//draw connections
- ctx.lineWidth = LGraphCanvas.link_width;
+ ctx.lineWidth = this.connections_width;
ctx.fillStyle = "#AAA";
ctx.strokeStyle = "#AAA";
+ ctx.globalAlpha = this.editor_alpha;
//for every node
- for (var n in this.graph.nodes)
+ for (var n in this.graph._nodes)
{
- var node = this.graph.nodes[n];
+ var node = this.graph._nodes[n];
//for every input (we render just inputs because it is easier as every slot can only have one input)
if(node.inputs && node.inputs.length)
for(var i in node.inputs)
@@ -3216,16 +3460,14 @@ LGraphCanvas.prototype.drawConnections = function(ctx)
var color = LGraphCanvas.link_type_colors[node.inputs[i].type];
if(color == null)
color = LGraphCanvas.link_colors[node.id % LGraphCanvas.link_colors.length];
- ctx.fillStyle = ctx.strokeStyle = color;
- this.renderLink(ctx, start_node_slotpos, node.getConnectionPos(true,i) );
+ this.renderLink(ctx, start_node_slotpos, node.getConnectionPos(true,i), color );
}
}
+ ctx.globalAlpha = 1;
}
-LGraphCanvas.prototype.renderLink = function(ctx,a,b)
+LGraphCanvas.prototype.renderLink = function(ctx,a,b,color)
{
- var curved_lines = true;
-
if(!this.highquality_render)
{
ctx.beginPath();
@@ -3237,32 +3479,44 @@ LGraphCanvas.prototype.renderLink = function(ctx,a,b)
var dist = distance(a,b);
+ if(this.render_connections_border)
+ ctx.lineWidth = this.connections_width + 4;
+
ctx.beginPath();
- if(curved_lines)
+ if(this.render_curved_connections) //splines
{
ctx.moveTo(a[0],a[1]);
ctx.bezierCurveTo(a[0] + dist*0.25, a[1],
b[0] - dist*0.25 , b[1],
b[0] ,b[1] );
}
- else
+ else //lines
{
ctx.moveTo(a[0]+10,a[1]);
ctx.lineTo(((a[0]+10) + (b[0]-10))*0.5,a[1]);
ctx.lineTo(((a[0]+10) + (b[0]-10))*0.5,b[1]);
ctx.lineTo(b[0]-10,b[1]);
}
+
+ if(this.render_connections_border)
+ {
+ ctx.strokeStyle = "rgba(0,0,0,0.5)";
+ ctx.stroke();
+ }
+
+ ctx.lineWidth = this.connections_width;
+ ctx.fillStyle = ctx.strokeStyle = color;
ctx.stroke();
//render arrow
- if(this.graph.config.canvas_scale > 0.6)
+ if(this.render_connection_arrows && this.scale > 0.6)
{
//get two points in the bezier curve
var pos = this.computeConnectionPoint(a,b,0.5);
var pos2 = this.computeConnectionPoint(a,b,0.51);
var angle = 0;
- if(curved_lines)
+ if(this.render_curved_connections)
angle = -Math.atan2( pos2[0] - pos[0], pos2[1] - pos[1]);
else
angle = b[1] > a[1] ? 0 : Math.PI;
@@ -3297,6 +3551,7 @@ LGraphCanvas.prototype.computeConnectionPoint = function(a,b,t)
return [x,y];
}
+/*
LGraphCanvas.prototype.resizeCanvas = function(width,height)
{
this.canvas.width = width;
@@ -3307,12 +3562,63 @@ LGraphCanvas.prototype.resizeCanvas = function(width,height)
this.bgcanvas.height = this.canvas.height;
this.draw(true,true);
}
+*/
-LGraphCanvas.prototype.switchLiveMode = function()
+LGraphCanvas.prototype.resize = function(width, height)
{
- this.live_mode = !this.live_mode;
- this.dirty_canvas = true;
- this.dirty_bgcanvas = true;
+ if(!width && !height)
+ {
+ var parent = this.canvas.parentNode;
+ width = parent.offsetWidth;
+ height = parent.offsetHeight;
+ }
+
+ if(this.canvas.width == width && this.canvas.height == height)
+ return;
+
+ this.canvas.width = width;
+ this.canvas.height = height;
+ this.bgcanvas.width = this.canvas.width;
+ this.bgcanvas.height = this.canvas.height;
+ this.setDirty(true,true);
+}
+
+
+LGraphCanvas.prototype.switchLiveMode = function(transition)
+{
+ if(!transition)
+ {
+ this.live_mode = !this.live_mode;
+ this.dirty_canvas = true;
+ this.dirty_bgcanvas = true;
+ return;
+ }
+
+ var self = this;
+ var delta = this.live_mode ? 1.1 : 0.9;
+ if(this.live_mode)
+ {
+ this.live_mode = false;
+ this.editor_alpha = 0.1;
+ }
+
+ var t = setInterval(function() {
+ self.editor_alpha *= delta;
+ self.dirty_canvas = true;
+ self.dirty_bgcanvas = true;
+
+ if(delta < 1 && self.editor_alpha < 0.01)
+ {
+ clearInterval(t);
+ if(delta < 1)
+ self.live_mode = true;
+ }
+ if(delta > 1 && self.editor_alpha > 0.99)
+ {
+ clearInterval(t);
+ self.editor_alpha = 1;
+ }
+ },1);
}
LGraphCanvas.prototype.onNodeSelectionChange = function(node)
@@ -3339,6 +3645,9 @@ LGraphCanvas.prototype.touchHandler = function(event)
//initMouseEvent(type, canBubble, cancelable, view, clickCount,
// screenX, screenY, clientX, clientY, ctrlKey,
// altKey, shiftKey, metaKey, button, relatedTarget);
+
+ var window = this.getCanvasWindow();
+ var document = window.document;
var simulatedEvent = document.createEvent("MouseEvent");
simulatedEvent.initMouseEvent(type, true, true, window, 1,
@@ -3353,13 +3662,15 @@ LGraphCanvas.prototype.touchHandler = function(event)
LGraphCanvas.onMenuAdd = function(node, e, prev_menu, canvas, first_event )
{
+ var window = canvas.getCanvasWindow();
+
var values = LiteGraph.getNodeTypesCategories();
var entries = {};
for(var i in values)
if(values[i])
entries[ i ] = { value: values[i], content: values[i] , is_menu: true };
- var menu = LiteGraph.createContextualMenu(entries, {event: e, callback: inner_clicked, from: prev_menu});
+ var menu = LiteGraph.createContextualMenu(entries, {event: e, callback: inner_clicked, from: prev_menu}, window);
function inner_clicked(v, e)
{
@@ -3369,7 +3680,7 @@ LGraphCanvas.onMenuAdd = function(node, e, prev_menu, canvas, first_event )
for(var i in node_types)
values.push( { content: node_types[i].title, value: node_types[i].type });
- LiteGraph.createContextualMenu(values, {event: e, callback: inner_create, from: menu});
+ LiteGraph.createContextualMenu(values, {event: e, callback: inner_create, from: menu}, window);
return false;
}
@@ -3450,7 +3761,19 @@ LGraphCanvas.onMenuNodeOutputs = function(node, e, prev_menu)
function inner_clicked(v)
{
if(!node) return;
- node.addOutput(v.value[0],v.value[1]);
+
+ var value = v.value[1];
+
+ if(value && (value.constructor === Object || value.constructor === Array)) //submenu
+ {
+ var entries = [];
+ for(var i in value)
+ entries.push({content: i, value: value[i]});
+ LiteGraph.createContextualMenu(entries, {event: e, callback: inner_clicked, from: prev_menu});
+ return false;
+ }
+ else
+ node.addOutput(v.value[0],v.value[1]);
}
return false;
@@ -3462,6 +3785,11 @@ LGraphCanvas.onMenuNodeCollapse = function(node)
node.graph.canvas.setDirty(true,true);
}
+LGraphCanvas.onMenuNodePin = function(node)
+{
+ node.pin();
+}
+
LGraphCanvas.onMenuNodeColors = function(node, e, prev_menu)
{
var values = [];
@@ -3490,7 +3818,7 @@ LGraphCanvas.onMenuNodeColors = function(node, e, prev_menu)
LGraphCanvas.onMenuNodeShapes = function(node,e)
{
- LiteGraph.createContextualMenu(["box","round","circle"], {event: e, callback: inner_clicked});
+ LiteGraph.createContextualMenu(["box","round"], {event: e, callback: inner_clicked});
function inner_clicked(v)
{
@@ -3541,6 +3869,7 @@ LGraphCanvas.prototype.getNodeMenuOptions = function(node)
{content:"Outputs", is_menu: true, disabled:true, callback: LGraphCanvas.onMenuNodeOutputs },
null,
{content:"Collapse", callback: LGraphCanvas.onMenuNodeCollapse },
+ {content:"Pin", callback: LGraphCanvas.onMenuNodePin },
{content:"Colors", is_menu: true, callback: LGraphCanvas.onMenuNodeColors },
{content:"Shapes", is_menu: true, callback: LGraphCanvas.onMenuNodeShapes },
null,
@@ -3565,7 +3894,9 @@ LGraphCanvas.prototype.getNodeMenuOptions = function(node)
LGraphCanvas.prototype.processContextualMenu = function(node,event)
{
var that = this;
- var menu = LiteGraph.createContextualMenu(node ? this.getNodeMenuOptions(node) : this.getCanvasMenuOptions(), {event: event, callback: inner_option_clicked});
+ var win = this.getCanvasWindow();
+
+ var menu = LiteGraph.createContextualMenu(node ? this.getNodeMenuOptions(node) : this.getCanvasMenuOptions(), {event: event, callback: inner_option_clicked}, win);
function inner_option_clicked(v,e)
{
@@ -3701,15 +4032,18 @@ function num2hex(triplet) {
/* LiteGraph GUI elements *************************************/
-LiteGraph.createContextualMenu = function(values,options)
+LiteGraph.createContextualMenu = function(values,options, ref_window)
{
options = options || {};
this.options = options;
+ //allows to create graph canvas in separate window
+ ref_window = ref_window || window;
+
if(!options.from)
LiteGraph.closeAllContextualMenus();
- var root = document.createElement("div");
+ var root = ref_window.document.createElement("div");
root.className = "litecontextualmenu litemenubar-panel";
this.root = root;
var style = root.style;
@@ -3731,7 +4065,7 @@ LiteGraph.createContextualMenu = function(values,options)
for(var i in values)
{
var item = values[i];
- var element = document.createElement("div");
+ var element = ref_window.document.createElement("div");
element.className = "litemenu-entry";
if(item == null)
@@ -3766,7 +4100,7 @@ LiteGraph.createContextualMenu = function(values,options)
root.addEventListener("mouseout", function(e) {
//console.log("OUT!");
var aux = e.toElement;
- while(aux != this && aux != document)
+ while(aux != this && aux != ref_window.document)
aux = aux.parentNode;
if(aux == this) return;
@@ -3775,17 +4109,8 @@ LiteGraph.createContextualMenu = function(values,options)
this.closeMenu();
});
- /* MS specific
- root.addEventListener("mouseleave", function(e) {
-
- this.mouse_inside = false;
- if(!this.block_close)
- this.closeMenu();
- });
- */
-
//insert before checking position
- document.body.appendChild(root);
+ ref_window.document.body.appendChild(root);
var root_rect = root.getClientRects()[0];
@@ -3804,7 +4129,7 @@ LiteGraph.createContextualMenu = function(values,options)
if(options.left)
left = options.left;
- var rect = document.body.getClientRects()[0];
+ var rect = ref_window.document.body.getClientRects()[0];
if(options.from)
{
@@ -3845,7 +4170,7 @@ LiteGraph.createContextualMenu = function(values,options)
options.from.closeMenu();
}
if(this.parentNode)
- document.body.removeChild(this);
+ ref_window.document.body.removeChild(this);
};
return root;
@@ -3872,7 +4197,27 @@ LiteGraph.extendClass = function(origin, target)
if(origin.prototype) //copy prototype properties
for(var i in origin.prototype)
target.prototype[i] = origin.prototype[i];
-}
+}
+
+/*
+LiteGraph.createNodetypeWrapper = function( class_object )
+{
+ //create Nodetype object
+}
+//LiteGraph.registerNodeType("scene/global", LGraphGlobal );
+*/
+
+if( !window["requestAnimationFrame"] )
+{
+ window.requestAnimationFrame = window.webkitRequestAnimationFrame ||
+ window.mozRequestAnimationFrame ||
+ (function( callback ){
+ window.setTimeout(callback, 1000 / 60);
+ });
+}
+
+
+
diff --git a/doc/index.html b/doc/index.html
index b60c37e4b..0d9a3cbe7 100644
--- a/doc/index.html
+++ b/doc/index.html
@@ -43,6 +43,8 @@
LGraph
+ LGraphCanvas
+
LGraphNode
LiteGraph
diff --git a/src/litegraph-editor.js b/src/litegraph-editor.js
new file mode 100644
index 000000000..ef027c804
--- /dev/null
+++ b/src/litegraph-editor.js
@@ -0,0 +1,165 @@
+//NOT FINISHED
+
+function Editor(container_id, options)
+{
+ //fill container
+ var html = "";
+ html += "";
+ html += "";
+
+ var root = document.createElement("div");
+ this.root = root;
+ root.className = "litegraph-editor";
+ root.innerHTML = html;
+
+ var canvas = root.querySelector(".graphcanvas");
+
+ //create graph
+ var graph = this.graph = new LGraph();
+ var graphcanvas = this.graphcanvas = new LGraphCanvas(canvas,graph);
+ graphcanvas.background_image = "imgs/grid.png";
+ graph.onAfterExecute = function() { graphcanvas.draw(true) };
+
+ //add stuff
+ this.addLoadCounter();
+ this.addToolsButton("playnode_button","Play","imgs/icon-play.png", this.onPlayButton.bind(this), ".tools-right" );
+ this.addToolsButton("playstepnode_button","Step","imgs/icon-playstep.png", this.onPlayStepButton.bind(this), ".tools-right" );
+
+ this.addToolsButton("livemode_button","Live","imgs/icon-record.png", this.onLiveButton.bind(this), ".tools-right" );
+ this.addToolsButton("maximize_button","","imgs/icon-maximize.png", this.onFullscreenButton.bind(this), ".tools-right" );
+
+ this.addMiniWindow(300,200);
+
+ //append to DOM
+ var parent = document.getElementById(container_id);
+ if(parent)
+ parent.appendChild(root);
+
+ graphcanvas.resize();
+ //graphcanvas.draw(true,true);
+}
+
+Editor.prototype.addLoadCounter = function()
+{
+ var meter = document.createElement("div");
+ meter.className = 'headerpanel loadmeter toolbar-widget';
+
+ var html = "";
+ html += "";
+
+ meter.innerHTML = html;
+ this.root.querySelector(".header .tools-left").appendChild(meter);
+ var self = this;
+
+ setInterval(function() {
+ meter.querySelector(".cpuload .fgload").style.width = ((2*self.graph.elapsed_time) * 90) + "px";
+ if(self.graph.status == LGraph.STATUS_RUNNING)
+ meter.querySelector(".gpuload .fgload").style.width = ((self.graphcanvas.render_time*10) * 90) + "px";
+ else
+ meter.querySelector(".gpuload .fgload").style.width = 4 + "px";
+ },200);
+}
+
+Editor.prototype.addToolsButton = function(id,name,icon_url, callback, container)
+{
+ if(!container) container = ".tools";
+
+ var button = document.createElement("button");
+ button.id = id;
+ button.innerHTML = " "+name+"";
+ button.addEventListener("click", callback);
+
+ this.root.querySelector(container).appendChild(button);
+
+}
+
+Editor.prototype.goFullscreen = function()
+{
+ if(this.root.requestFullscreen)
+ this.root.requestFullscreen(Element.ALLOW_KEYBOARD_INPUT);
+ else if(this.root.mozRequestFullscreen)
+ this.root.requestFullscreen(Element.ALLOW_KEYBOARD_INPUT);
+ else if(this.root.webkitRequestFullscreen)
+ this.root.webkitRequestFullscreen(Element.ALLOW_KEYBOARD_INPUT);
+ else
+ throw("Fullscreen not supported");
+
+ var self = this;
+ setTimeout(function() {
+ self.graphcanvas.resize();
+ },100);
+}
+
+Editor.prototype.onPlayButton = function()
+{
+ var graph = this.graph;
+ var button = this.root.querySelector("#playnode_button");
+
+ if(graph.status == LGraph.STATUS_STOPPED)
+ {
+ button.innerHTML = " Stop";
+ graph.start(1);
+ }
+ else
+ {
+ button.innerHTML = " Play";
+ graph.stop();
+ }
+}
+
+Editor.prototype.onPlayStepButton = function()
+{
+ var graph = this.graph;
+ graph.runStep(1);
+ this.graphcanvas.draw(true,true);
+}
+
+Editor.prototype.onLiveButton = function()
+{
+ var is_live_mode = !this.graphcanvas.live_mode;
+ this.graphcanvas.switchLiveMode(true);
+ this.graphcanvas.draw();
+ var url = this.graphcanvas.live_mode ? "imgs/gauss_bg_medium.jpg" : "imgs/gauss_bg.jpg";
+ var button = this.root.querySelector("#livemode_button");
+ button.innerHTML = !is_live_mode ? " Live" : " Edit" ;
+}
+
+Editor.prototype.onFullscreenButton = function()
+{
+ this.goFullscreen();
+}
+
+Editor.prototype.onMaximizeButton = function()
+{
+ this.maximize();
+}
+
+Editor.prototype.addMiniWindow = function(w,h)
+{
+ var miniwindow = document.createElement("div");
+ miniwindow.className = "litegraph miniwindow";
+ miniwindow.innerHTML = " ";
+ var canvas = miniwindow.querySelector("canvas");
+
+ var graphcanvas = new LGraphCanvas(canvas, this.graph);
+ graphcanvas.background_image = "imgs/grid.png";
+ graphcanvas.scale = 0.5;
+
+ miniwindow.style.position = "absolute";
+ miniwindow.style.top = "4px";
+ miniwindow.style.right = "4px";
+
+ var close_button = document.createElement("div");
+ close_button.className = "corner-button";
+ close_button.innerHTML = "X";
+ close_button.addEventListener("click",function(e) {
+ graphcanvas.setGraph(null);
+ miniwindow.parentNode.removeChild(miniwindow);
+ });
+ miniwindow.appendChild(close_button);
+
+
+ this.root.querySelector(".content").appendChild(miniwindow);
+}
+
+LiteGraph.Editor = Editor;
\ No newline at end of file
diff --git a/src/litegraph.js b/src/litegraph.js
index 70ed409eb..43e71b165 100644
--- a/src/litegraph.js
+++ b/src/litegraph.js
@@ -29,7 +29,6 @@ var LiteGraph = {
debug: false,
registered_node_types: {},
- graphs: [],
/**
* Register a node class so it can be listed when the user wants to create a new one
@@ -232,28 +231,19 @@ var LiteGraph = {
}
}
- for (var i in LiteGraph.graphs)
- {
- for (var j in LiteGraph.graphs[i].nodes)
- {
- var m = LiteGraph.graphs[i].nodes[j];
- var t = LiteGraph.getNodeType(n.type);
- if(!t) continue;
-
- for (var k in t)
- if( typeof(t[k]) == "function" )
- m[k] = t[k];
- }
- }
-
if(LiteGraph.debug)
console.log("Nodes reloaded");
},
//separated just to improve if it doesnt work
- cloneObject: function(obj)
+ cloneObject: function(obj, target)
{
- return JSON.parse( JSON.stringify( obj ) );
+ var r = JSON.parse( JSON.stringify( obj ) );
+ if(!target) return r;
+
+ for(var i in r)
+ target[i] = r[i];
+ return target;
}
/*
@@ -262,11 +252,11 @@ var LiteGraph = {
mode = mode || "all";
trace("Benchmarking " + mode + "...");
- trace(" Num. nodes: " + this.nodes.length );
+ trace(" Num. nodes: " + this._nodes.length );
var links = 0;
- for(var i in this.nodes)
- for(var j in this.nodes[i].outputs)
- if(this.nodes[i].outputs[j].node_id != null)
+ for(var i in this._nodes)
+ for(var j in this._nodes[i].outputs)
+ if(this._nodes[i].outputs[j].node_id != null)
links++;
trace(" Num. links: " + links );
@@ -317,8 +307,7 @@ function LGraph()
{
if (LiteGraph.debug)
console.log("Graph created");
- this.canvas = null;
- LiteGraph.graphs.push(this);
+ this.list_of_graphcanvas = null;
this.clear();
}
@@ -337,8 +326,8 @@ LGraph.prototype.clear = function()
this.last_node_id = 0;
//nodes
- this.nodes = [];
- this.nodes_by_id = {};
+ this._nodes = [];
+ this._nodes_by_id = {};
//links
this.last_link_id = 0;
@@ -348,8 +337,6 @@ LGraph.prototype.clear = function()
this.iteration = 0;
this.config = {
- canvas_offset: [0,0],
- canvas_scale: 1.0
};
//timing
@@ -360,12 +347,48 @@ LGraph.prototype.clear = function()
this.elapsed_time = 0.01;
this.starttime = 0;
+ //globals
+ this.globals = {};
+
this.graph = {};
this.debug = true;
this.change();
- if(this.canvas)
- this.canvas.clear();
+
+ this.sendActionToCanvas("clear");
+}
+
+/**
+* Attach Canvas to this graph
+* @method attachCanvas
+* @param {GraphCanvas} graph_canvas
+*/
+
+LGraph.prototype.attachCanvas = function(graphcanvas)
+{
+ if(graphcanvas.constructor != LGraphCanvas)
+ throw("attachCanvas expects a LGraphCanvas instance");
+ if(graphcanvas.graph && graphcanvas.graph != this)
+ graphcanvas.graph.detachCanvas( graphcanvas );
+
+ graphcanvas.graph = this;
+ if(!this.list_of_graphcanvas)
+ this.list_of_graphcanvas = [];
+ this.list_of_graphcanvas.push(graphcanvas);
+}
+
+/**
+* Detach Canvas from this graph
+* @method detachCanvas
+* @param {GraphCanvas} graph_canvas
+*/
+
+LGraph.prototype.detachCanvas = function(graphcanvas)
+{
+ var pos = this.list_of_graphcanvas.indexOf(graphcanvas);
+ if(pos == -1) return;
+ graphcanvas.graph = null;
+ this.list_of_graphcanvas.splice(pos,1);
}
/**
@@ -385,7 +408,7 @@ LGraph.prototype.start = function(interval)
this.sendEventToAllNodes("onStart");
//launch
- this.starttime = new Date().getTime();
+ this.starttime = window.performance.now();
interval = interval || 1;
var that = this;
@@ -397,7 +420,7 @@ LGraph.prototype.start = function(interval)
/**
* Stops the execution loop of the graph
-* @method stop
+* @method stop execution
*/
LGraph.prototype.stop = function()
@@ -427,7 +450,7 @@ LGraph.prototype.runStep = function(num)
{
num = num || 1;
- var start = new Date().getTime();
+ var start = window.performance.now();
this.globaltime = 0.001 * (start - this.starttime);
try
@@ -454,7 +477,7 @@ LGraph.prototype.runStep = function(num)
this.stop();
}
- var elapsed = (new Date().getTime()) - start;
+ var elapsed = window.performance.now() - start;
if (elapsed == 0) elapsed = 1;
this.elapsed_time = 0.001 * elapsed;
this.globaltime += 0.001 * elapsed;
@@ -469,7 +492,7 @@ LGraph.prototype.runStep = function(num)
LGraph.prototype.updateExecutionOrder = function()
{
- this.nodes_in_order = this.computeExecutionOrder();
+ this._nodes_in_order = this.computeExecutionOrder();
}
//This is more internal, it computes the order and returns it
@@ -482,9 +505,9 @@ LGraph.prototype.computeExecutionOrder = function()
var remaining_links = {}; //to a
//search for the nodes without inputs (starting nodes)
- for (var i in this.nodes)
+ for (var i in this._nodes)
{
- var n = this.nodes[i];
+ var n = this._nodes[i];
M[n.id] = n; //add to pending nodes
var num = 0; //num of input connections
@@ -546,7 +569,7 @@ LGraph.prototype.computeExecutionOrder = function()
for(var i in M)
L.push(M[i]);
- if(L.length != this.nodes.length && LiteGraph.debug)
+ if(L.length != this._nodes.length && LiteGraph.debug)
console.log("something went wrong, nodes missing");
//save order number in the node
@@ -600,12 +623,25 @@ LGraph.prototype.getElapsedTime = function()
LGraph.prototype.sendEventToAllNodes = function(eventname, param)
{
- var M = this.nodes_in_order ? this.nodes_in_order : this.nodes;
+ var M = this._nodes_in_order ? this._nodes_in_order : this._nodes;
for(var j in M)
if(M[j][eventname])
M[j][eventname](param);
}
+LGraph.prototype.sendActionToCanvas = function(action, params)
+{
+ if(!this.list_of_graphcanvas)
+ return;
+
+ for(var i in this.list_of_graphcanvas)
+ {
+ var c = this.list_of_graphcanvas[i];
+ if( c[action] )
+ c[action].apply(c, params);
+ }
+}
+
/**
* Adds a new node instasnce to this graph
* @method add
@@ -614,10 +650,10 @@ LGraph.prototype.sendEventToAllNodes = function(eventname, param)
LGraph.prototype.add = function(node)
{
- if(!node || (node.id != -1 && this.nodes_by_id[node.id] != null))
+ if(!node || (node.id != -1 && this._nodes_by_id[node.id] != null))
return; //already added
- if(this.nodes.length >= LiteGraph.MAX_NUMBER_OF_NODES)
+ if(this._nodes.length >= LiteGraph.MAX_NUMBER_OF_NODES)
throw("LiteGraph: max number of nodes in a graph reached");
//give him an id
@@ -626,8 +662,8 @@ LGraph.prototype.add = function(node)
node.graph = this;
- this.nodes.push(node);
- this.nodes_by_id[node.id] = node;
+ this._nodes.push(node);
+ this._nodes_by_id[node.id] = node;
/*
// rendering stuf...
@@ -659,7 +695,7 @@ LGraph.prototype.add = function(node)
LGraph.prototype.remove = function(node)
{
- if(this.nodes_by_id[node.id] == null)
+ if(this._nodes_by_id[node.id] == null)
return; //not found
if(node.ignore_remove)
@@ -699,10 +735,10 @@ LGraph.prototype.remove = function(node)
}
//remove from containers
- var pos = this.nodes.indexOf(node);
+ var pos = this._nodes.indexOf(node);
if(pos != -1)
- this.nodes.splice(pos,1);
- delete this.nodes_by_id[node.id];
+ this._nodes.splice(pos,1);
+ delete this._nodes_by_id[node.id];
if(this.canvas)
this.canvas.setDirty(true,true);
@@ -721,7 +757,7 @@ LGraph.prototype.remove = function(node)
LGraph.prototype.getNodeById = function(id)
{
if(id==null) return null;
- return this.nodes_by_id[id];
+ return this._nodes_by_id[id];
}
@@ -735,9 +771,9 @@ LGraph.prototype.getNodeById = function(id)
LGraph.prototype.findNodesByType = function(type)
{
var r = [];
- for(var i in this.nodes)
- if(this.nodes[i].type == type)
- r.push(this.nodes[i]);
+ for(var i in this._nodes)
+ if(this._nodes[i].type == type)
+ r.push(this._nodes[i]);
return r;
}
@@ -751,9 +787,9 @@ LGraph.prototype.findNodesByType = function(type)
LGraph.prototype.findNodesByName = function(name)
{
var result = [];
- for (var i in this.nodes)
- if(this.nodes[i].name == name)
- result.push(this.nodes[i]);
+ for (var i in this._nodes)
+ if(this._nodes[i].name == name)
+ result.push(this._nodes[i]);
return result;
}
@@ -768,7 +804,7 @@ LGraph.prototype.findNodesByName = function(name)
LGraph.prototype.getNodeOnPos = function(x,y, nodes_list)
{
- nodes_list = nodes_list || this.nodes;
+ nodes_list = nodes_list || this._nodes;
for (var i = nodes_list.length - 1; i >= 0; i--)
{
var n = nodes_list[i];
@@ -824,39 +860,46 @@ LGraph.prototype.setCallback = function(name,func)
m[i].setTrigger(func);
}
-//**********
-
LGraph.prototype.onConnectionChange = function()
{
this.updateExecutionOrder();
}
+/**
+* returns if the graph is in live mode
+* @method isLive
+*/
+
LGraph.prototype.isLive = function()
{
if(!this.canvas) return false;
return this.canvas.live_mode;
}
+/* Called when something visually changed */
LGraph.prototype.change = function()
{
if(LiteGraph.debug)
console.log("Graph changed");
+
+ this.sendActionToCanvas("setDirty",[true,true]);
+
if(this.on_change)
this.on_change(this);
}
//save and recover app state ***************************************
/**
-* Creates a JSON String containing all the info about this graph
+* Creates a Object containing all the info about this graph, it can be serialized
* @method serialize
-* @return {String} value of the node
+* @return {Object} value of the node
*/
LGraph.prototype.serialize = function()
{
var nodes_info = [];
- for (var i in this.nodes)
- nodes_info.push( this.nodes[i].objectivize() );
+ for (var i in this._nodes)
+ nodes_info.push( this._nodes[i].serialize() );
var data = {
graph: this.graph,
@@ -870,20 +913,20 @@ LGraph.prototype.serialize = function()
nodes: nodes_info
};
- return JSON.stringify(data);
+ return data;
}
+
/**
* Configure a graph from a JSON string
-* @method unserialize
+* @method configure
* @param {String} str configure a graph from a JSON string
*/
-LGraph.prototype.unserialize = function(str, keep_old)
+LGraph.prototype.configure = function(data, keep_old)
{
if(!keep_old)
this.clear();
- var data = JSON.parse(str);
var nodes = data.nodes;
//copy all stored fields
@@ -893,7 +936,7 @@ LGraph.prototype.unserialize = function(str, keep_old)
var error = false;
//create nodes
- this.nodes = [];
+ this._nodes = [];
for (var i in nodes)
{
var n_info = nodes[i]; //stored info
@@ -906,7 +949,7 @@ LGraph.prototype.unserialize = function(str, keep_old)
continue;
}
- n.copyFromObject(n_info);
+ n.configure(n_info);
this.add(n);
}
@@ -980,9 +1023,59 @@ function LGraphNode(name)
};
}
-//serialization *************************
+/**
+* configure a node from an object
+* @method configure
+*/
+LGraphNode.prototype.configure = function(info)
+{
+ for (var j in info)
+ {
+ if(j == "console") continue;
-LGraphNode.prototype.objectivize = function()
+ if(info[j] == null)
+ continue;
+ else if( info[j].concat ) //array
+ this[j] = info[j].concat();
+ else if (typeof(info[j]) == 'object') //object
+ this[j] = LiteGraph.cloneObject(info[j], this[j] || {} );
+ else //value
+ this[j] = info[j];
+ }
+}
+
+/* Copy all the info from one object to this node (used for serialization) */
+LGraphNode.prototype.copyFromObject = function(info, ignore_connections)
+{
+ var outputs = null;
+ var inputs = null;
+ var properties = null;
+ var local_data = null;
+
+ for (var j in info)
+ {
+ if(ignore_connections && (j == "outputs" || j == "inputs"))
+ continue;
+
+ if(j == "console") continue;
+
+ if(info[j] == null)
+ continue;
+ else if( info[j].concat ) //array
+ this[j] = info[j].concat();
+ else if (typeof(info[j]) == 'object') //object
+ this[j] = LiteGraph.cloneObject(info[j]);
+ else //value
+ this[j] = info[j];
+ }
+}
+
+/**
+* serialize the content
+* @method serialize
+*/
+
+LGraphNode.prototype.serialize = function()
{
var o = {
id: this.id,
@@ -1009,10 +1102,14 @@ LGraphNode.prototype.objectivize = function()
if(this.shape)
o.shape = this.shape;
+ if(this.onSerialize)
+ this.onSerialize(o);
+
return o;
}
//reduced version of objectivize: NOT FINISHED
+/*
LGraphNode.prototype.reducedObjectivize = function()
{
var o = this.objectivize();
@@ -1030,19 +1127,27 @@ LGraphNode.prototype.reducedObjectivize = function()
return o;
}
+*/
+/**
+* serialize and stringify
+* @method toString
+*/
-LGraphNode.prototype.serialize = function()
+LGraphNode.prototype.toString = function()
{
- if(this.onSerialize)
- this.onSerialize();
- return JSON.stringify( this.reducedObjectivize() );
+ return JSON.stringify( this.serialize() );
}
//LGraphNode.prototype.unserialize = function(info) {} //this cannot be done from within, must be done in LiteGraph
// Execution *************************
-
+/**
+* sets the output data
+* @method setOutputData
+* @param {number} slot
+* @param {*} data
+*/
LGraphNode.prototype.setOutputData = function(slot,data)
{
if(!this.outputs) return;
@@ -1053,6 +1158,12 @@ LGraphNode.prototype.setOutputData = function(slot,data)
}
}
+/**
+* retrieves the input data from one slot
+* @method getInputData
+* @param {number} slot
+* @return {*} data
+*/
LGraphNode.prototype.getInputData = function(slot)
{
if(!this.inputs) return null;
@@ -1061,12 +1172,24 @@ LGraphNode.prototype.getInputData = function(slot)
return null;
}
+/**
+* tells you if there is a connection in one input slot
+* @method isInputConnected
+* @param {number} slot
+* @return {boolean}
+*/
LGraphNode.prototype.isInputConnected = function(slot)
{
if(!this.inputs) return null;
return (slot < this.inputs.length && this.inputs[slot].link != null);
}
+/**
+* tells you info about an input connection (which node, type, etc)
+* @method getInputInfo
+* @param {number} slot
+* @return {Object}
+*/
LGraphNode.prototype.getInputInfo = function(slot)
{
if(!this.inputs) return null;
@@ -1076,6 +1199,12 @@ LGraphNode.prototype.getInputInfo = function(slot)
}
+/**
+* tells you info about an output connection (which node, type, etc)
+* @method getOutputInfo
+* @param {number} slot
+* @return {Object}
+*/
LGraphNode.prototype.getOutputInfo = function(slot)
{
if(!this.outputs) return null;
@@ -1084,12 +1213,25 @@ LGraphNode.prototype.getOutputInfo = function(slot)
return null;
}
+
+/**
+* tells you if there is a connection in one output slot
+* @method isOutputConnected
+* @param {number} slot
+* @return {boolean}
+*/
LGraphNode.prototype.isOutputConnected = function(slot)
{
if(!this.outputs) return null;
return (slot < this.outputs.length && this.outputs[slot].links && this.outputs[slot].links.length);
}
+/**
+* retrieves all the nodes connected to this output slot
+* @method getOutputNodes
+* @param {number} slot
+* @return {array}
+*/
LGraphNode.prototype.getOutputNodes = function(slot)
{
if(!this.outputs || this.outputs.length == 0) return null;
@@ -1113,6 +1255,13 @@ LGraphNode.prototype.triggerOutput = function(slot,param)
//connections
+/**
+* add a new output slot to use in this node
+* @method addOutput
+* @param {string} name
+* @param {string} type string defining the output type ("vec3","number",...)
+* @param {Object} extra_info this can be used to have special properties of an output (special color, position, etc)
+*/
LGraphNode.prototype.addOutput = function(name,type,extra_info)
{
var o = {name:name,type:type,links:null};
@@ -1125,6 +1274,11 @@ LGraphNode.prototype.addOutput = function(name,type,extra_info)
this.size = this.computeSize();
}
+/**
+* remove an existing output slot
+* @method removeOutput
+* @param {number} slot
+*/
LGraphNode.prototype.removeOutput = function(slot)
{
this.disconnectOutput(slot);
@@ -1132,6 +1286,13 @@ LGraphNode.prototype.removeOutput = function(slot)
this.size = this.computeSize();
}
+/**
+* add a new input slot to use in this node
+* @method addInput
+* @param {string} name
+* @param {string} type string defining the input type ("vec3","number",...)
+* @param {Object} extra_info this can be used to have special properties of an input (special color, position, etc)
+*/
LGraphNode.prototype.addInput = function(name,type,extra_info)
{
var o = {name:name,type:type,link:null};
@@ -1144,6 +1305,11 @@ LGraphNode.prototype.addInput = function(name,type,extra_info)
this.size = this.computeSize();
}
+/**
+* remove an existing input slot
+* @method removeInput
+* @param {number} slot
+*/
LGraphNode.prototype.removeInput = function(slot)
{
this.disconnectInput(slot);
@@ -1151,13 +1317,25 @@ LGraphNode.prototype.removeInput = function(slot)
this.size = this.computeSize();
}
-//trigger connection
+/**
+* add an special connection to this node (used for special kinds of graphs)
+* @method addConnection
+* @param {string} name
+* @param {string} type string defining the input type ("vec3","number",...)
+* @param {[x,y]} pos position of the connection inside the node
+* @param {string} direction if is input or output
+*/
LGraphNode.prototype.addConnection = function(name,type,pos,direction)
{
this.connections.push( {name:name,type:type,pos:pos,direction:direction,links:null});
}
-
+/**
+* computes the size of a node according to its inputs and output slots
+* @method computeSize
+* @param {number} minHeight
+* @return {number} the total size
+*/
LGraphNode.prototype.computeSize = function(minHeight)
{
var rows = Math.max( this.inputs ? this.inputs.length : 1, this.outputs ? this.outputs.length : 1);
@@ -1170,13 +1348,23 @@ LGraphNode.prototype.computeSize = function(minHeight)
return size;
}
-//returns the bounding of the object, used for rendering purposes
+/**
+* returns the bounding of the object, used for rendering purposes
+* @method getBounding
+* @return {Float32Array[4]} the total size
+*/
LGraphNode.prototype.getBounding = function()
{
return new Float32Array([this.pos[0] - 4, this.pos[1] - LiteGraph.NODE_TITLE_HEIGHT, this.pos[0] + this.size[0] + 4, this.pos[1] + this.size[1] + LGraph.NODE_TITLE_HEIGHT]);
}
-//checks if a point is inside the shape of a node
+/**
+* checks if a point is inside the shape of a node
+* @method isPointInsideNode
+* @param {number} x
+* @param {number} y
+* @return {boolean}
+*/
LGraphNode.prototype.isPointInsideNode = function(x,y)
{
var margin_top = this.graph.isLive() ? 0 : 20;
@@ -1210,7 +1398,14 @@ LGraphNode.prototype.findOutputSlot = function(name)
return -1;
}
-//connect this node output to the input of another node
+/**
+* connect this node output to the input of another node
+* @method connect
+* @param {number_or_string} slot (could be the number of the slot or the string with the name of the slot)
+* @param {LGraphNode} node the target node
+* @param {number_or_string} target_slot the input slot of the target node (could be the number of the slot or the string with the name of the slot)
+* @return {boolean} if it was connected succesfully
+*/
LGraphNode.prototype.connect = function(slot, node, target_slot)
{
target_slot = target_slot || 0;
@@ -1284,6 +1479,13 @@ LGraphNode.prototype.connect = function(slot, node, target_slot)
return true;
}
+/**
+* disconnect one output to an specific node
+* @method disconnectOutput
+* @param {number_or_string} slot (could be the number of the slot or the string with the name of the slot)
+* @param {LGraphNode} target_node the target node to which this slot is connected [Optional, if not target_node is specified all nodes will be disconnected]
+* @return {boolean} if it was disconnected succesfully
+*/
LGraphNode.prototype.disconnectOutput = function(slot, target_node)
{
if( slot.constructor === String )
@@ -1340,6 +1542,12 @@ LGraphNode.prototype.disconnectOutput = function(slot, target_node)
return true;
}
+/**
+* disconnect one input
+* @method disconnectInput
+* @param {number_or_string} slot (could be the number of the slot or the string with the name of the slot)
+* @return {boolean} if it was disconnected succesfully
+*/
LGraphNode.prototype.disconnectInput = function(slot)
{
//seek for the output slot
@@ -1388,7 +1596,13 @@ LGraphNode.prototype.disconnectInput = function(slot)
return true;
}
-//returns the center of a connection point in canvas coords
+/**
+* returns the center of a connection point in canvas coords
+* @method getConnectionPos
+* @param {boolean} is_input true if if a input slot, false if it is an output
+* @param {number_or_string} slot (could be the number of the slot or the string with the name of the slot)
+* @return {[x,y]} the position
+**/
LGraphNode.prototype.getConnectionPos = function(is_input,slot_number)
{
if(this.flags.collapsed)
@@ -1422,50 +1636,6 @@ LGraphNode.prototype.alignToGrid = function()
this.pos[1] = LiteGraph.CANVAS_GRID_SIZE * Math.round(this.pos[1] / LiteGraph.CANVAS_GRID_SIZE);
}
-/* Copy all the info from one object to this node (used for serialization) */
-LGraphNode.prototype.copyFromObject = function(info, ignore_connections)
-{
- var outputs = null;
- var inputs = null;
- var properties = null;
- var local_data = null;
-
- for (var j in info)
- {
- if(ignore_connections && (j == "outputs" || j == "inputs"))
- continue;
-
- if(j == "console") continue;
-
- if(info[j] == null)
- continue;
- else if( info[j].concat ) //array
- this[j] = info[j].concat();
- else if (typeof(info[j]) == 'object') //object
- this[j] = LiteGraph.cloneObject(info[j]);
- else //value
- this[j] = info[j];
- }
-
- //redo the connections
- /*
- if(outputs)
- this.outputs = outputs.concat();
- if(inputs)
- this.inputs = inputs.concat();
-
- if(local_data)
- this.data = local_data;
- if(properties)
- {
- //copy only the ones defined
- for (var j in properties)
- if (this.properties[j] != null)
- this.properties[j] = properties[j];
- }
- */
-}
-
/* Creates a clone of this node */
LGraphNode.prototype.clone = function()
{
@@ -1505,13 +1675,9 @@ LGraphNode.prototype.trace = function(msg)
/* Forces to redraw or the main canvas (LGraphNode) or the bg canvas (links) */
LGraphNode.prototype.setDirtyCanvas = function(dirty_foreground, dirty_background)
{
- if(!this.graph || !this.graph.canvas)
+ if(!this.graph)
return;
-
- if(dirty_foreground)
- this.graph.canvas.dirty_canvas = true;
- if(dirty_background)
- this.graph.canvas.dirty_bgcanvas = true;
+ this.graph.sendActionToCanvas("setDirty",[dirty_foreground, dirty_background]);
}
LGraphNode.prototype.loadImage = function(url)
@@ -1568,20 +1734,29 @@ LGraphNode.prototype.executeAction = function(action)
/* Allows to get onMouseMove and onMouseUp events even if the mouse is out of focus */
LGraphNode.prototype.captureInput = function(v)
{
- if(!this.graph || !this.graph.canvas)
+ if(!this.graph || !this.graph.list_of_graphcanvas)
return;
- //releasing somebody elses capture?!
- if(!v && this.graph.canvas.node_capturing_input != this)
- return;
+ var list = this.graph.list_of_graphcanvas;
- //change
- this.graph.canvas.node_capturing_input = v ? this : null;
- if(this.graph.debug)
- console.log(this.name + ": Capturing input " + (v?"ON":"OFF"));
+ for(var i in list)
+ {
+ var c = list[i];
+ //releasing somebody elses capture?!
+ if(!v && c.node_capturing_input != this)
+ continue;
+
+ //change
+ c.node_capturing_input = v ? this : null;
+ if(this.graph.debug)
+ console.log(this.name + ": Capturing input " + (v?"ON":"OFF"));
+ }
}
-/* Collapse the node */
+/**
+* Collapse the node to make it smaller on the canvas
+* @method collapse
+**/
LGraphNode.prototype.collapse = function()
{
if(!this.flags.collapsed)
@@ -1591,19 +1766,23 @@ LGraphNode.prototype.collapse = function()
this.setDirtyCanvas(true,true);
}
-/* Forces the node to do not move or realign on Z */
-LGraphNode.prototype.pin = function()
+/**
+* Forces the node to do not move or realign on Z
+* @method pin
+**/
+
+LGraphNode.prototype.pin = function(v)
{
- if(!this.flags.pinned)
- this.flags.pinned = true;
+ if(v === undefined)
+ this.flags.pinned = !this.flags.pinned;
else
- this.flags.pinned = false;
+ this.flags.pinned = v;
}
-LGraphNode.prototype.localToScreen = function(x,y)
+LGraphNode.prototype.localToScreen = function(x,y, graphcanvas)
{
- return [(x + this.pos[0]) * this.graph.config.canvas_scale + this.graph.config.canvas_offset[0],
- (y + this.pos[1]) * this.graph.config.canvas_scale + this.graph.config.canvas_offset[1]];
+ return [(x + this.pos[0]) * graphcanvas.scale + graphcanvas.offset[0],
+ (y + this.pos[1]) * graphcanvas.scale + graphcanvas.offset[1]];
}
@@ -1612,27 +1791,28 @@ LGraphNode.prototype.localToScreen = function(x,y)
// LGraphCanvas: LGraph renderer CLASS
//*********************************************************************************
+/**
+* The Global Scope. It contains all the registered node classes.
+*
+* @class LGraphCanvas
+* @constructor
+* @param {HTMLCanvas} canvas the canvas where you want to render (it accepts a selector in string format)
+* @param {LGraph} graph
+*/
function LGraphCanvas(canvas, graph)
{
- if(graph === undefined)
- throw ("No graph assigned");
+ //if(graph === undefined)
+ // throw ("No graph assigned");
- if( typeof(window) != "undefined" )
- {
- window.requestAnimFrame = (function(){
- return window.requestAnimationFrame ||
- window.webkitRequestAnimationFrame ||
- window.mozRequestAnimationFrame ||
- function( callback ){
- window.setTimeout(callback, 1000 / 60);
- };
- })();
- }
+ if(typeof(canvas) == "string")
+ canvas = document.querySelector(canvas);
+
+ if(!canvas)
+ throw("no canvas found");
//link canvas and graph
- this.graph = graph;
if(graph)
- graph.canvas = this;
+ graph.attachCanvas(this);
this.setCanvas(canvas);
this.clear();
@@ -1641,7 +1821,6 @@ function LGraphCanvas(canvas, graph)
}
LGraphCanvas.link_type_colors = {'number':"#AAC",'node':"#DCA"};
-LGraphCanvas.link_width = 2;
LGraphCanvas.prototype.clear = function()
{
@@ -1650,6 +1829,9 @@ LGraphCanvas.prototype.clear = function()
this.render_time = 0;
this.fps = 0;
+ this.scale = 1;
+ this.offset = [0,0];
+
this.selected_nodes = {};
this.node_dragged = null;
this.node_over = null;
@@ -1657,6 +1839,7 @@ LGraphCanvas.prototype.clear = function()
this.connecting_node = null;
this.highquality_render = true;
+ this.editor_alpha = 1; //used for transition
this.pause_rendering = false;
this.render_shadows = true;
this.dirty_canvas = true;
@@ -1674,6 +1857,16 @@ LGraphCanvas.prototype.clear = function()
this.last_mouse = [0,0];
this.last_mouseclick = 0;
+ this.title_text_font = "bold 14px Arial";
+ this.inner_text_font = "normal 12px Arial";
+
+ this.render_connections_shadows = false; //too much cpu
+ this.render_connections_border = true;
+ this.render_curved_connections = true;
+ this.render_connection_arrows = true;
+
+ this.connections_width = 4;
+
if(this.onClear) this.onClear();
//this.UIinit();
}
@@ -1681,29 +1874,25 @@ LGraphCanvas.prototype.clear = function()
LGraphCanvas.prototype.setGraph = function(graph)
{
if(this.graph == graph) return;
-
this.clear();
+
+ if(!graph && this.graph)
+ {
+ this.graph.detachCanvas(this);
+ return;
+ }
+
+ /*
if(this.graph)
this.graph.canvas = null; //remove old graph link to the canvas
this.graph = graph;
if(this.graph)
this.graph.canvas = this;
+ */
+ graph.attachCanvas(this);
this.setDirty(true,true);
}
-LGraphCanvas.prototype.resize = function(width, height)
-{
- if(this.canvas.width == width && this.canvas.height == height)
- return;
-
- this.canvas.width = width;
- this.canvas.height = height;
- this.bgcanvas.width = this.canvas.width;
- this.bgcanvas.height = this.canvas.height;
- this.setDirty(true,true);
-}
-
-
LGraphCanvas.prototype.setCanvas = function(canvas)
{
var that = this;
@@ -1828,6 +2017,13 @@ LGraphCanvas.prototype.setDirty = function(fgcanvas,bgcanvas)
this.dirty_bgcanvas = true;
}
+//Used to attach the canvas in a popup
+LGraphCanvas.prototype.getCanvasWindow = function()
+{
+ var doc = this.canvas.ownerDocument;
+ return doc.defaultView || doc.parentWindow;
+}
+
LGraphCanvas.prototype.startRendering = function()
{
if(this.is_rendering) return; //already rendering
@@ -1840,8 +2036,9 @@ LGraphCanvas.prototype.startRendering = function()
if(!this.pause_rendering)
this.draw();
+ var window = this.getCanvasWindow();
if(this.is_rendering)
- window.requestAnimFrame( renderFrame.bind(this) );
+ window.requestAnimationFrame( renderFrame.bind(this) );
}
@@ -1873,9 +2070,12 @@ LGraphCanvas.prototype.processMouseDown = function(e)
this.adjustMouseEvent(e);
+ var ref_window = this.getCanvasWindow();
+ var document = ref_window.document;
+
this.canvas.removeEventListener("mousemove", this._mousemove_callback );
- document.addEventListener("mousemove", this._mousemove_callback );
- document.addEventListener("mouseup", this._mouseup_callback );
+ ref_window.document.addEventListener("mousemove", this._mousemove_callback ); //catch for the entire window
+ ref_window.document.addEventListener("mouseup", this._mouseup_callback );
var n = this.graph.getNodeOnPos(e.canvasX, e.canvasY, this.visible_nodes);
var skip_dragging = false;
@@ -1956,7 +2156,7 @@ LGraphCanvas.prototype.processMouseDown = function(e)
var block_drag_node = false;
//double clicking
- var now = new Date().getTime();
+ var now = window.performance.now();
if ((now - this.last_mouseclick) < 300 && this.selected_nodes[n.id])
{
//double click node
@@ -2011,7 +2211,7 @@ LGraphCanvas.prototype.processMouseDown = function(e)
this.last_mouse[0] = e.localX;
this.last_mouse[1] = e.localY;
- this.last_mouseclick = new Date().getTime();
+ this.last_mouseclick = window.performance.now();
this.canvas_mouse = [e.canvasX, e.canvasY];
/*
@@ -2022,7 +2222,7 @@ LGraphCanvas.prototype.processMouseDown = function(e)
this.graph.change();
//this is to ensure to defocus(blur) if a text input element is on focus
- if(!document.activeElement || (document.activeElement.nodeName.toLowerCase() != "input" && document.activeElement.nodeName.toLowerCase() != "textarea"))
+ if(!ref_window.document.activeElement || (ref_window.document.activeElement.nodeName.toLowerCase() != "input" && ref_window.document.activeElement.nodeName.toLowerCase() != "textarea"))
e.preventDefault();
e.stopPropagation();
return false;
@@ -2040,8 +2240,8 @@ LGraphCanvas.prototype.processMouseMove = function(e)
if(this.dragging_canvas)
{
- this.graph.config.canvas_offset[0] += delta[0] / this.graph.config.canvas_scale;
- this.graph.config.canvas_offset[1] += delta[1] / this.graph.config.canvas_scale;
+ this.offset[0] += delta[0] / this.scale;
+ this.offset[1] += delta[1] / this.scale;
this.dirty_canvas = true;
this.dirty_bgcanvas = true;
}
@@ -2054,12 +2254,12 @@ LGraphCanvas.prototype.processMouseMove = function(e)
var n = this.graph.getNodeOnPos(e.canvasX, e.canvasY, this.visible_nodes);
//remove mouseover flag
- for(var i in this.graph.nodes)
+ for(var i in this.graph._nodes)
{
- if(this.graph.nodes[i].mouseOver && n != this.graph.nodes[i])
+ if(this.graph._nodes[i].mouseOver && n != this.graph._nodes[i])
{
//mouse leave
- this.graph.nodes[i].mouseOver = false;
+ this.graph._nodes[i].mouseOver = false;
if(this.node_over && this.node_over.onMouseLeave)
this.node_over.onMouseLeave(e);
this.node_over = null;
@@ -2116,8 +2316,8 @@ LGraphCanvas.prototype.processMouseMove = function(e)
if(this.node_dragged && !this.live_mode)
{
/*
- this.node_dragged.pos[0] += delta[0] / this.graph.config.canvas_scale;
- this.node_dragged.pos[1] += delta[1] / this.graph.config.canvas_scale;
+ this.node_dragged.pos[0] += delta[0] / this.scale;
+ this.node_dragged.pos[1] += delta[1] / this.scale;
this.node_dragged.pos[0] = Math.round(this.node_dragged.pos[0]);
this.node_dragged.pos[1] = Math.round(this.node_dragged.pos[1]);
*/
@@ -2126,8 +2326,8 @@ LGraphCanvas.prototype.processMouseMove = function(e)
{
var n = this.selected_nodes[i];
- n.pos[0] += delta[0] / this.graph.config.canvas_scale;
- n.pos[1] += delta[1] / this.graph.config.canvas_scale;
+ n.pos[0] += delta[0] / this.scale;
+ n.pos[1] += delta[1] / this.scale;
n.pos[0] = Math.round(n.pos[0]);
n.pos[1] = Math.round(n.pos[1]);
}
@@ -2138,8 +2338,8 @@ LGraphCanvas.prototype.processMouseMove = function(e)
if(this.resizing_node && !this.live_mode)
{
- this.resizing_node.size[0] += delta[0] / this.graph.config.canvas_scale;
- this.resizing_node.size[1] += delta[1] / this.graph.config.canvas_scale;
+ this.resizing_node.size[0] += delta[0] / this.scale;
+ this.resizing_node.size[1] += delta[1] / this.scale;
var max_slots = Math.max( this.resizing_node.inputs ? this.resizing_node.inputs.length : 0, this.resizing_node.outputs ? this.resizing_node.outputs.length : 0);
if(this.resizing_node.size[1] < max_slots * LiteGraph.NODE_SLOT_HEIGHT + 4)
this.resizing_node.size[1] = max_slots * LiteGraph.NODE_SLOT_HEIGHT + 4;
@@ -2168,6 +2368,9 @@ LGraphCanvas.prototype.processMouseUp = function(e)
{
if(!this.graph) return;
+ var window = this.getCanvasWindow();
+ var document = window.document;
+
document.removeEventListener("mousemove", this._mousemove_callback, true );
this.canvas.addEventListener("mousemove", this._mousemove_callback, true);
document.removeEventListener("mouseup", this._mouseup_callback, true );
@@ -2333,7 +2536,7 @@ LGraphCanvas.prototype.processMouseWheel = function(e)
this.adjustMouseEvent(e);
- var zoom = this.graph.config.canvas_scale;
+ var zoom = this.scale;
if (delta > 0)
zoom *= 1.1;
@@ -2418,13 +2621,13 @@ LGraphCanvas.prototype.selectNode = function(node)
LGraphCanvas.prototype.selectAllNodes = function()
{
- for(var i in this.graph.nodes)
+ for(var i in this.graph._nodes)
{
- var n = this.graph.nodes[i];
+ var n = this.graph._nodes[i];
if(!n.selected && n.onSelected)
n.onSelected();
n.selected = true;
- this.selected_nodes[this.graph.nodes[i].id] = n;
+ this.selected_nodes[this.graph._nodes[i].id] = n;
}
this.setDirty(true);
@@ -2457,8 +2660,8 @@ LGraphCanvas.prototype.deleteSelectedNodes = function()
LGraphCanvas.prototype.centerOnNode = function(node)
{
- this.graph.config.canvas_offset[0] = -node.pos[0] - node.size[0] * 0.5 + (this.canvas.width * 0.5 / this.graph.config.canvas_scale);
- this.graph.config.canvas_offset[1] = -node.pos[1] - node.size[1] * 0.5 + (this.canvas.height * 0.5 / this.graph.config.canvas_scale);
+ this.offset[0] = -node.pos[0] - node.size[0] * 0.5 + (this.canvas.width * 0.5 / this.scale);
+ this.offset[1] = -node.pos[1] - node.size[1] * 0.5 + (this.canvas.height * 0.5 / this.scale);
this.setDirty(true,true);
}
@@ -2468,8 +2671,8 @@ LGraphCanvas.prototype.adjustMouseEvent = function(e)
e.localX = e.pageX - b.left;
e.localY = e.pageY - b.top;
- e.canvasX = e.localX / this.graph.config.canvas_scale - this.graph.config.canvas_offset[0];
- e.canvasY = e.localY / this.graph.config.canvas_scale - this.graph.config.canvas_offset[1];
+ e.canvasX = e.localX / this.scale - this.offset[0];
+ e.canvasY = e.localY / this.scale - this.offset[1];
}
LGraphCanvas.prototype.setZoom = function(value, zooming_center)
@@ -2479,18 +2682,18 @@ LGraphCanvas.prototype.setZoom = function(value, zooming_center)
var center = this.convertOffsetToCanvas( zooming_center );
- this.graph.config.canvas_scale = value;
+ this.scale = value;
- if(this.graph.config.canvas_scale > 4)
- this.graph.config.canvas_scale = 4;
- else if(this.graph.config.canvas_scale < 0.1)
- this.graph.config.canvas_scale = 0.1;
+ if(this.scale > 4)
+ this.scale = 4;
+ else if(this.scale < 0.1)
+ this.scale = 0.1;
var new_center = this.convertOffsetToCanvas( zooming_center );
var delta_offset = [new_center[0] - center[0], new_center[1] - center[1]];
- this.graph.config.canvas_offset[0] += delta_offset[0];
- this.graph.config.canvas_offset[1] += delta_offset[1];
+ this.offset[0] += delta_offset[0];
+ this.offset[1] += delta_offset[1];
this.dirty_canvas = true;
this.dirty_bgcanvas = true;
@@ -2498,13 +2701,13 @@ LGraphCanvas.prototype.setZoom = function(value, zooming_center)
LGraphCanvas.prototype.convertOffsetToCanvas = function(pos)
{
- return [pos[0] / this.graph.config.canvas_scale - this.graph.config.canvas_offset[0], pos[1] / this.graph.config.canvas_scale - this.graph.config.canvas_offset[1]];
+ return [pos[0] / this.scale - this.offset[0], pos[1] / this.scale - this.offset[1]];
}
LGraphCanvas.prototype.convertCanvasToOffset = function(pos)
{
- return [(pos[0] + this.graph.config.canvas_offset[0]) * this.graph.config.canvas_scale,
- (pos[1] + this.graph.config.canvas_offset[1]) * this.graph.config.canvas_scale ];
+ return [(pos[0] + this.offset[0]) * this.scale,
+ (pos[1] + this.offset[1]) * this.scale ];
}
LGraphCanvas.prototype.convertEventToCanvas = function(e)
@@ -2515,20 +2718,20 @@ LGraphCanvas.prototype.convertEventToCanvas = function(e)
LGraphCanvas.prototype.bringToFront = function(n)
{
- var i = this.graph.nodes.indexOf(n);
+ var i = this.graph._nodes.indexOf(n);
if(i == -1) return;
- this.graph.nodes.splice(i,1);
- this.graph.nodes.push(n);
+ this.graph._nodes.splice(i,1);
+ this.graph._nodes.push(n);
}
LGraphCanvas.prototype.sendToBack = function(n)
{
- var i = this.graph.nodes.indexOf(n);
+ var i = this.graph._nodes.indexOf(n);
if(i == -1) return;
- this.graph.nodes.splice(i,1);
- this.graph.nodes.unshift(n);
+ this.graph._nodes.splice(i,1);
+ this.graph._nodes.unshift(n);
}
/* Interaction */
@@ -2540,9 +2743,9 @@ LGraphCanvas.prototype.sendToBack = function(n)
LGraphCanvas.prototype.computeVisibleNodes = function()
{
var visible_nodes = [];
- for (var i in this.graph.nodes)
+ for (var i in this.graph._nodes)
{
- var n = this.graph.nodes[i];
+ var n = this.graph._nodes[i];
//skip rendering nodes in live mode
if(this.live_mode && !n.onDrawBackground && !n.onDrawForeground)
@@ -2559,14 +2762,14 @@ LGraphCanvas.prototype.computeVisibleNodes = function()
LGraphCanvas.prototype.draw = function(force_canvas, force_bgcanvas)
{
//fps counting
- var now = new Date().getTime();
+ var now = window.performance.now();
this.render_time = (now - this.last_draw_time)*0.001;
this.last_draw_time = now;
if(this.graph)
{
- var start = [-this.graph.config.canvas_offset[0], -this.graph.config.canvas_offset[1] ];
- var end = [start[0] + this.canvas.width / this.graph.config.canvas_scale, start[1] + this.canvas.height / this.graph.config.canvas_scale];
+ var start = [-this.offset[0], -this.offset[1] ];
+ var end = [start[0] + this.canvas.width / this.scale, start[1] + this.canvas.height / this.scale];
this.visible_area = new Float32Array([start[0],start[1],end[0],end[1]]);
}
@@ -2625,8 +2828,8 @@ LGraphCanvas.prototype.drawFrontCanvas = function()
{
//apply transformations
ctx.save();
- ctx.scale(this.graph.config.canvas_scale,this.graph.config.canvas_scale);
- ctx.translate(this.graph.config.canvas_offset[0],this.graph.config.canvas_offset[1]);
+ ctx.scale(this.scale,this.scale);
+ ctx.translate(this.offset[0],this.offset[1]);
//draw nodes
var drawn_nodes = 0;
@@ -2657,10 +2860,9 @@ LGraphCanvas.prototype.drawFrontCanvas = function()
//current connection
if(this.connecting_pos != null)
{
- ctx.lineWidth = LGraphCanvas.link_width;
- ctx.fillStyle = this.connecting_output.type == 'node' ? "#F85" : "#AFA";
- ctx.strokeStyle = ctx.fillStyle;
- this.renderLink(ctx, this.connecting_pos, [this.canvas_mouse[0],this.canvas_mouse[1]] );
+ ctx.lineWidth = this.connections_width;
+ var link_color = this.connecting_output.type == 'node' ? "#F85" : "#AFA";
+ this.renderLink(ctx, this.connecting_pos, [this.canvas_mouse[0],this.canvas_mouse[1]], link_color );
ctx.beginPath();
ctx.arc( this.connecting_pos[0], this.connecting_pos[1],4,0,Math.PI*2);
@@ -2709,13 +2911,13 @@ LGraphCanvas.prototype.drawBgcanvas = function()
{
//apply transformations
ctx.save();
- ctx.scale(this.graph.config.canvas_scale,this.graph.config.canvas_scale);
- ctx.translate(this.graph.config.canvas_offset[0],this.graph.config.canvas_offset[1]);
+ ctx.scale(this.scale,this.scale);
+ ctx.translate(this.offset[0],this.offset[1]);
//render BG
- if(this.background_image && this.graph.config.canvas_scale > 0.5)
+ if(this.background_image && this.scale > 0.5)
{
- ctx.globalAlpha = 1.0 - 0.5 / this.graph.config.canvas_scale;
+ ctx.globalAlpha = (1.0 - 0.5 / this.scale) * this.editor_alpha;
ctx.webkitImageSmoothingEnabled = ctx.mozImageSmoothingEnabled = ctx.imageSmoothingEnabled = false
if(!this._bg_img || this._bg_img.name != this.background_image)
{
@@ -2755,8 +2957,7 @@ LGraphCanvas.prototype.drawBgcanvas = function()
ctx.strokeStyle = "#235";
ctx.strokeRect(0,0,canvas.width,canvas.height);
- /*
- if(this.render_shadows)
+ if(this.render_connections_shadows)
{
ctx.shadowColor = "#000";
ctx.shadowOffsetX = 0;
@@ -2765,12 +2966,13 @@ LGraphCanvas.prototype.drawBgcanvas = function()
}
else
ctx.shadowColor = "rgba(0,0,0,0)";
- */
//draw connections
if(!this.live_mode)
this.drawConnections(ctx);
+ ctx.shadowColor = "rgba(0,0,0,0)";
+
//restore state
ctx.restore();
}
@@ -2821,8 +3023,8 @@ LGraphCanvas.prototype.drawNode = function(node, ctx )
if(!node.flags.collapsed)
{
ctx.shadowColor = "transparent";
- if(node.onDrawBackground)
- node.onDrawBackground(ctx);
+ //if(node.onDrawBackground)
+ // node.onDrawBackground(ctx);
if(node.onDrawForeground)
node.onDrawForeground(ctx);
}
@@ -2840,13 +3042,16 @@ LGraphCanvas.prototype.drawNode = function(node, ctx )
}
*/
+ var editor_alpha = this.editor_alpha;
+ ctx.globalAlpha = editor_alpha;
+
//clip if required (mask)
var shape = node.shape || "box";
var size = new Float32Array(node.size);
if(node.flags.collapsed)
size.set([LiteGraph.NODE_COLLAPSED_WIDTH, 0]);
- //Start cliping
+ //Start clipping
if(node.flags.clip_area)
{
ctx.save();
@@ -2873,9 +3078,9 @@ LGraphCanvas.prototype.drawNode = function(node, ctx )
//connection slots
ctx.textAlign = "left";
- ctx.font = "12px Arial";
+ ctx.font = this.inner_text_font;
- var render_text = node.graph.config.canvas_scale > 0.6;
+ var render_text = this.scale > 0.6;
//render inputs and outputs
if(!node.flags.collapsed)
@@ -2886,9 +3091,9 @@ LGraphCanvas.prototype.drawNode = function(node, ctx )
{
var slot = node.inputs[i];
- ctx.globalAlpha = 1.0;
+ ctx.globalAlpha = editor_alpha;
if (this.connecting_node != null && this.connecting_output.type != 0 && node.inputs[i].type != 0 && this.connecting_output.type != node.inputs[i].type)
- ctx.globalAlpha = 0.4;
+ ctx.globalAlpha = 0.4 * editor_alpha;
ctx.fillStyle = slot.link != null ? "#7F7" : "#AAA";
@@ -2919,7 +3124,7 @@ LGraphCanvas.prototype.drawNode = function(node, ctx )
//output connection slots
if(this.connecting_node)
- ctx.globalAlpha = 0.4;
+ ctx.globalAlpha = 0.4 * editor_alpha;
ctx.lineWidth = 1;
@@ -2964,7 +3169,7 @@ LGraphCanvas.prototype.drawNode = function(node, ctx )
}
ctx.textAlign = "left";
- ctx.globalAlpha = 1.0;
+ ctx.globalAlpha = 1;
if(node.onDrawForeground)
node.onDrawForeground(ctx);
@@ -2972,6 +3177,8 @@ LGraphCanvas.prototype.drawNode = function(node, ctx )
if(node.flags.clip_area)
ctx.restore();
+
+ ctx.globalAlpha = 1.0;
}
/* Renders the node shape */
@@ -2987,7 +3194,7 @@ LGraphCanvas.prototype.drawNodeShape = function(node, ctx, size, fgcolor, bgcolo
grad.addColorStop(0.5, fgcolor || LiteGraph.NODE_DEFAULT_COLOR);
grad.addColorStop(1, bgcolor || LiteGraph.NODE_DEFAULT_BGCOLOR);
ctx.fillStyle = grad;
- */
+ //*/
var title_height = LiteGraph.NODE_TITLE_HEIGHT;
@@ -3003,7 +3210,7 @@ LGraphCanvas.prototype.drawNodeShape = function(node, ctx, size, fgcolor, bgcolo
}
ctx.beginPath();
- ctx.rect(0,no_title ? 0.5 : -title_height + 1,size[0]+1, no_title ? size[1] : size[1] + title_height);
+ ctx.rect(0,no_title ? 0.5 : -title_height + 0.5,size[0]+1, no_title ? size[1] : size[1] + title_height);
}
else if (node.shape == "round")
{
@@ -3034,7 +3241,8 @@ LGraphCanvas.prototype.drawNodeShape = function(node, ctx, size, fgcolor, bgcolo
if(!no_title)
{
ctx.fillStyle = fgcolor || LiteGraph.NODE_DEFAULT_COLOR;
-
+ var old_alpha = ctx.globalAlpha;
+ ctx.globalAlpha = 0.5 * old_alpha;
if(shape == "box")
{
ctx.beginPath();
@@ -3057,10 +3265,11 @@ LGraphCanvas.prototype.drawNodeShape = function(node, ctx, size, fgcolor, bgcolo
else
ctx.rect(3,-title_height + 3,title_height - 6,title_height - 6);
ctx.fill();
+ ctx.globalAlpha = old_alpha;
//title text
- ctx.font = "bold 12px Arial";
- if(node.name != "" && node.graph.config.canvas_scale > 0.8)
+ ctx.font = this.title_text_font;
+ if(node.name != "" && this.scale > 0.8)
{
ctx.fillStyle = "#222";
ctx.fillText(node.name,16,13-title_height );
@@ -3127,14 +3336,15 @@ LGraphCanvas.link_colors = ["#AAC","#ACA","#CAA"];
LGraphCanvas.prototype.drawConnections = function(ctx)
{
//draw connections
- ctx.lineWidth = LGraphCanvas.link_width;
+ ctx.lineWidth = this.connections_width;
ctx.fillStyle = "#AAA";
ctx.strokeStyle = "#AAA";
+ ctx.globalAlpha = this.editor_alpha;
//for every node
- for (var n in this.graph.nodes)
+ for (var n in this.graph._nodes)
{
- var node = this.graph.nodes[n];
+ var node = this.graph._nodes[n];
//for every input (we render just inputs because it is easier as every slot can only have one input)
if(node.inputs && node.inputs.length)
for(var i in node.inputs)
@@ -3156,16 +3366,14 @@ LGraphCanvas.prototype.drawConnections = function(ctx)
var color = LGraphCanvas.link_type_colors[node.inputs[i].type];
if(color == null)
color = LGraphCanvas.link_colors[node.id % LGraphCanvas.link_colors.length];
- ctx.fillStyle = ctx.strokeStyle = color;
- this.renderLink(ctx, start_node_slotpos, node.getConnectionPos(true,i) );
+ this.renderLink(ctx, start_node_slotpos, node.getConnectionPos(true,i), color );
}
}
+ ctx.globalAlpha = 1;
}
-LGraphCanvas.prototype.renderLink = function(ctx,a,b)
+LGraphCanvas.prototype.renderLink = function(ctx,a,b,color)
{
- var curved_lines = true;
-
if(!this.highquality_render)
{
ctx.beginPath();
@@ -3177,32 +3385,44 @@ LGraphCanvas.prototype.renderLink = function(ctx,a,b)
var dist = distance(a,b);
+ if(this.render_connections_border)
+ ctx.lineWidth = this.connections_width + 4;
+
ctx.beginPath();
- if(curved_lines)
+ if(this.render_curved_connections) //splines
{
ctx.moveTo(a[0],a[1]);
ctx.bezierCurveTo(a[0] + dist*0.25, a[1],
b[0] - dist*0.25 , b[1],
b[0] ,b[1] );
}
- else
+ else //lines
{
ctx.moveTo(a[0]+10,a[1]);
ctx.lineTo(((a[0]+10) + (b[0]-10))*0.5,a[1]);
ctx.lineTo(((a[0]+10) + (b[0]-10))*0.5,b[1]);
ctx.lineTo(b[0]-10,b[1]);
}
+
+ if(this.render_connections_border)
+ {
+ ctx.strokeStyle = "rgba(0,0,0,0.5)";
+ ctx.stroke();
+ }
+
+ ctx.lineWidth = this.connections_width;
+ ctx.fillStyle = ctx.strokeStyle = color;
ctx.stroke();
//render arrow
- if(this.graph.config.canvas_scale > 0.6)
+ if(this.render_connection_arrows && this.scale > 0.6)
{
//get two points in the bezier curve
var pos = this.computeConnectionPoint(a,b,0.5);
var pos2 = this.computeConnectionPoint(a,b,0.51);
var angle = 0;
- if(curved_lines)
+ if(this.render_curved_connections)
angle = -Math.atan2( pos2[0] - pos[0], pos2[1] - pos[1]);
else
angle = b[1] > a[1] ? 0 : Math.PI;
@@ -3237,6 +3457,7 @@ LGraphCanvas.prototype.computeConnectionPoint = function(a,b,t)
return [x,y];
}
+/*
LGraphCanvas.prototype.resizeCanvas = function(width,height)
{
this.canvas.width = width;
@@ -3247,12 +3468,63 @@ LGraphCanvas.prototype.resizeCanvas = function(width,height)
this.bgcanvas.height = this.canvas.height;
this.draw(true,true);
}
+*/
-LGraphCanvas.prototype.switchLiveMode = function()
+LGraphCanvas.prototype.resize = function(width, height)
{
- this.live_mode = !this.live_mode;
- this.dirty_canvas = true;
- this.dirty_bgcanvas = true;
+ if(!width && !height)
+ {
+ var parent = this.canvas.parentNode;
+ width = parent.offsetWidth;
+ height = parent.offsetHeight;
+ }
+
+ if(this.canvas.width == width && this.canvas.height == height)
+ return;
+
+ this.canvas.width = width;
+ this.canvas.height = height;
+ this.bgcanvas.width = this.canvas.width;
+ this.bgcanvas.height = this.canvas.height;
+ this.setDirty(true,true);
+}
+
+
+LGraphCanvas.prototype.switchLiveMode = function(transition)
+{
+ if(!transition)
+ {
+ this.live_mode = !this.live_mode;
+ this.dirty_canvas = true;
+ this.dirty_bgcanvas = true;
+ return;
+ }
+
+ var self = this;
+ var delta = this.live_mode ? 1.1 : 0.9;
+ if(this.live_mode)
+ {
+ this.live_mode = false;
+ this.editor_alpha = 0.1;
+ }
+
+ var t = setInterval(function() {
+ self.editor_alpha *= delta;
+ self.dirty_canvas = true;
+ self.dirty_bgcanvas = true;
+
+ if(delta < 1 && self.editor_alpha < 0.01)
+ {
+ clearInterval(t);
+ if(delta < 1)
+ self.live_mode = true;
+ }
+ if(delta > 1 && self.editor_alpha > 0.99)
+ {
+ clearInterval(t);
+ self.editor_alpha = 1;
+ }
+ },1);
}
LGraphCanvas.prototype.onNodeSelectionChange = function(node)
@@ -3279,6 +3551,9 @@ LGraphCanvas.prototype.touchHandler = function(event)
//initMouseEvent(type, canBubble, cancelable, view, clickCount,
// screenX, screenY, clientX, clientY, ctrlKey,
// altKey, shiftKey, metaKey, button, relatedTarget);
+
+ var window = this.getCanvasWindow();
+ var document = window.document;
var simulatedEvent = document.createEvent("MouseEvent");
simulatedEvent.initMouseEvent(type, true, true, window, 1,
@@ -3293,13 +3568,15 @@ LGraphCanvas.prototype.touchHandler = function(event)
LGraphCanvas.onMenuAdd = function(node, e, prev_menu, canvas, first_event )
{
+ var window = canvas.getCanvasWindow();
+
var values = LiteGraph.getNodeTypesCategories();
var entries = {};
for(var i in values)
if(values[i])
entries[ i ] = { value: values[i], content: values[i] , is_menu: true };
- var menu = LiteGraph.createContextualMenu(entries, {event: e, callback: inner_clicked, from: prev_menu});
+ var menu = LiteGraph.createContextualMenu(entries, {event: e, callback: inner_clicked, from: prev_menu}, window);
function inner_clicked(v, e)
{
@@ -3309,7 +3586,7 @@ LGraphCanvas.onMenuAdd = function(node, e, prev_menu, canvas, first_event )
for(var i in node_types)
values.push( { content: node_types[i].title, value: node_types[i].type });
- LiteGraph.createContextualMenu(values, {event: e, callback: inner_create, from: menu});
+ LiteGraph.createContextualMenu(values, {event: e, callback: inner_create, from: menu}, window);
return false;
}
@@ -3390,7 +3667,19 @@ LGraphCanvas.onMenuNodeOutputs = function(node, e, prev_menu)
function inner_clicked(v)
{
if(!node) return;
- node.addOutput(v.value[0],v.value[1]);
+
+ var value = v.value[1];
+
+ if(value && (value.constructor === Object || value.constructor === Array)) //submenu
+ {
+ var entries = [];
+ for(var i in value)
+ entries.push({content: i, value: value[i]});
+ LiteGraph.createContextualMenu(entries, {event: e, callback: inner_clicked, from: prev_menu});
+ return false;
+ }
+ else
+ node.addOutput(v.value[0],v.value[1]);
}
return false;
@@ -3402,6 +3691,11 @@ LGraphCanvas.onMenuNodeCollapse = function(node)
node.graph.canvas.setDirty(true,true);
}
+LGraphCanvas.onMenuNodePin = function(node)
+{
+ node.pin();
+}
+
LGraphCanvas.onMenuNodeColors = function(node, e, prev_menu)
{
var values = [];
@@ -3481,6 +3775,7 @@ LGraphCanvas.prototype.getNodeMenuOptions = function(node)
{content:"Outputs", is_menu: true, disabled:true, callback: LGraphCanvas.onMenuNodeOutputs },
null,
{content:"Collapse", callback: LGraphCanvas.onMenuNodeCollapse },
+ {content:"Pin", callback: LGraphCanvas.onMenuNodePin },
{content:"Colors", is_menu: true, callback: LGraphCanvas.onMenuNodeColors },
{content:"Shapes", is_menu: true, callback: LGraphCanvas.onMenuNodeShapes },
null,
@@ -3505,7 +3800,9 @@ LGraphCanvas.prototype.getNodeMenuOptions = function(node)
LGraphCanvas.prototype.processContextualMenu = function(node,event)
{
var that = this;
- var menu = LiteGraph.createContextualMenu(node ? this.getNodeMenuOptions(node) : this.getCanvasMenuOptions(), {event: event, callback: inner_option_clicked});
+ var win = this.getCanvasWindow();
+
+ var menu = LiteGraph.createContextualMenu(node ? this.getNodeMenuOptions(node) : this.getCanvasMenuOptions(), {event: event, callback: inner_option_clicked}, win);
function inner_option_clicked(v,e)
{
@@ -3641,15 +3938,18 @@ function num2hex(triplet) {
/* LiteGraph GUI elements *************************************/
-LiteGraph.createContextualMenu = function(values,options)
+LiteGraph.createContextualMenu = function(values,options, ref_window)
{
options = options || {};
this.options = options;
+ //allows to create graph canvas in separate window
+ ref_window = ref_window || window;
+
if(!options.from)
LiteGraph.closeAllContextualMenus();
- var root = document.createElement("div");
+ var root = ref_window.document.createElement("div");
root.className = "litecontextualmenu litemenubar-panel";
this.root = root;
var style = root.style;
@@ -3671,7 +3971,7 @@ LiteGraph.createContextualMenu = function(values,options)
for(var i in values)
{
var item = values[i];
- var element = document.createElement("div");
+ var element = ref_window.document.createElement("div");
element.className = "litemenu-entry";
if(item == null)
@@ -3706,7 +4006,7 @@ LiteGraph.createContextualMenu = function(values,options)
root.addEventListener("mouseout", function(e) {
//console.log("OUT!");
var aux = e.toElement;
- while(aux != this && aux != document)
+ while(aux != this && aux != ref_window.document)
aux = aux.parentNode;
if(aux == this) return;
@@ -3715,17 +4015,8 @@ LiteGraph.createContextualMenu = function(values,options)
this.closeMenu();
});
- /* MS specific
- root.addEventListener("mouseleave", function(e) {
-
- this.mouse_inside = false;
- if(!this.block_close)
- this.closeMenu();
- });
- */
-
//insert before checking position
- document.body.appendChild(root);
+ ref_window.document.body.appendChild(root);
var root_rect = root.getClientRects()[0];
@@ -3744,7 +4035,7 @@ LiteGraph.createContextualMenu = function(values,options)
if(options.left)
left = options.left;
- var rect = document.body.getClientRects()[0];
+ var rect = ref_window.document.body.getClientRects()[0];
if(options.from)
{
@@ -3785,7 +4076,7 @@ LiteGraph.createContextualMenu = function(values,options)
options.from.closeMenu();
}
if(this.parentNode)
- document.body.removeChild(this);
+ ref_window.document.body.removeChild(this);
};
return root;
@@ -3812,4 +4103,23 @@ LiteGraph.extendClass = function(origin, target)
if(origin.prototype) //copy prototype properties
for(var i in origin.prototype)
target.prototype[i] = origin.prototype[i];
-}
\ No newline at end of file
+}
+
+/*
+LiteGraph.createNodetypeWrapper = function( class_object )
+{
+ //create Nodetype object
+}
+//LiteGraph.registerNodeType("scene/global", LGraphGlobal );
+*/
+
+if( !window["requestAnimationFrame"] )
+{
+ window.requestAnimationFrame = window.webkitRequestAnimationFrame ||
+ window.mozRequestAnimationFrame ||
+ (function( callback ){
+ window.setTimeout(callback, 1000 / 60);
+ });
+}
+
+
diff --git a/src/nodes/uinodes.js b/src/nodes/uinodes.js
index cede31931..9eb0d2529 100644
--- a/src/nodes/uinodes.js
+++ b/src/nodes/uinodes.js
@@ -79,7 +79,7 @@
ctx.textAlign = "left";
},
- onDrawBackground: function(ctx)
+ onDrawForeground: function(ctx)
{
this.onDrawImageKnob(ctx);
},
@@ -227,7 +227,7 @@
ctx.drawImage(this.imgfg, 2+(this.size[0]-4)*this.value - this.imgfg.width*0.5,-this.imgfg.height*0.5 + 10);
},
- onDrawBackground: function(ctx)
+ onDrawForeground: function(ctx)
{
this.onDrawImage(ctx);
},
@@ -451,7 +451,7 @@
ctx.textAlign = "left";
},
- onDrawBackground: function(ctx)
+ onDrawForeground: function(ctx)
{
this.drawBevelShape(ctx);
},
@@ -515,7 +515,7 @@
if( v != undefined )
this.properties["value"] = v;
},
- onDrawBackground: function(ctx)
+ onDrawForeground: function(ctx)
{
//border
ctx.lineWidth = 1;
@@ -535,7 +535,7 @@
inputs: [["",0]],
properties:{value:"...",font:"Arial", fontsize:18, color:"#AAA", align:"left", glowSize:0, decimals:1},
- onDrawBackground: function(ctx)
+ onDrawForeground: function(ctx)
{
//ctx.fillStyle="#000";
//ctx.fillRect(0,0,100,60);
@@ -645,7 +645,7 @@
this.lineargradient.addColorStop(1,this.properties["bgcolorBottom"]);
},
- onDrawBackground: function(ctx)
+ onDrawForeground: function(ctx)
{
if(this.lineargradient == null)
this.createGradient(ctx);