@ankhorage/zora 22.1.2 → 22.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/README.md +1 -1
  3. package/dist/features/graph-view/adapters/inbound/web-artifact/GraphView.d.ts +3 -3
  4. package/dist/features/graph-view/adapters/inbound/web-artifact/GraphView.js +3 -3
  5. package/dist/features/graph-view/adapters/inbound/web-artifact/GraphView.js.map +1 -1
  6. package/dist/features/graph-view/adapters/inbound/web-artifact/compactGraphSpacing.d.ts +6 -5
  7. package/dist/features/graph-view/adapters/inbound/web-artifact/compactGraphSpacing.d.ts.map +1 -1
  8. package/dist/features/graph-view/adapters/inbound/web-artifact/compactGraphSpacing.js +107 -171
  9. package/dist/features/graph-view/adapters/inbound/web-artifact/compactGraphSpacing.js.map +1 -1
  10. package/dist/features/graph-view/adapters/inbound/web-artifact/createGraphController.d.ts +4 -0
  11. package/dist/features/graph-view/adapters/inbound/web-artifact/createGraphController.d.ts.map +1 -1
  12. package/dist/features/graph-view/adapters/inbound/web-artifact/createGraphController.js +8 -0
  13. package/dist/features/graph-view/adapters/inbound/web-artifact/createGraphController.js.map +1 -1
  14. package/dist/features/graph-view/adapters/inbound/web-artifact/createGraphRuntime.js +5 -1
  15. package/dist/features/graph-view/adapters/inbound/web-artifact/createGraphRuntime.js.map +1 -1
  16. package/dist/features/graph-view/adapters/inbound/web-artifact/createGraphSpacingEvaluator.d.ts +9 -0
  17. package/dist/features/graph-view/adapters/inbound/web-artifact/createGraphSpacingEvaluator.d.ts.map +1 -0
  18. package/dist/features/graph-view/adapters/inbound/web-artifact/createGraphSpacingEvaluator.js +234 -0
  19. package/dist/features/graph-view/adapters/inbound/web-artifact/createGraphSpacingEvaluator.js.map +1 -0
  20. package/dist/types/graph-view-spacing.d.ts +15 -0
  21. package/dist/types/graph-view-spacing.d.ts.map +1 -0
  22. package/dist/types/graph-view-spacing.js +2 -0
  23. package/dist/types/graph-view-spacing.js.map +1 -0
  24. package/dist/types/graph-view.d.ts +4 -1
  25. package/dist/types/graph-view.d.ts.map +1 -1
  26. package/dist/types/graph-view.js.map +1 -1
  27. package/package.json +2 -2
  28. package/src/features/graph-view/adapters/inbound/web-artifact/GraphView.tsx +3 -3
  29. package/src/features/graph-view/adapters/inbound/web-artifact/compactGraphSpacing.test.ts +195 -69
  30. package/src/features/graph-view/adapters/inbound/web-artifact/compactGraphSpacing.ts +162 -241
  31. package/src/features/graph-view/adapters/inbound/web-artifact/createGraphController.test.ts +2 -0
  32. package/src/features/graph-view/adapters/inbound/web-artifact/createGraphController.ts +8 -0
  33. package/src/features/graph-view/adapters/inbound/web-artifact/createGraphRuntime.ts +5 -1
  34. package/src/features/graph-view/adapters/inbound/web-artifact/createGraphSpacingEvaluator.ts +338 -0
  35. package/src/types/graph-view-spacing.ts +16 -0
  36. package/src/types/graph-view.ts +4 -1
  37. package/web-dist/components/graph-view/GraphView.d.ts +3 -3
  38. package/web-dist/components/graph-view/GraphView.js +237 -126
  39. package/web-dist/components/graph-view/GraphView.types-0.d.ts +4 -1
