@@ -4,7 +4,7 @@ import "@xyflow/react/dist/style.css";
4
4
5
5
import { scheme } from "vega-scale" ;
6
6
import { ErrorBoundary } from "react-error-boundary" ;
7
- import ELK , { ElkExtendedEdge , ElkNode , ElkPrimitiveEdge } from "elkjs/lib/elk.bundled.js" ;
7
+ import ELK , { ElkNode , ElkPrimitiveEdge } from "elkjs/lib/elk.bundled.js" ;
8
8
import { memo , startTransition , Suspense , use , useCallback , useEffect , useMemo , useState } from "react" ;
9
9
import {
10
10
ReactFlow ,
@@ -36,8 +36,10 @@ const layoutOptions = {
36
36
"elk.direction" : "DOWN" ,
37
37
"elk.portConstraints" : "FIXED_SIDE" ,
38
38
"elk.hierarchyHandling" : "INCLUDE_CHILDREN" ,
39
- "elk.layered.mergeEdges" : "True" ,
39
+ // "elk.layered.mergeEdges": "True",
40
40
"elk.edgeRouting" : "ORTHOGONAL" ,
41
+ "elk.layered.nodePlacement.strategy" : "NETWORK_SIMPLEX" ,
42
+
41
43
// "elk.layered.edgeRouting.splines.mode": "CONSERVATIVE_SOFT",
42
44
// "elk.layered.spacing.baseValue": "40",
43
45
// "elk.layered.nodePlacement.strategy": "NETWORK_SIMPLEX",
@@ -156,12 +158,12 @@ function toELKNode(
156
158
id : `class-${ id } ` ,
157
159
data : { color : type_to_color . get ( egraph . class_data [ id ] ?. type ) || null , port : `port-${ id } ` , id } ,
158
160
ports : [
159
- {
160
- id : `port-${ id } ` ,
161
- layoutOptions : {
162
- "port.side" : "SOUTH " ,
163
- } ,
164
- } ,
161
+ // {
162
+ // id: `port-${id}`,
163
+ // layoutOptions: {
164
+ // "port.side": "NORTH ",
165
+ // },
166
+ // },
165
167
] ,
166
168
type : "class" ,
167
169
children : nodes . map ( ( [ id , node ] ) => {
@@ -184,6 +186,29 @@ function toELKNode(
184
186
ports,
185
187
} ;
186
188
} ) ,
189
+ edges : nodes . flatMap ( ( [ id , node ] ) =>
190
+ [ ...node . children . entries ( ) ] . flatMap ( ( [ index , childNode ] ) => {
191
+ const sourcePort = `port-${ id } -${ index } ` ;
192
+ const class_ = nodeToClass . get ( childNode ) ! ;
193
+ // only include if this is a self loop
194
+ if ( class_ != id ) {
195
+ return [ ] ;
196
+ }
197
+ // If the target or source class is not in the selected nodes, don't draw the edge
198
+ const targetPort = `port-${ class_ } ` ;
199
+ return [
200
+ {
201
+ id : `edge-${ id } -${ index } ` ,
202
+ source : `node-${ id } ` ,
203
+ sourcePort,
204
+ sourceHandle : sourcePort ,
205
+ target : `class-${ class_ } ` ,
206
+ targetPort,
207
+ targetHandle : targetPort ,
208
+ } ,
209
+ ] ;
210
+ } )
211
+ ) ,
187
212
} ;
188
213
} ) ;
189
214
@@ -192,7 +217,11 @@ function toELKNode(
192
217
const sourcePort = `port-${ id } -${ index } ` ;
193
218
const class_ = nodeToClass . get ( childNode ) ! ;
194
219
// If the target or source class is not in the selected nodes, don't draw the edge
195
- if ( ! classToNodes . get ( node . eclass ) ?. find ( ( [ sourceID , _ ] ) => sourceID == id ) || ! classToNodes . has ( class_ ) ) {
220
+ if (
221
+ ! classToNodes . get ( node . eclass ) ?. find ( ( [ sourceID ] ) => sourceID == id ) ||
222
+ ! classToNodes . has ( class_ ) ||
223
+ class_ == nodeToClass . get ( id )
224
+ ) {
196
225
return [ ] ;
197
226
}
198
227
const targetPort = `port-${ class_ } ` ;
@@ -213,7 +242,7 @@ function toELKNode(
213
242
id : "--eclipse-layout-kernel-root" ,
214
243
layoutOptions,
215
244
children,
216
- edges : edges as unknown as ElkExtendedEdge [ ] ,
245
+ edges,
217
246
} ;
218
247
}
219
248
@@ -233,7 +262,7 @@ function toFlowNodes(layout: MyELKNodeLayedOut): Node[] {
233
262
] ) ;
234
263
}
235
264
236
- export function EClassNode ( { data } : { data : { port : string ; color : string } } ) {
265
+ export function EClassNode ( { data } : { data : { port : string ; color : string ; id : string } } ) {
237
266
return (
238
267
< div className = "rounded-md border border-dotted border-stone-400 h-full w-full" style = { { backgroundColor : data . color } } >
239
268
< Handle className = "top-0 bottom-0 opacity-0 translate-0" type = "target" id = { data . port } position = { Position . Top } />
@@ -245,7 +274,7 @@ export function ENode({
245
274
data,
246
275
...rest
247
276
} : {
248
- data : { label : string ; ports : { id : string } [ ] } ;
277
+ data : { label : string ; ports : { id : string } [ ] ; id : string } ;
249
278
outerRef ?: React . Ref < HTMLDivElement > ;
250
279
innerRef ?: React . Ref < HTMLDivElement > ;
251
280
} ) {
@@ -284,7 +313,10 @@ function LayoutFlow({ egraph, outerElem, innerElem }: { egraph: string; outerEle
284
313
// console.log(JSON.parse(JSON.stringify(r, null, 2)));
285
314
return r ;
286
315
} , [ parsedEGraph , outerElem , innerElem , selectedNode ] ) ;
287
- const edges = useMemo ( ( ) => elkNode . edges ! . map ( ( e ) => ( { ...e } ) ) , [ elkNode ] ) ;
316
+ const edges = useMemo (
317
+ ( ) => [ ...elkNode . children . flatMap ( ( c ) => c . edges ! . map ( ( e ) => ( { ...e } ) ) ) , ...elkNode . edges ! . map ( ( e ) => ( { ...e } ) ) ] ,
318
+ [ elkNode ]
319
+ ) ;
288
320
const layoutPromise = useMemo ( ( ) => elk . layout ( elkNode ) as Promise < MyELKNodeLayedOut > , [ elkNode ] ) ;
289
321
const layout = use ( layoutPromise ) ;
290
322
const nodes = useMemo ( ( ) => toFlowNodes ( layout ) , [ layout ] ) ;
0 commit comments