mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-02-02 22:37:32 +00:00
[Refactor] Move strokeShape from LGraphCanvas to draw (#435)
* [Refactor] Move strokeShape from LGraphCanvas to draw * Fix round radius * nit * nit * nit
This commit is contained in:
@@ -56,7 +56,7 @@ import {
|
||||
isInRect,
|
||||
snapPoint,
|
||||
} from "./measure"
|
||||
import { drawSlot, LabelPosition } from "./draw"
|
||||
import { drawSlot, LabelPosition, strokeShape } from "./draw"
|
||||
import { DragAndScale } from "./DragAndScale"
|
||||
import { LinkReleaseContextExtended, LiteGraph, clamp } from "./litegraph"
|
||||
import { stringOrEmpty, stringOrNull } from "./strings"
|
||||
@@ -132,16 +132,6 @@ interface IDialogOptions {
|
||||
onclose?(): void
|
||||
}
|
||||
|
||||
interface IDrawSelectionBoundingOptions {
|
||||
shape?: RenderShape
|
||||
title_height?: number
|
||||
title_mode?: TitleMode
|
||||
colour?: CanvasColour
|
||||
padding?: number
|
||||
collapsed?: boolean
|
||||
thickness?: number
|
||||
}
|
||||
|
||||
/** @inheritdoc {@link LGraphCanvas.state} */
|
||||
export interface LGraphCanvasState {
|
||||
/** {@link Positionable} items are being dragged on the canvas. */
|
||||
@@ -313,6 +303,20 @@ export class LGraphCanvas {
|
||||
this.#maximumFrameGap = value > Number.EPSILON ? 1000 / value : 0
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link LiteGraphGlobal.ROUND_RADIUS} instead.
|
||||
*/
|
||||
get round_radius() {
|
||||
return LiteGraph.ROUND_RADIUS
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link LiteGraphGlobal.ROUND_RADIUS} instead.
|
||||
*/
|
||||
set round_radius(value: number) {
|
||||
LiteGraph.ROUND_RADIUS = value
|
||||
}
|
||||
|
||||
options: {
|
||||
skip_events?: any
|
||||
viewport?: any
|
||||
@@ -388,7 +392,6 @@ export class LGraphCanvas {
|
||||
/** to render foreground objects (above nodes and connections) in the canvas affected by transform */
|
||||
onDrawForeground?: (arg0: CanvasRenderingContext2D, arg1: any) => void
|
||||
connections_width: number
|
||||
round_radius: number
|
||||
/** The current node being drawn by {@link drawNode}. This should NOT be used to determine the currently selected node. See {@link selectedItems} */
|
||||
current_node: LGraphNode | null
|
||||
/** used for widgets */
|
||||
@@ -628,7 +631,6 @@ export class LGraphCanvas {
|
||||
this.onAfterChange = null
|
||||
|
||||
this.connections_width = 3
|
||||
this.round_radius = 8
|
||||
|
||||
this.current_node = null
|
||||
this.node_widget = null
|
||||
@@ -4534,7 +4536,7 @@ export class LGraphCanvas {
|
||||
|
||||
const area = node.boundingRect
|
||||
const gap = 3
|
||||
const radius = this.round_radius + gap
|
||||
const radius = LiteGraph.ROUND_RADIUS + gap
|
||||
|
||||
const x = area[0] - gap
|
||||
const y = area[1] - gap
|
||||
@@ -5191,8 +5193,8 @@ export class LGraphCanvas {
|
||||
area[2],
|
||||
area[3],
|
||||
shape == RenderShape.CARD
|
||||
? [this.round_radius, this.round_radius, 0, 0]
|
||||
: [this.round_radius],
|
||||
? [LiteGraph.ROUND_RADIUS, LiteGraph.ROUND_RADIUS, 0, 0]
|
||||
: [LiteGraph.ROUND_RADIUS],
|
||||
)
|
||||
} else if (shape == RenderShape.CIRCLE) {
|
||||
ctx.arc(size[0] * 0.5, size[1] * 0.5, size[0] * 0.5, 0, Math.PI * 2)
|
||||
@@ -5200,7 +5202,7 @@ export class LGraphCanvas {
|
||||
ctx.fill()
|
||||
|
||||
if (node.has_errors && !LiteGraph.use_legacy_node_error_indicator) {
|
||||
this.strokeShape(ctx, area, {
|
||||
strokeShape(ctx, area, {
|
||||
shape,
|
||||
title_mode,
|
||||
title_height,
|
||||
@@ -5247,8 +5249,8 @@ export class LGraphCanvas {
|
||||
size[0],
|
||||
title_height,
|
||||
collapsed
|
||||
? [this.round_radius]
|
||||
: [this.round_radius, this.round_radius, 0, 0],
|
||||
? [LiteGraph.ROUND_RADIUS]
|
||||
: [LiteGraph.ROUND_RADIUS, LiteGraph.ROUND_RADIUS, 0, 0],
|
||||
)
|
||||
}
|
||||
ctx.fill()
|
||||
@@ -5411,7 +5413,7 @@ export class LGraphCanvas {
|
||||
|
||||
const padding = node.has_errors && !LiteGraph.use_legacy_node_error_indicator ? 20 : undefined
|
||||
|
||||
this.strokeShape(ctx, area, {
|
||||
strokeShape(ctx, area, {
|
||||
shape,
|
||||
title_height,
|
||||
title_mode,
|
||||
@@ -5425,94 +5427,6 @@ export class LGraphCanvas {
|
||||
if (node.action_triggered > 0) node.action_triggered--
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws only the path of a shape on the canvas, without filling.
|
||||
* Used to draw indicators for node status, e.g. "selected".
|
||||
* @param ctx The 2D context to draw on
|
||||
* @param area The position and size of the shape to render
|
||||
*/
|
||||
strokeShape(
|
||||
ctx: CanvasRenderingContext2D,
|
||||
area: Rect,
|
||||
{
|
||||
/** The shape to render */
|
||||
shape = RenderShape.BOX,
|
||||
/** Shape will extend above the Y-axis 0 by this amount */
|
||||
title_height = LiteGraph.NODE_TITLE_HEIGHT,
|
||||
/** @deprecated This is node-specific: it should be removed entirely, and behaviour defined by the caller more explicitly */
|
||||
title_mode = TitleMode.NORMAL_TITLE,
|
||||
/** The colour that should be drawn */
|
||||
colour = LiteGraph.NODE_BOX_OUTLINE_COLOR,
|
||||
/** The distance between the edge of the {@link area} and the middle of the line */
|
||||
padding = 6,
|
||||
/** @deprecated This is node-specific: it should be removed entirely, and behaviour defined by the caller more explicitly */
|
||||
collapsed = false,
|
||||
/** Thickness of the line drawn (`lineWidth`) */
|
||||
thickness = 1,
|
||||
}: IDrawSelectionBoundingOptions = {},
|
||||
): void {
|
||||
// Adjust area if title is transparent
|
||||
if (title_mode === TitleMode.TRANSPARENT_TITLE) {
|
||||
area[1] -= title_height
|
||||
area[3] += title_height
|
||||
}
|
||||
|
||||
// Set up context
|
||||
const { lineWidth, strokeStyle } = ctx
|
||||
ctx.lineWidth = thickness
|
||||
ctx.globalAlpha = 0.8
|
||||
ctx.strokeStyle = colour
|
||||
ctx.beginPath()
|
||||
|
||||
// Draw shape based on type
|
||||
const [x, y, width, height] = area
|
||||
switch (shape) {
|
||||
case RenderShape.BOX: {
|
||||
ctx.rect(
|
||||
x - padding,
|
||||
y - padding,
|
||||
width + 2 * padding,
|
||||
height + 2 * padding,
|
||||
)
|
||||
break
|
||||
}
|
||||
case RenderShape.ROUND:
|
||||
case RenderShape.CARD: {
|
||||
const radius = this.round_radius + padding
|
||||
const isCollapsed = shape === RenderShape.CARD && collapsed
|
||||
const cornerRadii =
|
||||
isCollapsed || shape === RenderShape.ROUND
|
||||
? [radius]
|
||||
: [radius, 2, radius, 2]
|
||||
ctx.roundRect(
|
||||
x - padding,
|
||||
y - padding,
|
||||
width + 2 * padding,
|
||||
height + 2 * padding,
|
||||
cornerRadii,
|
||||
)
|
||||
break
|
||||
}
|
||||
case RenderShape.CIRCLE: {
|
||||
const centerX = x + width / 2
|
||||
const centerY = y + height / 2
|
||||
const radius = Math.max(width, height) / 2 + padding
|
||||
ctx.arc(centerX, centerY, radius, 0, Math.PI * 2)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// Stroke the shape
|
||||
ctx.stroke()
|
||||
|
||||
// Reset context
|
||||
ctx.lineWidth = lineWidth
|
||||
ctx.strokeStyle = strokeStyle
|
||||
|
||||
// TODO: Store and reset value properly. Callers currently expect this behaviour (e.g. muted nodes).
|
||||
ctx.globalAlpha = 1
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws a snap guide for a {@link Positionable} item.
|
||||
*
|
||||
|
||||
@@ -18,7 +18,7 @@ import {
|
||||
snapPoint,
|
||||
} from "./measure"
|
||||
import { LGraphNode } from "./LGraphNode"
|
||||
import { RenderShape, TitleMode } from "./types/globalEnums"
|
||||
import { strokeShape } from "./draw"
|
||||
|
||||
export interface IGraphGroupFlags extends Record<string, unknown> {
|
||||
pinned?: true
|
||||
@@ -183,7 +183,7 @@ export class LGraphGroup implements Positionable, IPinnable {
|
||||
ctx.fillText(this.title + (this.pinned ? "📌" : ""), x + padding, y + font_size)
|
||||
|
||||
if (LiteGraph.highlight_selected_group && this.selected) {
|
||||
graphCanvas.strokeShape(ctx, this._bounding, {
|
||||
strokeShape(ctx, this._bounding, {
|
||||
title_height: this.titleHeight,
|
||||
padding,
|
||||
})
|
||||
|
||||
@@ -76,6 +76,7 @@ export class LiteGraphGlobal {
|
||||
DEFAULT_POSITION = [100, 100]
|
||||
/** ,"circle" */
|
||||
VALID_SHAPES = ["default", "box", "round", "card"]
|
||||
ROUND_RADIUS = 8
|
||||
|
||||
// shapes are used for nodes but also for slots
|
||||
BOX_SHAPE = RenderShape.BOX
|
||||
|
||||
107
src/draw.ts
107
src/draw.ts
@@ -1,6 +1,6 @@
|
||||
import type { Vector2 } from "./litegraph"
|
||||
import type { INodeSlot } from "./interfaces"
|
||||
import { LinkDirection, RenderShape } from "./types/globalEnums"
|
||||
import { LiteGraph, type Vector2 } from "./litegraph"
|
||||
import type { CanvasColour, INodeSlot, Rect } from "./interfaces"
|
||||
import { LinkDirection, RenderShape, TitleMode } from "./types/globalEnums"
|
||||
|
||||
export enum SlotType {
|
||||
Array = "array",
|
||||
@@ -143,3 +143,104 @@ export function drawSlot(
|
||||
ctx.strokeStyle = originalStrokeStyle
|
||||
ctx.lineWidth = originalLineWidth
|
||||
}
|
||||
|
||||
interface IDrawSelectionBoundingOptions {
|
||||
shape?: RenderShape
|
||||
round_radius?: number
|
||||
title_height?: number
|
||||
title_mode?: TitleMode
|
||||
colour?: CanvasColour
|
||||
padding?: number
|
||||
collapsed?: boolean
|
||||
thickness?: number
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws only the path of a shape on the canvas, without filling.
|
||||
* Used to draw indicators for node status, e.g. "selected".
|
||||
* @param ctx The 2D context to draw on
|
||||
* @param area The position and size of the shape to render
|
||||
*/
|
||||
export function strokeShape(
|
||||
ctx: CanvasRenderingContext2D,
|
||||
area: Rect,
|
||||
{
|
||||
/** The shape to render */
|
||||
shape = RenderShape.BOX,
|
||||
/** The radius of the rounded corners for {@link RenderShape.ROUND} and {@link RenderShape.CARD} */
|
||||
round_radius = LiteGraph.ROUND_RADIUS,
|
||||
/** Shape will extend above the Y-axis 0 by this amount */
|
||||
title_height = LiteGraph.NODE_TITLE_HEIGHT,
|
||||
/** @deprecated This is node-specific: it should be removed entirely, and behaviour defined by the caller more explicitly */
|
||||
title_mode = TitleMode.NORMAL_TITLE,
|
||||
/** The colour that should be drawn */
|
||||
colour = LiteGraph.NODE_BOX_OUTLINE_COLOR,
|
||||
/** The distance between the edge of the {@link area} and the middle of the line */
|
||||
padding = 6,
|
||||
/** @deprecated This is node-specific: it should be removed entirely, and behaviour defined by the caller more explicitly */
|
||||
collapsed = false,
|
||||
/** Thickness of the line drawn (`lineWidth`) */
|
||||
thickness = 1,
|
||||
}: IDrawSelectionBoundingOptions = {},
|
||||
): void {
|
||||
// Adjust area if title is transparent
|
||||
if (title_mode === TitleMode.TRANSPARENT_TITLE) {
|
||||
area[1] -= title_height
|
||||
area[3] += title_height
|
||||
}
|
||||
|
||||
// Set up context
|
||||
const { lineWidth, strokeStyle } = ctx
|
||||
ctx.lineWidth = thickness
|
||||
ctx.globalAlpha = 0.8
|
||||
ctx.strokeStyle = colour
|
||||
ctx.beginPath()
|
||||
|
||||
// Draw shape based on type
|
||||
const [x, y, width, height] = area
|
||||
switch (shape) {
|
||||
case RenderShape.BOX: {
|
||||
ctx.rect(
|
||||
x - padding,
|
||||
y - padding,
|
||||
width + 2 * padding,
|
||||
height + 2 * padding,
|
||||
)
|
||||
break
|
||||
}
|
||||
case RenderShape.ROUND:
|
||||
case RenderShape.CARD: {
|
||||
const radius = round_radius + padding
|
||||
const isCollapsed = shape === RenderShape.CARD && collapsed
|
||||
const cornerRadii =
|
||||
isCollapsed || shape === RenderShape.ROUND
|
||||
? [radius]
|
||||
: [radius, 2, radius, 2]
|
||||
ctx.roundRect(
|
||||
x - padding,
|
||||
y - padding,
|
||||
width + 2 * padding,
|
||||
height + 2 * padding,
|
||||
cornerRadii,
|
||||
)
|
||||
break
|
||||
}
|
||||
case RenderShape.CIRCLE: {
|
||||
const centerX = x + width / 2
|
||||
const centerY = y + height / 2
|
||||
const radius = Math.max(width, height) / 2 + padding
|
||||
ctx.arc(centerX, centerY, radius, 0, Math.PI * 2)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// Stroke the shape
|
||||
ctx.stroke()
|
||||
|
||||
// Reset context
|
||||
ctx.lineWidth = lineWidth
|
||||
ctx.strokeStyle = strokeStyle
|
||||
|
||||
// TODO: Store and reset value properly. Callers currently expect this behaviour (e.g. muted nodes).
|
||||
ctx.globalAlpha = 1
|
||||
}
|
||||
|
||||
@@ -83,6 +83,7 @@ export type {
|
||||
export { CanvasPointer } from "./CanvasPointer"
|
||||
export { Reroute } from "./Reroute"
|
||||
export { createBounds } from "./measure"
|
||||
export { strokeShape } from "./draw"
|
||||
|
||||
export function clamp(v: number, a: number, b: number): number {
|
||||
return a > v ? a : b < v ? b : v
|
||||
|
||||
@@ -88,6 +88,7 @@ LiteGraphGlobal {
|
||||
"ON_TRIGGER": 3,
|
||||
"OUTPUT": 2,
|
||||
"RIGHT": 4,
|
||||
"ROUND_RADIUS": 8,
|
||||
"ROUND_SHAPE": 2,
|
||||
"Reroute": [Function],
|
||||
"SPLINE_LINK": 2,
|
||||
|
||||
Reference in New Issue
Block a user