@@ -1 +1 @@
1
- {"version":3,"file":"createGraphController.js","sourceRoot":"","sources":["../../../../../../src/features/graph-view/adapters/inbound/web-artifact/createGraphController.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Core } from 'cytoscape';\n\nimport type {\n GraphViewController,\n GraphViewFitOptions,\n GraphViewMeasurement,\n} from '../../../../../types/graph-view';\nimport type { GraphRuntimeUpdate } from '../../../../../types/graphViewRuntime';\nimport { fitGraphViewport } from './fitGraphViewport';\n\n/*** Own viewport units and limits alongside the public controller, without exposing Cytoscape. */\nexport function createGraphController(\n cy: Core,\n fitPaddingRef: { current: number },\n optimizeFit?: (options: GraphViewFitOptions) => void,\n) {\n const state = {\n scale: 1,\n relative: false,\n min: 0.05,\n max: 2,\n readableSize: 0,\n fitSize: Infinity,\n readableZoom: 0,\n fitZoom: Infinity,\n };\n const controller: GraphViewController = {\n fit(options) {\n if (options?.optimizeSpacing && !options.nodeIds?.length && optimizeFit) {\n optimizeFit(options);\n return;\n }\n fitGraphViewport(\n cy,\n {\n nodeIds: options?.nodeIds,\n padding: options?.padding ?? fitPaddingRef.current,\n },\n state.fitZoom,\n );\n },\n measureNodes(nodeIds) {\n return measureRenderedNodes(cy, nodeIds);\n },\n getViewport() {\n return { pan: cy.pan(), zoom: cy.zoom() / state.scale };\n },\n getZoomRange() {\n return { min: cy.minZoom() / state.scale, max: cy.maxZoom() / state.scale };\n },\n setPan(pan) {\n cy.pan(pan);\n },\n setZoom(zoom) {\n setCenteredZoom(cy, zoom * state.scale);\n },\n zoomBy(factor) {\n setCenteredZoom(cy, cy.zoom() * factor);\n },\n };\n\n return {\n controller,\n configure(input: GraphRuntimeUpdate) {\n state.relative = input.zoomMode === 'fit-relative';\n state.min = input.minZoom ?? 0.05;\n state.max = input.maxZoom ?? 2;\n state.readableSize = positiveSize(input.minReadableLabelSize, 0);\n state.fitSize = positiveSize(input.maxFitLabelSize, Infinity);\n if (!state.relative) state.scale = 1;\n applyZoomLimits(cy, state);\n },\n settle(fit: boolean) {\n const logicalZoom = cy.zoom() / state.scale;\n const fonts = cy\n .nodes()\n .filter((node) => !node.isParent() && Boolean(node.style('label')))\n .map((node) => Number.parseFloat(String(node.style('font-size'))))\n .filter((size) => Number.isFinite(size) && size > 0);\n state.readableZoom = fonts.length\n ? state.readableSize / fonts.reduce((minimum, size) => Math.min(minimum, size), Infinity)\n : 0;\n state.fitZoom = fonts.length\n ? state.fitSize / fonts.reduce((maximum, size) => Math.max(maximum, size), 0)\n : Infinity;\n state.scale = state.relative\n ? Math.min(getNodeFitZoom(cy, fitPaddingRef.current), state.fitZoom)\n : 1;\n applyZoomLimits(cy, state);\n if (fit) controller.fit();\n else if (state.relative) {\n setCenteredZoom(cy, logicalZoom * state.scale);\n cy.center(cy.nodes());\n }\n },\n };\n}\n\n/*** Measure rendered node geometry for public consumers while keeping Cytoscape private. */\nfunction measureRenderedNodes(cy: Core, nodeIds: readonly string[]): GraphViewMeasurement | null {\n const viewport = { width: cy.width(), height: cy.height() };\n if (viewport.width <= 0 || viewport.height <= 0 || nodeIds.length === 0) return null;\n\n const nodes = [...new Set(nodeIds)].flatMap((id) => {\n const node = cy.getElementById(id);\n if (!node.isNode()) return [];\n\n const bounds = node.renderedBoundingBox();\n return [\n {\n id,\n position: node.renderedPosition(),\n size: { width: bounds.w, height: bounds.h },\n },\n ];\n });\n return nodes.length === 0 ? null : { nodes, viewport };\n}\n\n/*** Keep pointer, wheel, and programmatic zoom on the same limits in the engine's native units. */\nfunction applyZoomLimits(\n cy: Core,\n state: {\n readonly min: number;\n readonly max: number;\n readonly scale: number;\n readonly readableZoom: number;\n },\n) {\n const min = state.min * state.scale;\n cy.minZoom(Math.min(cy.minZoom(), min));\n cy.maxZoom(Math.max(min, state.max * state.scale, state.readableZoom));\n cy.minZoom(min);\n}\n\n/*** Ignore invalid optional typography targets at the public configuration boundary. */\nfunction positiveSize(value: number | undefined, fallback: number): number {\n return value !== undefined && Number.isFinite(value) && value > 0 ? value : fallback;\n}\n\n/***\n * Recompute the fit reference only after layout or resize, never on every pan/zoom event.\n * Cache the geometry-derived scale in the viewport owner; labels are included, edges excluded.\n */\nfunction getNodeFitZoom(cy: Core, padding: number): number {\n if (cy.nodes().empty()) return 1;\n const bounds = cy.nodes().boundingBox();\n const width = cy.width() - 2 * padding;\n const height = cy.height() - 2 * padding;\n if (width <= 0 || height <= 0 || bounds.w <= 0 || bounds.h <= 0) return 1;\n return Math.min(width / bounds.w, height / bounds.h);\n}\n\n/*** Zoom around the visible viewport center instead of its top-left corner. */\nfunction setCenteredZoom(cy: Core, zoom: number) {\n cy.zoom({ level: zoom, renderedPosition: { x: cy.width() / 2, y: cy.height() / 2 } });\n}\n"]}
1
+ {"version":3,"file":"createGraphController.js","sourceRoot":"","sources":["../../../../../../src/features/graph-view/adapters/inbound/web-artifact/createGraphController.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Core } from 'cytoscape';\n\nimport type {\n GraphViewController,\n GraphViewFitOptions,\n GraphViewMeasurement,\n} from '../../../../../types/graph-view';\nimport type { GraphRuntimeUpdate } from '../../../../../types/graphViewRuntime';\nimport { fitGraphViewport } from './fitGraphViewport';\n\n/*** Own viewport units and limits alongside the public controller, without exposing Cytoscape. */\nexport function createGraphController(\n cy: Core,\n fitPaddingRef: { current: number },\n optimizeFit?: (options: GraphViewFitOptions) => void,\n) {\n const state = {\n scale: 1,\n relative: false,\n min: 0.05,\n max: 2,\n readableSize: 0,\n fitSize: Infinity,\n readableZoom: 0,\n fitZoom: Infinity,\n };\n const controller: GraphViewController = {\n fit(options) {\n if (options?.optimizeSpacing && !options.nodeIds?.length && optimizeFit) {\n optimizeFit(options);\n return;\n }\n fitGraphViewport(\n cy,\n {\n nodeIds: options?.nodeIds,\n padding: options?.padding ?? fitPaddingRef.current,\n },\n state.fitZoom,\n );\n },\n measureNodes(nodeIds) {\n return measureRenderedNodes(cy, nodeIds);\n },\n getViewport() {\n return { pan: cy.pan(), zoom: cy.zoom() / state.scale };\n },\n getZoomRange() {\n return { min: cy.minZoom() / state.scale, max: cy.maxZoom() / state.scale };\n },\n setPan(pan) {\n cy.pan(pan);\n },\n setZoom(zoom) {\n setCenteredZoom(cy, zoom * state.scale);\n },\n zoomBy(factor) {\n setCenteredZoom(cy, cy.zoom() * factor);\n },\n };\n\n return {\n controller,\n configure(input: GraphRuntimeUpdate) {\n state.relative = input.zoomMode === 'fit-relative';\n state.min = input.minZoom ?? 0.05;\n state.max = input.maxZoom ?? 2;\n state.readableSize = positiveSize(input.minReadableLabelSize, 0);\n state.fitSize = positiveSize(input.maxFitLabelSize, Infinity);\n if (!state.relative) state.scale = 1;\n applyZoomLimits(cy, state);\n },\n /*** Return the native automatic-fit ceiling used by spacing optimization. */\n getFitZoomLimit() {\n return state.relative ? state.fitZoom : Math.min(state.fitZoom, state.max);\n },\n /*** Return the native label-readability threshold used before allowing background overlap. */\n getReadableZoomTarget() {\n return state.readableZoom;\n },\n settle(fit: boolean) {\n const logicalZoom = cy.zoom() / state.scale;\n const fonts = cy\n .nodes()\n .filter((node) => !node.isParent() && Boolean(node.style('label')))\n .map((node) => Number.parseFloat(String(node.style('font-size'))))\n .filter((size) => Number.isFinite(size) && size > 0);\n state.readableZoom = fonts.length\n ? state.readableSize / fonts.reduce((minimum, size) => Math.min(minimum, size), Infinity)\n : 0;\n state.fitZoom = fonts.length\n ? state.fitSize / fonts.reduce((maximum, size) => Math.max(maximum, size), 0)\n : Infinity;\n state.scale = state.relative\n ? Math.min(getNodeFitZoom(cy, fitPaddingRef.current), state.fitZoom)\n : 1;\n applyZoomLimits(cy, state);\n if (fit) controller.fit();\n else if (state.relative) {\n setCenteredZoom(cy, logicalZoom * state.scale);\n cy.center(cy.nodes());\n }\n },\n };\n}\n\n/*** Measure rendered node geometry for public consumers while keeping Cytoscape private. */\nfunction measureRenderedNodes(cy: Core, nodeIds: readonly string[]): GraphViewMeasurement | null {\n const viewport = { width: cy.width(), height: cy.height() };\n if (viewport.width <= 0 || viewport.height <= 0 || nodeIds.length === 0) return null;\n\n const nodes = [...new Set(nodeIds)].flatMap((id) => {\n const node = cy.getElementById(id);\n if (!node.isNode()) return [];\n\n const bounds = node.renderedBoundingBox();\n return [\n {\n id,\n position: node.renderedPosition(),\n size: { width: bounds.w, height: bounds.h },\n },\n ];\n });\n return nodes.length === 0 ? null : { nodes, viewport };\n}\n\n/*** Keep pointer, wheel, and programmatic zoom on the same limits in the engine's native units. */\nfunction applyZoomLimits(\n cy: Core,\n state: {\n readonly min: number;\n readonly max: number;\n readonly scale: number;\n readonly readableZoom: number;\n },\n) {\n const min = state.min * state.scale;\n cy.minZoom(Math.min(cy.minZoom(), min));\n cy.maxZoom(Math.max(min, state.max * state.scale, state.readableZoom));\n cy.minZoom(min);\n}\n\n/*** Ignore invalid optional typography targets at the public configuration boundary. */\nfunction positiveSize(value: number | undefined, fallback: number): number {\n return value !== undefined && Number.isFinite(value) && value > 0 ? value : fallback;\n}\n\n/***\n * Recompute the fit reference only after layout or resize, never on every pan/zoom event.\n * Cache the geometry-derived scale in the viewport owner; labels are included, edges excluded.\n */\nfunction getNodeFitZoom(cy: Core, padding: number): number {\n if (cy.nodes().empty()) return 1;\n const bounds = cy.nodes().boundingBox();\n const width = cy.width() - 2 * padding;\n const height = cy.height() - 2 * padding;\n if (width <= 0 || height <= 0 || bounds.w <= 0 || bounds.h <= 0) return 1;\n return Math.min(width / bounds.w, height / bounds.h);\n}\n\n/*** Zoom around the visible viewport center instead of its top-left corner. */\nfunction setCenteredZoom(cy: Core, zoom: number) {\n cy.zoom({ level: zoom, renderedPosition: { x: cy.width() / 2, y: cy.height() / 2 } });\n}\n"]}
@@ -201,7 +201,11 @@ function requestOptimizedFit(state, options) {
201
201
  if (!input)
202
202
  return;
203
203
  const previous = state.optimizedSpacingRef.current ?? input.spacingFactor ?? 1;
204
- const spacing = compactGraphSpacing(state.cy, previous);
204
+ const spacing = compactGraphSpacing(state.cy, previous, {
205
+ fitPadding: options.padding ?? state.fitPaddingRef.current,
206
+ maxFitZoom: state.viewport.getFitZoomLimit(),
207
+ minReadableZoom: state.viewport.getReadableZoomTarget(),
208
+ });
205
209
  state.geometryRef.current = getGraphGeometryKey(state.cy);
206
210
  state.loopSizer.update();
207
211
  state.viewport.settle(false);
@@ -1 +1 @@
1
- {"version":3,"file":"createGraphRuntime.js","sourceRoot":"","sources":["../../../../../../src/features/graph-view/adapters/inbound/web-artifact/createGraphRuntime.ts"],"names":[],"mappings":"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","sourcesContent":["import cytoscape, { type Core, type CytoscapeOptions } from 'cytoscape';\n\nimport type {\n GraphViewCallbacks,\n GraphViewElementEventType,\n GraphViewFitOptions,\n GraphViewRenderedNode,\n GraphViewSize,\n GraphViewStyleRule,\n} from '../../../../../types/graph-view';\nimport type { GraphRuntimeUpdate } from '../../../../../types/graphViewRuntime';\nimport { bindGraphEvents } from './bindGraphEvents';\nimport { compactGraphSpacing } from './compactGraphSpacing';\nimport { createGraphController } from './createGraphController';\nimport { createGraphLoopSizer } from './createGraphLoopSizer';\nimport { createGraphResizeObserver, type GraphResizeObserver } from './createGraphResizeObserver';\nimport { getGraphGeometryKey } from './getGraphGeometryKey';\nimport { getGraphTopologyKey } from './getGraphTopologyKey';\nimport { hasGraphLayoutChanged } from './hasGraphLayoutChanged';\nimport { readGraphRenderedNodes } from './readGraphRenderedNodes';\nimport { registerGraphLayouts } from './registerGraphLayouts';\nimport { runGraphLayout } from './runGraphLayout';\nimport { scheduleGraphFrame } from './scheduleGraphFrame';\nimport { shouldFitGraphAfterLayout } from './shouldFitGraphAfterLayout';\nimport { sizeGraphNodesToLabels } from './sizeGraphNodesToLabels';\nimport { syncGraphElements } from './syncGraphElements';\n\ntype GraphContainer = CytoscapeOptions['container'];\ntype RenderedNodeListener = (nodes: readonly GraphViewRenderedNode[]) => void;\n\nexport interface GraphRuntime {\n destroy(): void;\n handleOverlayNodeEvent(id: string, type: GraphViewElementEventType): void;\n setNodeSize(id: string, size: GraphViewSize): void;\n setSelectedNodeIds(nodeIds: readonly string[] | undefined): void;\n subscribeRenderedNodes(listener: RenderedNodeListener): () => void;\n update(input: GraphRuntimeUpdate): void;\n}\n\ninterface GraphRuntimeState {\n readonly fitRequestRef: { current: GraphViewFitOptions | null };\n readonly optimizedSpacingRef: { current: number | null };\n readonly callbacksRef: { current: GraphViewCallbacks };\n readonly controller: ReturnType<typeof createGraphController>['controller'];\n readonly viewport: ReturnType<typeof createGraphController>;\n readonly cy: Core;\n readonly fitPaddingRef: { current: number };\n readonly generationRef: { current: number };\n readonly geometryRef: { current: string | null };\n readonly hoveredNodeIds: Set<string>;\n readonly latestUpdateRef: { current: GraphRuntimeUpdate | null };\n readonly layoutRef: { current: ReturnType<typeof runGraphLayout> | null };\n readonly layoutRunningRef: { current: boolean };\n readonly nodeSizes: Map<string, GraphViewSize>;\n readonly labelSizedNodeIds: Set<string>;\n readonly loopSizer: ReturnType<typeof createGraphLoopSizer>;\n readonly pendingInitialFitRef: { current: boolean };\n readonly readyRef: { current: boolean };\n readonly settledTopologyRef: { current: string | null };\n readonly relayoutScheduledRef: { current: boolean };\n readonly renderedNodeListeners: Set<RenderedNodeListener>;\n readonly resizeObserver: GraphResizeObserver | null;\n readonly unbindEvents: () => void;\n}\n\n/*** Create one Cytoscape runtime that exclusively owns layout, fit, resize, and disposal. */\nexport function createGraphRuntime(\n container: GraphContainer,\n callbacksRef: { current: GraphViewCallbacks },\n): GraphRuntime {\n const cy = cytoscape({\n container,\n elements: [],\n minZoom: 0.05,\n maxZoom: 2,\n selectionType: 'additive',\n userPanningEnabled: true,\n });\n const state = createRuntimeState(cy, container, callbacksRef);\n\n return {\n destroy: () => destroyRuntime(state),\n handleOverlayNodeEvent: (id, type) => handleOverlayNodeEvent(state, id, type),\n setNodeSize: (id, size) => setNodeSize(state, id, size),\n setSelectedNodeIds: (nodeIds) => setSelectedNodeIds(state, nodeIds),\n subscribeRenderedNodes: (listener) => subscribeRenderedNodes(state, listener),\n update: (input) => updateRuntime(state, input),\n };\n}\n\n/*** Build the mutable state shared by the single graph-runtime owner. */\nfunction createRuntimeState(\n cy: Core,\n container: GraphContainer,\n callbacksRef: { current: GraphViewCallbacks },\n): GraphRuntimeState {\n const fitPaddingRef = { current: 50 };\n const viewport = createGraphController(cy, fitPaddingRef, (options) =>\n requestOptimizedFit(state, options),\n );\n const { controller } = viewport;\n const layoutRunningRef = { current: false };\n const readyRef = { current: false };\n const renderedNodeListeners = new Set<RenderedNodeListener>();\n const stateBase = {\n fitRequestRef: { current: null as GraphViewFitOptions | null },\n optimizedSpacingRef: { current: null as number | null },\n callbacksRef,\n controller,\n viewport,\n cy,\n fitPaddingRef,\n generationRef: { current: 0 },\n geometryRef: { current: null as string | null },\n hoveredNodeIds: new Set<string>(),\n latestUpdateRef: { current: null as GraphRuntimeUpdate | null },\n layoutRef: { current: null as ReturnType<typeof runGraphLayout> | null },\n layoutRunningRef,\n nodeSizes: new Map<string, GraphViewSize>(),\n labelSizedNodeIds: new Set<string>(),\n loopSizer: createGraphLoopSizer(cy),\n pendingInitialFitRef: { current: false },\n readyRef,\n settledTopologyRef: { current: null as string | null },\n relayoutScheduledRef: { current: false },\n renderedNodeListeners,\n };\n const unbindEvents = bindGraphEvents(cy, callbacksRef, controller, () =>\n emitRenderedNodes(stateBase),\n );\n const resizeObserver = createGraphResizeObserver({\n container,\n cy,\n settleViewport: () => viewport.settle(true),\n layoutRunningRef,\n pendingInitialFitRef: stateBase.pendingInitialFitRef,\n onViewportSettled: (completedPendingInitialFit) => {\n emitRenderedNodes(stateBase);\n if (!completedPendingInitialFit || readyRef.current) return;\n readyRef.current = true;\n callbacksRef.current.onReady?.(controller);\n callbacksRef.current.onLayoutComplete?.(controller);\n },\n readyRef,\n });\n\n const state = { ...stateBase, resizeObserver, unbindEvents };\n return state;\n}\n\n/***\n * Reconcile presentation in place and relayout only when graph geometry or layout policy changes.\n * Batch reconciliation and skip layout for presentation-only updates.\n */\nfunction updateRuntime(state: GraphRuntimeState, input: GraphRuntimeUpdate) {\n if (state.cy.destroyed()) return;\n const last = state.latestUpdateRef.current;\n const acceptsSpacing =\n state.optimizedSpacingRef.current !== null &&\n state.optimizedSpacingRef.current === input.spacingFactor;\n const previous = acceptsSpacing && last ? { ...last, spacingFactor: input.spacingFactor } : last;\n if (acceptsSpacing) state.optimizedSpacingRef.current = null;\n state.latestUpdateRef.current = input;\n state.fitPaddingRef.current = input.fitPadding ?? 50;\n state.viewport.configure(input);\n state.cy.batch(() => {\n if (previous?.nodes !== input.nodes || previous.edges !== input.edges) {\n syncGraphElements(state.cy, input.nodes, input.edges);\n }\n if (\n previous?.styleRules !== input.styleRules ||\n previous?.richNodeRendering !== input.richNodeRendering\n ) {\n state.loopSizer.reset();\n applyGraphStyles(state.cy, input.styleRules, input.richNodeRendering);\n }\n });\n sizeGraphNodesToLabels(\n state.cy,\n state.labelSizedNodeIds,\n input.sizeNodesToLabels === true && !input.richNodeRendering,\n );\n applyKnownNodeSizes(state);\n state.loopSizer.update();\n const geometry = getGraphGeometryKey(state.cy);\n const relayout = geometry !== state.geometryRef.current || hasGraphLayoutChanged(previous, input);\n state.geometryRef.current = geometry;\n if (!relayout) {\n if (\n previous?.zoomMode !== input.zoomMode ||\n previous?.fitPadding !== input.fitPadding ||\n previous?.minZoom !== input.minZoom ||\n previous?.maxZoom !== input.maxZoom ||\n previous?.minReadableLabelSize !== input.minReadableLabelSize ||\n previous?.maxFitLabelSize !== input.maxFitLabelSize\n ) {\n state.viewport.settle(previous?.zoomMode !== input.zoomMode);\n }\n emitRenderedNodes(state);\n if (!state.layoutRunningRef.current && !state.pendingInitialFitRef.current)\n state.callbacksRef.current.onLayoutComplete?.(state.controller);\n return;\n }\n stopCurrentLayout(state);\n state.fitRequestRef.current = null;\n state.optimizedSpacingRef.current = null;\n startCurrentLayout(state, input);\n}\n\n/*** Start a generation-safe layout whose completion is the only normal automatic fit trigger. */\nfunction startCurrentLayout(state: GraphRuntimeState, input: GraphRuntimeUpdate) {\n state.pendingInitialFitRef.current = false;\n const generation = state.generationRef.current + 1;\n state.generationRef.current = generation;\n state.layoutRunningRef.current = true;\n state.cy.resize();\n state.layoutRef.current = runGraphLayout(\n state.cy,\n {\n layout: input.layout ?? 'concentric',\n layoutOptions: input.layoutOptions,\n spacingFactor: input.spacingFactor ?? 1,\n },\n () => completeCurrentLayout(state, generation),\n );\n}\n\n/***\n * Settle only the latest layout generation and fit once from node bounds.\n * Discard stale completions and avoid repeated automatic fits.\n */\nfunction completeCurrentLayout(state: GraphRuntimeState, generation: number) {\n scheduleGraphFrame(() => {\n if (state.cy.destroyed() || generation !== state.generationRef.current) return;\n state.loopSizer.update();\n state.layoutRef.current = null;\n state.cy.resize();\n state.layoutRunningRef.current = false;\n if (!hasUsableViewport(state.cy)) {\n if (!state.readyRef.current) state.pendingInitialFitRef.current = true;\n return;\n }\n state.pendingInitialFitRef.current = false;\n const input = state.latestUpdateRef.current;\n if (input === null) return;\n const topology = getGraphTopologyKey(input.nodes, input.edges);\n const shouldFit = shouldFitGraphAfterLayout(\n state.readyRef.current,\n topology !== state.settledTopologyRef.current,\n );\n state.viewport.settle(shouldFit);\n state.settledTopologyRef.current = topology;\n const fitRequest = state.fitRequestRef.current;\n state.fitRequestRef.current = null;\n if (fitRequest) requestOptimizedFit(state, fitRequest);\n emitRenderedNodes(state);\n\n if (!state.readyRef.current) {\n state.readyRef.current = true;\n state.callbacksRef.current.onReady?.(state.controller);\n }\n state.callbacksRef.current.onLayoutComplete?.(state.controller);\n });\n}\n\n/***\n * Handle explicit readable-fit intent in the runtime owner, never from zoom or React effects.\n * Bounded spacing optimization preserves the settled algorithm instead of repeatedly running it.\n */\nfunction requestOptimizedFit(state: GraphRuntimeState, options: GraphViewFitOptions) {\n if (state.cy.destroyed()) return;\n if (state.layoutRunningRef.current) {\n state.fitRequestRef.current = options;\n return;\n }\n const input = state.latestUpdateRef.current;\n if (!input) return;\n const previous = state.optimizedSpacingRef.current ?? input.spacingFactor ?? 1;\n const spacing = compactGraphSpacing(state.cy, previous);\n state.geometryRef.current = getGraphGeometryKey(state.cy);\n state.loopSizer.update();\n state.viewport.settle(false);\n state.controller.fit({ ...options, optimizeSpacing: false });\n if (spacing !== previous) {\n state.optimizedSpacingRef.current = spacing;\n state.callbacksRef.current.onSpacingFactorChange?.(spacing);\n }\n emitRenderedNodes(state);\n}\n\n/*** Stop the current layout and invalidate every stale completion callback. */\nfunction stopCurrentLayout(state: GraphRuntimeState) {\n state.generationRef.current += 1;\n state.layoutRunningRef.current = false;\n state.layoutRef.current?.stop();\n state.layoutRef.current = null;\n}\n\n/*** Apply consumer styles and hide native node paint only when React rich nodes are active. */\nfunction applyGraphStyles(\n cy: Core,\n rules: readonly GraphViewStyleRule[] | undefined,\n richNodeRendering: boolean,\n) {\n const styles = [...(rules ?? [])];\n if (richNodeRendering) {\n styles.push({\n selector: 'node',\n style: {\n 'background-opacity': 0,\n 'border-width': 0,\n label: '',\n 'overlay-opacity': 0,\n },\n });\n }\n if (styles.length > 0) cy.style(styles).update();\n}\n\n/***\n * Synchronize controlled selection without rerunning layout.\n * Selection updates must not trigger graph reconstruction or layout.\n */\nfunction setSelectedNodeIds(state: GraphRuntimeState, nodeIds: readonly string[] | undefined) {\n if (state.cy.destroyed() || nodeIds === undefined) return;\n const selectedIds = new Set(nodeIds);\n state.cy.nodes().forEach((node) => {\n if (selectedIds.has(node.id())) node.select();\n else node.unselect();\n });\n emitRenderedNodes(state);\n}\n\n/***\n * Persist one rich-node size and schedule at most one relayout for changed geometry.\n * Ignore unchanged measurements before scheduling layout work.\n */\nfunction setNodeSize(state: GraphRuntimeState, id: string, size: GraphViewSize) {\n const previous = state.nodeSizes.get(id);\n if (previous?.width === size.width && previous.height === size.height) return;\n state.nodeSizes.set(id, size);\n applyNodeSize(state.cy, id, size);\n scheduleMeasuredNodeRelayout(state);\n}\n\n/*** Apply every known rich-node size after Cytoscape elements are replaced. */\nfunction applyKnownNodeSizes(state: GraphRuntimeState) {\n for (const [id, size] of state.nodeSizes) applyNodeSize(state.cy, id, size);\n}\n\n/*** Apply one measured model-space size as a Cytoscape per-node style bypass. */\nfunction applyNodeSize(cy: Core, id: string, size: GraphViewSize) {\n const node = cy.getElementById(id);\n if (node.empty()) return;\n node.style({ height: size.height, width: size.width });\n}\n\n/***\n * Coalesce DOM measurements into one follow-up layout generation.\n * Keep one scheduled layout per frame instead of one per measured node.\n */\nfunction scheduleMeasuredNodeRelayout(state: GraphRuntimeState) {\n if (state.relayoutScheduledRef.current) return;\n state.relayoutScheduledRef.current = true;\n scheduleGraphFrame(() => {\n state.relayoutScheduledRef.current = false;\n const input = state.latestUpdateRef.current;\n if (input === null || state.cy.destroyed()) return;\n stopCurrentLayout(state);\n startCurrentLayout(state, input);\n });\n}\n\n/*** Subscribe one React overlay to rendered node state without exposing the Cytoscape core. */\nfunction subscribeRenderedNodes(state: GraphRuntimeState, listener: RenderedNodeListener) {\n state.renderedNodeListeners.add(listener);\n listener(readGraphRenderedNodes(state.cy, state.hoveredNodeIds));\n return () => {\n state.renderedNodeListeners.delete(listener);\n };\n}\n\n/***\n * Publish current rendered node positions only to active rich-node subscribers.\n * Skip snapshot preparation when no overlay is subscribed.\n */\nfunction emitRenderedNodes(\n state: Pick<GraphRuntimeState, 'cy' | 'hoveredNodeIds' | 'renderedNodeListeners'>,\n) {\n if (state.renderedNodeListeners.size === 0) return;\n const nodes = readGraphRenderedNodes(state.cy, state.hoveredNodeIds);\n for (const listener of state.renderedNodeListeners) listener(nodes);\n}\n\n/*** Translate one rich-overlay event back into normal graph selection and callbacks. */\nfunction handleOverlayNodeEvent(\n state: GraphRuntimeState,\n id: string,\n type: GraphViewElementEventType,\n) {\n if (type === 'pointer-enter') state.hoveredNodeIds.add(id);\n if (type === 'pointer-leave') state.hoveredNodeIds.delete(id);\n if (type === 'press') state.cy.getElementById(id).select();\n state.callbacksRef.current.onNodeEvent?.({ id, type });\n emitRenderedNodes(state);\n}\n\n/*** Return whether Cytoscape currently has dimensions suitable for fitting. */\nfunction hasUsableViewport(cy: Core): boolean {\n return cy.width() > 0 && cy.height() > 0;\n}\n\n/*** Dispose all runtime resources in the reverse order they were acquired. */\nfunction destroyRuntime(state: GraphRuntimeState) {\n state.resizeObserver?.disconnect();\n stopCurrentLayout(state);\n state.unbindEvents();\n state.renderedNodeListeners.clear();\n if (!state.cy.destroyed()) state.cy.destroy();\n}\n\nregisterGraphLayouts();\n"]}
1
+ {"version":3,"file":"createGraphRuntime.js","sourceRoot":"","sources":["../../../../../../src/features/graph-view/adapters/inbound/web-artifact/createGraphRuntime.ts"],"names":[],"mappings":"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","sourcesContent":["import cytoscape, { type Core, type CytoscapeOptions } from 'cytoscape';\n\nimport type {\n GraphViewCallbacks,\n GraphViewElementEventType,\n GraphViewFitOptions,\n GraphViewRenderedNode,\n GraphViewSize,\n GraphViewStyleRule,\n} from '../../../../../types/graph-view';\nimport type { GraphRuntimeUpdate } from '../../../../../types/graphViewRuntime';\nimport { bindGraphEvents } from './bindGraphEvents';\nimport { compactGraphSpacing } from './compactGraphSpacing';\nimport { createGraphController } from './createGraphController';\nimport { createGraphLoopSizer } from './createGraphLoopSizer';\nimport { createGraphResizeObserver, type GraphResizeObserver } from './createGraphResizeObserver';\nimport { getGraphGeometryKey } from './getGraphGeometryKey';\nimport { getGraphTopologyKey } from './getGraphTopologyKey';\nimport { hasGraphLayoutChanged } from './hasGraphLayoutChanged';\nimport { readGraphRenderedNodes } from './readGraphRenderedNodes';\nimport { registerGraphLayouts } from './registerGraphLayouts';\nimport { runGraphLayout } from './runGraphLayout';\nimport { scheduleGraphFrame } from './scheduleGraphFrame';\nimport { shouldFitGraphAfterLayout } from './shouldFitGraphAfterLayout';\nimport { sizeGraphNodesToLabels } from './sizeGraphNodesToLabels';\nimport { syncGraphElements } from './syncGraphElements';\n\ntype GraphContainer = CytoscapeOptions['container'];\ntype RenderedNodeListener = (nodes: readonly GraphViewRenderedNode[]) => void;\n\nexport interface GraphRuntime {\n destroy(): void;\n handleOverlayNodeEvent(id: string, type: GraphViewElementEventType): void;\n setNodeSize(id: string, size: GraphViewSize): void;\n setSelectedNodeIds(nodeIds: readonly string[] | undefined): void;\n subscribeRenderedNodes(listener: RenderedNodeListener): () => void;\n update(input: GraphRuntimeUpdate): void;\n}\n\ninterface GraphRuntimeState {\n readonly fitRequestRef: { current: GraphViewFitOptions | null };\n readonly optimizedSpacingRef: { current: number | null };\n readonly callbacksRef: { current: GraphViewCallbacks };\n readonly controller: ReturnType<typeof createGraphController>['controller'];\n readonly viewport: ReturnType<typeof createGraphController>;\n readonly cy: Core;\n readonly fitPaddingRef: { current: number };\n readonly generationRef: { current: number };\n readonly geometryRef: { current: string | null };\n readonly hoveredNodeIds: Set<string>;\n readonly latestUpdateRef: { current: GraphRuntimeUpdate | null };\n readonly layoutRef: { current: ReturnType<typeof runGraphLayout> | null };\n readonly layoutRunningRef: { current: boolean };\n readonly nodeSizes: Map<string, GraphViewSize>;\n readonly labelSizedNodeIds: Set<string>;\n readonly loopSizer: ReturnType<typeof createGraphLoopSizer>;\n readonly pendingInitialFitRef: { current: boolean };\n readonly readyRef: { current: boolean };\n readonly settledTopologyRef: { current: string | null };\n readonly relayoutScheduledRef: { current: boolean };\n readonly renderedNodeListeners: Set<RenderedNodeListener>;\n readonly resizeObserver: GraphResizeObserver | null;\n readonly unbindEvents: () => void;\n}\n\n/*** Create one Cytoscape runtime that exclusively owns layout, fit, resize, and disposal. */\nexport function createGraphRuntime(\n container: GraphContainer,\n callbacksRef: { current: GraphViewCallbacks },\n): GraphRuntime {\n const cy = cytoscape({\n container,\n elements: [],\n minZoom: 0.05,\n maxZoom: 2,\n selectionType: 'additive',\n userPanningEnabled: true,\n });\n const state = createRuntimeState(cy, container, callbacksRef);\n\n return {\n destroy: () => destroyRuntime(state),\n handleOverlayNodeEvent: (id, type) => handleOverlayNodeEvent(state, id, type),\n setNodeSize: (id, size) => setNodeSize(state, id, size),\n setSelectedNodeIds: (nodeIds) => setSelectedNodeIds(state, nodeIds),\n subscribeRenderedNodes: (listener) => subscribeRenderedNodes(state, listener),\n update: (input) => updateRuntime(state, input),\n };\n}\n\n/*** Build the mutable state shared by the single graph-runtime owner. */\nfunction createRuntimeState(\n cy: Core,\n container: GraphContainer,\n callbacksRef: { current: GraphViewCallbacks },\n): GraphRuntimeState {\n const fitPaddingRef = { current: 50 };\n const viewport = createGraphController(cy, fitPaddingRef, (options) =>\n requestOptimizedFit(state, options),\n );\n const { controller } = viewport;\n const layoutRunningRef = { current: false };\n const readyRef = { current: false };\n const renderedNodeListeners = new Set<RenderedNodeListener>();\n const stateBase = {\n fitRequestRef: { current: null as GraphViewFitOptions | null },\n optimizedSpacingRef: { current: null as number | null },\n callbacksRef,\n controller,\n viewport,\n cy,\n fitPaddingRef,\n generationRef: { current: 0 },\n geometryRef: { current: null as string | null },\n hoveredNodeIds: new Set<string>(),\n latestUpdateRef: { current: null as GraphRuntimeUpdate | null },\n layoutRef: { current: null as ReturnType<typeof runGraphLayout> | null },\n layoutRunningRef,\n nodeSizes: new Map<string, GraphViewSize>(),\n labelSizedNodeIds: new Set<string>(),\n loopSizer: createGraphLoopSizer(cy),\n pendingInitialFitRef: { current: false },\n readyRef,\n settledTopologyRef: { current: null as string | null },\n relayoutScheduledRef: { current: false },\n renderedNodeListeners,\n };\n const unbindEvents = bindGraphEvents(cy, callbacksRef, controller, () =>\n emitRenderedNodes(stateBase),\n );\n const resizeObserver = createGraphResizeObserver({\n container,\n cy,\n settleViewport: () => viewport.settle(true),\n layoutRunningRef,\n pendingInitialFitRef: stateBase.pendingInitialFitRef,\n onViewportSettled: (completedPendingInitialFit) => {\n emitRenderedNodes(stateBase);\n if (!completedPendingInitialFit || readyRef.current) return;\n readyRef.current = true;\n callbacksRef.current.onReady?.(controller);\n callbacksRef.current.onLayoutComplete?.(controller);\n },\n readyRef,\n });\n\n const state = { ...stateBase, resizeObserver, unbindEvents };\n return state;\n}\n\n/***\n * Reconcile presentation in place and relayout only when graph geometry or layout policy changes.\n * Batch reconciliation and skip layout for presentation-only updates.\n */\nfunction updateRuntime(state: GraphRuntimeState, input: GraphRuntimeUpdate) {\n if (state.cy.destroyed()) return;\n const last = state.latestUpdateRef.current;\n const acceptsSpacing =\n state.optimizedSpacingRef.current !== null &&\n state.optimizedSpacingRef.current === input.spacingFactor;\n const previous = acceptsSpacing && last ? { ...last, spacingFactor: input.spacingFactor } : last;\n if (acceptsSpacing) state.optimizedSpacingRef.current = null;\n state.latestUpdateRef.current = input;\n state.fitPaddingRef.current = input.fitPadding ?? 50;\n state.viewport.configure(input);\n state.cy.batch(() => {\n if (previous?.nodes !== input.nodes || previous.edges !== input.edges) {\n syncGraphElements(state.cy, input.nodes, input.edges);\n }\n if (\n previous?.styleRules !== input.styleRules ||\n previous?.richNodeRendering !== input.richNodeRendering\n ) {\n state.loopSizer.reset();\n applyGraphStyles(state.cy, input.styleRules, input.richNodeRendering);\n }\n });\n sizeGraphNodesToLabels(\n state.cy,\n state.labelSizedNodeIds,\n input.sizeNodesToLabels === true && !input.richNodeRendering,\n );\n applyKnownNodeSizes(state);\n state.loopSizer.update();\n const geometry = getGraphGeometryKey(state.cy);\n const relayout = geometry !== state.geometryRef.current || hasGraphLayoutChanged(previous, input);\n state.geometryRef.current = geometry;\n if (!relayout) {\n if (\n previous?.zoomMode !== input.zoomMode ||\n previous?.fitPadding !== input.fitPadding ||\n previous?.minZoom !== input.minZoom ||\n previous?.maxZoom !== input.maxZoom ||\n previous?.minReadableLabelSize !== input.minReadableLabelSize ||\n previous?.maxFitLabelSize !== input.maxFitLabelSize\n ) {\n state.viewport.settle(previous?.zoomMode !== input.zoomMode);\n }\n emitRenderedNodes(state);\n if (!state.layoutRunningRef.current && !state.pendingInitialFitRef.current)\n state.callbacksRef.current.onLayoutComplete?.(state.controller);\n return;\n }\n stopCurrentLayout(state);\n state.fitRequestRef.current = null;\n state.optimizedSpacingRef.current = null;\n startCurrentLayout(state, input);\n}\n\n/*** Start a generation-safe layout whose completion is the only normal automatic fit trigger. */\nfunction startCurrentLayout(state: GraphRuntimeState, input: GraphRuntimeUpdate) {\n state.pendingInitialFitRef.current = false;\n const generation = state.generationRef.current + 1;\n state.generationRef.current = generation;\n state.layoutRunningRef.current = true;\n state.cy.resize();\n state.layoutRef.current = runGraphLayout(\n state.cy,\n {\n layout: input.layout ?? 'concentric',\n layoutOptions: input.layoutOptions,\n spacingFactor: input.spacingFactor ?? 1,\n },\n () => completeCurrentLayout(state, generation),\n );\n}\n\n/***\n * Settle only the latest layout generation and fit once from node bounds.\n * Discard stale completions and avoid repeated automatic fits.\n */\nfunction completeCurrentLayout(state: GraphRuntimeState, generation: number) {\n scheduleGraphFrame(() => {\n if (state.cy.destroyed() || generation !== state.generationRef.current) return;\n state.loopSizer.update();\n state.layoutRef.current = null;\n state.cy.resize();\n state.layoutRunningRef.current = false;\n if (!hasUsableViewport(state.cy)) {\n if (!state.readyRef.current) state.pendingInitialFitRef.current = true;\n return;\n }\n state.pendingInitialFitRef.current = false;\n const input = state.latestUpdateRef.current;\n if (input === null) return;\n const topology = getGraphTopologyKey(input.nodes, input.edges);\n const shouldFit = shouldFitGraphAfterLayout(\n state.readyRef.current,\n topology !== state.settledTopologyRef.current,\n );\n state.viewport.settle(shouldFit);\n state.settledTopologyRef.current = topology;\n const fitRequest = state.fitRequestRef.current;\n state.fitRequestRef.current = null;\n if (fitRequest) requestOptimizedFit(state, fitRequest);\n emitRenderedNodes(state);\n\n if (!state.readyRef.current) {\n state.readyRef.current = true;\n state.callbacksRef.current.onReady?.(state.controller);\n }\n state.callbacksRef.current.onLayoutComplete?.(state.controller);\n });\n}\n\n/***\n * Handle explicit readable-fit intent in the runtime owner, never from zoom or React effects.\n * Bounded spacing optimization preserves the settled algorithm instead of repeatedly running it.\n */\nfunction requestOptimizedFit(state: GraphRuntimeState, options: GraphViewFitOptions) {\n if (state.cy.destroyed()) return;\n if (state.layoutRunningRef.current) {\n state.fitRequestRef.current = options;\n return;\n }\n const input = state.latestUpdateRef.current;\n if (!input) return;\n const previous = state.optimizedSpacingRef.current ?? input.spacingFactor ?? 1;\n const spacing = compactGraphSpacing(state.cy, previous, {\n fitPadding: options.padding ?? state.fitPaddingRef.current,\n maxFitZoom: state.viewport.getFitZoomLimit(),\n minReadableZoom: state.viewport.getReadableZoomTarget(),\n });\n state.geometryRef.current = getGraphGeometryKey(state.cy);\n state.loopSizer.update();\n state.viewport.settle(false);\n state.controller.fit({ ...options, optimizeSpacing: false });\n if (spacing !== previous) {\n state.optimizedSpacingRef.current = spacing;\n state.callbacksRef.current.onSpacingFactorChange?.(spacing);\n }\n emitRenderedNodes(state);\n}\n\n/*** Stop the current layout and invalidate every stale completion callback. */\nfunction stopCurrentLayout(state: GraphRuntimeState) {\n state.generationRef.current += 1;\n state.layoutRunningRef.current = false;\n state.layoutRef.current?.stop();\n state.layoutRef.current = null;\n}\n\n/*** Apply consumer styles and hide native node paint only when React rich nodes are active. */\nfunction applyGraphStyles(\n cy: Core,\n rules: readonly GraphViewStyleRule[] | undefined,\n richNodeRendering: boolean,\n) {\n const styles = [...(rules ?? [])];\n if (richNodeRendering) {\n styles.push({\n selector: 'node',\n style: {\n 'background-opacity': 0,\n 'border-width': 0,\n label: '',\n 'overlay-opacity': 0,\n },\n });\n }\n if (styles.length > 0) cy.style(styles).update();\n}\n\n/***\n * Synchronize controlled selection without rerunning layout.\n * Selection updates must not trigger graph reconstruction or layout.\n */\nfunction setSelectedNodeIds(state: GraphRuntimeState, nodeIds: readonly string[] | undefined) {\n if (state.cy.destroyed() || nodeIds === undefined) return;\n const selectedIds = new Set(nodeIds);\n state.cy.nodes().forEach((node) => {\n if (selectedIds.has(node.id())) node.select();\n else node.unselect();\n });\n emitRenderedNodes(state);\n}\n\n/***\n * Persist one rich-node size and schedule at most one relayout for changed geometry.\n * Ignore unchanged measurements before scheduling layout work.\n */\nfunction setNodeSize(state: GraphRuntimeState, id: string, size: GraphViewSize) {\n const previous = state.nodeSizes.get(id);\n if (previous?.width === size.width && previous.height === size.height) return;\n state.nodeSizes.set(id, size);\n applyNodeSize(state.cy, id, size);\n scheduleMeasuredNodeRelayout(state);\n}\n\n/*** Apply every known rich-node size after Cytoscape elements are replaced. */\nfunction applyKnownNodeSizes(state: GraphRuntimeState) {\n for (const [id, size] of state.nodeSizes) applyNodeSize(state.cy, id, size);\n}\n\n/*** Apply one measured model-space size as a Cytoscape per-node style bypass. */\nfunction applyNodeSize(cy: Core, id: string, size: GraphViewSize) {\n const node = cy.getElementById(id);\n if (node.empty()) return;\n node.style({ height: size.height, width: size.width });\n}\n\n/***\n * Coalesce DOM measurements into one follow-up layout generation.\n * Keep one scheduled layout per frame instead of one per measured node.\n */\nfunction scheduleMeasuredNodeRelayout(state: GraphRuntimeState) {\n if (state.relayoutScheduledRef.current) return;\n state.relayoutScheduledRef.current = true;\n scheduleGraphFrame(() => {\n state.relayoutScheduledRef.current = false;\n const input = state.latestUpdateRef.current;\n if (input === null || state.cy.destroyed()) return;\n stopCurrentLayout(state);\n startCurrentLayout(state, input);\n });\n}\n\n/*** Subscribe one React overlay to rendered node state without exposing the Cytoscape core. */\nfunction subscribeRenderedNodes(state: GraphRuntimeState, listener: RenderedNodeListener) {\n state.renderedNodeListeners.add(listener);\n listener(readGraphRenderedNodes(state.cy, state.hoveredNodeIds));\n return () => {\n state.renderedNodeListeners.delete(listener);\n };\n}\n\n/***\n * Publish current rendered node positions only to active rich-node subscribers.\n * Skip snapshot preparation when no overlay is subscribed.\n */\nfunction emitRenderedNodes(\n state: Pick<GraphRuntimeState, 'cy' | 'hoveredNodeIds' | 'renderedNodeListeners'>,\n) {\n if (state.renderedNodeListeners.size === 0) return;\n const nodes = readGraphRenderedNodes(state.cy, state.hoveredNodeIds);\n for (const listener of state.renderedNodeListeners) listener(nodes);\n}\n\n/*** Translate one rich-overlay event back into normal graph selection and callbacks. */\nfunction handleOverlayNodeEvent(\n state: GraphRuntimeState,\n id: string,\n type: GraphViewElementEventType,\n) {\n if (type === 'pointer-enter') state.hoveredNodeIds.add(id);\n if (type === 'pointer-leave') state.hoveredNodeIds.delete(id);\n if (type === 'press') state.cy.getElementById(id).select();\n state.callbacksRef.current.onNodeEvent?.({ id, type });\n emitRenderedNodes(state);\n}\n\n/*** Return whether Cytoscape currently has dimensions suitable for fitting. */\nfunction hasUsableViewport(cy: Core): boolean {\n return cy.width() > 0 && cy.height() > 0;\n}\n\n/*** Dispose all runtime resources in the reverse order they were acquired. */\nfunction destroyRuntime(state: GraphRuntimeState) {\n state.resizeObserver?.disconnect();\n stopCurrentLayout(state);\n state.unbindEvents();\n state.renderedNodeListeners.clear();\n if (!state.cy.destroyed()) state.cy.destroy();\n}\n\nregisterGraphLayouts();\n"]}
@@ -0,0 +1,9 @@
1
+ import type { Core } from 'cytoscape';
2
+ import type { GraphSpacingEvaluator, GraphSpacingFitOptions } from '../../../../../types/graph-view-spacing';
3
+ /***
4
+ * Snapshot renderer geometry once and expose pure candidate evaluation plus one accepted mutation.
5
+ * Labels and unrelated compound boundaries are hard constraints. Leaf backgrounds report rendered
6
+ * overlap separately so the caller can spend a small visual-overlap budget only for dense graphs.
7
+ */
8
+ export declare function createGraphSpacingEvaluator(cy: Core, options?: GraphSpacingFitOptions): GraphSpacingEvaluator | null;
9
+ //# sourceMappingURL=createGraphSpacingEvaluator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createGraphSpacingEvaluator.d.ts","sourceRoot":"","sources":["../../../../../../src/features/graph-view/adapters/inbound/web-artifact/createGraphSpacingEvaluator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAgB,MAAM,WAAW,CAAC;AAEpD,OAAO,KAAK,EAEV,qBAAqB,EACrB,sBAAsB,EACvB,MAAM,yCAAyC,CAAC;AAiEjD;;;;GAIG;AACH,wBAAgB,2BAA2B,CACzC,EAAE,EAAE,IAAI,EACR,OAAO,GAAE,sBAA2B,GACnC,qBAAqB,GAAG,IAAI,CAwB9B"}
@@ -0,0 +1,234 @@
1
+ const MAX_PAIR_CHECKS = 200000;
2
+ /***
3
+ * Snapshot renderer geometry once and expose pure candidate evaluation plus one accepted mutation.
4
+ * Labels and unrelated compound boundaries are hard constraints. Leaf backgrounds report rendered
5
+ * overlap separately so the caller can spend a small visual-overlap budget only for dense graphs.
6
+ */
7
+ export function createGraphSpacingEvaluator(cy, options = {}) {
8
+ const leaves = cy.nodes(':childless');
9
+ const viewport = { width: cy.width(), height: cy.height() };
10
+ if (leaves.length < 2 || viewport.width <= 0 || viewport.height <= 0)
11
+ return null;
12
+ const leafBounds = leaves.boundingBox();
13
+ const center = {
14
+ x: (leafBounds.x1 + leafBounds.x2) / 2,
15
+ y: (leafBounds.y1 + leafBounds.y2) / 2,
16
+ };
17
+ const leafGeometry = leaves.map(readLeafGeometry);
18
+ const context = {
19
+ center,
20
+ fitPadding: Math.max(0, options.fitPadding ?? 50),
21
+ leaves: leafGeometry,
22
+ groups: cy.nodes(':parent').map((node) => readGroupGeometry(node, leafGeometry)),
23
+ maxFitZoom: positiveNumber(options.maxFitZoom, Infinity),
24
+ viewport,
25
+ };
26
+ return {
27
+ evaluate: (factor) => evaluateSpacingCandidate(context, factor),
28
+ apply: (factor) => applyScale(cy, leafGeometry, center, factor),
29
+ };
30
+ }
31
+ /*** Read immutable leaf geometry while separating label content from decorative node bounds. */
32
+ function readLeafGeometry(node) {
33
+ const fitBox = readNodeBox(node, true);
34
+ const visualBox = readNodeBox(node, false);
35
+ const labelBox = node.boundingBox({
36
+ includeNodes: false,
37
+ includeEdges: false,
38
+ includeLabels: true,
39
+ includeOverlays: false,
40
+ includeUnderlays: false,
41
+ });
42
+ return {
43
+ id: node.id(),
44
+ ancestors: new Set(node.ancestors().map((parent) => parent.id())),
45
+ position: { ...node.position() },
46
+ fitBox,
47
+ labelBox: isUsableBox(labelBox) ? labelBox : null,
48
+ visualBox: isUsableBox(visualBox) ? visualBox : fitBox,
49
+ };
50
+ }
51
+ /*** Read a leaf node box with explicit label participation and no edge/overlay geometry. */
52
+ function readNodeBox(node, includeLabels) {
53
+ return node.boundingBox({
54
+ includeNodes: true,
55
+ includeEdges: false,
56
+ includeLabels,
57
+ includeOverlays: false,
58
+ includeUnderlays: false,
59
+ });
60
+ }
61
+ /*** Capture compound insets so candidate parent bounds follow uniformly shifted descendants. */
62
+ function readGroupGeometry(node, leaves) {
63
+ const descendants = leaves.filter((leaf) => leaf.ancestors.has(node.id()));
64
+ const parentBox = readNodeBox(node, true);
65
+ const descendantUnion = unionBounds(descendants.map((leaf) => leaf.fitBox)) ?? parentBox;
66
+ return {
67
+ id: node.id(),
68
+ ancestors: new Set(node.ancestors().map((parent) => parent.id())),
69
+ descendantIds: descendants.map((leaf) => leaf.id),
70
+ insets: {
71
+ left: Math.max(0, descendantUnion.x1 - parentBox.x1),
72
+ right: Math.max(0, parentBox.x2 - descendantUnion.x2),
73
+ top: Math.max(0, descendantUnion.y1 - parentBox.y1),
74
+ bottom: Math.max(0, parentBox.y2 - descendantUnion.y2),
75
+ },
76
+ };
77
+ }
78
+ /*** Evaluate one uniform spacing factor without mutating Cytoscape or painting intermediate frames. */
79
+ function evaluateSpacingCandidate(context, factor) {
80
+ const leaves = context.leaves.map((leaf) => resolveLeafGeometry(leaf, context.center, factor));
81
+ const byId = new Map(leaves.map((leaf) => [leaf.id, leaf]));
82
+ const groups = context.groups.flatMap((group) => resolveGroupBox(group, byId));
83
+ const fitBounds = unionBounds([
84
+ ...leaves.map((leaf) => leaf.fitBox),
85
+ ...groups.map((group) => group.box),
86
+ ]);
87
+ const rawFitZoom = fitBounds === undefined ? 1 : getFitZoom(fitBounds, context);
88
+ const effectiveFitZoom = Math.min(rawFitZoom, context.maxFitZoom);
89
+ return {
90
+ effectiveFitZoom,
91
+ ...readCollisionState(createCollisionBoxes(leaves, groups), effectiveFitZoom),
92
+ };
93
+ }
94
+ /*** Shift one leaf's fixed renderer boxes with its center under uniform radial scaling. */
95
+ function resolveLeafGeometry(leaf, center, factor) {
96
+ return {
97
+ id: leaf.id,
98
+ ancestors: leaf.ancestors,
99
+ fitBox: shiftBounds(leaf.fitBox, leaf.position, center, factor),
100
+ labelBox: leaf.labelBox === null ? null : shiftBounds(leaf.labelBox, leaf.position, center, factor),
101
+ visualBox: shiftBounds(leaf.visualBox, leaf.position, center, factor),
102
+ };
103
+ }
104
+ /*** Resolve one compound boundary from shifted descendants plus measured outer insets. */
105
+ function resolveGroupBox(group, leaves) {
106
+ const descendantBounds = group.descendantIds.flatMap((id) => {
107
+ const leaf = leaves.get(id);
108
+ return leaf === undefined ? [] : [leaf.fitBox];
109
+ });
110
+ const union = unionBounds(descendantBounds);
111
+ return union === undefined
112
+ ? []
113
+ : [
114
+ {
115
+ id: group.id,
116
+ ancestors: group.ancestors,
117
+ kind: 'group',
118
+ box: expandBounds(union, group.insets),
119
+ },
120
+ ];
121
+ }
122
+ /*** Build collision boxes with semantic labels separate from decorative leaf backgrounds. */
123
+ function createCollisionBoxes(leaves, groups) {
124
+ return [
125
+ ...leaves.flatMap((leaf) => leaf.labelBox === null
126
+ ? []
127
+ : [{ id: leaf.id, ancestors: leaf.ancestors, kind: 'label', box: leaf.labelBox }]),
128
+ ...leaves.map((leaf) => ({
129
+ id: leaf.id,
130
+ ancestors: leaf.ancestors,
131
+ kind: 'visual',
132
+ box: leaf.visualBox,
133
+ })),
134
+ ...groups,
135
+ ];
136
+ }
137
+ /***
138
+ * Sweep collision boxes and separate semantic collisions from decorative background penetration.
139
+ * Pair-budget exhaustion is conservative and therefore treated as a hard collision.
140
+ */
141
+ function readCollisionState(boxes, zoom) {
142
+ const sorted = [...boxes].sort((first, second) => first.box.x1 - second.box.x1);
143
+ const budget = { remaining: MAX_PAIR_CHECKS };
144
+ const overlap = { maximum: 0 };
145
+ for (const [index, first] of sorted.entries()) {
146
+ for (let next = index + 1; next < sorted.length; next += 1) {
147
+ const second = sorted.at(next);
148
+ if (second === undefined)
149
+ break;
150
+ if (second.box.x1 >= first.box.x2)
151
+ break;
152
+ if (first.id === second.id || isIntentionalContainment(first, second))
153
+ continue;
154
+ const penetration = getOverlapPenetration(first.box, second.box);
155
+ if (penetration <= 0)
156
+ continue;
157
+ budget.remaining -= 1;
158
+ if (budget.remaining < 0)
159
+ return { hardCollision: true, renderedBackgroundOverlap: Infinity };
160
+ if (first.kind === 'visual' && second.kind === 'visual') {
161
+ overlap.maximum = Math.max(overlap.maximum, penetration * zoom);
162
+ continue;
163
+ }
164
+ return { hardCollision: true, renderedBackgroundOverlap: overlap.maximum };
165
+ }
166
+ }
167
+ return { hardCollision: false, renderedBackgroundOverlap: overlap.maximum };
168
+ }
169
+ /*** Ignore only true ancestor/descendant containment; siblings remain collision candidates. */
170
+ function isIntentionalContainment(first, second) {
171
+ return first.ancestors.has(second.id) || second.ancestors.has(first.id);
172
+ }
173
+ /*** Return the smaller-axis penetration for intersecting rectangles, or zero when disjoint. */
174
+ function getOverlapPenetration(first, second) {
175
+ const width = Math.min(first.x2, second.x2) - Math.max(first.x1, second.x1);
176
+ const height = Math.min(first.y2, second.y2) - Math.max(first.y1, second.y1);
177
+ return width > 0 && height > 0 ? Math.min(width, height) : 0;
178
+ }
179
+ /*** Calculate native zoom for fitting candidate node geometry inside the padded viewport. */
180
+ function getFitZoom(bounds, context) {
181
+ const width = context.viewport.width - 2 * context.fitPadding;
182
+ const height = context.viewport.height - 2 * context.fitPadding;
183
+ if (width <= 0 || height <= 0 || bounds.w <= 0 || bounds.h <= 0)
184
+ return 1;
185
+ return Math.min(width / bounds.w, height / bounds.h);
186
+ }
187
+ /*** Shift one fixed renderer box with its leaf center under uniform radial scaling. */
188
+ function shiftBounds(box, position, center, factor) {
189
+ const dx = (position.x - center.x) * (factor - 1);
190
+ const dy = (position.y - center.y) * (factor - 1);
191
+ return { ...box, x1: box.x1 + dx, y1: box.y1 + dy, x2: box.x2 + dx, y2: box.y2 + dy };
192
+ }
193
+ /*** Expand a descendant union by the compound renderer's measured outer insets. */
194
+ function expandBounds(box, insets) {
195
+ const x1 = box.x1 - insets.left;
196
+ const y1 = box.y1 - insets.top;
197
+ const x2 = box.x2 + insets.right;
198
+ const y2 = box.y2 + insets.bottom;
199
+ return { x1, y1, x2, y2, w: x2 - x1, h: y2 - y1 };
200
+ }
201
+ /*** Return the immutable union of measured boxes, or undefined for an empty collection. */
202
+ function unionBounds(boxes) {
203
+ if (boxes.length === 0)
204
+ return undefined;
205
+ const x1 = Math.min(...boxes.map((box) => box.x1));
206
+ const y1 = Math.min(...boxes.map((box) => box.y1));
207
+ const x2 = Math.max(...boxes.map((box) => box.x2));
208
+ const y2 = Math.max(...boxes.map((box) => box.y2));
209
+ return { x1, y1, x2, y2, w: x2 - x1, h: y2 - y1 };
210
+ }
211
+ /*** Return whether renderer measurement produced a non-empty box. */
212
+ function isUsableBox(box) {
213
+ return box.w > 0 && box.h > 0;
214
+ }
215
+ /*** Normalize an optional positive numeric input without allowing NaN or non-positive values. */
216
+ function positiveNumber(value, fallback) {
217
+ return value !== undefined && Number.isFinite(value) && value > 0 ? value : fallback;
218
+ }
219
+ /*** Apply the accepted factor once, preserving dimensions, hierarchy, ordering and edge data. */
220
+ function applyScale(cy, leaves, center, factor) {
221
+ const positions = new Map(leaves.map((leaf) => [leaf.id, leaf.position]));
222
+ cy.batch(() => {
223
+ cy.nodes()
224
+ .not(':parent')
225
+ .positions((node) => {
226
+ const original = positions.get(node.id()) ?? node.position();
227
+ return {
228
+ x: center.x + (original.x - center.x) * factor,
229
+ y: center.y + (original.y - center.y) * factor,
230
+ };
231
+ });
232
+ });
233
+ }
234
+ //# sourceMappingURL=createGraphSpacingEvaluator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createGraphSpacingEvaluator.js","sourceRoot":"","sources":["../../../../../../src/features/graph-view/adapters/inbound/web-artifact/createGraphSpacingEvaluator.ts"],"names":[],"mappings":"AAQA,MAAM,eAAe,GAAG,MAAM,CAAC;AA+D/B;;;;GAIG;AACH,MAAM,UAAU,2BAA2B,CACzC,EAAQ,EACR,UAAkC,EAAE;IAEpC,MAAM,MAAM,GAAG,EAAE,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;IACtC,MAAM,QAAQ,GAAG,EAAE,KAAK,EAAE,EAAE,CAAC,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC;IAC5D,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,IAAI,QAAQ,CAAC,KAAK,IAAI,CAAC,IAAI,QAAQ,CAAC,MAAM,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IAElF,MAAM,UAAU,GAAG,MAAM,CAAC,WAAW,EAAE,CAAC;IACxC,MAAM,MAAM,GAAG;QACb,CAAC,EAAE,CAAC,UAAU,CAAC,EAAE,GAAG,UAAU,CAAC,EAAE,CAAC,GAAG,CAAC;QACtC,CAAC,EAAE,CAAC,UAAU,CAAC,EAAE,GAAG,UAAU,CAAC,EAAE,CAAC,GAAG,CAAC;KACvC,CAAC;IACF,MAAM,YAAY,GAAG,MAAM,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC;IAClD,MAAM,OAAO,GAAmB;QAC9B,MAAM;QACN,UAAU,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,CAAC,UAAU,IAAI,EAAE,CAAC;QACjD,MAAM,EAAE,YAAY;QACpB,MAAM,EAAE,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,iBAAiB,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC;QAChF,UAAU,EAAE,cAAc,CAAC,OAAO,CAAC,UAAU,EAAE,QAAQ,CAAC;QACxD,QAAQ;KACT,CAAC;IAEF,OAAO;QACL,QAAQ,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC,wBAAwB,CAAC,OAAO,EAAE,MAAM,CAAC;QAC/D,KAAK,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC,UAAU,CAAC,EAAE,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,CAAC;KAChE,CAAC;AACJ,CAAC;AAED,gGAAgG;AAChG,SAAS,gBAAgB,CAAC,IAAkB;IAC1C,MAAM,MAAM,GAAG,WAAW,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IACvC,MAAM,SAAS,GAAG,WAAW,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IAC3C,MAAM,QAAQ,GAAG,IAAI,CAAC,WAAW,CAAC;QAChC,YAAY,EAAE,KAAK;QACnB,YAAY,EAAE,KAAK;QACnB,aAAa,EAAE,IAAI;QACnB,eAAe,EAAE,KAAK;QACtB,gBAAgB,EAAE,KAAK;KACxB,CAAC,CAAC;IACH,OAAO;QACL,EAAE,EAAE,IAAI,CAAC,EAAE,EAAE;QACb,SAAS,EAAE,IAAI,GAAG,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC;QACjE,QAAQ,EAAE,EAAE,GAAG,IAAI,CAAC,QAAQ,EAAE,EAAE;QAChC,MAAM;QACN,QAAQ,EAAE,WAAW,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI;QACjD,SAAS,EAAE,WAAW,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM;KACvD,CAAC;AACJ,CAAC;AAED,4FAA4F;AAC5F,SAAS,WAAW,CAAC,IAAkB,EAAE,aAAsB;IAC7D,OAAO,IAAI,CAAC,WAAW,CAAC;QACtB,YAAY,EAAE,IAAI;QAClB,YAAY,EAAE,KAAK;QACnB,aAAa;QACb,eAAe,EAAE,KAAK;QACtB,gBAAgB,EAAE,KAAK;KACxB,CAAC,CAAC;AACL,CAAC;AAED,gGAAgG;AAChG,SAAS,iBAAiB,CAAC,IAAkB,EAAE,MAA+B;IAC5E,MAAM,WAAW,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;IAC3E,MAAM,SAAS,GAAG,WAAW,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAC1C,MAAM,eAAe,GAAG,WAAW,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,SAAS,CAAC;IACzF,OAAO;QACL,EAAE,EAAE,IAAI,CAAC,EAAE,EAAE;QACb,SAAS,EAAE,IAAI,GAAG,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC;QACjE,aAAa,EAAE,WAAW,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;QACjD,MAAM,EAAE;YACN,IAAI,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,eAAe,CAAC,EAAE,GAAG,SAAS,CAAC,EAAE,CAAC;YACpD,KAAK,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,SAAS,CAAC,EAAE,GAAG,eAAe,CAAC,EAAE,CAAC;YACrD,GAAG,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,eAAe,CAAC,EAAE,GAAG,SAAS,CAAC,EAAE,CAAC;YACnD,MAAM,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,SAAS,CAAC,EAAE,GAAG,eAAe,CAAC,EAAE,CAAC;SACvD;KACF,CAAC;AACJ,CAAC;AAED,uGAAuG;AACvG,SAAS,wBAAwB,CAAC,OAAuB,EAAE,MAAc;IACvE,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,mBAAmB,CAAC,IAAI,EAAE,OAAO,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAC/F,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC;IAC5D,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,eAAe,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC,CAAC;IAC/E,MAAM,SAAS,GAAG,WAAW,CAAC;QAC5B,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC;QACpC,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC;KACpC,CAAC,CAAC;IACH,MAAM,UAAU,GAAG,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;IAChF,MAAM,gBAAgB,GAAG,IAAI,CAAC,GAAG,CAAC,UAAU,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;IAClE,OAAO;QACL,gBAAgB;QAChB,GAAG,kBAAkB,CAAC,oBAAoB,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,gBAAgB,CAAC;KAC9E,CAAC;AACJ,CAAC;AAED,2FAA2F;AAC3F,SAAS,mBAAmB,CAC1B,IAAkB,EAClB,MAAa,EACb,MAAc;IAEd,OAAO;QACL,EAAE,EAAE,IAAI,CAAC,EAAE;QACX,SAAS,EAAE,IAAI,CAAC,SAAS;QACzB,MAAM,EAAE,WAAW,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC;QAC/D,QAAQ,EACN,IAAI,CAAC,QAAQ,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,WAAW,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC;QAC3F,SAAS,EAAE,WAAW,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC;KACtE,CAAC;AACJ,CAAC;AAED,0FAA0F;AAC1F,SAAS,eAAe,CACtB,KAAoB,EACpB,MAAiD;IAEjD,MAAM,gBAAgB,GAAG,KAAK,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,EAAE,EAAE,EAAE;QAC1D,MAAM,IAAI,GAAG,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAC5B,OAAO,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACjD,CAAC,CAAC,CAAC;IACH,MAAM,KAAK,GAAG,WAAW,CAAC,gBAAgB,CAAC,CAAC;IAC5C,OAAO,KAAK,KAAK,SAAS;QACxB,CAAC,CAAC,EAAE;QACJ,CAAC,CAAC;YACE;gBACE,EAAE,EAAE,KAAK,CAAC,EAAE;gBACZ,SAAS,EAAE,KAAK,CAAC,SAAS;gBAC1B,IAAI,EAAE,OAAO;gBACb,GAAG,EAAE,YAAY,CAAC,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC;aACvC;SACF,CAAC;AACR,CAAC;AAED,6FAA6F;AAC7F,SAAS,oBAAoB,CAC3B,MAAuC,EACvC,MAA+B;IAE/B,OAAO;QACL,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE,CACzB,IAAI,CAAC,QAAQ,KAAK,IAAI;YACpB,CAAC,CAAC,EAAE;YACJ,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,CAAC,SAAS,EAAE,IAAI,EAAE,OAAgB,EAAE,GAAG,EAAE,IAAI,CAAC,QAAQ,EAAE,CAAC,CAC7F;QACD,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;YACvB,EAAE,EAAE,IAAI,CAAC,EAAE;YACX,SAAS,EAAE,IAAI,CAAC,SAAS;YACzB,IAAI,EAAE,QAAiB;YACvB,GAAG,EAAE,IAAI,CAAC,SAAS;SACpB,CAAC,CAAC;QACH,GAAG,MAAM;KACV,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,SAAS,kBAAkB,CACzB,KAA8B,EAC9B,IAAY;IAEZ,MAAM,MAAM,GAAG,CAAC,GAAG,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,GAAG,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAChF,MAAM,MAAM,GAAG,EAAE,SAAS,EAAE,eAAe,EAAE,CAAC;IAC9C,MAAM,OAAO,GAAG,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC;IAC/B,KAAK,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,EAAE,EAAE,CAAC;QAC9C,KAAK,IAAI,IAAI,GAAG,KAAK,GAAG,CAAC,EAAE,IAAI,GAAG,MAAM,CAAC,MAAM,EAAE,IAAI,IAAI,CAAC,EAAE,CAAC;YAC3D,MAAM,MAAM,GAAG,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC;YAC/B,IAAI,MAAM,KAAK,SAAS;gBAAE,MAAM;YAChC,IAAI,MAAM,CAAC,GAAG,CAAC,EAAE,IAAI,KAAK,CAAC,GAAG,CAAC,EAAE;gBAAE,MAAM;YACzC,IAAI,KAAK,CAAC,EAAE,KAAK,MAAM,CAAC,EAAE,IAAI,wBAAwB,CAAC,KAAK,EAAE,MAAM,CAAC;gBAAE,SAAS;YAChF,MAAM,WAAW,GAAG,qBAAqB,CAAC,KAAK,CAAC,GAAG,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC;YACjE,IAAI,WAAW,IAAI,CAAC;gBAAE,SAAS;YAC/B,MAAM,CAAC,SAAS,IAAI,CAAC,CAAC;YACtB,IAAI,MAAM,CAAC,SAAS,GAAG,CAAC;gBAAE,OAAO,EAAE,aAAa,EAAE,IAAI,EAAE,yBAAyB,EAAE,QAAQ,EAAE,CAAC;YAC9F,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ,IAAI,MAAM,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;gBACxD,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,EAAE,WAAW,GAAG,IAAI,CAAC,CAAC;gBAChE,SAAS;YACX,CAAC;YACD,OAAO,EAAE,aAAa,EAAE,IAAI,EAAE,yBAAyB,EAAE,OAAO,CAAC,OAAO,EAAE,CAAC;QAC7E,CAAC;IACH,CAAC;IACD,OAAO,EAAE,aAAa,EAAE,KAAK,EAAE,yBAAyB,EAAE,OAAO,CAAC,OAAO,EAAE,CAAC;AAC9E,CAAC;AAED,+FAA+F;AAC/F,SAAS,wBAAwB,CAAC,KAAmB,EAAE,MAAoB;IACzE,OAAO,KAAK,CAAC,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;AAC1E,CAAC;AAED,+FAA+F;AAC/F,SAAS,qBAAqB,CAAC,KAAa,EAAE,MAAc;IAC1D,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,EAAE,MAAM,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC;IAC5E,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,EAAE,MAAM,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC;IAC7E,OAAO,KAAK,GAAG,CAAC,IAAI,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC/D,CAAC;AAED,6FAA6F;AAC7F,SAAS,UAAU,CAAC,MAAc,EAAE,OAAuB;IACzD,MAAM,KAAK,GAAG,OAAO,CAAC,QAAQ,CAAC,KAAK,GAAG,CAAC,GAAG,OAAO,CAAC,UAAU,CAAC;IAC9D,MAAM,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,GAAG,OAAO,CAAC,UAAU,CAAC;IAChE,IAAI,KAAK,IAAI,CAAC,IAAI,MAAM,IAAI,CAAC,IAAI,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,MAAM,CAAC,CAAC,IAAI,CAAC;QAAE,OAAO,CAAC,CAAC;IAC1E,OAAO,IAAI,CAAC,GAAG,CAAC,KAAK,GAAG,MAAM,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;AACvD,CAAC;AAED,uFAAuF;AACvF,SAAS,WAAW,CAAC,GAAW,EAAE,QAAe,EAAE,MAAa,EAAE,MAAc;IAC9E,MAAM,EAAE,GAAG,CAAC,QAAQ,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAClD,MAAM,EAAE,GAAG,CAAC,QAAQ,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAClD,OAAO,EAAE,GAAG,GAAG,EAAE,EAAE,EAAE,GAAG,CAAC,EAAE,GAAG,EAAE,EAAE,EAAE,EAAE,GAAG,CAAC,EAAE,GAAG,EAAE,EAAE,EAAE,EAAE,GAAG,CAAC,EAAE,GAAG,EAAE,EAAE,EAAE,EAAE,GAAG,CAAC,EAAE,GAAG,EAAE,EAAE,CAAC;AACxF,CAAC;AAED,mFAAmF;AACnF,SAAS,YAAY,CAAC,GAAW,EAAE,MAAc;IAC/C,MAAM,EAAE,GAAG,GAAG,CAAC,EAAE,GAAG,MAAM,CAAC,IAAI,CAAC;IAChC,MAAM,EAAE,GAAG,GAAG,CAAC,EAAE,GAAG,MAAM,CAAC,GAAG,CAAC;IAC/B,MAAM,EAAE,GAAG,GAAG,CAAC,EAAE,GAAG,MAAM,CAAC,KAAK,CAAC;IACjC,MAAM,EAAE,GAAG,GAAG,CAAC,EAAE,GAAG,MAAM,CAAC,MAAM,CAAC;IAClC,OAAO,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,GAAG,EAAE,EAAE,CAAC,EAAE,EAAE,GAAG,EAAE,EAAE,CAAC;AACpD,CAAC;AAED,2FAA2F;AAC3F,SAAS,WAAW,CAAC,KAAwB;IAC3C,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,SAAS,CAAC;IACzC,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;IACnD,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;IACnD,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;IACnD,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;IACnD,OAAO,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,GAAG,EAAE,EAAE,CAAC,EAAE,EAAE,GAAG,EAAE,EAAE,CAAC;AACpD,CAAC;AAED,qEAAqE;AACrE,SAAS,WAAW,CAAC,GAAW;IAC9B,OAAO,GAAG,CAAC,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC;AAChC,CAAC;AAED,iGAAiG;AACjG,SAAS,cAAc,CAAC,KAAyB,EAAE,QAAgB;IACjE,OAAO,KAAK,KAAK,SAAS,IAAI,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC;AACvF,CAAC;AAED,iGAAiG;AACjG,SAAS,UAAU,CACjB,EAAQ,EACR,MAA+B,EAC/B,MAAa,EACb,MAAc;IAEd,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;IAC1E,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE;QACZ,EAAE,CAAC,KAAK,EAAE;aACP,GAAG,CAAC,SAAS,CAAC;aACd,SAAS,CAAC,CAAC,IAAI,EAAE,EAAE;YAClB,MAAM,QAAQ,GAAG,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YAC7D,OAAO;gBACL,CAAC,EAAE,MAAM,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,GAAG,MAAM;gBAC9C,CAAC,EAAE,MAAM,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,GAAG,MAAM;aAC/C,CAAC;QACJ,CAAC,CAAC,CAAC;IACP,CAAC,CAAC,CAAC;AACL,CAAC","sourcesContent":["import type { Core, NodeSingular } from 'cytoscape';\n\nimport type {\n GraphSpacingCandidate,\n GraphSpacingEvaluator,\n GraphSpacingFitOptions,\n} from '../../../../../types/graph-view-spacing';\n\nconst MAX_PAIR_CHECKS = 200000;\n\ninterface Point {\n readonly x: number;\n readonly y: number;\n}\n\ninterface Bounds {\n readonly x1: number;\n readonly y1: number;\n readonly x2: number;\n readonly y2: number;\n readonly w: number;\n readonly h: number;\n}\n\ninterface Insets {\n readonly left: number;\n readonly right: number;\n readonly top: number;\n readonly bottom: number;\n}\n\ninterface LeafGeometry {\n readonly id: string;\n readonly ancestors: ReadonlySet<string>;\n readonly position: Point;\n readonly fitBox: Bounds;\n readonly labelBox: Bounds | null;\n readonly visualBox: Bounds;\n}\n\ninterface GroupGeometry {\n readonly id: string;\n readonly ancestors: ReadonlySet<string>;\n readonly descendantIds: readonly string[];\n readonly insets: Insets;\n}\n\ninterface ResolvedLeafGeometry {\n readonly id: string;\n readonly ancestors: ReadonlySet<string>;\n readonly fitBox: Bounds;\n readonly labelBox: Bounds | null;\n readonly visualBox: Bounds;\n}\n\ninterface CollisionBox {\n readonly id: string;\n readonly ancestors: ReadonlySet<string>;\n readonly kind: 'group' | 'label' | 'visual';\n readonly box: Bounds;\n}\n\ninterface SpacingContext {\n readonly center: Point;\n readonly fitPadding: number;\n readonly leaves: readonly LeafGeometry[];\n readonly groups: readonly GroupGeometry[];\n readonly maxFitZoom: number;\n readonly viewport: { readonly width: number; readonly height: number };\n}\n\n/***\n * Snapshot renderer geometry once and expose pure candidate evaluation plus one accepted mutation.\n * Labels and unrelated compound boundaries are hard constraints. Leaf backgrounds report rendered\n * overlap separately so the caller can spend a small visual-overlap budget only for dense graphs.\n */\nexport function createGraphSpacingEvaluator(\n cy: Core,\n options: GraphSpacingFitOptions = {},\n): GraphSpacingEvaluator | null {\n const leaves = cy.nodes(':childless');\n const viewport = { width: cy.width(), height: cy.height() };\n if (leaves.length < 2 || viewport.width <= 0 || viewport.height <= 0) return null;\n\n const leafBounds = leaves.boundingBox();\n const center = {\n x: (leafBounds.x1 + leafBounds.x2) / 2,\n y: (leafBounds.y1 + leafBounds.y2) / 2,\n };\n const leafGeometry = leaves.map(readLeafGeometry);\n const context: SpacingContext = {\n center,\n fitPadding: Math.max(0, options.fitPadding ?? 50),\n leaves: leafGeometry,\n groups: cy.nodes(':parent').map((node) => readGroupGeometry(node, leafGeometry)),\n maxFitZoom: positiveNumber(options.maxFitZoom, Infinity),\n viewport,\n };\n\n return {\n evaluate: (factor) => evaluateSpacingCandidate(context, factor),\n apply: (factor) => applyScale(cy, leafGeometry, center, factor),\n };\n}\n\n/*** Read immutable leaf geometry while separating label content from decorative node bounds. */\nfunction readLeafGeometry(node: NodeSingular): LeafGeometry {\n const fitBox = readNodeBox(node, true);\n const visualBox = readNodeBox(node, false);\n const labelBox = node.boundingBox({\n includeNodes: false,\n includeEdges: false,\n includeLabels: true,\n includeOverlays: false,\n includeUnderlays: false,\n });\n return {\n id: node.id(),\n ancestors: new Set(node.ancestors().map((parent) => parent.id())),\n position: { ...node.position() },\n fitBox,\n labelBox: isUsableBox(labelBox) ? labelBox : null,\n visualBox: isUsableBox(visualBox) ? visualBox : fitBox,\n };\n}\n\n/*** Read a leaf node box with explicit label participation and no edge/overlay geometry. */\nfunction readNodeBox(node: NodeSingular, includeLabels: boolean): Bounds {\n return node.boundingBox({\n includeNodes: true,\n includeEdges: false,\n includeLabels,\n includeOverlays: false,\n includeUnderlays: false,\n });\n}\n\n/*** Capture compound insets so candidate parent bounds follow uniformly shifted descendants. */\nfunction readGroupGeometry(node: NodeSingular, leaves: readonly LeafGeometry[]): GroupGeometry {\n const descendants = leaves.filter((leaf) => leaf.ancestors.has(node.id()));\n const parentBox = readNodeBox(node, true);\n const descendantUnion = unionBounds(descendants.map((leaf) => leaf.fitBox)) ?? parentBox;\n return {\n id: node.id(),\n ancestors: new Set(node.ancestors().map((parent) => parent.id())),\n descendantIds: descendants.map((leaf) => leaf.id),\n insets: {\n left: Math.max(0, descendantUnion.x1 - parentBox.x1),\n right: Math.max(0, parentBox.x2 - descendantUnion.x2),\n top: Math.max(0, descendantUnion.y1 - parentBox.y1),\n bottom: Math.max(0, parentBox.y2 - descendantUnion.y2),\n },\n };\n}\n\n/*** Evaluate one uniform spacing factor without mutating Cytoscape or painting intermediate frames. */\nfunction evaluateSpacingCandidate(context: SpacingContext, factor: number): GraphSpacingCandidate {\n const leaves = context.leaves.map((leaf) => resolveLeafGeometry(leaf, context.center, factor));\n const byId = new Map(leaves.map((leaf) => [leaf.id, leaf]));\n const groups = context.groups.flatMap((group) => resolveGroupBox(group, byId));\n const fitBounds = unionBounds([\n ...leaves.map((leaf) => leaf.fitBox),\n ...groups.map((group) => group.box),\n ]);\n const rawFitZoom = fitBounds === undefined ? 1 : getFitZoom(fitBounds, context);\n const effectiveFitZoom = Math.min(rawFitZoom, context.maxFitZoom);\n return {\n effectiveFitZoom,\n ...readCollisionState(createCollisionBoxes(leaves, groups), effectiveFitZoom),\n };\n}\n\n/*** Shift one leaf's fixed renderer boxes with its center under uniform radial scaling. */\nfunction resolveLeafGeometry(\n leaf: LeafGeometry,\n center: Point,\n factor: number,\n): ResolvedLeafGeometry {\n return {\n id: leaf.id,\n ancestors: leaf.ancestors,\n fitBox: shiftBounds(leaf.fitBox, leaf.position, center, factor),\n labelBox:\n leaf.labelBox === null ? null : shiftBounds(leaf.labelBox, leaf.position, center, factor),\n visualBox: shiftBounds(leaf.visualBox, leaf.position, center, factor),\n };\n}\n\n/*** Resolve one compound boundary from shifted descendants plus measured outer insets. */\nfunction resolveGroupBox(\n group: GroupGeometry,\n leaves: ReadonlyMap<string, ResolvedLeafGeometry>,\n): readonly CollisionBox[] {\n const descendantBounds = group.descendantIds.flatMap((id) => {\n const leaf = leaves.get(id);\n return leaf === undefined ? [] : [leaf.fitBox];\n });\n const union = unionBounds(descendantBounds);\n return union === undefined\n ? []\n : [\n {\n id: group.id,\n ancestors: group.ancestors,\n kind: 'group',\n box: expandBounds(union, group.insets),\n },\n ];\n}\n\n/*** Build collision boxes with semantic labels separate from decorative leaf backgrounds. */\nfunction createCollisionBoxes(\n leaves: readonly ResolvedLeafGeometry[],\n groups: readonly CollisionBox[],\n): readonly CollisionBox[] {\n return [\n ...leaves.flatMap((leaf) =>\n leaf.labelBox === null\n ? []\n : [{ id: leaf.id, ancestors: leaf.ancestors, kind: 'label' as const, box: leaf.labelBox }],\n ),\n ...leaves.map((leaf) => ({\n id: leaf.id,\n ancestors: leaf.ancestors,\n kind: 'visual' as const,\n box: leaf.visualBox,\n })),\n ...groups,\n ];\n}\n\n/***\n * Sweep collision boxes and separate semantic collisions from decorative background penetration.\n * Pair-budget exhaustion is conservative and therefore treated as a hard collision.\n */\nfunction readCollisionState(\n boxes: readonly CollisionBox[],\n zoom: number,\n): Pick<GraphSpacingCandidate, 'hardCollision' | 'renderedBackgroundOverlap'> {\n const sorted = [...boxes].sort((first, second) => first.box.x1 - second.box.x1);\n const budget = { remaining: MAX_PAIR_CHECKS };\n const overlap = { maximum: 0 };\n for (const [index, first] of sorted.entries()) {\n for (let next = index + 1; next < sorted.length; next += 1) {\n const second = sorted.at(next);\n if (second === undefined) break;\n if (second.box.x1 >= first.box.x2) break;\n if (first.id === second.id || isIntentionalContainment(first, second)) continue;\n const penetration = getOverlapPenetration(first.box, second.box);\n if (penetration <= 0) continue;\n budget.remaining -= 1;\n if (budget.remaining < 0) return { hardCollision: true, renderedBackgroundOverlap: Infinity };\n if (first.kind === 'visual' && second.kind === 'visual') {\n overlap.maximum = Math.max(overlap.maximum, penetration * zoom);\n continue;\n }\n return { hardCollision: true, renderedBackgroundOverlap: overlap.maximum };\n }\n }\n return { hardCollision: false, renderedBackgroundOverlap: overlap.maximum };\n}\n\n/*** Ignore only true ancestor/descendant containment; siblings remain collision candidates. */\nfunction isIntentionalContainment(first: CollisionBox, second: CollisionBox): boolean {\n return first.ancestors.has(second.id) || second.ancestors.has(first.id);\n}\n\n/*** Return the smaller-axis penetration for intersecting rectangles, or zero when disjoint. */\nfunction getOverlapPenetration(first: Bounds, second: Bounds): number {\n const width = Math.min(first.x2, second.x2) - Math.max(first.x1, second.x1);\n const height = Math.min(first.y2, second.y2) - Math.max(first.y1, second.y1);\n return width > 0 && height > 0 ? Math.min(width, height) : 0;\n}\n\n/*** Calculate native zoom for fitting candidate node geometry inside the padded viewport. */\nfunction getFitZoom(bounds: Bounds, context: SpacingContext): number {\n const width = context.viewport.width - 2 * context.fitPadding;\n const height = context.viewport.height - 2 * context.fitPadding;\n if (width <= 0 || height <= 0 || bounds.w <= 0 || bounds.h <= 0) return 1;\n return Math.min(width / bounds.w, height / bounds.h);\n}\n\n/*** Shift one fixed renderer box with its leaf center under uniform radial scaling. */\nfunction shiftBounds(box: Bounds, position: Point, center: Point, factor: number): Bounds {\n const dx = (position.x - center.x) * (factor - 1);\n const dy = (position.y - center.y) * (factor - 1);\n return { ...box, x1: box.x1 + dx, y1: box.y1 + dy, x2: box.x2 + dx, y2: box.y2 + dy };\n}\n\n/*** Expand a descendant union by the compound renderer's measured outer insets. */\nfunction expandBounds(box: Bounds, insets: Insets): Bounds {\n const x1 = box.x1 - insets.left;\n const y1 = box.y1 - insets.top;\n const x2 = box.x2 + insets.right;\n const y2 = box.y2 + insets.bottom;\n return { x1, y1, x2, y2, w: x2 - x1, h: y2 - y1 };\n}\n\n/*** Return the immutable union of measured boxes, or undefined for an empty collection. */\nfunction unionBounds(boxes: readonly Bounds[]): Bounds | undefined {\n if (boxes.length === 0) return undefined;\n const x1 = Math.min(...boxes.map((box) => box.x1));\n const y1 = Math.min(...boxes.map((box) => box.y1));\n const x2 = Math.max(...boxes.map((box) => box.x2));\n const y2 = Math.max(...boxes.map((box) => box.y2));\n return { x1, y1, x2, y2, w: x2 - x1, h: y2 - y1 };\n}\n\n/*** Return whether renderer measurement produced a non-empty box. */\nfunction isUsableBox(box: Bounds): boolean {\n return box.w > 0 && box.h > 0;\n}\n\n/*** Normalize an optional positive numeric input without allowing NaN or non-positive values. */\nfunction positiveNumber(value: number | undefined, fallback: number): number {\n return value !== undefined && Number.isFinite(value) && value > 0 ? value : fallback;\n}\n\n/*** Apply the accepted factor once, preserving dimensions, hierarchy, ordering and edge data. */\nfunction applyScale(\n cy: Core,\n leaves: readonly LeafGeometry[],\n center: Point,\n factor: number,\n): void {\n const positions = new Map(leaves.map((leaf) => [leaf.id, leaf.position]));\n cy.batch(() => {\n cy.nodes()\n .not(':parent')\n .positions((node) => {\n const original = positions.get(node.id()) ?? node.position();\n return {\n x: center.x + (original.x - center.x) * factor,\n y: center.y + (original.y - center.y) * factor,\n };\n });\n });\n}\n"]}
@@ -0,0 +1,15 @@
1
+ export interface GraphSpacingFitOptions {
2
+ readonly fitPadding?: number;
3
+ readonly maxFitZoom?: number;
4
+ readonly minReadableZoom?: number;
5
+ }
6
+ export interface GraphSpacingCandidate {
7
+ readonly effectiveFitZoom: number;
8
+ readonly hardCollision: boolean;
9
+ readonly renderedBackgroundOverlap: number;
10
+ }
11
+ export interface GraphSpacingEvaluator {
12
+ readonly evaluate: (factor: number) => GraphSpacingCandidate;
13
+ readonly apply: (factor: number) => void;
14
+ }
15
+ //# sourceMappingURL=graph-view-spacing.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"graph-view-spacing.d.ts","sourceRoot":"","sources":["../../src/types/graph-view-spacing.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAC;CACnC;AAED,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAClC,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAC;IAChC,QAAQ,CAAC,yBAAyB,EAAE,MAAM,CAAC;CAC5C;AAED,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,qBAAqB,CAAC;IAC7D,QAAQ,CAAC,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;CAC1C"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=graph-view-spacing.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"graph-view-spacing.js","sourceRoot":"","sources":["../../src/types/graph-view-spacing.ts"],"names":[],"mappings":"","sourcesContent":["export interface GraphSpacingFitOptions {\n readonly fitPadding?: number;\n readonly maxFitZoom?: number;\n readonly minReadableZoom?: number;\n}\n\nexport interface GraphSpacingCandidate {\n readonly effectiveFitZoom: number;\n readonly hardCollision: boolean;\n readonly renderedBackgroundOverlap: number;\n}\n\nexport interface GraphSpacingEvaluator {\n readonly evaluate: (factor: number) => GraphSpacingCandidate;\n readonly apply: (factor: number) => void;\n}\n"]}
@@ -54,7 +54,10 @@ export interface GraphViewViewport {
54
54
  readonly pan: GraphViewPoint;
55
55
  }
56
56
  export interface GraphViewFitOptions {
57
- /** Optimize existing layout spacing without rerunning its algorithm; whole-graph fits only. */
57
+ /**
58
+ * Optimize effective rendered fit without rerunning the layout algorithm; whole-graph fits only.
59
+ * Stops at the configured fit-size target and keeps semantic labels collision-safe.
60
+ */
58
61
  readonly optimizeSpacing?: boolean;
59
62
  readonly nodeIds?: readonly string[];
60
63
  readonly padding?: number;
@@ -1 +1 @@
1
- {"version":3,"file":"graph-view.d.ts","sourceRoot":"","sources":["../../src/types/graph-view.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"graph-view.d.ts","sourceRoot":"","sources":["../../src/types/graph-view.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"graph-view.js","sourceRoot":"","sources":["../../src/types/graph-view.ts"],"names":[],"mappings":"","sourcesContent":["import type React from 'react';\n\nexport type GraphViewLayoutName = 'breadthfirst' | 'circle' | 'concentric' | 'elk' | 'grid';\nexport type GraphViewElementEventType =\n 'press' | 'double-press' | 'select' | 'unselect' | 'pointer-enter' | 'pointer-leave';\n\nexport interface GraphViewNode {\n readonly id: string;\n readonly label?: string;\n readonly parentId?: string;\n readonly classes?: string;\n readonly data?: Readonly<Record<string, unknown>>;\n}\n\nexport interface GraphViewEdge {\n readonly id?: string;\n readonly source: string;\n readonly target: string;\n readonly classes?: string;\n readonly data?: Readonly<Record<string, unknown>>;\n}\n\nexport interface GraphViewStyleRule {\n readonly selector: string;\n readonly style: Readonly<Record<string, unknown>>;\n}\n\nexport interface GraphViewPoint {\n readonly x: number;\n readonly y: number;\n}\n\nexport interface GraphViewSize {\n readonly width: number;\n readonly height: number;\n}\n\nexport interface GraphViewNodeRenderContext {\n readonly hovered: boolean;\n readonly node: GraphViewNode;\n readonly selected: boolean;\n readonly zoom: number;\n}\n\nexport interface GraphViewRenderedNode {\n readonly hovered: boolean;\n readonly id: string;\n readonly position: GraphViewPoint;\n readonly selected: boolean;\n readonly zoom: number;\n}\n\nexport interface GraphViewNodeMeasurement {\n readonly id: string;\n readonly position: GraphViewPoint;\n readonly size: GraphViewSize;\n}\n\nexport interface GraphViewMeasurement {\n readonly nodes: readonly GraphViewNodeMeasurement[];\n readonly viewport: GraphViewSize;\n}\n\nexport interface GraphViewViewport {\n readonly zoom: number;\n readonly pan: GraphViewPoint;\n}\n\nexport interface GraphViewFitOptions {\n /** Optimize existing layout spacing without rerunning its algorithm; whole-graph fits only. */\n readonly optimizeSpacing?: boolean;\n readonly nodeIds?: readonly string[];\n readonly padding?: number;\n}\n\nexport interface GraphViewElementEvent {\n readonly id: string;\n readonly type: GraphViewElementEventType;\n}\n\nexport interface GraphViewController {\n fit(options?: GraphViewFitOptions): void;\n /** Measure rendered node geometry without exposing the backing graph engine. */\n measureNodes?(nodeIds: readonly string[]): GraphViewMeasurement | null;\n getViewport(): GraphViewViewport;\n getZoomRange(): { readonly min: number; readonly max: number };\n setPan(pan: GraphViewPoint): void;\n setZoom(zoom: number): void;\n zoomBy(factor: number): void;\n}\n\nexport interface GraphViewProps {\n readonly nodes: readonly GraphViewNode[];\n readonly edges: readonly GraphViewEdge[];\n readonly layout?: GraphViewLayoutName;\n readonly layoutOptions?: Readonly<Record<string, unknown>>;\n readonly spacingFactor?: number;\n readonly styleRules?: readonly GraphViewStyleRule[];\n readonly selectedNodeIds?: readonly string[];\n readonly renderNode?: (context: GraphViewNodeRenderContext) => React.ReactNode;\n readonly getNodeSize?: (node: GraphViewNode) => GraphViewSize | undefined;\n readonly fitPadding?: number;\n readonly minZoom?: number;\n readonly maxZoom?: number;\n readonly minReadableLabelSize?: number;\n readonly maxFitLabelSize?: number;\n /** Zoom values and bounds use the full-node fit as 1 when fit-relative is selected. */\n readonly zoomMode?: 'absolute' | 'fit-relative';\n /** Measure plain labels before layout instead of estimating width from character count. */\n readonly sizeNodesToLabels?: boolean;\n readonly className?: string;\n readonly style?: React.CSSProperties;\n readonly ariaLabel?: string;\n readonly onReady?: (controller: GraphViewController) => void;\n readonly onLayoutComplete?: (controller: GraphViewController) => void;\n readonly onNodeEvent?: (event: GraphViewElementEvent) => void;\n readonly onEdgeEvent?: (event: GraphViewElementEvent) => void;\n readonly onViewportChange?: (viewport: GraphViewViewport) => void;\n readonly onSpacingFactorChange?: (spacingFactor: number) => void;\n}\n\nexport type GraphViewCallbacks = Pick<\n GraphViewProps,\n | 'onEdgeEvent'\n | 'onLayoutComplete'\n | 'onNodeEvent'\n | 'onReady'\n | 'onViewportChange'\n | 'onSpacingFactorChange'\n>;\n"]}
1
+ {"version":3,"file":"graph-view.js","sourceRoot":"","sources":["../../src/types/graph-view.ts"],"names":[],"mappings":"","sourcesContent":["import type React from 'react';\n\nexport type GraphViewLayoutName = 'breadthfirst' | 'circle' | 'concentric' | 'elk' | 'grid';\nexport type GraphViewElementEventType =\n 'press' | 'double-press' | 'select' | 'unselect' | 'pointer-enter' | 'pointer-leave';\n\nexport interface GraphViewNode {\n readonly id: string;\n readonly label?: string;\n readonly parentId?: string;\n readonly classes?: string;\n readonly data?: Readonly<Record<string, unknown>>;\n}\n\nexport interface GraphViewEdge {\n readonly id?: string;\n readonly source: string;\n readonly target: string;\n readonly classes?: string;\n readonly data?: Readonly<Record<string, unknown>>;\n}\n\nexport interface GraphViewStyleRule {\n readonly selector: string;\n readonly style: Readonly<Record<string, unknown>>;\n}\n\nexport interface GraphViewPoint {\n readonly x: number;\n readonly y: number;\n}\n\nexport interface GraphViewSize {\n readonly width: number;\n readonly height: number;\n}\n\nexport interface GraphViewNodeRenderContext {\n readonly hovered: boolean;\n readonly node: GraphViewNode;\n readonly selected: boolean;\n readonly zoom: number;\n}\n\nexport interface GraphViewRenderedNode {\n readonly hovered: boolean;\n readonly id: string;\n readonly position: GraphViewPoint;\n readonly selected: boolean;\n readonly zoom: number;\n}\n\nexport interface GraphViewNodeMeasurement {\n readonly id: string;\n readonly position: GraphViewPoint;\n readonly size: GraphViewSize;\n}\n\nexport interface GraphViewMeasurement {\n readonly nodes: readonly GraphViewNodeMeasurement[];\n readonly viewport: GraphViewSize;\n}\n\nexport interface GraphViewViewport {\n readonly zoom: number;\n readonly pan: GraphViewPoint;\n}\n\nexport interface GraphViewFitOptions {\n /**\n * Optimize effective rendered fit without rerunning the layout algorithm; whole-graph fits only.\n * Stops at the configured fit-size target and keeps semantic labels collision-safe.\n */\n readonly optimizeSpacing?: boolean;\n readonly nodeIds?: readonly string[];\n readonly padding?: number;\n}\n\nexport interface GraphViewElementEvent {\n readonly id: string;\n readonly type: GraphViewElementEventType;\n}\n\nexport interface GraphViewController {\n fit(options?: GraphViewFitOptions): void;\n /** Measure rendered node geometry without exposing the backing graph engine. */\n measureNodes?(nodeIds: readonly string[]): GraphViewMeasurement | null;\n getViewport(): GraphViewViewport;\n getZoomRange(): { readonly min: number; readonly max: number };\n setPan(pan: GraphViewPoint): void;\n setZoom(zoom: number): void;\n zoomBy(factor: number): void;\n}\n\nexport interface GraphViewProps {\n readonly nodes: readonly GraphViewNode[];\n readonly edges: readonly GraphViewEdge[];\n readonly layout?: GraphViewLayoutName;\n readonly layoutOptions?: Readonly<Record<string, unknown>>;\n readonly spacingFactor?: number;\n readonly styleRules?: readonly GraphViewStyleRule[];\n readonly selectedNodeIds?: readonly string[];\n readonly renderNode?: (context: GraphViewNodeRenderContext) => React.ReactNode;\n readonly getNodeSize?: (node: GraphViewNode) => GraphViewSize | undefined;\n readonly fitPadding?: number;\n readonly minZoom?: number;\n readonly maxZoom?: number;\n readonly minReadableLabelSize?: number;\n readonly maxFitLabelSize?: number;\n /** Zoom values and bounds use the full-node fit as 1 when fit-relative is selected. */\n readonly zoomMode?: 'absolute' | 'fit-relative';\n /** Measure plain labels before layout instead of estimating width from character count. */\n readonly sizeNodesToLabels?: boolean;\n readonly className?: string;\n readonly style?: React.CSSProperties;\n readonly ariaLabel?: string;\n readonly onReady?: (controller: GraphViewController) => void;\n readonly onLayoutComplete?: (controller: GraphViewController) => void;\n readonly onNodeEvent?: (event: GraphViewElementEvent) => void;\n readonly onEdgeEvent?: (event: GraphViewElementEvent) => void;\n readonly onViewportChange?: (viewport: GraphViewViewport) => void;\n readonly onSpacingFactorChange?: (spacingFactor: number) => void;\n}\n\nexport type GraphViewCallbacks = Pick<\n GraphViewProps,\n | 'onEdgeEvent'\n | 'onLayoutComplete'\n | 'onNodeEvent'\n | 'onReady'\n | 'onViewportChange'\n | 'onSpacingFactorChange'\n>;\n"]}