MCPcopy
hub / github.com/supermemoryai/supermemory / useGraphData

Function useGraphData

packages/memory-graph/src/hooks/use-graph-data.ts:458–630  ·  view source on GitHub ↗
(
	documents: GraphApiDocument[],
	draggingNodeId: string | null,
	canvasWidth: number,
	canvasHeight: number,
	colors: GraphThemeColors,
)

Source from the content-addressed store, hash-verified

456}
457
458export function useGraphData(
459 documents: GraphApiDocument[],
460 draggingNodeId: string | null,
461 canvasWidth: number,
462 canvasHeight: number,
463 colors: GraphThemeColors,
464) {
465 const nodeCache = useRef<Map<string, GraphNode>>(new Map())
466
467 const graphData = useMemo<{
468 nodes: GraphNode[]
469 cache: Map<string, GraphNode>
470 }>(() => {
471 if (!documents || documents.length === 0) {
472 return { nodes: [], cache: new Map<string, GraphNode>() }
473 }
474
475 const currentIds = new Set<string>()
476 for (const doc of documents) {
477 currentIds.add(doc.id)
478 for (const mem of doc.memories) currentIds.add(mem.id)
479 }
480
481 const previousCache = nodeCache.current
482 const nextCache = new Map<string, GraphNode>()
483 const appendPlacementNodes = Array.from(previousCache.values()).filter(
484 (node) => currentIds.has(node.id),
485 )
486 const shouldAppendNewNodes = appendPlacementNodes.length > 0
487 const appendBaseBounds = shouldAppendNewNodes
488 ? getNodeBounds(appendPlacementNodes)
489 : null
490 const appendSpatialGrid =
491 shouldAppendNewNodes && appendBaseBounds
492 ? buildAppendSpatialGrid(appendPlacementNodes)
493 : null
494 let appendIndex = 0
495 const clusterAssignments = computeClusterAssignments(documents)
496
497 const result: GraphNode[] = []
498 // Spiral layout: documents form a compact spiral core, memories orbit
499 // around their parent documents. The force simulation then gently
500 // pushes memories outward to create the constellation/starburst effect.
501 const cx = canvasWidth / 2
502 const cy = canvasHeight / 2
503 const docCount = documents.length
504 // Wide spiral so documents start well-separated. The simulation
505 // refines positions but the initial spread prevents clustering.
506 const spiralScale = Math.sqrt(docCount) * 60
507 // Golden angle (~137.5 deg) produces optimal packing in a spiral
508 const goldenAngle = Math.PI * (3 - Math.sqrt(5))
509
510 for (let docIdx = 0; docIdx < docCount; docIdx++) {
511 const doc = documents[docIdx]
512 const docCluster = getDocumentClusterAssignment(doc, clusterAssignments)
513 const angle = docIdx * goldenAngle
514 const radius = spiralScale * Math.sqrt((docIdx + 1) / docCount)
515 const initialX = cx + Math.cos(angle) * radius

Callers 1

MemoryGraphFunction · 0.90

Calls 12

getNodeBoundsFunction · 0.85
buildAppendSpatialGridFunction · 0.85
getAppendPositionFunction · 0.85
addAppendSpatialNodeFunction · 0.85
getMemoryNodeBorderColorFunction · 0.85
getMemoryOrbitOffsetFunction · 0.85
hasMethod · 0.80
getMethod · 0.80
setMethod · 0.80
computeEdgesFunction · 0.70

Tested by

no test coverage detected

Used in the wild real call sites across dependent graphs

searching dependent graphs…