@aiready/visualizer 0.7.5 → 0.7.6
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/cli.js +7 -9
- package/dist/cli.js.map +1 -1
- package/dist/graph/index.js +7 -9
- package/dist/graph/index.js.map +1 -1
- package/dist/index.js +7 -9
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/web/dist/assets/index-C8KyAlJg.js.map +1 -1
- package/web/src/components/GraphCanvas.tsx +65 -76
|
@@ -17,6 +17,17 @@ interface GraphCanvasProps {
|
|
|
17
17
|
onNodeClick: (node: FileNode | null) => void;
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
+
interface D3Node extends d3.SimulationNodeDatum, FileNode {
|
|
21
|
+
fx?: number | null;
|
|
22
|
+
fy?: number | null;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
interface D3Link extends d3.SimulationLinkDatum<D3Node> {
|
|
26
|
+
source: D3Node;
|
|
27
|
+
target: D3Node;
|
|
28
|
+
type: string;
|
|
29
|
+
}
|
|
30
|
+
|
|
20
31
|
export function GraphCanvas({
|
|
21
32
|
data,
|
|
22
33
|
dimensions,
|
|
@@ -42,18 +53,18 @@ export function GraphCanvas({
|
|
|
42
53
|
const svgGroup = svg.append('g');
|
|
43
54
|
|
|
44
55
|
// Setup zoom
|
|
45
|
-
const zoom =
|
|
46
|
-
.zoom()
|
|
56
|
+
const zoom = d3
|
|
57
|
+
.zoom<SVGSVGElement, unknown>()
|
|
47
58
|
.scaleExtent([GRAPH_CONFIG.zoomMin, GRAPH_CONFIG.zoomMax])
|
|
48
|
-
.on('zoom', (event:
|
|
49
|
-
svgGroup.attr('transform', event.transform);
|
|
59
|
+
.on('zoom', (event: d3.D3ZoomEvent<SVGSVGElement, unknown>) => {
|
|
60
|
+
svgGroup.attr('transform', event.transform.toString());
|
|
50
61
|
zoomTransformRef.current = event.transform;
|
|
51
62
|
});
|
|
52
63
|
svg.call(zoom);
|
|
53
64
|
svg.call(zoom.transform, zoomTransformRef.current);
|
|
54
65
|
|
|
55
66
|
// Prepare nodes and links
|
|
56
|
-
const nodes = data.nodes.map((d, i) => {
|
|
67
|
+
const nodes: D3Node[] = data.nodes.map((d, i) => {
|
|
57
68
|
// Initialize nodes in a circle around center with slight random spread
|
|
58
69
|
const angle = (i / data.nodes.length) * Math.PI * 2;
|
|
59
70
|
const radius = 50 + Math.random() * 30;
|
|
@@ -63,22 +74,28 @@ export function GraphCanvas({
|
|
|
63
74
|
y: height / 2 + Math.sin(angle) * radius,
|
|
64
75
|
};
|
|
65
76
|
});
|
|
66
|
-
const links = data.edges.map((d) =>
|
|
77
|
+
const links: D3Link[] = data.edges.map((d) => {
|
|
78
|
+
// Find source and target nodes to satisfy D3Link interface
|
|
79
|
+
const source = nodes.find((n) => n.id === d.source) || nodes[0];
|
|
80
|
+
const target = nodes.find((n) => n.id === d.target) || nodes[0];
|
|
81
|
+
return {
|
|
82
|
+
...d,
|
|
83
|
+
source,
|
|
84
|
+
target,
|
|
85
|
+
type: d.type || 'default',
|
|
86
|
+
};
|
|
87
|
+
});
|
|
67
88
|
|
|
68
89
|
// Create force simulation
|
|
69
90
|
const simulation = d3
|
|
70
|
-
.forceSimulation(nodes
|
|
91
|
+
.forceSimulation<D3Node>(nodes)
|
|
71
92
|
.force(
|
|
72
93
|
'link',
|
|
73
94
|
d3
|
|
74
|
-
.forceLink(links)
|
|
75
|
-
.id((d
|
|
76
|
-
.distance((d
|
|
77
|
-
|
|
78
|
-
)
|
|
79
|
-
.strength((d: unknown) =>
|
|
80
|
-
getEdgeStrength((d as { type: string }).type)
|
|
81
|
-
)
|
|
95
|
+
.forceLink<D3Node, D3Link>(links)
|
|
96
|
+
.id((d) => d.id)
|
|
97
|
+
.distance((d) => getEdgeDistance(d.type))
|
|
98
|
+
.strength((d) => getEdgeStrength(d.type))
|
|
82
99
|
)
|
|
83
100
|
.force(
|
|
84
101
|
'charge',
|
|
@@ -87,15 +104,15 @@ export function GraphCanvas({
|
|
|
87
104
|
.force('center', d3.forceCenter(width / 2, height / 2))
|
|
88
105
|
.force(
|
|
89
106
|
'collision',
|
|
90
|
-
d3.forceCollide().radius(GRAPH_CONFIG.collisionRadius)
|
|
107
|
+
d3.forceCollide<D3Node>().radius(GRAPH_CONFIG.collisionRadius)
|
|
91
108
|
)
|
|
92
109
|
.force(
|
|
93
110
|
'x',
|
|
94
|
-
d3.forceX(width / 2).strength(GRAPH_CONFIG.simulation.centerStrength)
|
|
111
|
+
d3.forceX<D3Node>(width / 2).strength(GRAPH_CONFIG.simulation.centerStrength)
|
|
95
112
|
)
|
|
96
113
|
.force(
|
|
97
114
|
'y',
|
|
98
|
-
d3.forceY(height / 2).strength(GRAPH_CONFIG.simulation.centerStrength)
|
|
115
|
+
d3.forceY<D3Node>(height / 2).strength(GRAPH_CONFIG.simulation.centerStrength)
|
|
99
116
|
);
|
|
100
117
|
|
|
101
118
|
// Create link group
|
|
@@ -105,17 +122,9 @@ export function GraphCanvas({
|
|
|
105
122
|
.data(links)
|
|
106
123
|
.enter()
|
|
107
124
|
.append('line')
|
|
108
|
-
.attr(
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
edgeColors[(d as { type: string }).type] || edgeColors.default
|
|
112
|
-
)
|
|
113
|
-
.attr('stroke-opacity', (d: unknown) =>
|
|
114
|
-
getEdgeOpacity((d as { type: string }).type)
|
|
115
|
-
)
|
|
116
|
-
.attr('stroke-width', (d: unknown) =>
|
|
117
|
-
getEdgeStrokeWidth((d as { type: string }).type)
|
|
118
|
-
);
|
|
125
|
+
.attr('stroke', (d) => edgeColors[d.type] || edgeColors.default)
|
|
126
|
+
.attr('stroke-opacity', (d) => getEdgeOpacity(d.type))
|
|
127
|
+
.attr('stroke-width', (d) => getEdgeStrokeWidth(d.type));
|
|
119
128
|
|
|
120
129
|
// Create node group
|
|
121
130
|
const nodeGroup = svgGroup.append('g').attr('class', 'nodes');
|
|
@@ -127,42 +136,27 @@ export function GraphCanvas({
|
|
|
127
136
|
.append('g')
|
|
128
137
|
.attr('cursor', 'pointer')
|
|
129
138
|
.call(
|
|
130
|
-
|
|
131
|
-
.drag()
|
|
139
|
+
d3
|
|
140
|
+
.drag<SVGGElement, D3Node>()
|
|
132
141
|
.on('start', dragstarted)
|
|
133
142
|
.on('drag', dragged)
|
|
134
|
-
.on('end', dragended)
|
|
143
|
+
.on('end', dragended)
|
|
135
144
|
);
|
|
136
145
|
|
|
137
146
|
// Add circles to nodes
|
|
138
147
|
node
|
|
139
148
|
.append('circle')
|
|
140
|
-
.attr(
|
|
141
|
-
|
|
142
|
-
(d: unknown) =>
|
|
143
|
-
Math.sqrt((d as { value: number }).value || 10) +
|
|
144
|
-
GRAPH_CONFIG.nodeBaseRadius
|
|
145
|
-
)
|
|
146
|
-
.attr(
|
|
147
|
-
'fill',
|
|
148
|
-
(d: unknown) => (d as { color: string }).color || severityColors.default
|
|
149
|
-
)
|
|
149
|
+
.attr('r', (d) => Math.sqrt(d.value || 10) + GRAPH_CONFIG.nodeBaseRadius)
|
|
150
|
+
.attr('fill', (d) => d.color || severityColors.default)
|
|
150
151
|
.attr('stroke', effectiveTheme === 'dark' ? '#fff' : '#000')
|
|
151
152
|
.attr('stroke-width', 1.5);
|
|
152
153
|
|
|
153
154
|
// Add labels to nodes
|
|
154
155
|
node
|
|
155
156
|
.append('text')
|
|
156
|
-
.text(
|
|
157
|
-
(d: unknown) =>
|
|
158
|
-
(d as { label: string }).label.split('/').pop() ||
|
|
159
|
-
(d as { label: string }).label
|
|
160
|
-
)
|
|
157
|
+
.text((d) => d.label.split('/').pop() || d.label)
|
|
161
158
|
.attr('x', 0)
|
|
162
|
-
.attr(
|
|
163
|
-
'y',
|
|
164
|
-
(d: unknown) => Math.sqrt((d as { value: number }).value || 10) + 12
|
|
165
|
-
)
|
|
159
|
+
.attr('y', (d) => Math.sqrt(d.value || 10) + 12)
|
|
166
160
|
.attr('text-anchor', 'middle')
|
|
167
161
|
.attr('fill', effectiveTheme === 'dark' ? '#e2e8f0' : '#1e293b')
|
|
168
162
|
.attr('font-size', '9px')
|
|
@@ -170,47 +164,42 @@ export function GraphCanvas({
|
|
|
170
164
|
.attr('pointer-events', 'none');
|
|
171
165
|
|
|
172
166
|
// Add tooltips
|
|
173
|
-
node.append('title').text((d
|
|
167
|
+
node.append('title').text((d) => d.title || '');
|
|
174
168
|
|
|
175
169
|
// Event handlers
|
|
176
|
-
node.on('click', (event:
|
|
177
|
-
|
|
178
|
-
onNodeClick(d
|
|
170
|
+
node.on('click', (event: MouseEvent, d: D3Node) => {
|
|
171
|
+
event.stopPropagation();
|
|
172
|
+
onNodeClick(d);
|
|
179
173
|
});
|
|
180
174
|
svg.on('click', () => onNodeClick(null));
|
|
181
175
|
|
|
182
176
|
// Simulation tick
|
|
183
177
|
simulation.on('tick', () => {
|
|
184
178
|
link
|
|
185
|
-
.attr('x1', (d
|
|
186
|
-
.attr('y1', (d
|
|
187
|
-
.attr('x2', (d
|
|
188
|
-
.attr('y2', (d
|
|
179
|
+
.attr('x1', (d) => (d.source as D3Node).x || 0)
|
|
180
|
+
.attr('y1', (d) => (d.source as D3Node).y || 0)
|
|
181
|
+
.attr('x2', (d) => (d.target as D3Node).x || 0)
|
|
182
|
+
.attr('y2', (d) => (d.target as D3Node).y || 0);
|
|
189
183
|
|
|
190
|
-
node.attr(
|
|
191
|
-
'transform',
|
|
192
|
-
(d: unknown) =>
|
|
193
|
-
`translate(${(d as { x: number }).x},${(d as { y: number }).y})`
|
|
194
|
-
);
|
|
184
|
+
node.attr('transform', (d) => `translate(${d.x || 0},${d.y || 0})`);
|
|
195
185
|
});
|
|
196
186
|
|
|
197
187
|
// Drag functions
|
|
198
|
-
function dragstarted(event:
|
|
199
|
-
if (!
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
(d as { fy: number | null }).fy = (d as { y: number }).y;
|
|
188
|
+
function dragstarted(event: d3.D3DragEvent<SVGGElement, D3Node, D3Node>, d: D3Node) {
|
|
189
|
+
if (!event.active) simulation.alphaTarget(0.3).restart();
|
|
190
|
+
d.fx = d.x;
|
|
191
|
+
d.fy = d.y;
|
|
203
192
|
}
|
|
204
193
|
|
|
205
|
-
function dragged(event:
|
|
206
|
-
|
|
207
|
-
|
|
194
|
+
function dragged(event: d3.D3DragEvent<SVGGElement, D3Node, D3Node>, d: D3Node) {
|
|
195
|
+
d.fx = event.x;
|
|
196
|
+
d.fy = event.y;
|
|
208
197
|
}
|
|
209
198
|
|
|
210
|
-
function dragended(event:
|
|
211
|
-
if (!
|
|
212
|
-
|
|
213
|
-
|
|
199
|
+
function dragended(event: d3.D3DragEvent<SVGGElement, D3Node, D3Node>, d: D3Node) {
|
|
200
|
+
if (!event.active) simulation.alphaTarget(0);
|
|
201
|
+
d.fx = null;
|
|
202
|
+
d.fy = null;
|
|
214
203
|
}
|
|
215
204
|
|
|
216
205
|
return () => {
|