-
Notifications
You must be signed in to change notification settings - Fork 49
Expand file tree
/
Copy pathForceGraph.tsx
More file actions
163 lines (143 loc) · 5.03 KB
/
ForceGraph.tsx
File metadata and controls
163 lines (143 loc) · 5.03 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
"use client"
import { useCallback, useEffect, useRef, useState } from "react"
import type { Data } from "@falkordb/canvas"
import { GraphRef } from "@/lib/utils"
import { GraphData, Link, Node } from "./model"
interface Props {
data: GraphData
canvasRef: GraphRef
onNodeClick?: (node: Node, event: MouseEvent) => void
onNodeRightClick?: (node: Node, event: MouseEvent) => void
onLinkClick?: (link: Link, event: MouseEvent) => void
onLinkRightClick?: (link: Link, event: MouseEvent) => void
onBackgroundClick?: (event: MouseEvent) => void
onBackgroundRightClick?: (event: MouseEvent) => void
onZoom?: () => void
onEngineStop?: () => void
onNodeDragEnd?: (node: Node, translate: { x: number; y: number }) => void
cooldownTicks?: number | undefined
backgroundColor?: string
foregroundColor?: string
}
const convertToCanvasData = (graphData: GraphData): Data => ({
nodes: graphData.nodes.filter(n => n.visible).map(({ id, category, color, visible, name, ...data }) => ({
id,
labels: [category],
color,
visible,
data: { name, ...data }
})),
links: graphData.links.filter(l => l.visible).map(({ id, label, color, visible, source, target, ...data }) => ({
id,
relationship: label,
color,
visible,
source,
target,
data
}))
});
export default function ForceGraph({
data,
canvasRef,
onNodeClick,
onNodeRightClick,
onLinkClick,
onLinkRightClick,
onBackgroundClick,
onBackgroundRightClick,
onZoom,
onEngineStop,
cooldownTicks,
backgroundColor = "#FFFFFF",
foregroundColor = "#000000"
}: Props) {
const [canvasLoaded, setCanvasLoaded] = useState(false)
// Load falkordb-canvas dynamically (client-only)
useEffect(() => {
import('@falkordb/canvas').then(() => {
setCanvasLoaded(true)
})
}, [])
// Update canvas colors
useEffect(() => {
if (!canvasRef.current || !canvasLoaded) return
canvasRef.current.setBackgroundColor(backgroundColor)
canvasRef.current.setForegroundColor(foregroundColor)
}, [canvasRef, backgroundColor, foregroundColor, canvasLoaded])
// Update cooldown ticks
useEffect(() => {
if (!canvasRef.current || !canvasLoaded) return
canvasRef.current.setCooldownTicks(cooldownTicks)
}, [canvasRef, cooldownTicks, canvasLoaded])
// Map node click handler
const handleNodeClick = useCallback((node: any, event: MouseEvent) => {
if (onNodeClick) {
const originalNode = data.nodes.find(n => n.id === node.id)
if (originalNode) onNodeClick(originalNode, event)
}
}, [onNodeClick, data.nodes])
// Map node right click handler
const handleNodeRightClick = useCallback((node: any, event: MouseEvent) => {
if (onNodeRightClick) {
const originalNode = data.nodes.find(n => n.id === node.id)
if (originalNode) onNodeRightClick(originalNode, event)
}
}, [onNodeRightClick, data.nodes])
// Map link click handler
const handleLinkClick = useCallback((link: any, event: MouseEvent) => {
if (onLinkClick) {
const originalLink = data.links.find(l => l.id === link.id)
if (originalLink) onLinkClick(originalLink, event)
}
}, [onLinkClick, data.links])
// Map link right click handler
const handleLinkRightClick = useCallback((link: any, event: MouseEvent) => {
if (onLinkRightClick) {
const originalLink = data.links.find(l => l.id === link.id)
if (originalLink) onLinkRightClick(originalLink, event)
}
}, [onLinkRightClick, data.links])
// Handle engine stop and set window.graph
const handleEngineStop = useCallback(() => {
const canvas = canvasRef.current
if (!canvas) return
(window as any).graph = () => canvas.getGraphData();
if (onEngineStop) onEngineStop()
}, [canvasRef, onEngineStop])
// Update event handlers
useEffect(() => {
if (!canvasRef.current || !canvasLoaded) return
canvasRef.current.setConfig({
onNodeClick: handleNodeClick,
onNodeRightClick: handleNodeRightClick,
onLinkClick: handleLinkClick,
onLinkRightClick: handleLinkRightClick,
onBackgroundClick,
onBackgroundRightClick,
onEngineStop: handleEngineStop,
onZoom
})
}, [
handleNodeClick,
handleNodeRightClick,
handleLinkClick,
handleLinkRightClick,
onBackgroundClick,
onBackgroundRightClick,
handleEngineStop,
onZoom,
canvasRef,
canvasLoaded
])
// Update canvas data
useEffect(() => {
const canvas = canvasRef.current
if (!canvas || !canvasLoaded) return
const canvasData = convertToCanvasData(data)
canvas.setData(canvasData)
}, [canvasRef, data, canvasLoaded])
return (
<falkordb-canvas ref={canvasRef} />
)
}