mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-02-27 18:24:11 +00:00
refactor: Reorganize layout system into new renderer architecture (#5071)
- Move layout system to renderer/core/layout/ - Store, operations, adapters, and sync modules organized clearly - Merged layoutTypes.ts and layoutOperations.ts into single types.ts - Move canvas rendering to renderer/core/canvas/ - LiteGraph-specific code in litegraph/ subdirectory - PathRenderer at canvas level - Move spatial indexing to renderer/core/spatial/ - Move Vue node composables to renderer/extensions/vue-nodes/ - Update all import paths throughout codebase - Apply consistent naming (renderer vs rendering) This establishes clearer separation between core rendering concerns and optional extensions, making the architecture more maintainable. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -1,150 +0,0 @@
|
||||
/**
|
||||
* Layout Mutations - Simplified Direct Operations
|
||||
*
|
||||
* Provides a clean API for layout operations that are CRDT-ready.
|
||||
* Operations are synchronous and applied directly to the store.
|
||||
*/
|
||||
import { layoutStore } from '@/stores/layoutStore'
|
||||
import type {
|
||||
LayoutMutations,
|
||||
NodeId,
|
||||
NodeLayout,
|
||||
Point,
|
||||
Size
|
||||
} from '@/types/layoutTypes'
|
||||
|
||||
class LayoutMutationsImpl implements LayoutMutations {
|
||||
/**
|
||||
* Set the current mutation source
|
||||
*/
|
||||
setSource(source: 'canvas' | 'vue' | 'external'): void {
|
||||
layoutStore.setSource(source)
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the current actor (for CRDT)
|
||||
*/
|
||||
setActor(actor: string): void {
|
||||
layoutStore.setActor(actor)
|
||||
}
|
||||
|
||||
/**
|
||||
* Move a node to a new position
|
||||
*/
|
||||
moveNode(nodeId: NodeId, position: Point): void {
|
||||
const existing = layoutStore.getNodeLayoutRef(nodeId).value
|
||||
if (!existing) return
|
||||
|
||||
layoutStore.applyOperation({
|
||||
type: 'moveNode',
|
||||
nodeId,
|
||||
position,
|
||||
previousPosition: existing.position,
|
||||
timestamp: Date.now(),
|
||||
source: layoutStore.getCurrentSource(),
|
||||
actor: layoutStore.getCurrentActor()
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Resize a node
|
||||
*/
|
||||
resizeNode(nodeId: NodeId, size: Size): void {
|
||||
const existing = layoutStore.getNodeLayoutRef(nodeId).value
|
||||
if (!existing) return
|
||||
|
||||
layoutStore.applyOperation({
|
||||
type: 'resizeNode',
|
||||
nodeId,
|
||||
size,
|
||||
previousSize: existing.size,
|
||||
timestamp: Date.now(),
|
||||
source: layoutStore.getCurrentSource(),
|
||||
actor: layoutStore.getCurrentActor()
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Set node z-index
|
||||
*/
|
||||
setNodeZIndex(nodeId: NodeId, zIndex: number): void {
|
||||
const existing = layoutStore.getNodeLayoutRef(nodeId).value
|
||||
if (!existing) return
|
||||
|
||||
layoutStore.applyOperation({
|
||||
type: 'setNodeZIndex',
|
||||
nodeId,
|
||||
zIndex,
|
||||
previousZIndex: existing.zIndex,
|
||||
timestamp: Date.now(),
|
||||
source: layoutStore.getCurrentSource(),
|
||||
actor: layoutStore.getCurrentActor()
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new node
|
||||
*/
|
||||
createNode(nodeId: NodeId, layout: Partial<NodeLayout>): void {
|
||||
const fullLayout: NodeLayout = {
|
||||
id: nodeId,
|
||||
position: layout.position ?? { x: 0, y: 0 },
|
||||
size: layout.size ?? { width: 200, height: 100 },
|
||||
zIndex: layout.zIndex ?? 0,
|
||||
visible: layout.visible ?? true,
|
||||
bounds: {
|
||||
x: layout.position?.x ?? 0,
|
||||
y: layout.position?.y ?? 0,
|
||||
width: layout.size?.width ?? 200,
|
||||
height: layout.size?.height ?? 100
|
||||
}
|
||||
}
|
||||
|
||||
layoutStore.applyOperation({
|
||||
type: 'createNode',
|
||||
nodeId,
|
||||
layout: fullLayout,
|
||||
timestamp: Date.now(),
|
||||
source: layoutStore.getCurrentSource(),
|
||||
actor: layoutStore.getCurrentActor()
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a node
|
||||
*/
|
||||
deleteNode(nodeId: NodeId): void {
|
||||
const existing = layoutStore.getNodeLayoutRef(nodeId).value
|
||||
if (!existing) return
|
||||
|
||||
layoutStore.applyOperation({
|
||||
type: 'deleteNode',
|
||||
nodeId,
|
||||
previousLayout: existing,
|
||||
timestamp: Date.now(),
|
||||
source: layoutStore.getCurrentSource(),
|
||||
actor: layoutStore.getCurrentActor()
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Bring a node to the front (highest z-index)
|
||||
*/
|
||||
bringNodeToFront(nodeId: NodeId): void {
|
||||
// Get all nodes to find the highest z-index
|
||||
const allNodes = layoutStore.getAllNodes().value
|
||||
let maxZIndex = 0
|
||||
|
||||
for (const [, layout] of allNodes) {
|
||||
if (layout.zIndex > maxZIndex) {
|
||||
maxZIndex = layout.zIndex
|
||||
}
|
||||
}
|
||||
|
||||
// Set this node's z-index to be one higher than the current max
|
||||
this.setNodeZIndex(nodeId, maxZIndex + 1)
|
||||
}
|
||||
}
|
||||
|
||||
// Create singleton instance
|
||||
export const layoutMutations = new LayoutMutationsImpl()
|
||||
@@ -1,166 +0,0 @@
|
||||
/**
|
||||
* Spatial Index Manager
|
||||
*
|
||||
* Manages spatial indexing for efficient node queries based on bounds.
|
||||
* Uses QuadTree for fast spatial lookups with caching for performance.
|
||||
*/
|
||||
import { PERFORMANCE_CONFIG, QUADTREE_CONFIG } from '@/constants/layout'
|
||||
import type { Bounds, NodeId } from '@/types/layoutTypes'
|
||||
import { QuadTree } from '@/utils/spatial/QuadTree'
|
||||
|
||||
/**
|
||||
* Cache entry for spatial queries
|
||||
*/
|
||||
interface CacheEntry {
|
||||
result: NodeId[]
|
||||
timestamp: number
|
||||
}
|
||||
|
||||
/**
|
||||
* Spatial index manager using QuadTree
|
||||
*/
|
||||
export class SpatialIndexManager {
|
||||
private quadTree: QuadTree<NodeId>
|
||||
private queryCache: Map<string, CacheEntry>
|
||||
private cacheSize = 0
|
||||
|
||||
constructor(bounds?: Bounds) {
|
||||
this.quadTree = new QuadTree<NodeId>(
|
||||
bounds ?? QUADTREE_CONFIG.DEFAULT_BOUNDS,
|
||||
{
|
||||
maxDepth: QUADTREE_CONFIG.MAX_DEPTH,
|
||||
maxItemsPerNode: QUADTREE_CONFIG.MAX_ITEMS_PER_NODE
|
||||
}
|
||||
)
|
||||
this.queryCache = new Map()
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert a node into the spatial index
|
||||
*/
|
||||
insert(nodeId: NodeId, bounds: Bounds): void {
|
||||
this.quadTree.insert(nodeId, bounds, nodeId)
|
||||
this.invalidateCache()
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a node's bounds in the spatial index
|
||||
*/
|
||||
update(nodeId: NodeId, bounds: Bounds): void {
|
||||
this.quadTree.update(nodeId, bounds)
|
||||
this.invalidateCache()
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a node from the spatial index
|
||||
*/
|
||||
remove(nodeId: NodeId): void {
|
||||
this.quadTree.remove(nodeId)
|
||||
this.invalidateCache()
|
||||
}
|
||||
|
||||
/**
|
||||
* Query nodes within the given bounds
|
||||
*/
|
||||
query(bounds: Bounds): NodeId[] {
|
||||
const cacheKey = this.getCacheKey(bounds)
|
||||
const cached = this.queryCache.get(cacheKey)
|
||||
|
||||
// Check cache validity
|
||||
if (cached) {
|
||||
const age = Date.now() - cached.timestamp
|
||||
if (age < PERFORMANCE_CONFIG.SPATIAL_CACHE_TTL) {
|
||||
return cached.result
|
||||
}
|
||||
// Remove stale entry
|
||||
this.queryCache.delete(cacheKey)
|
||||
this.cacheSize--
|
||||
}
|
||||
|
||||
// Perform query
|
||||
const result = this.quadTree.query(bounds)
|
||||
|
||||
// Cache result
|
||||
this.addToCache(cacheKey, result)
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear all nodes from the spatial index
|
||||
*/
|
||||
clear(): void {
|
||||
this.quadTree.clear()
|
||||
this.invalidateCache()
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current size of the index
|
||||
*/
|
||||
get size(): number {
|
||||
return this.quadTree.size
|
||||
}
|
||||
|
||||
/**
|
||||
* Get debug information about the spatial index
|
||||
*/
|
||||
getDebugInfo() {
|
||||
return {
|
||||
quadTreeInfo: this.quadTree.getDebugInfo(),
|
||||
cacheSize: this.cacheSize,
|
||||
cacheEntries: this.queryCache.size
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate cache key for bounds
|
||||
*/
|
||||
private getCacheKey(bounds: Bounds): string {
|
||||
return `${bounds.x},${bounds.y},${bounds.width},${bounds.height}`
|
||||
}
|
||||
|
||||
/**
|
||||
* Add result to cache with LRU eviction
|
||||
*/
|
||||
private addToCache(key: string, result: NodeId[]): void {
|
||||
// Evict oldest entries if cache is full
|
||||
if (this.cacheSize >= PERFORMANCE_CONFIG.SPATIAL_CACHE_MAX_SIZE) {
|
||||
const oldestKey = this.findOldestCacheEntry()
|
||||
if (oldestKey) {
|
||||
this.queryCache.delete(oldestKey)
|
||||
this.cacheSize--
|
||||
}
|
||||
}
|
||||
|
||||
this.queryCache.set(key, {
|
||||
result,
|
||||
timestamp: Date.now()
|
||||
})
|
||||
this.cacheSize++
|
||||
}
|
||||
|
||||
/**
|
||||
* Find oldest cache entry for LRU eviction
|
||||
*/
|
||||
private findOldestCacheEntry(): string | null {
|
||||
let oldestKey: string | null = null
|
||||
let oldestTime = Infinity
|
||||
|
||||
for (const [key, entry] of this.queryCache) {
|
||||
if (entry.timestamp < oldestTime) {
|
||||
oldestTime = entry.timestamp
|
||||
oldestKey = key
|
||||
}
|
||||
}
|
||||
|
||||
return oldestKey
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidate all cached queries
|
||||
*/
|
||||
private invalidateCache(): void {
|
||||
this.queryCache.clear()
|
||||
this.cacheSize = 0
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user