Separated CSS to make it cleaner and more maintainable. Fixed bug only 2 nodes would be displayed.
This commit is contained in:
+207
@@ -0,0 +1,207 @@
|
||||
import { app } from "../../scripts/app.js";
|
||||
|
||||
// 1. Inject CSS
|
||||
const link = document.createElement("link");
|
||||
link.rel = "stylesheet";
|
||||
link.type = "text/css";
|
||||
link.href = "extensions/ComfyUI-Node-HUD/css/hud_styles.css";
|
||||
document.head.appendChild(link);
|
||||
|
||||
app.registerExtension({
|
||||
name: "Comfy.CleanLayoutDock",
|
||||
|
||||
async beforeRegisterNodeDef(nodeType, nodeData, app) {
|
||||
|
||||
// --- A. Toggle Menu Option ---
|
||||
const getExtraMenuOptions = nodeType.prototype.getExtraMenuOptions;
|
||||
nodeType.prototype.getExtraMenuOptions = function(_, options) {
|
||||
if (getExtraMenuOptions) getExtraMenuOptions.apply(this, arguments);
|
||||
options.push({
|
||||
content: "Toggle Stack Info",
|
||||
callback: () => {
|
||||
this.show_stack_info = !this.show_stack_info;
|
||||
// Force a redraw to update visibility immediately
|
||||
app.graph.setDirtyCanvas(true, true);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// --- B. The Main Loop (Replaces Draw) ---
|
||||
// We hook into onDrawForeground to handle Position updates
|
||||
const onDrawForeground = nodeType.prototype.onDrawForeground;
|
||||
nodeType.prototype.onDrawForeground = function(ctx) {
|
||||
if (onDrawForeground) onDrawForeground.apply(this, arguments);
|
||||
|
||||
// 1. Cleanup: If toggled off or empty, remove the dock
|
||||
const stackList = getHiddenNodes(this, app.graph);
|
||||
const shouldShow = this.show_stack_info && stackList.length > 0;
|
||||
|
||||
if (!shouldShow) {
|
||||
if (this.hudElement) {
|
||||
this.hudElement.remove();
|
||||
this.hudElement = null;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// 2. Update the Dock (Position & Content)
|
||||
updateDock(this, stackList, app.graph);
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
// --- HELPER: Find Hidden Nodes ---
|
||||
function getHiddenNodes(parent, graph) {
|
||||
const stackList = [];
|
||||
if (!graph || !graph._nodes) return stackList;
|
||||
|
||||
const pLeft = parent.pos[0];
|
||||
const pRight = parent.pos[0] + parent.size[0];
|
||||
const pTop = parent.pos[1];
|
||||
const pBottom = parent.pos[1] + parent.size[1];
|
||||
|
||||
for (const node of graph._nodes) {
|
||||
if (node.id === parent.id) continue;
|
||||
const nx = node.pos[0];
|
||||
const ny = node.pos[1];
|
||||
// Check if center of node is inside parent (simple hit test)
|
||||
if (nx >= pLeft && nx < pRight && ny >= pTop && ny < pBottom) {
|
||||
stackList.push(node);
|
||||
}
|
||||
}
|
||||
return stackList;
|
||||
}
|
||||
|
||||
// --- HELPER: Get Link Color ---
|
||||
function getLinkColor(link) {
|
||||
if (!link) return "#aaaaff";
|
||||
const type = link.type;
|
||||
const colorMap = LGraphCanvas.link_type_colors;
|
||||
|
||||
if (colorMap[type]) return colorMap[type];
|
||||
|
||||
if (type === "STRING") return "#66ff66";
|
||||
if (type === "INT") return "#22cc22";
|
||||
if (type === "FLOAT") return "#22cc22";
|
||||
if (type === "LATENT") return "#ff99aa";
|
||||
if (type === "IMAGE") return "#66aaff";
|
||||
if (type === "MODEL") return "#6666aa";
|
||||
if (type === "VAE") return "#ff4444";
|
||||
if (type === "CLIP") return "#ffff66";
|
||||
if (type === "CONDITIONING") return "#aa6666";
|
||||
|
||||
return "#aaaaff";
|
||||
}
|
||||
|
||||
// --- THE NEW DOM BUILDER ---
|
||||
function updateDock(node, stackList, graph) {
|
||||
// 1. Create Element if missing
|
||||
if (!node.hudElement) {
|
||||
node.hudElement = document.createElement("div");
|
||||
node.hudElement.className = "hud-dock";
|
||||
document.body.appendChild(node.hudElement);
|
||||
node.lastStackSignature = ""; // Init signature
|
||||
}
|
||||
const dock = node.hudElement;
|
||||
|
||||
// 2. Content Update (Optimization: Only if stack changed)
|
||||
// We create a "signature" string of IDs (e.g., "12,15,22")
|
||||
const currentSignature = stackList.map(n => n.id).join(",");
|
||||
|
||||
if (currentSignature !== node.lastStackSignature) {
|
||||
dock.innerHTML = ""; // Clear
|
||||
node.lastStackSignature = currentSignature; // Update signature
|
||||
|
||||
// Build Chips
|
||||
for (const item of stackList) {
|
||||
const chip = document.createElement("div");
|
||||
chip.className = "hud-chip";
|
||||
|
||||
// Determine Border Color based on Mode
|
||||
if (item.mode === 2) chip.style.borderColor = "#888888"; // Muted
|
||||
else if (item.mode === 4) chip.style.borderColor = "#cc66ff"; // Bypassed
|
||||
|
||||
// --- GATHER DOT COLORS ---
|
||||
const leftDots = [];
|
||||
const rightDots = [];
|
||||
|
||||
// Inputs
|
||||
if (item.inputs) {
|
||||
for (const input of item.inputs) {
|
||||
if (input.link) {
|
||||
const link = graph.links[input.link];
|
||||
if (link) leftDots.push(getLinkColor(link));
|
||||
}
|
||||
}
|
||||
}
|
||||
// Outputs
|
||||
if (item.outputs) {
|
||||
for (const output of item.outputs) {
|
||||
if (output.links && output.links.length > 0) {
|
||||
const link = graph.links[output.links[0]];
|
||||
if (link) rightDots.push(getLinkColor(link));
|
||||
else if (LGraphCanvas.link_type_colors[output.type]) {
|
||||
rightDots.push(LGraphCanvas.link_type_colors[output.type]);
|
||||
} else {
|
||||
if (output.type === "STRING") rightDots.push("#66ff66");
|
||||
else rightDots.push("#cccccc");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Fallback Red Dot
|
||||
if (leftDots.length === 0 && rightDots.length === 0) {
|
||||
leftDots.push("#ff4444");
|
||||
}
|
||||
|
||||
// --- BUILD CHIP DOM ---
|
||||
// Left Dots
|
||||
leftDots.forEach(c => {
|
||||
const d = document.createElement("div");
|
||||
d.className = "hud-dot";
|
||||
d.style.backgroundColor = c;
|
||||
chip.appendChild(d);
|
||||
});
|
||||
|
||||
// Text
|
||||
const span = document.createElement("span");
|
||||
let text = item.title || item.type;
|
||||
if (text.length > 20) text = text.substring(0, 18) + "..";
|
||||
span.innerText = text;
|
||||
chip.appendChild(span);
|
||||
|
||||
// Right Dots
|
||||
rightDots.forEach(c => {
|
||||
const d = document.createElement("div");
|
||||
d.className = "hud-dot";
|
||||
d.style.backgroundColor = c;
|
||||
chip.appendChild(d);
|
||||
});
|
||||
|
||||
dock.appendChild(chip);
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Position Update (Run every frame)
|
||||
// Map Graph Coordinates -> Screen Coordinates
|
||||
const canvas = app.canvas;
|
||||
const scale = canvas.ds.scale;
|
||||
const offset = canvas.ds.offset;
|
||||
|
||||
// Calculate screen position
|
||||
// (node.pos is [x, y])
|
||||
const screenX = (node.pos[0] + offset[0]) * scale;
|
||||
// Position it at the bottom of the node
|
||||
const screenY = (node.pos[1] + node.size[1] + offset[1]) * scale;
|
||||
|
||||
dock.style.position = "absolute";
|
||||
dock.style.left = screenX + "px";
|
||||
dock.style.top = screenY + "px";
|
||||
dock.style.width = (node.size[0] * scale) + "px";
|
||||
|
||||
// Scale the UI to match the zoom level
|
||||
// (Using transform-origin top-left ensures it scales from the corner)
|
||||
dock.style.transform = `scale(${scale})`;
|
||||
dock.style.transformOrigin = "top left";
|
||||
dock.style.zIndex = "1000"; // Ensure it's on top
|
||||
}
|
||||
Reference in New Issue
Block a user