Merge branch 'comfyanonymous:master' into custom-node-socket
This commit is contained in:
@@ -486,6 +486,27 @@ class ComfyApp {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup slot colors for types
|
||||
*/
|
||||
setupSlotColors() {
|
||||
let colors = {
|
||||
"CLIP": "#FFD500", // bright yellow
|
||||
"CLIP_VISION": "#A8DADC", // light blue-gray
|
||||
"CLIP_VISION_OUTPUT": "#ad7452", // rusty brown-orange
|
||||
"CONDITIONING": "#FFA931", // vibrant orange-yellow
|
||||
"CONTROL_NET": "#6EE7B7", // soft mint green
|
||||
"IMAGE": "#64B5F6", // bright sky blue
|
||||
"LATENT": "#FF9CF9", // light pink-purple
|
||||
"MASK": "#81C784", // muted green
|
||||
"MODEL": "#B39DDB", // light lavender-purple
|
||||
"STYLE_MODEL": "#C2FFAE", // light green-yellow
|
||||
"VAE": "#FF6E6E", // bright red
|
||||
};
|
||||
|
||||
Object.assign(this.canvas.default_connection_color_byType, colors);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set up the app on the page
|
||||
*/
|
||||
@@ -494,13 +515,15 @@ class ComfyApp {
|
||||
|
||||
// Create and mount the LiteGraph in the DOM
|
||||
const canvasEl = (this.canvasEl = Object.assign(document.createElement("canvas"), { id: "graph-canvas" }));
|
||||
canvasEl.tabIndex = "1"
|
||||
canvasEl.tabIndex = "1";
|
||||
document.body.prepend(canvasEl);
|
||||
|
||||
this.graph = new LGraph();
|
||||
const canvas = (this.canvas = new LGraphCanvas(canvasEl, this.graph));
|
||||
this.ctx = canvasEl.getContext("2d");
|
||||
|
||||
this.setupSlotColors();
|
||||
|
||||
this.graph.start();
|
||||
|
||||
function resizeCanvas() {
|
||||
@@ -525,7 +548,9 @@ class ComfyApp {
|
||||
this.loadGraphData(workflow);
|
||||
restored = true;
|
||||
}
|
||||
} catch (err) {}
|
||||
} catch (err) {
|
||||
console.error("Error loading previous workflow", err);
|
||||
}
|
||||
|
||||
// We failed to restore a workflow so load the default
|
||||
if (!restored) {
|
||||
@@ -572,12 +597,8 @@ class ComfyApp {
|
||||
const type = inputData[0];
|
||||
|
||||
if (Array.isArray(type)) {
|
||||
// Enums e.g. latent rotation
|
||||
let defaultValue = type[0];
|
||||
if (inputData[1] && inputData[1].default) {
|
||||
defaultValue = inputData[1].default;
|
||||
}
|
||||
this.addWidget("combo", inputName, defaultValue, () => {}, { values: type });
|
||||
// Enums
|
||||
Object.assign(config, widgets.COMBO(this, inputName, inputData, app) || {});
|
||||
} else if (`${type}:${inputName}` in widgets) {
|
||||
// Support custom widgets by Type:Name
|
||||
Object.assign(config, widgets[`${type}:${inputName}`](this, inputName, inputData, app) || {});
|
||||
@@ -667,11 +688,15 @@ class ComfyApp {
|
||||
async graphToPrompt() {
|
||||
const workflow = this.graph.serialize();
|
||||
const output = {};
|
||||
for (const n of workflow.nodes) {
|
||||
const node = this.graph.getNodeById(n.id);
|
||||
// Process nodes in order of execution
|
||||
for (const node of this.graph.computeExecutionOrder(false)) {
|
||||
const n = workflow.nodes.find((n) => n.id === node.id);
|
||||
|
||||
if (node.isVirtualNode) {
|
||||
// Don't serialize frontend only nodes
|
||||
// Don't serialize frontend only nodes but let them make changes
|
||||
if (node.applyToGraph) {
|
||||
node.applyToGraph(workflow);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -695,7 +720,11 @@ class ComfyApp {
|
||||
let link = node.getInputLink(i);
|
||||
while (parent && parent.isVirtualNode) {
|
||||
link = parent.getInputLink(link.origin_slot);
|
||||
parent = parent.getInputNode(link.origin_slot);
|
||||
if (link) {
|
||||
parent = parent.getInputNode(link.origin_slot);
|
||||
} else {
|
||||
parent = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (link) {
|
||||
|
||||
@@ -35,6 +35,54 @@ function $el(tag, propsOrChildren, children) {
|
||||
return element;
|
||||
}
|
||||
|
||||
function dragElement(dragEl) {
|
||||
var posDiffX = 0,
|
||||
posDiffY = 0,
|
||||
posStartX = 0,
|
||||
posStartY = 0,
|
||||
newPosX = 0,
|
||||
newPosY = 0;
|
||||
if (dragEl.getElementsByClassName('drag-handle')[0]) {
|
||||
// if present, the handle is where you move the DIV from:
|
||||
dragEl.getElementsByClassName('drag-handle')[0].onmousedown = dragMouseDown;
|
||||
} else {
|
||||
// otherwise, move the DIV from anywhere inside the DIV:
|
||||
dragEl.onmousedown = dragMouseDown;
|
||||
}
|
||||
|
||||
function dragMouseDown(e) {
|
||||
e = e || window.event;
|
||||
e.preventDefault();
|
||||
// get the mouse cursor position at startup:
|
||||
posStartX = e.clientX;
|
||||
posStartY = e.clientY;
|
||||
document.onmouseup = closeDragElement;
|
||||
// call a function whenever the cursor moves:
|
||||
document.onmousemove = elementDrag;
|
||||
}
|
||||
|
||||
function elementDrag(e) {
|
||||
e = e || window.event;
|
||||
e.preventDefault();
|
||||
// calculate the new cursor position:
|
||||
posDiffX = e.clientX - posStartX;
|
||||
posDiffY = e.clientY - posStartY;
|
||||
posStartX = e.clientX;
|
||||
posStartY = e.clientY;
|
||||
newPosX = Math.min((document.body.clientWidth - dragEl.clientWidth), Math.max(0, (dragEl.offsetLeft + posDiffX)));
|
||||
newPosY = Math.min((document.body.clientHeight - dragEl.clientHeight), Math.max(0, (dragEl.offsetTop + posDiffY)));
|
||||
// set the element's new position:
|
||||
dragEl.style.top = newPosY + "px";
|
||||
dragEl.style.left = newPosX + "px";
|
||||
}
|
||||
|
||||
function closeDragElement() {
|
||||
// stop moving when mouse button is released:
|
||||
document.onmouseup = null;
|
||||
document.onmousemove = null;
|
||||
}
|
||||
}
|
||||
|
||||
class ComfyDialog {
|
||||
constructor() {
|
||||
this.element = $el("div.comfy-modal", { parent: document.body }, [
|
||||
@@ -253,6 +301,7 @@ export class ComfyUI {
|
||||
|
||||
this.menuContainer = $el("div.comfy-menu", { parent: document.body }, [
|
||||
$el("div", { style: { overflow: "hidden", position: "relative", width: "100%" } }, [
|
||||
$el("span.drag-handle"),
|
||||
$el("span", { $: (q) => (this.queueSize = q) }),
|
||||
$el("button.comfy-settings-btn", { textContent: "⚙️", onclick: () => this.settings.show() }),
|
||||
]),
|
||||
@@ -331,6 +380,8 @@ export class ComfyUI {
|
||||
$el("button", { textContent: "Load Default", onclick: () => app.loadGraphData() }),
|
||||
]);
|
||||
|
||||
dragElement(this.menuContainer);
|
||||
|
||||
this.setStatus({ exec_info: { queue_remaining: "X" } });
|
||||
}
|
||||
|
||||
|
||||
@@ -10,9 +10,8 @@ function getNumberDefaults(inputData, defaultStep) {
|
||||
return { val: defaultVal, config: { min, max, step: 10.0 * step } };
|
||||
}
|
||||
|
||||
function seedWidget(node, inputName, inputData) {
|
||||
const seed = ComfyWidgets.INT(node, inputName, inputData);
|
||||
const randomize = node.addWidget("toggle", "Random seed after every gen", true, function (v) {}, {
|
||||
export function addRandomizeWidget(node, targetWidget, name, defaultValue = false) {
|
||||
const randomize = node.addWidget("toggle", name, defaultValue, function (v) {}, {
|
||||
on: "enabled",
|
||||
off: "disabled",
|
||||
serialize: false, // Don't include this in prompt.
|
||||
@@ -20,14 +19,32 @@ function seedWidget(node, inputName, inputData) {
|
||||
|
||||
randomize.afterQueued = () => {
|
||||
if (randomize.value) {
|
||||
seed.widget.value = Math.floor(Math.random() * 1125899906842624);
|
||||
const min = targetWidget.options?.min;
|
||||
let max = targetWidget.options?.max;
|
||||
if (min != null || max != null) {
|
||||
if (max) {
|
||||
// limit max to something that javascript can handle
|
||||
max = Math.min(1125899906842624, max);
|
||||
}
|
||||
targetWidget.value = Math.floor(Math.random() * ((max ?? 9999999999) - (min ?? 0) + 1) + (min ?? 0));
|
||||
} else {
|
||||
targetWidget.value = Math.floor(Math.random() * 1125899906842624);
|
||||
}
|
||||
}
|
||||
};
|
||||
return randomize;
|
||||
}
|
||||
|
||||
function seedWidget(node, inputName, inputData) {
|
||||
const seed = ComfyWidgets.INT(node, inputName, inputData);
|
||||
const randomize = addRandomizeWidget(node, seed.widget, "Random seed after every gen", true);
|
||||
|
||||
seed.widget.linkedWidgets = [randomize];
|
||||
return { widget: seed, randomize };
|
||||
}
|
||||
|
||||
const MultilineSymbol = Symbol();
|
||||
const MultilineResizeSymbol = Symbol();
|
||||
|
||||
function addMultilineWidget(node, name, opts, app) {
|
||||
const MIN_SIZE = 50;
|
||||
@@ -95,7 +112,7 @@ function addMultilineWidget(node, name, opts, app) {
|
||||
// Calculate it here instead
|
||||
computeSize(node.size);
|
||||
}
|
||||
const visible = app.canvas.ds.scale > 0.5;
|
||||
const visible = app.canvas.ds.scale > 0.5 && this.type === "customtext";
|
||||
const t = ctx.getTransform();
|
||||
const margin = 10;
|
||||
Object.assign(this.inputEl.style, {
|
||||
@@ -149,9 +166,22 @@ function addMultilineWidget(node, name, opts, app) {
|
||||
}
|
||||
};
|
||||
|
||||
if (!(MultilineSymbol in node)) {
|
||||
node[MultilineSymbol] = true;
|
||||
const onResize = node.onResize;
|
||||
widget.onRemove = () => {
|
||||
widget.inputEl?.remove();
|
||||
|
||||
// Restore original size handler if we are the last
|
||||
if (!--node[MultilineSymbol]) {
|
||||
node.onResize = node[MultilineResizeSymbol];
|
||||
delete node[MultilineSymbol];
|
||||
delete node[MultilineResizeSymbol];
|
||||
}
|
||||
};
|
||||
|
||||
if (node[MultilineSymbol]) {
|
||||
node[MultilineSymbol]++;
|
||||
} else {
|
||||
node[MultilineSymbol] = 1;
|
||||
const onResize = (node[MultilineResizeSymbol] = node.onResize);
|
||||
|
||||
node.onResize = function (size) {
|
||||
computeSize(size);
|
||||
@@ -199,6 +229,14 @@ export const ComfyWidgets = {
|
||||
return { widget: node.addWidget("text", inputName, defaultVal, () => {}, {}) };
|
||||
}
|
||||
},
|
||||
COMBO(node, inputName, inputData) {
|
||||
const type = inputData[0];
|
||||
let defaultValue = type[0];
|
||||
if (inputData[1] && inputData[1].default) {
|
||||
defaultValue = inputData[1].default;
|
||||
}
|
||||
return { widget: node.addWidget("combo", inputName, defaultValue, () => {}, { values: type }) };
|
||||
},
|
||||
IMAGEUPLOAD(node, inputName, inputData, app) {
|
||||
const imageWidget = node.widgets.find((w) => w.name === "image");
|
||||
let uploadWidget;
|
||||
|
||||
Reference in New Issue
Block a user