Fix video node canvas navigation

This commit is contained in:
Fillip
2026-08-24 11:44:16 -07:00
parent 78e1d1f659
commit 199ba0a2b6
5 changed files with 155 additions and 1 deletions
+1 -1
View File
@@ -1,7 +1,7 @@
[project]
name = "comfyui_fill-nodes"
description = "Fill-Nodes is a versatile collection of custom nodes for ComfyUI that extends functionality across multiple domains. Features include advanced image processing (pixelation, slicing, masking), visual effects generation (glitch, halftone, pixel art), comprehensive file handling (PDF creation/extraction, Google Drive integration), AI model interfaces (GPT, DALL-E, Hugging Face), utility nodes for workflow enhancement, and specialized tools for video processing, captioning, and batch operations. The pack provides both practical workflow solutions and creative tools within a unified node collection."
version = "2.28.5"
version = "2.28.6"
license = {file = "LICENSE"}
dependencies = [
"librosa",
+108
View File
@@ -0,0 +1,108 @@
import assert from "node:assert/strict";
import { readFile } from "node:fs/promises";
import test from "node:test";
const VIDEO_NODE_URL = new URL("../web/nodes/video/", import.meta.url);
class FakeElement {
constructor() {
this.listeners = new Map();
this.events = [];
}
addEventListener(name, handler) {
const handlers = this.listeners.get(name) || [];
handlers.push(handler);
this.listeners.set(name, handlers);
}
dispatchEvent(event) {
this.events.push(event);
}
emit(name, event) {
for (const handler of this.listeners.get(name) || []) handler(event);
}
}
class FakeEvent {
constructor(type, init = {}) {
Object.assign(this, init);
this.type = type;
}
preventDefault() {
this.defaultPrevented = true;
}
stopPropagation() {
this.propagationStopped = true;
}
}
globalThis.PointerEvent = FakeEvent;
globalThis.WheelEvent = FakeEvent;
const source = await readFile(new URL("canvas_navigation.js", VIDEO_NODE_URL), "utf8");
const moduleUrl = `data:text/javascript;base64,${Buffer.from(source).toString("base64")}`;
const { addCanvasNavigation } = await import(moduleUrl);
function pointerEvent(type, overrides = {}) {
return new FakeEvent(type, {
pointerId: 4,
button: -1,
buttons: 0,
altKey: false,
ctrlKey: false,
shiftKey: false,
...overrides,
});
}
test("video panels pass wheel and canvas drag gestures to LiteGraph", () => {
const element = new FakeElement();
const graphCanvas = new FakeElement();
const canvas = { canvas: graphCanvas, dragZoomEnabled: true, read_only: false };
addCanvasNavigation(element, canvas);
const wheel = new FakeEvent("wheel", { deltaY: -120 });
element.emit("wheel", wheel);
assert.deepEqual(graphCanvas.events.map((event) => event.type), ["wheel"]);
assert.equal(wheel.defaultPrevented, true);
assert.equal(wheel.propagationStopped, true);
element.emit("pointerdown", pointerEvent("pointerdown", { button: 0, buttons: 1 }));
assert.equal(graphCanvas.events.length, 1);
element.emit("pointerdown", pointerEvent("pointerdown", { button: 1, buttons: 4 }));
element.emit("pointermove", pointerEvent("pointermove", { buttons: 4 }));
element.emit("pointerup", pointerEvent("pointerup", { button: 1 }));
element.emit("pointermove", pointerEvent("pointermove", { buttons: 4 }));
assert.deepEqual(
graphCanvas.events.map((event) => event.type),
["wheel", "pointerdown", "pointermove", "pointerup"],
);
canvas.read_only = true;
element.emit("pointerdown", pointerEvent("pointerdown", { button: 0, buttons: 1 }));
element.emit("pointerup", pointerEvent("pointerup", { button: 0 }));
assert.deepEqual(graphCanvas.events.slice(-2).map((event) => event.type), ["pointerdown", "pointerup"]);
canvas.read_only = false;
element.emit("pointerdown", pointerEvent("pointerdown", {
button: 0,
buttons: 1,
ctrlKey: true,
shiftKey: true,
}));
element.emit("pointercancel", pointerEvent("pointercancel", { button: 0 }));
assert.deepEqual(graphCanvas.events.slice(-2).map((event) => event.type), ["pointerdown", "pointercancel"]);
});
test("both FL video DOM widgets enable canvas navigation", async () => {
for (const filename of ["FL_VideoCombine.js", "FL_LoadVideo.js"]) {
const nodeSource = await readFile(new URL(filename, VIDEO_NODE_URL), "utf8");
assert.match(nodeSource, /import \{ addCanvasNavigation \} from "\.\/canvas_navigation\.js";/);
assert.match(nodeSource, /addCanvasNavigation\(container, app\.canvas\);/);
}
});
+2
View File
@@ -1,5 +1,6 @@
import { app } from "../../../../scripts/app.js";
import { api } from "../../../../scripts/api.js";
import { addCanvasNavigation } from "./canvas_navigation.js";
const DEFAULT_SETTINGS = {
version: 1,
@@ -1871,6 +1872,7 @@ app.registerExtension({
container.style.height = "100%";
container.style.minHeight = `${MIN_PANEL_HEIGHT}px`;
container.style.overflow = "hidden";
addCanvasNavigation(container, app.canvas);
const domWidget = node.addDOMWidget("fl_load_video_panel", "fl-load-video", container, {
getMinHeight: () => MIN_PANEL_HEIGHT,
+2
View File
@@ -1,5 +1,6 @@
import { app } from "../../../../scripts/app.js";
import { api } from "../../../../scripts/api.js";
import { addCanvasNavigation } from "./canvas_navigation.js";
const DEFAULT_SETTINGS = {
version: 1,
@@ -1125,6 +1126,7 @@ app.registerExtension({
container.style.height = "100%";
container.style.minHeight = `${MIN_PANEL_HEIGHT}px`;
container.style.overflow = "hidden";
addCanvasNavigation(container, app.canvas);
const domWidget = node.addDOMWidget("fl_video_combine_panel", "fl-video-combine", container, {
getMinHeight: () => MIN_PANEL_HEIGHT,
+42
View File
@@ -0,0 +1,42 @@
function startsCanvasGesture(event, canvas) {
return event.button === 1 || (
event.button === 0
&& (
canvas.read_only
|| (canvas.dragZoomEnabled && event.ctrlKey && event.shiftKey && !event.altKey)
)
);
}
export function addCanvasNavigation(element, canvas) {
const graphCanvas = canvas.canvas;
let pointerId = null;
element.addEventListener("wheel", (event) => {
graphCanvas.dispatchEvent(new WheelEvent(event.type, event));
event.preventDefault();
event.stopPropagation();
}, { passive: false });
element.addEventListener("pointerdown", (event) => {
if (!startsCanvasGesture(event, canvas)) return;
pointerId = event.pointerId;
graphCanvas.dispatchEvent(new PointerEvent(event.type, event));
event.preventDefault();
event.stopPropagation();
});
for (const eventName of ["pointermove", "pointerup", "pointercancel"]) {
element.addEventListener(eventName, (event) => {
if (event.pointerId !== pointerId) return;
graphCanvas.dispatchEvent(new PointerEvent(event.type, event));
if (eventName !== "pointermove") pointerId = null;
event.preventDefault();
event.stopPropagation();
});
}
element.addEventListener("auxclick", (event) => {
if (event.button === 1) event.preventDefault();
});
}