Cleanup/Perf: Float32Array/Float64Array removal (#5877)

## Summary

Redoing https://github.com/Comfy-Org/ComfyUI_frontend/pull/5567, without
the link rendering changes.

## Changes

- **What**: Standardizing the Point/Size/Rect logic around numeric
tuples instead of typed arrays.

## Review Focus

Cutting here and going to continue in a second PR.

Do the simpler types make sense?
Do we want to keep the behavior of Rectangle as it is now?

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-5877-WIP-Float32Array-Float64Array-removal-27f6d73d36508169a39eff1e4a87a61c)
by [Unito](https://www.unito.io)

---------

Co-authored-by: filtered <176114999+webfiltered@users.noreply.github.com>
Co-authored-by: github-actions <github-actions@github.com>
This commit is contained in:
Alexander Brown
2025-10-02 17:20:31 -07:00
committed by GitHub
parent 720de8cc8a
commit 4b1c165d43
24 changed files with 166 additions and 218 deletions

View File

@@ -151,7 +151,8 @@ class NodeSlotReference {
const convertedPos =
window['app'].canvas.ds.convertOffsetToCanvas(rawPos)
// Debug logging - convert Float32Arrays to regular arrays for visibility
// Debug logging - convert Float64Arrays to regular arrays for visibility
// eslint-disable-next-line no-console
console.log(
`NodeSlotReference debug for ${type} slot ${index} on node ${id}:`,
{

Binary file not shown.

Before

Width:  |  Height:  |  Size: 95 KiB

After

Width:  |  Height:  |  Size: 95 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 50 KiB

After

Width:  |  Height:  |  Size: 50 KiB

View File

@@ -1,7 +1,6 @@
import { toString } from 'es-toolkit/compat'
import { PREFIX, SEPARATOR } from '@/constants/groupNodeConstants'
import { LinkConnector } from '@/lib/litegraph/src/canvas/LinkConnector'
import {
type LinkRenderContext,
LitegraphLinkAdapter
@@ -17,6 +16,7 @@ import { LGraphGroup } from './LGraphGroup'
import { LGraphNode, type NodeId, type NodeProperty } from './LGraphNode'
import { LLink, type LinkId } from './LLink'
import { Reroute, type RerouteId } from './Reroute'
import { LinkConnector } from './canvas/LinkConnector'
import { isOverNodeInput, isOverNodeOutput } from './canvas/measureSlots'
import { strokeShape } from './draw'
import type {
@@ -25,6 +25,7 @@ import type {
} from './infrastructure/CustomEventTarget'
import type { LGraphCanvasEventMap } from './infrastructure/LGraphCanvasEventMap'
import { NullGraphError } from './infrastructure/NullGraphError'
import { Rectangle } from './infrastructure/Rectangle'
import type {
CanvasColour,
ColorOption,
@@ -47,12 +48,11 @@ import type {
NullableProperties,
Point,
Positionable,
ReadOnlyPoint,
ReadOnlyRect,
Rect,
Size
} from './interfaces'
import { LiteGraph, Rectangle, SubgraphNode, createUuidv4 } from './litegraph'
import { LiteGraph } from './litegraph'
import {
containsRect,
createBounds,
@@ -67,6 +67,7 @@ import { NodeInputSlot } from './node/NodeInputSlot'
import type { Subgraph } from './subgraph/Subgraph'
import { SubgraphIONodeBase } from './subgraph/SubgraphIONodeBase'
import type { SubgraphInputNode } from './subgraph/SubgraphInputNode'
import { SubgraphNode } from './subgraph/SubgraphNode'
import type { SubgraphOutputNode } from './subgraph/SubgraphOutputNode'
import type {
CanvasPointerEvent,
@@ -88,6 +89,7 @@ import type { IBaseWidget } from './types/widgets'
import { alignNodes, distributeNodes, getBoundaryNodes } from './utils/arrange'
import { findFirstNode, getAllNestedItems } from './utils/collections'
import { resolveConnectingLinkColor } from './utils/linkColors'
import { createUuidv4 } from './utils/uuid'
import type { UUID } from './utils/uuid'
import { BaseWidget } from './widgets/BaseWidget'
import { toConcreteWidget } from './widgets/widgetMap'
@@ -228,6 +230,12 @@ const cursors = {
NW: 'nwse-resize'
} as const
// Optimised buffers used during rendering
const temp = new Rectangle()
const temp_vec2: Point = [0, 0]
const tmp_area = new Rectangle()
const margin_area = new Rectangle()
const link_bounding = new Rectangle()
/**
* This class is in charge of rendering one graph inside a canvas. And provides all the interaction required.
* Valid callbacks are: onNodeSelected, onNodeDeselected, onShowNodePanel, onNodeDblClicked
@@ -235,13 +243,6 @@ const cursors = {
export class LGraphCanvas
implements CustomEventDispatcher<LGraphCanvasEventMap>
{
// Optimised buffers used during rendering
static #temp = new Float32Array(4)
static #temp_vec2 = new Float32Array(2)
static #tmp_area = new Float32Array(4)
static #margin_area = new Float32Array(4)
static #link_bounding = new Float32Array(4)
static DEFAULT_BACKGROUND_IMAGE =
'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAIAAAD/gAIDAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAQBJREFUeNrs1rEKwjAUhlETUkj3vP9rdmr1Ysammk2w5wdxuLgcMHyptfawuZX4pJSWZTnfnu/lnIe/jNNxHHGNn//HNbbv+4dr6V+11uF527arU7+u63qfa/bnmh8sWLBgwYJlqRf8MEptXPBXJXa37BSl3ixYsGDBMliwFLyCV/DeLIMFCxYsWLBMwSt4Be/NggXLYMGCBUvBK3iNruC9WbBgwYJlsGApeAWv4L1ZBgsWLFiwYJmCV/AK3psFC5bBggULloJX8BpdwXuzYMGCBctgwVLwCl7Be7MMFixYsGDBsu8FH1FaSmExVfAxBa/gvVmwYMGCZbBg/W4vAQYA5tRF9QYlv/QAAAAASUVORK5CYII='
@@ -628,7 +629,7 @@ export class LGraphCanvas
dirty_area?: Rect | null
/** @deprecated Unused */
node_in_panel?: LGraphNode | null
last_mouse: ReadOnlyPoint = [0, 0]
last_mouse: Readonly<Point> = [0, 0]
last_mouseclick: number = 0
graph: LGraph | Subgraph | null
get _graph(): LGraph | Subgraph {
@@ -2634,7 +2635,7 @@ export class LGraphCanvas
pointer: CanvasPointer,
node?: LGraphNode | undefined
): void {
const dragRect = new Float32Array(4)
const dragRect: Rect = [0, 0, 0, 0]
dragRect[0] = e.canvasX
dragRect[1] = e.canvasY
@@ -3174,7 +3175,7 @@ export class LGraphCanvas
LGraphCanvas.active_canvas = this
this.adjustMouseEvent(e)
const mouse: ReadOnlyPoint = [e.clientX, e.clientY]
const mouse: Readonly<Point> = [e.clientX, e.clientY]
this.mouse[0] = mouse[0]
this.mouse[1] = mouse[1]
const delta = [mouse[0] - this.last_mouse[0], mouse[1] - this.last_mouse[1]]
@@ -4077,7 +4078,7 @@ export class LGraphCanvas
this.setDirty(true)
}
#handleMultiSelect(e: CanvasPointerEvent, dragRect: Float32Array) {
#handleMultiSelect(e: CanvasPointerEvent, dragRect: Rect) {
// Process drag
// Convert Point pair (pos, offset) to Rect
const { graph, selectedItems, subgraph } = this
@@ -4848,7 +4849,7 @@ export class LGraphCanvas
}
/** Get the target snap / highlight point in graph space */
#getHighlightPosition(): ReadOnlyPoint {
#getHighlightPosition(): Readonly<Point> {
return LiteGraph.snaps_for_comfy
? this.linkConnector.state.snapLinksPos ??
this._highlight_pos ??
@@ -4863,7 +4864,7 @@ export class LGraphCanvas
*/
#renderSnapHighlight(
ctx: CanvasRenderingContext2D,
highlightPos: ReadOnlyPoint
highlightPos: Readonly<Point>
): void {
const linkConnectorSnap = !!this.linkConnector.state.snapLinksPos
if (!this._highlight_pos && !linkConnectorSnap) return
@@ -5204,8 +5205,9 @@ export class LGraphCanvas
// clip if required (mask)
const shape = node._shape || RenderShape.BOX
const size = LGraphCanvas.#temp_vec2
size.set(node.renderingSize)
const size = temp_vec2
size[0] = node.renderingSize[0]
size[1] = node.renderingSize[1]
if (node.collapsed) {
ctx.font = this.inner_text_font
@@ -5399,7 +5401,7 @@ export class LGraphCanvas
: true
// Normalised node dimensions
const area = LGraphCanvas.#tmp_area
const area = tmp_area
area.set(node.boundingRect)
area[0] -= node.pos[0]
area[1] -= node.pos[1]
@@ -5501,7 +5503,7 @@ export class LGraphCanvas
item: Positionable,
shape = RenderShape.ROUND
) {
const snapGuide = LGraphCanvas.#temp
const snapGuide = temp
snapGuide.set(item.boundingRect)
// Not all items have pos equal to top-left of bounds
@@ -5548,10 +5550,10 @@ export class LGraphCanvas
const now = LiteGraph.getTime()
const { visible_area } = this
LGraphCanvas.#margin_area[0] = visible_area[0] - 20
LGraphCanvas.#margin_area[1] = visible_area[1] - 20
LGraphCanvas.#margin_area[2] = visible_area[2] + 40
LGraphCanvas.#margin_area[3] = visible_area[3] + 40
margin_area[0] = visible_area[0] - 20
margin_area[1] = visible_area[1] - 20
margin_area[2] = visible_area[2] + 40
margin_area[3] = visible_area[3] + 40
// draw connections
ctx.lineWidth = this.connections_width
@@ -5772,18 +5774,13 @@ export class LGraphCanvas
// Bounding box of all points (bezier overshoot on long links will be cut)
const pointsX = points.map((x) => x[0])
const pointsY = points.map((x) => x[1])
LGraphCanvas.#link_bounding[0] = Math.min(...pointsX)
LGraphCanvas.#link_bounding[1] = Math.min(...pointsY)
LGraphCanvas.#link_bounding[2] =
Math.max(...pointsX) - LGraphCanvas.#link_bounding[0]
LGraphCanvas.#link_bounding[3] =
Math.max(...pointsY) - LGraphCanvas.#link_bounding[1]
link_bounding[0] = Math.min(...pointsX)
link_bounding[1] = Math.min(...pointsY)
link_bounding[2] = Math.max(...pointsX) - link_bounding[0]
link_bounding[3] = Math.max(...pointsY) - link_bounding[1]
// skip links outside of the visible area of the canvas
if (
!overlapBounding(LGraphCanvas.#link_bounding, LGraphCanvas.#margin_area)
)
return
if (!overlapBounding(link_bounding, margin_area)) return
const start_dir = startDirection || LinkDirection.RIGHT
const end_dir = endDirection || LinkDirection.LEFT
@@ -5942,8 +5939,8 @@ export class LGraphCanvas
*/
renderLink(
ctx: CanvasRenderingContext2D,
a: ReadOnlyPoint,
b: ReadOnlyPoint,
a: Readonly<Point>,
b: Readonly<Point>,
link: LLink | null,
skip_border: boolean,
flow: number | null,
@@ -5960,9 +5957,9 @@ export class LGraphCanvas
/** When defined, render data will be saved to this reroute instead of the {@link link}. */
reroute?: Reroute
/** Offset of the bezier curve control point from {@link a point a} (output side) */
startControl?: ReadOnlyPoint
startControl?: Readonly<Point>
/** Offset of the bezier curve control point from {@link b point b} (input side) */
endControl?: ReadOnlyPoint
endControl?: Readonly<Point>
/** Number of sublines (useful to represent vec3 or rgb) @todo If implemented, refactor calculations out of the loop */
num_sublines?: number
/** Whether this is a floating link segment */

View File

@@ -13,7 +13,7 @@ import type {
Positionable,
Size
} from './interfaces'
import { LiteGraph } from './litegraph'
import { LiteGraph, Rectangle } from './litegraph'
import {
containsCentre,
containsRect,
@@ -40,15 +40,10 @@ export class LGraphGroup implements Positionable, IPinnable, IColorable {
title: string
font?: string
font_size: number = LiteGraph.DEFAULT_GROUP_FONT || 24
_bounding: Float32Array = new Float32Array([
10,
10,
LGraphGroup.minWidth,
LGraphGroup.minHeight
])
_bounding = new Rectangle(10, 10, LGraphGroup.minWidth, LGraphGroup.minHeight)
_pos: Point = this._bounding.subarray(0, 2)
_size: Size = this._bounding.subarray(2, 4)
_pos: Point = this._bounding.pos
_size: Size = this._bounding.size
/** @deprecated See {@link _children} */
_nodes: LGraphNode[] = []
_children: Set<Positionable> = new Set()

View File

@@ -37,7 +37,6 @@ import type {
ISlotType,
Point,
Positionable,
ReadOnlyPoint,
ReadOnlyRect,
Rect,
Size
@@ -413,7 +412,7 @@ export class LGraphNode
}
/** @inheritdoc {@link renderArea} */
#renderArea: Float32Array = new Float32Array(4)
#renderArea = new Rectangle()
/**
* Rect describing the node area, including shadows and any protrusions.
* Determines if the node is visible. Calculated once at the start of every frame.
@@ -434,7 +433,7 @@ export class LGraphNode
}
/** The offset from {@link pos} to the top-left of {@link boundingRect}. */
get boundingOffset(): ReadOnlyPoint {
get boundingOffset(): Readonly<Point> {
const {
pos: [posX, posY],
boundingRect: [bX, bY]
@@ -442,10 +441,10 @@ export class LGraphNode
return [posX - bX, posY - bY]
}
/** {@link pos} and {@link size} values are backed by this {@link Rect}. */
_posSize: Float32Array = new Float32Array(4)
_pos: Point = this._posSize.subarray(0, 2)
_size: Size = this._posSize.subarray(2, 4)
/** {@link pos} and {@link size} values are backed by this {@link Rectangle}. */
_posSize = new Rectangle()
_pos: Point = this._posSize.pos
_size: Size = this._posSize.size
public get pos() {
return this._pos
@@ -1653,7 +1652,7 @@ export class LGraphNode
inputs ? inputs.filter((input) => !isWidgetInputSlot(input)).length : 1,
outputs ? outputs.length : 1
)
const size = out || new Float32Array([0, 0])
const size = out ?? [0, 0]
rows = Math.max(rows, 1)
// although it should be graphcanvas.inner_text_font size
const font_size = LiteGraph.NODE_TEXT_SIZE
@@ -2004,13 +2003,13 @@ export class LGraphNode
/**
* returns the bounding of the object, used for rendering purposes
* @param out {Float32Array[4]?} [optional] a place to store the output, to free garbage
* @param out {Rect?} [optional] a place to store the output, to free garbage
* @param includeExternal {boolean?} [optional] set to true to
* include the shadow and connection points in the bounding calculation
* @returns the bounding box in format of [topleft_cornerx, topleft_cornery, width, height]
*/
getBounding(out?: Rect, includeExternal?: boolean): Rect {
out ||= new Float32Array(4)
out ||= [0, 0, 0, 0]
const rect = includeExternal ? this.renderArea : this.boundingRect
out[0] = rect[0]
@@ -3169,7 +3168,7 @@ export class LGraphNode
* @returns the position
*/
getConnectionPos(is_input: boolean, slot_number: number, out?: Point): Point {
out ||= new Float32Array(2)
out ||= [0, 0]
const {
pos: [nodeX, nodeY],

View File

@@ -14,6 +14,7 @@ import type {
ISlotType,
LinkNetwork,
LinkSegment,
Point,
ReadonlyLinkNetwork
} from './interfaces'
import type {
@@ -109,7 +110,7 @@ export class LLink implements LinkSegment, Serialisable<SerialisableLLink> {
data?: number | string | boolean | { toToolTip?(): string }
_data?: unknown
/** Centre point of the link, calculated during render only - can be inaccurate */
_pos: Float32Array
_pos: Point
/** @todo Clean up - never implemented in comfy. */
_last_time?: number
/** The last canvas 2D path that was used to render this link */
@@ -171,7 +172,7 @@ export class LLink implements LinkSegment, Serialisable<SerialisableLLink> {
this._data = null
// center
this._pos = new Float32Array(2)
this._pos = [0, 0]
}
/** @deprecated Use {@link LLink.create} */

View File

@@ -49,8 +49,6 @@ export class Reroute
return Reroute.radius + gap + Reroute.slotRadius
}
#malloc = new Float32Array(8)
/** The network this reroute belongs to. Contains all valid links and reroutes. */
#network: WeakRef<LinkNetwork>
@@ -73,7 +71,7 @@ export class Reroute
/** This property is only defined on the last reroute of a floating reroute chain (closest to input end). */
floating?: FloatingRerouteSlot
#pos = this.#malloc.subarray(0, 2)
#pos: Point = [0, 0]
/** @inheritdoc */
get pos(): Point {
return this.#pos
@@ -126,14 +124,14 @@ export class Reroute
sin: number = 0
/** Bezier curve control point for the "target" (input) side of the link */
controlPoint: Point = this.#malloc.subarray(4, 6)
controlPoint: Point = [0, 0]
/** @inheritdoc */
path?: Path2D
/** @inheritdoc */
_centreAngle?: number
/** @inheritdoc */
_pos: Float32Array = this.#malloc.subarray(6, 8)
_pos: Point = [0, 0]
/** @inheritdoc */
_dragging?: boolean

View File

@@ -1,5 +1,5 @@
import type { Rectangle } from './infrastructure/Rectangle'
import type { CanvasColour, Rect } from './interfaces'
import type { CanvasColour } from './interfaces'
import { LiteGraph } from './litegraph'
import { RenderShape, TitleMode } from './types/globalEnums'
@@ -67,7 +67,7 @@ interface IDrawTextInAreaOptions {
*/
export function strokeShape(
ctx: CanvasRenderingContext2D,
area: Rect,
area: Rectangle,
{
shape = RenderShape.BOX,
round_radius,

View File

@@ -1,10 +1,6 @@
import { clamp } from 'es-toolkit/compat'
import type {
ReadOnlyRect,
ReadOnlySize,
Size
} from '@/lib/litegraph/src/interfaces'
import type { ReadOnlyRect, Size } from '@/lib/litegraph/src/interfaces'
/**
* Basic width and height, with min/max constraints.
@@ -55,7 +51,7 @@ export class ConstrainedSize {
this.desiredHeight = height
}
static fromSize(size: ReadOnlySize): ConstrainedSize {
static fromSize(size: Readonly<Size>): ConstrainedSize {
return new ConstrainedSize(size[0], size[1])
}
@@ -63,7 +59,7 @@ export class ConstrainedSize {
return new ConstrainedSize(rect[2], rect[3])
}
setSize(size: ReadOnlySize): void {
setSize(size: Readonly<Size>): void {
this.desiredWidth = size[0]
this.desiredHeight = size[1]
}

View File

@@ -1,9 +1,7 @@
import type {
CompassCorners,
Point,
ReadOnlyPoint,
ReadOnlyRect,
ReadOnlySize,
ReadOnlyTypedArray,
Size
} from '@/lib/litegraph/src/interfaces'
@@ -21,8 +19,8 @@ import { isInRectangle } from '@/lib/litegraph/src/measure'
* - {@link size}: The size of the rectangle.
*/
export class Rectangle extends Float64Array {
#pos: Point | undefined
#size: Size | undefined
#pos: Float64Array<ArrayBuffer> | undefined
#size: Float64Array<ArrayBuffer> | undefined
constructor(
x: number = 0,
@@ -50,7 +48,7 @@ export class Rectangle extends Float64Array {
* @returns A new rectangle whose centre is at {@link x}
*/
static fromCentre(
[x, y]: ReadOnlyPoint,
[x, y]: Readonly<Point>,
width: number,
height = width
): Rectangle {
@@ -81,10 +79,10 @@ export class Rectangle extends Float64Array {
*/
get pos(): Point {
this.#pos ??= this.subarray(0, 2)
return this.#pos!
return this.#pos! as unknown as Point
}
set pos(value: ReadOnlyPoint) {
set pos(value: Readonly<Point>) {
this[0] = value[0]
this[1] = value[1]
}
@@ -96,10 +94,10 @@ export class Rectangle extends Float64Array {
*/
get size(): Size {
this.#size ??= this.subarray(2, 4)
return this.#size!
return this.#size! as unknown as Size
}
set size(value: ReadOnlySize) {
set size(value: Readonly<Size>) {
this[2] = value[0]
this[3] = value[1]
}
@@ -215,7 +213,7 @@ export class Rectangle extends Float64Array {
* @param point The point to check
* @returns `true` if {@link point} is inside this rectangle, otherwise `false`.
*/
containsPoint([x, y]: ReadOnlyPoint): boolean {
containsPoint([x, y]: Readonly<Point>): boolean {
const [left, top, width, height] = this
return x >= left && x < left + width && y >= top && y < top + height
}
@@ -384,12 +382,12 @@ export class Rectangle extends Float64Array {
}
/** @returns The offset from the top-left of this rectangle to the point [{@link x}, {@link y}], as a new {@link Point}. */
getOffsetTo([x, y]: ReadOnlyPoint): Point {
getOffsetTo([x, y]: Readonly<Point>): Point {
return [x - this[0], y - this[1]]
}
/** @returns The offset from the point [{@link x}, {@link y}] to the top-left of this rectangle, as a new {@link Point}. */
getOffsetFrom([x, y]: ReadOnlyPoint): Point {
getOffsetFrom([x, y]: Readonly<Point>): Point {
return [this[0] - x, this[1] - y]
}

View File

@@ -194,7 +194,7 @@ export interface LinkSegment {
/** The last canvas 2D path that was used to render this segment */
path?: Path2D
/** Centre point of the {@link path}. Calculated during render only - can be inaccurate */
readonly _pos: Float32Array
readonly _pos: Point
/**
* Y-forward along the {@link path} from its centre point, in radians.
* `undefined` if using circles for link centres.
@@ -226,52 +226,25 @@ export interface IFoundSlot extends IInputOrOutput {
}
/** A point represented as `[x, y]` co-ordinates */
export type Point = [x: number, y: number] | Float32Array | Float64Array
export type Point = [x: number, y: number]
/** A size represented as `[width, height]` */
export type Size = [width: number, height: number] | Float32Array | Float64Array
/** A very firm array */
type ArRect = [x: number, y: number, width: number, height: number]
export type Size = [width: number, height: number]
/** A rectangle starting at top-left coordinates `[x, y, width, height]` */
export type Rect = ArRect | Float32Array | Float64Array
/** A point represented as `[x, y]` co-ordinates that will not be modified */
export type ReadOnlyPoint =
| readonly [x: number, y: number]
| ReadOnlyTypedArray<Float32Array>
| ReadOnlyTypedArray<Float64Array>
/** A size represented as `[width, height]` that will not be modified */
export type ReadOnlySize =
| readonly [width: number, height: number]
| ReadOnlyTypedArray<Float32Array>
| ReadOnlyTypedArray<Float64Array>
export type Rect =
| [x: number, y: number, width: number, height: number]
| Float64Array
/** A rectangle starting at top-left coordinates `[x, y, width, height]` that will not be modified */
export type ReadOnlyRect =
| readonly [x: number, y: number, width: number, height: number]
| ReadOnlyTypedArray<Float32Array>
| ReadOnlyTypedArray<Float64Array>
type TypedArrays =
| Int8Array
| Uint8Array
| Uint8ClampedArray
| Int16Array
| Uint16Array
| Int32Array
| Uint32Array
| Float32Array
| Float64Array
type TypedBigIntArrays = BigInt64Array | BigUint64Array
export type ReadOnlyTypedArray<T extends TypedArrays | TypedBigIntArrays> =
Omit<
Readonly<T>,
'fill' | 'copyWithin' | 'reverse' | 'set' | 'sort' | 'subarray'
>
export type ReadOnlyTypedArray<T extends Float64Array> = Omit<
Readonly<T>,
'fill' | 'copyWithin' | 'reverse' | 'set' | 'sort' | 'subarray'
>
/** Union of property names that are of type Match */
type KeysOfType<T, Match> = Exclude<
@@ -330,7 +303,7 @@ export interface INodeSlot extends HasBoundingRect {
nameLocked?: boolean
pos?: Point
/** @remarks Automatically calculated; not included in serialisation. */
boundingRect: Rect
boundingRect: ReadOnlyRect
/**
* A list of floating link IDs that are connected to this slot.
* This is calculated at runtime; it is **not** serialized.

View File

@@ -1,10 +1,4 @@
import type {
HasBoundingRect,
Point,
ReadOnlyPoint,
ReadOnlyRect,
Rect
} from './interfaces'
import type { HasBoundingRect, Point, ReadOnlyRect, Rect } from './interfaces'
import { Alignment, LinkDirection, hasFlag } from './types/globalEnums'
/**
@@ -13,7 +7,7 @@ import { Alignment, LinkDirection, hasFlag } from './types/globalEnums'
* @param b Point b as `x, y`
* @returns Distance between point {@link a} & {@link b}
*/
export function distance(a: ReadOnlyPoint, b: ReadOnlyPoint): number {
export function distance(a: Readonly<Point>, b: Readonly<Point>): number {
return Math.sqrt(
(b[0] - a[0]) * (b[0] - a[0]) + (b[1] - a[1]) * (b[1] - a[1])
)
@@ -62,7 +56,7 @@ export function isInRectangle(
* @returns `true` if the point is inside the rect, otherwise `false`
*/
export function isPointInRect(
point: ReadOnlyPoint,
point: Readonly<Point>,
rect: ReadOnlyRect
): boolean {
return (
@@ -289,8 +283,8 @@ export function rotateLink(
* the right
*/
export function getOrientation(
lineStart: ReadOnlyPoint,
lineEnd: ReadOnlyPoint,
lineStart: Readonly<Point>,
lineEnd: Readonly<Point>,
x: number,
y: number
): number {
@@ -310,10 +304,10 @@ export function getOrientation(
*/
export function findPointOnCurve(
out: Point,
a: ReadOnlyPoint,
b: ReadOnlyPoint,
controlA: ReadOnlyPoint,
controlB: ReadOnlyPoint,
a: Readonly<Point>,
b: Readonly<Point>,
controlA: Readonly<Point>,
controlB: Readonly<Point>,
t: number = 0.5
): void {
const iT = 1 - t
@@ -331,7 +325,7 @@ export function createBounds(
objects: Iterable<HasBoundingRect>,
padding: number = 10
): ReadOnlyRect | null {
const bounds = new Float32Array([Infinity, Infinity, -Infinity, -Infinity])
const bounds: Rect = [Infinity, Infinity, -Infinity, -Infinity]
for (const obj of objects) {
const rect = obj.boundingRect
@@ -382,7 +376,7 @@ export function alignToContainer(
rect: Rect,
anchors: Alignment,
[containerX, containerY, containerWidth, containerHeight]: ReadOnlyRect,
[insetX, insetY]: ReadOnlyPoint = [0, 0]
[insetX, insetY]: Readonly<Point> = [0, 0]
): Rect {
if (hasFlag(anchors, Alignment.Left)) {
// Left
@@ -425,7 +419,7 @@ export function alignOutsideContainer(
rect: Rect,
anchors: Alignment,
[otherX, otherY, otherWidth, otherHeight]: ReadOnlyRect,
[outsetX, outsetY]: ReadOnlyPoint = [0, 0]
[outsetX, outsetY]: Readonly<Point> = [0, 0]
): Rect {
if (hasFlag(anchors, Alignment.Left)) {
// Left

View File

@@ -5,7 +5,7 @@ import type {
INodeInputSlot,
INodeOutputSlot,
OptionalProps,
ReadOnlyPoint
Point
} from '@/lib/litegraph/src/interfaces'
import { LiteGraph } from '@/lib/litegraph/src/litegraph'
import { type IDrawOptions, NodeSlot } from '@/lib/litegraph/src/node/NodeSlot'
@@ -32,7 +32,7 @@ export class NodeInputSlot extends NodeSlot implements INodeInputSlot {
this.#widget = widget ? new WeakRef(widget) : undefined
}
get collapsedPos(): ReadOnlyPoint {
get collapsedPos(): Readonly<Point> {
return [0, LiteGraph.NODE_TITLE_HEIGHT * -0.5]
}

View File

@@ -5,7 +5,7 @@ import type {
INodeInputSlot,
INodeOutputSlot,
OptionalProps,
ReadOnlyPoint
Point
} from '@/lib/litegraph/src/interfaces'
import { LiteGraph } from '@/lib/litegraph/src/litegraph'
import { type IDrawOptions, NodeSlot } from '@/lib/litegraph/src/node/NodeSlot'
@@ -24,7 +24,7 @@ export class NodeOutputSlot extends NodeSlot implements INodeOutputSlot {
return false
}
get collapsedPos(): ReadOnlyPoint {
get collapsedPos(): Readonly<Point> {
return [
this.#node._collapsed_width ?? LiteGraph.NODE_COLLAPSED_WIDTH,
LiteGraph.NODE_TITLE_HEIGHT * -0.5

View File

@@ -8,8 +8,7 @@ import type {
INodeSlot,
ISubgraphInput,
OptionalProps,
Point,
ReadOnlyPoint
Point
} from '@/lib/litegraph/src/interfaces'
import { LiteGraph, Rectangle } from '@/lib/litegraph/src/litegraph'
import { getCentre } from '@/lib/litegraph/src/measure'
@@ -36,7 +35,7 @@ export abstract class NodeSlot extends SlotBase implements INodeSlot {
pos?: Point
/** The offset from the parent node to the centre point of this slot. */
get #centreOffset(): ReadOnlyPoint {
get #centreOffset(): Readonly<Point> {
const nodePos = this.node.pos
const { boundingRect } = this
@@ -52,7 +51,7 @@ export abstract class NodeSlot extends SlotBase implements INodeSlot {
}
/** The center point of this slot when the node is collapsed. */
abstract get collapsedPos(): ReadOnlyPoint
abstract get collapsedPos(): Readonly<Point>
#node: LGraphNode
get node(): LGraphNode {

View File

@@ -12,7 +12,7 @@ import type {
INodeOutputSlot,
Point,
ReadOnlyRect,
ReadOnlySize
Size
} from '@/lib/litegraph/src/interfaces'
import { LiteGraph } from '@/lib/litegraph/src/litegraph'
import { SlotBase } from '@/lib/litegraph/src/node/SlotBase'
@@ -45,7 +45,7 @@ export abstract class SubgraphSlot
return LiteGraph.NODE_SLOT_HEIGHT
}
readonly #pos: Point = new Float32Array(2)
readonly #pos: Point = [0, 0]
readonly measurement: ConstrainedSize = new ConstrainedSize(
SubgraphSlot.defaultHeight,
@@ -133,7 +133,7 @@ export abstract class SubgraphSlot
}
}
measure(): ReadOnlySize {
measure(): Readonly<Size> {
const width = LGraphCanvas._measureText?.(this.displayName) ?? 0
const { defaultHeight } = SubgraphSlot

View File

@@ -84,8 +84,8 @@ describe('LGraphNode', () => {
}))
}
node.configure(configureData)
expect(node.pos).toEqual(new Float32Array([50, 60]))
expect(node.size).toEqual(new Float32Array([70, 80]))
expect(node.pos).toEqual([50, 60])
expect(node.size).toEqual([70, 80])
})
test('should configure inputs correctly', () => {
@@ -266,7 +266,7 @@ describe('LGraphNode', () => {
const node = new LGraphNode('TestNode') as unknown as Omit<
LGraphNode,
'boundingRect'
> & { boundingRect: Float32Array }
> & { boundingRect: Float64Array }
node.pos = [100, 100]
node.size = [100, 100]
node.boundingRect[0] = 100
@@ -335,7 +335,7 @@ describe('LGraphNode', () => {
const node = new LGraphNode('TestNode') as unknown as Omit<
LGraphNode,
'boundingRect'
> & { boundingRect: Float32Array }
> & { boundingRect: Float64Array }
node.pos = [100, 100]
node.size = [100, 100]
node.boundingRect[0] = 100
@@ -367,7 +367,7 @@ describe('LGraphNode', () => {
const node = new LGraphNode('TestNode') as unknown as Omit<
LGraphNode,
'boundingRect'
> & { boundingRect: Float32Array }
> & { boundingRect: Float64Array }
node.pos = [100, 100]
node.size = [100, 100]
node.boundingRect[0] = 100
@@ -400,7 +400,7 @@ describe('LGraphNode', () => {
const node = new LGraphNode('TestNode') as unknown as Omit<
LGraphNode,
'boundingRect'
> & { boundingRect: Float32Array }
> & { boundingRect: Float64Array }
node.pos = [100, 100]
node.size = [100, 100]
node.boundingRect[0] = 100
@@ -571,7 +571,7 @@ describe('LGraphNode', () => {
name: 'test_in',
type: 'string',
link: null,
boundingRect: new Float32Array([0, 0, 0, 0])
boundingRect: [0, 0, 0, 0]
}
})
test('should return position based on title height when collapsed', () => {
@@ -590,11 +590,11 @@ describe('LGraphNode', () => {
test('should return default vertical position when input.pos is undefined and not collapsed', () => {
node.flags.collapsed = false
const inputSlot2 = {
const inputSlot2: INodeInputSlot = {
name: 'test_in_2',
type: 'number',
link: null,
boundingRect: new Float32Array([0, 0, 0, 0])
boundingRect: [0, 0, 0, 0]
}
node.inputs = [inputSlot, inputSlot2]
const slotIndex = 0
@@ -629,13 +629,13 @@ describe('LGraphNode', () => {
name: 'in0',
type: 'string',
link: null,
boundingRect: new Float32Array([0, 0, 0, 0])
boundingRect: [0, 0, 0, 0]
}
const input1: INodeInputSlot = {
name: 'in1',
type: 'number',
link: null,
boundingRect: new Float32Array([0, 0, 0, 0]),
boundingRect: [0, 0, 0, 0],
pos: [5, 45]
}
node.inputs = [input0, input1]

View File

@@ -1,6 +1,6 @@
import type { LGraphCanvas } from '@/lib/litegraph/src/LGraphCanvas'
import type { RenderLink } from '@/lib/litegraph/src/canvas/RenderLink'
import type { ReadOnlyPoint } from '@/lib/litegraph/src/interfaces'
import type { Point } from '@/lib/litegraph/src/interfaces'
import { LinkDirection } from '@/lib/litegraph/src/types/globalEnums'
import { resolveConnectingLinkColor } from '@/lib/litegraph/src/utils/linkColors'
import { createLinkConnectorAdapter } from '@/renderer/core/canvas/links/linkConnectorAdapter'
@@ -49,7 +49,7 @@ export function attachSlotLinkPreviewRenderer(canvas: LGraphCanvas) {
const renderLinks = createLinkConnectorAdapter()?.renderLinks
if (!renderLinks || renderLinks.length === 0) return
const to: ReadOnlyPoint = [pointer.canvas.x, pointer.canvas.y]
const to: Readonly<Point> = [pointer.canvas.x, pointer.canvas.y]
ctx.save()
for (const link of renderLinks) {
const startDir = link.fromDirection ?? LinkDirection.RIGHT
@@ -74,7 +74,7 @@ export function attachSlotLinkPreviewRenderer(canvas: LGraphCanvas) {
canvas.onDrawForeground = patched
}
function resolveRenderLinkOrigin(link: RenderLink): ReadOnlyPoint {
function resolveRenderLinkOrigin(link: RenderLink): Readonly<Point> {
if (link.fromReroute) {
const rerouteLayout = layoutStore.getRerouteLayout(link.fromReroute.id)
if (rerouteLayout) {

View File

@@ -8,10 +8,7 @@
*/
import type { LLink } from '@/lib/litegraph/src/LLink'
import type { Reroute } from '@/lib/litegraph/src/Reroute'
import type {
CanvasColour,
ReadOnlyPoint
} from '@/lib/litegraph/src/interfaces'
import type { CanvasColour, Point } from '@/lib/litegraph/src/interfaces'
import { LiteGraph } from '@/lib/litegraph/src/litegraph'
import {
LinkDirection,
@@ -24,7 +21,7 @@ import {
type Direction,
type LinkRenderData,
type RenderContext as PathRenderContext,
type Point,
type Point as PointObj,
type RenderMode
} from '@/renderer/core/canvas/pathRenderer'
import { layoutStore } from '@/renderer/core/layout/store/layoutStore'
@@ -172,7 +169,7 @@ export class LitegraphLinkAdapter {
* Critically: does nothing for CENTER/NONE directions (no case for them)
*/
private applySplineOffset(
point: Point,
point: PointObj,
direction: LinkDirection,
distance: number
): void {
@@ -199,8 +196,8 @@ export class LitegraphLinkAdapter {
*/
renderLinkDirect(
ctx: CanvasRenderingContext2D,
a: ReadOnlyPoint,
b: ReadOnlyPoint,
a: Readonly<Point>,
b: Readonly<Point>,
link: LLink | null,
skip_border: boolean,
flow: number | boolean | null,
@@ -210,8 +207,8 @@ export class LitegraphLinkAdapter {
context: LinkRenderContext,
extras: {
reroute?: Reroute
startControl?: ReadOnlyPoint
endControl?: ReadOnlyPoint
startControl?: Readonly<Point>
endControl?: Readonly<Point>
num_sublines?: number
disabled?: boolean
} = {}
@@ -250,7 +247,7 @@ export class LitegraphLinkAdapter {
)
const factor = 0.25
const cps: Point[] = []
const cps: PointObj[] = []
if (hasStartCtrl && hasEndCtrl) {
// Both provided explicitly
@@ -315,7 +312,7 @@ export class LitegraphLinkAdapter {
// Copy calculated center position back to litegraph object
// This is needed for hit detection and menu interaction
if (linkData.centerPos) {
linkSegment._pos = linkSegment._pos || new Float32Array(2)
linkSegment._pos = linkSegment._pos || [0, 0]
linkSegment._pos[0] = linkData.centerPos.x
linkSegment._pos[1] = linkData.centerPos.y
@@ -329,8 +326,8 @@ export class LitegraphLinkAdapter {
if (this.enableLayoutStoreWrites && link && link.id !== -1) {
// Calculate bounds and center only when writing
const bounds = this.calculateLinkBounds(
[linkData.startPoint.x, linkData.startPoint.y] as ReadOnlyPoint,
[linkData.endPoint.x, linkData.endPoint.y] as ReadOnlyPoint,
[linkData.startPoint.x, linkData.startPoint.y] as Readonly<Point>,
[linkData.endPoint.x, linkData.endPoint.y] as Readonly<Point>,
linkData
)
const centerPos = linkData.centerPos || {
@@ -365,8 +362,8 @@ export class LitegraphLinkAdapter {
renderDraggingLink(
ctx: CanvasRenderingContext2D,
from: ReadOnlyPoint,
to: ReadOnlyPoint,
from: Readonly<Point>,
to: Readonly<Point>,
colour: CanvasColour,
startDir: LinkDirection,
endDir: LinkDirection,
@@ -397,8 +394,8 @@ export class LitegraphLinkAdapter {
* Includes padding for line width and control points
*/
private calculateLinkBounds(
startPos: ReadOnlyPoint,
endPos: ReadOnlyPoint,
startPos: Readonly<Point>,
endPos: Readonly<Point>,
linkData: LinkRenderData
): Bounds {
let minX = Math.min(startPos[0], endPos[0])

View File

@@ -4,7 +4,7 @@ import { computed, ref, toValue } from 'vue'
import type { LGraphCanvas } from '@/lib/litegraph/src/LGraphCanvas'
import { LLink } from '@/lib/litegraph/src/LLink'
import { Reroute } from '@/lib/litegraph/src/Reroute'
import type { ReadOnlyPoint } from '@/lib/litegraph/src/interfaces'
import type { Point } from '@/lib/litegraph/src/interfaces'
import { LinkDirection } from '@/lib/litegraph/src/types/globalEnums'
import { LitegraphLinkAdapter } from '@/renderer/core/canvas/litegraph/litegraphLinkAdapter'
import type { LinkRenderContext } from '@/renderer/core/canvas/litegraph/litegraphLinkAdapter'
@@ -113,7 +113,7 @@ export function useLinkLayoutSync() {
// Special handling for floating input chain
const isFloatingInputChain = !sourceNode && targetNode
const startControl: ReadOnlyPoint = isFloatingInputChain
const startControl: Readonly<Point> = isFloatingInputChain
? [0, 0]
: [dist * reroute.cos, dist * reroute.sin]
@@ -149,7 +149,7 @@ export function useLinkLayoutSync() {
(endPos[1] - lastReroute.pos[1]) ** 2
)
const finalDist = Math.min(Reroute.maxSplineOffset, finalDistance * 0.25)
const finalStartControl: ReadOnlyPoint = [
const finalStartControl: Readonly<Point> = [
finalDist * lastReroute.cos,
finalDist * lastReroute.sin
]

View File

@@ -93,16 +93,16 @@ const mountSlots = (nodeData: VueNodeData, readonly = false) => {
describe('NodeSlots.vue', () => {
it('filters out inputs with widget property and maps indexes correctly', () => {
// Two inputs without widgets (object and string) and one with widget (filtered)
const inputObjNoWidget = {
const inputObjNoWidget: INodeInputSlot = {
name: 'objNoWidget',
type: 'number',
boundingRect: new Float32Array([0, 0, 0, 0]),
boundingRect: [0, 0, 0, 0],
link: null
}
const inputObjWithWidget = {
const inputObjWithWidget: INodeInputSlot = {
name: 'objWithWidget',
type: 'number',
boundingRect: new Float32Array([0, 0, 0, 0]),
boundingRect: [0, 0, 0, 0],
widget: { name: 'objWithWidget' },
link: null
}
@@ -147,16 +147,16 @@ describe('NodeSlots.vue', () => {
})
it('maps outputs and passes correct indexes', () => {
const outputObj = {
const outputObj: INodeOutputSlot = {
name: 'outA',
type: 'any',
boundingRect: new Float32Array([0, 0, 0, 0]),
boundingRect: [0, 0, 0, 0],
links: []
}
const outputObjB = {
const outputObjB: INodeOutputSlot = {
name: 'outB',
type: 'any',
boundingRect: new Float32Array([0, 0, 0, 0]),
boundingRect: [0, 0, 0, 0],
links: []
}
const outputs: INodeOutputSlot[] = [outputObj, outputObjB]

View File

@@ -84,8 +84,8 @@ describe('LGraphNode', () => {
}))
}
node.configure(configureData)
expect(node.pos).toEqual(new Float32Array([50, 60]))
expect(node.size).toEqual(new Float32Array([70, 80]))
expect(node.pos).toEqual(new Float64Array([50, 60]))
expect(node.size).toEqual(new Float64Array([70, 80]))
})
test('should configure inputs correctly', () => {
@@ -266,7 +266,7 @@ describe('LGraphNode', () => {
const node = new LGraphNode('TestNode') as unknown as Omit<
LGraphNode,
'boundingRect'
> & { boundingRect: Float32Array }
> & { boundingRect: Float64Array }
node.pos = [100, 100]
node.size = [100, 100]
node.boundingRect[0] = 100
@@ -335,7 +335,7 @@ describe('LGraphNode', () => {
const node = new LGraphNode('TestNode') as unknown as Omit<
LGraphNode,
'boundingRect'
> & { boundingRect: Float32Array }
> & { boundingRect: Float64Array }
node.pos = [100, 100]
node.size = [100, 100]
node.boundingRect[0] = 100
@@ -367,7 +367,7 @@ describe('LGraphNode', () => {
const node = new LGraphNode('TestNode') as unknown as Omit<
LGraphNode,
'boundingRect'
> & { boundingRect: Float32Array }
> & { boundingRect: Float64Array }
node.pos = [100, 100]
node.size = [100, 100]
node.boundingRect[0] = 100
@@ -400,7 +400,7 @@ describe('LGraphNode', () => {
const node = new LGraphNode('TestNode') as unknown as Omit<
LGraphNode,
'boundingRect'
> & { boundingRect: Float32Array }
> & { boundingRect: Float64Array }
node.pos = [100, 100]
node.size = [100, 100]
node.boundingRect[0] = 100
@@ -571,7 +571,7 @@ describe('LGraphNode', () => {
name: 'test_in',
type: 'string',
link: null,
boundingRect: new Float32Array([0, 0, 0, 0])
boundingRect: [0, 0, 0, 0]
}
})
test('should return position based on title height when collapsed', () => {
@@ -590,11 +590,11 @@ describe('LGraphNode', () => {
test('should return default vertical position when input.pos is undefined and not collapsed', () => {
node.flags.collapsed = false
const inputSlot2 = {
const inputSlot2: INodeInputSlot = {
name: 'test_in_2',
type: 'number',
link: null,
boundingRect: new Float32Array([0, 0, 0, 0])
boundingRect: [0, 0, 0, 0]
}
node.inputs = [inputSlot, inputSlot2]
const slotIndex = 0

View File

@@ -4,7 +4,7 @@ exports[`LGraph > supports schema v0.4 graphs > oldSchemaGraph 1`] = `
LGraph {
"_groups": [
LGraphGroup {
"_bounding": Float32Array [
"_bounding": Rectangle [
20,
20,
1,
@@ -12,11 +12,11 @@ LGraph {
],
"_children": Set {},
"_nodes": [],
"_pos": Float32Array [
"_pos": Float64Array [
20,
20,
],
"_size": Float32Array [
"_size": Float64Array [
1,
3,
],
@@ -39,11 +39,11 @@ LGraph {
LGraphNode {
"_collapsed_width": undefined,
"_level": undefined,
"_pos": Float32Array [
"_pos": Float64Array [
10,
10,
],
"_posSize": Float32Array [
"_posSize": Rectangle [
10,
10,
140,
@@ -51,7 +51,7 @@ LGraph {
],
"_relative_id": undefined,
"_shape": undefined,
"_size": Float32Array [
"_size": Float64Array [
140,
60,
],
@@ -111,11 +111,11 @@ LGraph {
"1": LGraphNode {
"_collapsed_width": undefined,
"_level": undefined,
"_pos": Float32Array [
"_pos": Float64Array [
10,
10,
],
"_posSize": Float32Array [
"_posSize": Rectangle [
10,
10,
140,
@@ -123,7 +123,7 @@ LGraph {
],
"_relative_id": undefined,
"_shape": undefined,
"_size": Float32Array [
"_size": Float64Array [
140,
60,
],
@@ -184,11 +184,11 @@ LGraph {
LGraphNode {
"_collapsed_width": undefined,
"_level": undefined,
"_pos": Float32Array [
"_pos": Float64Array [
10,
10,
],
"_posSize": Float32Array [
"_posSize": Rectangle [
10,
10,
140,
@@ -196,7 +196,7 @@ LGraph {
],
"_relative_id": undefined,
"_shape": undefined,
"_size": Float32Array [
"_size": Float64Array [
140,
60,
],