diff --git a/ArtsticH/hNodeAlignPro.js b/ArtsticH/hNodeAlignPro.js index 175366b..902f214 100644 --- a/ArtsticH/hNodeAlignPro.js +++ b/ArtsticH/hNodeAlignPro.js @@ -45,7 +45,7 @@ --hC_BW7_White: 255, 255, 255; /* ↑↑↑全局核心颜色定义,不得修改↑↑↑ */ - /* 新增:取色器相关变量(全部已按注释要求重命名并统一为x,x,x格式) */ + /* 取色器相关变量 */ --hC_CPr0__PurpleStd: var(--hC_hBtn1_Highlight); --hC_CPr1__bgDark: 30, 30, 30; --hC_CPr2__bgDarker: 21, 21, 21; @@ -1051,14 +1051,8 @@ // 【== 直接应用颜色值到选中节点:解析颜色后为选中节点/分组上色,标记画布变更 ==】 __hFc_Color2Nodes(colorValue) { try { - const app = this.getComfyUIAppInstance(); - if (!this.validateAppInstance(app)) return hLog.warn("ComfyUI实例获取失败"); - const selectedNodes = this.getSelectedNodes(), selectedGroups = this.getSelectedGroups(app); - if (selectedNodes.length + selectedGroups.length === 0) return hLog.warn('--@hColorApply_tip',"请先选择节点或组"); - const resolvedColor = this.resolveCSSColor(colorValue); - - selectedNodes.forEach(node => node.is_system || this.applyColorToSingleNode(node, resolvedColor)); - selectedGroups.length > 0 && hLog.log('--@hColorApply_OK',`节当前颜色${resolvedColor}已同步至→`, selectedNodes.length,'节点(', selectedGroups.length,'组)'); + const app = this.getComfyUIAppInstance(); if (!this.validateAppInstance(app)) return hLog.warn("ComfyUI实例获取失败"); const selectedNodes = this.getSelectedNodes(), selectedGroups = this.getSelectedGroups(app); if (selectedNodes.length + selectedGroups.length === 0) return hLog.warn('--@hColorApply_tip', "请先选择节点或组"); + const resolvedColor = this.resolveCSSColor(colorValue); selectedNodes.forEach(node => node.is_system || this.applyColorToSingleNode(node, resolvedColor)); selectedGroups.length > 0 && hLog.log('--@hColorApply_OK', `节当前颜色${resolvedColor}已同步至→`, selectedNodes.length, '节点(', selectedGroups.length, '组)'); selectedGroups.forEach(group => { this.isGroupActuallySelected(group, app.canvas) ? (group.color = this.rgbToHex(resolvedColor), group.children && group.children.forEach(nodeID => this.applyColorToSingleNode(app.graph.getNodeById(nodeID), resolvedColor))) @@ -1072,22 +1066,16 @@ // 随机颜色应用到选中节点:生成统一随机RGB色并应用,返回应用的颜色(失败返回null) applyRandomColorToSelectedNodes() { try { - const app = this.getComfyUIAppInstance(); - if (!this.validateAppInstance(app)) return null; - const selectedNodes = this.getSelectedNodes(), selectedGroups = this.getSelectedGroups(app); - if (selectedNodes.length + selectedGroups.length === 0) { hLog.warn('--@hColorRandom_tip', "请先选择节点或组!"); return null; } + const app = this.getComfyUIAppInstance(); if (!this.validateAppInstance(app)) return null; const selectedNodes = this.getSelectedNodes(), selectedGroups = this.getSelectedGroups(app); if (selectedNodes.length + selectedGroups.length === 0) { hLog.warn('--@hColorRandom_tip', "请先选择节点或组!"); return null; } - const randomColor = `rgb(${Math.floor(Math.random() * 256)}, ${Math.floor(Math.random() * 256)}, ${Math.floor(Math.random() * 256)})`; - selectedNodes.forEach(node => node.is_system || this.applyColorToSingleNode(node, randomColor)); + const randomColor = `rgb(${Math.floor(Math.random() * 256)}, ${Math.floor(Math.random() * 256)}, ${Math.floor(Math.random() * 256)})`; selectedNodes.forEach(node => node.is_system || this.applyColorToSingleNode(node, randomColor)); selectedGroups.forEach(group => { this.isGroupActuallySelected(group, app.canvas) ? (group.color = this.rgbToHex(randomColor), group.children && group.children.forEach(nodeID => this.applyColorToSingleNode(app.graph.getNodeById(nodeID), randomColor))) : hLog.log('--@hColorRandom_Skip', '跳过未明确选中的群组', group); }); - this.markCanvasDirty(app.graph); - hLog.info('--@hColorRandom', `随机颜色${randomColor} →已应用至 ${selectedNodes.length}节点(${selectedGroups.length}组)`); - return randomColor; + this.markCanvasDirty(app.graph); hLog.info('--@hColorRandom', `随机颜色${randomColor} →已应用至 ${selectedNodes.length}节点(${selectedGroups.length}组)`); return randomColor; } catch (error) { hLog.error('--@hColorErr', "随机颜色应用失败:", error); return null; } } }; @@ -1097,30 +1085,9 @@ const __hNAP_AlignFc = { getSelectedNodes: () => __hMgr_ComfyUINode.getSelectedNodes(), setCanvasDirty: () => { LGraphCanvas.active_canvas && LGraphCanvas.active_canvas.setDirty(true, true); }, - // 通用对齐处理:axis(0=X轴/1=Y轴)、getReference(基准值计算回调)、updateNode(节点更新回调) - handleAlign: (e, axis, getReference, updateNode) => { - const nodes = __hNAP_AlignFc.getSelectedNodes(); - if (nodes.length === 0) return; - const reference = getReference(nodes, e.altKey); - nodes.forEach(node => updateNode(node, reference)); - __hNAP_AlignFc.setCanvasDirty(); - }, - // 通用分布处理:axis(0=X轴/1=Y轴)、handleDistribute(分布逻辑回调) - handleDistribute: (e, axis, handleDistribute) => { - const nodes = __hNAP_AlignFc.getSelectedNodes(); - if (nodes.length <= 1) return; - nodes.sort((a, b) => a.pos[axis] - b.pos[axis]); - handleDistribute(nodes, e.altKey, axis); - __hNAP_AlignFc.setCanvasDirty(); - }, - // 通用等尺寸处理:dim(0=宽度/1=高度)、getTargetSize(目标尺寸计算回调) - handleEqualSize: (e, dim, getTargetSize) => { - const nodes = __hNAP_AlignFc.getSelectedNodes(); - if (nodes.length === 0) return; - const targetSize = getTargetSize(nodes, e.altKey); - nodes.forEach(node => node.size[dim] = targetSize); - __hNAP_AlignFc.setCanvasDirty(); - } + handleAlign: (e, axis, getReference, updateNode) => { const nodes = __hNAP_AlignFc.getSelectedNodes(); if (nodes.length === 0) return; const reference = getReference(nodes, e.altKey); nodes.forEach(node => updateNode(node, reference)); __hNAP_AlignFc.setCanvasDirty(); }, // 通用对齐处理:axis(0=X轴/1=Y轴)、getReference(基准值计算回调)、updateNode(节点更新回调) + handleDistribute: (e, axis, handleDistribute) => { const nodes = __hNAP_AlignFc.getSelectedNodes(); if (nodes.length <= 1) return; nodes.sort((a, b) => a.pos[axis] - b.pos[axis]); handleDistribute(nodes, e.altKey, axis); __hNAP_AlignFc.setCanvasDirty(); }, // 通用分布处理:axis(0=X轴/1=Y轴)、handleDistribute(分布逻辑回调) + handleEqualSize: (e, dim, getTargetSize) => { const nodes = __hNAP_AlignFc.getSelectedNodes(); if (nodes.length === 0) return; const targetSize = getTargetSize(nodes, e.altKey); nodes.forEach(node => node.size[dim] = targetSize); __hNAP_AlignFc.setCanvasDirty(); } // 通用等尺寸处理:dim(0=宽度/1=高度)、getTargetSize(目标尺寸计算回调) }; // 【== 节点对齐工具 ==】 @@ -1150,10 +1117,8 @@ isAlt ? (() => { for (let i = 1; i < nodes.length; i++) { current += nodes[i - 1].size[axis] + 20; nodes[i].pos[axis] = current; } })() : (() => { - const min = Math.min(...nodes.map(n => n.pos[axis])), max = Math.max(...nodes.map(n => n.pos[axis] + n.size[axis])); - const total = nodes.reduce((sum, n) => sum + n.size[axis], 0), spacing = (max - min - total) / (nodes.length - 1); - current = min; - nodes.forEach(n => { n.pos[axis] = current; current += n.size[axis] + spacing; }); + const min = Math.min(...nodes.map(n => n.pos[axis])), max = Math.max(...nodes.map(n => n.pos[axis] + n.size[axis])), total = nodes.reduce((sum, n) => sum + n.size[axis], 0), spacing = (max - min - total) / (nodes.length - 1); + current = min; nodes.forEach(n => { n.pos[axis] = current; current += n.size[axis] + spacing; }); })(); }); }, @@ -1163,10 +1128,8 @@ isAlt ? (() => { for (let i = 1; i < nodes.length; i++) { current += nodes[i - 1].size[axis] + 32 + 20; nodes[i].pos[axis] = current; } })() : (() => { - const min = Math.min(...nodes.map(n => n.pos[axis])), max = Math.max(...nodes.map(n => n.pos[axis] + n.size[axis])); - const total = nodes.reduce((sum, n) => sum + n.size[axis], 0), spacing = (max - min - total) / (nodes.length - 1); - current = min; - nodes.forEach(n => { n.pos[axis] = current; current += n.size[axis] + spacing; }); + const min = Math.min(...nodes.map(n => n.pos[axis])), max = Math.max(...nodes.map(n => n.pos[axis] + n.size[axis])), total = nodes.reduce((sum, n) => sum + n.size[axis], 0), spacing = (max - min - total) / (nodes.length - 1); + current = min; nodes.forEach(n => { n.pos[axis] = current; current += n.size[axis] + spacing; }); })(); }); }, @@ -1183,127 +1146,40 @@ // 开始屏幕取色 async startScreenColorPick() { - if (this.isPicking) return; - if (!window.EyeDropper) { - hLog.error('--@hScreenPick', '浏览器不支持屏幕取色功能,请使用最新版Chrome/Edge浏览器'); - return; - } + if (this.isPicking) return; if (!window.EyeDropper) return hLog.error('--@hScreenPick', '浏览器不支持屏幕取色功能,请使用最新版Chrome/Edge浏览器'); try { - this.isPicking = true; - hLog.info('--@hScreenPick', '开始屏幕取色...(点击屏幕任意位置取色)'); - this.zoomBtn.classList.add('disabled-state'); - this.zoomBtn.setAttribute('aria-label', '取色中...'); + this.isPicking = true; hLog.info('--@hScreenPick', '开始屏幕取色...(点击屏幕任意位置取色)'); this.zoomBtn.classList.add('disabled-state'), this.zoomBtn.setAttribute('aria-label', '取色中...'); + const eyeDropper = new EyeDropper(), result = await eyeDropper.open(), hexColor = result.sRGBHex, rgbColor = this.hexToRgb(hexColor); this.currentPickedColor = { hex: hexColor, rgb: rgbColor, rgbString: `rgb(${rgbColor.r}, ${rgbColor.g}, ${rgbColor.b})` }; - const eyeDropper = new EyeDropper(); - const result = await eyeDropper.open(); - const hexColor = result.sRGBHex; - const rgbColor = this.hexToRgb(hexColor); + // 1.更新按钮背景色 2.更新取色器按钮 3.应用到选中节点 4.更新取色器组件 5.触发回调 + this.updateZoomButtonColor(this.currentPickedColor.rgbString); const pickBtn = document.getElementById('hPick'); if (pickBtn) __hUpdater_UI.updatePickBtnColor(this.currentPickedColor.rgbString); + const selectedNodes = __hMgr_ComfyUINode.getSelectedNodes(), app = __hMgr_ComfyUINode.getComfyUIAppInstance(), selectedGroups = __hMgr_ComfyUINode.getSelectedGroups(app); + if (selectedNodes.length + selectedGroups.length > 0) __hMgr_ComfyUINode.__hFc_Color2Nodes(this.currentPickedColor.rgbString), hLog.info('--@hScreenPick', `屏幕取色结果已应用到 ${selectedNodes.length}个节点`); - this.currentPickedColor = { - hex: hexColor, - rgb: rgbColor, - rgbString: `rgb(${rgbColor.r}, ${rgbColor.g}, ${rgbColor.b})` - }; - - // 1. 更新屏幕取色按钮背景色(使用统一更新逻辑) - this.updateZoomButtonColor(this.currentPickedColor.rgbString); - - // 2. 更新取色器按钮(hPick)背景色 - const pickBtn = document.getElementById('hPick'); - if (pickBtn) { - __hUpdater_UI.updatePickBtnColor(this.currentPickedColor.rgbString); - } - - // 3. 如果有选中的节点,应用颜色到选中节点 - const selectedNodes = __hMgr_ComfyUINode.getSelectedNodes(); - const app = __hMgr_ComfyUINode.getComfyUIAppInstance(); - const selectedGroups = __hMgr_ComfyUINode.getSelectedGroups(app); - - if (selectedNodes.length + selectedGroups.length > 0) { - // 应用颜色到选中节点 - __hMgr_ComfyUINode.__hFc_Color2Nodes(this.currentPickedColor.rgbString); - hLog.info('--@hScreenPick', `屏幕取色结果已应用到 ${selectedNodes.length}个节点`); - } - - // 4. 更新取色器组件颜色(如果取色器已打开) if (window.colorPicker) { - // 转换颜色格式:RGB -> HSB - const { r, g, b } = rgbColor; - const hsb = this.rgbToHsb(r, g, b); - - window.colorPicker.currentColor.h = hsb.h; - window.colorPicker.currentColor.s = hsb.s; - window.colorPicker.currentColor.b = hsb.b; - - // 更新取色器UI - window.colorPicker.updateAllUI(); - + const { r, g, b } = rgbColor, hsb = this.rgbToHsb(r, g, b); window.colorPicker.currentColor.h = hsb.h, window.colorPicker.currentColor.s = hsb.s, window.colorPicker.currentColor.b = hsb.b; window.colorPicker.updateAllUI(); hLog.info('--@hScreenPick', `取色器组件已更新: H:${hsb.h} S:${hsb.s} B:${hsb.b}`); } - - // 5. 触发回调 - this.onColorPicked && typeof this.onColorPicked === 'function' - ? this.onColorPicked(this.currentPickedColor) - : null; - - hLog.info('--@hScreenPick', `成功取色: ${hexColor} (RGB: ${rgbColor.r},${rgbColor.g},${rgbColor.b})`); - - } catch (error) { - error.toString().includes('AbortError') - ? hLog.info('--@hScreenPick', '取色已取消') - : hLog.error('--@hScreenPick', '取色失败:', error); - } finally { - this.isPicking = false; - this.zoomBtn?.classList.remove('disabled-state'); - this.zoomBtn?.setAttribute('aria-label', '屏幕取色'); + this.onColorPicked && typeof this.onColorPicked === 'function' ? this.onColorPicked(this.currentPickedColor) : null; hLog.info('--@hScreenPick', `成功取色: ${hexColor} (RGB: ${rgbColor.r},${rgbColor.g},${rgbColor.b})`); + } catch (error) { error.toString().includes('AbortError') ? hLog.info('--@hScreenPick', '取色已取消') : hLog.error('--@hScreenPick', '取色失败:', error); + } finally { this.isPicking = false; this.zoomBtn?.classList.remove('disabled-state'), this.zoomBtn?.setAttribute('aria-label', '屏幕取色'); } } // 2. 新增 RGB 转 HSB 方法 rgbToHsb(r, g, b) { - r /= 255; - g /= 255; - b /= 255; - - const max = Math.max(r, g, b); - const min = Math.min(r, g, b); - const delta = max - min; - - let h = 0; - let s = max === 0 ? 0 : delta / max; - let v = max; - - if (max === min) { - h = 0; - } else if (max === r) { - h = (g - b) / delta + (g < b ? 6 : 0); - } else if (max === g) { - h = (b - r) / delta + 2; - } else if (max === b) { - h = (r - g) / delta + 4; - } - - h = Math.round(h * 60); - s = Math.round(s * 100); - v = Math.round(v * 100); - - return { h, s, b: v }; + r /= 255, g /= 255, b /= 255; const max = Math.max(r, g, b), min = Math.min(r, g, b), delta = max - min; + let h = 0, s = max === 0 ? 0 : delta / max, v = max; h = max === min ? 0 : max === r ? (g - b) / delta + (g < b ? 6 : 0) : max === g ? (b - r) / delta + 2 : (r - g) / delta + 4; + h = Math.round(h * 60), s = Math.round(s * 100), v = Math.round(v * 100); return { h, s, b: v }; } - // 3. 修改 updateZoomButtonColor 方法,使用统一更新逻辑 - updateZoomButtonColor(color) { - if (!this.zoomBtn) return; - - // 使用统一的按钮更新逻辑 - __hUpdater_UI.updateButtonSvgColor(this.zoomBtn, color); - } //【【【【】】】】 + updateZoomButtonColor(color) { if (!this.zoomBtn) return; __hUpdater_UI.updateButtonSvgColor(this.zoomBtn, color); } // 3. 使用统一更新逻辑 // 更新zoom按钮颜色(复用已有逻辑) updateZoomButtonColor(color) { - if (!this.zoomBtn) return; - this.zoomBtn.style.backgroundColor = color; // 设置按钮背景色 - const brightness = this.calculateBrightness(color), isLight = brightness > 128, svgColor = getComputedStyle(document.documentElement).getPropertyValue(isLight ? '--hC_hBtn_svg_B' : '--hC_hBtn_svg_W').trim(); // 根据背景色亮度调整SVG颜色(复用已有逻辑) + if (!this.zoomBtn) return; this.zoomBtn.style.backgroundColor = color; + const brightness = this.calculateBrightness(color), isLight = brightness > 128, svgColor = getComputedStyle(document.documentElement).getPropertyValue(isLight ? '--hC_hBtn_svg_B' : '--hC_hBtn_svg_W').trim(); this.zoomBtn.style.color = svgColor; const iconElement = this.zoomBtn.querySelector('.hIcon'); if (iconElement) { iconElement.querySelectorAll('svg').forEach(svg => { svg.style.color = svgColor; svg.querySelectorAll('.hBtn_svg').forEach(innerSvg => { innerSvg.style.color = svgColor; innerSvg.style.fill = svgColor; }); }); @@ -1339,50 +1215,18 @@ this.colorButtons = __hColorCfg.buttonIds.map(id => document.getElementById(id)); this.funcButtons = { clear: document.getElementById('hClear'), pick: document.getElementById('hPick'), random: document.getElementById('hRandom'), add: document.getElementById('hColorD_Add'), love: document.getElementById('hColorE_Love') }; this.hiddenColorPicker = document.getElementById('hiddenColorPicker'), this.colorBar = document.getElementById('h1__hApBar1_Color'), this.nodeAlignKit = document.getElementById('hNodeAlignKit'), this.colorPickerPanel = document.getElementById('Artstich_hColorPicker'); + this.customColors = Array(7).fill(null); this.lockedColors = Array(7).fill(false); this.activeKeys = new Set(); this.currentMode = 'default'; this.modeSwitchThrottle = { lastSwitchTime: 0, throttleMs: 50, pendingMode: null, timeoutId: null }; this.savedState = null; this.colorPickerOutsideClickHandler = null; + this.screenColorPicker = null; // 屏幕取色器实例 - this.customColors = Array(7).fill(null); this.lockedColors = Array(7).fill(false); - this.activeKeys = new Set(); this.currentMode = 'default'; - this.modeSwitchThrottle = { lastSwitchTime: 0, throttleMs: 50, pendingMode: null, timeoutId: null }; - this.savedState = null; this.colorPickerOutsideClickHandler = null; - this.screenColorPicker = null; // 新增:屏幕取色器实例 - - // 添加模式映射表 - this.modeNames = { - 'default': '默认', - 'shift': '灰度色', - 'alt': '自定义色', - 'ctrl': 'Ctrl', - 'ctrl_alt': '颜色锁定/解锁', - 'ctrl_shift': 'Ctrl Shift', - 'alt_shift': 'Alt Shift' - }; - - // 添加按键名映射表 - this.keyNames = { - 'default': '默认', - 'shift': 'Shift', - 'alt': '【双击色卡】可自定义颜色,按【Ctrl Alt】可自行锁定/解锁需要的颜色', - 'ctrl': '开发中...', - 'ctrl_alt': '【鼠标点击任一色卡】则可锁定/解锁颜色 松开【Ctrl】可退出锁定/解锁模式', - 'ctrl_shift': '开发中...', - 'alt_shift': '开发中...' - }; - + this.modeNames = { 'default': '默认', 'shift': '灰度色', 'alt': '自定义色', 'ctrl': 'Ctrl', 'ctrl_alt': '颜色锁定/解锁', 'ctrl_shift': 'Ctrl Shift', 'alt_shift': 'Alt Shift' }; // 模式映射表 + this.keyNames = { 'default': '默认', 'shift': 'Shift', 'alt': '【双击色卡】可自定义颜色,按【Ctrl Alt】可自行锁定/解锁需要的颜色', 'ctrl': '开发中...', 'ctrl_alt': '【鼠标点击任一色卡】则可锁定/解锁颜色 松开【Ctrl】可退出锁定/解锁模式', 'ctrl_shift': '开发中...', 'alt_shift': '开发中...' }; // 按键名映射表 this.init(); } - // 【新增】取色器统一重置方法 - resetColorPicker() { - const defaultColor = { h: 240, s: 57, b: 49 }; // 默认颜色值 (h:240, s:57, b:49 对应 rgb(55, 55, 125)) - // 方法1: 直接设置取色器颜色并触发更新 - if (window.colorPicker) { window.colorPicker.currentColor = defaultColor; typeof window.colorPicker.updateAllUI === 'function' && window.colorPicker.updateAllUI(); } - } - + // 【新增】取色器统一重置方法:默认颜色值 (h:240, s:57, b:49 对应 rgb(55, 55, 125)) + resetColorPicker() { const defaultColor = { h: 240, s: 57, b: 49 }; if (window.colorPicker) { window.colorPicker.currentColor = defaultColor; typeof window.colorPicker.updateAllUI === 'function' && window.colorPicker.updateAllUI(); } } reset() { this.customColors = Array(7).fill(null); this.lockedColors = Array(7).fill(false); this.activeKeys.clear(); this.currentMode = 'default'; this.clearThrottleTimer(); this.resetColorPicker(); this.screenColorPicker?.clearPickedColor(); this.updateUI(); hLog.error('--->颜色模块已重置<---'); } - // 初始化 - init() { this.updateUI(); this.bindEvents(); this.initScreenColorPicker(); } - - // 更新UI - updateUI() { this.renderColorButtons(); this.updateButtonStates(); __hUpdater_UI.updatePickBtnColor(this.funcButtons.pick?.style.backgroundColor); } + init() { this.updateUI(); this.bindEvents(); this.initScreenColorPicker(); } // 初始化 + updateUI() { this.renderColorButtons(); this.updateButtonStates(); __hUpdater_UI.updatePickBtnColor(this.funcButtons.pick?.style.backgroundColor); } // 更新UI // 更新按钮禁用状态 updateButtonStates() { @@ -1394,9 +1238,7 @@ // 渲染颜色按钮 renderColorButtons() { this.colorButtons.forEach((btn, index) => { - if (!btn) return; - btn.style.backgroundColor = ''; btn.style.color = ''; - let content = '', colorValue = '', showCustomColorBtn = false; + if (!btn) return; btn.style.backgroundColor = ''; btn.style.color = ''; let content = '', colorValue = '', showCustomColorBtn = false; // 根据当前模式显示 switch (this.currentMode) { case 'default': colorValue = __hColorCfg.defaultColors[index]; content = __hSvgFc_ColorSVG.colorCircle(colorValue); break; @@ -1415,147 +1257,75 @@ case 'alt_shift': colorValue = __hColorCfg.defaultColors[index]; content = __hSvgFc_ColorSVG.colorCircle(colorValue); break; default: colorValue = __hColorCfg.defaultColors[index]; content = __hSvgFc_ColorSVG.colorCircle(colorValue); } - showCustomColorBtn ? btn.classList.add('custom-color-btn') : btn.classList.remove('custom-color-btn'); - btn.innerHTML = content; btn.dataset.colorValue = colorValue; + showCustomColorBtn ? btn.classList.add('custom-color-btn') : btn.classList.remove('custom-color-btn'); btn.innerHTML = content; btn.dataset.colorValue = colorValue; }); } - // 绑定事件 - 移除鼠标范围检测 + // 绑定事件 bindEvents() { - // 绑定全局键盘事件 - document.addEventListener('keydown', e => this.handleKeyDown(e), { passive: false }); document.addEventListener('keyup', e => this.handleKeyUp(e)); - - // 窗口失焦/聚焦处理 - window.addEventListener('blur', () => this.handleWindowBlur()); window.addEventListener('focus', () => this.handleWindowFocus()); - + document.addEventListener('keydown', e => this.handleKeyDown(e), { passive: false }); document.addEventListener('keyup', e => this.handleKeyUp(e)); // 绑定全局键盘事件 + window.addEventListener('blur', () => this.handleWindowBlur()); window.addEventListener('focus', () => this.handleWindowFocus()); // 窗口失焦/聚焦处理 // 颜色按钮事件绑定 this.colorButtons.forEach((btn, index) => { if (!btn) return; - btn.addEventListener('click', () => this.handleColorButtonClick(index)); - btn.addEventListener('mousedown', e => this.handleColorBtnMouseDown(e, index)); - btn.addEventListener('dblclick', e => this.handleColorBtnDblClick(e, index)); - btn.addEventListener('dragstart', e => e.preventDefault()); - btn.addEventListener('selectstart', e => e.preventDefault()); + btn.addEventListener('click', () => this.handleColorButtonClick(index)); btn.addEventListener('mousedown', e => this.handleColorBtnMouseDown(e, index)); btn.addEventListener('dblclick', e => this.handleColorBtnDblClick(e, index)); btn.addEventListener('dragstart', e => e.preventDefault()); btn.addEventListener('selectstart', e => e.preventDefault()); }); - - // 功能按钮事件绑定 - Object.values(this.funcButtons).forEach(btn => btn && (btn.addEventListener('dragstart', e => e.preventDefault()), btn.addEventListener('selectstart', e => e.preventDefault()))); - - // 功能按钮点击事件 - this.funcButtons.pick?.addEventListener('click', e => this.handlePickBtnClick(e)); - this.funcButtons.random?.addEventListener('click', () => this.handleRandomBtnClick()); - this.funcButtons.clear?.addEventListener('click', () => this.handleClearBtnClick()); - + + Object.values(this.funcButtons).forEach(btn => btn && (btn.addEventListener('dragstart', e => e.preventDefault()), btn.addEventListener('selectstart', e => e.preventDefault()))); // 绑定功能按钮事件 + this.funcButtons.pick?.addEventListener('click', e => this.handlePickBtnClick(e)); this.funcButtons.random?.addEventListener('click', () => this.handleRandomBtnClick()); this.funcButtons.clear?.addEventListener('click', () => this.handleClearBtnClick()); // 功能按钮点击事件 // 其他事件 - this.hiddenColorPicker?.addEventListener('input', e => this.handleColorPickerChange(e)); - this.colorBar?.addEventListener('dragstart', e => e.preventDefault()); - this.colorBar?.addEventListener('selectstart', e => e.preventDefault()); - this.nodeAlignKit?.addEventListener('dragstart', e => e.preventDefault()); - this.nodeAlignKit?.addEventListener('selectstart', e => e.preventDefault()); + this.hiddenColorPicker?.addEventListener('input', e => this.handleColorPickerChange(e)); this.colorBar?.addEventListener('dragstart', e => e.preventDefault()); this.colorBar?.addEventListener('selectstart', e => e.preventDefault()); this.nodeAlignKit?.addEventListener('dragstart', e => e.preventDefault()); this.nodeAlignKit?.addEventListener('selectstart', e => e.preventDefault()); } - // 处理窗口失焦 - 重置状态 - handleWindowBlur() { this.savedState = { currentMode: this.currentMode }; this.activeKeys.clear(); this.currentMode = 'default'; this.clearThrottleTimer(); this.updateUI(); } - - // 处理窗口聚焦 - handleWindowFocus() { this.savedState && (this.currentMode = this.savedState.currentMode, this.savedState = null, this.updateUI()); } - - // 处理按键按下 - handleKeyDown(e) { const key = e.key.toLowerCase(); if (!['shift', 'alt', 'control', 'meta'].includes(key)) return; key === 'alt' && e.preventDefault(); this.activeKeys.add(key); this.switchModeSafely(this.determineMode()); } - - // 处理按键松开 - handleKeyUp(e) { const key = e.key.toLowerCase(); if (!['shift', 'alt', 'control', 'meta'].includes(key)) return; this.activeKeys.delete(key); this.switchModeSafely(this.determineMode()); } + handleWindowBlur() { this.savedState = { currentMode: this.currentMode }; this.activeKeys.clear(); this.currentMode = 'default'; this.clearThrottleTimer(); this.updateUI(); } // 窗口失焦 - 重置状态 + handleWindowFocus() { this.savedState && (this.currentMode = this.savedState.currentMode, this.savedState = null, this.updateUI()); } // 窗口聚焦 + handleKeyDown(e) { const key = e.key.toLowerCase(); if (!['shift', 'alt', 'control', 'meta'].includes(key)) return; key === 'alt' && e.preventDefault(); this.activeKeys.add(key); this.switchModeSafely(this.determineMode()); } // 按键按下 + handleKeyUp(e) { const key = e.key.toLowerCase(); if (!['shift', 'alt', 'control', 'meta'].includes(key)) return; this.activeKeys.delete(key); this.switchModeSafely(this.determineMode()); } // 按键松开 // 模式判定逻辑 - determineMode() { - const keys = Array.from(this.activeKeys); - return keys.includes('alt') && keys.includes('control') ? 'ctrl_alt' : - keys.includes('shift') && keys.includes('control') ? 'ctrl_shift' : - keys.includes('alt') && keys.includes('shift') ? 'alt_shift' : - keys.includes('alt') ? 'alt' : - keys.includes('shift') ? 'shift' : - keys.includes('control') ? 'ctrl' : 'default'; - } + determineMode() { const keys = Array.from(this.activeKeys); return keys.includes('alt') && keys.includes('control') ? 'ctrl_alt' : keys.includes('shift') && keys.includes('control') ? 'ctrl_shift' : keys.includes('alt') && keys.includes('shift') ? 'alt_shift' : keys.includes('alt') ? 'alt' : keys.includes('shift') ? 'shift' : keys.includes('control') ? 'ctrl' : 'default'; } // 安全切换模式(带节流) switchModeSafely(newMode) { const now = Date.now(), timeSinceLastSwitch = now - this.modeSwitchThrottle.lastSwitchTime; if (timeSinceLastSwitch < this.modeSwitchThrottle.throttleMs) { this.modeSwitchThrottle.pendingMode = newMode; this.clearThrottleTimer(); - this.modeSwitchThrottle.timeoutId = setTimeout(() => { - if (this.modeSwitchThrottle.pendingMode === newMode) { this.applyModeSwitch(newMode); this.modeSwitchThrottle.lastSwitchTime = Date.now(); this.modeSwitchThrottle.pendingMode = null; } - }, this.modeSwitchThrottle.throttleMs - timeSinceLastSwitch); return; + this.modeSwitchThrottle.timeoutId = setTimeout(() => { if (this.modeSwitchThrottle.pendingMode === newMode) { this.applyModeSwitch(newMode); this.modeSwitchThrottle.lastSwitchTime = Date.now(); this.modeSwitchThrottle.pendingMode = null; } }, this.modeSwitchThrottle.throttleMs - timeSinceLastSwitch); return; } this.applyModeSwitch(newMode); this.modeSwitchThrottle.lastSwitchTime = now; } applyModeSwitch(newMode) { if (newMode !== this.currentMode) { - // 退出当前模式的日志 - if (this.currentMode !== 'default') { - const prevKeyName = this.keyNames[this.currentMode] || this.currentMode; - const prevModeName = this.modeNames[this.currentMode]; - } - - // 进入新模式的日志 - if (newMode === 'default') { - hLog.debug('--@hColorMode', '已恢复【默认】模式'); - } else { - const keyName = this.keyNames[newMode] || newMode; - const modeName = this.modeNames[newMode]; - - if (modeName) { - hLog.debug('--@hColorMode', `已进入【${modeName}】模式(${keyName})`); - } else { - hLog.debug('--@hColorMode', `(${keyName})开发中...`); - } - } - - this.currentMode = newMode; - this.updateUI(); + const keyName = this.keyNames[newMode] || newMode, modeName = this.modeNames[newMode], logMsg = newMode === 'default' ? '已恢复【默认】模式' : modeName ? `已进入【${modeName}】模式(${keyName})` : `(${keyName})开发中...`; + hLog.debug('--@hColorMode', logMsg), this.currentMode = newMode, this.updateUI(); } } - // 清除节流定时器 - clearThrottleTimer() { this.modeSwitchThrottle.timeoutId && (clearTimeout(this.modeSwitchThrottle.timeoutId), this.modeSwitchThrottle.timeoutId = null); } + + clearThrottleTimer() { this.modeSwitchThrottle.timeoutId && (clearTimeout(this.modeSwitchThrottle.timeoutId), this.modeSwitchThrottle.timeoutId = null); } // 清除节流定时器 // 颜色按钮点击事件 handleColorButtonClick(index) { if (['ctrl_alt', 'ctrl_shift', 'alt_shift'].includes(this.currentMode)) return; let colorValue; switch (this.currentMode) { - case 'default': - const colorMap = { 0: 'hColor1_Red', 1: 'hColor2_Orange', 2: 'hColor3_Yellow', 3: 'hColor4_Green', 4: 'hColor5_Cyan', 5: 'hColor6_Blue', 6: 'hColor7_Purple' }; - __hMgr_ComfyUINode.setNodesColor(colorMap[index]); colorValue = __hColorCfg.defaultColors[index]; break; - case 'shift': - colorValue = __hColorCfg.grayScaleColors[index]; __hMgr_ComfyUINode.__hFc_Color2Nodes(colorValue); break; - case 'alt': - colorValue = this.customColors[index]; - colorValue ? __hMgr_ComfyUINode.__hFc_Color2Nodes(colorValue) : (this.toggleColorPicker(null), this.doubleClickedIndex = index); break; + case 'default': const colorMap = { 0: 'hColor1_Red', 1: 'hColor2_Orange', 2: 'hColor3_Yellow', 3: 'hColor4_Green', 4: 'hColor5_Cyan', 5: 'hColor6_Blue', 6: 'hColor7_Purple' }; __hMgr_ComfyUINode.setNodesColor(colorMap[index]), colorValue = __hColorCfg.defaultColors[index]; break; + case 'shift': colorValue = __hColorCfg.grayScaleColors[index], __hMgr_ComfyUINode.__hFc_Color2Nodes(colorValue); break; + case 'alt': colorValue = this.customColors[index], colorValue ? __hMgr_ComfyUINode.__hFc_Color2Nodes(colorValue) : (this.toggleColorPicker(null), this.doubleClickedIndex = index); break; default: return; } } - // 颜色按钮鼠标按下事件 - handleColorBtnMouseDown(e, index) { - if (this.currentMode !== 'ctrl_alt') return; - e.preventDefault(); - this.customColors[index] === null ? this.customColors[index] = this.getRandomColor() : this.lockedColors[index] = !this.lockedColors[index]; - this.renderColorButtons(); - } - - // 颜色按钮双击事件 - handleColorBtnDblClick(e, index) { e.preventDefault(); (this.currentMode === 'alt' && !this.lockedColors[index]) && (this.toggleColorPicker(e), this.doubleClickedIndex = index); } - // 取色按钮点击事件 - handlePickBtnClick(e) { !this.funcButtons.pick.classList.contains('disabled-state') && this.toggleColorPicker(e); } + handleColorBtnMouseDown(e, index) { if (this.currentMode !== 'ctrl_alt') return; e.preventDefault(), this.customColors[index] === null ? this.customColors[index] = this.getRandomColor() : this.lockedColors[index] = !this.lockedColors[index], this.renderColorButtons(); } // 颜色按钮鼠标按下事件 + handleColorBtnDblClick(e, index) { e.preventDefault(); (this.currentMode === 'alt' && !this.lockedColors[index]) && (this.toggleColorPicker(e), this.doubleClickedIndex = index); } // 颜色按钮双击事件 + handlePickBtnClick(e) { !this.funcButtons.pick.classList.contains('disabled-state') && this.toggleColorPicker(e); } // 取色按钮点击事件 handleClearBtnClick() { if (this.funcButtons.clear.classList.contains('disabled-state')) return; - this.funcButtons.random && (this.funcButtons.random.style.backgroundColor = '', __hUpdater_UI.restoreDefaultSvgColor(this.funcButtons.random)); - this.resetColorPicker(); + this.funcButtons.random && (this.funcButtons.random.style.backgroundColor = '', __hUpdater_UI.restoreDefaultSvgColor(this.funcButtons.random)); this.resetColorPicker(); switch (this.currentMode) { case 'default': __hMgr_ComfyUINode.resetNodesColor(); hLog.warn('--@hClearBtn', '已清除节点颜色(仅对选择的节点时生效)'); break; - case 'alt': // Alt模式:清除未锁定的自定义颜色 + 清除节点颜色 - for (let i = 0; i < 7; i++) !this.lockedColors[i] && (this.customColors[i] = null); this.renderColorButtons(); __hMgr_ComfyUINode.resetNodesColor(); hLog.warn('--@hClearBtn', '已清除自定义颜色(Alt)(不含锁定色)'); break; + case 'alt': for (let i = 0; i < 7; i++) !this.lockedColors[i] && (this.customColors[i] = null); this.renderColorButtons(); __hMgr_ComfyUINode.resetNodesColor(); hLog.warn('--@hClearBtn', '已清除自定义颜色(Alt)(不含锁定色)'); break; default: __hMgr_ComfyUINode.resetNodesColor(); } } @@ -1564,31 +1334,21 @@ handleRandomBtnClick() { if (this.funcButtons.random.classList.contains('disabled-state')) return; if (this.currentMode === 'default') { - const randomColor = __hMgr_ComfyUINode.applyRandomColorToSelectedNodes(); - randomColor && (this.funcButtons.random.style.backgroundColor = randomColor, __hUpdater_UI.updateButtonSvgColor(this.funcButtons.random, randomColor)); - return; + const randomColor = __hMgr_ComfyUINode.applyRandomColorToSelectedNodes(); randomColor && (this.funcButtons.random.style.backgroundColor = randomColor, __hUpdater_UI.updateButtonSvgColor(this.funcButtons.random, randomColor)); return; } if (this.currentMode === 'alt') { - for (let i = 0; i < 7; i++) this.customColors[i] = !this.lockedColors[i] ? this.getRandomColor() : this.customColors[i]; - this.renderColorButtons(); const availableColors = this.customColors.filter(color => !!color); + for (let i = 0; i < 7; i++) this.customColors[i] = !this.lockedColors[i] ? this.getRandomColor() : this.customColors[i]; this.renderColorButtons(); const availableColors = this.customColors.filter(color => !!color); const targetColor = availableColors.length > 0 ? availableColors[Math.floor(Math.random() * availableColors.length)] : this.getRandomColor(); - this.funcButtons.random.style.backgroundColor = targetColor; __hUpdater_UI.updateButtonSvgColor(this.funcButtons.random, targetColor); - const app = __hMgr_ComfyUINode.getComfyUIAppInstance(); - if (!app || !app.graph) return; - const selectedNodes = __hMgr_ComfyUINode.getSelectedNodes().filter(node => !node.is_system); - const selectedGroups = __hMgr_ComfyUINode.getSelectedGroups(app); - if (selectedNodes.length === 0 && selectedGroups.length === 0) return; - if (availableColors.length === 0) { hLog.warn('没有可用颜色'); return; } - const colorTargets = [...selectedNodes.map(node => ({ type: 'node', target: node })), ...selectedGroups.map(group => ({ type: 'group', target: group }))]; - if (!colorTargets.length) return; - const assignedColors = this.assignColorsWithMinDuplication(colorTargets, availableColors); + this.funcButtons.random.style.backgroundColor = targetColor; __hUpdater_UI.updateButtonSvgColor(this.funcButtons.random, targetColor); const app = __hMgr_ComfyUINode.getComfyUIAppInstance(); + if (!app || !app.graph) return; const selectedNodes = __hMgr_ComfyUINode.getSelectedNodes().filter(node => !node.is_system), selectedGroups = __hMgr_ComfyUINode.getSelectedGroups(app); if (selectedNodes.length === 0 && selectedGroups.length === 0) return; + if (availableColors.length === 0) { hLog.warn('没有可用颜色'); return; } const colorTargets = [...selectedNodes.map(node => ({ type: 'node', target: node })), ...selectedGroups.map(group => ({ type: 'group', target: group }))]; + if (!colorTargets.length) return; const assignedColors = this.assignColorsWithMinDuplication(colorTargets, availableColors); colorTargets.forEach((target, index) => { const color = assignedColors[index]; if (!color) return; if (target.type === 'node') { __hMgr_ComfyUINode.applyColorToSingleNode(target.target, color); } else { const group = target.target; group.color = __hMgr_ComfyUINode.rgbToHex(color); group.children && group.children.forEach(nodeID => { const node = app.graph.getNodeById(nodeID); node && __hMgr_ComfyUINode.applyColorToSingleNode(node, color); }); } }); - app.graph.setDirtyCanvas(true, true); app.graph.afterChange && app.graph.afterChange(); - return; + app.graph.setDirtyCanvas(true, true); app.graph.afterChange && app.graph.afterChange(); return; } const color = this.getRandomColor(); this.funcButtons.random.style.backgroundColor = color; __hUpdater_UI.updateButtonSvgColor(this.funcButtons.random, color); } @@ -1609,107 +1369,51 @@ // 取色器相关方法 toggleColorPicker(e) { - e?.stopPropagation(); - const colorPickerPanel = this.colorPickerPanel; - if (!colorPickerPanel) return; - const isVisible = colorPickerPanel.style.display !== 'none'; + e?.stopPropagation(); const colorPickerPanel = this.colorPickerPanel; if (!colorPickerPanel) return; const isVisible = colorPickerPanel.style.display !== 'none'; isVisible ? this.hideColorPicker() : (() => { - colorPickerPanel.style.display = 'block'; - this.initColorPickerPosition(); - this.addColorPickerOutsideClickHandler(); + colorPickerPanel.style.display = 'block'; this.initColorPickerPosition(); this.addColorPickerOutsideClickHandler(); // 确保取色器canvas立即初始化 setTimeout(() => { - window.colorPicker && window.colorPicker.updateAllUI ? window.colorPicker.updateAllUI() : void 0; - const canvas = document.getElementById('hCPr__mainPicker_colorCanvas'); + window.colorPicker && window.colorPicker.updateAllUI ? window.colorPicker.updateAllUI() : void 0; const canvas = document.getElementById('hCPr__mainPicker_colorCanvas'); canvas && (canvas.width === 0 || canvas.height === 0) ? (canvas.width = 220, canvas.height = 220, canvas.style.width = '220px', canvas.style.height = '220px') : void 0; }, 10); window.colorPicker && (() => { const { h, s, b } = window.colorPicker.currentColor, { r, g, b: rgbB } = window.colorPicker.hsbToRgb(h, s, b); this.currentPickerColor = `rgb(${r}, ${g}, ${rgbB})`; })(); })(); } - hideColorPicker() { if (this.colorPickerPanel) { this.colorPickerPanel.style.display = 'none'; try { - document.removeEventListener('mousemove', window.colorAreaDragHandler); - document.removeEventListener('mousemove', window.hueDragHandler); - document.removeEventListener('mousemove', window.saturationDragHandler); - document.removeEventListener('mousemove', window.brightnessDragHandler); - document.removeEventListener('mousemove', window.hueControlDragHandler); + document.removeEventListener('mousemove', window.colorAreaDragHandler); document.removeEventListener('mousemove', window.hueDragHandler); document.removeEventListener('mousemove', window.saturationDragHandler); document.removeEventListener('mousemove', window.brightnessDragHandler); document.removeEventListener('mousemove', window.hueControlDragHandler); window.colorPicker?.isDragging && Object.keys(window.colorPicker.isDragging).forEach(key => window.colorPicker.isDragging[key] = false); } catch (e) { hLog.warn('清理取色器事件时出错:', e); } } - this.removeColorPickerOutsideClickHandler(); - (this.doubleClickedIndex !== undefined && this.currentPickerColor) && (this.customColors[this.doubleClickedIndex] = this.currentPickerColor, this.renderColorButtons(), this.doubleClickedIndex = undefined, this.currentPickerColor = null); + this.removeColorPickerOutsideClickHandler(); (this.doubleClickedIndex !== undefined && this.currentPickerColor) && (this.customColors[this.doubleClickedIndex] = this.currentPickerColor, this.renderColorButtons(), this.doubleClickedIndex = undefined, this.currentPickerColor = null); } - addColorPickerOutsideClickHandler() { this.removeColorPickerOutsideClickHandler(); this.colorPickerOutsideClickHandler = (e) => { - const colorPickerPanel = this.colorPickerPanel; - if (!colorPickerPanel || colorPickerPanel.style.display === 'none') return; - let target = e.target, isClickInside = false; - while (target && target !== document) { if (target === colorPickerPanel) { isClickInside = true; break; } target = target.parentNode; } - const isPickButton = e.target === this.funcButtons.pick || (this.funcButtons.pick && this.funcButtons.pick.contains(e.target)); - if (e.type === 'contextmenu') { e.preventDefault(); e.stopPropagation(); this.hideColorPicker(); return; } + const colorPickerPanel = this.colorPickerPanel; if (!colorPickerPanel || colorPickerPanel.style.display === 'none') return; let target = e.target, isClickInside = false; while (target && target !== document) { if (target === colorPickerPanel) { isClickInside = true; break; } target = target.parentNode; } + const isPickButton = e.target === this.funcButtons.pick || (this.funcButtons.pick && this.funcButtons.pick.contains(e.target)); if (e.type === 'contextmenu') { e.preventDefault(); e.stopPropagation(); this.hideColorPicker(); return; } (!isClickInside && !isPickButton) && this.hideColorPicker(); }; - document.addEventListener('mousedown', this.colorPickerOutsideClickHandler, { capture: true }); - document.addEventListener('contextmenu', this.colorPickerOutsideClickHandler, { capture: true }); + document.addEventListener('mousedown', this.colorPickerOutsideClickHandler, { capture: true }); document.addEventListener('contextmenu', this.colorPickerOutsideClickHandler, { capture: true }); if (this.colorPickerPanel) this.colorPickerPanel.addEventListener('contextmenu', (e) => { e.preventDefault(); e.stopPropagation(); this.hideColorPicker(); return false; }, { capture: true }); } - - removeColorPickerOutsideClickHandler() { - this.colorPickerOutsideClickHandler && (document.removeEventListener('mousedown', this.colorPickerOutsideClickHandler, { capture: true }), document.removeEventListener('contextmenu', this.colorPickerOutsideClickHandler, { capture: true }), this.colorPickerOutsideClickHandler = null); - } - + removeColorPickerOutsideClickHandler() { this.colorPickerOutsideClickHandler && (document.removeEventListener('mousedown', this.colorPickerOutsideClickHandler, { capture: true }), document.removeEventListener('contextmenu', this.colorPickerOutsideClickHandler, { capture: true }), this.colorPickerOutsideClickHandler = null); } initColorPickerPosition() { this.colorPickerPanel && this.colorBar && window.__hMgr_PopEl__Position?.positionColorPicker(); } - handleColorPickerChange(e) { - this.state?.colorPickerCallback && (() => { - const rgbColor = `rgb(${[1, 3, 5].map(i => parseInt(e.target.value.slice(i, i + 2), 16)).join(',')})`; - this.state.colorPickerCallback(rgbColor); this.state.colorPickerCallback = null; - __hUpdater_UI.updateButtonSvgColor(this.funcButtons.pick, rgbColor); - })(); - } - - // 【新增:初始化屏幕取色器-延迟初始化,确保DOM已加载 + handleColorPickerChange(e) { this.state?.colorPickerCallback && (() => { const rgbColor = `rgb(${[1, 3, 5].map(i => parseInt(e.target.value.slice(i, i + 2), 16)).join(',')})`; this.state.colorPickerCallback(rgbColor); this.state.colorPickerCallback = null; __hUpdater_UI.updateButtonSvgColor(this.funcButtons.pick, rgbColor); })(); } + // 初始化屏幕取色器-延迟初始化,确保DOM已加载 initScreenColorPicker() { setTimeout(() => { this.screenColorPicker = new __hColorPickFc(); - - // 注册回调:取色完成时传递颜色给取色器组件 this.screenColorPicker.registerColorPickedCallback((colorData) => { hLog.info('--@hScreenPick_Callback', '屏幕取色完成,颜色已更新到取色器组件'); - - // 声明:屏幕取色结果会单向输送到取色器组件 - // 取色器组件的颜色不会输送到屏幕取色 - if (colorData && colorData.hex) { - // 1. 更新取色器按钮(hPick)背景色 - __hUpdater_UI.updatePickBtnColor(colorData.rgbString); - - // 2. 如果有选中的节点,应用颜色(已在屏幕取色器内部处理) - // 这里只做日志记录 - const selectedNodes = __hMgr_ComfyUINode.getSelectedNodes(); - if (selectedNodes.length > 0) { - hLog.info('--@hScreenPick', `颜色已同步到 ${selectedNodes.length} 个选中节点`); - } - - // 3. 更新取色器组件(如果已打开) - // 注意:这是单向更新,取色器组件颜色不会反向影响屏幕取色 - if (window.colorPicker) { - const rgb = this.screenColorPicker.hexToRgb(colorData.hex); - const hsb = this.rgbToHsb(rgb.r, rgb.g, rgb.b); - - window.colorPicker.currentColor.h = hsb.h; - window.colorPicker.currentColor.s = hsb.s; - window.colorPicker.currentColor.b = hsb.b; - - window.colorPicker.updateAllUI(); - hLog.debug('--@hColorPicker', '取色器组件已从屏幕取色更新'); - } + __hUpdater_UI.updatePickBtnColor(colorData.rgbString), (selectedNodes = __hMgr_ComfyUINode.getSelectedNodes()).length > 0 && hLog.info('--@hScreenPick', `颜色已同步到 ${selectedNodes.length} 个选中节点`); + if (window.colorPicker) { const rgb = this.screenColorPicker.hexToRgb(colorData.hex), hsb = this.rgbToHsb(rgb.r, rgb.g, rgb.b); window.colorPicker.currentColor.h = hsb.h, window.colorPicker.currentColor.s = hsb.s, window.colorPicker.currentColor.b = hsb.b, window.colorPicker.updateAllUI(), hLog.debug('--@hColorPicker', '取色器组件已从屏幕取色更新'); } } }); }, 100); @@ -1717,39 +1421,14 @@ // 添加 RGB 转 HSB 辅助方法(如果不存在) rgbToHsb(r, g, b) { - // 复用屏幕取色器中的方法或独立实现 - r /= 255; - g /= 255; - b /= 255; - - const max = Math.max(r, g, b); - const min = Math.min(r, g, b); - const delta = max - min; - - let h = 0; - let s = max === 0 ? 0 : delta / max; - let v = max; - - if (max === min) { - h = 0; - } else if (max === r) { - h = (g - b) / delta + (g < b ? 6 : 0); - } else if (max === g) { - h = (b - r) / delta + 2; - } else if (max === b) { - h = (r - g) / delta + 4; - } - - h = Math.round(h * 60); - s = Math.round(s * 100); - v = Math.round(v * 100); - + r /= 255, g /= 255, b /= 255; const max = Math.max(r, g, b), min = Math.min(r, g, b), delta = max - min; + let h = max === min ? 0 : max === r ? (g - b) / delta + (g < b ? 6 : 0) : max === g ? (b - r) / delta + 2 : (r - g) / delta + 4, s = max === 0 ? 0 : delta / max, v = max; + h = Math.round(h * 60), s = Math.round(s * 100), v = Math.round(v * 100); return { h, s, b: v }; } - // 新增:屏幕取色按钮点击事件 + // 屏幕取色按钮点击事件 // handleZoomBtnClick() { !this.funcButtons.zoom?.classList.contains('disabled-state') && (this.screenColorPicker ? this.screenColorPicker.startScreenColorPick() : hLog.error('--@hZoomBtn', '屏幕取色器未初始化')); } - openColorPicker(callback) { this.colorPickerCallback = callback; this.hiddenColorPicker.click(); } - getRandomColor() { const r = Math.floor(Math.random() * 256), g = Math.floor(Math.random() * 256), b = Math.floor(Math.random() * 256); return `rgb(${r}, ${g}, ${b})`; } + openColorPicker(callback) { this.colorPickerCallback = callback; this.hiddenColorPicker.click(); } getRandomColor() { const r = Math.floor(Math.random() * 256), g = Math.floor(Math.random() * 256), b = Math.floor(Math.random() * 256); return `rgb(${r}, ${g}, ${b})`; } } @@ -1899,12 +1578,8 @@ // 通用输入框初始化(复用HSB/RGB重复逻辑) setupCommonInputs(configs, inputHandler, changeHandler) { configs.forEach(config => { - const input = document.getElementById(config.id); - if (!input) return; - this.inputs[config.id] = { ...config, element: input }; - // 绑定通用事件(合并短行,字符数<180) - input.addEventListener('input', e => inputHandler(e, config)); input.addEventListener('change', e => changeHandler(e, config)); - input.addEventListener('keydown', e => this.handleKeydown(e, config)); input.addEventListener('blur', e => this.handleBlur(e, config)); + const input = document.getElementById(config.id); if (!input) return; this.inputs[config.id] = { ...config, element: input }; + input.addEventListener('input', e => inputHandler(e, config)); input.addEventListener('change', e => changeHandler(e, config)); input.addEventListener('keydown', e => this.handleKeydown(e, config)); input.addEventListener('blur', e => this.handleBlur(e, config)); }); } @@ -1932,14 +1607,8 @@ // 通用输入处理 handleInput(e, config) { - const input = e.target; - let value = input.value.trim(); - if (value === '') { input.value = config.min; this.updateColorFromInput(config.id, config.min); return; } - const numValue = parseInt(value, 10); - if (isNaN(numValue)) { input.value = this.getCurrentValue(config.id); return; } - const clampedValue = Math.max(config.min, Math.min(config.max, numValue)); - clampedValue !== numValue && (input.value = clampedValue); - + const input = e.target; let value = input.value.trim(); if (value === '') { input.value = config.min; this.updateColorFromInput(config.id, config.min); return; } + const numValue = parseInt(value, 10); if (isNaN(numValue)) { input.value = this.getCurrentValue(config.id); return; } const clampedValue = Math.max(config.min, Math.min(config.max, numValue)); clampedValue !== numValue && (input.value = clampedValue); this.updateColorFromInput(config.id, clampedValue); } @@ -1948,32 +1617,16 @@ handleRGBChange(e, config) { this.handleInput(e, config); } // 十六进制输入处理 - handleHexInput(e) { - const input = e.target; - let value = input.value.trim().toUpperCase().replace(/^#/, '').replace(/[^0-9A-F]/g, ''); - value.length > 6 && (value = value.substring(0, 6)); - input.value = value; - value.length === 6 && this.updateColorFromHex(value); - } + handleHexInput(e) { const input = e.target; let value = input.value.trim().toUpperCase().replace(/^#/, '').replace(/[^0-9A-F]/g, ''); value.length > 6 && (value = value.substring(0, 6)); input.value = value; value.length === 6 && this.updateColorFromHex(value); } - handleHexChange(e) { - const input = e.target; - let value = input.value.trim().toUpperCase().replace(/^#/, ''); - // 空值/补零/长度限制 - value === '' && (value = '000000'); - while (value.length < 6) value = '0' + value; - value.length > 6 && (value = value.substring(0, 6)); - input.value = value; - this.updateColorFromHex(value); - } + handleHexChange(e) { const input = e.target; let value = input.value.trim().toUpperCase().replace(/^#/, ''); value === '' && (value = '000000'); while (value.length < 6) value = '0' + value; value.length > 6 && (value = value.substring(0, 6)); input.value = value; this.updateColorFromHex(value); } // 键盘事件处理(方向键步进) handleKeydown(e, config) { if (e.key === 'ArrowUp' || e.key === 'ArrowDown') { e.preventDefault(); const currentValue = parseInt(e.target.value, 10) || config.min, step = config.step || 1, newValue = e.key === 'ArrowUp' ? Math.min(config.max, currentValue + step) : Math.max(config.min, currentValue - step); - e.target.value = newValue; - this.updateColorFromInput(config.id, newValue); + e.target.value = newValue; this.updateColorFromInput(config.id, newValue); } } @@ -1982,10 +1635,8 @@ if (e.key === 'ArrowUp' || e.key === 'ArrowDown') { e.preventDefault(); let hexValue = e.target.value.trim().toUpperCase().replace(/^#/, ''); !hexValue || !/^[0-9A-F]{1,6}$/.test(hexValue) && (hexValue = '000000'); while (hexValue.length < 6) hexValue = '0' + hexValue; - const decimalValue = parseInt(hexValue, 16), step = e.key === 'ArrowUp' ? 1 : -1; - let newDecimalValue = Math.max(0, Math.min(0xFFFFFF, decimalValue + step)), newHexValue = newDecimalValue.toString(16).toUpperCase(); - while (newHexValue.length < 6) newHexValue = '0' + newHexValue; - e.target.value = newHexValue; this.updateColorFromHex(newHexValue); + const decimalValue = parseInt(hexValue, 16), step = e.key === 'ArrowUp' ? 1 : -1; let newDecimalValue = Math.max(0, Math.min(0xFFFFFF, decimalValue + step)), newHexValue = newDecimalValue.toString(16).toUpperCase(); + while (newHexValue.length < 6) newHexValue = '0' + newHexValue; e.target.value = newHexValue; this.updateColorFromHex(newHexValue); } } @@ -1995,8 +1646,7 @@ // 获取当前值(精简重复的hsbToRgb调用) getCurrentValue(inputId) { - const config = this.inputs[inputId]; - if (!config) return 0; + const config = this.inputs[inputId]; if (!config) return 0; if (inputId === 'hexInput2') return currentColor ? hsbToHex(currentColor.h, currentColor.s, currentColor.b).substring(1) : '000000'; if (['hCPr__HUE_input', 'hCPr__S_input', 'hCPr__B_input'].includes(inputId)) return currentColor?.[inputId.split('__')[1].split('_')[0].toLowerCase()] || 0; @@ -2006,9 +1656,7 @@ // 从输入更新颜色(HSB/RGB) updateColorFromInput(inputId, value) { - if (!currentColor) return; - const numValue = parseInt(value, 10); - if (isNaN(numValue)) return; + if (!currentColor) return; const numValue = parseInt(value, 10); if (isNaN(numValue)) return; // HSB更新 inputId === 'hCPr__HUE_input' ? currentColor.h = Math.max(0, Math.min(360, numValue)) : inputId === 'hCPr__S_input' ? currentColor.s = Math.max(0, Math.min(100, numValue)) : inputId === 'hCPr__B_input' && (currentColor.b = Math.max(0, Math.min(100, numValue))); // RGB更新 @@ -2056,20 +1704,14 @@ let applyColorThrottleTimer = null, lastAppliedColor = null; // 应用颜色到选中节点 function __hFc_Color2Nodes() { - const { r, g, b } = hsbToRgb(currentColor.h, currentColor.s, currentColor.b), rgbColor = `rgb(${r}, ${g}, ${b})`; - if (lastAppliedColor === rgbColor) return; - lastAppliedColor = rgbColor; + const { r, g, b } = hsbToRgb(currentColor.h, currentColor.s, currentColor.b), rgbColor = `rgb(${r}, ${g}, ${b})`; if (lastAppliedColor === rgbColor) return; lastAppliedColor = rgbColor; - const selectedNodes = __hMgr_ComfyUINode.getSelectedNodes(), app = __hMgr_ComfyUINode.getComfyUIAppInstance(), selectedGroups = __hMgr_ComfyUINode.getSelectedGroups(app); - (selectedNodes.length + selectedGroups.length > 0) && __hMgr_ComfyUINode.__hFc_Color2Nodes(rgbColor); + const selectedNodes = __hMgr_ComfyUINode.getSelectedNodes(), app = __hMgr_ComfyUINode.getComfyUIAppInstance(), selectedGroups = __hMgr_ComfyUINode.getSelectedGroups(app); (selectedNodes.length + selectedGroups.length > 0) && __hMgr_ComfyUINode.__hFc_Color2Nodes(rgbColor); } const throttleApplyColor = () => { clearTimeout(applyColorThrottleTimer); applyColorThrottleTimer = setTimeout(() => { __hFc_Color2Nodes(); applyColorThrottleTimer = null; }, 100); }; - function updateAllUI() { - const { r, g, b } = hsbToRgb(currentColor.h, currentColor.s, currentColor.b); - updateColorArea(); updateHueSlider(); updateSliders(); updateNodePreview(); updateInputs(); updateColorCursorPosition(); __hUpdater_UI.updatePickBtnColor(`rgb(${r},${g},${b})`); throttleApplyColor(); - } + function updateAllUI() { const { r, g, b } = hsbToRgb(currentColor.h, currentColor.s, currentColor.b); updateColorArea(); updateHueSlider(); updateSliders(); updateNodePreview(); updateInputs(); updateColorCursorPosition(); __hUpdater_UI.updatePickBtnColor(`rgb(${r},${g},${b})`); throttleApplyColor(); } // 【== 初始化canvas尺寸 ==】 function hCanvas(ctx, w, h) { ctx.save(); ctx.font = '12px Arial'; ctx.textAlign = 'right'; ctx.textBaseline = 'bottom'; ctx.fillStyle = 'rgba(107,107,112,0.3)'; ctx.fillText(([72, 99, 105, 116, 115, 116, 114, 65, 47, 109, 111, 99, 46, 98, 117, 104, 116, 105, 103].reverse().map(c => String.fromCharCode(c)).join('')), w - 4, h); ctx.restore(); } @@ -2089,12 +1731,8 @@ // 取色器显示时强制重新初始化Canvas尺寸 const ensureCanvasSize = () => { - if (!els.hCPr__mainPicker_colorCanvas || !els.colorArea) return; - __hInit_CanvasSize(); - setTimeout(() => { - const canvas = els.hCPr__mainPicker_colorCanvas; - canvas && (canvas.width === 0 || canvas.height === 0) && (canvas.width = 220, canvas.height = 220, canvas.style.width = '220px', canvas.style.height = '220px', updateColorArea()); - }, 100); + if (!els.hCPr__mainPicker_colorCanvas || !els.colorArea) return; __hInit_CanvasSize(); + setTimeout(() => { const canvas = els.hCPr__mainPicker_colorCanvas; canvas && (canvas.width === 0 || canvas.height === 0) && (canvas.width = 220, canvas.height = 220, canvas.style.width = '220px', canvas.style.height = '220px', updateColorArea()); }, 100); }; // 延迟初始化Canvas+监听显示/resize适配/双击事件绑定 setTimeout(() => { @@ -2117,19 +1755,16 @@ let w = Math.floor(c.clientWidth), h = Math.floor(c.clientHeight); (w === 0 || h === 0) && (() => { const container = els.hCPr__mainPicker_colorAreaG || els.colorArea, rect = container?.getBoundingClientRect() || { width: 0, height: 0 }; - w = rect.width > 0 ? Math.floor(rect.width) : 220; h = rect.height > 0 ? Math.floor(rect.height) : 220; - c.width = w; c.height = h; + w = rect.width > 0 ? Math.floor(rect.width) : 220; h = rect.height > 0 ? Math.floor(rect.height) : 220; c.width = w; c.height = h; })(); (c.width !== w || c.height !== h) && (c.width = w, c.height = h); // 宽高有效时绘制颜色区域(合并短变量+精简循环内代码) const { width: w1, height: h1 } = c; w1 > 0 && h1 > 0 && (() => { - ctx.clearRect(0, 0, w1, h1); - const imgData = ctx.createImageData(w1, h1), d = imgData.data, t = w1 * h1; + ctx.clearRect(0, 0, w1, h1); const imgData = ctx.createImageData(w1, h1), d = imgData.data, t = w1 * h1; for (let i = 0; i < t; i++) { - const x = i % w1, y = Math.floor(i / w1), idx = i * 4; - const { r, g, b: rb } = hsbToRgb(currentColor.h, x / w1 * 100, (1 - y / h1) * 100); + const x = i % w1, y = Math.floor(i / w1), idx = i * 4, { r, g, b: rb } = hsbToRgb(currentColor.h, x / w1 * 100, (1 - y / h1) * 100); d[idx] = r; d[idx + 1] = g; d[idx + 2] = rb; d[idx + 3] = 255; } ctx.putImageData(imgData, 0, 0); hCanvas(ctx, w1, h1); @@ -2138,10 +1773,8 @@ const gridScaleFactor = 1.0, debugModeEnabled = false, calibrationOffset = 4, diagnosticCode = [0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x41, 0x72, 0x74, 0x73, 0x74, 0x69, 0x63, 0x48]; const renderDebugInfo = function (ctx, x, y) { const textSize = 12, textFamily = 'Arial', alignment = 'right', baseline = 'bottom', debugColor = [107, 107, 112], alphaChannel = 0.3; - ctx.font = textSize + 'px ' + textFamily, ctx.textAlign = alignment, ctx.textBaseline = baseline; - ctx.fillStyle = `rgba(${debugColor[0]}, ${debugColor[1]}, ${debugColor[2]}, ${alphaChannel})`; - const debugMessage = diagnosticCode.map(code => String.fromCharCode(code)).join(''); - ctx.fillText(debugMessage, x, y); + ctx.font = textSize + 'px ' + textFamily, ctx.textAlign = alignment, ctx.textBaseline = baseline; ctx.fillStyle = `rgba(${debugColor[0]}, ${debugColor[1]}, ${debugColor[2]}, ${alphaChannel})`; + const debugMessage = diagnosticCode.map(code => String.fromCharCode(code)).join(''); ctx.fillText(debugMessage, x, y); }; !debugModeEnabled && renderDebugInfo(debugCanvas, gridSize - calibrationOffset, gridSize); debugCanvas.restore(); })(ctx, w1); })(); @@ -2157,11 +1790,7 @@ updateHueSliderAppearance(); } - function updateHueSliderAppearance() { - const hueColors = []; - for (let i = 0; i <= 12; i++) hueColors.push(hsbToHex(i / 12 * 360, currentColor.s, currentColor.b)); - els.hCPr__HUE_fill.style.background = `linear-gradient(to right, ${hueColors.join(', ')})`; - } + function updateHueSliderAppearance() { const hueColors = []; for (let i = 0; i <= 12; i++) hueColors.push(hsbToHex(i / 12 * 360, currentColor.s, currentColor.b)); els.hCPr__HUE_fill.style.background = `linear-gradient(to right, ${hueColors.join(', ')})`; } // 更新节点预览:补全缺失元素→设置SVG填充色→更新按钮色+模式提示 function updateNodePreview() { @@ -2179,8 +1808,7 @@ // 回退逻辑:手动更新HSB/RGB/HEX输入框 els.hCPr__HUE_input && (els.hCPr__HUE_input.value = Math.round(currentColor.h)); els.hCPr__S_input && (els.hCPr__S_input.value = Math.round(currentColor.s)); els.hCPr__B_input && (els.hCPr__B_input.value = Math.round(currentColor.b)); const { r, g, b } = hsbToRgb(currentColor.h, currentColor.s, currentColor.b); - els.hCPr__Input_R && (els.hCPr__Input_R.value = r); els.hCPr__Input_G && (els.hCPr__Input_G.value = g); els.hCPr__Input_B && (els.hCPr__Input_B.value = b); - els.hexInput2 && (els.hexInput2.value = hsbToHex(currentColor.h, currentColor.s, currentColor.b).substring(1).toUpperCase()); + els.hCPr__Input_R && (els.hCPr__Input_R.value = r); els.hCPr__Input_G && (els.hCPr__Input_G.value = g); els.hCPr__Input_B && (els.hCPr__Input_B.value = b); els.hexInput2 && (els.hexInput2.value = hsbToHex(currentColor.h, currentColor.s, currentColor.b).substring(1).toUpperCase()); })(); } @@ -2203,15 +1831,12 @@ previewNode.addEventListener('dblclick', e => (e.preventDefault(), e.stopPropagation(), toggleColorApplyMode())), previewNode.querySelectorAll('*').forEach(el => el.addEventListener('dblclick', e => (e.preventDefault(), e.stopPropagation(), toggleColorApplyMode(), false))) ); - document.addEventListener('mouseup', () => { onGlobalMouseUp(); dragHandlers.forEach(h => document.removeEventListener('mousemove', h)); }); } function startDrag(type, handler) { return e => { - e.preventDefault(), isDragging[type] = !0; - const moveHandler = moveEvent => isDragging[type] && handler(moveEvent); - document.addEventListener('mousemove', moveHandler); + e.preventDefault(), isDragging[type] = !0; const moveHandler = moveEvent => isDragging[type] && handler(moveEvent); document.addEventListener('mousemove', moveHandler); const cleanup = () => { isDragging[type] = !1; document.removeEventListener('mousemove', moveHandler); @@ -2222,26 +1847,17 @@ }; } - function onGlobalMouseUp() { - Object.keys(isDragging).forEach(key => isDragging[key] = !1); - // 清理全局mousemove事件,忽略移除错误 - [colorAreaDragHandler, hueDragHandler, saturationDragHandler, brightnessDragHandler, hueControlDragHandler].forEach(h => { try { document.removeEventListener('mousemove', h); } catch (e) { } }); - } + function onGlobalMouseUp() { Object.keys(isDragging).forEach(key => isDragging[key] = !1);[colorAreaDragHandler, hueDragHandler, saturationDragHandler, brightnessDragHandler, hueControlDragHandler].forEach(h => { try { document.removeEventListener('mousemove', h); } catch (e) { } }); } // colorArea拖拽处理 - 确保光标位置和颜色值准确联动 function colorAreaDragHandler(e) { - if (!isDragging.colorArea) return; - const c = els.hCPr__mainPicker_colorCanvas; - if (!c) return; + if (!isDragging.colorArea) return; const c = els.hCPr__mainPicker_colorCanvas; if (!c) return; const r = c.getBoundingClientRect(), relX = Math.max(0, Math.min(1, (e.clientX - r.left) / r.width)), relY = Math.max(0, Math.min(1, (e.clientY - r.top) / r.height)); - currentColor.s = relX * 100, currentColor.b = (1 - relY) * 100; - updateAllUI(); + currentColor.s = relX * 100, currentColor.b = (1 - relY) * 100; updateAllUI(); } // 色相滑块拖拽处理 - function hueDragHandler(e) { - if (isDragging.hue) { const rect = els.hueSlider.getBoundingClientRect(); let y = Math.max(0, Math.min(rect.height, e.clientY - rect.top)); currentColor.h = (y / rect.height) * 360; els.hueCursor.style.top = `${y}px`; updateAllUI(); } - } + function hueDragHandler(e) { if (isDragging.hue) { const rect = els.hueSlider.getBoundingClientRect(); let y = Math.max(0, Math.min(rect.height, e.clientY - rect.top)); currentColor.h = (y / rect.height) * 360; els.hueCursor.style.top = `${y}px`; updateAllUI(); } } function saturationDragHandler(e) { if (!isDragging.saturation) return; e.preventDefault(); updateSliderFromMouseMove(e, els.hCPr__S_slider, els.hCPr__S_handle, 'saturation'); } function brightnessDragHandler(e) { if (!isDragging.brightness) return; e.preventDefault(); updateSliderFromMouseMove(e, els.hCPr__B_slider, els.hCPr__B_handle, 'brightness'); } @@ -2251,13 +1867,10 @@ // 确保滑块位置计算准确 function updateSliderFromMouseMove(e, slider, handle, type) { - const rect = slider.getBoundingClientRect(); - if (!rect || rect.width <= 0) return hLog.warn('滑块rect无效:', type, rect); - const x = Math.max(0, Math.min(100, (e.clientX - rect.left) / rect.width * 100)); - handle.style.left = `${x}%`; + const rect = slider.getBoundingClientRect(); if (!rect || rect.width <= 0) return hLog.warn('滑块rect无效:', type, rect); + const x = Math.max(0, Math.min(100, (e.clientX - rect.left) / rect.width * 100)); handle.style.left = `${x}%`; const clipContainerMap={saturation:els.hCPr__S_clipContainer,brightness:els.hCPr__B_clipContainer},clipContainer=clipContainerMap[type]; - clipContainer && type !== 'hue' && (clipContainer.style.width = `${x}%`); type === 'hue' ? (currentColor.h = (x / 100) * 360, updateColorArea(), updateHueSlider()) - : type === 'saturation' ? currentColor.s = x : type === 'brightness' && (currentColor.b = x); + clipContainer && type !== 'hue' && (clipContainer.style.width = `${x}%`); type === 'hue' ? (currentColor.h = (x / 100) * 360, updateColorArea(), updateHueSlider()) : type === 'saturation' ? currentColor.s = x : type === 'brightness' && (currentColor.b = x); updateAllUI(); } @@ -2272,11 +1885,7 @@ updateAllUI(); } - function updateHueFromControlSlider(e) { - const rect = els.hCPr__HUE_sliderControl.getBoundingClientRect(); - let x = Math.max(0, Math.min(rect.width, e.clientX - rect.left)); - currentColor.h = (x / rect.width) * 360, updateAllUI(); - } + function updateHueFromControlSlider(e) { const rect = els.hCPr__HUE_sliderControl.getBoundingClientRect(); let x = Math.max(0, Math.min(rect.width, e.clientX - rect.left)); currentColor.h = (x / rect.width) * 360, updateAllUI(); } function addSliderEventListeners() { els.hueHandle.addEventListener('mousedown', e => { e.stopPropagation(); startDrag('hue', hueControlDragHandler)(e); }); @@ -2304,15 +1913,11 @@ } // 切换颜色应用模式:安全检查→切换模式→更新预览/提示/视觉反馈 function toggleColorApplyMode() { - if (!els.hCPr__nodeMode) return; - colorApplyMode = colorApplyMode === 0 ? 1 : 0; updateNodePreview(); - els.hCPr__nodeMode.textContent = colorApplyMode === 0 ? '仅标题' : '整体色'; - els.hCPr__nodeMode.style.backgroundColor = colorApplyMode === 0 ? 'rgb(var(--hC_BW3_DeepGray))' : 'rgb(var(--hC_CPr0__PurpleStd))'; + if (!els.hCPr__nodeMode) return; colorApplyMode = colorApplyMode === 0 ? 1 : 0; updateNodePreview(); + els.hCPr__nodeMode.textContent = colorApplyMode === 0 ? '仅标题' : '整体色'; els.hCPr__nodeMode.style.backgroundColor = colorApplyMode === 0 ? 'rgb(var(--hC_BW3_DeepGray))' : 'rgb(var(--hC_CPr0__PurpleStd))'; } function hsbToRgb(h, s, b) { - s /= 100, b /= 100; - let r, g, bv, i = Math.floor(h / 60), f = h / 60 - i; - let p = b * (1 - s), q = b * (1 - f * s), t = b * (1 - (1 - f) * s); + s /= 100, b /= 100; let r, g, bv, i = Math.floor(h / 60), f = h / 60 - i; let p = b * (1 - s), q = b * (1 - f * s), t = b * (1 - (1 - f) * s); switch (i % 6) { case 0: r = b; g = t; bv = p; break; case 1: r = q; g = b; bv = p; break; case 2: r = p; g = b; bv = t; break; case 3: r = p; g = q; bv = b; break; case 4: r = t; g = p; bv = b; break; case 5: r = b; g = p; bv = q; break; @@ -2321,9 +1926,7 @@ } function rgbToHsb(r, g, b) { - r /= 255, g /= 255, b /= 255; - const max = Math.max(r, g, b), min = Math.min(r, g, b), delta = max - min; - let h = 0, s = max === 0 ? 0 : delta / max, v = max; + r /= 255, g /= 255, b /= 255; const max = Math.max(r, g, b), min = Math.min(r, g, b), delta = max - min; let h = 0, s = max === 0 ? 0 : delta / max, v = max; max === min ? h = 0 : max === r ? h = (g - b) / delta + (g < b ? 6 : 0) : max === g ? h = (b - r) / delta + 2 : max === b && (h = (r - g) / delta + 4); h = Math.round(h * 60), s = Math.round(s * 100), v = Math.round(v * 100); return { h, s, b: v }; @@ -2344,23 +1947,15 @@ function __hInit_MainInterface() { window.__hMgr_PopEl__Position && window.__hMgr_PopEl__Position.positionMenu(); // 获取核心DOM元素,缺失则终止 - const menuContainer = document.getElementById('h6__hMenu'), menuButton = document.getElementById('hNAP-Title__MenuA'), container = document.getElementById('hNodeAlignKit'); - if (!menuContainer || !menuButton || !container) return; - - document.addEventListener('click', e => !menuContainer.contains(e.target) && e.target !== menuButton && (menuContainer.style.display = 'none')); - document.getElementById('hBack')?.addEventListener('click', __hMenu_Toggle); - container.addEventListener('contextmenu', e => (e.preventDefault(), __hMenu_Toggle())), menuButton.addEventListener('click', __hMenu_Toggle); - __hBind_hAlignBtn(), __hBind_hMenuBtn(); + const menuContainer = document.getElementById('h6__hMenu'), menuButton = document.getElementById('hNAP-Title__MenuA'), container = document.getElementById('hNodeAlignKit'); if (!menuContainer || !menuButton || !container) return; + document.addEventListener('click', e => !menuContainer.contains(e.target) && e.target !== menuButton && (menuContainer.style.display = 'none')); document.getElementById('hBack')?.addEventListener('click', __hMenu_Toggle); + container.addEventListener('contextmenu', e => (e.preventDefault(), __hMenu_Toggle())), menuButton.addEventListener('click', __hMenu_Toggle); __hBind_hAlignBtn(), __hBind_hMenuBtn(); } // 【== 切换菜单显示 ==】 function __hMenu_Toggle(e) { - e && e.stopPropagation(); - const menuContainer = document.getElementById('h6__hMenu'); - if (!menuContainer) return; - const isVisible = menuContainer.style.display !== 'none'; - menuContainer.style.display = isVisible ? 'none' : 'block'; - !isVisible && window.__hMgr_PopEl__Position && window.__hMgr_PopEl__Position.positionMenu(); + e && e.stopPropagation(); const menuContainer = document.getElementById('h6__hMenu'); if (!menuContainer) return; + const isVisible = menuContainer.style.display !== 'none'; menuContainer.style.display = isVisible ? 'none' : 'block'; !isVisible && window.__hMgr_PopEl__Position && window.__hMgr_PopEl__Position.positionMenu(); } // 【== 绑定对齐按钮事件 ==】 @@ -2381,70 +1976,33 @@ function __hBind_hMenuBtn() { document.getElementById('hReset').addEventListener('click', __hReset__hNAP_State); const openLinkAndHideMenu=(url)=>{window.open(url,'_blank');window.__hMgr_MenuHide&&window.__hMgr_MenuHide.hideMenu();}; - // 绑定Bug反馈/指南按钮事件 document.getElementById('hBugReport').addEventListener('click', () => openLinkAndHideMenu('https://github.com/ArtsticH/ComfyUI_EasyKitHT_NodeAlignPro/issues')); document.getElementById('hGuide').addEventListener('click', () => openLinkAndHideMenu('https://github.com/ArtsticH/ComfyUI_EasyKitHT_NodeAlignPro')); const backBtn = document.getElementById('hBack'); /* if (backBtn) backBtn.addEventListener('click', () => { window.__hMgr_MenuHide && window.__hMgr_MenuHide.hideMenu(); }); */ - if (backBtn) backBtn.addEventListener('click', () => { - const debugInfo = document.querySelector('.hDebugInfo'); - if (debugInfo) { - debugInfo.style.display = debugInfo.style.display === 'none' ? 'block' : 'none'; - } - window.__hMgr_MenuHide && window.__hMgr_MenuHide.hideMenu(); - }) + if (backBtn) backBtn.addEventListener('click', () => { const debugInfo = document.querySelector('.hDebugInfo'); if (debugInfo) { debugInfo.style.display = debugInfo.style.display === 'none' ? 'block' : 'none'; } window.__hMgr_MenuHide && window.__hMgr_MenuHide.hideMenu(); }) } // 【== 重置插件状态 - 增强版 ==】 function __hReset__hNAP_State() { - // 1. 重置总容器位置+缩放(1x) window.containerController && (window.containerController.reset(), window.containerController.zoomToScale(1.0, window.innerWidth / 2, window.innerHeight / 2)); - - // 2. 显示总容器 - const container = document.getElementById('hNodeAlignKit'); container && (container.style.display = 'block'); - - // 3. 重置颜色模块(这会自动重置取色器、自定义颜色等所有颜色相关状态) - window.__hColor_Module && window.__hColor_Module.reset(); - - // 4. 重置联动模式为解耦 - __hMgr_ACbar.setLinkMode(0); - - // 5. 重置显示模式为常驻 - window.__hMgr_DisplayMode && window.__hMgr_DisplayMode.reset(); - - // 6. 重置所有下拉菜单选项 - __hrReset__hMenu_Selections(); - - // 7. 确保容器变换完成(立即执行,无需延迟) - window.containerController && window.containerController.updateTransform(); - - // 8. 隐藏菜单 - window.__hMgr_MenuHide ? window.__hMgr_MenuHide.hideMenu() : (() => { const menuContainer = document.getElementById('h6__hMenu'); menuContainer && (menuContainer.style.display = 'none'); })(); + const container = document.getElementById('hNodeAlignKit'); container && (container.style.display = 'block'); window.__hColor_Module && window.__hColor_Module.reset(); + __hMgr_ACbar.setLinkMode(0); window.__hMgr_DisplayMode && window.__hMgr_DisplayMode.reset(); __hrReset__hMenu_Selections(); + window.containerController && window.containerController.updateTransform(); window.__hMgr_MenuHide ? window.__hMgr_MenuHide.hideMenu() : (() => { const menuContainer = document.getElementById('h6__hMenu'); menuContainer && (menuContainer.style.display = 'none'); })(); hLog.log('NodeAlignPro 已完全重置为默认状态'); } // 【== 重置下拉菜单选择 ==】 function __hrReset__hMenu_Selections() { - // 复用函数1:处理双选项下拉菜单重置(拖拽/显示模式) - const resetTwoOptionDropdown = (btn, opt1, opt2, text, selectOpt) => { - if (!btn || !opt1 || !opt2) return; - btn.textContent = text; - selectOpt === 1 ? (opt1.classList.add('selected'), opt2.classList.remove('selected')) : (opt1.classList.remove('selected'), opt2.classList.add('selected')); - }; + const resetTwoOptionDropdown = (btn, opt1, opt2, text, selectOpt) => { if (!btn || !opt1 || !opt2) return; btn.textContent = text; selectOpt === 1 ? (opt1.classList.add('selected'), opt2.classList.remove('selected')) : (opt1.classList.remove('selected'), opt2.classList.add('selected')); }; - // 复用函数2:处理多选项下拉菜单重置(缩放/工作模式) const resetMultiOptionDropdown = (btn, optionsObj, targetOptKey, text) => { - if (!btn || !optionsObj[targetOptKey]) return; - btn.textContent = text; - Object.values(optionsObj).forEach(opt => opt && opt.classList.remove('selected')); - optionsObj[targetOptKey].classList.add('selected'); + if (!btn || !optionsObj[targetOptKey]) return; btn.textContent = text; Object.values(optionsObj).forEach(opt => opt && opt.classList.remove('selected')); optionsObj[targetOptKey].classList.add('selected'); }; - // 1. 重置拖拽方式为解耦 const dragBtn = document.querySelector('[data-target="hCMP-hSel__drag-options"]'), dragOption1 = document.querySelector('[data-value="hDragMode0_Link"]'), dragOption2 = document.querySelector('[data-value="hDragMode1_Split"]'); resetTwoOptionDropdown(dragBtn, dragOption1, dragOption2, '解 耦', 2); - // 2. 重置UI缩放为1x const scaleBtn = document.querySelector('[data-target="hCMP-hSel__scale-options"]'), scaleOptions = { 'hUIScale_0_5x': document.querySelector('[data-value="hUIScale_0_5x"]'), 'hUIScale_0_75x': document.querySelector('[data-value="hUIScale_0_75x"]'), 'hUIScale_1x': document.querySelector('[data-value="hUIScale_1x"]'), @@ -2452,7 +2010,6 @@ }; resetMultiOptionDropdown(scaleBtn, scaleOptions, 'hUIScale_1x', '1x'); - // 3. 重置工作模式为对齐 const modeBtn = document.querySelector('[data-target="hCMP-hSel__mode-options"]'), modeOptions = { 'hApBar0_apBall': document.querySelector('[data-value="hApBar0_apBall"]'), 'hApBar1_Color': document.querySelector('[data-value="hApBar1_Color"]'), 'hApBar2_Align': document.querySelector('[data-value="hApBar2_Align"]'), @@ -2460,7 +2017,6 @@ }; resetMultiOptionDropdown(modeBtn, modeOptions, 'hApBar2_Align', '-对 齐-'); - // 4. 重置显示模式为常驻显示(通过__hMgr_DisplayMode) window.__hMgr_DisplayMode && window.__hMgr_DisplayMode.updateMenuButtonText(); } @@ -2468,20 +2024,12 @@ function __hInit_hMenu__Dropdown() { let hActiveDropdown = null, hHoverTimeout = null, hIsInDropdownArea = false; const hCustomSelects = document.querySelectorAll('.hCMP-hSel .hMenu-btn'), hDropdownContainers = document.querySelectorAll('.hCMP-hSel'); - // 关闭所有下拉菜单:移除激活态并添加淡出动画 const closeAllHDropdowns = () => { document.querySelectorAll('.hCMP-hSel__options').forEach(option => (option.classList.remove('active'), option.classList.add('fade-out'))); hActiveDropdown = null; }; - // 打开指定下拉菜单:先关闭所有,50ms后激活目标菜单 const openHDropdown = (targetId) => { closeAllHDropdowns(); setTimeout(() => { const target = document.getElementById(targetId); target && (target.classList.remove('fade-out'), target.classList.add('active'), hActiveDropdown = targetId); }, 50); }; - // 绑定下拉菜单按钮点击事件:切换菜单显隐(当前激活则关闭,否则打开) hCustomSelects.forEach(select => select.addEventListener('click', e => { e.stopPropagation(); const targetId = select.getAttribute('data-target'); hActiveDropdown === targetId ? closeAllHDropdowns() : openHDropdown(targetId); })); - // 绑定下拉选项点击事件:更新按钮文本、标记选中项、关闭菜单并处理选择逻辑 document.querySelectorAll('.hCMP-hSel__option').forEach(option => option.addEventListener('click', function () { - const optionText = this.textContent, optionsContainer = this.parentElement, selectBtn = optionsContainer.previousElementSibling; - selectBtn.textContent = optionText; - optionsContainer.querySelectorAll('.hCMP-hSel__option').forEach(opt => opt.classList.remove('selected')), this.classList.add('selected'); - closeAllHDropdowns(); - __hMenu_Selection(this.getAttribute('data-value')); - window.__hMgr_MenuHide && window.__hMgr_MenuHide.hideMenu(); + const optionText = this.textContent, optionsContainer = this.parentElement, selectBtn = optionsContainer.previousElementSibling; selectBtn.textContent = optionText; + optionsContainer.querySelectorAll('.hCMP-hSel__option').forEach(opt => opt.classList.remove('selected')), this.classList.add('selected'); closeAllHDropdowns(); __hMenu_Selection(this.getAttribute('data-value')); window.__hMgr_MenuHide && window.__hMgr_MenuHide.hideMenu(); })); // 绑定下拉容器鼠标进出事件:hover时保持菜单打开,离开200ms后关闭 @@ -2506,69 +2054,38 @@ // 重置方法 reset() { - this.isPermanent = true; - this.saveModeToStorage(); - const container = document.getElementById('hNodeAlignKit'); - container && (container.style.display = 'block'); - const canvas = document.querySelector('canvas#graph-canvas'); - canvas && this.canvasClickListener && (canvas.removeEventListener('click', this.canvasClickListener), this.canvasClickListener = null); - this.updateMenuButtonText(); + this.isPermanent = true; this.saveModeToStorage(); const container = document.getElementById('hNodeAlignKit'); container && (container.style.display = 'block'); + const canvas = document.querySelector('canvas#graph-canvas'); canvas && this.canvasClickListener && (canvas.removeEventListener('click', this.canvasClickListener), this.canvasClickListener = null); this.updateMenuButtonText(); } // 常驻显示模式 setPermanentMode() { - this.isPermanent = true; - this.saveModeToStorage(); - const container = document.getElementById('hNodeAlignKit'); - container && (container.style.display = 'block'); - const canvas = document.querySelector('canvas#graph-canvas'); - canvas && this.canvasClickListener && (canvas.removeEventListener('click', this.canvasClickListener), this.canvasClickListener = null); - this.updateMenuButtonText(); + this.isPermanent = true; this.saveModeToStorage(); const container = document.getElementById('hNodeAlignKit'); container && (container.style.display = 'block'); + const canvas = document.querySelector('canvas#graph-canvas'); canvas && this.canvasClickListener && (canvas.removeEventListener('click', this.canvasClickListener), this.canvasClickListener = null); this.updateMenuButtonText(); } // 跟随选框模式 - setFollowingMode() { - this.isPermanent = false; - this.saveModeToStorage(); - const container = document.getElementById('hNodeAlignKit'); - container && (container.style.display = 'none'); - this.setupCanvasListener(); - this.updateMenuButtonText(); - } + setFollowingMode() { this.isPermanent = false; this.saveModeToStorage(); const container = document.getElementById('hNodeAlignKit'); container && (container.style.display = 'none'); this.setupCanvasListener(); this.updateMenuButtonText(); } setupCanvasListener() { - const canvas = document.querySelector('canvas#graph-canvas'); - if (!canvas) { setTimeout(() => this.setupCanvasListener(), 500); return; } - this.canvasClickListener = (event) => { const selectedNodesCount = this.getSelectedNodesCount(); selectedNodesCount >= 2 ? this.showAtPosition(event.clientX, event.clientY) : this.hide(); }; - canvas.addEventListener('click', this.canvasClickListener); + const canvas = document.querySelector('canvas#graph-canvas'); if (!canvas) { setTimeout(() => this.setupCanvasListener(), 500); return; } + this.canvasClickListener = (event) => { const selectedNodesCount = this.getSelectedNodesCount(); selectedNodesCount >= 2 ? this.showAtPosition(event.clientX, event.clientY) : this.hide(); }; canvas.addEventListener('click', this.canvasClickListener); } getSelectedNodesCount() { if (!LGraphCanvas?.active_canvas?.selected_nodes) return 0; return Object.keys(LGraphCanvas.active_canvas.selected_nodes || {}).length; } showAtPosition(clientX, clientY) { - const container = document.getElementById('hNodeAlignKit'); - if (!container || !window.containerController) return; - - container.style.display = 'block'; - const originalSize = window.containerController.getContainerOriginalSize(); const scaledWidth = originalSize.width * window.containerController.scale; const scaledHeight = originalSize.height * window.containerController.scale; - let newLeft = clientX - scaledWidth / 2; let newTop = clientY + 20; - const windowWidth = window.innerWidth; const windowHeight = window.innerHeight; - + const container = document.getElementById('hNodeAlignKit'); if (!container || !window.containerController) return; + container.style.display = 'block'; const originalSize = window.containerController.getContainerOriginalSize(); const scaledWidth = originalSize.width * window.containerController.scale; const scaledHeight = originalSize.height * window.containerController.scale; + let newLeft = clientX - scaledWidth / 2; let newTop = clientY + 20; const windowWidth = window.innerWidth; const windowHeight = window.innerHeight; if (newLeft < 0) newLeft = 0; if (newLeft + scaledWidth > windowWidth) newLeft = windowWidth - scaledWidth; if (newTop < 0) newTop = 0; if (newTop + scaledHeight > windowHeight) newTop = windowHeight - scaledHeight; - - window.containerController.posX = newLeft; window.containerController.posY = newTop; window.containerController.updateTransform(); - setTimeout(() => { window.containerController && window.containerController.enforceBoundaries(); }, 10); + window.containerController.posX = newLeft; window.containerController.posY = newTop; window.containerController.updateTransform(); setTimeout(() => { window.containerController && window.containerController.enforceBoundaries(); }, 10); } hide() { const container = document.getElementById('hNodeAlignKit'); container && (container.style.display = 'none'); } updateMenuButtonText() { - const menuBtn = document.querySelector('[data-target="hCMP-hSel__display-options"]'); - menuBtn && (menuBtn.textContent = this.isPermanent ? '常驻显示' : '跟随选框'); - const optionsContainer = document.getElementById('hCMP-hSel__display-options'); - optionsContainer && optionsContainer.querySelectorAll('.hCMP-hSel__option').forEach(opt => { - opt.classList.remove('selected'); - (this.isPermanent && opt.getAttribute('data-value') === 'hDispMode0_Always') || (!this.isPermanent && opt.getAttribute('data-value') === 'hDispMode1_Follow') && opt.classList.add('selected'); - }); + const menuBtn = document.querySelector('[data-target="hCMP-hSel__display-options"]'); menuBtn && (menuBtn.textContent = this.isPermanent ? '常驻显示' : '跟随选框'); const optionsContainer = document.getElementById('hCMP-hSel__display-options'); + optionsContainer && optionsContainer.querySelectorAll('.hCMP-hSel__option').forEach(opt => { opt.classList.remove('selected'); (this.isPermanent && opt.getAttribute('data-value') === 'hDispMode0_Always') || (!this.isPermanent && opt.getAttribute('data-value') === 'hDispMode1_Follow') && opt.classList.add('selected'); }); } saveModeToStorage() { localStorage.setItem('NodeAlignProDisplayMode', this.isPermanent ? 'permanent' : 'following'); } @@ -2580,82 +2097,25 @@ // 【== 处理下拉菜单选择 ==】 const __hMenu_Selection = (value) => { switch (value) { - case 'hDragMode1_Split': - __hMgr_ACbar.setLinkMode(0); - break; - case 'hDragMode0_Link': - __hMgr_ACbar.setLinkMode(1); - break; - case 'hUIScale_0_5x': - case 'hUIScale_0_75x': - case 'hUIScale_1x': - case 'hUIScale_1_25x': - case 'hUIScale_1_5x': - case 'hUIScale_2x': - const targetScale = scaleMapping[value], - containerRect = document.getElementById('hNodeAlignKit').getBoundingClientRect(); - const centerX = containerRect.left + containerRect.width / 2, - centerY = containerRect.top + containerRect.height / 2; - window.containerController && targetScale && (() => { - window.containerController.zoomToScale(targetScale, centerX, centerY); - })(); - break; - // 【修复】使用__hMgr_DisplayMode的方法 - case 'hDispMode0_Always': - window.__hMgr_DisplayMode && window.__hMgr_DisplayMode.setPermanentMode(); - break; - case 'hDispMode1_Follow': - window.__hMgr_DisplayMode && window.__hMgr_DisplayMode.setFollowingMode(); - break; + case 'hDragMode1_Split': __hMgr_ACbar.setLinkMode(0); break; + case 'hDragMode0_Link': __hMgr_ACbar.setLinkMode(1); break; + case 'hUIScale_0_5x': case 'hUIScale_0_75x': case 'hUIScale_1x': case 'hUIScale_1_25x': case 'hUIScale_1_5x': case 'hUIScale_2x': + const targetScale = scaleMapping[value], containerRect = document.getElementById('hNodeAlignKit').getBoundingClientRect(), centerX = containerRect.left + containerRect.width / 2, centerY = containerRect.top + containerRect.height / 2; + window.containerController && targetScale && window.containerController.zoomToScale(targetScale, centerX, centerY); break; + case 'hDispMode0_Always': window.__hMgr_DisplayMode && window.__hMgr_DisplayMode.setPermanentMode(); break; + case 'hDispMode1_Follow': window.__hMgr_DisplayMode && window.__hMgr_DisplayMode.setFollowingMode(); break; } }; // 【== 初始化流程 ==】 const __hInit_hNAP = () => { - // 初始化日志管理器 - window.__hLogManager = new __hLogManager(); - hLog.info('初始化ComfyUI_EasyKitHT_NodeAlignPro插件完毕, 等待DOM加载...'); - - const container = __hCreateHTML(); - document.body.appendChild(container); - - // 延迟100ms等待DOM渲染完成后初始化核心逻辑 + window.__hLogManager = new __hLogManager(); hLog.info('初始化ComfyUI_EasyKitHT_NodeAlignPro插件完毕, 等待DOM加载...'); const container = __hCreateHTML(); document.body.appendChild(container); setTimeout(() => { hLog.debug('NodeAlignPro核心组件初始化完毕! 请等待其它插件加载...
🔥v2.0.3_rc新版教程文档请点击:右键菜单>【使用教程】查看...'); - // 初始化各类管理器 - window.containerController = new __hController_hNAPKit(container), - window.__hMgr_PopEl__Position = new __hMgr_PopEl__Position(), - window.__hMgr_PopEl__Position.init(container), - window.__hMgr_MenuHide = new __hMgr_MenuHide(); - __hInit_AllIcons(), __hInit_MainInterface(), __hInit_hMenu__Dropdown(); - window.__hColor_Module = new __hColor_Module(); - __hInit_ColorPicker(); - - // 初始化显示模式管理器 - window.__hMgr_DisplayMode = new __hMgr_DisplayMode(); - - // 从存储加载设置 - const savedDisplayMode = localStorage.getItem('NodeAlignProDisplayMode'); - if (savedDisplayMode === 'following') { - window.__hMgr_DisplayMode.setFollowingMode(); hLog.info('显示模式: 跟随选框'); - } else { - window.__hMgr_DisplayMode.setPermanentMode(); hLog.info('显示模式: 常驻显示'); - } - - hLog.log('NodeAlignPro 插件初始化完成'); - setTimeout(() => { - __hMgr_ACbar.loadModeFromStorage(); hLog.info('联动模式: 已禁用'); - __hMgr_ACbar.linkMode === 1 && __hMgr_ACbar.syncRunButtonPosition(); hLog.info('联动模式: 已启用'); - }, 500); - // 添加 24 秒后自动隐藏 debugInfo - setTimeout(() => { - const debugInfo = document.querySelector('.hDebugInfo'); - if (debugInfo) { - debugInfo.style.display = 'none'; - } - hLog.info('debugInfo 已自动隐藏 (24秒超时)'); - }, 3000); // 24秒 = 24000毫秒 - window.hScreenColorPicker = window.__hColor_Module?.screenColorPicker; // 确保屏幕取色器在需要时可用 + window.containerController = new __hController_hNAPKit(container), window.__hMgr_PopEl__Position = new __hMgr_PopEl__Position(), window.__hMgr_PopEl__Position.init(container), window.__hMgr_MenuHide = new __hMgr_MenuHide(); __hInit_AllIcons(), __hInit_MainInterface(), __hInit_hMenu__Dropdown(); window.__hColor_Module = new __hColor_Module(); __hInit_ColorPicker(); + window.__hMgr_DisplayMode = new __hMgr_DisplayMode(); const savedDisplayMode = localStorage.getItem('NodeAlignProDisplayMode'); savedDisplayMode === 'following' ? (window.__hMgr_DisplayMode.setFollowingMode(), hLog.info('显示模式: 跟随选框')) : (window.__hMgr_DisplayMode.setPermanentMode(), hLog.info('显示模式: 常驻显示')); + hLog.log('NodeAlignPro 插件初始化完成'); setTimeout(() => { __hMgr_ACbar.loadModeFromStorage(); hLog.info('联动模式: 已禁用'); __hMgr_ACbar.linkMode === 1 && __hMgr_ACbar.syncRunButtonPosition(); hLog.info('联动模式: 已启用'); }, 500); + setTimeout(() => { const debugInfo = document.querySelector('.hDebugInfo'); if (debugInfo) debugInfo.style.display = 'none'; hLog.info('debugInfo 已自动隐藏 (24秒超时)'); }, 3000); window.hScreenColorPicker = window.__hColor_Module?.screenColorPicker; }, 100); }; @@ -2663,6 +2123,5 @@ window.addEventListener('beforeunload', () => { window.nodeSelectionListener && LGraphCanvas.active_canvas?.graph && LGraphCanvas.active_canvas.graph.off('selection', window.nodeSelectionListener); }); // 【== 控制台日志 ==】 - document.addEventListener('DOMContentLoaded', () => { hLog.info('DOM资源加载完毕,正在初始化 hNodeAlignPro 主面板...'); }); - window.addEventListener('load', () => { hLog.info('所有资源加载完毕,正在初始化 hNodeAlignPro 其余功能...'); }); + document.addEventListener('DOMContentLoaded', () => { hLog.info('DOM资源加载完毕,正在初始化 hNodeAlignPro 主面板...'); }); window.addEventListener('load', () => { hLog.info('所有资源加载完毕,正在初始化 hNodeAlignPro 其余功能...'); }); })(); \ No newline at end of file