diff --git a/CHANGELOG.md b/CHANGELOG.md
index d7af22a..f5bb08e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,4 +1,8 @@
# Changelog
+
+## [0.56.0] - 2025-04-3
+- 增加Resource monitor
+
## [0.51.0] - 2025-03-31
- node align 新增快捷键`Shift+WASD`
diff --git a/README.md b/README.md
index dc3af01..6a9d685 100644
--- a/README.md
+++ b/README.md
@@ -15,6 +15,15 @@ This is a custom node utility package developed for ComfyUI. Initially created f
**📌 所有 KayTool 节点包用到的资源都在 `ComfyUI/custom_nodes/kaytool` 文件夹内。| All KayTool node packages use resources in the `ComfyUI/custom_nodes/kaytool` folder.**
+## 资源监视器 Resource Monitor
+
+- 实时显示当前 ComfyUI 资源使用情况,包括内存占用、显存占用、CPU 占用等。
+ Displays real-time resource usage information, including memory usage, GPU memory usage, and CPU usage.
+- 支持曲线统计表以精确评估工作流资源消耗情况。
+ Supports curve statistics for accurate evaluation of workflow resource consumption.
+- 支持自定义颜色设置,可根据个人喜好调整显示效果。
+ Supports custom color settings, allowing personal preference adjustments.
+
## 节点排版工具栏 Node Align Toolbar
- 支持节点多种对齐方式的工具栏
diff --git a/__init__.py b/__init__.py
index c06e05b..fff709a 100644
--- a/__init__.py
+++ b/__init__.py
@@ -1,6 +1,8 @@
import os
import json
from aiohttp import web
+from .api import resources
+
from .nodes.custom_save_image import CustomSaveImage
from .nodes.color_adjustment import ColorAdjustment
from .nodes.strong_prompt import StrongPrompt
@@ -90,28 +92,3 @@ NODE_DISPLAY_NAME_MAPPINGS = {
}
WEB_DIRECTORY = "web"
-SETTINGS_FILE = os.path.join(os.path.dirname(os.path.realpath(__file__)), "settings.json")
-
-# async def load_settings(request):
-# if os.path.exists(SETTINGS_FILE):
-# with open(SETTINGS_FILE, "r") as f:
-# return web.json_response(json.load(f))
-# return web.json_response({"ShowRunOption": True, "ShowSetGetOptions": True})
-
-# async def save_settings(request):
-# data = await request.json()
-# settings = {}
-# if os.path.exists(SETTINGS_FILE):
-# with open(SETTINGS_FILE, "r") as f:
-# settings = json.load(f)
-# settings.update(data)
-# with open(SETTINGS_FILE, "w") as f:
-# json.dump(settings, f, indent=2)
-# return web.Response(status=200)
-
-# import server
-# app = server.PromptServer.instance
-# app.app.add_routes([
-# web.get("/kaytool/load_settings", load_settings),
-# web.post("/kaytool/save_settings", save_settings),
-# ])
\ No newline at end of file
diff --git a/api/resources.py b/api/resources.py
new file mode 100644
index 0000000..b4c556b
--- /dev/null
+++ b/api/resources.py
@@ -0,0 +1,84 @@
+from server import PromptServer
+import psutil
+import asyncio
+import json
+from aiohttp import web
+from cpuinfo import get_cpu_info
+import pynvml
+import platform
+
+PLATFORM = platform.system()
+IS_MACOS = PLATFORM == "Darwin"
+IS_LINUX = PLATFORM == "Linux"
+IS_WINDOWS = PLATFORM == "Windows"
+
+PYNVML_AVAILABLE = False
+if IS_LINUX or IS_WINDOWS:
+ try:
+ pynvml.nvmlInit()
+ PYNVML_AVAILABLE = True
+ except pynvml.NVMLError:
+ PYNVML_AVAILABLE = False
+
+CPU_NAME = get_cpu_info().get('brand_raw', "Unknown")
+GPU_INFO_CACHE = None
+LAST_GPU_UPDATE = 0
+GPU_CACHE_INTERVAL = 0.5
+
+async def get_gpu_info():
+ global GPU_INFO_CACHE, LAST_GPU_UPDATE
+ current_time = asyncio.get_event_loop().time()
+ if GPU_INFO_CACHE is None or (current_time - LAST_GPU_UPDATE) >= GPU_CACHE_INTERVAL:
+ if IS_MACOS:
+ GPU_INFO_CACHE = "GPU monitoring not supported on macOS"
+ elif PYNVML_AVAILABLE:
+ try:
+ device_count = pynvml.nvmlDeviceGetCount()
+ gpu_info = []
+ for i in range(device_count):
+ handle = pynvml.nvmlDeviceGetHandleByIndex(i)
+ name = pynvml.nvmlDeviceGetName(handle)
+ if isinstance(name, bytes):
+ name = name.decode('utf-8')
+ util = pynvml.nvmlDeviceGetUtilizationRates(handle)
+ mem_info = pynvml.nvmlDeviceGetMemoryInfo(handle)
+ gpu_info.append({
+ "index": i,
+ "name": name,
+ "load": float(util.gpu),
+ "memory_used": float(mem_info.used) / (1024 ** 3),
+ "memory_total": float(mem_info.total) / (1024 ** 3),
+ "memory_percent": (float(mem_info.used) / float(mem_info.total)) * 100
+ })
+ GPU_INFO_CACHE = gpu_info
+ except Exception:
+ GPU_INFO_CACHE = "GPU information unavailable"
+ else:
+ GPU_INFO_CACHE = "GPU information unavailable"
+ LAST_GPU_UPDATE = current_time
+ return GPU_INFO_CACHE
+
+@PromptServer.instance.routes.get("/kaytool/resources")
+async def fetch_resources(request):
+ try:
+ cpu_percent = psutil.cpu_percent(interval=0.1)
+ cpu_count = psutil.cpu_count()
+ ram = psutil.virtual_memory()
+ ram_total = round(ram.total / (1024 ** 3), 1)
+ ram_used = round(ram.used / (1024 ** 3), 1)
+ ram_percent = ram.percent
+
+ gpu_info = await get_gpu_info()
+
+ data = {
+ "cpu_percent": cpu_percent,
+ "cpu_count": cpu_count,
+ "cpu_name": CPU_NAME,
+ "ram_total": ram_total,
+ "ram_used": ram_used,
+ "ram_percent": ram_percent,
+ "gpu": gpu_info
+ }
+ return web.Response(text=json.dumps(data), content_type='application/json')
+ except Exception as e:
+ return web.Response(text=json.dumps({"error": str(e)}), status=500)
\ No newline at end of file
diff --git a/locales/zh/main.json b/locales/zh/main.json
index 9413eec..80193ff 100644
--- a/locales/zh/main.json
+++ b/locales/zh/main.json
@@ -5,7 +5,8 @@
"KayTool Menu": "右键菜单",
"Custom Web Logo (BETA)": "自定义网页徽标",
"Workflow PNG": "Workflow PNG",
- "NodeAlignment": "节点对齐工具栏"
+ "NodeAlignment": "节点对齐工具栏",
+ "Resource Monitor": "资源监视器"
},
"nodeCategories": {
"Image": "图像",
diff --git a/locales/zh/settings.json b/locales/zh/settings.json
index 93d9119..646b097 100644
--- a/locales/zh/settings.json
+++ b/locales/zh/settings.json
@@ -18,11 +18,20 @@
"name": "Workflow PNG 导出的边距大小",
"tooltip": "建议设置 100"
},
+ "KayTool_EnableResourceMonitor": {
+ "name": "启用资源监视器"
+ },
+ "KayTool_ResourceMonitorEdgeFade": {
+ "name": "统计表边缘渐隐"
+ },
+ "KayTool_ResourceMonitorBackgroundOpacity": {
+ "name": "资源监视器背景不透明度"
+ },
"KayTool_SetGetForegroundColor": {
- "name": " '🛜 Set/Get' 节点颜色"
+ "name": "节点颜色"
},
"KayTool_SetGetBackgroundColor": {
- "name": " '🛜 Set/Get' 标题颜色"
+ "name": "标题颜色"
},
"KayTool_CustomWebLogo": {
"name": "文件必须 < 1MB",
diff --git a/nodes/ab_images.py b/nodes/ab_images.py
index d4a4196..3cb07af 100644
--- a/nodes/ab_images.py
+++ b/nodes/ab_images.py
@@ -14,7 +14,6 @@ class ABImages(PreviewImage):
"a": ("IMAGE",),
},
"optional": {
-
"b": ("IMAGE",),
},
"hidden": {
diff --git a/pyproject.toml b/pyproject.toml
index 3c3efdf..91b499e 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,9 +1,9 @@
[project]
name = "kaytool"
-description ="KayTool enhances ComfyUI workflow efficiency with practical tools, including: image processing (resize, color, blur, expand, merge, crop), background/mask tasks via BiRefNet/RemBG, wireless data transfer (Get & Out), AI translation (Tencent/Baidu), dynamic math operations, flexible text handling, precision sliders, metadata/color profile-supported image saving, batch processing via image folder loading, canvas workflow node map export as PNG with embedded metadata, quick Run options via right-click (Run Group/Node), node alignment toolbar with custom styled styles, and custom ComfyUI logo integration."
-version = "0.52.2"
+description ="KayTool enhances ComfyUI workflow efficiency with practical tools, including: image processing (resize, color, blur, expand, merge, crop), background/mask tasks via BiRefNet/RemBG, wireless data transfer (Get & Out), AI translation (Tencent/Baidu),Professional high-precision resource monitor and statistics table, dynamic math operations, flexible text handling, precision sliders, metadata/color profile-supported image saving, batch processing via image folder loading, canvas workflow node map export as PNG with embedded metadata, quick Run options via right-click (Run Group/Node), node alignment toolbar with custom styled styles, and custom ComfyUI logo integration."
+version = "0.56.0"
license = {file = "LICENSE"}
-dependencies = ["rembg, timm, opencv-python, requests"]
+dependencies = ["rembg, timm, opencv-python, requests, py-cpuinfo, pynvml"]
[project.urls]
Repository = "https://github.com/kk8bit/KayTool"
diff --git a/requirements.txt b/requirements.txt
index f3a3f29..2145c7a 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,4 +1,6 @@
rembg
timm
opencv-python
-requests
\ No newline at end of file
+requests
+py-cpuinfo
+pynvml
\ No newline at end of file
diff --git a/web/resourcemonitor.js b/web/resourcemonitor.js
new file mode 100644
index 0000000..596b8eb
--- /dev/null
+++ b/web/resourcemonitor.js
@@ -0,0 +1,563 @@
+import { app } from "../../../scripts/app.js";
+
+const KayResourceMonitor = {
+ toolbar: null,
+ chartCanvas: null,
+ dataDisplay: null,
+ menuButton: null,
+
+ dataHistory: { cpu: [], ram: [], gpu: [], gpuMem: [] },
+ displayHistory: { cpu: [], ram: [], gpu: [], gpuMem: [] },
+ current: {
+ cpu: 0, ram: 0, gpu: 0, gpuMem: 0,
+ ramUsed: 0, ramTotal: 0, gpuMemUsed: 0, gpuMemTotal: 0
+ },
+ target: {
+ cpu: 0, ram: 0, gpu: 0, gpuMem: 0,
+ ramTotal: 0, ramUsed: 0, gpuMemTotal: 0, gpuMemUsed: 0,
+ cpuName: "Unknown", gpuName: "Unknown"
+ },
+
+ cpuCores: 4,
+ dragState: { isDragging: false, offsetX: 0, offsetY: 0 },
+ resizeState: { isResizing: false, direction: null, startX: 0, startY: 0, startWidth: 0, startHeight: 0 },
+ position: { left: 0, top: 0 },
+ size: { width: 250, height: 200 },
+ lastUpdate: 0, lastCurveUpdate: 0, lastDisplayUpdate: 0,
+ maxPoints: 6000,
+ fetchInterval: 500,
+ curveInterval: 0,
+ displayInterval: 0,
+ smoothFactor: 0.01,
+ minWidth: 150,
+ minHeight: 100,
+ maxHeight: 200,
+ edgeThreshold: 10,
+
+ colors: {
+ cpu: 'rgb(232, 166, 0)',
+ ram: 'rgb(88, 207, 3)',
+ gpu: 'rgb(224, 0, 153)',
+ gpuMem: 'rgb(0, 115, 255)'
+ },
+
+ styles: {
+ toolbar: `position: fixed; display: flex; flex-direction: column; color: rgba(186, 186, 186, 0.8); padding: 10px; border-radius: 5px; z-index: 10000; user-select: none; pointer-events: auto; max-height: 200px;`,
+ header: `cursor: grab; margin-bottom: 10px; font-weight: bold; font-size: 10px;`,
+ canvas: `margin-bottom: 10px; width: 100%; height: 100px;`,
+ display: `display: flex; flex-direction: column; font-size: 10px; flex-grow: 1; overflow: hidden;`,
+ dot: (color) => `display: inline-block; width: 3px; height: 3px; border-radius: 50%; background: ${color}; margin-right: 5px; flex-shrink: 0;`,
+ bar: (width) => `display: inline-block; width: ${width}px; height: 3px; background: rgba(200, 200, 200, 0.3); margin-right: 5px; position: relative; flex-shrink: 0;`,
+ fill: (color, percent) => `position: absolute; top: 0; left: 0; width: ${percent}%; height: 100%; background: ${color};`,
+ row: `display: flex; align-items: center; height: 12px; white-space: nowrap;`,
+ text: `overflow: hidden; text-overflow: ellipsis;`
+ },
+
+ isVisible: true,
+ animationFrameId: null,
+ isEnabled: true,
+ isInitialized: false,
+ edgeFadeEnabled: true,
+
+ async init() {
+ if (this.isInitialized) return;
+ this.isInitialized = true;
+
+ this.loadVisibility();
+ this.startMonitoring();
+ this.bindEvents();
+
+ await this.loadSettings();
+ this.setupUI();
+ },
+
+ async loadSettings() {
+ this.isEnabled = app.ui.settings.getSettingValue("KayTool.EnableResourceMonitor");
+ this.edgeFadeEnabled = app.ui.settings.getSettingValue("KayTool.ResourceMonitorEdgeFade");
+ },
+
+ loadVisibility() {
+ const visible = localStorage.getItem('KayResourceMonitorVisible');
+ this.isVisible = visible === null ? true : visible === 'true';
+ },
+
+ saveVisibility() {
+ localStorage.setItem('KayResourceMonitorVisible', this.isVisible.toString());
+ },
+
+ setupUI() {
+ this.toolbar = document.createElement('div');
+ this.toolbar.id = 'kay-resource-monitor';
+ const opacity = app.ui.settings.getSettingValue("KayTool.ResourceMonitorBackgroundOpacity") / 100;
+ this.toolbar.style.cssText = `${this.styles.toolbar} width: ${this.size.width}px; height: ${this.size.height}px; left: ${this.position.left}px; top: ${this.position.top}px; display: ${this.isVisible && this.isEnabled ? 'flex' : 'none'}; background: rgba(0, 0, 0, ${opacity});`;
+
+ const header = document.createElement('div');
+ header.style.cssText = this.styles.header;
+ header.textContent = "𝙆 Resource Monitor";
+ this.toolbar.appendChild(header);
+
+ this.chartCanvas = document.createElement('canvas');
+ this.chartCanvas.style.cssText = this.styles.canvas;
+ this.chartCanvas.width = this.size.width - 20;
+ this.chartCanvas.height = 100;
+ this.toolbar.appendChild(this.chartCanvas);
+
+ this.dataDisplay = document.createElement('div');
+ this.dataDisplay.style.cssText = this.styles.display;
+ this.toolbar.appendChild(this.dataDisplay);
+
+ document.body.appendChild(this.toolbar);
+ this.loadPosition();
+ this.loadSize();
+ this.onResize();
+ this.bindToolbarEvents();
+
+ if (this.isEnabled && this.isVisible) {
+ this.startAnimation();
+ }
+ },
+
+ show() {
+ this.isVisible = true;
+ if (this.toolbar && this.isEnabled) {
+ this.toolbar.style.display = 'flex';
+ this.refreshCanvas();
+ this.startAnimation();
+ }
+ this.saveVisibility();
+ },
+
+ hide() {
+ this.isVisible = false;
+ if (this.toolbar) {
+ this.toolbar.style.display = 'none';
+ this.stopAnimation();
+ }
+ this.saveVisibility();
+ },
+
+ updateEnabledState(enabled) {
+ this.isEnabled = enabled;
+ if (this.menuButton) {
+ this.menuButton.style.display = enabled ? '' : 'none';
+ }
+ if (this.toolbar) {
+ this.toolbar.style.display = enabled && this.isVisible ? 'flex' : 'none';
+ if (enabled && this.isVisible) {
+ this.refreshCanvas();
+ this.startAnimation();
+ } else {
+ this.stopAnimation();
+ }
+ }
+ },
+
+ refreshCanvas() {
+ if (this.chartCanvas) {
+ const headerHeight = this.toolbar.firstChild.getBoundingClientRect().height + 10;
+ const dataHeight = this.dataDisplay.clientHeight;
+ this.chartCanvas.width = this.toolbar.clientWidth - 20;
+ this.chartCanvas.height = this.toolbar.clientHeight - headerHeight - dataHeight - 10;
+ }
+ },
+
+ async fetchResources() {
+ try {
+ const response = await fetch('/kaytool/resources', { timeout: 5000 });
+ if (!response.ok) throw new Error(`HTTP error: ${response.status}`);
+ const data = await response.json();
+ this.updateTarget(data);
+ } catch (error) {
+ this.updateTarget({
+ cpu_percent: 0,
+ cpu_count: this.cpuCores,
+ cpu_name: "Unknown",
+ ram_total: 0,
+ ram_used: 0,
+ ram_percent: 0,
+ gpu: "Fetch failed"
+ });
+ }
+ },
+
+ updateTarget(data) {
+ this.target.cpu = data.cpu_percent || 0;
+ this.cpuCores = data.cpu_count || 4;
+ this.target.ram = data.ram_percent || 0;
+ this.target.ramTotal = data.ram_total || 0;
+ this.target.ramUsed = data.ram_used || 0;
+ this.target.cpuName = data.cpu_name || "Unknown";
+ this.dataHistory.cpu.push(this.target.cpu);
+ this.dataHistory.ram.push(this.target.ram);
+
+ if (data.gpu && typeof data.gpu !== 'string' && data.gpu.length > 0) {
+ this.target.gpu = data.gpu[0].load || 0;
+ this.target.gpuMem = data.gpu[0].memory_percent || 0;
+ this.target.gpuMemTotal = data.gpu[0].memory_total || 0;
+ this.target.gpuMemUsed = data.gpu[0].memory_used || 0;
+ this.target.gpuName = data.gpu[0].name || "Unknown";
+ this.dataHistory.gpu.push(this.target.gpu);
+ this.dataHistory.gpuMem.push(this.target.gpuMem);
+ } else {
+ this.target.gpu = 0;
+ this.target.gpuMem = 0;
+ this.target.gpuMemTotal = 0;
+ this.target.gpuMemUsed = 0;
+ this.target.gpuName = "Unknown";
+ this.dataHistory.gpu.push(0);
+ this.dataHistory.gpuMem.push(0);
+ }
+
+ if (this.dataHistory.cpu.length > this.maxPoints) {
+ this.dataHistory.cpu.shift();
+ this.dataHistory.ram.shift();
+ this.dataHistory.gpu.shift();
+ this.dataHistory.gpuMem.shift();
+ }
+ },
+
+ updateDisplay() {
+ const { cpu, ram, gpu, gpuMem, ramUsed, ramTotal, gpuMemUsed, gpuMemTotal } = this.current;
+ const { styles, colors } = this;
+ this.dataDisplay.innerHTML = [
+ this.renderRow('CPU', colors.cpu, cpu, `${cpu.toFixed(1)}% (${this.cpuCores} cores) - ${this.target.cpuName}`),
+ this.renderRow('RAM', colors.ram, ram, `${ramUsed.toFixed(1)}/${ramTotal.toFixed(1)}GB (${ram.toFixed(1)}%)`),
+ this.target.gpu || this.target.gpuMem
+ ? [
+ this.renderRow('GPU', colors.gpu, gpu, `${gpu.toFixed(1)}% - ${this.target.gpuName}`),
+ this.renderRow('VRAM', colors.gpuMem, gpuMem, `${gpuMemUsed.toFixed(1)}/${gpuMemTotal.toFixed(1)}GB (${gpuMem.toFixed(1)}%)`)
+ ].join('')
+ : [
+ this.renderRow('GPU', colors.gpu, 0, 'N/A'),
+ this.renderRow('VRAM', colors.gpuMem, 0, 'N/A')
+ ].join('')
+ ].join('');
+ },
+
+ renderRow(label, color, value, text) {
+ const { styles } = this;
+ const containerWidth = this.toolbar.clientWidth - 20;
+ const minBarWidth = 50;
+ const maxBarWidth = 200;
+ const fixedSpacing = 3 + 5 + 5;
+ const availableWidth = containerWidth - fixedSpacing;
+ const barWidth = Math.min(maxBarWidth, Math.max(minBarWidth, availableWidth * 0.3));
+
+ const textAvailableWidth = containerWidth - fixedSpacing - barWidth;
+ const canvas = document.createElement('canvas');
+ const ctx = canvas.getContext('2d');
+ ctx.font = '10px sans-serif';
+ const textWidth = ctx.measureText(`${label}: ${text}`).width;
+ let displayText = `${label}: ${text}`;
+ if (textWidth > textAvailableWidth) {
+ const ellipsisWidth = ctx.measureText('...').width;
+ let truncatedText = `${label}: `;
+ let remainingWidth = textAvailableWidth - ctx.measureText(truncatedText).width - ellipsisWidth;
+ for (let i = 0; i < text.length; i++) {
+ const charWidth = ctx.measureText(text[i]).width;
+ if (remainingWidth < charWidth) {
+ truncatedText += '...';
+ break;
+ }
+ truncatedText += text[i];
+ remainingWidth -= charWidth;
+ }
+ displayText = truncatedText;
+ }
+ return `
+
+
+ ${displayText}
+
`;
+ },
+
+ animate() {
+ if (!this.isVisible || !this.isEnabled || !this.toolbar) return;
+
+ const now = performance.now();
+
+ if (now - this.lastUpdate >= this.fetchInterval) {
+ this.fetchResources();
+ this.lastUpdate = now;
+ }
+
+ for (const key in this.current) {
+ if (this.current[key] === 0 && this.target[key] !== 0) {
+ this.current[key] = this.target[key];
+ } else {
+ this.current[key] += (this.target[key] - this.current[key]) * this.smoothFactor;
+ }
+ }
+
+ if (now - this.lastCurveUpdate >= this.curveInterval) {
+ for (const key in this.displayHistory) {
+ this.displayHistory[key].push(this.current[key]);
+ if (this.displayHistory[key].length > this.maxPoints) this.displayHistory[key].shift();
+ }
+ this.lastCurveUpdate = now;
+ }
+
+ if (now - this.lastDisplayUpdate >= this.displayInterval) {
+ this.updateDisplay();
+ this.lastDisplayUpdate = now;
+ }
+
+ if (typeof this.drawCurves === 'function') {
+ this.drawCurves();
+ }
+
+ this.animationFrameId = requestAnimationFrame(() => this.animate());
+ },
+
+ startAnimation() {
+ if (!this.animationFrameId && this.isEnabled && this.isVisible && this.toolbar) {
+ this.lastUpdate = performance.now();
+ this.lastCurveUpdate = performance.now();
+ this.lastDisplayUpdate = performance.now();
+ this.animationFrameId = requestAnimationFrame(() => this.animate());
+ }
+ },
+
+ stopAnimation() {
+ if (this.animationFrameId) {
+ cancelAnimationFrame(this.animationFrameId);
+ this.animationFrameId = null;
+ }
+ },
+
+ drawCurves() {
+ const ctx = this.chartCanvas.getContext('2d');
+ const w = this.chartCanvas.width;
+ const h = this.chartCanvas.height;
+
+ ctx.clearRect(0, 0, w, h);
+
+ ctx.strokeStyle = 'rgba(255, 255, 255, 0.15)';
+ ctx.lineWidth = 0.5;
+ ctx.beginPath();
+ for (let y = 0; y <= h; y += h / 4) {
+ ctx.moveTo(0, y);
+ ctx.lineTo(w, y);
+ }
+ ctx.stroke();
+
+ const step = w / (this.maxPoints - 1);
+ const { colors } = this;
+ [
+ { data: this.displayHistory.cpu, color: colors.cpu },
+ { data: this.displayHistory.ram, color: colors.ram },
+ { data: this.displayHistory.gpu, color: colors.gpu },
+ { data: this.displayHistory.gpuMem, color: colors.gpuMem }
+ ].forEach(({ data, color }) => {
+ ctx.strokeStyle = color;
+ ctx.lineWidth = 0.8;
+ ctx.beginPath();
+ data.forEach((v, i) => {
+ const x = i * step;
+ const y = h - (v / 100) * h;
+ if (i === 0) ctx.moveTo(x, y);
+ else ctx.lineTo(x, y);
+ });
+ ctx.stroke();
+ });
+
+ if (this.edgeFadeEnabled) {
+ const gradient = ctx.createLinearGradient(0, 0, w, 0);
+ gradient.addColorStop(0, 'rgba(255, 255, 255, 0)');
+ gradient.addColorStop(0.1, 'rgba(255, 255, 255, 1)');
+ gradient.addColorStop(0.9, 'rgba(255, 255, 255, 1)');
+ gradient.addColorStop(1, 'rgba(255, 255, 255, 0)');
+
+ ctx.save();
+ ctx.globalCompositeOperation = 'destination-in';
+ ctx.fillStyle = gradient;
+ ctx.fillRect(0, 0, w, h);
+ ctx.restore();
+ }
+ },
+
+ startMonitoring() {
+ for (const key in this.displayHistory) {
+ this.displayHistory[key] = Array(this.maxPoints).fill(0);
+ }
+ },
+
+ bindEvents() {
+ document.addEventListener('mousemove', (e) => {
+ if (this.dragState.isDragging) this.onDrag(e);
+ if (this.resizeState.isResizing) this.onResizeDrag(e);
+ });
+ document.addEventListener('mouseup', (e) => {
+ if (this.dragState.isDragging) this.endDrag();
+ if (this.resizeState.isResizing) this.endResize();
+ });
+ document.addEventListener('selectstart', (e) => (this.dragState.isDragging || this.resizeState.isResizing) && e.preventDefault());
+ window.addEventListener('resize', () => this.onResize());
+ },
+
+ bindToolbarEvents() {
+ if (this.toolbar) {
+ this.toolbar.addEventListener('mousemove', (e) => this.onMouseMove(e));
+ this.toolbar.addEventListener('mousedown', (e) => {
+ if (e.target.style.cursor === 'grab') this.startDrag(e);
+ else if (['e-resize', 's-resize', 'se-resize'].includes(e.target.style.cursor)) this.startResize(e, e.target.style.cursor.split('-')[0]);
+ });
+ }
+ },
+
+ loadPosition() {
+ const pos = JSON.parse(localStorage.getItem('KayResourceMonitorPosition')) || {};
+ this.position.left = pos.left || 0;
+ this.position.top = pos.top || 0;
+ this.toolbar.style.left = `${this.position.left}px`;
+ this.toolbar.style.top = `${this.position.top}px`;
+ },
+
+ loadSize() {
+ const size = JSON.parse(localStorage.getItem('KayResourceMonitorSize')) || {};
+ this.size.width = Math.max(size.width || 250, this.minWidth);
+ this.size.height = Math.max(size.height || 200, this.minHeight);
+ this.toolbar.style.width = `${this.size.width}px`;
+ this.toolbar.style.height = `${this.size.height}px`;
+ },
+
+ savePositionAndSize() {
+ localStorage.setItem('KayResourceMonitorPosition', JSON.stringify(this.position));
+ localStorage.setItem('KayResourceMonitorSize', JSON.stringify(this.size));
+ },
+
+ onResize() {
+ if (!this.toolbar) return;
+ const winW = window.innerWidth;
+ const winH = window.innerHeight;
+ this.position.left = Math.max(0, Math.min(this.position.left, winW - this.size.width));
+ this.position.top = Math.max(0, Math.min(this.position.top, winH - this.size.height));
+ this.toolbar.style.left = `${this.position.left}px`;
+ this.toolbar.style.top = `${this.position.top}px`;
+ this.chartCanvas.width = this.toolbar.clientWidth - 20;
+ const headerHeight = this.toolbar.firstChild.getBoundingClientRect().height + 10;
+ const dataHeight = this.dataDisplay.clientHeight;
+ this.chartCanvas.height = this.toolbar.clientHeight - headerHeight - dataHeight - 10;
+ this.updateDisplay();
+ },
+
+ onMouseMove(e) {
+ if (!this.toolbar || !this.toolbar.contains(e.target)) return;
+
+ if (this.dragState.isDragging) {
+ this.onDrag(e);
+ return;
+ }
+ if (this.resizeState.isResizing) {
+ this.onResizeDrag(e);
+ return;
+ }
+
+ const rect = this.toolbar.getBoundingClientRect();
+ const x = e.clientX - rect.left;
+ const y = e.clientY - rect.top;
+ const nearRight = x >= rect.width - this.edgeThreshold && x <= rect.width;
+ const nearBottom = y >= rect.height - this.edgeThreshold && y <= rect.height;
+
+ if (e.target.style.cursor === 'grab') {
+ this.toolbar.style.cursor = 'grab';
+ } else if (nearRight && nearBottom) {
+ this.toolbar.style.cursor = 'se-resize';
+ } else if (nearRight) {
+ this.toolbar.style.cursor = 'e-resize';
+ } else if (nearBottom) {
+ this.toolbar.style.cursor = 's-resize';
+ } else {
+ this.toolbar.style.cursor = 'default';
+ }
+ },
+
+ startDrag(e) {
+ e.preventDefault();
+ const rect = this.toolbar.getBoundingClientRect();
+ this.dragState.isDragging = true;
+ this.dragState.offsetX = e.clientX - rect.left;
+ this.dragState.offsetY = e.clientY - rect.top;
+ this.toolbar.style.cursor = 'grabbing';
+ },
+
+ onDrag(e) {
+ if (!this.dragState.isDragging) return;
+ const winW = window.innerWidth;
+ const winH = window.innerHeight;
+ this.position.left = Math.max(0, Math.min(e.clientX - this.dragState.offsetX, winW - this.size.width));
+ this.position.top = Math.max(0, Math.min(e.clientY - this.dragState.offsetY, winH - this.size.height));
+ this.toolbar.style.left = `${this.position.left}px`;
+ this.toolbar.style.top = `${this.position.top}px`;
+ },
+
+ endDrag() {
+ if (!this.dragState.isDragging) return;
+ this.dragState.isDragging = false;
+ this.toolbar.style.cursor = 'default';
+ this.savePositionAndSize();
+ },
+
+ startResize(e, direction) {
+ e.preventDefault();
+ this.resizeState.isResizing = true;
+ this.resizeState.direction = direction;
+ this.resizeState.startX = e.clientX;
+ this.resizeState.startY = e.clientY;
+ this.resizeState.startWidth = this.toolbar.clientWidth;
+ this.resizeState.startHeight = this.toolbar.clientHeight;
+ this.toolbar.style.cursor = `${direction}-resize`;
+ },
+
+ onResizeDrag(e) {
+ if (!this.resizeState.isResizing) return;
+ const dx = e.clientX - this.resizeState.startX;
+ const dy = e.clientY - this.resizeState.startY;
+
+ if (this.resizeState.direction === 'e' || this.resizeState.direction === 'se') {
+ this.size.width = Math.max(this.minWidth, this.resizeState.startWidth + dx);
+ this.toolbar.style.width = `${this.size.width}px`;
+ }
+ if (this.resizeState.direction === 's' || this.resizeState.direction === 'se') {
+ this.size.height = Math.min(this.maxHeight, Math.max(this.minHeight, this.resizeState.startHeight + dy));
+ this.toolbar.style.height = `${this.size.height}px`;
+ }
+ this.onResize();
+ },
+
+ endResize() {
+ if (!this.resizeState.isResizing) return;
+ this.resizeState.isResizing = false;
+ this.resizeState.direction = null;
+ this.toolbar.style.cursor = 'default';
+ this.savePositionAndSize();
+ }
+};
+
+app.registerExtension({
+ name: "KayTool.ResourceMonitor",
+ async setup() {
+ await KayResourceMonitor.init();
+
+ const showMenuButton = new (await import("/scripts/ui/components/button.js")).ComfyButton({
+ content: "𝙆 Monitor",
+ action: () => {
+ if (KayResourceMonitor.isVisible) {
+ KayResourceMonitor.hide();
+ showMenuButton.tooltip = "Show Monitor";
+ } else {
+ KayResourceMonitor.show();
+ showMenuButton.tooltip = "Hide Monitor";
+ }
+ },
+ tooltip: KayResourceMonitor.isVisible ? "Hide Monitor" : "Show Monitor"
+ });
+
+ KayResourceMonitor.menuButton = showMenuButton.element;
+ if (app.menu?.settingsGroup) {
+ app.menu.settingsGroup.append(showMenuButton);
+ }
+ KayResourceMonitor.updateEnabledState(KayResourceMonitor.isEnabled);
+ window.KayResourceMonitor = KayResourceMonitor;
+ }
+});
\ No newline at end of file
diff --git a/web/settings.js b/web/settings.js
index de52547..7055769 100644
--- a/web/settings.js
+++ b/web/settings.js
@@ -1,204 +1,243 @@
import { app } from "../../../scripts/app.js";
-
+
app.registerExtension({
name: "KayTool.Settings",
- setup() {
- app.ui.settings.addSetting({
- id: "KayTool.ShowRunOption",
- name: "Show '▶️ Run' option in node context menu",
- type: "boolean",
- defaultValue: true,
- category: ["KayTool", "▶️ Run", "ShowRunOption"],
- });
-
- app.ui.settings.addSetting({
- id: "KayTool.ShowSetGetOptions",
- name: "Show 'Set/Get' options in node context menu",
- type: "boolean",
- defaultValue: true,
- category: ["KayTool", "🛜 Set/Get", "ShowSetGetOptions"],
- tooltip: "Toggles visibility of 'Set/Get' options in node context menus."
- });
-
- app.ui.settings.addSetting({
- id: "KayTool.ShiftR",
- name: "Use 'Shift+R' to quickly run selected node",
- type: "boolean",
- defaultValue: true,
- category: ["KayTool", "▶️ Run", "ShiftR"],
- });
-
- app.ui.settings.addSetting({
- id: "KayTool.ShowWorkflowPNG",
- name: "Show 'Workflow PNG' option in KayTool menu",
- type: "boolean",
- defaultValue: true,
- category: ["KayTool", "Workflow PNG", "ShowWorkflowPNG"],
- });
-
- app.ui.settings.addSetting({
- id: "KayTool.ShowStarToMe",
- name: "Show 'Star to me' option in KayTool menu",
- type: "boolean",
- defaultValue: true,
- category: ["KayTool", "Menu", "ShowStarToMe"],
- });
-
- app.ui.settings.addSetting({
- id: "KayTool.WorkflowPNG",
- name: "Margin size for Workflow PNG export",
- type: "slider",
- defaultValue: 100,
- attrs: { min: 0, max: 200, step: 10 },
- category: ["KayTool", "Workflow PNG", "MarginSize"],
- tooltip: "Default value: 100."
- });
-
- app.ui.settings.addSetting({
- id: "KayTool.SetGetForegroundColor",
- name: "Set/Get Node Foreground Color",
- type: "color",
- defaultValue: "000000",
- category: ["KayTool", "🛜 Set/Get", "ForegroundColor"],
- onChange: (newVal) => {
- if (/^[0-9A-Fa-f]{6}$/.test(newVal)) {
- updateSetGetNodeColors();
- if (app.graph) app.graph.setDirtyCanvas(true, true);
+ async setup() {
+ const settings = [
+ {
+ id: "KayTool.ShowRunOption",
+ name: "Show '▶️ Run' option in node context menu",
+ type: "boolean",
+ defaultValue: true,
+ category: ["KayTool", "▶️ Run", "ShowRunOption"],
+ },
+ {
+ id: "KayTool.ShowSetGetOptions",
+ name: "Show 'Set/Get' options in node context menu",
+ type: "boolean",
+ defaultValue: true,
+ category: ["KayTool", "🛜 Set/Get", "ShowSetGetOptions"],
+ tooltip: "Toggles visibility of 'Set/Get' options in node context menus."
+ },
+ {
+ id: "KayTool.ShiftR",
+ name: "Use 'Shift+R' to quickly run selected node",
+ type: "boolean",
+ defaultValue: true,
+ category: ["KayTool", "▶️ Run", "ShiftR"],
+ },
+ {
+ id: "KayTool.ShowWorkflowPNG",
+ name: "Show 'Workflow PNG' option in KayTool menu",
+ type: "boolean",
+ defaultValue: true,
+ category: ["KayTool", "Workflow PNG", "ShowWorkflowPNG"],
+ },
+ {
+ id: "KayTool.ShowStarToMe",
+ name: "Show 'Star to me' option in KayTool menu",
+ type: "boolean",
+ defaultValue: true,
+ category: ["KayTool", "Menu", "ShowStarToMe"],
+ },
+ {
+ id: "KayTool.WorkflowPNG",
+ name: "Margin size for Workflow PNG export",
+ type: "slider",
+ defaultValue: 100,
+ attrs: { min: 0, max: 200, step: 10 },
+ category: ["KayTool", "Workflow PNG", "MarginSize"],
+ tooltip: "Default value: 100."
+ },
+ {
+ id: "KayTool.SetGetForegroundColor",
+ name: "Set/Get Node Foreground Color",
+ type: "color",
+ defaultValue: "000000",
+ category: ["KayTool", "🛜 Set/Get", "ForegroundColor"],
+ onChange: (newVal) => {
+ if (/^[0-9A-Fa-f]{6}$/.test(newVal)) {
+ updateSetGetNodeColors();
+ if (app.graph) app.graph.setDirtyCanvas(true, true);
+ }
}
- }
- });
-
- app.ui.settings.addSetting({
- id: "KayTool.SetGetBackgroundColor",
- name: "Set/Get Node Background Color",
- type: "color",
- defaultValue: "000000",
- category: ["KayTool", "🛜 Set/Get", "BackgroundColor"],
- onChange: (newVal) => {
- if (/^[0-9A-Fa-f]{6}$/.test(newVal)) {
- updateSetGetNodeColors();
- if (app.graph) app.graph.setDirtyCanvas(true, true);
+ },
+ {
+ id: "KayTool.SetGetBackgroundColor",
+ name: "Set/Get Node Background Color",
+ type: "color",
+ defaultValue: "000000",
+ category: ["KayTool", "🛜 Set/Get", "BackgroundColor"],
+ onChange: (newVal) => {
+ if (/^[0-9A-Fa-f]{6}$/.test(newVal)) {
+ updateSetGetNodeColors();
+ if (app.graph) app.graph.setDirtyCanvas(true, true);
+ }
}
- }
- });
+ },
+ {
+ id: "KayTool.NodeAlignDisplayMode",
+ name: "Node Alignment Toolbar Display Mode",
+ type: "combo",
+ options: [
+ { value: "permanent", text: "Permanent" },
+ { value: "on-select", text: "Show on Node Selection" },
+ { value: "disabled", text: "Disabled" }
+ ],
+ defaultValue: "permanent",
+ category: ["KayTool", "NodeAlignment", "DisplayMode"],
+ onChange: (value) => {
+ const manager = window.KayNodeAlignmentManager;
+ const initFn = window.initializeKayNodeAlignment;
+ if (!manager || !initFn) return;
- app.ui.settings.addSetting({
- id: "KayTool.NodeAlignDisplayMode",
- name: "Node Alignment Toolbar Display Mode",
- type: "combo",
- options: [
- { value: "permanent", text: "Permanent" },
- { value: "on-select", text: "Show on Node Selection" },
- { value: "disabled", text: "Disabled" }
- ],
- defaultValue: "permanent",
- category: ["KayTool", "NodeAlignment", "DisplayMode"],
- onChange: (value) => {
- const manager = window.KayNodeAlignmentManager;
- const initFn = window.initializeKayNodeAlignment;
- if (!manager || !initFn) return;
-
- if (!manager.isInitialized) {
- initFn();
+ if (!manager.isInitialized) {
+ initFn();
+ }
+ manager.updateDisplayMode(value);
}
- manager.updateDisplayMode(value); //
- }
- });
-
- app.ui.settings.addSetting({
- id: "KayTool.EnableAlignmentShortcuts",
- name: "Enable Shift+WASD for Quick Alignment (Up/Left/Down/Right)",
- type: "boolean",
- defaultValue: true,
- category: ["KayTool", "NodeAlignment", "Shortcuts"],
- tooltip: "Use Shift+W (Up), Shift+A (Left), Shift+S (Down), Shift+D (Right) to align selected nodes."
- });
-
- app.ui.settings.addSetting({
- id: "KayTool.NodeAlignBackgroundOpacity",
- name: "Node Alignment Toolbar Background Opacity",
- type: "slider",
- defaultValue: 100,
- attrs: { min: 0, max: 100, step: 1 },
- category: ["KayTool", "NodeAlignment", "BackgroundOpacity"],
- onChange: (newVal) => {
- const toolbar = document.getElementById('kay-node-alignment-toolbar');
- if (toolbar) {
- const bgColor = app.ui.settings.getSettingValue("KayTool.NodeAlignBackgroundColor");
+ },
+ {
+ id: "KayTool.EnableAlignmentShortcuts",
+ name: "Enable Shift+WASD for Quick Alignment (Up/Left/Down/Right)",
+ type: "boolean",
+ defaultValue: true,
+ category: ["KayTool", "NodeAlignment", "Shortcuts"],
+ tooltip: "Use Shift+W (Up), Shift+A (Left), Shift+S (Down), Shift+D (Right) to align selected nodes."
+ },
+ {
+ id: "KayTool.NodeAlignBackgroundOpacity",
+ name: "Node Alignment Toolbar Background Opacity",
+ type: "slider",
+ defaultValue: 100,
+ attrs: { min: 0, max: 100, step: 1 },
+ category: ["KayTool", "NodeAlignment", "BackgroundOpacity"],
+ onChange: (newVal) => {
+ const toolbar = document.getElementById('kay-node-alignment-toolbar');
+ if (toolbar) {
+ const bgColor = app.ui.settings.getSettingValue("KayTool.NodeAlignBackgroundColor");
+ const opacity = newVal / 100;
+ if (opacity > 0 && /^[0-9A-Fa-f]{6}$/.test(bgColor)) {
+ toolbar.style.background = `rgba(${parseInt(bgColor.substr(0, 2), 16)}, ${parseInt(bgColor.substr(2, 2), 16)}, ${parseInt(bgColor.substr(4, 2), 16)}, ${opacity})`;
+ } else {
+ toolbar.style.background = '';
+ }
+ }
+ }
+ },
+ {
+ id: "KayTool.NodeAlignBackgroundColor",
+ name: "Node Alignment Toolbar Background Color",
+ type: "color",
+ defaultValue: "000000",
+ category: ["KayTool", "NodeAlignment", "BackgroundColor"],
+ onChange: (newVal) => {
+ const toolbar = document.getElementById('kay-node-alignment-toolbar');
+ if (toolbar && /^[0-9A-Fa-f]{6}$/.test(newVal)) {
+ const opacity = app.ui.settings.getSettingValue("KayTool.NodeAlignBackgroundOpacity") / 100;
+ if (opacity > 0) {
+ toolbar.style.background = `rgba(${parseInt(newVal.substr(0, 2), 16)}, ${parseInt(newVal.substr(2, 2), 16)}, ${parseInt(newVal.substr(4, 2), 16)}, ${opacity})`;
+ } else {
+ toolbar.style.background = '';
+ }
+ }
+ }
+ },
+ {
+ id: "KayTool.NodeAlignIconBackgroundColor",
+ name: "Node Alignment Icon Background Color",
+ type: "color",
+ defaultValue: "2b2b2b",
+ category: ["KayTool", "NodeAlignment", "IconBackgroundColor"],
+ tooltip: "Use parameter “363636” to match ComfyUI menu bar color for an icon-free background effect",
+ onChange: (newVal) => {
+ if (/^[0-9A-Fa-f]{6}$/.test(newVal)) {
+ const buttons = document.querySelectorAll('.kay-align-button');
+ buttons.forEach(btn => btn.style.backgroundColor = `#${newVal}`);
+ }
+ }
+ },
+ {
+ id: "KayTool.NodeAlignIconColor",
+ name: "Node Alignment Icon Color",
+ type: "color",
+ defaultValue: "666666",
+ category: ["KayTool", "NodeAlignment", "IconColor"],
+ onChange: (newVal) => {
+ if (/^[0-9A-Fa-f]{6}$/.test(newVal)) {
+ const buttons = document.querySelectorAll('.kay-align-button');
+ buttons.forEach(btn => {
+ const svg = btn.querySelector('svg');
+ if (svg) svg.querySelectorAll('path').forEach(path => path.setAttribute('fill', `#${newVal}`));
+ });
+ }
+ }
+ },
+ {
+ id: "KayTool.NodeAlignDividerColor",
+ name: "Node Alignment Divider Color",
+ type: "color",
+ defaultValue: "1e1e1e",
+ category: ["KayTool", "NodeAlignment", "DividerColor"],
+ onChange: (newVal) => {
+ if (/^[0-9A-Fa-f]{6}$/.test(newVal)) {
+ const dividers = document.querySelectorAll('.kay-toolbar-divider');
+ dividers.forEach(divider => divider.style.background = `#${newVal}`);
+ }
+ }
+ },
+ {
+ id: "KayTool.EnableResourceMonitor",
+ name: "Enable Resource Monitor button in menu",
+ type: "boolean",
+ defaultValue: true,
+ category: ["KayTool", "Resource Monitor", "EnableResourceMonitor"],
+ onChange: (newVal) => {
+ if (window.KayResourceMonitor) {
+ window.KayResourceMonitor.updateEnabledState(newVal);
+ }
+ }
+ },
+ {
+ id: "KayTool.ResourceMonitorEdgeFade",
+ name: "Enable Resource Monitor Chart Edge Fade",
+ type: "boolean",
+ defaultValue: true,
+ category: ["KayTool", "Resource Monitor", "EdgeFade"],
+ onChange: (newVal) => {
+ if (window.KayResourceMonitor) {
+ window.KayResourceMonitor.edgeFadeEnabled = newVal;
+ if (window.KayResourceMonitor.isVisible && window.KayResourceMonitor.isEnabled) {
+ window.KayResourceMonitor.drawCurves();
+ }
+ }
+ }
+ },
+ {
+ id: "KayTool.ResourceMonitorBackgroundOpacity",
+ name: "Resource Monitor Background Opacity",
+ type: "slider",
+ defaultValue: 80,
+ attrs: { min: 0, max: 100, step: 1 },
+ category: ["KayTool", "Resource Monitor", "BackgroundOpacity"],
+ onChange: (newVal) => {
const opacity = newVal / 100;
- if (opacity > 0 && /^[0-9A-Fa-f]{6}$/.test(bgColor)) {
- toolbar.style.background = `rgba(${parseInt(bgColor.substr(0, 2), 16)}, ${parseInt(bgColor.substr(2, 2), 16)}, ${parseInt(bgColor.substr(4, 2), 16)}, ${opacity})`;
- } else {
- toolbar.style.background = '';
+ if (window.KayResourceMonitor && window.KayResourceMonitor.toolbar) {
+ window.KayResourceMonitor.toolbar.style.background = `rgba(0, 0, 0, ${opacity})`;
}
}
}
- });
+ ];
- app.ui.settings.addSetting({
- id: "KayTool.NodeAlignBackgroundColor",
- name: "Node Alignment Toolbar Background Color",
- type: "color",
- defaultValue: "000000",
- category: ["KayTool", "NodeAlignment", "BackgroundColor"],
- onChange: (newVal) => {
- const toolbar = document.getElementById('kay-node-alignment-toolbar');
- if (toolbar && /^[0-9A-Fa-f]{6}$/.test(newVal)) {
- const opacity = app.ui.settings.getSettingValue("KayTool.NodeAlignBackgroundOpacity") / 100;
- if (opacity > 0) {
- toolbar.style.background = `rgba(${parseInt(newVal.substr(0, 2), 16)}, ${parseInt(newVal.substr(2, 2), 16)}, ${parseInt(newVal.substr(4, 2), 16)}, ${opacity})`;
- } else {
- toolbar.style.background = '';
- }
- }
- }
- });
- app.ui.settings.addSetting({
- id: "KayTool.NodeAlignIconBackgroundColor",
- name: "Node Alignment Icon Background Color",
- type: "color",
- defaultValue: "2b2b2b",
- category: ["KayTool", "NodeAlignment", "IconBackgroundColor"],
- tooltip: "Use parameter “363636” to match ComfyUI menu bar color for an icon-free background effect",
- onChange: (newVal) => {
- if (/^[0-9A-Fa-f]{6}$/.test(newVal)) {
- const buttons = document.querySelectorAll('.kay-align-button');
- buttons.forEach(btn => btn.style.backgroundColor = `#${newVal}`);
- }
- }
- });
+ for (const setting of settings) {
+ app.ui.settings.addSetting(setting);
- app.ui.settings.addSetting({
- id: "KayTool.NodeAlignIconColor",
- name: "Node Alignment Icon Color",
- type: "color",
- defaultValue: "666666",
- category: ["KayTool", "NodeAlignment", "IconColor"],
- onChange: (newVal) => {
- if (/^[0-9A-Fa-f]{6}$/.test(newVal)) {
- const buttons = document.querySelectorAll('.kay-align-button');
- buttons.forEach(btn => {
- const svg = btn.querySelector('svg');
- if (svg) svg.querySelectorAll('path').forEach(path => path.setAttribute('fill', `#${newVal}`));
- });
- }
+ const currentValue = app.ui.settings.getSettingValue(setting.id);
+ if (currentValue === undefined) {
+ await app.ui.settings.setSettingValue(setting.id, setting.defaultValue);
}
- });
-
- app.ui.settings.addSetting({
- id: "KayTool.NodeAlignDividerColor",
- name: "Node Alignment Divider Color",
- type: "color",
- defaultValue: "1e1e1e",
- category: ["KayTool", "NodeAlignment", "DividerColor"],
- onChange: (newVal) => {
- if (/^[0-9A-Fa-f]{6}$/.test(newVal)) {
- const dividers = document.querySelectorAll('.kay-toolbar-divider');
- dividers.forEach(divider => divider.style.background = `#${newVal}`);
- }
- }
- });
+ }
},
init() {
if (!app.graph) {
@@ -222,7 +261,7 @@ function updateSetGetNodeColors() {
if (node.type === "KaySetNode" || node.type === "KayGetNode" || node.type === "KayGet多元Node") {
node.color = fgColor;
node.bgcolor = bgColor;
- node.updateColors();
+ node.updateColors();
}
});
app.graph.setDirtyCanvas(true, true);