-
Notifications
You must be signed in to change notification settings - Fork 8
custom_widget
chrisgoringe edited this page Oct 15, 2023
·
2 revisions
Here's the code for a node that just shows some html...
import { app } from "../../../scripts/app.js";
import { $el } from "../../../scripts/ui.js";
/*
A method that returns the required style for the html
*/
function get_position_style(ctx, widget_width, y, node_height) {
const MARGIN = 4; // the margin around the html element
/* Create a transform that deals with all the scrolling and zooming */
const elRect = ctx.canvas.getBoundingClientRect();
const transform = new DOMMatrix()
.scaleSelf(elRect.width / ctx.canvas.width, elRect.height / ctx.canvas.height)
.multiplySelf(ctx.getTransform())
.translateSelf(MARGIN, MARGIN + y);
return {
transformOrigin: '0 0',
transform: transform,
left: `0px`,
top: `0px`,
position: "absolute",
maxWidth: `${widget_width - MARGIN*2}px`,
maxHeight: `${node_height - MARGIN*2}px`, // we're assuming we have the whole height of the node
width: `auto`,
height: `auto`,
}
}
app.registerExtension({
name: "the.unique,name",
async beforeRegisterNodeDef(nodeType, nodeData, app) {
if (nodeType.comfyClass=="HtmlNode") {
/*
Hijack the onNodeCreated call to add our widget
*/
const orig_nodeCreated = nodeType.prototype.onNodeCreated;
nodeType.prototype.onNodeCreated = function () {
orig_nodeCreated?.apply(this, arguments);
const widget = {
type: "HTML", // whatever
name: "flying", // whatever
draw(ctx, node, widget_width, y, widget_height) {
Object.assign(this.inputEl.style, get_position_style(ctx, widget_width, y, node.size[1])); // assign the required style when we are drawn
},
};
/*
Create an html element and add it to the document.
Look at $el in ui.js for all the options here
*/
widget.inputEl = $el("img", { src: "http://127.0.0.1:8188/view?filename=misc-stained+glass_00001_.png&subfolder=2023-10-16&type=output" });
document.body.appendChild(widget.inputEl);
/*
Add the widget, make sure we clean up nicely, and we do not want to be serialized!
*/
this.addCustomWidget(widget);
this.onRemoved = function () { widget.inputEl.remove(); };
this.serialize_widgets = false;
}
}
},
})
class HtmlNode:
CATEGORY = "quicknodes"
@classmethod
def INPUT_TYPES(s):
return { "required":{} }
RETURN_TYPES = ()
RETURN_NAMES = ()
FUNCTION = "func"
def func(self):
return ()
A node plugin can provide a method getCustomWidgets
to declare a widget that handles the datatype CHEESE
getCustomWidgets(app) {
return {
CHEESE(node, inputName, inputData, app) { // We return an object containing a field CHEESE which has a function (taking node, name, data, app)
const widget = /* see below */; // that creates a widget
widget.something = something; // maybe adds stuff to it
node.addCustomWidget(widget); // adds it to the node
return widget; // and returns it.
}
}
},
We can then use CHEESE
in inputs and outputs.
"required": { "slice": ("CHEESE",),
A custom widget can probably have lots of fields, but here are some to start with:
const widget = {
type: inputData[0], // the type, CHEESE
name: inputName, // the name, slice
size: [128,128], // a default size
draw(ctx, node, width, y) {
// a method to draw the widget (ctx is a CanvasRenderingContext2D)
},
computeSize(...args) {
return [128,128]; // a method to compute the current size of the widget
},
async serializeValue(nodeId,widgetIndex) {
return "Data That Goes to the Python Side";
}
}
Looking at litegraph.js will give you more info on node widgets.