feat: 适配 nodes2.0 模式连线动画
- getConnectionPos 改用 getOutputPos/getInputPos (兼容 layoutStore) - StyleManager/CircuitBoardStyle/StaticCircuitBoardStyle 同步替换 - Vue 模式下 document mousemove 替代 canvas 实现悬停检测 - canvas.select()/deselect() 补丁确保选中模式动画循环启动
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
// 动画核心模块,只包含动画逻辑和默认配置
|
||||
// 动画核心模块,只包含动画逻辑和默认配置
|
||||
import { EffectManager } from './effects/EffectManager.js';
|
||||
import { StyleManager } from './styles/StyleManager.js';
|
||||
import { StaticStyleManager } from './styles/static/StaticStyleManager.js';
|
||||
@@ -671,7 +671,13 @@ export class ConnectionAnimation {
|
||||
_getConnectionPos(node, slot, isOutput) {
|
||||
if (!node || slot === undefined) return null;
|
||||
|
||||
// 使用ComfyUI标准的连接点位置获取方法
|
||||
// 优先使用现代 API(Vue nodes2.0 模式下依赖 layoutStore,旧模式也能用)
|
||||
if (isOutput) {
|
||||
if (typeof node.getOutputPos === 'function') return node.getOutputPos(slot);
|
||||
} else {
|
||||
if (typeof node.getInputPos === 'function') return node.getInputPos(slot);
|
||||
}
|
||||
// 回退到 getConnectionPos
|
||||
if (typeof node.getConnectionPos === 'function') {
|
||||
return node.getConnectionPos(!isOutput, slot); // 注意:getConnectionPos的第一个参数是isInput
|
||||
}
|
||||
|
||||
@@ -123,10 +123,69 @@ function setupNodeHoverListeners(connectionAnimation) {
|
||||
}
|
||||
}
|
||||
|
||||
// Vue nodes2.0 模式下的悬停检测(LiteGraph 的 onNodeMouseEnter/Leave 在 Vue 模式下不触发)
|
||||
function setupVueModeHoverDetection(connectionAnimation) {
|
||||
if (!app.canvas) return;
|
||||
|
||||
const canvas = app.canvas;
|
||||
const canvasEl = canvas.canvas;
|
||||
if (!canvasEl) return;
|
||||
|
||||
document.addEventListener('mousemove', (e) => {
|
||||
if (!window.LiteGraph?.vueNodesMode) return;
|
||||
|
||||
const rect = canvasEl.getBoundingClientRect();
|
||||
if (e.clientX < rect.left || e.clientX > rect.right ||
|
||||
e.clientY < rect.top || e.clientY > rect.bottom) {
|
||||
connectionAnimation.setHoveredNode(null);
|
||||
return;
|
||||
}
|
||||
const graphPos = canvas.convertEventToCanvasOffset({ clientX: e.clientX, clientY: e.clientY });
|
||||
let hoveredNode = null;
|
||||
const graph = canvas.graph;
|
||||
if (graph && graph._nodes) {
|
||||
for (const node of Object.values(graph._nodes)) {
|
||||
if (node.isPointInside && node.isPointInside(graphPos[0], graphPos[1])) {
|
||||
hoveredNode = node;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
connectionAnimation.setHoveredNode(hoveredNode);
|
||||
});
|
||||
}
|
||||
|
||||
// 设置节点选择监听
|
||||
function setupNodeSelectionListeners(connectionAnimation) {
|
||||
if (!app.canvas) return;
|
||||
|
||||
// Vue nodes2.0 模式使用 select()/deselect(),不走 selectNode()/deselectNode()
|
||||
const originalSelect = app.canvas.select;
|
||||
app.canvas.select = function(item) {
|
||||
const result = originalSelect?.call(this, item);
|
||||
try {
|
||||
if (connectionAnimation.notifySelectionChanged) {
|
||||
connectionAnimation.notifySelectionChanged();
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn("Connection Animation: Error handling select:", e);
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
const originalDeselect = app.canvas.deselect;
|
||||
app.canvas.deselect = function(item) {
|
||||
const result = originalDeselect?.call(this, item);
|
||||
try {
|
||||
if (connectionAnimation.notifySelectionChanged) {
|
||||
connectionAnimation.notifySelectionChanged();
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn("Connection Animation: Error handling deselect:", e);
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
// 监听选择变化
|
||||
const originalOnSelectionChange = app.canvas.onSelectionChange;
|
||||
app.canvas.onSelectionChange = function(nodes) {
|
||||
@@ -198,6 +257,9 @@ app.registerExtension({
|
||||
// 设置节点悬停监听
|
||||
setupNodeHoverListeners(connectionAnimation);
|
||||
|
||||
// 设置 Vue nodes2.0 悬停检测(LiteGraph hover 在 Vue 模式不触发)
|
||||
setupVueModeHoverDetection(connectionAnimation);
|
||||
|
||||
// 设置节点选择监听
|
||||
setupNodeSelectionListeners(connectionAnimation);
|
||||
},
|
||||
|
||||
@@ -186,6 +186,22 @@ class MapLinks {
|
||||
this.gridHeight = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取输出端口位置(Vue nodes2.0 兼容)
|
||||
*/
|
||||
_getOutputPos(node, slot, outArray) {
|
||||
if (typeof node.getOutputPos === 'function') return node.getOutputPos(slot);
|
||||
return node.getConnectionPos ? node.getConnectionPos(false, slot, outArray) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取输入端口位置(Vue nodes2.0 兼容)
|
||||
*/
|
||||
_getInputPos(node, slot, outArray) {
|
||||
if (typeof node.getInputPos === 'function') return node.getInputPos(slot);
|
||||
return node.getConnectionPos ? node.getConnectionPos(true, slot, outArray) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查点是否在某个节点内部
|
||||
*/
|
||||
@@ -787,7 +803,7 @@ class MapLinks {
|
||||
}
|
||||
|
||||
const linkPos = new Float32Array(2);
|
||||
const outputXYConnection = node.getConnectionPos(false, slot, linkPos);
|
||||
const outputXYConnection = this._getOutputPos(node, slot, linkPos);
|
||||
const outputNodeInfo = this.nodesById[node.id];
|
||||
let outputXY = Array.from(outputXYConnection);
|
||||
|
||||
@@ -805,11 +821,7 @@ class MapLinks {
|
||||
}
|
||||
|
||||
const inputLinkPos = new Float32Array(2);
|
||||
const inputXYConnection = targetNode.getConnectionPos(
|
||||
true,
|
||||
link.target_slot,
|
||||
inputLinkPos
|
||||
);
|
||||
const inputXYConnection = this._getInputPos(targetNode, link.target_slot, inputLinkPos);
|
||||
const inputXY = Array.from(inputXYConnection);
|
||||
const nodeInfo = this.nodesById[targetNode.id];
|
||||
inputXY[0] = nodeInfo.linesArea[0] - 1;
|
||||
|
||||
@@ -89,7 +89,23 @@ export class StyleManager {
|
||||
this.currentStyleName = "曲线";
|
||||
}
|
||||
}
|
||||
/**
|
||||
/**
|
||||
* 获取输出端口位置(Vue nodes2.0 兼容)
|
||||
*/
|
||||
_getOutputPos(node, slot, outArray) {
|
||||
if (typeof node.getOutputPos === 'function') return node.getOutputPos(slot);
|
||||
return node.getConnectionPos ? node.getConnectionPos(false, slot, outArray) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取输入端口位置(Vue nodes2.0 兼容)
|
||||
*/
|
||||
_getInputPos(node, slot, outArray) {
|
||||
if (typeof node.getInputPos === 'function') return node.getInputPos(slot);
|
||||
return node.getConnectionPos ? node.getConnectionPos(true, slot, outArray) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算指定连线的路径
|
||||
* @param {Array} specificLinks - 要计算的特定连线数组,如果为null则计算所有连线
|
||||
* @returns {Array} 路径数据数组
|
||||
@@ -123,8 +139,8 @@ export class StyleManager {
|
||||
const inNode = link.target_id === -20 ? this.animationManager.canvas.graph.outputNode : this.animationManager.canvas.graph.getNodeById(link.target_id);
|
||||
if (!outNode || !inNode) return;
|
||||
|
||||
const outPos = link.origin_id === -10 ? outNode.slots[link.origin_slot].pos : outNode.getConnectionPos(false, link.origin_slot);
|
||||
const inPos = link.target_id === -20 ? inNode.slots[link.target_slot].pos : inNode.getConnectionPos(true, link.target_slot);
|
||||
const outPos = link.origin_id === -10 ? outNode.slots[link.origin_slot].pos : this._getOutputPos(outNode, link.origin_slot);
|
||||
const inPos = link.target_id === -20 ? inNode.slots[link.target_slot].pos : this._getInputPos(inNode, link.target_slot);
|
||||
|
||||
// 使用统一的getBaseColor方法获取颜色
|
||||
const baseColor = this.currentStyle.getBaseColor(link.origin_id !== -10 ? outNode : inNode, link);
|
||||
|
||||
@@ -174,6 +174,22 @@ class StaticMapLinks {
|
||||
this.gridHeight = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取输出端口位置(Vue nodes2.0 兼容)
|
||||
*/
|
||||
_getOutputPos(node, slot, outArray) {
|
||||
if (typeof node.getOutputPos === 'function') return node.getOutputPos(slot);
|
||||
return node.getConnectionPos ? node.getConnectionPos(false, slot, outArray) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取输入端口位置(Vue nodes2.0 兼容)
|
||||
*/
|
||||
_getInputPos(node, slot, outArray) {
|
||||
if (typeof node.getInputPos === 'function') return node.getInputPos(slot);
|
||||
return node.getConnectionPos ? node.getConnectionPos(true, slot, outArray) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查点是否在某个节点内部
|
||||
*/
|
||||
@@ -725,7 +741,7 @@ class StaticMapLinks {
|
||||
}
|
||||
|
||||
const linkPos = new Float32Array(2);
|
||||
const outputXYConnection = node.getConnectionPos(false, slot, linkPos);
|
||||
const outputXYConnection = this._getOutputPos(node, slot, linkPos);
|
||||
const outputNodeInfo = this.nodesById[node.id];
|
||||
let outputXY = Array.from(outputXYConnection);
|
||||
|
||||
@@ -744,11 +760,7 @@ class StaticMapLinks {
|
||||
}
|
||||
|
||||
const inputLinkPos = new Float32Array(2);
|
||||
const inputXYConnection = targetNode.getConnectionPos(
|
||||
true,
|
||||
link.target_slot,
|
||||
inputLinkPos
|
||||
);
|
||||
const inputXYConnection = this._getInputPos(targetNode, link.target_slot, inputLinkPos);
|
||||
const inputXY = Array.from(inputXYConnection);
|
||||
const nodeInfo = this.nodesById[targetNode.id];
|
||||
// 关键!调整输入点到节点左边缘
|
||||
|
||||
Reference in New Issue
Block a user