feat: implement real-time resolution dropdown refresh with JS extension

This commit is contained in:
Your Name
2026-01-20 09:39:37 +07:00
parent a809e1afa2
commit f4d201d34d
3 changed files with 92 additions and 2 deletions
+2 -1
View File
@@ -9,7 +9,8 @@ A ComfyUI custom node for selecting mathematically valid image resolutions.
- Divisibility constraints (16 / 32 / 64)
- Max megapixel limit
- 1 MP = 1024 × 1024 = 1,048,576 pixels
- Dynamically filtered resolution dropdown
- **Real-time filtered resolution dropdown** (New!)
- Resolultions update instantly when parameters are changed.
- Outputs:
- Width (px)
- Height (px)
+1 -1
View File
@@ -46,7 +46,7 @@ class PixelForge:
["1 MP", "2 MP", "4 MP", "6 MP", "8 MP", "12 MP", "16 MP"],
{"default": f"{cls._last_max_mp} MP"},
),
"resolution": (resolutions,),
"resolution": ("STRING", {"default": "1024×1024"}),
}
}
+89
View File
@@ -0,0 +1,89 @@
import { app } from "../../../scripts/app.js";
// PixelForge Resolution Matrix - Frontend Extension
app.registerExtension({
name: "PixelForge.ResolutionMatrix",
async beforeRegisterNodeDef(nodeType, nodeData, app) {
if (nodeData.name === "PixelForge") {
const ASPECT_RATIOS = {
"1:1": [1, 1],
"3:2": [3, 2],
"4:3": [4, 3],
"16:9": [16, 9],
"16:10": [16, 10],
};
const MP_BASE = 1024 * 1024;
const onNodeCreated = nodeType.prototype.onNodeCreated;
nodeType.prototype.onNodeCreated = function () {
const r = onNodeCreated ? onNodeCreated.apply(this, arguments) : undefined;
const aspectWidget = this.widgets.find(w => w.name === "aspect_ratio");
const divisibleWidget = this.widgets.find(w => w.name === "divisible_by");
const mpLimitWidget = this.widgets.find(w => w.name === "max_megapixels");
const resolutionWidget = this.widgets.find(w => w.name === "resolution");
resolutionWidget.type = "combo";
resolutionWidget.options = { values: [] };
const updateResolutions = () => {
const aspect = aspectWidget.value;
const div = parseInt(divisibleWidget.value);
const maxMp = parseInt(mpLimitWidget.value.split(" ")[0]);
const ratio = ASPECT_RATIOS[aspect];
if (!ratio) return;
const [ratio_w, ratio_h] = ratio;
const maxPixels = maxMp * MP_BASE;
const resolutions = [];
let k = div;
while (true) {
const w = ratio_w * k;
const h = ratio_h * k;
const total = w * h;
if (total > maxPixels) break;
resolutions.push(`${w}×${h}`);
k += div;
}
if (resolutions.length === 0) {
resolutions.push("INVALID");
}
// Update the widget options
resolutionWidget.options.values = resolutions;
// If current value is not in the new list, pick the closest one or the first one
if (!resolutions.includes(resolutionWidget.value)) {
resolutionWidget.value = resolutions[0];
}
if (this.setDirtyCanvas) {
this.setDirtyCanvas(true, true);
}
};
// Add callbacks to trigger update
const widgetsToWatch = [aspectWidget, divisibleWidget, mpLimitWidget];
widgetsToWatch.forEach(widget => {
const callback = widget.callback;
widget.callback = function () {
const result = callback ? callback.apply(this, arguments) : undefined;
updateResolutions();
return result;
};
});
// Initial update
updateResolutions();
return r;
};
}
}
});