Merge branch 'dragdrop-image-upload' of https://github.com/pythongosssss/ComfyUI into m1
This commit is contained in:
commit
ef71d2c281
|
@ -291,9 +291,47 @@ class ComfyApp {
|
||||||
document.addEventListener("drop", async (event) => {
|
document.addEventListener("drop", async (event) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
const file = event.dataTransfer.files[0];
|
|
||||||
await this.handleFile(file);
|
const n = this.dragOverNode;
|
||||||
|
this.dragOverNode = null;
|
||||||
|
// Node handles file drop, we dont use the built in onDropFile handler as its buggy
|
||||||
|
// If you drag multiple files it will call it multiple times with the same file
|
||||||
|
if (n && n.onDragDrop && (await n.onDragDrop(event))) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.handleFile(event.dataTransfer.files[0]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Always clear over node on drag leave
|
||||||
|
this.canvasEl.addEventListener("dragleave", async () => {
|
||||||
|
if (this.dragOverNode) {
|
||||||
|
this.dragOverNode = null;
|
||||||
|
this.graph.setDirtyCanvas(false, true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Add handler for dropping onto a specific node
|
||||||
|
this.canvasEl.addEventListener(
|
||||||
|
"dragover",
|
||||||
|
(e) => {
|
||||||
|
this.canvas.adjustMouseEvent(e);
|
||||||
|
const node = this.graph.getNodeOnPos(e.canvasX, e.canvasY);
|
||||||
|
if (node) {
|
||||||
|
if (node.onDragOver && node.onDragOver(e)) {
|
||||||
|
this.dragOverNode = node;
|
||||||
|
|
||||||
|
// dragover event is fired very frequently, run this on an animation frame
|
||||||
|
requestAnimationFrame(() => {
|
||||||
|
this.graph.setDirtyCanvas(false, true);
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.dragOverNode = null;
|
||||||
|
},
|
||||||
|
false
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -321,15 +359,22 @@ class ComfyApp {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Draws currently executing node highlight and progress bar
|
* Draws node highlights (executing, drag drop) and progress bar
|
||||||
*/
|
*/
|
||||||
#addDrawNodeProgressHandler() {
|
#addDrawNodeHandler() {
|
||||||
const orig = LGraphCanvas.prototype.drawNodeShape;
|
const orig = LGraphCanvas.prototype.drawNodeShape;
|
||||||
const self = this;
|
const self = this;
|
||||||
LGraphCanvas.prototype.drawNodeShape = function (node, ctx, size, fgcolor, bgcolor, selected, mouse_over) {
|
LGraphCanvas.prototype.drawNodeShape = function (node, ctx, size, fgcolor, bgcolor, selected, mouse_over) {
|
||||||
const res = orig.apply(this, arguments);
|
const res = orig.apply(this, arguments);
|
||||||
|
|
||||||
if (node.id + "" === self.runningNodeId) {
|
let color = null;
|
||||||
|
if (node.id === +self.runningNodeId) {
|
||||||
|
color = "#0f0";
|
||||||
|
} else if (self.dragOverNode && node.id === self.dragOverNode.id) {
|
||||||
|
color = "dodgerblue";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (color) {
|
||||||
const shape = node._shape || node.constructor.shape || LiteGraph.ROUND_SHAPE;
|
const shape = node._shape || node.constructor.shape || LiteGraph.ROUND_SHAPE;
|
||||||
ctx.lineWidth = 1;
|
ctx.lineWidth = 1;
|
||||||
ctx.globalAlpha = 0.8;
|
ctx.globalAlpha = 0.8;
|
||||||
|
@ -355,7 +400,7 @@ class ComfyApp {
|
||||||
);
|
);
|
||||||
else if (shape == LiteGraph.CIRCLE_SHAPE)
|
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.arc(size[0] * 0.5, size[1] * 0.5, size[0] * 0.5 + 6, 0, Math.PI * 2);
|
||||||
ctx.strokeStyle = "#0f0";
|
ctx.strokeStyle = color;
|
||||||
ctx.stroke();
|
ctx.stroke();
|
||||||
ctx.strokeStyle = fgcolor;
|
ctx.strokeStyle = fgcolor;
|
||||||
ctx.globalAlpha = 1;
|
ctx.globalAlpha = 1;
|
||||||
|
@ -435,7 +480,7 @@ class ComfyApp {
|
||||||
await this.#loadExtensions();
|
await this.#loadExtensions();
|
||||||
|
|
||||||
// Create and mount the LiteGraph in the DOM
|
// Create and mount the LiteGraph in the DOM
|
||||||
const canvasEl = Object.assign(document.createElement("canvas"), { id: "graph-canvas" });
|
const canvasEl = (this.canvasEl = Object.assign(document.createElement("canvas"), { id: "graph-canvas" }));
|
||||||
document.body.prepend(canvasEl);
|
document.body.prepend(canvasEl);
|
||||||
|
|
||||||
this.graph = new LGraph();
|
this.graph = new LGraph();
|
||||||
|
@ -476,7 +521,7 @@ class ComfyApp {
|
||||||
// Save current workflow automatically
|
// Save current workflow automatically
|
||||||
setInterval(() => localStorage.setItem("workflow", JSON.stringify(this.graph.serialize())), 1000);
|
setInterval(() => localStorage.setItem("workflow", JSON.stringify(this.graph.serialize())), 1000);
|
||||||
|
|
||||||
this.#addDrawNodeProgressHandler();
|
this.#addDrawNodeHandler();
|
||||||
this.#addApiUpdateHandlers();
|
this.#addApiUpdateHandlers();
|
||||||
this.#addDropHandler();
|
this.#addDropHandler();
|
||||||
this.#addPasteHandler();
|
this.#addPasteHandler();
|
||||||
|
|
|
@ -132,7 +132,7 @@ export const ComfyWidgets = {
|
||||||
|
|
||||||
function showImage(name) {
|
function showImage(name) {
|
||||||
// Position the image somewhere sensible
|
// Position the image somewhere sensible
|
||||||
if(!node.imageOffset) {
|
if (!node.imageOffset) {
|
||||||
node.imageOffset = uploadWidget.last_y ? uploadWidget.last_y + 25 : 75;
|
node.imageOffset = uploadWidget.last_y ? uploadWidget.last_y + 25 : 75;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -162,6 +162,36 @@ export const ComfyWidgets = {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
async function uploadFile(file, updateNode) {
|
||||||
|
try {
|
||||||
|
// Wrap file in formdata so it includes filename
|
||||||
|
const body = new FormData();
|
||||||
|
body.append("image", file);
|
||||||
|
const resp = await fetch("/upload/image", {
|
||||||
|
method: "POST",
|
||||||
|
body,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (resp.status === 200) {
|
||||||
|
const data = await resp.json();
|
||||||
|
// Add the file as an option and update the widget value
|
||||||
|
if (!imageWidget.options.values.includes(data.name)) {
|
||||||
|
imageWidget.options.values.push(data.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (updateNode) {
|
||||||
|
showImage(data.name);
|
||||||
|
|
||||||
|
imageWidget.value = data.name;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
alert(resp.status + " - " + resp.statusText);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
alert(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const fileInput = document.createElement("input");
|
const fileInput = document.createElement("input");
|
||||||
Object.assign(fileInput, {
|
Object.assign(fileInput, {
|
||||||
type: "file",
|
type: "file",
|
||||||
|
@ -169,30 +199,7 @@ export const ComfyWidgets = {
|
||||||
style: "display: none",
|
style: "display: none",
|
||||||
onchange: async () => {
|
onchange: async () => {
|
||||||
if (fileInput.files.length) {
|
if (fileInput.files.length) {
|
||||||
try {
|
await uploadFile(fileInput.files[0], true);
|
||||||
// Wrap file in formdata so it includes filename
|
|
||||||
const body = new FormData();
|
|
||||||
body.append("image", fileInput.files[0]);
|
|
||||||
const resp = await fetch("/upload/image", {
|
|
||||||
method: "POST",
|
|
||||||
body,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (resp.status === 200) {
|
|
||||||
const data = await resp.json();
|
|
||||||
showImage(data.name);
|
|
||||||
|
|
||||||
// Add the file as an option and update the widget value
|
|
||||||
if (!imageWidget.options.values.includes(data.name)) {
|
|
||||||
imageWidget.options.values.push(data.name);
|
|
||||||
}
|
|
||||||
imageWidget.value = data.name;
|
|
||||||
} else {
|
|
||||||
alert(resp.status + " - " + resp.statusText);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
alert(error);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -204,6 +211,30 @@ export const ComfyWidgets = {
|
||||||
});
|
});
|
||||||
uploadWidget.serialize = false;
|
uploadWidget.serialize = false;
|
||||||
|
|
||||||
|
// Add handler to check if an image is being dragged over our node
|
||||||
|
node.onDragOver = function (e) {
|
||||||
|
if (e.dataTransfer && e.dataTransfer.items) {
|
||||||
|
const image = [...e.dataTransfer.items].find((f) => f.kind === "file" && f.type.startsWith("image/"));
|
||||||
|
return !!image;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
// On drop upload files
|
||||||
|
node.onDragDrop = function (e) {
|
||||||
|
console.log("onDragDrop called");
|
||||||
|
let handled = false;
|
||||||
|
for (const file of e.dataTransfer.files) {
|
||||||
|
if (file.type.startsWith("image/")) {
|
||||||
|
uploadFile(file, !handled); // Dont await these, any order is fine, only update on first one
|
||||||
|
handled = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return handled;
|
||||||
|
};
|
||||||
|
|
||||||
return { widget: uploadWidget };
|
return { widget: uploadWidget };
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue