Skip to content

Commit 0dcfdc6

Browse files
authored
Merge branch 'comfyanonymous:master' into Main
2 parents b5a4ce8 + 42fc7cd commit 0dcfdc6

3 files changed

Lines changed: 153 additions & 17 deletions

File tree

guides/README.md

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ Slots have the next information:
110110
* **dir**: optional, could be LiteGraph.UP, LiteGraph.RIGHT, LiteGraph.DOWN, LiteGraph.LEFT
111111
* **color_on**: color to render when it is connected
112112
* **color_off**: color to render when it is not connected
113-
113+
114114
To retrieve the data traveling through a link you can call ```node.getInputData``` or ```node.getOutputData```
115115

116116
### Define your Graph Node
@@ -151,7 +151,7 @@ node.onDrawForeground = function(ctx, graphcanvas)
151151
}
152152
```
153153

154-
### Custom Node Behaviour
154+
### Custom Node Behaviour
155155

156156
You can also grab events from the mouse in case your node has some sort of special interactivity.
157157

@@ -187,16 +187,16 @@ function MyNodeType()
187187
```
188188

189189
This is the list of supported widgets:
190-
* **"number"** to change a value of a number, the syntax is ```this.addWidget("number","Number", current_value, callback, { min: 0, max: 100, step: 1} );```
190+
* **"number"** to change a value of a number, the syntax is ```this.addWidget("number","Number", current_value, callback, { min: 0, max: 100, step: 1, precision: 3 } );```
191191
* **"slider"** to change a number by dragging the mouse, the syntax is the same as number.
192192
* **"combo"** to select between multiple choices, the syntax is:
193193

194194
```this.addWidget("combo","Combo", "red", callback, { values:["red","green","blue"]} );```
195-
195+
196196
or if you want to use objects:
197-
197+
198198
```this.addWidget("combo","Combo", value1, callback, { values: { "title1":value1, "title2":value2 } } );```
199-
199+
200200
* **"text"** to edit a short string
201201
* **"toggle"** like a checkbox
202202
* **"button"**
@@ -205,6 +205,7 @@ The fourth optional parameter could be options for the widget, the parameters ac
205205
* **property**: specifies the name of a property to modify when the widget changes
206206
* **min**: min value
207207
* **max**: max value
208+
* **precision**: set the number of digits after decimal point
208209
* **callback**: function to call when the value changes.
209210

210211
Widget's value is not serialized by default when storing the node state, but if you want to store the value of widgets just set serialize_widgets to true:
@@ -223,11 +224,17 @@ Or if you want to associate a widget with a property of the node, then specify i
223224
function MyNode()
224225
{
225226
this.properties = { surname: "smith" };
226-
this.addWidget("text","Surname","", { property: "surname"}); //this will modify the node.properties
227+
this.addWidget("text","Surname","", { property: "surname"}); //this will modify the node.properties
227228
}
228229
```
229230
## LGraphCanvas
230231
LGraphCanvas is the class in charge of rendering/interaction with the nodes inside the browser.
232+
233+
## LGraphCanvas settings
234+
There are graph canvas settings that could be defined or modified to change behaviour:
235+
236+
* **allow_interaction**: when set to `false` disable interaction with the canvas (`flags.allow_interaction` on node can be used to override graph canvas setting)
237+
231238
### Canvas Shortcuts
232239
* Space - Holding space key while moving the cursor moves the canvas around. It works when holding the mouse button down so it is easier to connect different nodes when the canvas gets too large.
233240
* Ctrl/Shift + Click - Add clicked node to selection.
@@ -277,7 +284,7 @@ To define slots for nodes you must use the type LiteGraph.ACTION for inputs, and
277284
function MyNode()
278285
{
279286
this.addInput("play", LiteGraph.ACTION );
280-
this.addInput("onFinish", LiteGraph.EVENT );
287+
this.addInput("onFinish", LiteGraph.EVENT );
281288
}
282289
```
283290

src/litegraph.js

Lines changed: 137 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5865,13 +5865,13 @@ LGraphNode.prototype.executeAction = function(action)
58655865

