fixes in the horizontal nodes collapsed, also performance improvements

This commit is contained in:
tamat
2018-12-17 19:18:04 +01:00
parent 6c810d3ca8
commit b576b52fda
5 changed files with 948 additions and 666 deletions

View File

@@ -14,7 +14,7 @@
target_id: number,
target_slot: number,
data: *
};
}; //it can contain color to colorize this particular link
*/
/**
@@ -1506,7 +1506,7 @@ LGraph.prototype.setCallback = function(name,func)
}
LGraph.prototype.connectionChange = function( node )
LGraph.prototype.connectionChange = function( node, link_info )
{
this.updateExecutionOrder();
if( this.onConnectionChange )
@@ -1534,6 +1534,23 @@ LGraph.prototype.isLive = function()
return false;
}
/**
* clears the triggered slot animation in all links
* @method clearTriggeredSlots
*/
LGraph.prototype.clearTriggeredSlots = function()
{
for(var i in this.links)
{
var link_info = this.links[k];
if( !link_info )
continue;
if( link_info._last_time )
link_info._last_time = 0;
}
}
/* Called when something visually changed (not the graph!) */
LGraph.prototype.change = function()
{
@@ -1726,8 +1743,11 @@ LGraph.prototype.onNodeTrace = function(node, msg, color)
+ onPropertyChanged: when a property is changed in the panel (return true to skip default behaviour)
+ onGetInputs: returns an array of possible inputs
+ onGetOutputs: returns an array of possible outputs
+ onDblClick
+ onSerialize
+ onBounding: in case this node has a bigger bounding than the node itself (the callback receives the bounding as [x,y,w,h])
+ onDblClick: double clicked in the node
+ onInputDblClick: input slot double clicked (can be used to automatically create a node connected)
+ onOutputDblClick: output slot double clicked (can be used to automatically create a node connected)
+ onSerialize: to add extra info when serializing (the callback receives the object that should be filled with the data)
+ onSelected
+ onDeselected
+ onDropItem : DOM item dropped over the node
@@ -2331,6 +2351,38 @@ LGraphNode.prototype.triggerSlot = function( slot, param, link_id )
}
}
/**
* clears the trigger slot animation
* @method clearTriggeredSlot
* @param {Number} slot the index of the output slot
* @param {Number} link_id [optional] in case you want to trigger and specific output link in a slot
*/
LGraphNode.prototype.clearTriggeredSlot = function( slot, link_id )
{
if( !this.outputs )
return;
var output = this.outputs[ slot ];
if( !output )
return;
var links = output.links;
if(!links || !links.length)
return;
//for every link attached here
for(var k = 0; k < links.length; ++k)
{
var id = links[k];
if( link_id != null && link_id != id ) //to skip links
continue;
var link_info = this.graph.links[ links[k] ];
if(!link_info) //not connected
continue;
link_info._last_time = 0;
}
}
/**
* add a new property to this node
* @method addProperty
@@ -2634,6 +2686,9 @@ LGraphNode.prototype.getBounding = function( out )
out[1] = this.pos[1] - LiteGraph.NODE_TITLE_HEIGHT;
out[2] = this.size[0] + 4;
out[3] = this.size[1] + LiteGraph.NODE_TITLE_HEIGHT;
if( this.onBounding )
this.onBounding( out );
return out;
}
@@ -2673,11 +2728,12 @@ LGraphNode.prototype.isPointInside = function( x, y, margin, skip_title )
LGraphNode.prototype.getSlotInPosition = function( x, y )
{
//search for inputs
var link_pos = new Float32Array(2);
if(this.inputs)
for(var i = 0, l = this.inputs.length; i < l; ++i)
{
var input = this.inputs[i];
var link_pos = this.getConnectionPos( true,i );
this.getConnectionPos( true,i, link_pos );
if( isInsideRectangle(x, y, link_pos[0] - 10, link_pos[1] - 5, 20,10) )
return { input: input, slot: i, link_pos: link_pos, locked: input.locked };
}
@@ -2686,7 +2742,7 @@ LGraphNode.prototype.getSlotInPosition = function( x, y )
for(var i = 0, l = this.outputs.length; i < l; ++i)
{
var output = this.outputs[i];
var link_pos = this.getConnectionPos(false,i);
this.getConnectionPos(false,i,link_pos);
if( isInsideRectangle(x, y, link_pos[0] - 10, link_pos[1] - 5, 20,10) )
return { output: output, slot: i, link_pos: link_pos, locked: output.locked };
}
@@ -2731,7 +2787,7 @@ LGraphNode.prototype.findOutputSlot = function(name)
* @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, or -1 to connect a trigger)
* @return {boolean} if it was connected succesfully
* @return {Object} the link_info is created, otherwise null
*/
LGraphNode.prototype.connect = function( slot, target_node, target_slot )
{
@@ -2740,7 +2796,7 @@ LGraphNode.prototype.connect = function( slot, target_node, target_slot )
if(!this.graph) //could be connected before adding it to a graph
{
console.log("Connect: Error, node doesnt belong to any graph. Nodes must be added first to a graph before connecting them."); //due to link ids being associated with graphs
return false;
return null;
}
@@ -2752,14 +2808,14 @@ LGraphNode.prototype.connect = function( slot, target_node, target_slot )
{
if(LiteGraph.debug)
console.log("Connect: Error, no slot of name " + slot);
return false;
return null;
}
}
else if(!this.outputs || slot >= this.outputs.length)
{
if(LiteGraph.debug)
console.log("Connect: Error, slot number not found");
return false;
return null;
}
if(target_node && target_node.constructor === Number)
@@ -2769,7 +2825,7 @@ LGraphNode.prototype.connect = function( slot, target_node, target_slot )
//avoid loopback
if(target_node == this)
return false;
return null;
//you can specify the slot by name
if(target_slot.constructor === String)
@@ -2779,7 +2835,7 @@ LGraphNode.prototype.connect = function( slot, target_node, target_slot )
{
if(LiteGraph.debug)
console.log("Connect: Error, no slot of name " + target_slot);
return false;
return null;
}
}
else if( target_slot === LiteGraph.EVENT )
@@ -2791,13 +2847,13 @@ LGraphNode.prototype.connect = function( slot, target_node, target_slot )
target_slot = target_node.inputs.length - 1; //last one is the one created
target_node.mode = LiteGraph.ON_TRIGGER;
*/
return false;
return null;
}
else if( !target_node.inputs || target_slot >= target_node.inputs.length )
{
if(LiteGraph.debug)
console.log("Connect: Error, slot number not found");
return false;
return null;
}
//if there is something already plugged there, disconnect
@@ -2813,13 +2869,14 @@ LGraphNode.prototype.connect = function( slot, target_node, target_slot )
//allows nodes to block connection
if(target_node.onConnectInput)
if( target_node.onConnectInput( target_slot, output.type, output ) === false)
return false;
return null;
var input = target_node.inputs[target_slot];
var link_info = null;
if( LiteGraph.isValidConnection( output.type, input.type ) )
{
var link_info = {
link_info = {
id: this.graph.last_link_id++,
type: input.type,
origin_id: this.id,
@@ -2851,9 +2908,9 @@ LGraphNode.prototype.connect = function( slot, target_node, target_slot )
}
this.setDirtyCanvas(false,true);
this.graph.connectionChange( this );
this.graph.connectionChange( this, link_info );
return true;
return link_info;
}
/**
@@ -3043,41 +3100,79 @@ LGraphNode.prototype.disconnectInput = function( slot )
* @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)
* @param {vec2} out [optional] a place to store the output, to free garbage
* @return {[x,y]} the position
**/
LGraphNode.prototype.getConnectionPos = function( is_input, slot_number )
LGraphNode.prototype.getConnectionPos = function( is_input, slot_number, out )
{
out = out || new Float32Array(2);
var num_slots = 0;
if( is_input && this.inputs )
num_slots = this.inputs.length;
if( !is_input && this.outputs )
num_slots = this.outputs.length;
if(this.flags.collapsed)
{
if(is_input)
return [this.pos[0], this.pos[1] - LiteGraph.NODE_TITLE_HEIGHT * 0.5];
var w = (this._collapsed_width || LiteGraph.NODE_COLLAPSED_WIDTH);
if( this.flags.horizontal )
{
out[0] = this.pos[0] + w * 0.5;
if(is_input)
out[1] = this.pos[1] - LiteGraph.NODE_TITLE_HEIGHT;
else
out[1] = this.pos[1];
}
else
return [this.pos[0] + (this._collapsed_width || LiteGraph.NODE_COLLAPSED_WIDTH), this.pos[1] - LiteGraph.NODE_TITLE_HEIGHT * 0.5];
{
if(is_input)
out[0] = this.pos[0];
else
out[0] = this.pos[0] + w;
out[1] = this.pos[1] - LiteGraph.NODE_TITLE_HEIGHT * 0.5;
}
return out;
}
if(is_input && slot_number == -1)
{
return [this.pos[0] + 10, this.pos[1] + 10];
out[0] = this.pos[0] + 10;
out[1] = this.pos[1] + 10;
return out;
}
//hardcoded pos
if(is_input && this.inputs && this.inputs.length > slot_number && this.inputs[slot_number].pos)
return [this.pos[0] + this.inputs[slot_number].pos[0],this.pos[1] + this.inputs[slot_number].pos[1]];
else if(!is_input && this.outputs && this.outputs.length > slot_number && this.outputs[slot_number].pos)
return [this.pos[0] + this.outputs[slot_number].pos[0],this.pos[1] + this.outputs[slot_number].pos[1]];
if(is_input && num_slots > slot_number && this.inputs[ slot_number ].pos)
{
out[0] = this.pos[0] + this.inputs[slot_number].pos[0];
out[1] = this.pos[1] + this.inputs[slot_number].pos[1];
return out;
}
else if(!is_input && num_slots > slot_number && this.outputs[ slot_number ].pos)
{
out[0] = this.pos[0] + this.outputs[slot_number].pos[0];
out[1] = this.pos[1] + this.outputs[slot_number].pos[1];
return out;
}
//horizontal distributed slots
if(this.flags.horizontal)
{
out[0] = this.pos[0] + (slot_number + 0.5) * (this.size[0] / num_slots);
if(is_input)
return [this.pos[0] + (slot_number + 0.5) * (this.size[0] / (this.inputs.length)), this.pos[1] - LiteGraph.NODE_TITLE_HEIGHT ];
return [this.pos[0] + (slot_number + 0.5) * (this.size[0] / (this.outputs.length)), this.pos[1] + this.size[1] ];
out[1] = this.pos[1] - LiteGraph.NODE_TITLE_HEIGHT;
else
out[1] = this.pos[1] + this.size[1];
return out;
}
//default
if(is_input)
return [this.pos[0] , this.pos[1] + 10 + slot_number * LiteGraph.NODE_SLOT_HEIGHT + (this.constructor.slot_start_y || 0) ];
return [this.pos[0] + this.size[0] + 1, this.pos[1] + 10 + slot_number * LiteGraph.NODE_SLOT_HEIGHT + (this.constructor.slot_start_y || 0)];
out[0] = this.pos[0];
else
out[0] = this.pos[0] + this.size[0] + 1;
out[1] = this.pos[1] + 10 + slot_number * LiteGraph.NODE_SLOT_HEIGHT + (this.constructor.slot_start_y || 0);
return out;
}
/* Force align to grid */
@@ -3941,7 +4036,7 @@ LGraphCanvas.prototype.processMouseDown = function(e)
this.connecting_node = this.graph._nodes_by_id[ link_info.origin_id ];
this.connecting_slot = link_info.origin_slot;
this.connecting_output = this.connecting_node.outputs[ this.connecting_slot ];
this.connecting_pos = this.connecting_node.getConnectionPos( false, this.connecting_slot);
this.connecting_pos = this.connecting_node.getConnectionPos( false, this.connecting_slot );
}
this.dirty_bgcanvas = true;
@@ -4463,7 +4558,7 @@ LGraphCanvas.prototype.isOverNodeInput = function(node, canvasx, canvasy, slot_p
for(var i = 0, l = node.inputs.length; i < l; ++i)
{
var input = node.inputs[i];
var link_pos = node.getConnectionPos(true,i);
var link_pos = node.getConnectionPos( true, i );
if( isInsideRectangle(canvasx, canvasy, link_pos[0] - 10, link_pos[1] - 5, 20,10) )
{
if(slot_pos)
@@ -5151,12 +5246,14 @@ LGraphCanvas.prototype.drawFrontCanvas = function()
{
ctx.lineWidth = this.connections_width;
var link_color = null;
switch( this.connecting_output.type )
{
case LiteGraph.EVENT: link_color = LiteGraph.EVENT_LINK_COLOR; break;
default:
link_color = LiteGraph.CONNECTING_LINK_COLOR;
}
//the connection being dragged by the mouse
this.renderLink( ctx, this.connecting_pos, [ this.canvas_mouse[0], this.canvas_mouse[1] ], null, false, null, link_color, this.connecting_output.dir || (this.connecting_node.flags.horizontal ? LiteGraph.DOWN : LiteGraph.RIGHT), LiteGraph.CENTER );
@@ -5462,6 +5559,7 @@ LGraphCanvas.prototype.drawNode = function(node, ctx )
ctx.lineWidth = 1;
var max_y = 0;
var slot_pos = new Float32Array(2); //to reuse
//render inputs and outputs
if(!node.flags.collapsed)
@@ -5479,7 +5577,7 @@ LGraphCanvas.prototype.drawNode = function(node, ctx )
ctx.fillStyle = slot.link != null ? (slot.color_on || this.default_connection_color.input_on) : (slot.color_off || this.default_connection_color.input_off);
var pos = node.getConnectionPos( true, i );
var pos = node.getConnectionPos( true, i, slot_pos );
pos[0] -= node.pos[0];
pos[1] -= node.pos[1];
if( max_y < pos[1] + LiteGraph.NODE_SLOT_HEIGHT*0.5 )
@@ -5526,7 +5624,7 @@ LGraphCanvas.prototype.drawNode = function(node, ctx )
{
var slot = node.outputs[i];
var pos = node.getConnectionPos(false,i);
var pos = node.getConnectionPos(false,i, slot_pos );
pos[0] -= node.pos[0];
pos[1] -= node.pos[1];
if( max_y < pos[1] + LiteGraph.NODE_SLOT_HEIGHT*0.5)
@@ -5586,6 +5684,10 @@ LGraphCanvas.prototype.drawNode = function(node, ctx )
}
else //if collapsed
{
var input_slot = null;
var output_slot = null;
//get first connected slot to render
if(node.inputs)
{
for(var i = 0; i < node.inputs.length; i++)
@@ -5593,23 +5695,10 @@ LGraphCanvas.prototype.drawNode = function(node, ctx )
var slot = node.inputs[i];
if( slot.link == null )
continue;
ctx.fillStyle = slot.color_on || this.default_connection_color.input_on;
ctx.beginPath();
if ( slot.type === LiteGraph.EVENT || slot.shape === LiteGraph.BOX_SHAPE) {
ctx.rect(0.5, 4 - LiteGraph.NODE_TITLE_HEIGHT + 0.5,14,LiteGraph.NODE_TITLE_HEIGHT - 8);
} else if (slot.shape === LiteGraph.ARROW_SHAPE) {
ctx.moveTo(8, LiteGraph.NODE_TITLE_HEIGHT * -0.5);
ctx.lineTo(-4, LiteGraph.NODE_TITLE_HEIGHT * -0.8);
ctx.lineTo(-4, LiteGraph.NODE_TITLE_HEIGHT * -0.2);
ctx.closePath();
} else {
ctx.arc(0, LiteGraph.NODE_TITLE_HEIGHT * -0.5, 4, 0, Math.PI * 2);
}
ctx.fill();
input_slot = slot;
break;
}
}
if(node.outputs)
{
for(var i = 0; i < node.outputs.length; i++)
@@ -5617,23 +5706,60 @@ LGraphCanvas.prototype.drawNode = function(node, ctx )
var slot = node.outputs[i];
if(!slot.links || !slot.links.length)
continue;
ctx.fillStyle = slot.color_on || this.default_connection_color.output_on;
ctx.strokeStyle = "black";
ctx.beginPath();
if (slot.type === LiteGraph.EVENT || slot.shape === LiteGraph.BOX_SHAPE) {
ctx.rect( node._collapsed_width - 4 + 0.5, 4 - LiteGraph.NODE_TITLE_HEIGHT + 0.5,14,LiteGraph.NODE_TITLE_HEIGHT - 8);
} else if (slot.shape === LiteGraph.ARROW_SHAPE) {
ctx.moveTo(node._collapsed_width + 6, LiteGraph.NODE_TITLE_HEIGHT * -0.5);
ctx.lineTo(node._collapsed_width - 6, LiteGraph.NODE_TITLE_HEIGHT * -0.8);
ctx.lineTo(node._collapsed_width - 6, LiteGraph.NODE_TITLE_HEIGHT * -0.2);
ctx.closePath();
} else {
ctx.arc(node._collapsed_width, LiteGraph.NODE_TITLE_HEIGHT * -0.5, 4, 0, Math.PI * 2);
}
ctx.fill();
ctx.stroke();
output_slot = slot;
}
}
if(input_slot)
{
var x = 0;
var y = LiteGraph.NODE_TITLE_HEIGHT * -0.5; //center
if( node.flags.horizontal )
{
x = node._collapsed_width * 0.5;
y = -LiteGraph.NODE_TITLE_HEIGHT;
}
ctx.fillStyle = slot.color_on || this.default_connection_color.input_on;
ctx.beginPath();
if ( slot.type === LiteGraph.EVENT || slot.shape === LiteGraph.BOX_SHAPE) {
ctx.rect(x + 0.5, y + 4 - LiteGraph.NODE_TITLE_HEIGHT * 0.5 + 0.5,14,LiteGraph.NODE_TITLE_HEIGHT - 8);
} else if (slot.shape === LiteGraph.ARROW_SHAPE) {
ctx.moveTo(x + 8, y);
ctx.lineTo(x + -4, y - 4);
ctx.lineTo(x + -4, y + 4);
ctx.closePath();
} else {
ctx.arc(x, y, 4, 0, Math.PI * 2);
}
ctx.fill();
}
if(output_slot)
{
var x = node._collapsed_width;
var y = LiteGraph.NODE_TITLE_HEIGHT * -0.5; //center
if( node.flags.horizontal )
{
x = node._collapsed_width * 0.5;
y = 0;
}
ctx.fillStyle = slot.color_on || this.default_connection_color.output_on;
ctx.strokeStyle = "black";
ctx.beginPath();
if (slot.type === LiteGraph.EVENT || slot.shape === LiteGraph.BOX_SHAPE) {
ctx.rect( x - 4 + 0.5, 4 - LiteGraph.NODE_TITLE_HEIGHT * 0.5 + 0.5,14,LiteGraph.NODE_TITLE_HEIGHT - 8);
} else if (slot.shape === LiteGraph.ARROW_SHAPE) {
ctx.moveTo(x + 6, y);
ctx.lineTo(x - 6, y - 4);
ctx.lineTo(x - 6, y + 4);
ctx.closePath();
} else {
ctx.arc(x, y, 4, 0, Math.PI * 2);
}
ctx.fill();
ctx.stroke();
}
}
@@ -5647,6 +5773,8 @@ LGraphCanvas.prototype.drawNode = function(node, ctx )
* draws the shape of the given node in the canvas
* @method drawNodeShape
**/
var tmp_area = new Float32Array(4);
LGraphCanvas.prototype.drawNodeShape = function( node, ctx, size, fgcolor, bgcolor, selected, mouse_over )
{
//bg rect
@@ -5665,19 +5793,20 @@ LGraphCanvas.prototype.drawNodeShape = function( node, ctx, size, fgcolor, bgcol
else if( title_mode == LiteGraph.AUTOHIDE_TITLE && mouse_over)
render_title = true;
var areax = 0;
var areay = render_title ? -title_height : 0;
var areaw = size[0]+1;
var areah = render_title ? size[1] + title_height : size[1];
var area = tmp_area;
area[0] = 0; //x
area[1] = render_title ? -title_height : 0; //y
area[2] = size[0]+1; //w
area[3] = render_title ? size[1] + title_height : size[1]; //h
//full node shape
if(!node.flags.collapsed)
{
ctx.beginPath();
if(shape == LiteGraph.BOX_SHAPE || this.scale < 0.5)
ctx.fillRect( areax, areay, areaw, areah );
ctx.fillRect( area[0], area[1], area[2], area[3] );
else if (shape == LiteGraph.ROUND_SHAPE || shape == LiteGraph.CARD_SHAPE)
ctx.roundRect( areax, areay, areaw, areah, this.round_radius, shape == LiteGraph.CARD_SHAPE ? 0 : this.round_radius);
ctx.roundRect( area[0], area[1], area[2], area[3], this.round_radius, shape == LiteGraph.CARD_SHAPE ? 0 : this.round_radius);
else if (shape == LiteGraph.CIRCLE_SHAPE)
ctx.arc(size[0] * 0.5, size[1] * 0.5, size[0] * 0.5, 0, Math.PI*2);
ctx.fill();
@@ -5790,20 +5919,23 @@ LGraphCanvas.prototype.drawNodeShape = function( node, ctx, size, fgcolor, bgcol
//render selection marker
if(selected)
{
if( node.onBounding )
node.onBounding( area );
if( title_mode == LiteGraph.TRANSPARENT_TITLE )
{
areay -= title_height;
areah += title_height;
area[1] -= title_height;
area[3] += title_height;
}
ctx.lineWidth = 1;
ctx.globalAlpha = 0.8;
ctx.beginPath();
if(shape == LiteGraph.BOX_SHAPE)
ctx.rect(-6 + areax,-6 + areay, 12 + areaw, 12 + areah );
ctx.rect(-6 + area[0],-6 + area[1], 12 + area[2], 12 + area[3] );
else if (shape == LiteGraph.ROUND_SHAPE || (shape == LiteGraph.CARD_SHAPE && node.flags.collapsed) )
ctx.roundRect(-6 + areax,-6 + areay, 12 + areaw, 12 + areah , this.round_radius * 2);
ctx.roundRect(-6 + area[0],-6 + area[1], 12 + area[2], 12 + area[3] , this.round_radius * 2);
else if (shape == LiteGraph.CARD_SHAPE)
ctx.roundRect(-6 + areax,-6 + areay, 12 + areaw, 12 + areah , this.round_radius * 2, 2);
ctx.roundRect(-6 + area[0],-6 + area[1], 12 + area[2], 12 + area[3] , this.round_radius * 2, 2);
else if (shape == LiteGraph.CIRCLE_SHAPE)
ctx.arc(size[0] * 0.5, size[1] * 0.5, size[0] * 0.5 + 6, 0, Math.PI*2);
ctx.strokeStyle = "#FFF";
@@ -5824,6 +5956,8 @@ LGraphCanvas.prototype.drawConnections = function(ctx)
var visible_area = this.visible_area;
var margin_area = new Float32Array([visible_area[0] - 20, visible_area[1] - 20, visible_area[2] + 40, visible_area[3] + 40 ]);
var link_bounding = new Float32Array(4);
var tempA = new Float32Array(2);
var tempB = new Float32Array(2);
//draw connections
ctx.lineWidth = this.connections_width;
@@ -5858,8 +5992,8 @@ LGraphCanvas.prototype.drawConnections = function(ctx)
if(start_node_slot == -1)
start_node_slotpos = [start_node.pos[0] + 10, start_node.pos[1] + 10];
else
start_node_slotpos = start_node.getConnectionPos(false, start_node_slot);
var end_node_slotpos = node.getConnectionPos(true,i);
start_node_slotpos = start_node.getConnectionPos( false, start_node_slot, tempA );
var end_node_slotpos = node.getConnectionPos( true, i, tempB );
//compute link bounding
link_bounding[0] = start_node_slotpos[0];
@@ -5926,7 +6060,7 @@ LGraphCanvas.prototype.renderLink = function( ctx, a, b, link, skip_border, flow
//choose color
if( !color && link )
color = LGraphCanvas.link_type_colors[ link.type ];
color = link.color || LGraphCanvas.link_type_colors[ link.type ];
if( !color )
color = this.default_link_color;
@@ -7855,7 +7989,7 @@ function ContextMenu( values, options )
return;
if(root.closing_timer)
clearTimeout( root.closing_timer );
root.closing_timer = setTimeout( that.close.bind(that), 500 );
root.closing_timer = setTimeout( that.close.bind(that, e), 500 );
//that.close(e);
});

1016
build/litegraph.min.js vendored

File diff suppressed because it is too large Load Diff

View File

@@ -227,7 +227,7 @@
user-select: none;
-moz-user-select: none;
-webkit-user-select: none;
transition: all linear 0.5s;
transition: all linear 0.3s;
}
.graphmenu-entry.event, .litemenu-entry.event {

View File

@@ -156,6 +156,12 @@ TestSpecialNode.prototype.onDrawBackground = function(ctx)
ctx.moveTo(this.size[0]-40,0);
ctx.lineTo(this.size[0]-45,20);
ctx.stroke();
if( this.mouseOver )
{
ctx.fillStyle = "#AAA";
ctx.fillText( "Example of helper", 0, this.size[1] + 14 );
}
}
TestSpecialNode.prototype.onMouseDown = function(e, pos)
@@ -169,6 +175,12 @@ TestSpecialNode.prototype.onMouseDown = function(e, pos)
this.visible = !this.visible;
}
TestSpecialNode.prototype.onBounding = function(rect)
{
if(!this.flags.collapsed && this.mouseOver )
rect[3] = this.size[1] + 20;
}
LiteGraph.registerNodeType("features/shape", TestSpecialNode );

View File

@@ -12,7 +12,7 @@
target_id: number,
target_slot: number,
data: *
};
}; //it can contain color to colorize this particular link
*/
/**
@@ -1504,7 +1504,7 @@ LGraph.prototype.setCallback = function(name,func)
}
LGraph.prototype.connectionChange = function( node )
LGraph.prototype.connectionChange = function( node, link_info )
{
this.updateExecutionOrder();
if( this.onConnectionChange )
@@ -1532,6 +1532,23 @@ LGraph.prototype.isLive = function()
return false;
}
/**
* clears the triggered slot animation in all links
* @method clearTriggeredSlots
*/
LGraph.prototype.clearTriggeredSlots = function()
{
for(var i in this.links)
{
var link_info = this.links[k];
if( !link_info )
continue;
if( link_info._last_time )
link_info._last_time = 0;
}
}
/* Called when something visually changed (not the graph!) */
LGraph.prototype.change = function()
{
@@ -1724,8 +1741,11 @@ LGraph.prototype.onNodeTrace = function(node, msg, color)
+ onPropertyChanged: when a property is changed in the panel (return true to skip default behaviour)
+ onGetInputs: returns an array of possible inputs
+ onGetOutputs: returns an array of possible outputs
+ onDblClick
+ onSerialize
+ onBounding: in case this node has a bigger bounding than the node itself (the callback receives the bounding as [x,y,w,h])
+ onDblClick: double clicked in the node
+ onInputDblClick: input slot double clicked (can be used to automatically create a node connected)
+ onOutputDblClick: output slot double clicked (can be used to automatically create a node connected)
+ onSerialize: to add extra info when serializing (the callback receives the object that should be filled with the data)
+ onSelected
+ onDeselected
+ onDropItem : DOM item dropped over the node
@@ -2329,6 +2349,38 @@ LGraphNode.prototype.triggerSlot = function( slot, param, link_id )
}
}
/**
* clears the trigger slot animation
* @method clearTriggeredSlot
* @param {Number} slot the index of the output slot
* @param {Number} link_id [optional] in case you want to trigger and specific output link in a slot
*/
LGraphNode.prototype.clearTriggeredSlot = function( slot, link_id )
{
if( !this.outputs )
return;
var output = this.outputs[ slot ];
if( !output )
return;
var links = output.links;
if(!links || !links.length)
return;
//for every link attached here
for(var k = 0; k < links.length; ++k)
{
var id = links[k];
if( link_id != null && link_id != id ) //to skip links
continue;
var link_info = this.graph.links[ links[k] ];
if(!link_info) //not connected
continue;
link_info._last_time = 0;
}
}
/**
* add a new property to this node
* @method addProperty
@@ -2632,6 +2684,9 @@ LGraphNode.prototype.getBounding = function( out )
out[1] = this.pos[1] - LiteGraph.NODE_TITLE_HEIGHT;
out[2] = this.size[0] + 4;
out[3] = this.size[1] + LiteGraph.NODE_TITLE_HEIGHT;
if( this.onBounding )
this.onBounding( out );
return out;
}
@@ -2671,11 +2726,12 @@ LGraphNode.prototype.isPointInside = function( x, y, margin, skip_title )
LGraphNode.prototype.getSlotInPosition = function( x, y )
{
//search for inputs
var link_pos = new Float32Array(2);
if(this.inputs)
for(var i = 0, l = this.inputs.length; i < l; ++i)
{
var input = this.inputs[i];
var link_pos = this.getConnectionPos( true,i );
this.getConnectionPos( true,i, link_pos );
if( isInsideRectangle(x, y, link_pos[0] - 10, link_pos[1] - 5, 20,10) )
return { input: input, slot: i, link_pos: link_pos, locked: input.locked };
}
@@ -2684,7 +2740,7 @@ LGraphNode.prototype.getSlotInPosition = function( x, y )
for(var i = 0, l = this.outputs.length; i < l; ++i)
{
var output = this.outputs[i];
var link_pos = this.getConnectionPos(false,i);
this.getConnectionPos(false,i,link_pos);
if( isInsideRectangle(x, y, link_pos[0] - 10, link_pos[1] - 5, 20,10) )
return { output: output, slot: i, link_pos: link_pos, locked: output.locked };
}
@@ -2729,7 +2785,7 @@ LGraphNode.prototype.findOutputSlot = function(name)
* @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, or -1 to connect a trigger)
* @return {boolean} if it was connected succesfully
* @return {Object} the link_info is created, otherwise null
*/
LGraphNode.prototype.connect = function( slot, target_node, target_slot )
{
@@ -2738,7 +2794,7 @@ LGraphNode.prototype.connect = function( slot, target_node, target_slot )
if(!this.graph) //could be connected before adding it to a graph
{
console.log("Connect: Error, node doesnt belong to any graph. Nodes must be added first to a graph before connecting them."); //due to link ids being associated with graphs
return false;
return null;
}
@@ -2750,14 +2806,14 @@ LGraphNode.prototype.connect = function( slot, target_node, target_slot )
{
if(LiteGraph.debug)
console.log("Connect: Error, no slot of name " + slot);
return false;
return null;
}
}
else if(!this.outputs || slot >= this.outputs.length)
{
if(LiteGraph.debug)
console.log("Connect: Error, slot number not found");
return false;
return null;
}
if(target_node && target_node.constructor === Number)
@@ -2767,7 +2823,7 @@ LGraphNode.prototype.connect = function( slot, target_node, target_slot )
//avoid loopback
if(target_node == this)
return false;
return null;
//you can specify the slot by name
if(target_slot.constructor === String)
@@ -2777,7 +2833,7 @@ LGraphNode.prototype.connect = function( slot, target_node, target_slot )
{
if(LiteGraph.debug)
console.log("Connect: Error, no slot of name " + target_slot);
return false;
return null;
}
}
else if( target_slot === LiteGraph.EVENT )
@@ -2789,13 +2845,13 @@ LGraphNode.prototype.connect = function( slot, target_node, target_slot )
target_slot = target_node.inputs.length - 1; //last one is the one created
target_node.mode = LiteGraph.ON_TRIGGER;
*/
return false;
return null;
}
else if( !target_node.inputs || target_slot >= target_node.inputs.length )
{
if(LiteGraph.debug)
console.log("Connect: Error, slot number not found");
return false;
return null;
}
//if there is something already plugged there, disconnect
@@ -2811,13 +2867,14 @@ LGraphNode.prototype.connect = function( slot, target_node, target_slot )
//allows nodes to block connection
if(target_node.onConnectInput)
if( target_node.onConnectInput( target_slot, output.type, output ) === false)
return false;
return null;
var input = target_node.inputs[target_slot];
var link_info = null;
if( LiteGraph.isValidConnection( output.type, input.type ) )
{
var link_info = {
link_info = {
id: this.graph.last_link_id++,
type: input.type,
origin_id: this.id,
@@ -2849,9 +2906,9 @@ LGraphNode.prototype.connect = function( slot, target_node, target_slot )
}
this.setDirtyCanvas(false,true);
this.graph.connectionChange( this );
this.graph.connectionChange( this, link_info );
return true;
return link_info;
}
/**
@@ -3041,41 +3098,79 @@ LGraphNode.prototype.disconnectInput = function( slot )
* @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)
* @param {vec2} out [optional] a place to store the output, to free garbage
* @return {[x,y]} the position
**/
LGraphNode.prototype.getConnectionPos = function( is_input, slot_number )
LGraphNode.prototype.getConnectionPos = function( is_input, slot_number, out )
{
out = out || new Float32Array(2);
var num_slots = 0;
if( is_input && this.inputs )
num_slots = this.inputs.length;
if( !is_input && this.outputs )
num_slots = this.outputs.length;
if(this.flags.collapsed)
{
if(is_input)
return [this.pos[0], this.pos[1] - LiteGraph.NODE_TITLE_HEIGHT * 0.5];
var w = (this._collapsed_width || LiteGraph.NODE_COLLAPSED_WIDTH);
if( this.flags.horizontal )
{
out[0] = this.pos[0] + w * 0.5;
if(is_input)
out[1] = this.pos[1] - LiteGraph.NODE_TITLE_HEIGHT;
else
out[1] = this.pos[1];
}
else
return [this.pos[0] + (this._collapsed_width || LiteGraph.NODE_COLLAPSED_WIDTH), this.pos[1] - LiteGraph.NODE_TITLE_HEIGHT * 0.5];
{
if(is_input)
out[0] = this.pos[0];
else
out[0] = this.pos[0] + w;
out[1] = this.pos[1] - LiteGraph.NODE_TITLE_HEIGHT * 0.5;
}
return out;
}
if(is_input && slot_number == -1)
{
return [this.pos[0] + 10, this.pos[1] + 10];
out[0] = this.pos[0] + 10;
out[1] = this.pos[1] + 10;
return out;
}
//hardcoded pos
if(is_input && this.inputs && this.inputs.length > slot_number && this.inputs[slot_number].pos)
return [this.pos[0] + this.inputs[slot_number].pos[0],this.pos[1] + this.inputs[slot_number].pos[1]];
else if(!is_input && this.outputs && this.outputs.length > slot_number && this.outputs[slot_number].pos)
return [this.pos[0] + this.outputs[slot_number].pos[0],this.pos[1] + this.outputs[slot_number].pos[1]];
if(is_input && num_slots > slot_number && this.inputs[ slot_number ].pos)
{
out[0] = this.pos[0] + this.inputs[slot_number].pos[0];
out[1] = this.pos[1] + this.inputs[slot_number].pos[1];
return out;
}
else if(!is_input && num_slots > slot_number && this.outputs[ slot_number ].pos)
{
out[0] = this.pos[0] + this.outputs[slot_number].pos[0];
out[1] = this.pos[1] + this.outputs[slot_number].pos[1];
return out;
}
//horizontal distributed slots
if(this.flags.horizontal)
{
out[0] = this.pos[0] + (slot_number + 0.5) * (this.size[0] / num_slots);
if(is_input)
return [this.pos[0] + (slot_number + 0.5) * (this.size[0] / (this.inputs.length)), this.pos[1] - LiteGraph.NODE_TITLE_HEIGHT ];
return [this.pos[0] + (slot_number + 0.5) * (this.size[0] / (this.outputs.length)), this.pos[1] + this.size[1] ];
out[1] = this.pos[1] - LiteGraph.NODE_TITLE_HEIGHT;
else
out[1] = this.pos[1] + this.size[1];
return out;
}
//default
if(is_input)
return [this.pos[0] , this.pos[1] + 10 + slot_number * LiteGraph.NODE_SLOT_HEIGHT + (this.constructor.slot_start_y || 0) ];
return [this.pos[0] + this.size[0] + 1, this.pos[1] + 10 + slot_number * LiteGraph.NODE_SLOT_HEIGHT + (this.constructor.slot_start_y || 0)];
out[0] = this.pos[0];
else
out[0] = this.pos[0] + this.size[0] + 1;
out[1] = this.pos[1] + 10 + slot_number * LiteGraph.NODE_SLOT_HEIGHT + (this.constructor.slot_start_y || 0);
return out;
}
/* Force align to grid */
@@ -3939,7 +4034,7 @@ LGraphCanvas.prototype.processMouseDown = function(e)
this.connecting_node = this.graph._nodes_by_id[ link_info.origin_id ];
this.connecting_slot = link_info.origin_slot;
this.connecting_output = this.connecting_node.outputs[ this.connecting_slot ];
this.connecting_pos = this.connecting_node.getConnectionPos( false, this.connecting_slot);
this.connecting_pos = this.connecting_node.getConnectionPos( false, this.connecting_slot );
}
this.dirty_bgcanvas = true;
@@ -4461,7 +4556,7 @@ LGraphCanvas.prototype.isOverNodeInput = function(node, canvasx, canvasy, slot_p
for(var i = 0, l = node.inputs.length; i < l; ++i)
{
var input = node.inputs[i];
var link_pos = node.getConnectionPos(true,i);
var link_pos = node.getConnectionPos( true, i );
if( isInsideRectangle(canvasx, canvasy, link_pos[0] - 10, link_pos[1] - 5, 20,10) )
{
if(slot_pos)
@@ -5149,12 +5244,14 @@ LGraphCanvas.prototype.drawFrontCanvas = function()
{
ctx.lineWidth = this.connections_width;
var link_color = null;
switch( this.connecting_output.type )
{
case LiteGraph.EVENT: link_color = LiteGraph.EVENT_LINK_COLOR; break;
default:
link_color = LiteGraph.CONNECTING_LINK_COLOR;
}
//the connection being dragged by the mouse
this.renderLink( ctx, this.connecting_pos, [ this.canvas_mouse[0], this.canvas_mouse[1] ], null, false, null, link_color, this.connecting_output.dir || (this.connecting_node.flags.horizontal ? LiteGraph.DOWN : LiteGraph.RIGHT), LiteGraph.CENTER );
@@ -5460,6 +5557,7 @@ LGraphCanvas.prototype.drawNode = function(node, ctx )
ctx.lineWidth = 1;
var max_y = 0;
var slot_pos = new Float32Array(2); //to reuse
//render inputs and outputs
if(!node.flags.collapsed)
@@ -5477,7 +5575,7 @@ LGraphCanvas.prototype.drawNode = function(node, ctx )
ctx.fillStyle = slot.link != null ? (slot.color_on || this.default_connection_color.input_on) : (slot.color_off || this.default_connection_color.input_off);
var pos = node.getConnectionPos( true, i );
var pos = node.getConnectionPos( true, i, slot_pos );
pos[0] -= node.pos[0];
pos[1] -= node.pos[1];
if( max_y < pos[1] + LiteGraph.NODE_SLOT_HEIGHT*0.5 )
@@ -5524,7 +5622,7 @@ LGraphCanvas.prototype.drawNode = function(node, ctx )
{
var slot = node.outputs[i];
var pos = node.getConnectionPos(false,i);
var pos = node.getConnectionPos(false,i, slot_pos );
pos[0] -= node.pos[0];
pos[1] -= node.pos[1];
if( max_y < pos[1] + LiteGraph.NODE_SLOT_HEIGHT*0.5)
@@ -5584,6 +5682,10 @@ LGraphCanvas.prototype.drawNode = function(node, ctx )
}
else //if collapsed
{
var input_slot = null;
var output_slot = null;
//get first connected slot to render
if(node.inputs)
{
for(var i = 0; i < node.inputs.length; i++)
@@ -5591,23 +5693,10 @@ LGraphCanvas.prototype.drawNode = function(node, ctx )
var slot = node.inputs[i];
if( slot.link == null )
continue;
ctx.fillStyle = slot.color_on || this.default_connection_color.input_on;
ctx.beginPath();
if ( slot.type === LiteGraph.EVENT || slot.shape === LiteGraph.BOX_SHAPE) {
ctx.rect(0.5, 4 - LiteGraph.NODE_TITLE_HEIGHT + 0.5,14,LiteGraph.NODE_TITLE_HEIGHT - 8);
} else if (slot.shape === LiteGraph.ARROW_SHAPE) {
ctx.moveTo(8, LiteGraph.NODE_TITLE_HEIGHT * -0.5);
ctx.lineTo(-4, LiteGraph.NODE_TITLE_HEIGHT * -0.8);
ctx.lineTo(-4, LiteGraph.NODE_TITLE_HEIGHT * -0.2);
ctx.closePath();
} else {
ctx.arc(0, LiteGraph.NODE_TITLE_HEIGHT * -0.5, 4, 0, Math.PI * 2);
}
ctx.fill();
input_slot = slot;
break;
}
}
if(node.outputs)
{
for(var i = 0; i < node.outputs.length; i++)
@@ -5615,23 +5704,60 @@ LGraphCanvas.prototype.drawNode = function(node, ctx )
var slot = node.outputs[i];
if(!slot.links || !slot.links.length)
continue;
ctx.fillStyle = slot.color_on || this.default_connection_color.output_on;
ctx.strokeStyle = "black";
ctx.beginPath();
if (slot.type === LiteGraph.EVENT || slot.shape === LiteGraph.BOX_SHAPE) {
ctx.rect( node._collapsed_width - 4 + 0.5, 4 - LiteGraph.NODE_TITLE_HEIGHT + 0.5,14,LiteGraph.NODE_TITLE_HEIGHT - 8);
} else if (slot.shape === LiteGraph.ARROW_SHAPE) {
ctx.moveTo(node._collapsed_width + 6, LiteGraph.NODE_TITLE_HEIGHT * -0.5);
ctx.lineTo(node._collapsed_width - 6, LiteGraph.NODE_TITLE_HEIGHT * -0.8);
ctx.lineTo(node._collapsed_width - 6, LiteGraph.NODE_TITLE_HEIGHT * -0.2);
ctx.closePath();
} else {
ctx.arc(node._collapsed_width, LiteGraph.NODE_TITLE_HEIGHT * -0.5, 4, 0, Math.PI * 2);
}
ctx.fill();
ctx.stroke();
output_slot = slot;
}
}
if(input_slot)
{
var x = 0;
var y = LiteGraph.NODE_TITLE_HEIGHT * -0.5; //center
if( node.flags.horizontal )
{
x = node._collapsed_width * 0.5;
y = -LiteGraph.NODE_TITLE_HEIGHT;
}
ctx.fillStyle = slot.color_on || this.default_connection_color.input_on;
ctx.beginPath();
if ( slot.type === LiteGraph.EVENT || slot.shape === LiteGraph.BOX_SHAPE) {
ctx.rect(x + 0.5, y + 4 - LiteGraph.NODE_TITLE_HEIGHT * 0.5 + 0.5,14,LiteGraph.NODE_TITLE_HEIGHT - 8);
} else if (slot.shape === LiteGraph.ARROW_SHAPE) {
ctx.moveTo(x + 8, y);
ctx.lineTo(x + -4, y - 4);
ctx.lineTo(x + -4, y + 4);
ctx.closePath();
} else {
ctx.arc(x, y, 4, 0, Math.PI * 2);
}
ctx.fill();
}
if(output_slot)
{
var x = node._collapsed_width;
var y = LiteGraph.NODE_TITLE_HEIGHT * -0.5; //center
if( node.flags.horizontal )
{
x = node._collapsed_width * 0.5;
y = 0;
}
ctx.fillStyle = slot.color_on || this.default_connection_color.output_on;
ctx.strokeStyle = "black";
ctx.beginPath();
if (slot.type === LiteGraph.EVENT || slot.shape === LiteGraph.BOX_SHAPE) {
ctx.rect( x - 4 + 0.5, 4 - LiteGraph.NODE_TITLE_HEIGHT * 0.5 + 0.5,14,LiteGraph.NODE_TITLE_HEIGHT - 8);
} else if (slot.shape === LiteGraph.ARROW_SHAPE) {
ctx.moveTo(x + 6, y);
ctx.lineTo(x - 6, y - 4);
ctx.lineTo(x - 6, y + 4);
ctx.closePath();
} else {
ctx.arc(x, y, 4, 0, Math.PI * 2);
}
ctx.fill();
ctx.stroke();
}
}
@@ -5645,6 +5771,8 @@ LGraphCanvas.prototype.drawNode = function(node, ctx )
* draws the shape of the given node in the canvas
* @method drawNodeShape
**/
var tmp_area = new Float32Array(4);
LGraphCanvas.prototype.drawNodeShape = function( node, ctx, size, fgcolor, bgcolor, selected, mouse_over )
{
//bg rect
@@ -5663,19 +5791,20 @@ LGraphCanvas.prototype.drawNodeShape = function( node, ctx, size, fgcolor, bgcol
else if( title_mode == LiteGraph.AUTOHIDE_TITLE && mouse_over)
render_title = true;
var areax = 0;
var areay = render_title ? -title_height : 0;
var areaw = size[0]+1;
var areah = render_title ? size[1] + title_height : size[1];
var area = tmp_area;
area[0] = 0; //x
area[1] = render_title ? -title_height : 0; //y
area[2] = size[0]+1; //w
area[3] = render_title ? size[1] + title_height : size[1]; //h
//full node shape
if(!node.flags.collapsed)
{
ctx.beginPath();
if(shape == LiteGraph.BOX_SHAPE || this.scale < 0.5)
ctx.fillRect( areax, areay, areaw, areah );
ctx.fillRect( area[0], area[1], area[2], area[3] );
else if (shape == LiteGraph.ROUND_SHAPE || shape == LiteGraph.CARD_SHAPE)
ctx.roundRect( areax, areay, areaw, areah, this.round_radius, shape == LiteGraph.CARD_SHAPE ? 0 : this.round_radius);
ctx.roundRect( area[0], area[1], area[2], area[3], this.round_radius, shape == LiteGraph.CARD_SHAPE ? 0 : this.round_radius);
else if (shape == LiteGraph.CIRCLE_SHAPE)
ctx.arc(size[0] * 0.5, size[1] * 0.5, size[0] * 0.5, 0, Math.PI*2);
ctx.fill();
@@ -5788,20 +5917,23 @@ LGraphCanvas.prototype.drawNodeShape = function( node, ctx, size, fgcolor, bgcol
//render selection marker
if(selected)
{
if( node.onBounding )
node.onBounding( area );
if( title_mode == LiteGraph.TRANSPARENT_TITLE )
{
areay -= title_height;
areah += title_height;
area[1] -= title_height;
area[3] += title_height;
}
ctx.lineWidth = 1;
ctx.globalAlpha = 0.8;
ctx.beginPath();
if(shape == LiteGraph.BOX_SHAPE)
ctx.rect(-6 + areax,-6 + areay, 12 + areaw, 12 + areah );
ctx.rect(-6 + area[0],-6 + area[1], 12 + area[2], 12 + area[3] );
else if (shape == LiteGraph.ROUND_SHAPE || (shape == LiteGraph.CARD_SHAPE && node.flags.collapsed) )
ctx.roundRect(-6 + areax,-6 + areay, 12 + areaw, 12 + areah , this.round_radius * 2);
ctx.roundRect(-6 + area[0],-6 + area[1], 12 + area[2], 12 + area[3] , this.round_radius * 2);
else if (shape == LiteGraph.CARD_SHAPE)
ctx.roundRect(-6 + areax,-6 + areay, 12 + areaw, 12 + areah , this.round_radius * 2, 2);
ctx.roundRect(-6 + area[0],-6 + area[1], 12 + area[2], 12 + area[3] , this.round_radius * 2, 2);
else if (shape == LiteGraph.CIRCLE_SHAPE)
ctx.arc(size[0] * 0.5, size[1] * 0.5, size[0] * 0.5 + 6, 0, Math.PI*2);
ctx.strokeStyle = "#FFF";
@@ -5822,6 +5954,8 @@ LGraphCanvas.prototype.drawConnections = function(ctx)
var visible_area = this.visible_area;
var margin_area = new Float32Array([visible_area[0] - 20, visible_area[1] - 20, visible_area[2] + 40, visible_area[3] + 40 ]);
var link_bounding = new Float32Array(4);
var tempA = new Float32Array(2);
var tempB = new Float32Array(2);
//draw connections
ctx.lineWidth = this.connections_width;
@@ -5856,8 +5990,8 @@ LGraphCanvas.prototype.drawConnections = function(ctx)
if(start_node_slot == -1)
start_node_slotpos = [start_node.pos[0] + 10, start_node.pos[1] + 10];
else
start_node_slotpos = start_node.getConnectionPos(false, start_node_slot);
var end_node_slotpos = node.getConnectionPos(true,i);
start_node_slotpos = start_node.getConnectionPos( false, start_node_slot, tempA );
var end_node_slotpos = node.getConnectionPos( true, i, tempB );
//compute link bounding
link_bounding[0] = start_node_slotpos[0];
@@ -5924,7 +6058,7 @@ LGraphCanvas.prototype.renderLink = function( ctx, a, b, link, skip_border, flow
//choose color
if( !color && link )
color = LGraphCanvas.link_type_colors[ link.type ];
color = link.color || LGraphCanvas.link_type_colors[ link.type ];
if( !color )
color = this.default_link_color;
@@ -7853,7 +7987,7 @@ function ContextMenu( values, options )
return;
if(root.closing_timer)
clearTimeout( root.closing_timer );
root.closing_timer = setTimeout( that.close.bind(that), 500 );
root.closing_timer = setTimeout( that.close.bind(that, e), 500 );
//that.close(e);
});