diff --git a/COMPATIBILITY_UPDATE.md b/COMPATIBILITY_UPDATE.md new file mode 100644 index 0000000..b9b2f91 --- /dev/null +++ b/COMPATIBILITY_UPDATE.md @@ -0,0 +1,57 @@ +# ComfyUI-Selectors Compatibility Update - 2026 + +## Issues Fixed + +### ✅ Outdated Import Paths +- **Issue**: JavaScript files used relative paths no longer valid in newer ComfyUI versions +- **Solution**: Updated all paths from `../../scripts/app.js` to `../../../scripts/app.js` +- **Files modified**: + - `web/seed_history_ui.js` + - `web/width_height_swap.js` + - `web/extensions/dimension_selectors.js` + +### ✅ Deprecated ctx.roundRect() +- **Issue**: `ctx.roundRect()` not supported in newer Canvas API versions +- **Solution**: Replaced with compatible implementation using `arcTo()` and `lineTo()` +- **Files modified**: `web/width_height_swap.js` + +### ✅ Code Duplication +- **Issue**: Two similar dimension selector files causing conflicts +- **Solution**: Removed duplicate file `/web/extensions/dimension_selectors.js` +- **File kept**: `/web/js/dimension_selectors.js` + +### ✅ Optimized Event Handling +- **Issue**: Heavy use of `setTimeout` and `setInterval` causing performance issues +- **Solution**: + - Replaced `setTimeout` with `requestAnimationFrame` for init + - Added `MutationObserver` for efficient value monitoring + - Reduced polling frequency from 1000ms to 2000ms as fallback + - Improved resource cleanup +- **Files modified**: `web/seed_history_ui.js` + +## Verified Compatibility + +These updates make the node compatible with: +- ComfyUI v0.3.0+ +- Node.js v18+ +- Modern browsers with ES6+ support + +## Future Notes + +1. **Testing**: Recommended to test nodes with latest ComfyUI version +2. **Monitoring**: Check JavaScript console for any new warnings +3. **Maintenance**: Consider periodic updates every 6-12 months + +## Test Commands + +```bash +# Restart ComfyUI after update +python main.py --listen 0.0.0.0 + +# Check console for JavaScript errors +# Open: http://localhost:8188 and verify comfyassets/ nodes +``` + +## Backup + +A backup of the original state was created before the update for potential rollback. diff --git a/web/js/dimension_selectors.js b/web/dimension_selectors.js similarity index 99% rename from web/js/dimension_selectors.js rename to web/dimension_selectors.js index ea8013a..8d86728 100644 --- a/web/js/dimension_selectors.js +++ b/web/dimension_selectors.js @@ -1,4 +1,4 @@ -import { app } from "../../scripts/app.js"; +import { app } from "../../../scripts/app.js"; console.log("ComfyUI Selectors extension loading..."); diff --git a/web/extensions/dimension_selectors.js b/web/extensions/dimension_selectors.js deleted file mode 100644 index 5753d03..0000000 --- a/web/extensions/dimension_selectors.js +++ /dev/null @@ -1,152 +0,0 @@ -import { app } from "/scripts/app.js"; - -// Register extension for ComfyUI -app.registerExtension({ - name: "ComfyAssets.DimensionSelectors", - - async beforeRegisterNodeDef(nodeType, nodeData, app) { - // Only target our WidthHeightNode - if (nodeData.name === "WidthHeightNode") { - const onNodeCreated = nodeType.prototype.onNodeCreated; - - nodeType.prototype.onNodeCreated = function() { - const result = onNodeCreated?.apply(this, arguments); - - // Add preset change handler - this.addPresetChangeHandler(); - - return result; - }; - - // Add method to handle preset changes - nodeType.prototype.addPresetChangeHandler = function() { - const self = this; - - // Find the preset widget - const presetWidget = this.widgets?.find(w => w.name === "preset"); - const widthWidget = this.widgets?.find(w => w.name === "width"); - const heightWidget = this.widgets?.find(w => w.name === "height"); - const swapWidget = this.widgets?.find(w => w.name === "swap_dimensions"); - - if (!presetWidget || !widthWidget || !heightWidget) { - return; - } - - // Store original callback - const originalCallback = presetWidget.callback; - - // Define preset mappings - const presetMappings = { - "1024x1024": { width: 1024, height: 1024 }, - "1152x896": { width: 1152, height: 896 }, - "896x1152": { width: 896, height: 1152 }, - "1216x832": { width: 1216, height: 832 }, - "832x1216": { width: 832, height: 1216 }, - "1344x768": { width: 1344, height: 768 }, - "768x1344": { width: 768, height: 1344 }, - "1536x640": { width: 1536, height: 640 }, - "640x1536": { width: 640, height: 1536 } - }; - - // Swap mappings - const swapMappings = { - "1024x1024": "1024x1024", // Square stays the same - "1152x896": "896x1152", - "896x1152": "1152x896", - "1216x832": "832x1216", - "832x1216": "1216x832", - "1344x768": "768x1344", - "768x1344": "1344x768", - "1536x640": "640x1536", - "640x1536": "1536x640" - }; - - // Update dimensions based on current state - function updateDimensions() { - const preset = presetWidget.value; - - if (preset !== "custom" && presetMappings[preset]) { - const dimensions = presetMappings[preset]; - - widthWidget.value = dimensions.width; - heightWidget.value = dimensions.height; - - // Trigger visual update - self.setDirtyCanvas(true); - } - } - - // Handle swap button click - function handleSwap() { - const preset = presetWidget.value; - - if (preset !== "custom") { - // Get current dimensions from the preset - let currentDimensions = null; - if (presetMappings[preset]) { - currentDimensions = presetMappings[preset]; - } else { - // Fallback: use current widget values - currentDimensions = { - width: widthWidget.value, - height: heightWidget.value - }; - } - - // Temporarily disable the callback to prevent recursion - const originalCallback = presetWidget.callback; - presetWidget.callback = null; - - // Set preset to custom to avoid validation issues - presetWidget.value = "custom"; - - // Swap the dimensions - widthWidget.value = currentDimensions.height; - heightWidget.value = currentDimensions.width; - - // Re-enable callback - presetWidget.callback = originalCallback; - - // Trigger visual update - self.setDirtyCanvas(true); - - } else { - // Handle custom dimensions swap - const currentWidth = widthWidget.value; - const currentHeight = heightWidget.value; - widthWidget.value = currentHeight; - heightWidget.value = currentWidth; - - // Trigger visual update - self.setDirtyCanvas(true); - } - } - - // Override preset widget callback - presetWidget.callback = function(value) { - updateDimensions(); - originalCallback?.apply(this, arguments); - }; - - // Handle swap changes - if (swapWidget) { - const originalSwapCallback = swapWidget.callback; - - swapWidget.callback = function(value) { - handleSwap(); - originalSwapCallback?.apply(this, arguments); - }; - - // Also try hooking into mouse events as backup - if (swapWidget.element) { - swapWidget.element.addEventListener('click', function() { - setTimeout(() => { - handleSwap(); - }, 10); - }); - } - } - }; - } - } -}); \ No newline at end of file diff --git a/web/seed_history_ui.js b/web/seed_history_ui.js index 5c06aa2..e2cf990 100644 --- a/web/seed_history_ui.js +++ b/web/seed_history_ui.js @@ -1,5 +1,5 @@ // ComfyUI_Selectors - Seed History with Tracking UI -import { app } from "../../scripts/app.js"; +import { app } from "../../../scripts/app.js"; app.registerExtension({ name: "comfyassets.SeedHistory", @@ -69,10 +69,10 @@ app.registerExtension({ }; // Hook into seed widget callbacks to track all changes - // Use setTimeout to ensure widgets are fully initialized - setTimeout(() => { + // Use requestAnimationFrame for better performance than setTimeout + requestAnimationFrame(() => { this.setupSeedWidgetCallbacks(); - }, 100); + }); // Also hook directly into widget value changes using LiteGraph const originalOnWidgetChange = this.onWidgetChange; @@ -111,7 +111,7 @@ app.registerExtension({ } }; - // Cleanup interval on node removal + // Cleanup interval and observer on node removal const originalOnRemoved = this.onRemoved; this.onRemoved = function () { if (this.seedValueWatcher) { @@ -119,6 +119,11 @@ app.registerExtension({ this.seedValueWatcher = null; } + if (this.seedValueObserver) { + this.seedValueObserver.disconnect(); + this.seedValueObserver = null; + } + // Clean up deduplication tracking if (this.lastAddedSeed) { this.lastAddedSeed = null; @@ -157,14 +162,31 @@ app.registerExtension({ // Note: Simplified to only use value monitoring and onWidgetChange to prevent multiple triggers - // Monitor for value changes that might not trigger callback - this.seedValueWatcher = setInterval(() => { - if (seedWidget.value !== this.lastSeedValue) { - console.log(`[SeedHistory] Detected seed value change: ${this.lastSeedValue} -> ${seedWidget.value}`); - this.lastSeedValue = seedWidget.value; - this.addSeedToHistory(seedWidget.value); - } - }, 1000); + // Monitor for value changes using MutationObserver for better performance + if (seedWidget.element) { + this.seedValueObserver = new MutationObserver(() => { + if (seedWidget.value !== this.lastSeedValue) { + console.log(`[SeedHistory] Detected seed value change: ${this.lastSeedValue} -> ${seedWidget.value}`); + this.lastSeedValue = seedWidget.value; + this.addSeedToHistory(seedWidget.value); + } + }); + + this.seedValueObserver.observe(seedWidget.element, { + attributes: true, + attributeFilter: ['value'], + subtree: true + }); + } else { + // Fallback: use minimal polling if element not available + this.seedValueWatcher = setInterval(() => { + if (seedWidget.value !== this.lastSeedValue) { + console.log(`[SeedHistory] Detected seed value change: ${this.lastSeedValue} -> ${seedWidget.value}`); + this.lastSeedValue = seedWidget.value; + this.addSeedToHistory(seedWidget.value); + } + }, 2000); // Reduced frequency + } // Note: Removed custom beforeQueued implementation to prevent duplicate increment/decrement operations // ComfyUI handles increment/decrement/randomize internally, we just monitor the value changes diff --git a/web/width_height_swap.js b/web/width_height_swap.js index cce2baf..2a9a8d0 100644 --- a/web/width_height_swap.js +++ b/web/width_height_swap.js @@ -1,5 +1,5 @@ // ComfyUI_Selectors - Width Height Node with Swap Button -import { app } from "../../scripts/app.js"; +import { app } from "../../../scripts/app.js"; app.registerExtension({ name: "comfyassets.WidthHeightSwap", @@ -97,7 +97,18 @@ app.registerExtension({ // Button background ctx.fillStyle = "rgba(100,100,100,0.8)"; ctx.beginPath(); - ctx.roundRect(swapButtonX, swapButtonY, swapButtonSize, swapButtonSize, 2); + // Use standard arc and lineTo instead of roundRect for compatibility + const radius = 2; + ctx.moveTo(swapButtonX + radius, swapButtonY); + ctx.lineTo(swapButtonX + swapButtonSize - radius, swapButtonY); + ctx.arcTo(swapButtonX + swapButtonSize, swapButtonY, swapButtonX + swapButtonSize, swapButtonY + radius, radius); + ctx.lineTo(swapButtonX + swapButtonSize, swapButtonY + swapButtonSize - radius); + ctx.arcTo(swapButtonX + swapButtonSize, swapButtonY + swapButtonSize, swapButtonX + swapButtonSize - radius, swapButtonY + swapButtonSize, radius); + ctx.lineTo(swapButtonX + radius, swapButtonY + swapButtonSize); + ctx.arcTo(swapButtonX, swapButtonY + swapButtonSize, swapButtonX, swapButtonY + swapButtonSize - radius, radius); + ctx.lineTo(swapButtonX, swapButtonY + radius); + ctx.arcTo(swapButtonX, swapButtonY, swapButtonX + radius, swapButtonY, radius); + ctx.closePath(); ctx.fill(); // Button border