mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-04-26 17:30:07 +00:00
* knip: Don't ignore exports that are only used within a given file * knip: More pruning after rebase * knip: Vite plugin config fix * knip: vitest plugin config * knip: Playwright config, remove unnecessary ignores. * knip: Simplify project file enumeration. * knip: simplify the config file patterns ?(.optional_segment) * knip: tailwind v4 fix * knip: A little more, explain some of the deps. Should be good for this PR. * knip: remove unused disabling of classMembers. It's opt-in, which we should probably do. * knip: floating comments We should probably delete _one_ of these parallell trees, right? * knip: Add additional entrypoints * knip: Restore UserData that's exposed via the types for now. * knip: Add as an entry file even though knip says it's not necessary. * knip: re-export functions used by nodes (h/t @christian-byrne)
187 lines
5.0 KiB
TypeScript
187 lines
5.0 KiB
TypeScript
/**
|
|
* Level of Detail (LOD) composable for Vue-based node rendering
|
|
*
|
|
* Provides dynamic quality adjustment based on zoom level to maintain
|
|
* performance with large node graphs. Uses zoom thresholds to determine
|
|
* how much detail to render for each node component.
|
|
*
|
|
* ## LOD Levels
|
|
*
|
|
* - **FULL** (zoom > 0.8): Complete rendering with all widgets, slots, and content
|
|
* - **REDUCED** (0.4 < zoom <= 0.8): Essential widgets only, simplified slots
|
|
* - **MINIMAL** (zoom <= 0.4): Title only, no widgets or slots
|
|
*
|
|
* ## Performance Benefits
|
|
*
|
|
* - Reduces DOM element count by up to 80% at low zoom levels
|
|
* - Minimizes layout calculations and paint operations
|
|
* - Enables smooth performance with 1000+ nodes
|
|
* - Maintains visual fidelity when detail is actually visible
|
|
*
|
|
* @example
|
|
* ```typescript
|
|
* const { lodLevel, shouldRenderWidgets, shouldRenderSlots } = useLOD(zoomRef)
|
|
*
|
|
* // In template
|
|
* <NodeWidgets v-if="shouldRenderWidgets" />
|
|
* <NodeSlots v-if="shouldRenderSlots" />
|
|
* ```
|
|
*/
|
|
import { type Ref, computed, readonly } from 'vue'
|
|
|
|
export enum LODLevel {
|
|
MINIMAL = 'minimal', // zoom <= 0.4
|
|
REDUCED = 'reduced', // 0.4 < zoom <= 0.8
|
|
FULL = 'full' // zoom > 0.8
|
|
}
|
|
|
|
interface LODConfig {
|
|
renderWidgets: boolean
|
|
renderSlots: boolean
|
|
renderContent: boolean
|
|
renderSlotLabels: boolean
|
|
renderWidgetLabels: boolean
|
|
cssClass: string
|
|
}
|
|
|
|
// LOD configuration for each level
|
|
const LOD_CONFIGS: Record<LODLevel, LODConfig> = {
|
|
[LODLevel.FULL]: {
|
|
renderWidgets: true,
|
|
renderSlots: true,
|
|
renderContent: true,
|
|
renderSlotLabels: true,
|
|
renderWidgetLabels: true,
|
|
cssClass: 'lg-node--lod-full'
|
|
},
|
|
[LODLevel.REDUCED]: {
|
|
renderWidgets: true,
|
|
renderSlots: true,
|
|
renderContent: false,
|
|
renderSlotLabels: false,
|
|
renderWidgetLabels: false,
|
|
cssClass: 'lg-node--lod-reduced'
|
|
},
|
|
[LODLevel.MINIMAL]: {
|
|
renderWidgets: false,
|
|
renderSlots: false,
|
|
renderContent: false,
|
|
renderSlotLabels: false,
|
|
renderWidgetLabels: false,
|
|
cssClass: 'lg-node--lod-minimal'
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Create LOD (Level of Detail) state based on zoom level
|
|
*
|
|
* @param zoomRef - Reactive reference to current zoom level (camera.z)
|
|
* @returns LOD state and configuration
|
|
*/
|
|
export function useLOD(zoomRef: Ref<number>) {
|
|
// Continuous LOD score (0-1) for smooth transitions
|
|
const lodScore = computed(() => {
|
|
const zoom = zoomRef.value
|
|
return Math.max(0, Math.min(1, zoom))
|
|
})
|
|
|
|
// Determine current LOD level based on zoom
|
|
const lodLevel = computed<LODLevel>(() => {
|
|
const zoom = zoomRef.value
|
|
|
|
if (zoom > 0.8) return LODLevel.FULL
|
|
if (zoom > 0.4) return LODLevel.REDUCED
|
|
return LODLevel.MINIMAL
|
|
})
|
|
|
|
// Get configuration for current LOD level
|
|
const lodConfig = computed<LODConfig>(() => LOD_CONFIGS[lodLevel.value])
|
|
|
|
// Convenience computed properties for common rendering decisions
|
|
const shouldRenderWidgets = computed(() => lodConfig.value.renderWidgets)
|
|
const shouldRenderSlots = computed(() => lodConfig.value.renderSlots)
|
|
const shouldRenderContent = computed(() => lodConfig.value.renderContent)
|
|
const shouldRenderSlotLabels = computed(
|
|
() => lodConfig.value.renderSlotLabels
|
|
)
|
|
const shouldRenderWidgetLabels = computed(
|
|
() => lodConfig.value.renderWidgetLabels
|
|
)
|
|
|
|
// CSS class for styling based on LOD level
|
|
const lodCssClass = computed(() => lodConfig.value.cssClass)
|
|
|
|
// Get essential widgets for reduced LOD (only interactive controls)
|
|
const getEssentialWidgets = (widgets: unknown[]): unknown[] => {
|
|
if (lodLevel.value === LODLevel.FULL) return widgets
|
|
if (lodLevel.value === LODLevel.MINIMAL) return []
|
|
|
|
// For reduced LOD, filter to essential widget types only
|
|
return widgets.filter((widget: any) => {
|
|
const type = widget?.type?.toLowerCase()
|
|
return [
|
|
'combo',
|
|
'select',
|
|
'toggle',
|
|
'boolean',
|
|
'slider',
|
|
'number'
|
|
].includes(type)
|
|
})
|
|
}
|
|
|
|
// Performance metrics for debugging
|
|
const lodMetrics = computed(() => ({
|
|
level: lodLevel.value,
|
|
zoom: zoomRef.value,
|
|
widgetCount: shouldRenderWidgets.value ? 'full' : 'none',
|
|
slotCount: shouldRenderSlots.value ? 'full' : 'none'
|
|
}))
|
|
|
|
return {
|
|
// Core LOD state
|
|
lodLevel: readonly(lodLevel),
|
|
lodConfig: readonly(lodConfig),
|
|
lodScore: readonly(lodScore),
|
|
|
|
// Rendering decisions
|
|
shouldRenderWidgets,
|
|
shouldRenderSlots,
|
|
shouldRenderContent,
|
|
shouldRenderSlotLabels,
|
|
shouldRenderWidgetLabels,
|
|
|
|
// Styling
|
|
lodCssClass,
|
|
|
|
// Utilities
|
|
getEssentialWidgets,
|
|
lodMetrics
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get LOD level thresholds for configuration or debugging
|
|
*/
|
|
export const LOD_THRESHOLDS = {
|
|
FULL_THRESHOLD: 0.8,
|
|
REDUCED_THRESHOLD: 0.4,
|
|
MINIMAL_THRESHOLD: 0.0
|
|
} as const
|
|
|
|
/**
|
|
* Check if zoom level supports a specific feature
|
|
*/
|
|
export function supportsFeatureAtZoom(
|
|
zoom: number,
|
|
feature: keyof LODConfig
|
|
): boolean {
|
|
const level =
|
|
zoom > 0.8
|
|
? LODLevel.FULL
|
|
: zoom > 0.4
|
|
? LODLevel.REDUCED
|
|
: LODLevel.MINIMAL
|
|
return LOD_CONFIGS[level][feature] as boolean
|
|
}
|