Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion browser_tests/fixtures/ComfyPage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -564,7 +564,7 @@ export class ComfyPage {
async dragAndDrop(source: Position, target: Position) {
await this.page.mouse.move(source.x, source.y)
await this.page.mouse.down()
await this.page.mouse.move(target.x, target.y)
await this.page.mouse.move(target.x, target.y, { steps: 100 })
await this.page.mouse.up()
await this.nextFrame()
}
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 2 additions & 1 deletion src/composables/graph/useGraphNodeManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import type {
import type { IBaseWidget } from '@/lib/litegraph/src/types/widgets'
import { useLayoutMutations } from '@/renderer/core/layout/operations/layoutMutations'
import { LayoutSource } from '@/renderer/core/layout/types'
import type { NodeId } from '@/renderer/core/layout/types'
import type { InputSpec } from '@/schemas/nodeDef/nodeDefSchemaV2'
import { isDOMWidget } from '@/scripts/domWidget'
import { useNodeDefStore } from '@/stores/nodeDefStore'
Expand Down Expand Up @@ -46,7 +47,7 @@ export interface SafeWidgetData {
}

export interface VueNodeData {
id: string
id: NodeId
title: string
type: string
mode: number
Expand Down
25 changes: 13 additions & 12 deletions src/lib/litegraph/src/LGraphCanvas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1771,18 +1771,19 @@ export class LGraphCanvas
}

static onMenuNodeClone(
// @ts-expect-error - unused parameter
value: IContextMenuValue,
// @ts-expect-error - unused parameter
options: IContextMenuOptions,
// @ts-expect-error - unused parameter
e: MouseEvent,
// @ts-expect-error - unused parameter
menu: ContextMenu,
_value: IContextMenuValue,
_options: IContextMenuOptions,
_e: MouseEvent,
_menu: ContextMenu,
node: LGraphNode
): void {
const canvas = LGraphCanvas.active_canvas
const nodes = canvas.selectedItems.size ? canvas.selectedItems : [node]
const nodes = canvas.selectedItems.size ? [...canvas.selectedItems] : [node]
if (nodes.length) LGraphCanvas.cloneNodes(nodes)
}

static cloneNodes(nodes: Positionable[]) {
const canvas = LGraphCanvas.active_canvas

// Find top-left-most boundary
let offsetX = Infinity
Expand All @@ -1792,11 +1793,11 @@ export class LGraphCanvas
throw new TypeError(
'Invalid node encountered on clone. `pos` was null.'
)
if (item.pos[0] < offsetX) offsetX = item.pos[0]
if (item.pos[1] < offsetY) offsetY = item.pos[1]
offsetX = Math.min(offsetX, item.pos[0])
offsetY = Math.min(offsetY, item.pos[1])
}

canvas._deserializeItems(canvas._serializeItems(nodes), {
return canvas._deserializeItems(canvas._serializeItems(nodes), {
position: [offsetX + 5, offsetY + 5]
})
}
Expand Down
31 changes: 0 additions & 31 deletions src/renderer/core/layout/injectionKeys.ts

This file was deleted.

19 changes: 2 additions & 17 deletions src/renderer/core/layout/transform/TransformPane.vue
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,9 @@

<script setup lang="ts">
import { useRafFn } from '@vueuse/core'
import { computed, provide } from 'vue'
import { computed } from 'vue'

import type { LGraphCanvas } from '@/lib/litegraph/src/litegraph'
import { TransformStateKey } from '@/renderer/core/layout/injectionKeys'
import { useTransformSettling } from '@/renderer/core/layout/transform/useTransformSettling'
import { useTransformState } from '@/renderer/core/layout/transform/useTransformState'
import { useLOD } from '@/renderer/extensions/vueNodes/lod/useLOD'
Expand All @@ -32,14 +31,7 @@ interface TransformPaneProps {

const props = defineProps<TransformPaneProps>()

const {
camera,
transformStyle,
syncWithCanvas,
canvasToScreen,
screenToCanvas,
isNodeInViewport
} = useTransformState()
const { camera, transformStyle, syncWithCanvas } = useTransformState()

const { isLOD } = useLOD(camera)

Expand All @@ -48,13 +40,6 @@ const { isTransforming: isInteracting } = useTransformSettling(canvasElement, {
settleDelay: 512
})

provide(TransformStateKey, {
camera,
canvasToScreen,
screenToCanvas,
isNodeInViewport
})

const emit = defineEmits<{
transformUpdate: []
}>()
Expand Down
45 changes: 25 additions & 20 deletions src/renderer/core/layout/transform/useTransformState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
import { computed, reactive, readonly } from 'vue'

import type { LGraphCanvas } from '@/lib/litegraph/src/litegraph'
import { createSharedComposable } from '@vueuse/core'

interface Point {
x: number
Expand All @@ -64,7 +65,7 @@ interface Camera {
z: number // scale/zoom
}

export const useTransformState = () => {
function useTransformStateIndividual() {
// Reactive state mirroring LiteGraph's canvas transform
const camera = reactive<Camera>({
x: 0,
Expand All @@ -91,7 +92,7 @@ export const useTransformState = () => {
*
* @param canvas - LiteGraph canvas instance with DragAndScale (ds) transform state
*/
const syncWithCanvas = (canvas: LGraphCanvas) => {
function syncWithCanvas(canvas: LGraphCanvas) {
if (!canvas || !canvas.ds) return

// Mirror LiteGraph's transform state to Vue's reactive state
Expand All @@ -112,7 +113,7 @@ export const useTransformState = () => {
* @param point - Point in canvas coordinate system
* @returns Point in screen coordinate system
*/
const canvasToScreen = (point: Point): Point => {
function canvasToScreen(point: Point): Point {
return {
x: (point.x + camera.x) * camera.z,
y: (point.y + camera.y) * camera.z
Expand All @@ -138,10 +139,10 @@ export const useTransformState = () => {
}

// Get node's screen bounds for culling
const getNodeScreenBounds = (
pos: ArrayLike<number>,
size: ArrayLike<number>
): DOMRect => {
function getNodeScreenBounds(
pos: [number, number],
size: [number, number]
): DOMRect {
const topLeft = canvasToScreen({ x: pos[0], y: pos[1] })
const width = size[0] * camera.z
const height = size[1] * camera.z
Expand All @@ -150,23 +151,23 @@ export const useTransformState = () => {
}

// Helper: Calculate zoom-adjusted margin for viewport culling
const calculateAdjustedMargin = (baseMargin: number): number => {
function calculateAdjustedMargin(baseMargin: number): number {
if (camera.z < 0.1) return Math.min(baseMargin * 5, 2.0)
if (camera.z > 3.0) return Math.max(baseMargin * 0.5, 0.05)
return baseMargin
}

// Helper: Check if node is too small to be visible at current zoom
const isNodeTooSmall = (nodeSize: ArrayLike<number>): boolean => {
function isNodeTooSmall(nodeSize: [number, number]): boolean {
const nodeScreenSize = Math.max(nodeSize[0], nodeSize[1]) * camera.z
return nodeScreenSize < 4
}

// Helper: Calculate expanded viewport bounds with margin
const getExpandedViewportBounds = (
function getExpandedViewportBounds(
viewport: { width: number; height: number },
margin: number
) => {
) {
const marginX = viewport.width * margin
const marginY = viewport.height * margin
return {
Expand All @@ -178,11 +179,11 @@ export const useTransformState = () => {
}

// Helper: Test if node intersects with viewport bounds
const testViewportIntersection = (
function testViewportIntersection(
screenPos: { x: number; y: number },
nodeSize: ArrayLike<number>,
nodeSize: [number, number],
bounds: { left: number; right: number; top: number; bottom: number }
): boolean => {
): boolean {
const nodeRight = screenPos.x + nodeSize[0] * camera.z
const nodeBottom = screenPos.y + nodeSize[1] * camera.z

Expand All @@ -195,12 +196,12 @@ export const useTransformState = () => {
}

// Check if node is within viewport with frustum and size-based culling
const isNodeInViewport = (
nodePos: ArrayLike<number>,
nodeSize: ArrayLike<number>,
function isNodeInViewport(
nodePos: [number, number],
nodeSize: [number, number],
viewport: { width: number; height: number },
margin: number = 0.2
): boolean => {
): boolean {
// Early exit for tiny nodes
if (isNodeTooSmall(nodeSize)) return false

Expand All @@ -212,10 +213,10 @@ export const useTransformState = () => {
}

// Get viewport bounds in canvas coordinates (for spatial index queries)
const getViewportBounds = (
function getViewportBounds(
viewport: { width: number; height: number },
margin: number = 0.2
) => {
) {
const marginX = viewport.width * margin
const marginY = viewport.height * margin

Expand Down Expand Up @@ -244,3 +245,7 @@ export const useTransformState = () => {
getViewportBounds
}
}

export const useTransformState = createSharedComposable(
useTransformStateIndividual
)
6 changes: 3 additions & 3 deletions src/renderer/core/spatial/boundsCalculator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ interface SpatialBounds {
height: number
}

interface PositionedNode {
pos: ArrayLike<number>
size: ArrayLike<number>
export interface PositionedNode {
pos: [number, number]
size: [number, number]
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type { LGraph } from '@/lib/litegraph/src/litegraph'
import { calculateNodeBounds } from '@/renderer/core/spatial/boundsCalculator'
import type { PositionedNode } from '@/renderer/core/spatial/boundsCalculator'

import type {
IMinimapDataSource,
Expand Down Expand Up @@ -29,10 +30,12 @@ export abstract class AbstractMinimapDataSource implements IMinimapDataSource {
}

// Convert MinimapNodeData to the format expected by calculateNodeBounds
const compatibleNodes = nodes.map((node) => ({
pos: [node.x, node.y],
size: [node.width, node.height]
}))
const compatibleNodes = nodes.map(
(node): PositionedNode => ({
pos: [node.x, node.y],
size: [node.width, node.height]
})
)

const bounds = calculateNodeBounds(compatibleNodes)
if (!bounds) {
Expand Down
Loading