Fix video node canvas navigation
This commit is contained in:
+1
-1
@@ -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",
|
||||
|
||||
@@ -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\);/);
|
||||
}
|
||||
});
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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();
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user