Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
258 changes: 217 additions & 41 deletions js/mask-rect-area-advanced.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,16 @@ function showPreviewCanvas(node, app) {
const margin = 12;
const border = 2;
const widgetHeight = node.canvasHeight;
const width = Math.round(node.properties["width"]);
const height = Math.round(node.properties["height"]);
const scale = Math.min((widgetWidth - margin * 3) / width, (widgetHeight - margin * 3) / height);

// Keep preview in sync when inputs are driven by links.
syncLinkedInputsToPropertiesAdvanced(node);

const width = Math.max(1, Math.round(node.properties["width"]));
const height = Math.max(1, Math.round(node.properties["height"]));
const scale = Math.min(
(widgetWidth - margin * 3) / width,
(widgetHeight - margin * 3) / height
);
const blurRadius = node.properties["blur_radius"] || 0;
const index = 0;

Expand Down Expand Up @@ -120,11 +127,11 @@ function showPreviewCanvas(node, app) {
xOffset += (widgetWidth - backgroundWidth) / 2 - margin;
}

// Ajustar las coordenadas X e Y
// Adjust X and Y coordinates
const barHeight = 8;
let widgetYBar = widgetY + backgroundHeight + margin;

// Dibujar el borde negro alrededor de la barra
// Draw the border around the progress bar
ctx.fillStyle = globalThis.LiteGraph.WIDGET_OUTLINE_COLOR;
ctx.fillRect(
widgetX - border,
Expand All @@ -133,33 +140,32 @@ function showPreviewCanvas(node, app) {
barHeight + border * 2
);

// Dibujar el área principal de la barra (fondo)
ctx.fillStyle = globalThis.LiteGraph.WIDGET_BGCOLOR; // Mismo color de fondo que el canvas
// Draw the main bar area (background)
ctx.fillStyle = globalThis.LiteGraph.WIDGET_BGCOLOR;
ctx.fillRect(
widgetX,
widgetYBar,
backgroundWidth,
barHeight
);


// Draw progress bar grid
ctx.beginPath();
ctx.lineWidth = 1;
ctx.strokeStyle = "#66666650";

// Calcular el número de líneas en función del tamaño de la barra
// Calculate the number of grid lines based on the bar size
const numLines = Math.floor(backgroundWidth / 64);

// Dibujar líneas del grid
// Draw grid lines
for (let x = 0; x <= width / 64; x += 1) {
ctx.moveTo(widgetX + x * 64 * scale, widgetYBar);
ctx.lineTo(widgetX + x * 64 * scale, widgetYBar + barHeight);
}
ctx.stroke();
ctx.closePath();

// Dibujar progreso (basado en blur_radius)
// Draw progress (based on blur_radius)
const progress = Math.min(blurRadius / 255, 1);
ctx.fillStyle = "rgba(0, 120, 255, 0.5)";

Expand Down Expand Up @@ -203,25 +209,85 @@ function showPreviewCanvas(node, app) {
}

app.registerExtension({
name: 'drltdata.MaskRectAreaAdvanced',
name: "drltdata.MaskRectAreaAdvanced",
async beforeRegisterNodeDef(nodeType, nodeData, app) {
if (nodeData.name === "MaskRectAreaAdvanced") {
const onNodeCreated = nodeType.prototype.onNodeCreated;
nodeType.prototype.onNodeCreated = function () {
const r = onNodeCreated ? onNodeCreated.apply(this, arguments) : undefined;

this.setProperty("width", 512);
this.setProperty("height", 512);
this.setProperty("x", 0);
this.setProperty("y", 0);
this.setProperty("w", 256);
this.setProperty("h", 256);
this.setProperty("blur_radius", 0);
if (nodeData.name !== "MaskRectAreaAdvanced") {
return;
}

this.selected = false;
this.index = 3;
this.serialize_widgets = true;
const onNodeCreated = nodeType.prototype.onNodeCreated;
nodeType.prototype.onNodeCreated = function () {
const r = onNodeCreated ? onNodeCreated.apply(this, arguments) : undefined;

this.setProperty("width", 512);
this.setProperty("height", 512);
this.setProperty("x", 0);
this.setProperty("y", 0);
this.setProperty("w", 256);
this.setProperty("h", 256);
this.setProperty("blur_radius", 0);

this.selected = false;
this.index = 3;
this.serialize_widgets = true;

// If the node already provides widgets from Python/ComfyUI, do NOT recreate them
const hasExisting = Array.isArray(this.widgets) && this.widgets.some(w => w && w.name === "x");

// Helper: attach callbacks to existing widgets to keep node.properties in sync (canvas preview).
const hookWidget = (node, widgetName, propName, opts) => {
if (!Array.isArray(node.widgets)) {
return;
}
const w = node.widgets.find(ww => ww && ww.name === widgetName);
if (!w) {
return;
}

const min = (opts && typeof opts.min === "number") ? opts.min : undefined;
const max = (opts && typeof opts.max === "number") ? opts.max : undefined;
const step = (opts && typeof opts.step === "number") ? opts.step : undefined;

if (node.properties && Object.prototype.hasOwnProperty.call(node.properties, propName)) {
w.value = node.properties[propName];
} else {
node.properties[propName] = w.value;
}

const prevCb = w.callback;
w.callback = function (v, ...args) {
let val = v;
if (typeof val === "number") {
if (typeof step === "number" && step > 0) {
const s = step / 10;
val = Math.round(val / s) * s;
} else {
val = Math.round(val);
}
if (typeof min === "number") {
val = Math.max(min, val);
}
if (typeof max === "number") {
val = Math.min(max, val);
}
}
this.value = val;
node.properties[propName] = val;
if (prevCb) {
return prevCb.call(this, val, ...args);
}
};
};

if (hasExisting) {
hookWidget(this, "x", "x", {"step": 10});
hookWidget(this, "y", "y", {"step": 10});
hookWidget(this, "width", "w", {"step": 10});
hookWidget(this, "height", "h", {"step": 10});
hookWidget(this, "image_width", "width", {"step": 10});
hookWidget(this, "image_height", "height", {"step": 10});
hookWidget(this, "blur_radius", "blur_radius", {"min": 0, "max": 255, "step": 10});
} else {
CUSTOM_INT(this, "x", 0, function (v, _, node) {
const s = this.options.step / 10;
this.value = Math.round(v / s) * s;
Expand Down Expand Up @@ -258,19 +324,19 @@ app.registerExtension({
},
{"min": 0, "max": 255, "step": 10}
);
}

showPreviewCanvas(this, app);

this.onSelected = function () {
this.selected = true;
};
this.onDeselected = function () {
this.selected = false;
};
showPreviewCanvas(this, app);

return r;
this.onSelected = function () {
this.selected = true;
};
}
this.onDeselected = function () {
this.selected = false;
};

return r;
};
}
});

Expand Down Expand Up @@ -320,7 +386,7 @@ function getDrawColor(percent, alpha) {
const f = n => {
const k = (n + h / 30) % 12;
const color = l - a * Math.max(Math.min(k - 3, 9 - k, 1), -1);
return Math.round(255 * color).toString(16).padStart(2, '0'); // convert to Hex and prefix "0" if needed
return Math.round(255 * color).toString(16).padStart(2, '0');
};
return `#${f(0)}${f(8)}${f(4)}${alpha}`;
}
Expand All @@ -333,7 +399,8 @@ function computeCanvasSize(node, size) {
const MIN_HEIGHT = 220;
const MIN_WIDTH = 240;

let y = LiteGraph.NODE_WIDGET_HEIGHT * Math.max(node.inputs.length, node.outputs.length) + 5;
// FIX: use real last_y from layout, not slot count
let y = node.widgets[0].last_y + 5;
let freeSpace = size[1] - y;

// Compute the height of all non-customCanvas widgets
Expand All @@ -352,10 +419,15 @@ function computeCanvasSize(node, size) {
// Ensure there is enough vertical space
freeSpace -= widgetHeight;

// Adjust the height of the node if needed
// Minimum canvas height clamp
if (freeSpace < MIN_HEIGHT) {
freeSpace = MIN_HEIGHT;
node.size[1] = y + widgetHeight + freeSpace;
}

// Allow the node height to grow and shrink
const targetHeight = y + widgetHeight + freeSpace;
if (node.size[1] !== targetHeight) {
node.size[1] = targetHeight;
node.graph.setDirtyCanvas(true);
}

Expand All @@ -379,3 +451,107 @@ function computeCanvasSize(node, size) {

node.canvasHeight = freeSpace;
}

// Reads a numeric value from a connected link by inspecting the origin node widget.
// This is more reliable than getInputData() in ComfyUI's frontend execution model.
function readLinkedNumber(node, inputName) {
try {
if (!node || !node.graph || !Array.isArray(node.inputs)) {
return null;
}
const inp = node.inputs.find(i => i && i.name === inputName);
if (!inp || inp.link == null) {
return null;
}

const link = node.graph.links && node.graph.links[inp.link];
if (!link) {
return null;
}

const originNode = node.graph.getNodeById ? node.graph.getNodeById(link.origin_id) : null;
if (!originNode || !Array.isArray(originNode.widgets) || originNode.widgets.length === 0) {
return null;
}

// Most "Int" nodes expose the value in the first widget named "value".
const w = originNode.widgets.find(ww => ww && ww.name === "value") || originNode.widgets[0];
const v = w ? w.value : null;

return (typeof v === "number") ? v : null;
} catch (e) {
return null;
}
}
function syncLinkedInputsToPropertiesAdvanced(node) {
let changed = false;

const vx = readLinkedNumber(node, "x");
if (vx != null) {
const nv = Math.max(0, Math.round(vx));
if (node.properties["x"] !== nv) {
node.properties["x"] = nv;
changed = true;
}
}

const vy = readLinkedNumber(node, "y");
if (vy != null) {
const nv = Math.max(0, Math.round(vy));
if (node.properties["y"] !== nv) {
node.properties["y"] = nv;
changed = true;
}
}

// Input "width" is the rectangle width in px -> property "w"
const vw = readLinkedNumber(node, "width");
if (vw != null) {
const nv = Math.max(0, Math.round(vw));
if (node.properties["w"] !== nv) {
node.properties["w"] = nv;
changed = true;
}
}

// Input "height" is the rectangle height in px -> property "h"
const vh = readLinkedNumber(node, "height");
if (vh != null) {
const nv = Math.max(0, Math.round(vh));
if (node.properties["h"] !== nv) {
node.properties["h"] = nv;
changed = true;
}
}

// Image size (must be >=1 to avoid division by zero in getDrawArea)
const viw = readLinkedNumber(node, "image_width");
if (viw != null) {
const nv = Math.max(1, Math.round(viw));
if (node.properties["width"] !== nv) {
node.properties["width"] = nv;
changed = true;
}
}

const vih = readLinkedNumber(node, "image_height");
if (vih != null) {
const nv = Math.max(1, Math.round(vih));
if (node.properties["height"] !== nv) {
node.properties["height"] = nv;
changed = true;
}
}

const vbr = readLinkedNumber(node, "blur_radius");
if (vbr != null) {
const nv = Math.max(0, Math.min(255, Math.round(vbr)));
if (node.properties["blur_radius"] !== nv) {
node.properties["blur_radius"] = nv;
changed = true;
}
}

return changed;
}

Loading