@aiready/components 0.13.12 → 0.13.13
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/dist/charts/ForceDirectedGraph.js +19 -22
- package/dist/charts/ForceDirectedGraph.js.map +1 -1
- package/dist/hooks/useForceSimulation.d.ts +1 -0
- package/dist/hooks/useForceSimulation.js +20 -19
- package/dist/hooks/useForceSimulation.js.map +1 -1
- package/dist/index.d.ts +20 -20
- package/dist/index.js +187 -279
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/src/charts/ForceDirectedGraph.tsx +30 -22
- package/src/components/icons/IconBase.tsx +31 -0
- package/src/components/icons/index.tsx +99 -164
- package/src/hooks/simulation-helpers.ts +31 -0
- package/src/hooks/simulation-types.ts +158 -0
- package/src/hooks/useForceSimulation.ts +20 -175
|
@@ -286,6 +286,17 @@ function useWindowDrag(enableDrag, svgRef, transformRef, dragActiveRef, dragNode
|
|
|
286
286
|
};
|
|
287
287
|
}, [enableDrag, svgRef, transformRef, dragActiveRef, dragNodeRef, onDragEnd]);
|
|
288
288
|
}
|
|
289
|
+
function pinNode(node) {
|
|
290
|
+
node.fx = node.x;
|
|
291
|
+
node.fy = node.y;
|
|
292
|
+
}
|
|
293
|
+
function unpinNode(node) {
|
|
294
|
+
node.fx = null;
|
|
295
|
+
node.fy = null;
|
|
296
|
+
}
|
|
297
|
+
function unpinAllNodes(nodes) {
|
|
298
|
+
nodes.forEach(unpinNode);
|
|
299
|
+
}
|
|
289
300
|
var ForceDirectedGraph = forwardRef(
|
|
290
301
|
({
|
|
291
302
|
nodes: initialNodes,
|
|
@@ -368,26 +379,19 @@ var ForceDirectedGraph = forwardRef(
|
|
|
368
379
|
pinAll: () => {
|
|
369
380
|
const newPinned = /* @__PURE__ */ new Set();
|
|
370
381
|
nodes.forEach((node) => {
|
|
371
|
-
node
|
|
372
|
-
node.fy = node.y;
|
|
382
|
+
pinNode(node);
|
|
373
383
|
newPinned.add(node.id);
|
|
374
384
|
});
|
|
375
385
|
setPinnedNodes(newPinned);
|
|
376
386
|
restart();
|
|
377
387
|
},
|
|
378
388
|
unpinAll: () => {
|
|
379
|
-
nodes
|
|
380
|
-
node.fx = null;
|
|
381
|
-
node.fy = null;
|
|
382
|
-
});
|
|
389
|
+
unpinAllNodes(nodes);
|
|
383
390
|
setPinnedNodes(/* @__PURE__ */ new Set());
|
|
384
391
|
restart();
|
|
385
392
|
},
|
|
386
393
|
resetLayout: () => {
|
|
387
|
-
nodes
|
|
388
|
-
node.fx = null;
|
|
389
|
-
node.fy = null;
|
|
390
|
-
});
|
|
394
|
+
unpinAllNodes(nodes);
|
|
391
395
|
setPinnedNodes(/* @__PURE__ */ new Set());
|
|
392
396
|
restart();
|
|
393
397
|
},
|
|
@@ -479,8 +483,7 @@ var ForceDirectedGraph = forwardRef(
|
|
|
479
483
|
event.stopPropagation();
|
|
480
484
|
dragActiveRef.current = true;
|
|
481
485
|
dragNodeRef.current = node;
|
|
482
|
-
node
|
|
483
|
-
node.fy = node.y;
|
|
486
|
+
pinNode(node);
|
|
484
487
|
setPinnedNodes((prev) => /* @__PURE__ */ new Set([...prev, node.id]));
|
|
485
488
|
stop();
|
|
486
489
|
},
|
|
@@ -499,8 +502,7 @@ var ForceDirectedGraph = forwardRef(
|
|
|
499
502
|
if (!event.active) restart();
|
|
500
503
|
dragActiveRef.current = true;
|
|
501
504
|
dragNodeRef.current = node;
|
|
502
|
-
node
|
|
503
|
-
node.fy = node.y;
|
|
505
|
+
pinNode(node);
|
|
504
506
|
setPinnedNodes((prev) => /* @__PURE__ */ new Set([...prev, node.id]));
|
|
505
507
|
}).on("drag", (event) => {
|
|
506
508
|
if (!dragActiveRef.current || !dragNodeRef.current) return;
|
|
@@ -531,12 +533,10 @@ var ForceDirectedGraph = forwardRef(
|
|
|
531
533
|
event.stopPropagation();
|
|
532
534
|
if (!enableDrag) return;
|
|
533
535
|
if (node.fx === null || node.fx === void 0) {
|
|
534
|
-
node
|
|
535
|
-
node.fy = node.y;
|
|
536
|
+
pinNode(node);
|
|
536
537
|
setPinnedNodes((prev) => /* @__PURE__ */ new Set([...prev, node.id]));
|
|
537
538
|
} else {
|
|
538
|
-
node
|
|
539
|
-
node.fy = null;
|
|
539
|
+
unpinNode(node);
|
|
540
540
|
setPinnedNodes((prev) => {
|
|
541
541
|
const next = new Set(prev);
|
|
542
542
|
next.delete(node.id);
|
|
@@ -555,10 +555,7 @@ var ForceDirectedGraph = forwardRef(
|
|
|
555
555
|
height,
|
|
556
556
|
className: cn("bg-white dark:bg-gray-900", className),
|
|
557
557
|
onDoubleClick: () => {
|
|
558
|
-
nodes
|
|
559
|
-
n.fx = null;
|
|
560
|
-
n.fy = null;
|
|
561
|
-
});
|
|
558
|
+
unpinAllNodes(nodes);
|
|
562
559
|
setPinnedNodes(/* @__PURE__ */ new Set());
|
|
563
560
|
restart();
|
|
564
561
|
},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/utils/cn.ts","../../src/charts/NodeItem.tsx","../../src/charts/LinkItem.tsx","../../src/charts/constants.ts","../../src/charts/PackageBoundaries.tsx","../../src/charts/layout-utils.ts","../../src/charts/hooks.ts","../../src/charts/ForceDirectedGraph.tsx"],"names":["jsxs","jsx","d3","zoom","useEffect"],"mappings":"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","file":"ForceDirectedGraph.js","sourcesContent":["import { type ClassValue, clsx } from 'clsx';\nimport { twMerge } from 'tailwind-merge';\n\n/**\n * Merges class names using clsx and tailwind-merge\n * @param inputs - Class values to merge\n * @returns Merged class names\n */\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n","import React from 'react';\nimport type { GraphNode } from './types';\n\nexport interface NodeItemProps {\n node: GraphNode;\n isSelected: boolean;\n isHovered: boolean;\n pinned: boolean;\n defaultNodeSize: number;\n defaultNodeColor: string;\n showLabel?: boolean;\n onClick?: (n: GraphNode) => void;\n onDoubleClick?: (e: React.MouseEvent, n: GraphNode) => void;\n onMouseEnter?: (n: GraphNode) => void;\n onMouseLeave?: () => void;\n onMouseDown?: (e: React.MouseEvent, n: GraphNode) => void;\n}\n\nexport const NodeItem: React.FC<NodeItemProps> = ({\n node,\n isSelected,\n isHovered,\n pinned,\n defaultNodeSize,\n defaultNodeColor,\n showLabel = true,\n onClick,\n onDoubleClick,\n onMouseEnter,\n onMouseLeave,\n onMouseDown,\n}) => {\n const nodeSize = node.size || defaultNodeSize;\n const nodeColor = node.color || defaultNodeColor;\n\n const x = node.x ?? 0;\n const y = node.y ?? 0;\n\n return (\n <g\n key={node.id}\n className=\"cursor-pointer node\"\n data-id={node.id}\n transform={`translate(${x},${y})`}\n onClick={() => onClick?.(node)}\n onDoubleClick={(e) => onDoubleClick?.(e, node)}\n onMouseEnter={() => onMouseEnter?.(node)}\n onMouseLeave={() => onMouseLeave?.()}\n onMouseDown={(e) => onMouseDown?.(e, node)}\n >\n <circle\n r={nodeSize}\n fill={nodeColor}\n stroke={isSelected ? '#000' : isHovered ? '#666' : 'none'}\n strokeWidth={pinned ? 3 : isSelected ? 2.5 : isHovered ? 2 : 1.5}\n opacity={isHovered || isSelected ? 1 : 0.9}\n />\n {pinned && (\n <circle\n r={nodeSize + 4}\n fill=\"none\"\n stroke=\"#ff6b6b\"\n strokeWidth={1}\n opacity={0.5}\n className=\"pointer-events-none\"\n />\n )}\n {showLabel && node.label && (\n <text\n y={nodeSize + 15}\n fill=\"#333\"\n fontSize=\"12\"\n textAnchor=\"middle\"\n dominantBaseline=\"middle\"\n pointerEvents=\"none\"\n className=\"select-none\"\n >\n {node.label}\n </text>\n )}\n </g>\n );\n};\n\nexport default NodeItem;\n","import React from 'react';\nimport type { GraphLink, GraphNode } from './types';\n\nexport interface LinkItemProps {\n link: GraphLink;\n onClick?: (l: GraphLink) => void;\n defaultWidth?: number;\n showLabel?: boolean;\n nodes?: GraphNode[]; // Optional nodes array to resolve string IDs to node objects\n}\n\nexport const LinkItem: React.FC<LinkItemProps> = ({\n link,\n onClick,\n defaultWidth,\n showLabel = true,\n nodes = [],\n}) => {\n const src =\n (link.source as any)?.id ??\n (typeof link.source === 'string' ? link.source : undefined);\n const tgt =\n (link.target as any)?.id ??\n (typeof link.target === 'string' ? link.target : undefined);\n\n // Helper to get node position from source/target (which could be node object or string ID)\n const getNodePosition = (\n nodeOrId: string | GraphNode\n ): { x: number; y: number } | null => {\n if (typeof nodeOrId === 'object' && nodeOrId !== null) {\n // It's a node object\n const node = nodeOrId as GraphNode;\n return { x: node.x ?? 0, y: node.y ?? 0 };\n } else if (typeof nodeOrId === 'string') {\n // It's a string ID, try to find in nodes array\n const found = nodes.find((n) => n.id === nodeOrId);\n if (found) return { x: found.x ?? 0, y: found.y ?? 0 };\n }\n return null;\n };\n\n const sourcePos = getNodePosition(link.source);\n const targetPos = getNodePosition(link.target);\n\n // If we can't get positions, render nothing (or a placeholder)\n if (!sourcePos || !targetPos) {\n return null;\n }\n\n // Calculate midpoint for label positioning\n const midX = (sourcePos.x + targetPos.x) / 2;\n const midY = (sourcePos.y + targetPos.y) / 2;\n\n return (\n <g>\n <line\n x1={sourcePos.x}\n y1={sourcePos.y}\n x2={targetPos.x}\n y2={targetPos.y}\n data-source={src}\n data-target={tgt}\n stroke={link.color}\n strokeWidth={link.width ?? defaultWidth ?? 1}\n opacity={0.6}\n className=\"cursor-pointer transition-opacity hover:opacity-100\"\n onClick={() => onClick?.(link)}\n />\n {showLabel && link.label && (\n <text\n x={midX}\n y={midY}\n fill=\"#666\"\n fontSize=\"10\"\n textAnchor=\"middle\"\n dominantBaseline=\"middle\"\n pointerEvents=\"none\"\n >\n {link.label}\n </text>\n )}\n </g>\n );\n};\n\nexport default LinkItem;\n","/**\n * Default visual constants for the ForceDirectedGraph component.\n */\nexport const DEFAULT_NODE_COLOR = '#64748b';\nexport const DEFAULT_NODE_SIZE = 10;\nexport const DEFAULT_LINK_COLOR = '#94a3b8';\nexport const DEFAULT_LINK_WIDTH = 1;\n\n/**\n * Layout and interaction thresholds.\n */\nexport const CIRCULAR_LAYOUT_RADIUS_RATIO = 0.35;\nexport const FIT_VIEW_PADDING = 40;\nexport const ZOOM_MIN_SCALE = 0.1;\nexport const ZOOM_MAX_SCALE = 10;\n\n/**\n * Transition and animation durations.\n */\nexport const TRANSITION_DURATION_MS = 300;\n\n/**\n * Package boundary styling.\n */\nexport const PACKAGE_BOUNDARY_FILL = 'rgba(148,163,184,0.06)';\nexport const PACKAGE_BOUNDARY_STROKE = '#475569';\nexport const PACKAGE_BOUNDARY_STROKE_WIDTH = 2;\nexport const PACKAGE_BOUNDARY_DASH = '6 6';\nexport const PACKAGE_LABEL_FONT_SIZE = 11;\nexport const PACKAGE_LABEL_COLOR = '#475569';\n","import React from 'react';\nimport {\n PACKAGE_BOUNDARY_FILL,\n PACKAGE_BOUNDARY_STROKE,\n PACKAGE_BOUNDARY_STROKE_WIDTH,\n PACKAGE_BOUNDARY_DASH,\n PACKAGE_LABEL_COLOR,\n PACKAGE_LABEL_FONT_SIZE,\n} from './constants';\n\ninterface PackageBoundariesProps {\n packageBounds: Record<string, { x: number; y: number; r: number }>;\n}\n\n/**\n * Renders the circular boundaries and labels for package groups in the force-directed graph.\n *\n * @lastUpdated 2026-03-18\n */\nexport const PackageBoundaries: React.FC<PackageBoundariesProps> = ({\n packageBounds,\n}) => {\n if (!packageBounds || Object.keys(packageBounds).length === 0) return null;\n\n return (\n <g className=\"package-boundaries\" pointerEvents=\"none\">\n {Object.entries(packageBounds).map(([pid, b]) => (\n <g key={pid}>\n <circle\n cx={b.x}\n cy={b.y}\n r={b.r}\n fill={PACKAGE_BOUNDARY_FILL}\n stroke={PACKAGE_BOUNDARY_STROKE}\n strokeWidth={PACKAGE_BOUNDARY_STROKE_WIDTH}\n strokeDasharray={PACKAGE_BOUNDARY_DASH}\n opacity={0.9}\n />\n <text\n x={b.x}\n y={Math.max(12, b.y - b.r + 14)}\n fill={PACKAGE_LABEL_COLOR}\n fontSize={PACKAGE_LABEL_FONT_SIZE}\n textAnchor=\"middle\"\n pointerEvents=\"none\"\n >\n {pid.replace(/^pkg:/, '')}\n </text>\n </g>\n ))}\n </g>\n );\n};\n\nPackageBoundaries.displayName = 'PackageBoundaries';\n","import { GraphNode } from './types';\nimport { CIRCULAR_LAYOUT_RADIUS_RATIO } from './constants';\n\n/**\n * Calculates node positions for a circular layout.\n *\n * @param nodes - Array of dependency nodes.\n * @param width - Canvas width.\n * @param height - Canvas height.\n * @lastUpdated 2026-03-18\n */\nexport function applyCircularLayout(\n nodes: GraphNode[],\n width: number,\n height: number\n): void {\n const centerX = width / 2;\n const centerY = height / 2;\n const radius = Math.min(width, height) * CIRCULAR_LAYOUT_RADIUS_RATIO;\n\n nodes.forEach((node, i) => {\n const angle = (2 * Math.PI * i) / nodes.length;\n node.fx = centerX + Math.cos(angle) * radius;\n node.fy = centerY + Math.sin(angle) * radius;\n node.x = node.fx;\n node.y = node.fy;\n });\n}\n\n/**\n * Calculates node positions for a hierarchical layout by grouping packages.\n *\n * @param nodes - Array of dependency nodes.\n * @param width - Canvas width.\n * @param height - Canvas height.\n * @lastUpdated 2026-03-18\n */\nexport function applyHierarchicalLayout(\n nodes: GraphNode[],\n width: number,\n height: number\n): void {\n const groups = new Map<string, GraphNode[]>();\n nodes.forEach((n: any) => {\n const key = n.packageGroup || n.group || 'root';\n if (!groups.has(key)) groups.set(key, []);\n groups.get(key)!.push(n);\n });\n\n const groupArray = Array.from(groups.entries());\n const cols = Math.ceil(Math.sqrt(groupArray.length));\n const groupSpacingX = (width * 0.8) / cols;\n const groupSpacingY = (height * 0.8) / Math.ceil(groupArray.length / cols);\n\n groupArray.forEach(([groupKey, groupNodes], gi) => {\n const col = gi % cols;\n const row = Math.floor(gi / cols);\n const groupX = (col + 0.5) * groupSpacingX;\n const groupY = (row + 0.5) * groupSpacingY;\n\n if (groupKey.startsWith('pkg:') || groupKey === groupKey) {\n groupNodes.forEach((n, ni) => {\n const angle = (2 * Math.PI * ni) / groupNodes.length;\n const r = Math.min(80, 20 + groupNodes.length * 8);\n n.fx = groupX + Math.cos(angle) * r;\n n.fy = groupY + Math.sin(angle) * r;\n n.x = n.fx;\n n.y = n.fy;\n });\n }\n });\n}\n\n/**\n * Calculates initial random positions for nodes in a force-directed layout.\n *\n * @param nodes - Array of dependency nodes.\n * @param width - Canvas width.\n * @param height - Canvas height.\n * @lastUpdated 2026-03-18\n */\nexport function applyInitialForceLayout(\n nodes: GraphNode[],\n width: number,\n height: number\n): void {\n nodes.forEach((node) => {\n if (node.fx === undefined || node.fx === null) {\n node.x = Math.random() * width;\n node.y = Math.random() * height;\n }\n });\n}\n","import { useEffect } from 'react';\nimport * as d3 from 'd3';\nimport { GraphNode } from './types';\n\n/**\n * Hook for managing D3 zoom behavior on an SVG element.\n */\nexport function useGraphZoom(\n svgRef: React.RefObject<SVGSVGElement | null>,\n gRef: React.RefObject<SVGGElement | null>,\n enableZoom: boolean,\n setTransform: (transform: { k: number; x: number; y: number }) => void,\n transformRef: React.MutableRefObject<{ k: number; x: number; y: number }>\n) {\n useEffect(() => {\n if (!enableZoom || !svgRef.current || !gRef.current) return;\n\n const svg = d3.select(svgRef.current);\n const g = d3.select(gRef.current);\n\n const zoom = (d3 as any)\n .zoom()\n .scaleExtent([0.1, 10])\n .on('zoom', (event: any) => {\n g.attr('transform', event.transform);\n transformRef.current = event.transform;\n setTransform(event.transform);\n });\n\n svg.call(zoom);\n\n return () => {\n svg.on('.zoom', null);\n };\n }, [enableZoom, svgRef, gRef, setTransform, transformRef]);\n}\n\n/**\n * Hook for managing window-level drag events for smooth node dragging.\n */\nexport function useWindowDrag(\n enableDrag: boolean,\n svgRef: React.RefObject<SVGSVGElement | null>,\n transformRef: React.MutableRefObject<{ k: number; x: number; y: number }>,\n dragActiveRef: React.MutableRefObject<boolean>,\n dragNodeRef: React.MutableRefObject<GraphNode | null>,\n onDragEnd: () => void\n) {\n useEffect(() => {\n if (!enableDrag) return;\n\n const handleWindowMove = (event: MouseEvent) => {\n if (!dragActiveRef.current || !dragNodeRef.current) return;\n const svg = svgRef.current;\n if (!svg) return;\n const rect = svg.getBoundingClientRect();\n const t: any = transformRef.current;\n const x = (event.clientX - rect.left - t.x) / t.k;\n const y = (event.clientY - rect.top - t.y) / t.k;\n dragNodeRef.current.fx = x;\n dragNodeRef.current.fy = y;\n };\n\n const handleWindowUp = () => {\n if (!dragActiveRef.current) return;\n onDragEnd();\n dragNodeRef.current = null;\n dragActiveRef.current = false;\n };\n\n const handleWindowLeave = (event: MouseEvent) => {\n if (event.relatedTarget === null) handleWindowUp();\n };\n\n window.addEventListener('mousemove', handleWindowMove);\n window.addEventListener('mouseup', handleWindowUp);\n window.addEventListener('mouseout', handleWindowLeave);\n window.addEventListener('blur', handleWindowUp);\n\n return () => {\n window.removeEventListener('mousemove', handleWindowMove);\n window.removeEventListener('mouseup', handleWindowUp);\n window.removeEventListener('mouseout', handleWindowLeave);\n window.removeEventListener('blur', handleWindowUp);\n };\n }, [enableDrag, svgRef, transformRef, dragActiveRef, dragNodeRef, onDragEnd]);\n}\n","import React, {\n useCallback,\n useEffect,\n useRef,\n useState,\n forwardRef,\n useImperativeHandle,\n} from 'react';\nimport * as d3 from 'd3';\nimport { cn } from '../utils/cn';\nimport NodeItem from './NodeItem';\nimport LinkItem from './LinkItem';\nimport { PackageBoundaries } from './PackageBoundaries';\nimport {\n applyCircularLayout,\n applyHierarchicalLayout,\n applyInitialForceLayout,\n} from './layout-utils';\nimport {\n DEFAULT_NODE_COLOR,\n DEFAULT_NODE_SIZE,\n DEFAULT_LINK_COLOR,\n DEFAULT_LINK_WIDTH,\n FIT_VIEW_PADDING,\n TRANSITION_DURATION_MS,\n} from './constants';\nimport { useGraphZoom, useWindowDrag } from './hooks';\n\nimport { GraphNode, GraphLink, LayoutType } from './types';\nexport type { GraphNode, GraphLink, LayoutType };\n\n/**\n * Handle for imperative actions on the ForceDirectedGraph.\n */\nexport interface ForceDirectedGraphHandle {\n /** Pins all nodes to their current positions. */\n pinAll: () => void;\n /** Unpins all nodes, allowing them to move freely in the simulation. */\n unpinAll: () => void;\n /** Resets the layout by unpinning all nodes and restarting the simulation. */\n resetLayout: () => void;\n /** Rescales and re-centers the view to fit all nodes. */\n fitView: () => void;\n /** Returns the IDs of all currently pinned nodes. */\n getPinnedNodes: () => string[];\n /**\n * Enable or disable drag mode for nodes.\n * @param enabled - When true, nodes can be dragged; when false, dragging is disabled\n */\n setDragMode: (enabled: boolean) => void;\n /** Sets the current layout type. */\n setLayout: (layout: LayoutType) => void;\n /** Gets the current layout type. */\n getLayout: () => LayoutType;\n}\n\n/**\n * Props for the ForceDirectedGraph component.\n */\nexport interface ForceDirectedGraphProps {\n /** Array of node objects to render. */\n nodes: GraphNode[];\n /** Array of link objects to render. */\n links: GraphLink[];\n /** Width of the SVG canvas. */\n width: number;\n /** Height of the SVG canvas. */\n height: number;\n /** Whether to enable zoom and pan interactions. */\n enableZoom?: boolean;\n /** Whether to enable node dragging. */\n enableDrag?: boolean;\n /** Callback fired when a node is clicked. */\n onNodeClick?: (node: GraphNode) => void;\n /** Callback fired when a node is hovered. */\n onNodeHover?: (node: GraphNode | null) => void;\n /** Callback fired when a link is clicked. */\n onLinkClick?: (link: GraphLink) => void;\n /** ID of the currently selected node. */\n selectedNodeId?: string;\n /** ID of the currently hovered node. */\n hoveredNodeId?: string;\n /** Default fallback color for nodes. */\n defaultNodeColor?: string;\n /** Default fallback size for nodes. */\n defaultNodeSize?: number;\n /** Default fallback color for links. */\n defaultLinkColor?: string;\n /** Default fallback width for links. */\n defaultLinkWidth?: number;\n /** Whether to show labels on nodes. */\n showNodeLabels?: boolean;\n /** Whether to show labels on links. */\n showLinkLabels?: boolean;\n /** Additional CSS classes for the SVG element. */\n className?: string;\n /** Whether manual layout mode is active. */\n manualLayout?: boolean;\n /** Callback fired when manual layout mode changes. */\n onManualLayoutChange?: (enabled: boolean) => void;\n /** Optional bounds for package groups. */\n packageBounds?: Record<string, { x: number; y: number; r: number }>;\n /** Current layout algorithm. */\n layout?: LayoutType;\n /** Callback fired when layout changes. */\n onLayoutChange?: (layout: LayoutType) => void;\n}\n\n/**\n * An interactive Force-Directed Graph component using D3.js for physics and React for rendering.\n *\n * Supports multiple layout modes (force, circular, hierarchical), pinning, zooming, and dragging.\n * Optimal for visualizing complex dependency networks and codebase structures.\n *\n * @lastUpdated 2026-03-18\n */\nexport const ForceDirectedGraph = forwardRef<\n ForceDirectedGraphHandle,\n ForceDirectedGraphProps\n>(\n (\n {\n nodes: initialNodes,\n links: initialLinks,\n width,\n height,\n enableZoom = true,\n enableDrag = true,\n onNodeClick,\n onNodeHover,\n onLinkClick,\n selectedNodeId,\n hoveredNodeId,\n defaultNodeColor = DEFAULT_NODE_COLOR,\n defaultNodeSize = DEFAULT_NODE_SIZE,\n defaultLinkColor = DEFAULT_LINK_COLOR,\n defaultLinkWidth = DEFAULT_LINK_WIDTH,\n showNodeLabels = true,\n showLinkLabels = false,\n className,\n manualLayout = false,\n onManualLayoutChange,\n packageBounds,\n layout: externalLayout,\n onLayoutChange,\n },\n ref\n ) => {\n const svgRef = useRef<SVGSVGElement>(null);\n const gRef = useRef<SVGGElement>(null);\n const [transform, setTransform] = useState({ k: 1, x: 0, y: 0 });\n const transformRef = useRef(transform);\n const dragNodeRef = useRef<GraphNode | null>(null);\n const dragActiveRef = useRef(false);\n const [pinnedNodes, setPinnedNodes] = useState<Set<string>>(new Set());\n const internalDragEnabledRef = useRef(enableDrag);\n const [layout, setLayout] = useState<LayoutType>(externalLayout || 'force');\n\n // Sync external layout prop with internal state\n useEffect(() => {\n if (externalLayout && externalLayout !== layout) {\n setLayout(externalLayout);\n }\n }, [externalLayout, layout]);\n\n // Handle layout change and notify parent\n const handleLayoutChange = useCallback(\n (newLayout: LayoutType) => {\n setLayout(newLayout);\n onLayoutChange?.(newLayout);\n },\n [onLayoutChange]\n );\n\n // Update the ref when enableDrag prop changes\n useEffect(() => {\n internalDragEnabledRef.current = enableDrag;\n }, [enableDrag]);\n\n // Initial positioning - delegate to layout utils\n const nodes = React.useMemo(() => {\n if (!initialNodes || !initialNodes.length) return initialNodes;\n const copy = initialNodes.map((n) => ({ ...n }));\n if (layout === 'circular') applyCircularLayout(copy, width, height);\n else if (layout === 'hierarchical')\n applyHierarchicalLayout(copy, width, height);\n else applyInitialForceLayout(copy, width, height);\n return copy;\n }, [initialNodes, width, height, layout]);\n\n // No force simulation - static layout only (stubs for API compatibility)\n const restart = React.useCallback(() => {}, []);\n const stop = React.useCallback(() => {}, []);\n const setForcesEnabled = React.useCallback((enabled?: boolean) => {\n void enabled;\n }, []);\n\n // Apply layout-specific positioning when layout changes\n useEffect(() => {\n if (!nodes || nodes.length === 0) return;\n if (layout === 'circular') applyCircularLayout(nodes, width, height);\n else if (layout === 'hierarchical')\n applyHierarchicalLayout(nodes, width, height);\n\n restart();\n }, [layout, nodes, width, height, restart]);\n\n // If manual layout is enabled or any nodes are pinned, disable forces\n useEffect(() => {\n if (manualLayout || pinnedNodes.size > 0) setForcesEnabled(false);\n else setForcesEnabled(true);\n }, [manualLayout, pinnedNodes, setForcesEnabled]);\n\n // Expose imperative handle for parent components\n useImperativeHandle(\n ref,\n () => ({\n pinAll: () => {\n const newPinned = new Set<string>();\n nodes.forEach((node) => {\n node.fx = node.x;\n node.fy = node.y;\n newPinned.add(node.id);\n });\n setPinnedNodes(newPinned);\n restart();\n },\n unpinAll: () => {\n nodes.forEach((node) => {\n node.fx = null;\n node.fy = null;\n });\n setPinnedNodes(new Set());\n restart();\n },\n resetLayout: () => {\n nodes.forEach((node) => {\n node.fx = null;\n node.fy = null;\n });\n setPinnedNodes(new Set());\n restart();\n },\n fitView: () => {\n if (!svgRef.current || !nodes.length) return;\n let minX = Infinity,\n maxX = -Infinity,\n minY = Infinity,\n maxY = -Infinity;\n nodes.forEach((node) => {\n if (node.x !== undefined && node.y !== undefined) {\n const size = node.size || DEFAULT_NODE_SIZE;\n minX = Math.min(minX, node.x - size);\n maxX = Math.max(maxX, node.x + size);\n minY = Math.min(minY, node.y - size);\n maxY = Math.max(maxY, node.y + size);\n }\n });\n if (!isFinite(minX)) return;\n const scale = Math.min(\n (width - FIT_VIEW_PADDING * 2) / (maxX - minX),\n (height - FIT_VIEW_PADDING * 2) / (maxY - minY),\n 10\n );\n const x = width / 2 - ((minX + maxX) / 2) * scale;\n const y = height / 2 - ((minY + maxY) / 2) * scale;\n if (gRef.current && svgRef.current) {\n const svg = d3.select(svgRef.current);\n const newTransform = d3.zoomIdentity.translate(x, y).scale(scale);\n svg\n .transition()\n .duration(TRANSITION_DURATION_MS)\n .call((d3 as any).zoom().transform as any, newTransform);\n setTransform(newTransform);\n }\n },\n getPinnedNodes: () => Array.from(pinnedNodes),\n setDragMode: (enabled: boolean) => {\n internalDragEnabledRef.current = enabled;\n },\n setLayout: (newLayout: LayoutType) => handleLayoutChange(newLayout),\n getLayout: () => layout,\n }),\n [\n nodes,\n pinnedNodes,\n restart,\n width,\n height,\n layout,\n handleLayoutChange,\n setForcesEnabled,\n ]\n );\n\n // Notify parent when manual layout mode changes\n useEffect(() => {\n if (typeof onManualLayoutChange === 'function')\n onManualLayoutChange(manualLayout);\n }, [manualLayout, onManualLayoutChange]);\n\n // Use custom hooks for zoom and window-level drag\n useGraphZoom(svgRef, gRef, enableZoom, setTransform, transformRef);\n useWindowDrag(\n enableDrag,\n svgRef,\n transformRef,\n dragActiveRef,\n dragNodeRef,\n () => {\n setForcesEnabled(true);\n restart();\n }\n );\n\n // Run positioning pass when nodes/links change\n useEffect(() => {\n if (!gRef.current) return;\n const g = d3.select(gRef.current);\n g.selectAll('g.node').each(function (this: any) {\n const datum = d3.select(this).datum() as any;\n if (!datum) return;\n d3.select(this).attr(\n 'transform',\n `translate(${datum.x || 0},${datum.y || 0})`\n );\n });\n g.selectAll('line').each(function (this: any) {\n const l = d3.select(this).datum() as any;\n if (!l) return;\n const s: any =\n typeof l.source === 'object'\n ? l.source\n : nodes.find((n) => n.id === l.source) || l.source;\n const t: any =\n typeof l.target === 'object'\n ? l.target\n : nodes.find((n) => n.id === l.target) || l.target;\n if (!s || !t) return;\n d3.select(this)\n .attr('x1', s.x)\n .attr('y1', s.y)\n .attr('x2', t.x)\n .attr('y2', t.y);\n });\n }, [nodes, initialLinks]);\n\n const handleDragStart = useCallback(\n (event: React.MouseEvent, node: GraphNode) => {\n if (!enableDrag) return;\n event.preventDefault();\n event.stopPropagation();\n dragActiveRef.current = true;\n dragNodeRef.current = node;\n node.fx = node.x;\n node.fy = node.y;\n setPinnedNodes((prev) => new Set([...prev, node.id]));\n stop();\n },\n [enableDrag, stop]\n );\n\n // Attach d3.drag behavior to nodes\n useEffect(() => {\n if (!gRef.current || !enableDrag) return;\n const g = d3.select(gRef.current);\n const dragBehavior = (d3 as any)\n .drag()\n .on('start', (event: any) => {\n const target =\n (event.sourceEvent && (event.sourceEvent.target as Element)) ||\n (event.target as Element);\n const grp = target.closest?.('g.node') as Element | null;\n const id = grp?.getAttribute('data-id');\n if (!id || !internalDragEnabledRef.current) return;\n const node = nodes.find((n) => n.id === id);\n if (!node) return;\n if (!event.active) restart();\n dragActiveRef.current = true;\n dragNodeRef.current = node;\n node.fx = node.x;\n node.fy = node.y;\n setPinnedNodes((prev) => new Set([...prev, node.id]));\n })\n .on('drag', (event: any) => {\n if (!dragActiveRef.current || !dragNodeRef.current) return;\n const svg = svgRef.current;\n if (!svg) return;\n const rect = svg.getBoundingClientRect();\n dragNodeRef.current.fx =\n (event.sourceEvent.clientX - rect.left - transform.x) / transform.k;\n dragNodeRef.current.fy =\n (event.sourceEvent.clientY - rect.top - transform.y) / transform.k;\n })\n .on('end', () => {\n setForcesEnabled(true);\n restart();\n });\n\n g.selectAll('g.node').call(dragBehavior as any);\n return () => {\n g.selectAll('g.node').on('.drag', null as any);\n };\n }, [\n gRef,\n enableDrag,\n nodes,\n transform,\n restart,\n setForcesEnabled,\n internalDragEnabledRef,\n ]);\n\n const handleNodeDoubleClick = useCallback(\n (event: React.MouseEvent, node: GraphNode) => {\n event.stopPropagation();\n if (!enableDrag) return;\n if (node.fx === null || node.fx === undefined) {\n node.fx = node.x;\n node.fy = node.y;\n setPinnedNodes((prev) => new Set([...prev, node.id]));\n } else {\n node.fx = null;\n node.fy = null;\n setPinnedNodes((prev) => {\n const next = new Set(prev);\n next.delete(node.id);\n return next;\n });\n }\n restart();\n },\n [enableDrag, restart]\n );\n\n return (\n <svg\n ref={svgRef}\n width={width}\n height={height}\n className={cn('bg-white dark:bg-gray-900', className)}\n onDoubleClick={() => {\n nodes.forEach((n) => {\n n.fx = null;\n n.fy = null;\n });\n setPinnedNodes(new Set());\n restart();\n }}\n >\n <defs>\n <marker\n id=\"arrow\"\n viewBox=\"0 0 10 10\"\n refX=\"20\"\n refY=\"5\"\n markerWidth=\"6\"\n markerHeight=\"6\"\n orient=\"auto\"\n >\n <path d=\"M 0 0 L 10 5 L 0 10 z\" fill={defaultLinkColor} />\n </marker>\n </defs>\n\n <g ref={gRef}>\n {initialLinks.map((link, i) => (\n <LinkItem\n key={`link-${i}`}\n link={link as GraphLink}\n onClick={onLinkClick}\n defaultWidth={defaultLinkWidth}\n showLabel={showLinkLabels}\n nodes={nodes}\n />\n ))}\n\n {nodes.map((node) => (\n <NodeItem\n key={node.id}\n node={node}\n isSelected={selectedNodeId === node.id}\n isHovered={hoveredNodeId === node.id}\n pinned={pinnedNodes.has(node.id)}\n defaultNodeSize={defaultNodeSize}\n defaultNodeColor={defaultNodeColor}\n showLabel={showNodeLabels}\n onClick={onNodeClick}\n onDoubleClick={handleNodeDoubleClick}\n onMouseEnter={(n) => onNodeHover?.(n)}\n onMouseLeave={() => onNodeHover?.(null)}\n onMouseDown={handleDragStart}\n />\n ))}\n <PackageBoundaries packageBounds={packageBounds || {}} />\n </g>\n </svg>\n );\n }\n);\n\nForceDirectedGraph.displayName = 'ForceDirectedGraph';\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/utils/cn.ts","../../src/charts/NodeItem.tsx","../../src/charts/LinkItem.tsx","../../src/charts/constants.ts","../../src/charts/PackageBoundaries.tsx","../../src/charts/layout-utils.ts","../../src/charts/hooks.ts","../../src/charts/ForceDirectedGraph.tsx"],"names":["jsxs","jsx","d3","zoom","useEffect"],"mappings":"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","file":"ForceDirectedGraph.js","sourcesContent":["import { type ClassValue, clsx } from 'clsx';\nimport { twMerge } from 'tailwind-merge';\n\n/**\n * Merges class names using clsx and tailwind-merge\n * @param inputs - Class values to merge\n * @returns Merged class names\n */\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n","import React from 'react';\nimport type { GraphNode } from './types';\n\nexport interface NodeItemProps {\n node: GraphNode;\n isSelected: boolean;\n isHovered: boolean;\n pinned: boolean;\n defaultNodeSize: number;\n defaultNodeColor: string;\n showLabel?: boolean;\n onClick?: (n: GraphNode) => void;\n onDoubleClick?: (e: React.MouseEvent, n: GraphNode) => void;\n onMouseEnter?: (n: GraphNode) => void;\n onMouseLeave?: () => void;\n onMouseDown?: (e: React.MouseEvent, n: GraphNode) => void;\n}\n\nexport const NodeItem: React.FC<NodeItemProps> = ({\n node,\n isSelected,\n isHovered,\n pinned,\n defaultNodeSize,\n defaultNodeColor,\n showLabel = true,\n onClick,\n onDoubleClick,\n onMouseEnter,\n onMouseLeave,\n onMouseDown,\n}) => {\n const nodeSize = node.size || defaultNodeSize;\n const nodeColor = node.color || defaultNodeColor;\n\n const x = node.x ?? 0;\n const y = node.y ?? 0;\n\n return (\n <g\n key={node.id}\n className=\"cursor-pointer node\"\n data-id={node.id}\n transform={`translate(${x},${y})`}\n onClick={() => onClick?.(node)}\n onDoubleClick={(e) => onDoubleClick?.(e, node)}\n onMouseEnter={() => onMouseEnter?.(node)}\n onMouseLeave={() => onMouseLeave?.()}\n onMouseDown={(e) => onMouseDown?.(e, node)}\n >\n <circle\n r={nodeSize}\n fill={nodeColor}\n stroke={isSelected ? '#000' : isHovered ? '#666' : 'none'}\n strokeWidth={pinned ? 3 : isSelected ? 2.5 : isHovered ? 2 : 1.5}\n opacity={isHovered || isSelected ? 1 : 0.9}\n />\n {pinned && (\n <circle\n r={nodeSize + 4}\n fill=\"none\"\n stroke=\"#ff6b6b\"\n strokeWidth={1}\n opacity={0.5}\n className=\"pointer-events-none\"\n />\n )}\n {showLabel && node.label && (\n <text\n y={nodeSize + 15}\n fill=\"#333\"\n fontSize=\"12\"\n textAnchor=\"middle\"\n dominantBaseline=\"middle\"\n pointerEvents=\"none\"\n className=\"select-none\"\n >\n {node.label}\n </text>\n )}\n </g>\n );\n};\n\nexport default NodeItem;\n","import React from 'react';\nimport type { GraphLink, GraphNode } from './types';\n\nexport interface LinkItemProps {\n link: GraphLink;\n onClick?: (l: GraphLink) => void;\n defaultWidth?: number;\n showLabel?: boolean;\n nodes?: GraphNode[]; // Optional nodes array to resolve string IDs to node objects\n}\n\nexport const LinkItem: React.FC<LinkItemProps> = ({\n link,\n onClick,\n defaultWidth,\n showLabel = true,\n nodes = [],\n}) => {\n const src =\n (link.source as any)?.id ??\n (typeof link.source === 'string' ? link.source : undefined);\n const tgt =\n (link.target as any)?.id ??\n (typeof link.target === 'string' ? link.target : undefined);\n\n // Helper to get node position from source/target (which could be node object or string ID)\n const getNodePosition = (\n nodeOrId: string | GraphNode\n ): { x: number; y: number } | null => {\n if (typeof nodeOrId === 'object' && nodeOrId !== null) {\n // It's a node object\n const node = nodeOrId as GraphNode;\n return { x: node.x ?? 0, y: node.y ?? 0 };\n } else if (typeof nodeOrId === 'string') {\n // It's a string ID, try to find in nodes array\n const found = nodes.find((n) => n.id === nodeOrId);\n if (found) return { x: found.x ?? 0, y: found.y ?? 0 };\n }\n return null;\n };\n\n const sourcePos = getNodePosition(link.source);\n const targetPos = getNodePosition(link.target);\n\n // If we can't get positions, render nothing (or a placeholder)\n if (!sourcePos || !targetPos) {\n return null;\n }\n\n // Calculate midpoint for label positioning\n const midX = (sourcePos.x + targetPos.x) / 2;\n const midY = (sourcePos.y + targetPos.y) / 2;\n\n return (\n <g>\n <line\n x1={sourcePos.x}\n y1={sourcePos.y}\n x2={targetPos.x}\n y2={targetPos.y}\n data-source={src}\n data-target={tgt}\n stroke={link.color}\n strokeWidth={link.width ?? defaultWidth ?? 1}\n opacity={0.6}\n className=\"cursor-pointer transition-opacity hover:opacity-100\"\n onClick={() => onClick?.(link)}\n />\n {showLabel && link.label && (\n <text\n x={midX}\n y={midY}\n fill=\"#666\"\n fontSize=\"10\"\n textAnchor=\"middle\"\n dominantBaseline=\"middle\"\n pointerEvents=\"none\"\n >\n {link.label}\n </text>\n )}\n </g>\n );\n};\n\nexport default LinkItem;\n","/**\n * Default visual constants for the ForceDirectedGraph component.\n */\nexport const DEFAULT_NODE_COLOR = '#64748b';\nexport const DEFAULT_NODE_SIZE = 10;\nexport const DEFAULT_LINK_COLOR = '#94a3b8';\nexport const DEFAULT_LINK_WIDTH = 1;\n\n/**\n * Layout and interaction thresholds.\n */\nexport const CIRCULAR_LAYOUT_RADIUS_RATIO = 0.35;\nexport const FIT_VIEW_PADDING = 40;\nexport const ZOOM_MIN_SCALE = 0.1;\nexport const ZOOM_MAX_SCALE = 10;\n\n/**\n * Transition and animation durations.\n */\nexport const TRANSITION_DURATION_MS = 300;\n\n/**\n * Package boundary styling.\n */\nexport const PACKAGE_BOUNDARY_FILL = 'rgba(148,163,184,0.06)';\nexport const PACKAGE_BOUNDARY_STROKE = '#475569';\nexport const PACKAGE_BOUNDARY_STROKE_WIDTH = 2;\nexport const PACKAGE_BOUNDARY_DASH = '6 6';\nexport const PACKAGE_LABEL_FONT_SIZE = 11;\nexport const PACKAGE_LABEL_COLOR = '#475569';\n","import React from 'react';\nimport {\n PACKAGE_BOUNDARY_FILL,\n PACKAGE_BOUNDARY_STROKE,\n PACKAGE_BOUNDARY_STROKE_WIDTH,\n PACKAGE_BOUNDARY_DASH,\n PACKAGE_LABEL_COLOR,\n PACKAGE_LABEL_FONT_SIZE,\n} from './constants';\n\ninterface PackageBoundariesProps {\n packageBounds: Record<string, { x: number; y: number; r: number }>;\n}\n\n/**\n * Renders the circular boundaries and labels for package groups in the force-directed graph.\n *\n * @lastUpdated 2026-03-18\n */\nexport const PackageBoundaries: React.FC<PackageBoundariesProps> = ({\n packageBounds,\n}) => {\n if (!packageBounds || Object.keys(packageBounds).length === 0) return null;\n\n return (\n <g className=\"package-boundaries\" pointerEvents=\"none\">\n {Object.entries(packageBounds).map(([pid, b]) => (\n <g key={pid}>\n <circle\n cx={b.x}\n cy={b.y}\n r={b.r}\n fill={PACKAGE_BOUNDARY_FILL}\n stroke={PACKAGE_BOUNDARY_STROKE}\n strokeWidth={PACKAGE_BOUNDARY_STROKE_WIDTH}\n strokeDasharray={PACKAGE_BOUNDARY_DASH}\n opacity={0.9}\n />\n <text\n x={b.x}\n y={Math.max(12, b.y - b.r + 14)}\n fill={PACKAGE_LABEL_COLOR}\n fontSize={PACKAGE_LABEL_FONT_SIZE}\n textAnchor=\"middle\"\n pointerEvents=\"none\"\n >\n {pid.replace(/^pkg:/, '')}\n </text>\n </g>\n ))}\n </g>\n );\n};\n\nPackageBoundaries.displayName = 'PackageBoundaries';\n","import { GraphNode } from './types';\nimport { CIRCULAR_LAYOUT_RADIUS_RATIO } from './constants';\n\n/**\n * Calculates node positions for a circular layout.\n *\n * @param nodes - Array of dependency nodes.\n * @param width - Canvas width.\n * @param height - Canvas height.\n * @lastUpdated 2026-03-18\n */\nexport function applyCircularLayout(\n nodes: GraphNode[],\n width: number,\n height: number\n): void {\n const centerX = width / 2;\n const centerY = height / 2;\n const radius = Math.min(width, height) * CIRCULAR_LAYOUT_RADIUS_RATIO;\n\n nodes.forEach((node, i) => {\n const angle = (2 * Math.PI * i) / nodes.length;\n node.fx = centerX + Math.cos(angle) * radius;\n node.fy = centerY + Math.sin(angle) * radius;\n node.x = node.fx;\n node.y = node.fy;\n });\n}\n\n/**\n * Calculates node positions for a hierarchical layout by grouping packages.\n *\n * @param nodes - Array of dependency nodes.\n * @param width - Canvas width.\n * @param height - Canvas height.\n * @lastUpdated 2026-03-18\n */\nexport function applyHierarchicalLayout(\n nodes: GraphNode[],\n width: number,\n height: number\n): void {\n const groups = new Map<string, GraphNode[]>();\n nodes.forEach((n: any) => {\n const key = n.packageGroup || n.group || 'root';\n if (!groups.has(key)) groups.set(key, []);\n groups.get(key)!.push(n);\n });\n\n const groupArray = Array.from(groups.entries());\n const cols = Math.ceil(Math.sqrt(groupArray.length));\n const groupSpacingX = (width * 0.8) / cols;\n const groupSpacingY = (height * 0.8) / Math.ceil(groupArray.length / cols);\n\n groupArray.forEach(([groupKey, groupNodes], gi) => {\n const col = gi % cols;\n const row = Math.floor(gi / cols);\n const groupX = (col + 0.5) * groupSpacingX;\n const groupY = (row + 0.5) * groupSpacingY;\n\n if (groupKey.startsWith('pkg:') || groupKey === groupKey) {\n groupNodes.forEach((n, ni) => {\n const angle = (2 * Math.PI * ni) / groupNodes.length;\n const r = Math.min(80, 20 + groupNodes.length * 8);\n n.fx = groupX + Math.cos(angle) * r;\n n.fy = groupY + Math.sin(angle) * r;\n n.x = n.fx;\n n.y = n.fy;\n });\n }\n });\n}\n\n/**\n * Calculates initial random positions for nodes in a force-directed layout.\n *\n * @param nodes - Array of dependency nodes.\n * @param width - Canvas width.\n * @param height - Canvas height.\n * @lastUpdated 2026-03-18\n */\nexport function applyInitialForceLayout(\n nodes: GraphNode[],\n width: number,\n height: number\n): void {\n nodes.forEach((node) => {\n if (node.fx === undefined || node.fx === null) {\n node.x = Math.random() * width;\n node.y = Math.random() * height;\n }\n });\n}\n","import { useEffect } from 'react';\nimport * as d3 from 'd3';\nimport { GraphNode } from './types';\n\n/**\n * Hook for managing D3 zoom behavior on an SVG element.\n */\nexport function useGraphZoom(\n svgRef: React.RefObject<SVGSVGElement | null>,\n gRef: React.RefObject<SVGGElement | null>,\n enableZoom: boolean,\n setTransform: (transform: { k: number; x: number; y: number }) => void,\n transformRef: React.MutableRefObject<{ k: number; x: number; y: number }>\n) {\n useEffect(() => {\n if (!enableZoom || !svgRef.current || !gRef.current) return;\n\n const svg = d3.select(svgRef.current);\n const g = d3.select(gRef.current);\n\n const zoom = (d3 as any)\n .zoom()\n .scaleExtent([0.1, 10])\n .on('zoom', (event: any) => {\n g.attr('transform', event.transform);\n transformRef.current = event.transform;\n setTransform(event.transform);\n });\n\n svg.call(zoom);\n\n return () => {\n svg.on('.zoom', null);\n };\n }, [enableZoom, svgRef, gRef, setTransform, transformRef]);\n}\n\n/**\n * Hook for managing window-level drag events for smooth node dragging.\n */\nexport function useWindowDrag(\n enableDrag: boolean,\n svgRef: React.RefObject<SVGSVGElement | null>,\n transformRef: React.MutableRefObject<{ k: number; x: number; y: number }>,\n dragActiveRef: React.MutableRefObject<boolean>,\n dragNodeRef: React.MutableRefObject<GraphNode | null>,\n onDragEnd: () => void\n) {\n useEffect(() => {\n if (!enableDrag) return;\n\n const handleWindowMove = (event: MouseEvent) => {\n if (!dragActiveRef.current || !dragNodeRef.current) return;\n const svg = svgRef.current;\n if (!svg) return;\n const rect = svg.getBoundingClientRect();\n const t: any = transformRef.current;\n const x = (event.clientX - rect.left - t.x) / t.k;\n const y = (event.clientY - rect.top - t.y) / t.k;\n dragNodeRef.current.fx = x;\n dragNodeRef.current.fy = y;\n };\n\n const handleWindowUp = () => {\n if (!dragActiveRef.current) return;\n onDragEnd();\n dragNodeRef.current = null;\n dragActiveRef.current = false;\n };\n\n const handleWindowLeave = (event: MouseEvent) => {\n if (event.relatedTarget === null) handleWindowUp();\n };\n\n window.addEventListener('mousemove', handleWindowMove);\n window.addEventListener('mouseup', handleWindowUp);\n window.addEventListener('mouseout', handleWindowLeave);\n window.addEventListener('blur', handleWindowUp);\n\n return () => {\n window.removeEventListener('mousemove', handleWindowMove);\n window.removeEventListener('mouseup', handleWindowUp);\n window.removeEventListener('mouseout', handleWindowLeave);\n window.removeEventListener('blur', handleWindowUp);\n };\n }, [enableDrag, svgRef, transformRef, dragActiveRef, dragNodeRef, onDragEnd]);\n}\n","import React, {\n useCallback,\n useEffect,\n useRef,\n useState,\n forwardRef,\n useImperativeHandle,\n} from 'react';\nimport * as d3 from 'd3';\nimport { cn } from '../utils/cn';\nimport NodeItem from './NodeItem';\nimport LinkItem from './LinkItem';\nimport { PackageBoundaries } from './PackageBoundaries';\nimport {\n applyCircularLayout,\n applyHierarchicalLayout,\n applyInitialForceLayout,\n} from './layout-utils';\nimport {\n DEFAULT_NODE_COLOR,\n DEFAULT_NODE_SIZE,\n DEFAULT_LINK_COLOR,\n DEFAULT_LINK_WIDTH,\n FIT_VIEW_PADDING,\n TRANSITION_DURATION_MS,\n} from './constants';\nimport { useGraphZoom, useWindowDrag } from './hooks';\n\nimport { GraphNode, GraphLink, LayoutType } from './types';\nexport type { GraphNode, GraphLink, LayoutType };\n\n/**\n * Handle for imperative actions on the ForceDirectedGraph.\n */\nexport interface ForceDirectedGraphHandle {\n /** Pins all nodes to their current positions. */\n pinAll: () => void;\n /** Unpins all nodes, allowing them to move freely in the simulation. */\n unpinAll: () => void;\n /** Resets the layout by unpinning all nodes and restarting the simulation. */\n resetLayout: () => void;\n /** Rescales and re-centers the view to fit all nodes. */\n fitView: () => void;\n /** Returns the IDs of all currently pinned nodes. */\n getPinnedNodes: () => string[];\n /**\n * Enable or disable drag mode for nodes.\n * @param enabled - When true, nodes can be dragged; when false, dragging is disabled\n */\n setDragMode: (enabled: boolean) => void;\n /** Sets the current layout type. */\n setLayout: (layout: LayoutType) => void;\n /** Gets the current layout type. */\n getLayout: () => LayoutType;\n}\n\n/**\n * Props for the ForceDirectedGraph component.\n */\nexport interface ForceDirectedGraphProps {\n /** Array of node objects to render. */\n nodes: GraphNode[];\n /** Array of link objects to render. */\n links: GraphLink[];\n /** Width of the SVG canvas. */\n width: number;\n /** Height of the SVG canvas. */\n height: number;\n /** Whether to enable zoom and pan interactions. */\n enableZoom?: boolean;\n /** Whether to enable node dragging. */\n enableDrag?: boolean;\n /** Callback fired when a node is clicked. */\n onNodeClick?: (node: GraphNode) => void;\n /** Callback fired when a node is hovered. */\n onNodeHover?: (node: GraphNode | null) => void;\n /** Callback fired when a link is clicked. */\n onLinkClick?: (link: GraphLink) => void;\n /** ID of the currently selected node. */\n selectedNodeId?: string;\n /** ID of the currently hovered node. */\n hoveredNodeId?: string;\n /** Default fallback color for nodes. */\n defaultNodeColor?: string;\n /** Default fallback size for nodes. */\n defaultNodeSize?: number;\n /** Default fallback color for links. */\n defaultLinkColor?: string;\n /** Default fallback width for links. */\n defaultLinkWidth?: number;\n /** Whether to show labels on nodes. */\n showNodeLabels?: boolean;\n /** Whether to show labels on links. */\n showLinkLabels?: boolean;\n /** Additional CSS classes for the SVG element. */\n className?: string;\n /** Whether manual layout mode is active. */\n manualLayout?: boolean;\n /** Callback fired when manual layout mode changes. */\n onManualLayoutChange?: (enabled: boolean) => void;\n /** Optional bounds for package groups. */\n packageBounds?: Record<string, { x: number; y: number; r: number }>;\n /** Current layout algorithm. */\n layout?: LayoutType;\n /** Callback fired when layout changes. */\n onLayoutChange?: (layout: LayoutType) => void;\n}\n\n/**\n * Helper functions for graph node manipulation.\n * Extracted to reduce semantic duplicate patterns.\n */\n\n/** Pins a node to its current position (sets fx/fy to current x/y) */\nfunction pinNode(node: GraphNode): void {\n node.fx = node.x;\n node.fy = node.y;\n}\n\n/** Unpins a node (sets fx/fy to null) */\nfunction unpinNode(node: GraphNode): void {\n node.fx = null;\n node.fy = null;\n}\n\n/** Unpins all nodes - helper for bulk unpin operations */\nfunction unpinAllNodes(nodes: GraphNode[]): void {\n nodes.forEach(unpinNode);\n}\n\n/**\n * An interactive Force-Directed Graph component using D3.js for physics and React for rendering.\n *\n * Supports multiple layout modes (force, circular, hierarchical), pinning, zooming, and dragging.\n * Optimal for visualizing complex dependency networks and codebase structures.\n *\n * @lastUpdated 2026-03-18\n */\nexport const ForceDirectedGraph = forwardRef<\n ForceDirectedGraphHandle,\n ForceDirectedGraphProps\n>(\n (\n {\n nodes: initialNodes,\n links: initialLinks,\n width,\n height,\n enableZoom = true,\n enableDrag = true,\n onNodeClick,\n onNodeHover,\n onLinkClick,\n selectedNodeId,\n hoveredNodeId,\n defaultNodeColor = DEFAULT_NODE_COLOR,\n defaultNodeSize = DEFAULT_NODE_SIZE,\n defaultLinkColor = DEFAULT_LINK_COLOR,\n defaultLinkWidth = DEFAULT_LINK_WIDTH,\n showNodeLabels = true,\n showLinkLabels = false,\n className,\n manualLayout = false,\n onManualLayoutChange,\n packageBounds,\n layout: externalLayout,\n onLayoutChange,\n },\n ref\n ) => {\n const svgRef = useRef<SVGSVGElement>(null);\n const gRef = useRef<SVGGElement>(null);\n const [transform, setTransform] = useState({ k: 1, x: 0, y: 0 });\n const transformRef = useRef(transform);\n const dragNodeRef = useRef<GraphNode | null>(null);\n const dragActiveRef = useRef(false);\n const [pinnedNodes, setPinnedNodes] = useState<Set<string>>(new Set());\n const internalDragEnabledRef = useRef(enableDrag);\n const [layout, setLayout] = useState<LayoutType>(externalLayout || 'force');\n\n // Sync external layout prop with internal state\n useEffect(() => {\n if (externalLayout && externalLayout !== layout) {\n setLayout(externalLayout);\n }\n }, [externalLayout, layout]);\n\n // Handle layout change and notify parent\n const handleLayoutChange = useCallback(\n (newLayout: LayoutType) => {\n setLayout(newLayout);\n onLayoutChange?.(newLayout);\n },\n [onLayoutChange]\n );\n\n // Update the ref when enableDrag prop changes\n useEffect(() => {\n internalDragEnabledRef.current = enableDrag;\n }, [enableDrag]);\n\n // Initial positioning - delegate to layout utils\n const nodes = React.useMemo(() => {\n if (!initialNodes || !initialNodes.length) return initialNodes;\n const copy = initialNodes.map((n) => ({ ...n }));\n if (layout === 'circular') applyCircularLayout(copy, width, height);\n else if (layout === 'hierarchical')\n applyHierarchicalLayout(copy, width, height);\n else applyInitialForceLayout(copy, width, height);\n return copy;\n }, [initialNodes, width, height, layout]);\n\n // No force simulation - static layout only (stubs for API compatibility)\n const restart = React.useCallback(() => {}, []);\n const stop = React.useCallback(() => {}, []);\n const setForcesEnabled = React.useCallback((enabled?: boolean) => {\n void enabled;\n }, []);\n\n // Apply layout-specific positioning when layout changes\n useEffect(() => {\n if (!nodes || nodes.length === 0) return;\n if (layout === 'circular') applyCircularLayout(nodes, width, height);\n else if (layout === 'hierarchical')\n applyHierarchicalLayout(nodes, width, height);\n\n restart();\n }, [layout, nodes, width, height, restart]);\n\n // If manual layout is enabled or any nodes are pinned, disable forces\n useEffect(() => {\n if (manualLayout || pinnedNodes.size > 0) setForcesEnabled(false);\n else setForcesEnabled(true);\n }, [manualLayout, pinnedNodes, setForcesEnabled]);\n\n // Expose imperative handle for parent components\n useImperativeHandle(\n ref,\n () => ({\n pinAll: () => {\n const newPinned = new Set<string>();\n nodes.forEach((node) => {\n pinNode(node);\n newPinned.add(node.id);\n });\n setPinnedNodes(newPinned);\n restart();\n },\n unpinAll: () => {\n unpinAllNodes(nodes);\n setPinnedNodes(new Set());\n restart();\n },\n resetLayout: () => {\n unpinAllNodes(nodes);\n setPinnedNodes(new Set());\n restart();\n },\n fitView: () => {\n if (!svgRef.current || !nodes.length) return;\n let minX = Infinity,\n maxX = -Infinity,\n minY = Infinity,\n maxY = -Infinity;\n nodes.forEach((node) => {\n if (node.x !== undefined && node.y !== undefined) {\n const size = node.size || DEFAULT_NODE_SIZE;\n minX = Math.min(minX, node.x - size);\n maxX = Math.max(maxX, node.x + size);\n minY = Math.min(minY, node.y - size);\n maxY = Math.max(maxY, node.y + size);\n }\n });\n if (!isFinite(minX)) return;\n const scale = Math.min(\n (width - FIT_VIEW_PADDING * 2) / (maxX - minX),\n (height - FIT_VIEW_PADDING * 2) / (maxY - minY),\n 10\n );\n const x = width / 2 - ((minX + maxX) / 2) * scale;\n const y = height / 2 - ((minY + maxY) / 2) * scale;\n if (gRef.current && svgRef.current) {\n const svg = d3.select(svgRef.current);\n const newTransform = d3.zoomIdentity.translate(x, y).scale(scale);\n svg\n .transition()\n .duration(TRANSITION_DURATION_MS)\n .call((d3 as any).zoom().transform as any, newTransform);\n setTransform(newTransform);\n }\n },\n getPinnedNodes: () => Array.from(pinnedNodes),\n setDragMode: (enabled: boolean) => {\n internalDragEnabledRef.current = enabled;\n },\n setLayout: (newLayout: LayoutType) => handleLayoutChange(newLayout),\n getLayout: () => layout,\n }),\n [\n nodes,\n pinnedNodes,\n restart,\n width,\n height,\n layout,\n handleLayoutChange,\n setForcesEnabled,\n ]\n );\n\n // Notify parent when manual layout mode changes\n useEffect(() => {\n if (typeof onManualLayoutChange === 'function')\n onManualLayoutChange(manualLayout);\n }, [manualLayout, onManualLayoutChange]);\n\n // Use custom hooks for zoom and window-level drag\n useGraphZoom(svgRef, gRef, enableZoom, setTransform, transformRef);\n useWindowDrag(\n enableDrag,\n svgRef,\n transformRef,\n dragActiveRef,\n dragNodeRef,\n () => {\n setForcesEnabled(true);\n restart();\n }\n );\n\n // Run positioning pass when nodes/links change\n useEffect(() => {\n if (!gRef.current) return;\n const g = d3.select(gRef.current);\n g.selectAll('g.node').each(function (this: any) {\n const datum = d3.select(this).datum() as any;\n if (!datum) return;\n d3.select(this).attr(\n 'transform',\n `translate(${datum.x || 0},${datum.y || 0})`\n );\n });\n g.selectAll('line').each(function (this: any) {\n const l = d3.select(this).datum() as any;\n if (!l) return;\n const s: any =\n typeof l.source === 'object'\n ? l.source\n : nodes.find((n) => n.id === l.source) || l.source;\n const t: any =\n typeof l.target === 'object'\n ? l.target\n : nodes.find((n) => n.id === l.target) || l.target;\n if (!s || !t) return;\n d3.select(this)\n .attr('x1', s.x)\n .attr('y1', s.y)\n .attr('x2', t.x)\n .attr('y2', t.y);\n });\n }, [nodes, initialLinks]);\n\n const handleDragStart = useCallback(\n (event: React.MouseEvent, node: GraphNode) => {\n if (!enableDrag) return;\n event.preventDefault();\n event.stopPropagation();\n dragActiveRef.current = true;\n dragNodeRef.current = node;\n pinNode(node);\n setPinnedNodes((prev) => new Set([...prev, node.id]));\n stop();\n },\n [enableDrag, stop]\n );\n\n // Attach d3.drag behavior to nodes\n useEffect(() => {\n if (!gRef.current || !enableDrag) return;\n const g = d3.select(gRef.current);\n const dragBehavior = (d3 as any)\n .drag()\n .on('start', (event: any) => {\n const target =\n (event.sourceEvent && (event.sourceEvent.target as Element)) ||\n (event.target as Element);\n const grp = target.closest?.('g.node') as Element | null;\n const id = grp?.getAttribute('data-id');\n if (!id || !internalDragEnabledRef.current) return;\n const node = nodes.find((n) => n.id === id);\n if (!node) return;\n if (!event.active) restart();\n dragActiveRef.current = true;\n dragNodeRef.current = node;\n pinNode(node);\n setPinnedNodes((prev) => new Set([...prev, node.id]));\n })\n .on('drag', (event: any) => {\n if (!dragActiveRef.current || !dragNodeRef.current) return;\n const svg = svgRef.current;\n if (!svg) return;\n const rect = svg.getBoundingClientRect();\n dragNodeRef.current.fx =\n (event.sourceEvent.clientX - rect.left - transform.x) / transform.k;\n dragNodeRef.current.fy =\n (event.sourceEvent.clientY - rect.top - transform.y) / transform.k;\n })\n .on('end', () => {\n setForcesEnabled(true);\n restart();\n });\n\n g.selectAll('g.node').call(dragBehavior as any);\n return () => {\n g.selectAll('g.node').on('.drag', null as any);\n };\n }, [\n gRef,\n enableDrag,\n nodes,\n transform,\n restart,\n setForcesEnabled,\n internalDragEnabledRef,\n ]);\n\n const handleNodeDoubleClick = useCallback(\n (event: React.MouseEvent, node: GraphNode) => {\n event.stopPropagation();\n if (!enableDrag) return;\n if (node.fx === null || node.fx === undefined) {\n pinNode(node);\n setPinnedNodes((prev) => new Set([...prev, node.id]));\n } else {\n unpinNode(node);\n setPinnedNodes((prev) => {\n const next = new Set(prev);\n next.delete(node.id);\n return next;\n });\n }\n restart();\n },\n [enableDrag, restart]\n );\n\n return (\n <svg\n ref={svgRef}\n width={width}\n height={height}\n className={cn('bg-white dark:bg-gray-900', className)}\n onDoubleClick={() => {\n unpinAllNodes(nodes);\n setPinnedNodes(new Set());\n restart();\n }}\n >\n <defs>\n <marker\n id=\"arrow\"\n viewBox=\"0 0 10 10\"\n refX=\"20\"\n refY=\"5\"\n markerWidth=\"6\"\n markerHeight=\"6\"\n orient=\"auto\"\n >\n <path d=\"M 0 0 L 10 5 L 0 10 z\" fill={defaultLinkColor} />\n </marker>\n </defs>\n\n <g ref={gRef}>\n {initialLinks.map((link, i) => (\n <LinkItem\n key={`link-${i}`}\n link={link as GraphLink}\n onClick={onLinkClick}\n defaultWidth={defaultLinkWidth}\n showLabel={showLinkLabels}\n nodes={nodes}\n />\n ))}\n\n {nodes.map((node) => (\n <NodeItem\n key={node.id}\n node={node}\n isSelected={selectedNodeId === node.id}\n isHovered={hoveredNodeId === node.id}\n pinned={pinnedNodes.has(node.id)}\n defaultNodeSize={defaultNodeSize}\n defaultNodeColor={defaultNodeColor}\n showLabel={showNodeLabels}\n onClick={onNodeClick}\n onDoubleClick={handleNodeDoubleClick}\n onMouseEnter={(n) => onNodeHover?.(n)}\n onMouseLeave={() => onNodeHover?.(null)}\n onMouseDown={handleDragStart}\n />\n ))}\n <PackageBoundaries packageBounds={packageBounds || {}} />\n </g>\n </svg>\n );\n }\n);\n\nForceDirectedGraph.displayName = 'ForceDirectedGraph';\n"]}
|
|
@@ -36,6 +36,7 @@ interface UseForceSimulationReturn {
|
|
|
36
36
|
isRunning: boolean;
|
|
37
37
|
alpha: number;
|
|
38
38
|
}
|
|
39
|
+
|
|
39
40
|
declare function useForceSimulation(initialNodes: SimulationNode[], initialLinks: SimulationLink[], options: ForceSimulationOptions): UseForceSimulationReturn & {
|
|
40
41
|
setForcesEnabled: (enabled: boolean) => void;
|
|
41
42
|
};
|
|
@@ -1,7 +1,23 @@
|
|
|
1
1
|
import { useState, useRef, useEffect } from 'react';
|
|
2
2
|
import * as d3 from 'd3';
|
|
3
3
|
|
|
4
|
-
// src/hooks/
|
|
4
|
+
// src/hooks/simulation-helpers.ts
|
|
5
|
+
function stabilizeNodes(nodes) {
|
|
6
|
+
nodes.forEach((n) => {
|
|
7
|
+
n.vx = 0;
|
|
8
|
+
n.vy = 0;
|
|
9
|
+
if (typeof n.x === "number") n.x = Number(n.x.toFixed(3));
|
|
10
|
+
if (typeof n.y === "number") n.y = Number(n.y.toFixed(3));
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
function seedRandomPositions(nodes, width, height) {
|
|
14
|
+
nodes.forEach((n) => {
|
|
15
|
+
n.x = Math.random() * width;
|
|
16
|
+
n.y = Math.random() * height;
|
|
17
|
+
n.vx = (Math.random() - 0.5) * 10;
|
|
18
|
+
n.vy = (Math.random() - 0.5) * 10;
|
|
19
|
+
});
|
|
20
|
+
}
|
|
5
21
|
function useForceSimulation(initialNodes, initialLinks, options) {
|
|
6
22
|
const {
|
|
7
23
|
chargeStrength = -300,
|
|
@@ -49,12 +65,7 @@ function useForceSimulation(initialNodes, initialLinks, options) {
|
|
|
49
65
|
n.vy = (Math.random() - 0.5) * 2;
|
|
50
66
|
});
|
|
51
67
|
} catch (e) {
|
|
52
|
-
nodesCopy
|
|
53
|
-
n.x = Math.random() * width;
|
|
54
|
-
n.y = Math.random() * height;
|
|
55
|
-
n.vx = (Math.random() - 0.5) * 10;
|
|
56
|
-
n.vy = (Math.random() - 0.5) * 10;
|
|
57
|
-
});
|
|
68
|
+
seedRandomPositions(nodesCopy, width, height);
|
|
58
69
|
}
|
|
59
70
|
const simulation = d3.forceSimulation(
|
|
60
71
|
nodesCopy
|
|
@@ -122,12 +133,7 @@ function useForceSimulation(initialNodes, initialLinks, options) {
|
|
|
122
133
|
stopTimeoutRef.current = globalThis.setTimeout(() => {
|
|
123
134
|
try {
|
|
124
135
|
if (stabilizeOnStop) {
|
|
125
|
-
nodesCopy
|
|
126
|
-
n.vx = 0;
|
|
127
|
-
n.vy = 0;
|
|
128
|
-
if (typeof n.x === "number") n.x = Number(n.x.toFixed(3));
|
|
129
|
-
if (typeof n.y === "number") n.y = Number(n.y.toFixed(3));
|
|
130
|
-
});
|
|
136
|
+
stabilizeNodes(nodesCopy);
|
|
131
137
|
}
|
|
132
138
|
simulation.alpha(0);
|
|
133
139
|
simulation.stop();
|
|
@@ -150,12 +156,7 @@ function useForceSimulation(initialNodes, initialLinks, options) {
|
|
|
150
156
|
if (simulation.alpha() <= alphaMin) {
|
|
151
157
|
try {
|
|
152
158
|
if (stabilizeOnStop) {
|
|
153
|
-
nodesCopy
|
|
154
|
-
n.vx = 0;
|
|
155
|
-
n.vy = 0;
|
|
156
|
-
if (typeof n.x === "number") n.x = Number(n.x.toFixed(3));
|
|
157
|
-
if (typeof n.y === "number") n.y = Number(n.y.toFixed(3));
|
|
158
|
-
});
|
|
159
|
+
stabilizeNodes(nodesCopy);
|
|
159
160
|
}
|
|
160
161
|
simulation.stop();
|
|
161
162
|
} catch (e) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/hooks/useForceSimulation.ts"],"names":["e"],"mappings":"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","file":"useForceSimulation.js","sourcesContent":["import { useEffect, useRef, useState } from 'react';\nimport * as d3 from 'd3';\n\nexport interface SimulationNode extends d3.SimulationNodeDatum {\n id: string;\n [key: string]: any;\n}\n\nexport interface SimulationLink extends d3.SimulationLinkDatum<SimulationNode> {\n source: string | SimulationNode;\n target: string | SimulationNode;\n [key: string]: any;\n}\n\nexport interface ForceSimulationOptions {\n /**\n * Strength of the charge force (repulsion between nodes)\n * @default -300\n */\n chargeStrength?: number;\n\n /**\n * Distance for links between nodes\n * @default 100\n */\n linkDistance?: number;\n\n /**\n * Strength of the link force\n * @default 1\n */\n linkStrength?: number;\n\n /**\n * Strength of collision detection\n * @default 1\n */\n collisionStrength?: number;\n\n /**\n * Radius for collision detection (node size)\n * @default 10\n */\n collisionRadius?: number;\n\n /**\n * Strength of centering force\n * @default 0.1\n */\n centerStrength?: number;\n\n /**\n * Width of the simulation space\n */\n width: number;\n\n /**\n * Height of the simulation space\n */\n height: number;\n\n /**\n * Alpha decay rate (how quickly the simulation cools down)\n * @default 0.0228\n */\n alphaDecay?: number;\n\n /**\n * Alpha target controls the resting energy of the simulation. When set to 0\n * the simulation will cool and stop moving once forces settle. Increase to\n * keep the graph more dynamic.\n * @default 0\n */\n alphaTarget?: number;\n\n /**\n * Warm alpha used when (re)starting the simulation to give it a small amount\n * of energy. This mirrors the Observable example which sets a modest\n * alphaTarget when dragging instead of forcing alpha to 1.\n * @default 0.3\n */\n warmAlpha?: number;\n\n /**\n * Minimum alpha threshold below which the simulation is considered cooled\n * and will stop. Increasing this makes the simulation stop earlier.\n * @default 0.01\n */\n alphaMin?: number;\n\n /**\n * When true, zero node velocities and snap positions when the simulation\n * stops to reduce residual jitter.\n * @default true\n */\n stabilizeOnStop?: boolean;\n\n /**\n * Throttle for tick updates in milliseconds to reduce update frequency\n * (helps avoid excessive React re-renders).\n * @default 33\n */\n tickThrottleMs?: number;\n\n /**\n * Maximum time (ms) to allow the simulation to run after creation/restart.\n * If the simulation hasn't cooled by this time, it will be force-stopped\n * to prevent indefinite animation. Set to 0 to disable.\n * @default 3000\n */\n maxSimulationTimeMs?: number;\n\n /**\n * Velocity decay (friction)\n * @default 0.4\n */\n velocityDecay?: number;\n\n /**\n * Optional tick callback invoked on each simulation tick with current nodes/links and the simulation instance\n */\n onTick?: (\n nodes: SimulationNode[],\n links: SimulationLink[],\n sim: d3.Simulation<SimulationNode, SimulationLink>\n ) => void;\n}\n\nexport interface UseForceSimulationReturn {\n /**\n * Current nodes with positions\n */\n nodes: SimulationNode[];\n\n /**\n * Current links\n */\n links: SimulationLink[];\n\n /**\n * Restart the simulation\n */\n restart: () => void;\n\n /**\n * Stop the simulation\n */\n stop: () => void;\n\n /**\n * Whether the simulation is currently running\n */\n isRunning: boolean;\n\n /**\n * Current alpha value (simulation heat)\n */\n alpha: number;\n}\n\n/**\n * Hook for managing d3-force simulations\n * Automatically handles simulation lifecycle, tick updates, and cleanup\n *\n * @param initialNodes - Initial nodes for the simulation\n * @param initialLinks - Initial links for the simulation\n * @param options - Configuration options for the force simulation\n * @returns Simulation state and control functions\n *\n * @example\n * ```tsx\n * function NetworkGraph() {\n * const nodes = [\n * { id: 'node1', name: 'Node 1' },\n * { id: 'node2', name: 'Node 2' },\n * { id: 'node3', name: 'Node 3' },\n * ];\n *\n * const links = [\n * { source: 'node1', target: 'node2' },\n * { source: 'node2', target: 'node3' },\n * ];\n *\n * const { nodes: simulatedNodes, links: simulatedLinks, restart } = useForceSimulation(\n * nodes,\n * links,\n * {\n * width: 800,\n * height: 600,\n * chargeStrength: -500,\n * linkDistance: 150,\n * }\n * );\n *\n * return (\n * <svg width={800} height={600}>\n * {simulatedLinks.map((link, i) => (\n * <line\n * key={i}\n * x1={(link.source as SimulationNode).x}\n * y1={(link.source as SimulationNode).y}\n * x2={(link.target as SimulationNode).x}\n * y2={(link.target as SimulationNode).y}\n * stroke=\"#999\"\n * />\n * ))}\n * {simulatedNodes.map((node) => (\n * <circle\n * key={node.id}\n * cx={node.x}\n * cy={node.y}\n * r={10}\n * fill=\"#69b3a2\"\n * />\n * ))}\n * </svg>\n * );\n * }\n * ```\n */\nexport function useForceSimulation(\n initialNodes: SimulationNode[],\n initialLinks: SimulationLink[],\n options: ForceSimulationOptions\n): UseForceSimulationReturn & { setForcesEnabled: (enabled: boolean) => void } {\n /**\n * Enable or disable the simulation forces (charge and link forces).\n * When disabled, nodes can still be dragged but won't be affected by forces.\n * @param enabled - When true, simulation forces are active; when false, forces are disabled\n */\n const {\n chargeStrength = -300,\n linkDistance = 100,\n linkStrength = 1,\n collisionStrength = 1,\n collisionRadius = 10,\n centerStrength = 0.1,\n width,\n height,\n alphaDecay = 0.0228,\n velocityDecay = 0.4,\n alphaTarget = 0,\n warmAlpha = 0.3,\n alphaMin = 0.01,\n onTick,\n // Optional throttle in milliseconds for tick updates (reduce React re-renders)\n // Lower values = smoother but more CPU; default ~30ms (~33fps)\n stabilizeOnStop = true,\n tickThrottleMs = 33,\n maxSimulationTimeMs = 3000,\n } = options;\n\n const [nodes, setNodes] = useState<SimulationNode[]>(initialNodes);\n const [links, setLinks] = useState<SimulationLink[]>(initialLinks);\n const [isRunning, setIsRunning] = useState(false);\n const [alpha, setAlpha] = useState(1);\n\n const simulationRef = useRef<d3.Simulation<\n SimulationNode,\n SimulationLink\n > | null>(null);\n const stopTimeoutRef = useRef<number | null>(null);\n\n // Create lightweight keys for nodes/links so we only recreate the simulation\n // when the actual identity/content of inputs change (not when parent passes\n // new array references on each render).\n const nodesKey = initialNodes.map((n) => n.id).join('|');\n const linksKey = (initialLinks || [])\n .map((l) => {\n const s = typeof l.source === 'string' ? l.source : (l.source as any)?.id;\n const t = typeof l.target === 'string' ? l.target : (l.target as any)?.id;\n return `${s}->${t}:${(l as any).type || ''}`;\n })\n .join('|');\n\n useEffect(() => {\n // Create a copy of nodes and links to avoid mutating the original data\n const nodesCopy = initialNodes.map((node) => ({ ...node }));\n const linksCopy = initialLinks.map((link) => ({ ...link }));\n\n // ALWAYS seed initial positions to ensure nodes don't stack at origin\n // This is critical for force-directed graphs to work properly\n try {\n // Always seed positions for all nodes when simulation is created\n // This ensures nodes start spread out even if they have coordinates\n nodesCopy.forEach((n, i) => {\n // Use deterministic but more widely spread positions based on index\n const angle = (i * 2 * Math.PI) / nodesCopy.length;\n // Larger seed radius to encourage an initial spread\n const radius = Math.min(width, height) * 0.45;\n n.x = width / 2 + radius * Math.cos(angle);\n n.y = height / 2 + radius * Math.sin(angle);\n // Add very small random velocity to avoid large initial motion\n (n as any).vx = (Math.random() - 0.5) * 2;\n (n as any).vy = (Math.random() - 0.5) * 2;\n });\n } catch (e) {\n void e;\n // If error, fall back to random positions\n nodesCopy.forEach((n) => {\n n.x = Math.random() * width;\n n.y = Math.random() * height;\n (n as any).vx = (Math.random() - 0.5) * 10;\n (n as any).vy = (Math.random() - 0.5) * 10;\n });\n }\n\n // Create the simulation\n const simulation = d3.forceSimulation(\n nodesCopy as any\n ) as unknown as d3.Simulation<SimulationNode, SimulationLink>;\n\n // Configure link force separately to avoid using generic type args on d3 helpers\n try {\n const linkForce = d3.forceLink(\n linksCopy as any\n ) as unknown as d3.ForceLink<SimulationNode, SimulationLink>;\n linkForce\n .id((d: any) => d.id)\n .distance((d: any) =>\n d && d.distance != null ? d.distance : linkDistance\n )\n .strength(linkStrength);\n simulation.force('link', linkForce as any);\n } catch (e) {\n void e;\n // fallback: attach a plain link force\n try {\n simulation.force('link', d3.forceLink(linksCopy as any) as any);\n } catch (e) {\n void e;\n }\n }\n try {\n simulation.force(\n 'charge',\n d3.forceManyBody().strength(chargeStrength) as any\n );\n simulation.force(\n 'center',\n d3.forceCenter(width / 2, height / 2).strength(centerStrength) as any\n );\n const collide = d3\n .forceCollide()\n .radius((d: any) => {\n const nodeSize = d && d.size ? d.size : 10;\n return nodeSize + collisionRadius;\n })\n .strength(collisionStrength as any) as any;\n simulation.force('collision', collide);\n simulation.force(\n 'x',\n d3\n .forceX(width / 2)\n .strength(Math.max(0.02, centerStrength * 0.5)) as any\n );\n simulation.force(\n 'y',\n d3\n .forceY(height / 2)\n .strength(Math.max(0.02, centerStrength * 0.5)) as any\n );\n simulation.alphaDecay(alphaDecay);\n simulation.velocityDecay(velocityDecay);\n simulation.alphaMin(alphaMin);\n try {\n simulation.alphaTarget(alphaTarget);\n } catch (e) {\n void e;\n }\n try {\n simulation.alpha(warmAlpha);\n } catch (e) {\n void e;\n }\n } catch (e) {\n void e;\n // ignore force configuration errors\n }\n\n simulationRef.current = simulation;\n\n // Force-stop timeout to ensure simulation doesn't run forever.\n if (stopTimeoutRef.current != null) {\n try {\n (globalThis.clearTimeout as any)(stopTimeoutRef.current);\n } catch (e) {\n void e;\n }\n stopTimeoutRef.current = null;\n }\n if (maxSimulationTimeMs && maxSimulationTimeMs > 0) {\n stopTimeoutRef.current = (globalThis.setTimeout as any)(() => {\n try {\n if (stabilizeOnStop) {\n nodesCopy.forEach((n) => {\n (n as any).vx = 0;\n (n as any).vy = 0;\n if (typeof n.x === 'number') n.x = Number(n.x.toFixed(3));\n if (typeof n.y === 'number') n.y = Number(n.y.toFixed(3));\n });\n }\n simulation.alpha(0);\n simulation.stop();\n } catch (e) {\n void e;\n }\n setIsRunning(false);\n setNodes([...nodesCopy]);\n setLinks([...linksCopy]);\n }, maxSimulationTimeMs) as unknown as number;\n }\n\n // Update state on each tick. Batch updates via requestAnimationFrame to avoid\n // excessive React re-renders which can cause visual flicker.\n let rafId: number | null = null;\n let lastUpdate = 0;\n const tickHandler = () => {\n try {\n if (typeof onTick === 'function')\n onTick(nodesCopy, linksCopy, simulation);\n } catch (e) {\n void e;\n }\n\n // If simulation alpha has cooled below the configured minimum, stop it to\n // ensure nodes don't drift indefinitely (acts as a hard-stop safeguard).\n try {\n if (simulation.alpha() <= (alphaMin as number)) {\n try {\n if (stabilizeOnStop) {\n nodesCopy.forEach((n) => {\n (n as any).vx = 0;\n (n as any).vy = 0;\n if (typeof n.x === 'number') n.x = Number(n.x.toFixed(3));\n if (typeof n.y === 'number') n.y = Number(n.y.toFixed(3));\n });\n }\n simulation.stop();\n } catch (e) {\n void e;\n }\n setAlpha(simulation.alpha());\n setIsRunning(false);\n setNodes([...nodesCopy]);\n setLinks([...linksCopy]);\n return;\n }\n } catch (e) {\n void e;\n }\n\n const now = Date.now();\n const shouldUpdate = now - lastUpdate >= (tickThrottleMs as number);\n if (rafId == null && shouldUpdate) {\n rafId = (\n globalThis.requestAnimationFrame ||\n ((cb: FrameRequestCallback) => setTimeout(cb, 16))\n )(() => {\n rafId = null;\n lastUpdate = Date.now();\n setNodes([...nodesCopy]);\n setLinks([...linksCopy]);\n setAlpha(simulation.alpha());\n setIsRunning(simulation.alpha() > simulation.alphaMin());\n }) as unknown as number;\n }\n };\n\n simulation.on('tick', tickHandler);\n\n simulation.on('end', () => {\n setIsRunning(false);\n });\n\n // Cleanup on unmount\n return () => {\n try {\n simulation.on('tick', null as any);\n } catch (e) {\n void e;\n }\n if (stopTimeoutRef.current != null) {\n try {\n (globalThis.clearTimeout as any)(stopTimeoutRef.current);\n } catch (e) {\n void e;\n }\n stopTimeoutRef.current = null;\n }\n if (rafId != null) {\n try {\n (\n globalThis.cancelAnimationFrame ||\n ((id: number) => clearTimeout(id))\n )(rafId);\n } catch (e) {\n void e;\n }\n rafId = null;\n }\n simulation.stop();\n };\n }, [\n nodesKey,\n linksKey,\n chargeStrength,\n linkDistance,\n linkStrength,\n collisionStrength,\n collisionRadius,\n centerStrength,\n width,\n height,\n alphaDecay,\n velocityDecay,\n alphaTarget,\n alphaMin,\n stabilizeOnStop,\n tickThrottleMs,\n maxSimulationTimeMs,\n ]);\n\n const restart = () => {\n if (simulationRef.current) {\n // Reheat the simulation to a modest alpha target rather than forcing\n // full heat; this matches the Observable pattern and helps stability.\n try {\n simulationRef.current.alphaTarget(warmAlpha).restart();\n } catch {\n simulationRef.current.restart();\n }\n setIsRunning(true);\n // Reset safety timeout when simulation is manually restarted\n if (stopTimeoutRef.current != null) {\n try {\n (globalThis.clearTimeout as any)(stopTimeoutRef.current);\n } catch (e) {\n void e;\n }\n stopTimeoutRef.current = null;\n }\n if (maxSimulationTimeMs && maxSimulationTimeMs > 0) {\n stopTimeoutRef.current = (globalThis.setTimeout as any)(() => {\n try {\n simulationRef.current?.alpha(0);\n simulationRef.current?.stop();\n } catch (e) {\n void e;\n }\n setIsRunning(false);\n }, maxSimulationTimeMs) as unknown as number;\n }\n }\n };\n\n const stop = () => {\n if (simulationRef.current) {\n simulationRef.current.stop();\n setIsRunning(false);\n }\n };\n\n const originalForcesRef = useRef({\n charge: chargeStrength,\n link: linkStrength,\n collision: collisionStrength,\n });\n const forcesEnabledRef = useRef(true);\n\n const setForcesEnabled = (enabled: boolean) => {\n const sim = simulationRef.current;\n if (!sim) return;\n // avoid repeated updates\n if (forcesEnabledRef.current === enabled) return;\n forcesEnabledRef.current = enabled;\n\n try {\n // Only toggle charge and link forces to avoid collapse; keep collision/centering\n const charge: any = sim.force('charge');\n if (charge && typeof charge.strength === 'function') {\n charge.strength(enabled ? originalForcesRef.current.charge : 0);\n }\n\n const link: any = sim.force('link');\n if (link && typeof link.strength === 'function') {\n link.strength(enabled ? originalForcesRef.current.link : 0);\n }\n } catch (e) {\n void e;\n }\n };\n\n return {\n nodes,\n links,\n restart,\n stop,\n isRunning,\n alpha,\n setForcesEnabled,\n };\n}\n\n/**\n * Hook for creating a draggable force simulation\n * Provides drag handlers that can be attached to node elements\n *\n * @param simulation - The d3 force simulation instance\n * @returns Drag behavior that can be applied to nodes\n *\n * @example\n * ```tsx\n * function DraggableNetworkGraph() {\n * const simulation = useRef<d3.Simulation<SimulationNode, SimulationLink>>();\n * const drag = useDrag(simulation.current);\n *\n * return (\n * <svg>\n * {nodes.map((node) => (\n * <circle\n * key={node.id}\n * {...drag}\n * cx={node.x}\n * cy={node.y}\n * r={10}\n * />\n * ))}\n * </svg>\n * );\n * }\n * ```\n */\nexport function useDrag(\n simulation: d3.Simulation<SimulationNode, any> | null | undefined\n) {\n const dragStarted = (event: any, node: SimulationNode) => {\n if (!simulation) return;\n if (!event.active) simulation.alphaTarget(0.3).restart();\n node.fx = node.x;\n node.fy = node.y;\n };\n\n const dragged = (event: any, node: SimulationNode) => {\n node.fx = event.x;\n node.fy = event.y;\n };\n\n const dragEnded = (event: any, node: SimulationNode) => {\n if (!simulation) return;\n if (!event.active) simulation.alphaTarget(0);\n node.fx = null;\n node.fy = null;\n };\n\n return {\n onDragStart: dragStarted,\n onDrag: dragged,\n onDragEnd: dragEnded,\n };\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/hooks/simulation-helpers.ts","../../src/hooks/useForceSimulation.ts"],"names":["e"],"mappings":"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","file":"useForceSimulation.js","sourcesContent":["import { SimulationNode } from './simulation-types';\n\n/**\n * Stabilizes nodes by zeroing velocities and rounding positions.\n * Extracted to reduce duplicate patterns in useForceSimulation.\n */\nexport function stabilizeNodes(nodes: SimulationNode[]): void {\n nodes.forEach((n) => {\n (n as any).vx = 0;\n (n as any).vy = 0;\n if (typeof n.x === 'number') n.x = Number(n.x.toFixed(3));\n if (typeof n.y === 'number') n.y = Number(n.y.toFixed(3));\n });\n}\n\n/**\n * Seeds nodes with random positions within bounds.\n * Used as fallback when initial positioning fails.\n */\nexport function seedRandomPositions(\n nodes: SimulationNode[],\n width: number,\n height: number\n): void {\n nodes.forEach((n) => {\n n.x = Math.random() * width;\n n.y = Math.random() * height;\n (n as any).vx = (Math.random() - 0.5) * 10;\n (n as any).vy = (Math.random() - 0.5) * 10;\n });\n}\n","// Re-export types from separate module for backward compatibility\nexport {\n type SimulationNode,\n type SimulationLink,\n type ForceSimulationOptions,\n type UseForceSimulationReturn,\n} from './simulation-types';\n\n// Import helpers from separate module\nimport { stabilizeNodes, seedRandomPositions } from './simulation-helpers';\nimport type {\n SimulationNode,\n SimulationLink,\n ForceSimulationOptions,\n UseForceSimulationReturn,\n} from './simulation-types';\n\nimport { useEffect, useRef, useState } from 'react';\nimport * as d3 from 'd3';\n\n/**\n * Hook for managing d3-force simulations\n * Automatically handles simulation lifecycle, tick updates, and cleanup\n *\n * @param initialNodes - Initial nodes for the simulation\n * @param initialLinks - Initial links for the simulation\n * @param options - Configuration options for the force simulation\n * @returns Simulation state and control functions\n *\n * @example\n * ```tsx\n * function NetworkGraph() {\n * const nodes = [\n * { id: 'node1', name: 'Node 1' },\n * { id: 'node2', name: 'Node 2' },\n * { id: 'node3', name: 'Node 3' },\n * ];\n *\n * const links = [\n * { source: 'node1', target: 'node2' },\n * { source: 'node2', target: 'node3' },\n * ];\n *\n * const { nodes: simulatedNodes, links: simulatedLinks, restart } = useForceSimulation(\n * nodes,\n * links,\n * {\n * width: 800,\n * height: 600,\n * chargeStrength: -500,\n * linkDistance: 150,\n * }\n * );\n *\n * return (\n * <svg width={800} height={600}>\n * {simulatedLinks.map((link, i) => (\n * <line\n * key={i}\n * x1={(link.source as SimulationNode).x}\n * y1={(link.source as SimulationNode).y}\n * x2={(link.target as SimulationNode).x}\n * y2={(link.target as SimulationNode).y}\n * stroke=\"#999\"\n * />\n * ))}\n * {simulatedNodes.map((node) => (\n * <circle\n * key={node.id}\n * cx={node.x}\n * cy={node.y}\n * r={10}\n * fill=\"#69b3a2\"\n * />\n * ))}\n * </svg>\n * );\n * }\n * ```\n */\nexport function useForceSimulation(\n initialNodes: SimulationNode[],\n initialLinks: SimulationLink[],\n options: ForceSimulationOptions\n): UseForceSimulationReturn & { setForcesEnabled: (enabled: boolean) => void } {\n /**\n * Enable or disable the simulation forces (charge and link forces).\n * When disabled, nodes can still be dragged but won't be affected by forces.\n * @param enabled - When true, simulation forces are active; when false, forces are disabled\n */\n const {\n chargeStrength = -300,\n linkDistance = 100,\n linkStrength = 1,\n collisionStrength = 1,\n collisionRadius = 10,\n centerStrength = 0.1,\n width,\n height,\n alphaDecay = 0.0228,\n velocityDecay = 0.4,\n alphaTarget = 0,\n warmAlpha = 0.3,\n alphaMin = 0.01,\n onTick,\n // Optional throttle in milliseconds for tick updates (reduce React re-renders)\n // Lower values = smoother but more CPU; default ~30ms (~33fps)\n stabilizeOnStop = true,\n tickThrottleMs = 33,\n maxSimulationTimeMs = 3000,\n } = options;\n\n const [nodes, setNodes] = useState<SimulationNode[]>(initialNodes);\n const [links, setLinks] = useState<SimulationLink[]>(initialLinks);\n const [isRunning, setIsRunning] = useState(false);\n const [alpha, setAlpha] = useState(1);\n\n const simulationRef = useRef<d3.Simulation<\n SimulationNode,\n SimulationLink\n > | null>(null);\n const stopTimeoutRef = useRef<number | null>(null);\n\n // Create lightweight keys for nodes/links so we only recreate the simulation\n // when the actual identity/content of inputs change (not when parent passes\n // new array references on each render).\n const nodesKey = initialNodes.map((n) => n.id).join('|');\n const linksKey = (initialLinks || [])\n .map((l) => {\n const s = typeof l.source === 'string' ? l.source : (l.source as any)?.id;\n const t = typeof l.target === 'string' ? l.target : (l.target as any)?.id;\n return `${s}->${t}:${(l as any).type || ''}`;\n })\n .join('|');\n\n useEffect(() => {\n // Create a copy of nodes and links to avoid mutating the original data\n const nodesCopy = initialNodes.map((node) => ({ ...node }));\n const linksCopy = initialLinks.map((link) => ({ ...link }));\n\n // ALWAYS seed initial positions to ensure nodes don't stack at origin\n // This is critical for force-directed graphs to work properly\n try {\n // Always seed positions for all nodes when simulation is created\n // This ensures nodes start spread out even if they have coordinates\n nodesCopy.forEach((n, i) => {\n // Use deterministic but more widely spread positions based on index\n const angle = (i * 2 * Math.PI) / nodesCopy.length;\n // Larger seed radius to encourage an initial spread\n const radius = Math.min(width, height) * 0.45;\n n.x = width / 2 + radius * Math.cos(angle);\n n.y = height / 2 + radius * Math.sin(angle);\n // Add very small random velocity to avoid large initial motion\n (n as any).vx = (Math.random() - 0.5) * 2;\n (n as any).vy = (Math.random() - 0.5) * 2;\n });\n } catch (e) {\n void e;\n // If error, fall back to random positions\n seedRandomPositions(nodesCopy, width, height);\n }\n\n // Create the simulation\n const simulation = d3.forceSimulation(\n nodesCopy as any\n ) as unknown as d3.Simulation<SimulationNode, SimulationLink>;\n\n // Configure link force separately to avoid using generic type args on d3 helpers\n try {\n const linkForce = d3.forceLink(\n linksCopy as any\n ) as unknown as d3.ForceLink<SimulationNode, SimulationLink>;\n linkForce\n .id((d: any) => d.id)\n .distance((d: any) =>\n d && d.distance != null ? d.distance : linkDistance\n )\n .strength(linkStrength);\n simulation.force('link', linkForce as any);\n } catch (e) {\n void e;\n // fallback: attach a plain link force\n try {\n simulation.force('link', d3.forceLink(linksCopy as any) as any);\n } catch (e) {\n void e;\n }\n }\n try {\n simulation.force(\n 'charge',\n d3.forceManyBody().strength(chargeStrength) as any\n );\n simulation.force(\n 'center',\n d3.forceCenter(width / 2, height / 2).strength(centerStrength) as any\n );\n const collide = d3\n .forceCollide()\n .radius((d: any) => {\n const nodeSize = d && d.size ? d.size : 10;\n return nodeSize + collisionRadius;\n })\n .strength(collisionStrength as any) as any;\n simulation.force('collision', collide);\n simulation.force(\n 'x',\n d3\n .forceX(width / 2)\n .strength(Math.max(0.02, centerStrength * 0.5)) as any\n );\n simulation.force(\n 'y',\n d3\n .forceY(height / 2)\n .strength(Math.max(0.02, centerStrength * 0.5)) as any\n );\n simulation.alphaDecay(alphaDecay);\n simulation.velocityDecay(velocityDecay);\n simulation.alphaMin(alphaMin);\n try {\n simulation.alphaTarget(alphaTarget);\n } catch (e) {\n void e;\n }\n try {\n simulation.alpha(warmAlpha);\n } catch (e) {\n void e;\n }\n } catch (e) {\n void e;\n // ignore force configuration errors\n }\n\n simulationRef.current = simulation;\n\n // Force-stop timeout to ensure simulation doesn't run forever.\n if (stopTimeoutRef.current != null) {\n try {\n (globalThis.clearTimeout as any)(stopTimeoutRef.current);\n } catch (e) {\n void e;\n }\n stopTimeoutRef.current = null;\n }\n if (maxSimulationTimeMs && maxSimulationTimeMs > 0) {\n stopTimeoutRef.current = (globalThis.setTimeout as any)(() => {\n try {\n if (stabilizeOnStop) {\n stabilizeNodes(nodesCopy);\n }\n simulation.alpha(0);\n simulation.stop();\n } catch (e) {\n void e;\n }\n setIsRunning(false);\n setNodes([...nodesCopy]);\n setLinks([...linksCopy]);\n }, maxSimulationTimeMs) as unknown as number;\n }\n\n // Update state on each tick. Batch updates via requestAnimationFrame to avoid\n // excessive React re-renders which can cause visual flicker.\n let rafId: number | null = null;\n let lastUpdate = 0;\n const tickHandler = () => {\n try {\n if (typeof onTick === 'function')\n onTick(nodesCopy, linksCopy, simulation);\n } catch (e) {\n void e;\n }\n\n // If simulation alpha has cooled below the configured minimum, stop it to\n // ensure nodes don't drift indefinitely (acts as a hard-stop safeguard).\n try {\n if (simulation.alpha() <= (alphaMin as number)) {\n try {\n if (stabilizeOnStop) {\n stabilizeNodes(nodesCopy);\n }\n simulation.stop();\n } catch (e) {\n void e;\n }\n setAlpha(simulation.alpha());\n setIsRunning(false);\n setNodes([...nodesCopy]);\n setLinks([...linksCopy]);\n return;\n }\n } catch (e) {\n void e;\n }\n\n const now = Date.now();\n const shouldUpdate = now - lastUpdate >= (tickThrottleMs as number);\n if (rafId == null && shouldUpdate) {\n rafId = (\n globalThis.requestAnimationFrame ||\n ((cb: FrameRequestCallback) => setTimeout(cb, 16))\n )(() => {\n rafId = null;\n lastUpdate = Date.now();\n setNodes([...nodesCopy]);\n setLinks([...linksCopy]);\n setAlpha(simulation.alpha());\n setIsRunning(simulation.alpha() > simulation.alphaMin());\n }) as unknown as number;\n }\n };\n\n simulation.on('tick', tickHandler);\n\n simulation.on('end', () => {\n setIsRunning(false);\n });\n\n // Cleanup on unmount\n return () => {\n try {\n simulation.on('tick', null as any);\n } catch (e) {\n void e;\n }\n if (stopTimeoutRef.current != null) {\n try {\n (globalThis.clearTimeout as any)(stopTimeoutRef.current);\n } catch (e) {\n void e;\n }\n stopTimeoutRef.current = null;\n }\n if (rafId != null) {\n try {\n (\n globalThis.cancelAnimationFrame ||\n ((id: number) => clearTimeout(id))\n )(rafId);\n } catch (e) {\n void e;\n }\n rafId = null;\n }\n simulation.stop();\n };\n }, [\n nodesKey,\n linksKey,\n chargeStrength,\n linkDistance,\n linkStrength,\n collisionStrength,\n collisionRadius,\n centerStrength,\n width,\n height,\n alphaDecay,\n velocityDecay,\n alphaTarget,\n alphaMin,\n stabilizeOnStop,\n tickThrottleMs,\n maxSimulationTimeMs,\n ]);\n\n const restart = () => {\n if (simulationRef.current) {\n // Reheat the simulation to a modest alpha target rather than forcing\n // full heat; this matches the Observable pattern and helps stability.\n try {\n simulationRef.current.alphaTarget(warmAlpha).restart();\n } catch {\n simulationRef.current.restart();\n }\n setIsRunning(true);\n // Reset safety timeout when simulation is manually restarted\n if (stopTimeoutRef.current != null) {\n try {\n (globalThis.clearTimeout as any)(stopTimeoutRef.current);\n } catch (e) {\n void e;\n }\n stopTimeoutRef.current = null;\n }\n if (maxSimulationTimeMs && maxSimulationTimeMs > 0) {\n stopTimeoutRef.current = (globalThis.setTimeout as any)(() => {\n try {\n simulationRef.current?.alpha(0);\n simulationRef.current?.stop();\n } catch (e) {\n void e;\n }\n setIsRunning(false);\n }, maxSimulationTimeMs) as unknown as number;\n }\n }\n };\n\n const stop = () => {\n if (simulationRef.current) {\n simulationRef.current.stop();\n setIsRunning(false);\n }\n };\n\n const originalForcesRef = useRef({\n charge: chargeStrength,\n link: linkStrength,\n collision: collisionStrength,\n });\n const forcesEnabledRef = useRef(true);\n\n const setForcesEnabled = (enabled: boolean) => {\n const sim = simulationRef.current;\n if (!sim) return;\n // avoid repeated updates\n if (forcesEnabledRef.current === enabled) return;\n forcesEnabledRef.current = enabled;\n\n try {\n // Only toggle charge and link forces to avoid collapse; keep collision/centering\n const charge: any = sim.force('charge');\n if (charge && typeof charge.strength === 'function') {\n charge.strength(enabled ? originalForcesRef.current.charge : 0);\n }\n\n const link: any = sim.force('link');\n if (link && typeof link.strength === 'function') {\n link.strength(enabled ? originalForcesRef.current.link : 0);\n }\n } catch (e) {\n void e;\n }\n };\n\n return {\n nodes,\n links,\n restart,\n stop,\n isRunning,\n alpha,\n setForcesEnabled,\n };\n}\n\n/**\n * Hook for creating a draggable force simulation\n * Provides drag handlers that can be attached to node elements\n *\n * @param simulation - The d3 force simulation instance\n * @returns Drag behavior that can be applied to nodes\n *\n * @example\n * ```tsx\n * function DraggableNetworkGraph() {\n * const simulation = useRef<d3.Simulation<SimulationNode, SimulationLink>>();\n * const drag = useDrag(simulation.current);\n *\n * return (\n * <svg>\n * {nodes.map((node) => (\n * <circle\n * key={node.id}\n * {...drag}\n * cx={node.x}\n * cy={node.y}\n * r={10}\n * />\n * ))}\n * </svg>\n * );\n * }\n * ```\n */\nexport function useDrag(\n simulation: d3.Simulation<SimulationNode, any> | null | undefined\n) {\n const dragStarted = (event: any, node: SimulationNode) => {\n if (!simulation) return;\n if (!event.active) simulation.alphaTarget(0.3).restart();\n node.fx = node.x;\n node.fy = node.y;\n };\n\n const dragged = (event: any, node: SimulationNode) => {\n node.fx = event.x;\n node.fy = event.y;\n };\n\n const dragEnded = (event: any, node: SimulationNode) => {\n if (!simulation) return;\n if (!event.active) simulation.alphaTarget(0);\n node.fx = null;\n node.fy = null;\n };\n\n return {\n onDragStart: dragStarted,\n onDrag: dragged,\n onDragEnd: dragEnded,\n };\n}\n"]}
|
package/dist/index.d.ts
CHANGED
|
@@ -44,30 +44,30 @@ interface IconBaseProps extends React.SVGProps<SVGSVGElement> {
|
|
|
44
44
|
viewBox?: string;
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
-
declare function AlertCircleIcon(props: IconBaseProps):
|
|
48
|
-
declare function AlertTriangleIcon(props: IconBaseProps):
|
|
49
|
-
declare function ArrowRightIcon(props: IconBaseProps):
|
|
50
|
-
declare function BrainIcon(props: IconBaseProps):
|
|
47
|
+
declare function AlertCircleIcon(props: IconBaseProps): React$1.ReactElement<unknown, string | React$1.JSXElementConstructor<any>>;
|
|
48
|
+
declare function AlertTriangleIcon(props: IconBaseProps): React$1.ReactElement<unknown, string | React$1.JSXElementConstructor<any>>;
|
|
49
|
+
declare function ArrowRightIcon(props: IconBaseProps): React$1.ReactElement<unknown, string | React$1.JSXElementConstructor<any>>;
|
|
50
|
+
declare function BrainIcon(props: IconBaseProps): React$1.ReactElement<unknown, string | React$1.JSXElementConstructor<any>>;
|
|
51
51
|
declare function ChartIcon(props: IconBaseProps): react_jsx_runtime.JSX.Element;
|
|
52
|
-
declare function ClockIcon(props: IconBaseProps):
|
|
53
|
-
declare function FileIcon(props: IconBaseProps):
|
|
54
|
-
declare function HammerIcon(props: IconBaseProps):
|
|
55
|
-
declare function InfoIcon(props: IconBaseProps):
|
|
56
|
-
declare function PlayIcon(props: IconBaseProps):
|
|
57
|
-
declare function RefreshCwIcon(props: IconBaseProps):
|
|
52
|
+
declare function ClockIcon(props: IconBaseProps): React$1.ReactElement<unknown, string | React$1.JSXElementConstructor<any>>;
|
|
53
|
+
declare function FileIcon(props: IconBaseProps): React$1.ReactElement<unknown, string | React$1.JSXElementConstructor<any>>;
|
|
54
|
+
declare function HammerIcon(props: IconBaseProps): React$1.ReactElement<unknown, string | React$1.JSXElementConstructor<any>>;
|
|
55
|
+
declare function InfoIcon(props: IconBaseProps): React$1.ReactElement<unknown, string | React$1.JSXElementConstructor<any>>;
|
|
56
|
+
declare function PlayIcon(props: IconBaseProps): React$1.ReactElement<unknown, string | React$1.JSXElementConstructor<any>>;
|
|
57
|
+
declare function RefreshCwIcon(props: IconBaseProps): React$1.ReactElement<unknown, string | React$1.JSXElementConstructor<any>>;
|
|
58
58
|
declare function RobotIcon(props: IconBaseProps): react_jsx_runtime.JSX.Element;
|
|
59
59
|
declare function RocketIcon(props: IconBaseProps): react_jsx_runtime.JSX.Element;
|
|
60
|
-
declare function SaveIcon(props: IconBaseProps):
|
|
61
|
-
declare function SettingsIcon(props: IconBaseProps):
|
|
62
|
-
declare function ShieldCheckIcon(props: IconBaseProps):
|
|
63
|
-
declare function ShieldIcon(props: IconBaseProps):
|
|
60
|
+
declare function SaveIcon(props: IconBaseProps): React$1.ReactElement<unknown, string | React$1.JSXElementConstructor<any>>;
|
|
61
|
+
declare function SettingsIcon(props: IconBaseProps): React$1.ReactElement<unknown, string | React$1.JSXElementConstructor<any>>;
|
|
62
|
+
declare function ShieldCheckIcon(props: IconBaseProps): React$1.ReactElement<unknown, string | React$1.JSXElementConstructor<any>>;
|
|
63
|
+
declare function ShieldIcon(props: IconBaseProps): React$1.ReactElement<unknown, string | React$1.JSXElementConstructor<any>>;
|
|
64
64
|
declare function TargetIcon(props: IconBaseProps): react_jsx_runtime.JSX.Element;
|
|
65
|
-
declare function TerminalIcon(props: IconBaseProps):
|
|
66
|
-
declare function TrashIcon(props: IconBaseProps):
|
|
67
|
-
declare function TrendingUpIcon(props: IconBaseProps):
|
|
68
|
-
declare function UploadIcon(props: IconBaseProps):
|
|
69
|
-
declare function WalletIcon(props: IconBaseProps):
|
|
70
|
-
declare function ZapIcon(props: IconBaseProps):
|
|
65
|
+
declare function TerminalIcon(props: IconBaseProps): React$1.ReactElement<unknown, string | React$1.JSXElementConstructor<any>>;
|
|
66
|
+
declare function TrashIcon(props: IconBaseProps): React$1.ReactElement<unknown, string | React$1.JSXElementConstructor<any>>;
|
|
67
|
+
declare function TrendingUpIcon(props: IconBaseProps): React$1.ReactElement<unknown, string | React$1.JSXElementConstructor<any>>;
|
|
68
|
+
declare function UploadIcon(props: IconBaseProps): React$1.ReactElement<unknown, string | React$1.JSXElementConstructor<any>>;
|
|
69
|
+
declare function WalletIcon(props: IconBaseProps): React$1.ReactElement<unknown, string | React$1.JSXElementConstructor<any>>;
|
|
70
|
+
declare function ZapIcon(props: IconBaseProps): React$1.ReactElement<unknown, string | React$1.JSXElementConstructor<any>>;
|
|
71
71
|
|
|
72
72
|
interface CodeBlockProps {
|
|
73
73
|
children: React__default.ReactNode;
|