import { app } from "/scripts/app.js"; function showPreviewCanvas(node, app) { const widget = { type: "customCanvas", name: "mask-rect-area-canvas", get value() { return this.canvas.value; }, set value(x) { this.canvas.value = x; }, draw: function (ctx, node, widgetWidth, widgetY) { // If we are initially offscreen when created we wont have received a resize event // Calculate it here instead if (!node.canvasHeight) { computeCanvasSize(node, node.size); } const visible = true; const t = ctx.getTransform(); 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); const blurRadius = node.properties["blur_radius"] || 0; const index = 0; Object.assign(this.canvas.style, { left: `${t.e}px`, top: `${t.f + (widgetY * t.d)}px`, width: `${widgetWidth * t.a}px`, height: `${widgetHeight * t.d}px`, position: "absolute", zIndex: 1, fontSize: `${t.d * 10.0}px`, pointerEvents: "none" }); this.canvas.hidden = !visible; let backgroundWidth = width * scale; let backgroundHeight = height * scale; let xOffset = margin; if (backgroundWidth < widgetWidth) { xOffset += (widgetWidth - backgroundWidth) / 2 - margin; } let yOffset = (margin / 2); if (backgroundHeight < widgetHeight) { yOffset += (widgetHeight - backgroundHeight) / 2 - margin; } let widgetX = xOffset; widgetY = widgetY + yOffset; // Draw the background border ctx.fillStyle = globalThis.LiteGraph.WIDGET_OUTLINE_COLOR; ctx.fillRect(widgetX - border, widgetY - border, backgroundWidth + border * 2, backgroundHeight + border * 2) // Draw the main background area ctx.fillStyle = globalThis.LiteGraph.WIDGET_BGCOLOR; ctx.fillRect(widgetX, widgetY, backgroundWidth, backgroundHeight); // Draw the conditioning zone let [x, y, w, h] = getDrawArea(node, backgroundWidth, backgroundHeight); ctx.fillStyle = getDrawColor(0, "80"); ctx.fillRect(widgetX + x, widgetY + y, w, h); ctx.beginPath(); ctx.lineWidth = 1; // Draw grid lines for (let x = 0; x <= width / 64; x += 1) { ctx.moveTo(widgetX + x * 64 * scale, widgetY); ctx.lineTo(widgetX + x * 64 * scale, widgetY + backgroundHeight); } for (let y = 0; y <= height / 64; y += 1) { ctx.moveTo(widgetX, widgetY + y * 64 * scale); ctx.lineTo(widgetX + backgroundWidth, widgetY + y * 64 * scale); } ctx.strokeStyle = "#66666650"; ctx.stroke(); ctx.closePath(); // Draw current zone let [sx, sy, sw, sh] = getDrawArea(node, backgroundWidth, backgroundHeight); ctx.fillStyle = getDrawColor(0, "80"); ctx.fillRect(widgetX + sx, widgetY + sy, sw, sh); ctx.fillStyle = getDrawColor(0, "40"); ctx.fillRect(widgetX + sx + border, widgetY + sy + border, sw - border * 2, sh - border * 2); // Draw white border around the current zone ctx.strokeStyle = globalThis.LiteGraph.NODE_SELECTED_TITLE_COLOR; ctx.lineWidth = 2; ctx.strokeRect(widgetX + sx, widgetY + sy, sw, sh); // Display ctx.beginPath(); ctx.arc(LiteGraph.NODE_SLOT_HEIGHT * 0.5, LiteGraph.NODE_SLOT_HEIGHT * (index + 0.5) + 4, 4, 0, Math.PI * 2); ctx.fill(); ctx.lineWidth = 1; ctx.strokeStyle = "white"; ctx.stroke(); ctx.lineWidth = 1; ctx.closePath(); // Draw progress bar canvas if (backgroundWidth < widgetWidth) { xOffset += (widgetWidth - backgroundWidth) / 2 - margin; } // Ajustar las coordenadas X e Y const barHeight = 8; let widgetYBar = widgetY + backgroundHeight + margin; // Dibujar el borde negro alrededor de la barra ctx.fillStyle = globalThis.LiteGraph.WIDGET_OUTLINE_COLOR; ctx.fillRect( widgetX - border, widgetYBar - border, backgroundWidth + border * 2, barHeight + border * 2 ); // Dibujar el área principal de la barra (fondo) ctx.fillStyle = globalThis.LiteGraph.WIDGET_BGCOLOR; // Mismo color de fondo que el canvas 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 const numLines = Math.floor(backgroundWidth / 64); // Dibujar líneas del grid 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) const progress = Math.min(blurRadius / 255, 1); ctx.fillStyle = "rgba(0, 120, 255, 0.5)"; ctx.fillRect( widgetX, widgetYBar, backgroundWidth * progress, barHeight ); } }; widget.canvas = document.createElement("canvas"); widget.canvas.className = "mask-rect-area-canvas"; widget.parent = node; document.body.appendChild(widget.canvas); node.addCustomWidget(widget); app.canvas.onDrawBackground = function () { // Draw node isnt fired once the node is off the screen // if it goes off screen quickly, the input may not be removed // this shifts it off screen so it can be moved back if the node is visible. for (let n in app.graph._nodes) { n = app.graph._nodes[n]; for (let w in n.widgets) { let wid = n.widgets[w]; if (Object.hasOwn(wid, "canvas")) { wid.canvas.style.left = -8000 + "px"; wid.canvas.style.position = "absolute"; } } } }; node.onResize = function (size) { computeCanvasSize(node, size); }; return {minWidth: 200, minHeight: 200, widget}; } app.registerExtension({ 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); this.selected = false; this.index = 3; this.serialize_widgets = true; CUSTOM_INT(this, "x", 0, function (v, _, node) { const s = this.options.step / 10; this.value = Math.round(v / s) * s; node.properties["x"] = this.value; }); CUSTOM_INT(this, "y", 0, function (v, _, node) { const s = this.options.step / 10; this.value = Math.round(v / s) * s; node.properties["y"] = this.value; }); CUSTOM_INT(this, "width", 256, function (v, _, node) { const s = this.options.step / 10; this.value = Math.round(v / s) * s; node.properties["w"] = this.value; }); CUSTOM_INT(this, "height", 256, function (v, _, node) { const s = this.options.step / 10; this.value = Math.round(v / s) * s; node.properties["h"] = this.value; }); CUSTOM_INT(this, "image_width", 512, function (v, _, node) { const s = this.options.step / 10; this.value = Math.round(v / s) * s; node.properties["width"] = this.value; }); CUSTOM_INT(this, "image_height", 512, function (v, _, node) { const s = this.options.step / 10; this.value = Math.round(v / s) * s; node.properties["height"] = this.value; }); CUSTOM_INT(this, "blur_radius", 0, function (v, _, node) { this.value = Math.round(v) || 0; node.properties["blur_radius"] = this.value; }, {"min": 0, "max": 255, "step": 10} ); showPreviewCanvas(this, app); this.onSelected = function () { this.selected = true; }; this.onDeselected = function () { this.selected = false; }; return r; }; } } }); // Calculate the drawing area using individual properties. function getDrawArea(node, backgroundWidth, backgroundHeight) { let x = node.properties["x"] * backgroundWidth / node.properties["width"]; let y = node.properties["y"] * backgroundHeight / node.properties["height"]; let w = node.properties["w"] * backgroundWidth / node.properties["width"]; let h = node.properties["h"] * backgroundHeight / node.properties["height"]; if (x > backgroundWidth) { x = backgroundWidth; } if (y > backgroundHeight) { y = backgroundHeight; } if (x + w > backgroundWidth) { w = Math.max(0, backgroundWidth - x); } if (y + h > backgroundHeight) { h = Math.max(0, backgroundHeight - y); } return [x, y, w, h]; } function CUSTOM_INT(node, inputName, val, func, config = {}) { return { widget: node.addWidget( "number", inputName, val, func, Object.assign({}, {min: 0, max: 4096, step: 640, precision: 0}, config) ) }; } function getDrawColor(percent, alpha) { let h = 360 * percent; let s = 50; let l = 50; l /= 100; const a = s * Math.min(l, 1 - l) / 100; 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 `#${f(0)}${f(8)}${f(4)}${alpha}`; } function computeCanvasSize(node, size) { if (node.widgets[0].last_y == null) { return; } const MIN_HEIGHT = 220; const MIN_WIDTH = 240; let y = LiteGraph.NODE_WIDGET_HEIGHT * Math.max(node.inputs.length, node.outputs.length) + 5; let freeSpace = size[1] - y; // Compute the height of all non-customCanvas widgets let widgetHeight = 0; for (let i = 0; i < node.widgets.length; i++) { const w = node.widgets[i]; if (w.type !== "customCanvas") { if (w.computeSize) { widgetHeight += w.computeSize()[1] + 4; } else { widgetHeight += LiteGraph.NODE_WIDGET_HEIGHT + 5; } } } // Ensure there is enough vertical space freeSpace -= widgetHeight; // Adjust the height of the node if needed if (freeSpace < MIN_HEIGHT) { freeSpace = MIN_HEIGHT; node.size[1] = y + widgetHeight + freeSpace; node.graph.setDirtyCanvas(true); } // Ensure the node width meets the minimum width requirement if (node.size[0] < MIN_WIDTH) { node.size[0] = MIN_WIDTH; node.graph.setDirtyCanvas(true); } // Position each of the widgets for (const w of node.widgets) { w.y = y; if (w.type === "customCanvas") { y += freeSpace; } else if (w.computeSize) { y += w.computeSize()[1] + 4; } else { y += LiteGraph.NODE_WIDGET_HEIGHT + 4; } } node.canvasHeight = freeSpace; }