58665866
//when clicked on top of a node
58675867
//and it is not interactive
5868-
if (node && this.allow_interaction && !skip_action && !this.read_only) {
5868+
if (node && (this.allow_interaction || node.flags.allow_interaction) && !skip_action && !this.read_only) {
58695869
if (!this.live_mode && !node.flags.pinned) {
58705870
this.bringToFront(node);
58715871
} //if it wasn't selected?
58725872

58735873
//not dragging mouse to connect two slots
5874-
if ( !this.connecting_node && !node.flags.collapsed && !this.live_mode ) {
5874+
if ( this.allow_interaction && !this.connecting_node && !node.flags.collapsed && !this.live_mode ) {
58755875
//Search for corner for resize
58765876
if ( !skip_action &&
58775877
node.resizable !== false &&
@@ -6025,7 +6025,7 @@ LGraphNode.prototype.executeAction = function(action)
60256025
}
60266026

60276027
//double clicking
6028-
if (is_double_click && this.selected_nodes[node.id]) {
6028+
if (this.allow_interaction && is_double_click && this.selected_nodes[node.id]) {
60296029
//double click node
60306030
if (node.onDblClick) {
60316031
node.onDblClick( e, pos, this );
@@ -6299,6 +6299,9 @@ LGraphNode.prototype.executeAction = function(action)
62996299
this.dirty_canvas = true;
63006300
}
63016301

6302+
//get node over
6303+
var node = this.graph.getNodeOnPos(e.canvasX,e.canvasY,this.visible_nodes);
6304+
63026305
if (this.dragging_rectangle)
63036306
{
63046307
this.dragging_rectangle[2] = e.canvasX - this.dragging_rectangle[0];
@@ -6328,14 +6331,11 @@ LGraphNode.prototype.executeAction = function(action)
63286331
this.ds.offset[1] += delta[1] / this.ds.scale;
63296332
this.dirty_canvas = true;
63306333
this.dirty_bgcanvas = true;
6331-
} else if (this.allow_interaction && !this.read_only) {
6334+
} else if ((this.allow_interaction || (node && node.flags.allow_interaction)) && !this.read_only) {
63326335
if (this.connecting_node) {
63336336
this.dirty_canvas = true;
63346337
}
63356338

6336-
//get node over
6337-
var node = this.graph.getNodeOnPos(e.canvasX,e.canvasY,this.visible_nodes);
6338-
63396339
//remove mouseover flag
63406340
for (var i = 0, l = this.graph._nodes.length; i < l; ++i) {
63416341
if (this.graph._nodes[i].mouseOver && node != this.graph._nodes[i] ) {
@@ -9912,7 +9912,7 @@ LGraphNode.prototype.executeAction = function(action)
99129912
event,
99139913
active_widget
99149914
) {
9915-
if (!node.widgets || !node.widgets.length) {
9915+
if (!node.widgets || !node.widgets.length || (!this.allow_interaction && !node.flags.allow_interaction)) {
99169916
return null;
99179917
}
99189918

@@ -10294,6 +10294,119 @@ LGraphNode.prototype.executeAction = function(action)
1029410294
canvas.graph.add(group);
1029510295
};
1029610296

10297+
/**
10298+
* Determines the furthest nodes in each direction
10299+
* @param nodes {LGraphNode[]} the nodes to from which boundary nodes will be extracted
10300+
* @return {{left: LGraphNode, top: LGraphNode, right: LGraphNode, bottom: LGraphNode}}
10301+
*/
10302+
LGraphCanvas.getBoundaryNodes = function(nodes) {
10303+
let top = null;
10304+
let right = null;
10305+
let bottom = null;
10306+
let left = null;
10307+
for (const nID in nodes) {
10308+
const node = nodes[nID];
10309+
const [x, y] = node.pos;
10310+
const [width, height] = node.size;
10311+
10312+
if (top === null || y < top.pos[1]) {
10313+
top = node;
10314+
}
10315+
if (right === null || x + width > right.pos[0] + right.size[0]) {
10316+
right = node;
10317+
}
10318+
if (bottom === null || y + height > bottom.pos[1] + bottom.size[1]) {
10319+
bottom = node;
10320+
}
10321+
if (left === null || x < left.pos[0]) {
10322+
left = node;
10323+
}
10324+
}
10325+
10326+
return {
10327+
"top": top,
10328+
"right": right,
10329+
"bottom": bottom,
10330+
"left": left
10331+
};
10332+
}
10333+
/**
10334+
* Determines the furthest nodes in each direction for the currently selected nodes
10335+
* @return {{left: LGraphNode, top: LGraphNode, right: LGraphNode, bottom: LGraphNode}}
10336+
*/
10337+
LGraphCanvas.prototype.boundaryNodesForSelection = function() {
10338+
return LGraphCanvas.getBoundaryNodes(Object.values(this.selected_nodes));
10339+
}
10340+
10341+
/**
10342+
*
10343+
* @param {LGraphNode[]} nodes a list of nodes
10344+
* @param {"top"|"bottom"|"left"|"right"} direction Direction to align the nodes
10345+
* @param {LGraphNode?} align_to Node to align to (if null, align to the furthest node in the given direction)
10346+
*/
10347+
LGraphCanvas.alignNodes = function (nodes, direction, align_to) {
10348+
if (!nodes) {
10349+
return;
10350+
}
10351+
10352+
const canvas = LGraphCanvas.active_canvas;
10353+
let boundaryNodes = []
10354+
if (align_to === undefined) {
10355+
boundaryNodes = LGraphCanvas.getBoundaryNodes(nodes)
10356+
} else {
10357+
boundaryNodes = {
10358+
"top": align_to,
10359+
"right": align_to,
10360+
"bottom": align_to,
10361+
"left": align_to
10362+
}
10363+
}
10364+
10365+
for (const [_, node] of Object.entries(canvas.selected_nodes)) {
10366+
switch (direction) {
10367+
case "right":
10368+
node.pos[0] = boundaryNodes["right"].pos[0] + boundaryNodes["right"].size[0] - node.size[0];
10369+
break;
10370+
case "left":
10371+
node.pos[0] = boundaryNodes["left"].pos[0];
10372+
break;
10373+
case "top":
10374+
node.pos[1] = boundaryNodes["top"].pos[1];
10375+
break;
10376+
case "bottom":
10377+
node.pos[1] = boundaryNodes["bottom"].pos[1] + boundaryNodes["bottom"].size[1] - node.size[1];
10378+
break;
10379+
}
10380+
}
10381+
10382+
canvas.dirty_canvas = true;
10383+
canvas.dirty_bgcanvas = true;
10384+
};
10385+
10386+
LGraphCanvas.onNodeAlign = function(value, options, event, prev_menu, node) {
10387+
new LiteGraph.ContextMenu(["Top", "Bottom", "Left", "Right"], {
10388+
event: event,
10389+
callback: inner_clicked,
10390+
parentMenu: prev_menu,
10391+
});
10392+
10393+
function inner_clicked(value) {
10394+
LGraphCanvas.alignNodes(LGraphCanvas.active_canvas.selected_nodes, value.toLowerCase(), node);
10395+
}
10396+
}
10397+
10398+
LGraphCanvas.onGroupAlign = function(value, options, event, prev_menu) {
10399+
new LiteGraph.ContextMenu(["Top", "Bottom", "Left", "Right"], {
10400+
event: event,
10401+
callback: inner_clicked,
10402+
parentMenu: prev_menu,
10403+
});
10404+
10405+
function inner_clicked(value) {
10406+
LGraphCanvas.alignNodes(LGraphCanvas.active_canvas.selected_nodes, value.toLowerCase());
10407+
}
10408+
}
10409+
1029710410
LGraphCanvas.onMenuAdd = function (node, options, e, prev_menu, callback) {
1029810411

1029910412
var canvas = LGraphCanvas.active_canvas;
@@ -12894,6 +13007,14 @@ LGraphNode.prototype.executeAction = function(action)
1289413007
options.push({ content: "Options", callback: that.showShowGraphOptionsPanel });
1289513008
}*/
1289613009

13010+
if (Object.keys(this.selected_nodes).length > 1) {
13011+
options.push({
13012+
content: "Align",
13013+
has_submenu: true,
13014+
callback: LGraphCanvas.onGroupAlign,
13015+
})
13016+
}
13017+
1289713018
if (this._graph_stack && this._graph_stack.length > 0) {
1289813019
options.push(null, {
1289913020
content: "Close subgraph",
@@ -13008,6 +13129,14 @@ LGraphNode.prototype.executeAction = function(action)
1300813129
callback: LGraphCanvas.onMenuNodeToSubgraph
1300913130
});
1301013131

13132+
if (Object.keys(this.selected_nodes).length > 1) {
13133+
options.push({
13134+
content: "Align Selected To",
13135+
has_submenu: true,
13136+
callback: LGraphCanvas.onNodeAlign,
13137+
})
13138+
}
13139+
1301113140
options.push(null, {
1301213141
content: "Remove",
1301313142
disabled: !(node.removable !== false && !node.block_delete ),

utils/server.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,4 @@ app.use('/external', express.static('external'))
77
app.use('/editor', express.static('editor'))
88
app.use('/', express.static('editor'))
99

10-
app.listen(8000, () => console.log('Example app listening on port 8000!'))
10+
app.listen(8000, () => console.log('Example app listening on http://127.0.0.1:8000!'))

0 commit comments

Comments
 (0)