@ankhorage/zora 21.0.22 → 21.0.23
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.
- package/CHANGELOG.md +9 -0
- package/README.md +36 -184
- package/dist/features/button/adapters/inbound/Button.d.ts +0 -4
- package/dist/features/button/adapters/inbound/Button.d.ts.map +1 -1
- package/dist/features/button/adapters/inbound/Button.js +0 -4
- package/dist/features/button/adapters/inbound/Button.js.map +1 -1
- package/dist/features/card/adapters/inbound/Card.d.ts +0 -4
- package/dist/features/card/adapters/inbound/Card.d.ts.map +1 -1
- package/dist/features/card/adapters/inbound/Card.js +0 -4
- package/dist/features/card/adapters/inbound/Card.js.map +1 -1
- package/dist/features/empty-state/adapters/inbound/EmptyState.d.ts +0 -4
- package/dist/features/empty-state/adapters/inbound/EmptyState.d.ts.map +1 -1
- package/dist/features/empty-state/adapters/inbound/EmptyState.js +0 -4
- package/dist/features/empty-state/adapters/inbound/EmptyState.js.map +1 -1
- package/dist/features/form/text-input/adapters/inbound/TextInput.d.ts +0 -4
- package/dist/features/form/text-input/adapters/inbound/TextInput.d.ts.map +1 -1
- package/dist/features/form/text-input/adapters/inbound/TextInput.js +0 -4
- package/dist/features/form/text-input/adapters/inbound/TextInput.js.map +1 -1
- package/dist/features/graph-view/adapters/inbound/web-artifact/GraphView.d.ts +5 -5
- package/dist/features/graph-view/adapters/inbound/web-artifact/GraphView.js +5 -5
- package/dist/features/graph-view/adapters/inbound/web-artifact/GraphView.js.map +1 -1
- package/dist/features/graph-view/adapters/inbound/web-artifact/compactGraphSpacing.d.ts +1 -1
- package/dist/features/graph-view/adapters/inbound/web-artifact/compactGraphSpacing.js +1 -1
- package/dist/features/graph-view/adapters/inbound/web-artifact/compactGraphSpacing.js.map +1 -1
- package/dist/features/graph-view/adapters/inbound/web-artifact/createGraphController.js +1 -1
- package/dist/features/graph-view/adapters/inbound/web-artifact/createGraphController.js.map +1 -1
- package/dist/features/graph-view/adapters/inbound/web-artifact/createGraphLoopSizer.d.ts +1 -1
- package/dist/features/graph-view/adapters/inbound/web-artifact/createGraphLoopSizer.js +1 -1
- package/dist/features/graph-view/adapters/inbound/web-artifact/createGraphLoopSizer.js.map +1 -1
- package/dist/features/graph-view/adapters/inbound/web-artifact/createGraphRuntime.js +7 -7
- package/dist/features/graph-view/adapters/inbound/web-artifact/createGraphRuntime.js.map +1 -1
- package/dist/features/graph-view/adapters/inbound/web-artifact/getGraphGeometryKey.d.ts +0 -1
- package/dist/features/graph-view/adapters/inbound/web-artifact/getGraphGeometryKey.d.ts.map +1 -1
- package/dist/features/graph-view/adapters/inbound/web-artifact/getGraphGeometryKey.js +0 -1
- package/dist/features/graph-view/adapters/inbound/web-artifact/getGraphGeometryKey.js.map +1 -1
- package/dist/features/graph-view/adapters/inbound/web-artifact/getGraphTopologyKey.d.ts +1 -1
- package/dist/features/graph-view/adapters/inbound/web-artifact/getGraphTopologyKey.js +1 -1
- package/dist/features/graph-view/adapters/inbound/web-artifact/getGraphTopologyKey.js.map +1 -1
- package/dist/features/graph-view/adapters/inbound/web-artifact/hasGraphLayoutChanged.d.ts +0 -1
- package/dist/features/graph-view/adapters/inbound/web-artifact/hasGraphLayoutChanged.d.ts.map +1 -1
- package/dist/features/graph-view/adapters/inbound/web-artifact/hasGraphLayoutChanged.js +0 -1
- package/dist/features/graph-view/adapters/inbound/web-artifact/hasGraphLayoutChanged.js.map +1 -1
- package/dist/features/graph-view/adapters/inbound/web-artifact/runDetachedGraphLayout.d.ts +1 -1
- package/dist/features/graph-view/adapters/inbound/web-artifact/runDetachedGraphLayout.js +1 -1
- package/dist/features/graph-view/adapters/inbound/web-artifact/runDetachedGraphLayout.js.map +1 -1
- package/dist/features/graph-view/adapters/inbound/web-artifact/sizeGraphNodesToLabels.d.ts +1 -1
- package/dist/features/graph-view/adapters/inbound/web-artifact/sizeGraphNodesToLabels.js +1 -1
- package/dist/features/graph-view/adapters/inbound/web-artifact/sizeGraphNodesToLabels.js.map +1 -1
- package/dist/features/graph-view/adapters/inbound/web-artifact/syncGraphElements.d.ts +0 -1
- package/dist/features/graph-view/adapters/inbound/web-artifact/syncGraphElements.d.ts.map +1 -1
- package/dist/features/graph-view/adapters/inbound/web-artifact/syncGraphElements.js +0 -1
- package/dist/features/graph-view/adapters/inbound/web-artifact/syncGraphElements.js.map +1 -1
- package/dist/features/tree-view/adapters/inbound/TreeView.d.ts +1 -1
- package/dist/features/tree-view/adapters/inbound/TreeView.js +1 -1
- package/dist/features/tree-view/adapters/inbound/TreeView.js.map +1 -1
- package/dist/features/tree-view/adapters/inbound/web-artifact/TreeView.d.ts +1 -1
- package/dist/features/tree-view/adapters/inbound/web-artifact/TreeView.js +1 -1
- package/dist/features/tree-view/adapters/inbound/web-artifact/TreeView.js.map +1 -1
- package/dist/features/typography/adapters/inbound/Heading.d.ts +0 -4
- package/dist/features/typography/adapters/inbound/Heading.d.ts.map +1 -1
- package/dist/features/typography/adapters/inbound/Heading.js +0 -4
- package/dist/features/typography/adapters/inbound/Heading.js.map +1 -1
- package/dist/features/typography/adapters/inbound/Text.d.ts +0 -4
- package/dist/features/typography/adapters/inbound/Text.d.ts.map +1 -1
- package/dist/features/typography/adapters/inbound/Text.js +0 -4
- package/dist/features/typography/adapters/inbound/Text.js.map +1 -1
- package/package.json +4 -7
- package/src/features/button/adapters/inbound/Button.tsx +0 -4
- package/src/features/card/adapters/inbound/Card.tsx +0 -4
- package/src/features/empty-state/adapters/inbound/EmptyState.tsx +0 -4
- package/src/features/form/text-input/adapters/inbound/TextInput.tsx +0 -4
- package/src/features/graph-view/adapters/inbound/web-artifact/GraphView.tsx +5 -5
- package/src/features/graph-view/adapters/inbound/web-artifact/compactGraphSpacing.ts +1 -1
- package/src/features/graph-view/adapters/inbound/web-artifact/createGraphController.ts +1 -1
- package/src/features/graph-view/adapters/inbound/web-artifact/createGraphLoopSizer.ts +1 -1
- package/src/features/graph-view/adapters/inbound/web-artifact/createGraphRuntime.ts +7 -7
- package/src/features/graph-view/adapters/inbound/web-artifact/getGraphGeometryKey.ts +0 -1
- package/src/features/graph-view/adapters/inbound/web-artifact/getGraphTopologyKey.ts +1 -1
- package/src/features/graph-view/adapters/inbound/web-artifact/hasGraphLayoutChanged.ts +0 -1
- package/src/features/graph-view/adapters/inbound/web-artifact/runDetachedGraphLayout.ts +1 -1
- package/src/features/graph-view/adapters/inbound/web-artifact/sizeGraphNodesToLabels.ts +1 -1
- package/src/features/graph-view/adapters/inbound/web-artifact/syncGraphElements.ts +0 -1
- package/src/features/tree-view/adapters/inbound/TreeView.tsx +1 -1
- package/src/features/tree-view/adapters/inbound/web-artifact/TreeView.tsx +1 -1
- package/src/features/typography/adapters/inbound/Heading.tsx +0 -4
- package/src/features/typography/adapters/inbound/Text.tsx +0 -4
- package/web-dist/components/graph-view/GraphView.d.ts +5 -5
- package/web-dist/components/tree-view/TreeView.d.ts +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compactGraphSpacing.js","sourceRoot":"","sources":["../../../../../../src/features/graph-view/adapters/inbound/web-artifact/compactGraphSpacing.ts"],"names":[],"mappings":"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","sourcesContent":["import { findMinimumAcceptedNumber } from '@ankhorage/utility/algorithms';\nimport type { Core, NodeSingular } from 'cytoscape';\n\nconst LABEL_OVERLAP_RATIO = 0.12;\nconst MAX_EXPANSION_ATTEMPTS = 8;\nconst MAX_NODE_COUNT = 2000;\nconst MAX_PAIR_CHECKS = 200000;\nconst SEARCH_ITERATIONS = 8;\n\n/***\n * Optimize settled layout spacing around readable label bounds instead of full node clearance.\n * Compound containment stays intentional while sibling groups retain non-overlapping boundaries.\n * @performance Cytoscape geometry is measured once, then bounded pure numeric trials reuse the\n * immutable snapshot. No layout reruns, zoom work, or intermediate frames are painted.\n */\nexport function compactGraphSpacing(cy: Core, spacingFactor: number): number {\n const leaves = cy.nodes(':childless');\n if (leaves.length < 2 || cy.nodes().length > MAX_NODE_COUNT || cy.nodes(':locked').length > 0)\n return spacingFactor;\n\n const bounds = leaves.boundingBox();\n const center = { x: (bounds.x1 + bounds.x2) / 2, y: (bounds.y1 + bounds.y2) / 2 };\n const leafGeometry = leaves.map(readLeafGeometry);\n const groups = cy.nodes(':parent').map((node) =>\n readGroupGeometry(\n node.id(),\n node.ancestors().map((parent) => parent.id()),\n node.boundingBox(),\n leafGeometry,\n ),\n );\n const accepts = (factor: number) =>\n !hasUnsafeCollisions(resolveCollisionBoxes(leafGeometry, groups, center, factor));\n const currentAccepted = accepts(1);\n const minimum = currentAccepted ? Math.min(1, 0.1 / spacingFactor) : 1;\n const maximum = currentAccepted ? 1 : findExpansionMaximum(accepts);\n if (maximum === undefined) return spacingFactor;\n\n const factor = findMinimumAcceptedNumber({\n minimum,\n maximum,\n iterations: SEARCH_ITERATIONS,\n accepts,\n });\n if (factor === undefined) return spacingFactor;\n\n applyScale(cy, leafGeometry, center, factor);\n return spacingFactor * factor;\n}\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 labelBox: Bounds;\n readonly nodeBox: Bounds;\n}\n\ninterface GroupGeometry {\n readonly id: string;\n readonly ancestors: ReadonlySet<string>;\n readonly descendants: readonly LeafGeometry[];\n readonly insets: Insets;\n}\n\ninterface CollisionBox {\n readonly id: string;\n readonly ancestors: ReadonlySet<string>;\n readonly kind: 'label' | 'group';\n readonly box: Bounds;\n}\n\n/*** Read one leaf's immutable position, hierarchy and renderer-measured label geometry. */\nfunction readLeafGeometry(node: NodeSingular): LeafGeometry {\n const nodeBox = node.boundingBox({\n includeLabels: true,\n includeOverlays: false,\n includeUnderlays: false,\n });\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 labelBox: isUsableBox(labelBox) ? labelBox : nodeBox,\n nodeBox,\n };\n}\n\n/*** Capture one compound group's descendant geometry and constant renderer-owned outer insets. */\nfunction readGroupGeometry(\n id: string,\n ancestorIds: readonly string[],\n parentBox: Bounds,\n leaves: readonly LeafGeometry[],\n): GroupGeometry {\n const descendants = leaves.filter((leaf) => leaf.ancestors.has(id));\n const descendantUnion = unionBounds(descendants.map((leaf) => leaf.nodeBox)) ?? parentBox;\n return {\n id,\n ancestors: new Set(ancestorIds),\n descendants,\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/*** Resolve immutable label and compound boxes for one candidate uniform spacing factor. */\nfunction resolveCollisionBoxes(\n leaves: readonly LeafGeometry[],\n groups: readonly GroupGeometry[],\n center: Point,\n factor: number,\n): readonly CollisionBox[] {\n const labels = leaves.map((leaf) => ({\n id: leaf.id,\n ancestors: leaf.ancestors,\n kind: 'label' as const,\n box: shiftBounds(leaf.labelBox, leaf.position, center, factor),\n }));\n const compoundBoxes = groups.flatMap((group) => {\n const descendants = group.descendants.map((leaf) =>\n shiftBounds(leaf.nodeBox, leaf.position, center, factor),\n );\n const union = unionBounds(descendants);\n if (!union) return [];\n return [\n {\n id: group.id,\n ancestors: group.ancestors,\n kind: 'group' as const,\n box: expandBounds(union, group.insets),\n },\n ];\n });\n return [...labels, ...compoundBoxes];\n}\n\n/*** Find the first bounded expansion factor that makes the pure geometry snapshot acceptable. */\nfunction findExpansionMaximum(accepts: (factor: number) => boolean): number | undefined {\n return Array.from({ length: MAX_EXPANSION_ATTEMPTS }, (_, index) => 2 ** (index + 1)).find(\n accepts,\n );\n}\n\n/***\n * Sweep resolved boxes by x extent and stop conservatively if the pair-check budget is exhausted.\n * Local loop counters are intentionally mutable on this performance-critical boundary.\n */\nfunction hasUnsafeCollisions(boxes: readonly CollisionBox[]): boolean {\n const sorted = [...boxes].sort((first, second) => first.box.x1 - second.box.x1);\n const budget = { remaining: MAX_PAIR_CHECKS };\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) break;\n if (second.box.x1 >= first.box.x2) break;\n budget.remaining -= 1;\n if (budget.remaining < 0) return true;\n if (isIntentionalContainment(first, second)) continue;\n if (isUnsafeOverlap(first, second)) return true;\n }\n }\n return false;\n}\n\n/*** Ignore intentional compound containment while retaining sibling and unrelated separation. */\nfunction isIntentionalContainment(first: CollisionBox, second: CollisionBox): boolean {\n return first.ancestors.has(second.id) || second.ancestors.has(first.id);\n}\n\n/*** Permit only a small bounded label-label overlap; every other intersection remains unsafe. */\nfunction isUnsafeOverlap(first: CollisionBox, second: CollisionBox): boolean {\n const overlapWidth =\n Math.min(first.box.x2, second.box.x2) - Math.max(first.box.x1, second.box.x1);\n const overlapHeight =\n Math.min(first.box.y2, second.box.y2) - Math.max(first.box.y1, second.box.y1);\n if (overlapWidth <= 0 || overlapHeight <= 0) return false;\n if (first.kind !== 'label' || second.kind !== 'label') return true;\n const widthRatio = overlapWidth / Math.min(first.box.w, second.box.w);\n const heightRatio = overlapHeight / Math.min(first.box.h, second.box.h);\n return widthRatio > LABEL_OVERLAP_RATIO && heightRatio > LABEL_OVERLAP_RATIO;\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 {\n x1: box.x1 + dx,\n y1: box.y1 + dy,\n x2: box.x2 + dx,\n y2: box.y2 + dy,\n w: box.w,\n h: box.h,\n };\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 label box. */\nfunction isUsableBox(box: Bounds): boolean {\n return box.w > 0 && box.h > 0;\n}\n\n/*** Apply the accepted factor once, preserving node 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"]}
|
|
1
|
+
{"version":3,"file":"compactGraphSpacing.js","sourceRoot":"","sources":["../../../../../../src/features/graph-view/adapters/inbound/web-artifact/compactGraphSpacing.ts"],"names":[],"mappings":"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","sourcesContent":["import { findMinimumAcceptedNumber } from '@ankhorage/utility/algorithms';\nimport type { Core, NodeSingular } from 'cytoscape';\n\nconst LABEL_OVERLAP_RATIO = 0.12;\nconst MAX_EXPANSION_ATTEMPTS = 8;\nconst MAX_NODE_COUNT = 2000;\nconst MAX_PAIR_CHECKS = 200000;\nconst SEARCH_ITERATIONS = 8;\n\n/***\n * Optimize settled layout spacing around readable label bounds instead of full node clearance.\n * Compound containment stays intentional while sibling groups retain non-overlapping boundaries.\n * Cytoscape geometry is measured once, then bounded pure numeric trials reuse the\n * immutable snapshot. No layout reruns, zoom work, or intermediate frames are painted.\n */\nexport function compactGraphSpacing(cy: Core, spacingFactor: number): number {\n const leaves = cy.nodes(':childless');\n if (leaves.length < 2 || cy.nodes().length > MAX_NODE_COUNT || cy.nodes(':locked').length > 0)\n return spacingFactor;\n\n const bounds = leaves.boundingBox();\n const center = { x: (bounds.x1 + bounds.x2) / 2, y: (bounds.y1 + bounds.y2) / 2 };\n const leafGeometry = leaves.map(readLeafGeometry);\n const groups = cy.nodes(':parent').map((node) =>\n readGroupGeometry(\n node.id(),\n node.ancestors().map((parent) => parent.id()),\n node.boundingBox(),\n leafGeometry,\n ),\n );\n const accepts = (factor: number) =>\n !hasUnsafeCollisions(resolveCollisionBoxes(leafGeometry, groups, center, factor));\n const currentAccepted = accepts(1);\n const minimum = currentAccepted ? Math.min(1, 0.1 / spacingFactor) : 1;\n const maximum = currentAccepted ? 1 : findExpansionMaximum(accepts);\n if (maximum === undefined) return spacingFactor;\n\n const factor = findMinimumAcceptedNumber({\n minimum,\n maximum,\n iterations: SEARCH_ITERATIONS,\n accepts,\n });\n if (factor === undefined) return spacingFactor;\n\n applyScale(cy, leafGeometry, center, factor);\n return spacingFactor * factor;\n}\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 labelBox: Bounds;\n readonly nodeBox: Bounds;\n}\n\ninterface GroupGeometry {\n readonly id: string;\n readonly ancestors: ReadonlySet<string>;\n readonly descendants: readonly LeafGeometry[];\n readonly insets: Insets;\n}\n\ninterface CollisionBox {\n readonly id: string;\n readonly ancestors: ReadonlySet<string>;\n readonly kind: 'label' | 'group';\n readonly box: Bounds;\n}\n\n/*** Read one leaf's immutable position, hierarchy and renderer-measured label geometry. */\nfunction readLeafGeometry(node: NodeSingular): LeafGeometry {\n const nodeBox = node.boundingBox({\n includeLabels: true,\n includeOverlays: false,\n includeUnderlays: false,\n });\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 labelBox: isUsableBox(labelBox) ? labelBox : nodeBox,\n nodeBox,\n };\n}\n\n/*** Capture one compound group's descendant geometry and constant renderer-owned outer insets. */\nfunction readGroupGeometry(\n id: string,\n ancestorIds: readonly string[],\n parentBox: Bounds,\n leaves: readonly LeafGeometry[],\n): GroupGeometry {\n const descendants = leaves.filter((leaf) => leaf.ancestors.has(id));\n const descendantUnion = unionBounds(descendants.map((leaf) => leaf.nodeBox)) ?? parentBox;\n return {\n id,\n ancestors: new Set(ancestorIds),\n descendants,\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/*** Resolve immutable label and compound boxes for one candidate uniform spacing factor. */\nfunction resolveCollisionBoxes(\n leaves: readonly LeafGeometry[],\n groups: readonly GroupGeometry[],\n center: Point,\n factor: number,\n): readonly CollisionBox[] {\n const labels = leaves.map((leaf) => ({\n id: leaf.id,\n ancestors: leaf.ancestors,\n kind: 'label' as const,\n box: shiftBounds(leaf.labelBox, leaf.position, center, factor),\n }));\n const compoundBoxes = groups.flatMap((group) => {\n const descendants = group.descendants.map((leaf) =>\n shiftBounds(leaf.nodeBox, leaf.position, center, factor),\n );\n const union = unionBounds(descendants);\n if (!union) return [];\n return [\n {\n id: group.id,\n ancestors: group.ancestors,\n kind: 'group' as const,\n box: expandBounds(union, group.insets),\n },\n ];\n });\n return [...labels, ...compoundBoxes];\n}\n\n/*** Find the first bounded expansion factor that makes the pure geometry snapshot acceptable. */\nfunction findExpansionMaximum(accepts: (factor: number) => boolean): number | undefined {\n return Array.from({ length: MAX_EXPANSION_ATTEMPTS }, (_, index) => 2 ** (index + 1)).find(\n accepts,\n );\n}\n\n/***\n * Sweep resolved boxes by x extent and stop conservatively if the pair-check budget is exhausted.\n * Local loop counters are intentionally mutable on this performance-critical boundary.\n */\nfunction hasUnsafeCollisions(boxes: readonly CollisionBox[]): boolean {\n const sorted = [...boxes].sort((first, second) => first.box.x1 - second.box.x1);\n const budget = { remaining: MAX_PAIR_CHECKS };\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) break;\n if (second.box.x1 >= first.box.x2) break;\n budget.remaining -= 1;\n if (budget.remaining < 0) return true;\n if (isIntentionalContainment(first, second)) continue;\n if (isUnsafeOverlap(first, second)) return true;\n }\n }\n return false;\n}\n\n/*** Ignore intentional compound containment while retaining sibling and unrelated separation. */\nfunction isIntentionalContainment(first: CollisionBox, second: CollisionBox): boolean {\n return first.ancestors.has(second.id) || second.ancestors.has(first.id);\n}\n\n/*** Permit only a small bounded label-label overlap; every other intersection remains unsafe. */\nfunction isUnsafeOverlap(first: CollisionBox, second: CollisionBox): boolean {\n const overlapWidth =\n Math.min(first.box.x2, second.box.x2) - Math.max(first.box.x1, second.box.x1);\n const overlapHeight =\n Math.min(first.box.y2, second.box.y2) - Math.max(first.box.y1, second.box.y1);\n if (overlapWidth <= 0 || overlapHeight <= 0) return false;\n if (first.kind !== 'label' || second.kind !== 'label') return true;\n const widthRatio = overlapWidth / Math.min(first.box.w, second.box.w);\n const heightRatio = overlapHeight / Math.min(first.box.h, second.box.h);\n return widthRatio > LABEL_OVERLAP_RATIO && heightRatio > LABEL_OVERLAP_RATIO;\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 {\n x1: box.x1 + dx,\n y1: box.y1 + dy,\n x2: box.x2 + dx,\n y2: box.y2 + dy,\n w: box.w,\n h: box.h,\n };\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 label box. */\nfunction isUsableBox(box: Bounds): boolean {\n return box.w > 0 && box.h > 0;\n}\n\n/*** Apply the accepted factor once, preserving node 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"]}
|
|
@@ -89,7 +89,7 @@ function positiveSize(value, fallback) {
|
|
|
89
89
|
}
|
|
90
90
|
/***
|
|
91
91
|
* Recompute the fit reference only after layout or resize, never on every pan/zoom event.
|
|
92
|
-
*
|
|
92
|
+
* Cache the geometry-derived scale in the viewport owner; labels are included, edges excluded.
|
|
93
93
|
*/
|
|
94
94
|
function getNodeFitZoom(cy, padding) {
|
|
95
95
|
if (cy.nodes().empty())
|
|
@@ -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 { GraphRuntimeUpdate } from '../../../../../types/graphViewRuntime';\nimport { fitGraphViewport } from './fitGraphViewport';\nimport type { GraphViewController, GraphViewFitOptions } from './GraphView';\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 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/*** 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 *
|
|
1
|
+
{"version":3,"file":"createGraphController.js","sourceRoot":"","sources":["../../../../../../src/features/graph-view/adapters/inbound/web-artifact/createGraphController.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAGtD,kGAAkG;AAClG,MAAM,UAAU,qBAAqB,CACnC,EAAQ,EACR,aAAkC,EAClC,WAAoD;IAEpD,MAAM,KAAK,GAAG;QACZ,KAAK,EAAE,CAAC;QACR,QAAQ,EAAE,KAAK;QACf,GAAG,EAAE,IAAI;QACT,GAAG,EAAE,CAAC;QACN,YAAY,EAAE,CAAC;QACf,OAAO,EAAE,QAAQ;QACjB,YAAY,EAAE,CAAC;QACf,OAAO,EAAE,QAAQ;KAClB,CAAC;IACF,MAAM,UAAU,GAAwB;QACtC,GAAG,CAAC,OAAO;YACT,IAAI,OAAO,EAAE,eAAe,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,MAAM,IAAI,WAAW,EAAE,CAAC;gBACxE,WAAW,CAAC,OAAO,CAAC,CAAC;gBACrB,OAAO;YACT,CAAC;YACD,gBAAgB,CACd,EAAE,EACF;gBACE,OAAO,EAAE,OAAO,EAAE,OAAO;gBACzB,OAAO,EAAE,OAAO,EAAE,OAAO,IAAI,aAAa,CAAC,OAAO;aACnD,EACD,KAAK,CAAC,OAAO,CACd,CAAC;QACJ,CAAC;QACD,WAAW;YACT,OAAO,EAAE,GAAG,EAAE,EAAE,CAAC,GAAG,EAAE,EAAE,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE,GAAG,KAAK,CAAC,KAAK,EAAE,CAAC;QAC1D,CAAC;QACD,YAAY;YACV,OAAO,EAAE,GAAG,EAAE,EAAE,CAAC,OAAO,EAAE,GAAG,KAAK,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE,CAAC,OAAO,EAAE,GAAG,KAAK,CAAC,KAAK,EAAE,CAAC;QAC9E,CAAC;QACD,MAAM,CAAC,GAAG;YACR,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACd,CAAC;QACD,OAAO,CAAC,IAAI;YACV,eAAe,CAAC,EAAE,EAAE,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC;QAC1C,CAAC;QACD,MAAM,CAAC,MAAM;YACX,eAAe,CAAC,EAAE,EAAE,EAAE,CAAC,IAAI,EAAE,GAAG,MAAM,CAAC,CAAC;QAC1C,CAAC;KACF,CAAC;IAEF,OAAO;QACL,UAAU;QACV,SAAS,CAAC,KAAyB;YACjC,KAAK,CAAC,QAAQ,GAAG,KAAK,CAAC,QAAQ,KAAK,cAAc,CAAC;YACnD,KAAK,CAAC,GAAG,GAAG,KAAK,CAAC,OAAO,IAAI,IAAI,CAAC;YAClC,KAAK,CAAC,GAAG,GAAG,KAAK,CAAC,OAAO,IAAI,CAAC,CAAC;YAC/B,KAAK,CAAC,YAAY,GAAG,YAAY,CAAC,KAAK,CAAC,oBAAoB,EAAE,CAAC,CAAC,CAAC;YACjE,KAAK,CAAC,OAAO,GAAG,YAAY,CAAC,KAAK,CAAC,eAAe,EAAE,QAAQ,CAAC,CAAC;YAC9D,IAAI,CAAC,KAAK,CAAC,QAAQ;gBAAE,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC;YACrC,eAAe,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;QAC7B,CAAC;QACD,MAAM,CAAC,GAAY;YACjB,MAAM,WAAW,GAAG,EAAE,CAAC,IAAI,EAAE,GAAG,KAAK,CAAC,KAAK,CAAC;YAC5C,MAAM,KAAK,GAAG,EAAE;iBACb,KAAK,EAAE;iBACP,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;iBAClE,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,MAAM,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;iBACjE,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,IAAI,GAAG,CAAC,CAAC,CAAC;YACvD,KAAK,CAAC,YAAY,GAAG,KAAK,CAAC,MAAM;gBAC/B,CAAC,CAAC,KAAK,CAAC,YAAY,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,IAAI,CAAC,EAAE,QAAQ,CAAC;gBACzF,CAAC,CAAC,CAAC,CAAC;YACN,KAAK,CAAC,OAAO,GAAG,KAAK,CAAC,MAAM;gBAC1B,CAAC,CAAC,KAAK,CAAC,OAAO,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC;gBAC7E,CAAC,CAAC,QAAQ,CAAC;YACb,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC,QAAQ;gBAC1B,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,cAAc,CAAC,EAAE,EAAE,aAAa,CAAC,OAAO,CAAC,EAAE,KAAK,CAAC,OAAO,CAAC;gBACpE,CAAC,CAAC,CAAC,CAAC;YACN,eAAe,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;YAC3B,IAAI,GAAG;gBAAE,UAAU,CAAC,GAAG,EAAE,CAAC;iBACrB,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC;gBACxB,eAAe,CAAC,EAAE,EAAE,WAAW,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC;gBAC/C,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,CAAC;YACxB,CAAC;QACH,CAAC;KACF,CAAC;AACJ,CAAC;AAED,mGAAmG;AACnG,SAAS,eAAe,CACtB,EAAQ,EACR,KAKC;IAED,MAAM,GAAG,GAAG,KAAK,CAAC,GAAG,GAAG,KAAK,CAAC,KAAK,CAAC;IACpC,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,GAAG,CAAC,CAAC,CAAC;IACxC,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,GAAG,GAAG,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,YAAY,CAAC,CAAC,CAAC;IACvE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;AAClB,CAAC;AAED,wFAAwF;AACxF,SAAS,YAAY,CAAC,KAAyB,EAAE,QAAgB;IAC/D,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;;;GAGG;AACH,SAAS,cAAc,CAAC,EAAQ,EAAE,OAAe;IAC/C,IAAI,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,EAAE;QAAE,OAAO,CAAC,CAAC;IACjC,MAAM,MAAM,GAAG,EAAE,CAAC,KAAK,EAAE,CAAC,WAAW,EAAE,CAAC;IACxC,MAAM,KAAK,GAAG,EAAE,CAAC,KAAK,EAAE,GAAG,CAAC,GAAG,OAAO,CAAC;IACvC,MAAM,MAAM,GAAG,EAAE,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,OAAO,CAAC;IACzC,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,+EAA+E;AAC/E,SAAS,eAAe,CAAC,EAAQ,EAAE,IAAY;IAC7C,EAAE,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,gBAAgB,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,KAAK,EAAE,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC;AACxF,CAAC","sourcesContent":["import type { Core } from 'cytoscape';\n\nimport type { GraphRuntimeUpdate } from '../../../../../types/graphViewRuntime';\nimport { fitGraphViewport } from './fitGraphViewport';\nimport type { GraphViewController, GraphViewFitOptions } from './GraphView';\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 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/*** 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,7 +1,7 @@
|
|
|
1
1
|
import type { Core } from 'cytoscape';
|
|
2
2
|
/***
|
|
3
3
|
* Keeps self-loop control points outside the rendered node, independent of label size and direction.
|
|
4
|
-
*
|
|
4
|
+
* Reconcile loop geometry only after size/style/layout changes, never on pan or zoom.
|
|
5
5
|
* Preserve valid dependencies and configured larger loops; do not hide edges or silence warnings.
|
|
6
6
|
*/
|
|
7
7
|
export declare function createGraphLoopSizer(cy: Core): {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/***
|
|
2
2
|
* Keeps self-loop control points outside the rendered node, independent of label size and direction.
|
|
3
|
-
*
|
|
3
|
+
* Reconcile loop geometry only after size/style/layout changes, never on pan or zoom.
|
|
4
4
|
* Preserve valid dependencies and configured larger loops; do not hide edges or silence warnings.
|
|
5
5
|
*/
|
|
6
6
|
export function createGraphLoopSizer(cy) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createGraphLoopSizer.js","sourceRoot":"","sources":["../../../../../../src/features/graph-view/adapters/inbound/web-artifact/createGraphLoopSizer.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Core } from 'cytoscape';\n\n/***\n * Keeps self-loop control points outside the rendered node, independent of label size and direction.\n *
|
|
1
|
+
{"version":3,"file":"createGraphLoopSizer.js","sourceRoot":"","sources":["../../../../../../src/features/graph-view/adapters/inbound/web-artifact/createGraphLoopSizer.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Core } from 'cytoscape';\n\n/***\n * Keeps self-loop control points outside the rendered node, independent of label size and direction.\n * Reconcile loop geometry only after size/style/layout changes, never on pan or zoom.\n * Preserve valid dependencies and configured larger loops; do not hide edges or silence warnings.\n */\nexport function createGraphLoopSizer(cy: Core) {\n const configured = new Map<string, { step: number; distance: number }>();\n\n /*** Releases only this owner's overrides before a new stylesheet is applied. */\n function reset() {\n for (const id of configured.keys()) {\n cy.getElementById(id).removeStyle('control-point-step-size control-point-distances');\n }\n configured.clear();\n }\n\n /*** Reconciles loop clearances, including compound bounds after layout completion. */\n function update() {\n const loops = cy.edges(':loop');\n const active = new Set(loops.map((edge) => edge.id()));\n for (const id of configured.keys()) {\n if (active.has(id)) continue;\n cy.getElementById(id).removeStyle('control-point-step-size control-point-distances');\n configured.delete(id);\n }\n cy.batch(() => {\n loops.forEach((edge) => {\n const node = edge.source();\n const original = configured.get(edge.id()) ?? {\n step: Number.parseFloat(String(edge.style('control-point-step-size'))) || 40,\n distance: Number.parseFloat(String(edge.style('control-point-distances'))) || 40,\n };\n configured.set(edge.id(), original);\n const clearance = Math.max(\n 16,\n edge.width() * Number.parseFloat(String(edge.style('arrow-scale'))) * 2,\n );\n const minimum = (Math.hypot(node.outerWidth(), node.outerHeight()) / 2 + clearance) / 1.4;\n const step = Math.max(original.step, minimum);\n const distance = Math.max(original.distance, minimum);\n if (Number.parseFloat(String(edge.style('control-point-step-size'))) !== step)\n edge.style('control-point-step-size', step);\n if (Number.parseFloat(String(edge.style('control-point-distances'))) !== distance)\n edge.style('control-point-distances', distance);\n });\n });\n }\n\n return { reset, update };\n}\n"]}
|
|
@@ -87,7 +87,7 @@ function createRuntimeState(cy, container, callbacksRef) {
|
|
|
87
87
|
}
|
|
88
88
|
/***
|
|
89
89
|
* Reconcile presentation in place and relayout only when graph geometry or layout policy changes.
|
|
90
|
-
*
|
|
90
|
+
* Batch reconciliation and skip layout for presentation-only updates.
|
|
91
91
|
*/
|
|
92
92
|
function updateRuntime(state, input) {
|
|
93
93
|
if (state.cy.destroyed())
|
|
@@ -151,7 +151,7 @@ function startCurrentLayout(state, input) {
|
|
|
151
151
|
}
|
|
152
152
|
/***
|
|
153
153
|
* Settle only the latest layout generation and fit once from node bounds.
|
|
154
|
-
*
|
|
154
|
+
* Discard stale completions and avoid repeated automatic fits.
|
|
155
155
|
*/
|
|
156
156
|
function completeCurrentLayout(state, generation) {
|
|
157
157
|
scheduleGraphFrame(() => {
|
|
@@ -188,7 +188,7 @@ function completeCurrentLayout(state, generation) {
|
|
|
188
188
|
}
|
|
189
189
|
/***
|
|
190
190
|
* Handle explicit readable-fit intent in the runtime owner, never from zoom or React effects.
|
|
191
|
-
*
|
|
191
|
+
* Bounded spacing optimization preserves the settled algorithm instead of repeatedly running it.
|
|
192
192
|
*/
|
|
193
193
|
function requestOptimizedFit(state, options) {
|
|
194
194
|
if (state.cy.destroyed())
|
|
@@ -238,7 +238,7 @@ function applyGraphStyles(cy, rules, richNodeRendering) {
|
|
|
238
238
|
}
|
|
239
239
|
/***
|
|
240
240
|
* Synchronize controlled selection without rerunning layout.
|
|
241
|
-
*
|
|
241
|
+
* Selection updates must not trigger graph reconstruction or layout.
|
|
242
242
|
*/
|
|
243
243
|
function setSelectedNodeIds(state, nodeIds) {
|
|
244
244
|
if (state.cy.destroyed() || nodeIds === undefined)
|
|
@@ -254,7 +254,7 @@ function setSelectedNodeIds(state, nodeIds) {
|
|
|
254
254
|
}
|
|
255
255
|
/***
|
|
256
256
|
* Persist one rich-node size and schedule at most one relayout for changed geometry.
|
|
257
|
-
*
|
|
257
|
+
* Ignore unchanged measurements before scheduling layout work.
|
|
258
258
|
*/
|
|
259
259
|
function setNodeSize(state, id, size) {
|
|
260
260
|
const previous = state.nodeSizes.get(id);
|
|
@@ -278,7 +278,7 @@ function applyNodeSize(cy, id, size) {
|
|
|
278
278
|
}
|
|
279
279
|
/***
|
|
280
280
|
* Coalesce DOM measurements into one follow-up layout generation.
|
|
281
|
-
*
|
|
281
|
+
* Keep one scheduled layout per frame instead of one per measured node.
|
|
282
282
|
*/
|
|
283
283
|
function scheduleMeasuredNodeRelayout(state) {
|
|
284
284
|
if (state.relayoutScheduledRef.current)
|
|
@@ -303,7 +303,7 @@ function subscribeRenderedNodes(state, listener) {
|
|
|
303
303
|
}
|
|
304
304
|
/***
|
|
305
305
|
* Publish current rendered node positions only to active rich-node subscribers.
|
|
306
|
-
*
|
|
306
|
+
* Skip snapshot preparation when no overlay is subscribed.
|
|
307
307
|
*/
|
|
308
308
|
function emitRenderedNodes(state) {
|
|
309
309
|
if (state.renderedNodeListeners.size === 0)
|
|
@@ -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 { 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 type {\n GraphViewCallbacks,\n GraphViewElementEventType,\n GraphViewFitOptions,\n GraphViewRenderedNode,\n GraphViewSize,\n GraphViewStyleRule,\n} from './GraphView';\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 * @performance 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 * @performance 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 * @performance 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 * @performance 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 * @performance 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 * @performance 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 * @performance 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 { 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 type {\n GraphViewCallbacks,\n GraphViewElementEventType,\n GraphViewFitOptions,\n GraphViewRenderedNode,\n GraphViewSize,\n GraphViewStyleRule,\n} from './GraphView';\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,7 +1,6 @@
|
|
|
1
1
|
import type { Core } from 'cytoscape';
|
|
2
2
|
/***
|
|
3
3
|
* Identifies layout-relevant leaf dimensions without including positions or presentation colors.
|
|
4
|
-
* @performance
|
|
5
4
|
* Adding viewport, color or arbitrary data to this key turns interaction updates into relayouts.
|
|
6
5
|
* Measure after style reconciliation; actual size changes still require layout. Compound bounds
|
|
7
6
|
* follow child positions, so keying their measured bounds would feed layout output back into input.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getGraphGeometryKey.d.ts","sourceRoot":"","sources":["../../../../../../src/features/graph-view/adapters/inbound/web-artifact/getGraphGeometryKey.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEtC
|
|
1
|
+
{"version":3,"file":"getGraphGeometryKey.d.ts","sourceRoot":"","sources":["../../../../../../src/features/graph-view/adapters/inbound/web-artifact/getGraphGeometryKey.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEtC;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,EAAE,EAAE,IAAI,GAAG,MAAM,CAQpD"}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
/***
|
|
2
2
|
* Identifies layout-relevant leaf dimensions without including positions or presentation colors.
|
|
3
|
-
* @performance
|
|
4
3
|
* Adding viewport, color or arbitrary data to this key turns interaction updates into relayouts.
|
|
5
4
|
* Measure after style reconciliation; actual size changes still require layout. Compound bounds
|
|
6
5
|
* follow child positions, so keying their measured bounds would feed layout output back into input.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getGraphGeometryKey.js","sourceRoot":"","sources":["../../../../../../src/features/graph-view/adapters/inbound/web-artifact/getGraphGeometryKey.ts"],"names":[],"mappings":"AAEA
|
|
1
|
+
{"version":3,"file":"getGraphGeometryKey.js","sourceRoot":"","sources":["../../../../../../src/features/graph-view/adapters/inbound/web-artifact/getGraphGeometryKey.ts"],"names":[],"mappings":"AAEA;;;;;;GAMG;AACH,MAAM,UAAU,mBAAmB,CAAC,EAAQ;IAC1C,OAAO,IAAI,CAAC,SAAS,CACnB,EAAE,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;QACtB,IAAI,IAAI,CAAC,QAAQ,EAAE;YAAE,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC;QACxC,MAAM,UAAU,GAAG,IAAI,CAAC,gBAAgB,CAAC,EAAE,2BAA2B,EAAE,IAAI,EAAE,CAAC,CAAC;QAChF,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,UAAU,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC;IACjD,CAAC,CAAC,CACH,CAAC;AACJ,CAAC","sourcesContent":["import type { Core } from 'cytoscape';\n\n/***\n * Identifies layout-relevant leaf dimensions without including positions or presentation colors.\n * Adding viewport, color or arbitrary data to this key turns interaction updates into relayouts.\n * Measure after style reconciliation; actual size changes still require layout. Compound bounds\n * follow child positions, so keying their measured bounds would feed layout output back into input.\n * Styled geometry tests and runtime interaction tests protect these distinctions.\n */\nexport function getGraphGeometryKey(cy: Core): string {\n return JSON.stringify(\n cy.nodes().map((node) => {\n if (node.isParent()) return [node.id()];\n const dimensions = node.layoutDimensions({ nodeDimensionsIncludeLabels: true });\n return [node.id(), dimensions.w, dimensions.h];\n }),\n );\n}\n"]}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { GraphViewEdge, GraphViewNode } from './GraphView';
|
|
2
2
|
/***
|
|
3
3
|
* Identify visible graph membership and hierarchy independently of presentation metadata.
|
|
4
|
-
*
|
|
4
|
+
* Keep presentation-only changes out of the relayout decision.
|
|
5
5
|
*/
|
|
6
6
|
export declare function getGraphTopologyKey(nodes: readonly GraphViewNode[], edges: readonly GraphViewEdge[]): string;
|
|
7
7
|
//# sourceMappingURL=getGraphTopologyKey.d.ts.map
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/***
|
|
2
2
|
* Identify visible graph membership and hierarchy independently of presentation metadata.
|
|
3
|
-
*
|
|
3
|
+
* Keep presentation-only changes out of the relayout decision.
|
|
4
4
|
*/
|
|
5
5
|
export function getGraphTopologyKey(nodes, edges) {
|
|
6
6
|
return JSON.stringify([
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getGraphTopologyKey.js","sourceRoot":"","sources":["../../../../../../src/features/graph-view/adapters/inbound/web-artifact/getGraphTopologyKey.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,MAAM,UAAU,mBAAmB,CACjC,KAA+B,EAC/B,KAA+B;IAE/B,OAAO,IAAI,CAAC,SAAS,CAAC;QACpB,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,EAAE,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE;QAC5D,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,IAAI,IAAI,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,EAAE;KACxE,CAAC,CAAC;AACL,CAAC","sourcesContent":["import type { GraphViewEdge, GraphViewNode } from './GraphView';\n\n/***\n * Identify visible graph membership and hierarchy independently of presentation metadata.\n *
|
|
1
|
+
{"version":3,"file":"getGraphTopologyKey.js","sourceRoot":"","sources":["../../../../../../src/features/graph-view/adapters/inbound/web-artifact/getGraphTopologyKey.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,MAAM,UAAU,mBAAmB,CACjC,KAA+B,EAC/B,KAA+B;IAE/B,OAAO,IAAI,CAAC,SAAS,CAAC;QACpB,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,EAAE,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE;QAC5D,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,IAAI,IAAI,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,EAAE;KACxE,CAAC,CAAC;AACL,CAAC","sourcesContent":["import type { GraphViewEdge, GraphViewNode } from './GraphView';\n\n/***\n * Identify visible graph membership and hierarchy independently of presentation metadata.\n * Keep presentation-only changes out of the relayout decision.\n */\nexport function getGraphTopologyKey(\n nodes: readonly GraphViewNode[],\n edges: readonly GraphViewEdge[],\n): string {\n return JSON.stringify([\n nodes.map((node) => [node.id, node.parentId ?? null]).sort(),\n edges.map((edge) => [edge.id ?? null, edge.source, edge.target]).sort(),\n ]);\n}\n"]}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import type { GraphRuntimeUpdate } from '../../../../../types/graphViewRuntime';
|
|
2
2
|
/***
|
|
3
3
|
* Detects topology and explicit layout-policy changes independently of highlight metadata.
|
|
4
|
-
* @performance
|
|
5
4
|
* New node/edge array identities alone are not a layout request: consumers may update classes
|
|
6
5
|
* and colors on hover or selection. Keep structural identity separate from presentation and
|
|
7
6
|
* combine this decision with measured geometry in the single runtime owner, not consumer effects.
|
package/dist/features/graph-view/adapters/inbound/web-artifact/hasGraphLayoutChanged.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hasGraphLayoutChanged.d.ts","sourceRoot":"","sources":["../../../../../../src/features/graph-view/adapters/inbound/web-artifact/hasGraphLayoutChanged.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uCAAuC,CAAC;AAGhF
|
|
1
|
+
{"version":3,"file":"hasGraphLayoutChanged.d.ts","sourceRoot":"","sources":["../../../../../../src/features/graph-view/adapters/inbound/web-artifact/hasGraphLayoutChanged.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uCAAuC,CAAC;AAGhF;;;;;GAKG;AACH,wBAAgB,qBAAqB,CACnC,QAAQ,EAAE,kBAAkB,GAAG,IAAI,EACnC,KAAK,EAAE,kBAAkB,GACxB,OAAO,CAUT"}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { getGraphTopologyKey } from './getGraphTopologyKey';
|
|
2
2
|
/***
|
|
3
3
|
* Detects topology and explicit layout-policy changes independently of highlight metadata.
|
|
4
|
-
* @performance
|
|
5
4
|
* New node/edge array identities alone are not a layout request: consumers may update classes
|
|
6
5
|
* and colors on hover or selection. Keep structural identity separate from presentation and
|
|
7
6
|
* combine this decision with measured geometry in the single runtime owner, not consumer effects.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hasGraphLayoutChanged.js","sourceRoot":"","sources":["../../../../../../src/features/graph-view/adapters/inbound/web-artifact/hasGraphLayoutChanged.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAE5D
|
|
1
|
+
{"version":3,"file":"hasGraphLayoutChanged.js","sourceRoot":"","sources":["../../../../../../src/features/graph-view/adapters/inbound/web-artifact/hasGraphLayoutChanged.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAE5D;;;;;GAKG;AACH,MAAM,UAAU,qBAAqB,CACnC,QAAmC,EACnC,KAAyB;IAEzB,OAAO,CACL,QAAQ,KAAK,IAAI;QACjB,QAAQ,CAAC,MAAM,KAAK,KAAK,CAAC,MAAM;QAChC,QAAQ,CAAC,aAAa,KAAK,KAAK,CAAC,aAAa;QAC9C,QAAQ,CAAC,aAAa,KAAK,KAAK,CAAC,aAAa;QAC9C,QAAQ,CAAC,iBAAiB,KAAK,KAAK,CAAC,iBAAiB;QACtD,mBAAmB,CAAC,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC,KAAK,CAAC;YACjD,mBAAmB,CAAC,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,CAChD,CAAC;AACJ,CAAC","sourcesContent":["import type { GraphRuntimeUpdate } from '../../../../../types/graphViewRuntime';\nimport { getGraphTopologyKey } from './getGraphTopologyKey';\n\n/***\n * Detects topology and explicit layout-policy changes independently of highlight metadata.\n * New node/edge array identities alone are not a layout request: consumers may update classes\n * and colors on hover or selection. Keep structural identity separate from presentation and\n * combine this decision with measured geometry in the single runtime owner, not consumer effects.\n */\nexport function hasGraphLayoutChanged(\n previous: GraphRuntimeUpdate | null,\n input: GraphRuntimeUpdate,\n): boolean {\n return (\n previous === null ||\n previous.layout !== input.layout ||\n previous.spacingFactor !== input.spacingFactor ||\n previous.layoutOptions !== input.layoutOptions ||\n previous.richNodeRendering !== input.richNodeRendering ||\n getGraphTopologyKey(previous.nodes, previous.edges) !==\n getGraphTopologyKey(input.nodes, input.edges)\n );\n}\n"]}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { type Core, type LayoutOptions } from 'cytoscape';
|
|
2
2
|
/***
|
|
3
3
|
* Isolate an uncancellable layout from the displayed core and discard stopped generations.
|
|
4
|
-
*
|
|
4
|
+
* Apply current positions in one batch without rebuilding the displayed graph.
|
|
5
5
|
* A stopped ELK computation still runs to completion; this guard does not cancel its CPU work.
|
|
6
6
|
*/
|
|
7
7
|
export declare function runDetachedGraphLayout(cy: Core, options: LayoutOptions, onComplete: () => void): {
|
|
@@ -2,7 +2,7 @@ import { isRecord } from '@ankhorage/utility/object';
|
|
|
2
2
|
import cytoscape, {} from 'cytoscape';
|
|
3
3
|
/***
|
|
4
4
|
* Isolate an uncancellable layout from the displayed core and discard stopped generations.
|
|
5
|
-
*
|
|
5
|
+
* Apply current positions in one batch without rebuilding the displayed graph.
|
|
6
6
|
* A stopped ELK computation still runs to completion; this guard does not cancel its CPU work.
|
|
7
7
|
*/
|
|
8
8
|
export function runDetachedGraphLayout(cy, options, onComplete) {
|
package/dist/features/graph-view/adapters/inbound/web-artifact/runDetachedGraphLayout.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runDetachedGraphLayout.js","sourceRoot":"","sources":["../../../../../../src/features/graph-view/adapters/inbound/web-artifact/runDetachedGraphLayout.ts"],"names":[],"mappings":"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","sourcesContent":["import { isRecord } from '@ankhorage/utility/object';\nimport cytoscape, { type Core, type LayoutOptions } from 'cytoscape';\n\n/***\n * Isolate an uncancellable layout from the displayed core and discard stopped generations.\n *
|
|
1
|
+
{"version":3,"file":"runDetachedGraphLayout.js","sourceRoot":"","sources":["../../../../../../src/features/graph-view/adapters/inbound/web-artifact/runDetachedGraphLayout.ts"],"names":[],"mappings":"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","sourcesContent":["import { isRecord } from '@ankhorage/utility/object';\nimport cytoscape, { type Core, type LayoutOptions } from 'cytoscape';\n\n/***\n * Isolate an uncancellable layout from the displayed core and discard stopped generations.\n * Apply current positions in one batch without rebuilding the displayed graph.\n * A stopped ELK computation still runs to completion; this guard does not cancel its CPU work.\n */\nexport function runDetachedGraphLayout(cy: Core, options: LayoutOptions, onComplete: () => void) {\n const graph = createLayoutSnapshot(cy);\n const state = { stopped: false };\n const elkOptions: unknown = 'elk' in options ? options.elk : undefined;\n const layoutOptions = {\n ...options,\n fit: false,\n animate: false,\n elk: {\n aspectRatio: cy.width() / Math.max(cy.height(), 1),\n ...(isRecord(elkOptions) ? elkOptions : {}),\n },\n };\n const layout = graph.layout(layoutOptions);\n layout.one('layoutstop', () => {\n try {\n if (state.stopped || cy.destroyed()) return;\n cy.batch(() => {\n cy.nodes()\n .not(':parent')\n .positions((node) => graph.getElementById(node.id()).position());\n });\n onComplete();\n } finally {\n graph.destroy();\n }\n });\n layout.run();\n\n return {\n stop() {\n // ELK's stop() is a no-op. Keep its isolated core alive until it settles.\n state.stopped = true;\n },\n };\n}\n\n/*** Capture graph data and measured node sizes without retaining the browser renderer. */\nfunction createLayoutSnapshot(cy: Core): Core {\n const graph = cytoscape({\n headless: true,\n styleEnabled: true,\n elements: cy.elements().map((element) => {\n const data: unknown = element.data();\n return { data: isRecord(data) ? { ...data } : {}, classes: element.classes() };\n }),\n style: [{ selector: 'node', style: { label: '', padding: '0px', 'border-width': 0 } }],\n });\n graph.batch(() => {\n cy.nodes().forEach((node) => {\n if (node.isParent()) {\n const padding: unknown = node.style('padding');\n if (typeof padding === 'string') graph.getElementById(node.id()).style({ padding });\n return;\n }\n const dimensions = node.layoutDimensions({ nodeDimensionsIncludeLabels: true });\n graph.getElementById(node.id()).style({ width: dimensions.w, height: dimensions.h });\n });\n });\n return graph;\n}\n"]}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { Core } from 'cytoscape';
|
|
2
2
|
/***
|
|
3
3
|
* Size plain leaf nodes from the renderer's styled label bounds, keeping padding in the stylesheet.
|
|
4
|
-
*
|
|
4
|
+
* Reuse Cytoscape's cached text measurements during reconciliation, never a per-element
|
|
5
5
|
* style callback or a pan/zoom listener. Only write changed dimensions; bold and Unicode labels must
|
|
6
6
|
* not regress to character-count estimates. Compound dimensions remain owned by child bounds.
|
|
7
7
|
*/
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/***
|
|
2
2
|
* Size plain leaf nodes from the renderer's styled label bounds, keeping padding in the stylesheet.
|
|
3
|
-
*
|
|
3
|
+
* Reuse Cytoscape's cached text measurements during reconciliation, never a per-element
|
|
4
4
|
* style callback or a pan/zoom listener. Only write changed dimensions; bold and Unicode labels must
|
|
5
5
|
* not regress to character-count estimates. Compound dimensions remain owned by child bounds.
|
|
6
6
|
*/
|
package/dist/features/graph-view/adapters/inbound/web-artifact/sizeGraphNodesToLabels.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sizeGraphNodesToLabels.js","sourceRoot":"","sources":["../../../../../../src/features/graph-view/adapters/inbound/web-artifact/sizeGraphNodesToLabels.ts"],"names":[],"mappings":"AAEA;;;;;GAKG;AACH,MAAM,UAAU,sBAAsB,CAAC,EAAQ,EAAE,YAAyB,EAAE,OAAgB;IAC1F,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,KAAK,MAAM,EAAE,IAAI,YAAY;YAAE,EAAE,CAAC,cAAc,CAAC,EAAE,CAAC,CAAC,WAAW,CAAC,cAAc,CAAC,CAAC;QACjF,YAAY,CAAC,KAAK,EAAE,CAAC;QACrB,OAAO;IACT,CAAC;IACD,MAAM,UAAU,GAAG,IAAI,GAAG,EAAU,CAAC;IACrC,EAAE,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE;QACtC,MAAM,MAAM,GAAG,IAAI,CAAC,WAAW,CAAC;YAC9B,YAAY,EAAE,KAAK;YACnB,YAAY,EAAE,KAAK;YACnB,aAAa,EAAE,IAAI;YACnB,eAAe,EAAE,KAAK;YACtB,gBAAgB,EAAE,KAAK;SACxB,CAAC,CAAC;QACH,IAAI,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,MAAM,CAAC,CAAC,IAAI,CAAC;YAAE,OAAO;QAC3C,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QAClC,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QACnC,IAAI,IAAI,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,IAAI,CAAC,MAAM,EAAE,KAAK,MAAM;YAAE,IAAI,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;QACtF,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC;IAC5B,CAAC,CAAC,CAAC;IACH,KAAK,MAAM,EAAE,IAAI,YAAY,EAAE,CAAC;QAC9B,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC;YACxB,EAAE,CAAC,cAAc,CAAC,EAAE,CAAC,CAAC,WAAW,CAAC,cAAc,CAAC,CAAC;YAClD,YAAY,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QAC1B,CAAC;IACH,CAAC;IACD,KAAK,MAAM,EAAE,IAAI,UAAU;QAAE,YAAY,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;AACpD,CAAC","sourcesContent":["import type { Core } from 'cytoscape';\n\n/***\n * Size plain leaf nodes from the renderer's styled label bounds, keeping padding in the stylesheet.\n *
|
|
1
|
+
{"version":3,"file":"sizeGraphNodesToLabels.js","sourceRoot":"","sources":["../../../../../../src/features/graph-view/adapters/inbound/web-artifact/sizeGraphNodesToLabels.ts"],"names":[],"mappings":"AAEA;;;;;GAKG;AACH,MAAM,UAAU,sBAAsB,CAAC,EAAQ,EAAE,YAAyB,EAAE,OAAgB;IAC1F,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,KAAK,MAAM,EAAE,IAAI,YAAY;YAAE,EAAE,CAAC,cAAc,CAAC,EAAE,CAAC,CAAC,WAAW,CAAC,cAAc,CAAC,CAAC;QACjF,YAAY,CAAC,KAAK,EAAE,CAAC;QACrB,OAAO;IACT,CAAC;IACD,MAAM,UAAU,GAAG,IAAI,GAAG,EAAU,CAAC;IACrC,EAAE,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE;QACtC,MAAM,MAAM,GAAG,IAAI,CAAC,WAAW,CAAC;YAC9B,YAAY,EAAE,KAAK;YACnB,YAAY,EAAE,KAAK;YACnB,aAAa,EAAE,IAAI;YACnB,eAAe,EAAE,KAAK;YACtB,gBAAgB,EAAE,KAAK;SACxB,CAAC,CAAC;QACH,IAAI,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,MAAM,CAAC,CAAC,IAAI,CAAC;YAAE,OAAO;QAC3C,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QAClC,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QACnC,IAAI,IAAI,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,IAAI,CAAC,MAAM,EAAE,KAAK,MAAM;YAAE,IAAI,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;QACtF,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC;IAC5B,CAAC,CAAC,CAAC;IACH,KAAK,MAAM,EAAE,IAAI,YAAY,EAAE,CAAC;QAC9B,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC;YACxB,EAAE,CAAC,cAAc,CAAC,EAAE,CAAC,CAAC,WAAW,CAAC,cAAc,CAAC,CAAC;YAClD,YAAY,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QAC1B,CAAC;IACH,CAAC;IACD,KAAK,MAAM,EAAE,IAAI,UAAU;QAAE,YAAY,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;AACpD,CAAC","sourcesContent":["import type { Core } from 'cytoscape';\n\n/***\n * Size plain leaf nodes from the renderer's styled label bounds, keeping padding in the stylesheet.\n * Reuse Cytoscape's cached text measurements during reconciliation, never a per-element\n * style callback or a pan/zoom listener. Only write changed dimensions; bold and Unicode labels must\n * not regress to character-count estimates. Compound dimensions remain owned by child bounds.\n */\nexport function sizeGraphNodesToLabels(cy: Core, sizedNodeIds: Set<string>, enabled: boolean) {\n if (!enabled) {\n for (const id of sizedNodeIds) cy.getElementById(id).removeStyle('width height');\n sizedNodeIds.clear();\n return;\n }\n const visibleIds = new Set<string>();\n cy.nodes(':childless').forEach((node) => {\n const bounds = node.boundingBox({\n includeNodes: false,\n includeEdges: false,\n includeLabels: true,\n includeOverlays: false,\n includeUnderlays: false,\n });\n if (bounds.w <= 0 || bounds.h <= 0) return;\n const width = Math.ceil(bounds.w);\n const height = Math.ceil(bounds.h);\n if (node.width() !== width || node.height() !== height) node.style({ width, height });\n visibleIds.add(node.id());\n });\n for (const id of sizedNodeIds) {\n if (!visibleIds.has(id)) {\n cy.getElementById(id).removeStyle('width height');\n sizedNodeIds.delete(id);\n }\n }\n for (const id of visibleIds) sizedNodeIds.add(id);\n}\n"]}
|
|
@@ -2,7 +2,6 @@ import type { Core } from 'cytoscape';
|
|
|
2
2
|
import type { GraphViewEdge, GraphViewNode } from './GraphView';
|
|
3
3
|
/***
|
|
4
4
|
* Reconciles graph data in one batch while retaining positions, selection and element identity.
|
|
5
|
-
* @performance
|
|
6
5
|
* Do not replace this with remove-all/add-all: presentation updates must not discard interaction
|
|
7
6
|
* state or force the runtime to rebuild the graph. Use direct ID lookups for obsolete metadata;
|
|
8
7
|
* per-element selector scans would add avoidable work. Runtime tests cover hover/selection updates.
|