mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-03-11 16:10:05 +00:00
Add litegraph input indicator helper class (#842)
Example usage with ComfyUI_frontend, via console / devtools: ```ts const inputIndicators = new InputIndicators(app.canvas) // Dispose: inputIndicators.dispose() ```
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
import type { Dictionary, ISlotType, Rect, WhenNullish } from "./interfaces"
|
import type { Dictionary, ISlotType, Rect, WhenNullish } from "./interfaces"
|
||||||
|
|
||||||
|
import { InputIndicators } from "./canvas/InputIndicators"
|
||||||
import { ContextMenu } from "./ContextMenu"
|
import { ContextMenu } from "./ContextMenu"
|
||||||
import { CurveEditor } from "./CurveEditor"
|
import { CurveEditor } from "./CurveEditor"
|
||||||
import { DragAndScale } from "./DragAndScale"
|
import { DragAndScale } from "./DragAndScale"
|
||||||
@@ -270,6 +271,7 @@ export class LiteGraphGlobal {
|
|||||||
ContextMenu = ContextMenu
|
ContextMenu = ContextMenu
|
||||||
CurveEditor = CurveEditor
|
CurveEditor = CurveEditor
|
||||||
Reroute = Reroute
|
Reroute = Reroute
|
||||||
|
InputIndicators = InputIndicators
|
||||||
|
|
||||||
onNodeTypeRegistered?(type: string, base_class: typeof LGraphNode): void
|
onNodeTypeRegistered?(type: string, base_class: typeof LGraphNode): void
|
||||||
onNodeTypeReplaced?(type: string, base_class: typeof LGraphNode, prev: unknown): void
|
onNodeTypeReplaced?(type: string, base_class: typeof LGraphNode, prev: unknown): void
|
||||||
|
|||||||
167
src/canvas/InputIndicators.ts
Normal file
167
src/canvas/InputIndicators.ts
Normal file
@@ -0,0 +1,167 @@
|
|||||||
|
import type { LGraphCanvas } from "@/LGraphCanvas"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A class that can be added to the render cycle to show pointer / keyboard status symbols.
|
||||||
|
*
|
||||||
|
* Used to create videos of feature changes.
|
||||||
|
*
|
||||||
|
* Example usage with ComfyUI_frontend, via console / devtools:
|
||||||
|
*
|
||||||
|
* ```ts
|
||||||
|
* const inputIndicators = new InputIndicators(canvas)
|
||||||
|
* // Dispose:
|
||||||
|
* inputIndicators.dispose()
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
export class InputIndicators {
|
||||||
|
// #region config
|
||||||
|
radius = 8
|
||||||
|
startAngle = 0
|
||||||
|
endAngle = Math.PI * 2
|
||||||
|
|
||||||
|
inactiveColour = "#ffffff10"
|
||||||
|
colour1 = "#ff5f00"
|
||||||
|
colour2 = "#00ff7c"
|
||||||
|
colour3 = "#dea7ff"
|
||||||
|
fontString = "bold 12px Arial"
|
||||||
|
// #endregion
|
||||||
|
|
||||||
|
// #region state
|
||||||
|
enabled: boolean = true
|
||||||
|
|
||||||
|
shiftDown: boolean = false
|
||||||
|
undoDown: boolean = false
|
||||||
|
redoDown: boolean = false
|
||||||
|
ctrlDown: boolean = false
|
||||||
|
altDown: boolean = false
|
||||||
|
mouse0Down: boolean = false
|
||||||
|
mouse1Down: boolean = false
|
||||||
|
mouse2Down: boolean = false
|
||||||
|
|
||||||
|
x: number = 0
|
||||||
|
y: number = 0
|
||||||
|
// #endregion
|
||||||
|
|
||||||
|
controller?: AbortController
|
||||||
|
|
||||||
|
constructor(public canvas: LGraphCanvas) {
|
||||||
|
this.controller = new AbortController()
|
||||||
|
const { signal } = this.controller
|
||||||
|
|
||||||
|
const element = canvas.canvas
|
||||||
|
const options = { capture: true, signal } satisfies AddEventListenerOptions
|
||||||
|
|
||||||
|
element.addEventListener("pointerdown", this.#onPointerDownOrMove, options)
|
||||||
|
element.addEventListener("pointermove", this.#onPointerDownOrMove, options)
|
||||||
|
element.addEventListener("pointerup", this.#onPointerUp, options)
|
||||||
|
element.addEventListener("keydown", this.#onKeyDownOrUp, options)
|
||||||
|
document.addEventListener("keyup", this.#onKeyDownOrUp, options)
|
||||||
|
|
||||||
|
const origDrawFrontCanvas = canvas.drawFrontCanvas.bind(canvas)
|
||||||
|
signal.addEventListener("abort", () => {
|
||||||
|
canvas.drawFrontCanvas = origDrawFrontCanvas
|
||||||
|
})
|
||||||
|
|
||||||
|
canvas.drawFrontCanvas = () => {
|
||||||
|
origDrawFrontCanvas()
|
||||||
|
this.draw()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#onPointerDownOrMove = this.onPointerDownOrMove.bind(this)
|
||||||
|
onPointerDownOrMove(e: MouseEvent): void {
|
||||||
|
this.mouse0Down = (e.buttons & 1) === 1
|
||||||
|
this.mouse1Down = (e.buttons & 4) === 4
|
||||||
|
this.mouse2Down = (e.buttons & 2) === 2
|
||||||
|
|
||||||
|
this.x = e.clientX
|
||||||
|
this.y = e.clientY
|
||||||
|
|
||||||
|
this.canvas.setDirty(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
#onPointerUp = this.onPointerUp.bind(this)
|
||||||
|
onPointerUp(): void {
|
||||||
|
this.mouse0Down = false
|
||||||
|
this.mouse1Down = false
|
||||||
|
this.mouse2Down = false
|
||||||
|
}
|
||||||
|
|
||||||
|
#onKeyDownOrUp = this.onKeyDownOrUp.bind(this)
|
||||||
|
onKeyDownOrUp(e: KeyboardEvent): void {
|
||||||
|
this.ctrlDown = e.ctrlKey
|
||||||
|
this.altDown = e.altKey
|
||||||
|
this.shiftDown = e.shiftKey
|
||||||
|
this.undoDown = e.ctrlKey && e.code === "KeyZ" && e.type === "keydown"
|
||||||
|
this.redoDown = e.ctrlKey && e.code === "KeyY" && e.type === "keydown"
|
||||||
|
}
|
||||||
|
|
||||||
|
draw() {
|
||||||
|
const {
|
||||||
|
canvas: { ctx },
|
||||||
|
radius,
|
||||||
|
startAngle,
|
||||||
|
endAngle,
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
inactiveColour,
|
||||||
|
colour1,
|
||||||
|
colour2,
|
||||||
|
colour3,
|
||||||
|
fontString,
|
||||||
|
} = this
|
||||||
|
|
||||||
|
const { fillStyle, font } = ctx
|
||||||
|
|
||||||
|
const mouseDotX = x
|
||||||
|
const mouseDotY = y - 80
|
||||||
|
|
||||||
|
const textX = mouseDotX
|
||||||
|
const textY = mouseDotY - 15
|
||||||
|
ctx.font = fontString
|
||||||
|
|
||||||
|
textMarker(textX + 0, textY, "Shift", this.shiftDown ? colour1 : inactiveColour)
|
||||||
|
textMarker(textX + 45, textY + 20, "Alt", this.altDown ? colour2 : inactiveColour)
|
||||||
|
textMarker(textX + 30, textY, "Control", this.ctrlDown ? colour3 : inactiveColour)
|
||||||
|
textMarker(textX - 30, textY, "↩️", this.undoDown ? "#000" : "transparent")
|
||||||
|
textMarker(textX + 45, textY, "↪️", this.redoDown ? "#000" : "transparent")
|
||||||
|
|
||||||
|
ctx.beginPath()
|
||||||
|
drawDot(mouseDotX, mouseDotY)
|
||||||
|
drawDot(mouseDotX + 15, mouseDotY)
|
||||||
|
drawDot(mouseDotX + 30, mouseDotY)
|
||||||
|
ctx.fillStyle = inactiveColour
|
||||||
|
ctx.fill()
|
||||||
|
|
||||||
|
const leftButtonColour = this.mouse0Down ? colour1 : inactiveColour
|
||||||
|
const middleButtonColour = this.mouse1Down ? colour2 : inactiveColour
|
||||||
|
const rightButtonColour = this.mouse2Down ? colour3 : inactiveColour
|
||||||
|
if (this.mouse0Down) mouseMarker(mouseDotX, mouseDotY, leftButtonColour)
|
||||||
|
if (this.mouse1Down) mouseMarker(mouseDotX + 15, mouseDotY, middleButtonColour)
|
||||||
|
if (this.mouse2Down) mouseMarker(mouseDotX + 30, mouseDotY, rightButtonColour)
|
||||||
|
|
||||||
|
ctx.fillStyle = fillStyle
|
||||||
|
ctx.font = font
|
||||||
|
|
||||||
|
function textMarker(x: number, y: number, text: string, colour: string) {
|
||||||
|
ctx.fillStyle = colour
|
||||||
|
ctx.fillText(text, x, y)
|
||||||
|
}
|
||||||
|
|
||||||
|
function mouseMarker(x: number, y: number, colour: string) {
|
||||||
|
ctx.beginPath()
|
||||||
|
ctx.fillStyle = colour
|
||||||
|
drawDot(x, y)
|
||||||
|
ctx.fill()
|
||||||
|
}
|
||||||
|
|
||||||
|
function drawDot(x: number, y: number) {
|
||||||
|
ctx.arc(x, y, radius, startAngle, endAngle)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dispose() {
|
||||||
|
this.controller?.abort()
|
||||||
|
this.controller = undefined
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -87,6 +87,7 @@ export interface LGraphNodeConstructor<T extends LGraphNode = LGraphNode> {
|
|||||||
|
|
||||||
// End backwards compat
|
// End backwards compat
|
||||||
|
|
||||||
|
export { InputIndicators } from "./canvas/InputIndicators"
|
||||||
export { isOverNodeInput, isOverNodeOutput } from "./canvas/measureSlots"
|
export { isOverNodeInput, isOverNodeOutput } from "./canvas/measureSlots"
|
||||||
export { CanvasPointer } from "./CanvasPointer"
|
export { CanvasPointer } from "./CanvasPointer"
|
||||||
export { ContextMenu } from "./ContextMenu"
|
export { ContextMenu } from "./ContextMenu"
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ LiteGraphGlobal {
|
|||||||
"Globals": {},
|
"Globals": {},
|
||||||
"HIDDEN_LINK": -1,
|
"HIDDEN_LINK": -1,
|
||||||
"INPUT": 1,
|
"INPUT": 1,
|
||||||
|
"InputIndicators": [Function],
|
||||||
"LEFT": 3,
|
"LEFT": 3,
|
||||||
"LGraph": [Function],
|
"LGraph": [Function],
|
||||||
"LGraphCanvas": [Function],
|
"LGraphCanvas": [Function],
|
||||||
|
|||||||
Reference in New Issue
Block a user