Files
ComfyUI_frontend/src/utils/spaceDistribution.ts
Chenlei Hu d23a320f9f Upstream frontend widgets layout logic (#531)
* Upstream frontend widgets layout logic

* Add back LGraphNode.freeWidgetSpace

* nit

* update expectations
2025-02-14 19:22:37 -05:00

78 lines
2.1 KiB
TypeScript

export interface SpaceRequest {
minSize: number
maxSize?: number
}
/**
* Distributes available space among items with min/max size constraints
* @param totalSpace Total space available to distribute
* @param requests Array of space requests with size constraints
* @returns Array of space allocations
*/
export function distributeSpace(
totalSpace: number,
requests: SpaceRequest[],
): number[] {
// Handle edge cases
if (requests.length === 0) return []
// Calculate total minimum space needed
const totalMinSize = requests.reduce((sum, req) => sum + req.minSize, 0)
// If we can't meet minimum requirements, return the minimum sizes
if (totalSpace < totalMinSize) {
return requests.map(req => req.minSize)
}
// Initialize allocations with minimum sizes
let allocations = requests.map(req => ({
computedSize: req.minSize,
maxSize: req.maxSize ?? Infinity,
remaining: (req.maxSize ?? Infinity) - req.minSize,
}))
// Calculate remaining space to distribute
let remainingSpace = totalSpace - totalMinSize
// Distribute remaining space iteratively
while (
remainingSpace > 0 &&
allocations.some(alloc => alloc.remaining > 0)
) {
// Count items that can still grow
const growableItems = allocations.filter(
alloc => alloc.remaining > 0,
).length
if (growableItems === 0) break
// Calculate fair share per item
const sharePerItem = remainingSpace / growableItems
// Track how much space was actually used in this iteration
let spaceUsedThisRound = 0
// Distribute space
allocations = allocations.map((alloc) => {
if (alloc.remaining <= 0) return alloc
const growth = Math.min(sharePerItem, alloc.remaining)
spaceUsedThisRound += growth
return {
...alloc,
computedSize: alloc.computedSize + growth,
remaining: alloc.remaining - growth,
}
})
remainingSpace -= spaceUsedThisRound
// Break if we couldn't distribute any more space
if (spaceUsedThisRound === 0) break
}
// Return only the computed sizes
return allocations.map(({ computedSize }) => computedSize)
}