Files
2025-04-26 19:08:55 +08:00

265 lines
11 KiB
JavaScript

// import { app } from "../../../scripts/app.js";
// let originalLayout = null;
// class LayoutOptimizer {
// static optimizeWorkflow() {
// const graph = app.graph;
// const nodes = graph._nodes;
// if (!nodes.length) return;
// // 保存当前布局
// originalLayout = nodes.map(node => ({
// id: node.id,
// pos: [...node.pos]
// }));
// // 找到最后一个 KSampler 节点(按 id 排序)
// const samplers = nodes.filter(node => node.type.toLowerCase().includes("ksampler"));
// if (!samplers.length) {
// console.log("No KSampler node found.");
// return;
// }
// const lastSampler = samplers.sort((a, b) => b.id - a.id)[0];
// // 计算节点层级(从 KSampler 反推和正推)
// const levelsLeft = new Map(); // 左侧层级(反推)
// const levelsRight = new Map(); // 右侧层级(正推)
// const visitedLeft = new Set();
// const visitedRight = new Set();
// // 反推(左侧)
// function computeLevelLeft(node, level = 0) {
// if (visitedLeft.has(node.id)) return;
// visitedLeft.add(node.id);
// levelsLeft.set(node.id, level);
// if (node.inputs) {
// node.inputs.forEach(input => {
// if (input.link) {
// const link = graph.links[input.link];
// if (link) {
// const sourceNode = nodes.find(n => n.id === link.origin_id);
// if (sourceNode) computeLevelLeft(sourceNode, level + 1);
// }
// }
// });
// }
// }
// // 正推(右侧)
// function computeLevelRight(node, level = 0) {
// if (visitedRight.has(node.id)) return;
// visitedRight.add(node.id);
// levelsRight.set(node.id, level);
// if (node.outputs) {
// node.outputs.forEach(output => {
// if (output.links) {
// output.links.forEach(linkId => {
// const link = graph.links[linkId];
// if (link) {
// const targetNode = nodes.find(n => n.id === link.target_id);
// if (targetNode) computeLevelRight(targetNode, level + 1);
// }
// });
// }
// });
// }
// }
// computeLevelLeft(lastSampler);
// computeLevelRight(lastSampler);
// // 计算最大层级
// const maxLevelLeft = Math.max(...levelsLeft.values(), 0);
// const maxLevelRight = Math.max(...levelsRight.values(), 0);
// // 未连接的节点设为最外层
// nodes.forEach(node => {
// if (!levelsLeft.has(node.id) && !levelsRight.has(node.id)) {
// levelsLeft.set(node.id, maxLevelLeft + 1);
// }
// });
// // 按层级分组
// const levelsMapLeft = new Map();
// levelsLeft.forEach((level, id) => {
// if (!levelsMapLeft.has(level)) levelsMapLeft.set(level, []);
// levelsMapLeft.get(level).push(nodes.find(n => n.id === id));
// });
// const levelsMapRight = new Map();
// levelsRight.forEach((level, id) => {
// if (!levelsMapRight.has(level)) levelsMapRight.set(level, []);
// levelsMapRight.get(level).push(nodes.find(n => n.id === id));
// });
// // 计算间距(动态基于节点大小)
// const maxNodeWidth = Math.max(...nodes.map(node => node.size[0] || 200));
// const maxNodeHeight = Math.max(...nodes.map(node => node.size[1] || 100));
// const baseRadius = maxNodeWidth + 100; // 扇形基础半径
// const minAngleGap = 30; // 最小角度间隔(度)
// // 布局:以 KSampler 为中心
// const processed = new Set();
// const centerX = app.canvas.canvas.width / 2;
// const centerY = app.canvas.canvas.height / 2;
// // 放置 KSampler
// lastSampler.pos[0] = centerX;
// lastSampler.pos[1] = centerY;
// processed.add(lastSampler.id);
// // 扇形布局函数
// function arrangeFan(nodesInLevel, level, direction, parentX, parentY) {
// if (!nodesInLevel) return;
// const radius = baseRadius * (Math.abs(level) + 1); // 半径随层级递增
// const isLeft = direction === "left";
// const baseX = isLeft ? parentX - radius : parentX + radius;
// // 过滤未处理的节点
// const unprocessedNodes = nodesInLevel.filter(n => !processed.has(n.id));
// if (!unprocessedNodes.length) return;
// // 如果只有一个节点(无同级),直线排列
// if (unprocessedNodes.length === 1) {
// const node = unprocessedNodes[0];
// node.pos[0] = baseX;
// node.pos[1] = parentY; // 直线对齐
// processed.add(node.id);
// // 递归布局下一级
// const nextLevel = isLeft ? level + 1 : level + 1;
// const nextNodes = (isLeft ? levelsMapLeft : levelsMapRight).get(nextLevel)?.filter(n => !processed.has(n.id));
// arrangeFan(nextNodes, nextLevel, direction, node.pos[0], node.pos[1]);
// return;
// }
// // 多个节点,扇形排列
// const totalAngle = Math.min(180, (unprocessedNodes.length - 1) * minAngleGap); // 总角度不超过 180 度
// const startAngle = -totalAngle / 2;
// const angleStep = totalAngle / (unprocessedNodes.length - 1 || 1);
// unprocessedNodes.forEach((node, index) => {
// processed.add(node.id);
// const angle = startAngle + index * angleStep;
// const rad = (angle * Math.PI) / 180;
// node.pos[0] = baseX + (isLeft ? -radius * Math.cos(rad) : radius * Math.cos(rad));
// node.pos[1] = parentY + radius * Math.sin(rad);
// // 避免重叠:调整 y 坐标
// const nodesAtX = nodes.filter(n => Math.abs(n.pos[0] - node.pos[0]) < maxNodeWidth && n.id !== node.id);
// nodesAtX.sort((a, b) => a.pos[1] - b.pos[1]);
// nodesAtX.forEach((otherNode, idx) => {
// if (otherNode.id < node.id) {
// const otherHeight = otherNode.size[1] || maxNodeHeight;
// const nodeHeight = node.size[1] || maxNodeHeight;
// const minGap = (otherHeight + nodeHeight) / 2 + 50;
// if (Math.abs(node.pos[1] - otherNode.pos[1]) < minGap) {
// if (node.pos[1] > otherNode.pos[1]) {
// node.pos[1] = otherNode.pos[1] + minGap;
// } else {
// node.pos[1] = otherNode.pos[1] - minGap;
// }
// }
// }
// });
// // 递归布局下一级
// const nextLevel = isLeft ? level + 1 : level + 1;
// const nextNodes = (isLeft ? levelsMapLeft : levelsMapRight).get(nextLevel)?.filter(n => !processed.has(n.id));
// arrangeFan(nextNodes, nextLevel, direction, node.pos[0], node.pos[1]);
// });
// }
// // 布局左侧(传入节点)
// for (let level = 1; level <= maxLevelLeft; level++) {
// const nodesInLevel = levelsMapLeft.get(level)?.filter(n => !processed.has(n.id));
// arrangeFan(nodesInLevel, level, "left", lastSampler.pos[0], lastSampler.pos[1]);
// }
// // 布局右侧(输出节点)
// for (let level = 1; level <= maxLevelRight; level++) {
// const nodesInLevel = levelsMapRight.get(level)?.filter(n => !processed.has(n.id));
// arrangeFan(nodesInLevel, level, "right", lastSampler.pos[0], lastSampler.pos[1]);
// }
// // 处理未布局的节点
// nodes.forEach(node => {
// if (!processed.has(node.id)) {
// const level = levelsLeft.get(node.id) || 0;
// node.pos[0] = centerX + (level * baseRadius);
// node.pos[1] = centerY + (nodes.indexOf(node) * (maxNodeHeight + 50));
// processed.add(node.id);
// }
// });
// app.canvas.setDirty(true, true);
// }
// static restoreWorkflow() {
// if (!originalLayout) {
// console.log("No previous layout to restore.");
// return;
// }
// const graph = app.graph;
// originalLayout.forEach(saved => {
// const node = graph._nodes.find(n => n.id === saved.id);
// if (node) {
// node.pos[0] = saved.pos[0];
// node.pos[1] = saved.pos[1];
// }
// });
// app.canvas.setDirty(true, true);
// originalLayout = null;
// }
// }
// app.registerExtension({
// name: "KayTool.LayoutOptimizer",
// setup() {
// const orig = LGraphCanvas.prototype.getCanvasMenuOptions;
// LGraphCanvas.prototype.getCanvasMenuOptions = function () {
// const options = orig.apply(this, arguments) || [];
// const showWorkflowPNG = app.ui.settings.getSettingValue("KayTool.ShowWorkflowPNG");
// if (showWorkflowPNG) {
// const newOptions = [...options];
// let kaytoolMenu = newOptions.find(opt => opt && opt.content === "KayTool");
// if (!kaytoolMenu) {
// kaytoolMenu = {
// content: "KayTool",
// submenu: { options: [] }
// };
// newOptions.push(null, kaytoolMenu);
// }
// kaytoolMenu.submenu.options = kaytoolMenu.submenu.options || [];
// kaytoolMenu.submenu.options.push({
// content: "Layout Tools",
// submenu: {
// options: [
// {
// content: "优化工作流",
// callback: () => {
// LayoutOptimizer.optimizeWorkflow();
// },
// },
// {
// content: "恢复",
// callback: () => {
// LayoutOptimizer.restoreWorkflow();
// },
// },
// ],
// },
// });
// return newOptions;
// }
// return options;
// };
// },
// });