@@ -621,6 +621,8 @@ function GraphD3(_selector: HTMLDivElement, _options: any): IGraphD3 {
621
621
let info : any
622
622
let nodes : INode [ ]
623
623
let relationship : d3 . Selection < SVGGElement , IRelationship , SVGGElement , any >
624
+ let labelCounter = 0 ;
625
+ let labels : { [ key : string ] : number } = { }
624
626
let relationshipOutline
625
627
let relationshipOverlay
626
628
let relationshipText
@@ -644,7 +646,7 @@ function GraphD3(_selector: HTMLDivElement, _options: any): IGraphD3 {
644
646
const options = { ...DEFAULT_OPTIONS , ..._options }
645
647
let zoom : d3 . ZoomBehavior < Element , unknown > = options . graphZoom
646
648
647
- const { labelColors, edgeColors} = options
649
+ const { labelColors, edgeColors } = options
648
650
649
651
function color ( ) {
650
652
return COLORS [ Math . floor ( Math . random ( ) * COLORS . length ) ]
@@ -725,11 +727,15 @@ function GraphD3(_selector: HTMLDivElement, _options: any): IGraphD3 {
725
727
. html ( `<strong>${ property } </strong> ${ value } ` )
726
728
}
727
729
728
- function stickNode ( event , d ) {
730
+ function stickNode ( ele , event , d ) {
729
731
/* eslint-disable */
730
732
d . fx = event . x
731
733
d . fy = event . y
732
734
/* eslint-enable */
735
+
736
+ // Add a ring to specify that the node was selected
737
+ d3 . select ( ele ) . attr ( 'class' , 'node selected' )
738
+
733
739
}
734
740
735
741
function dragEnded ( event , d ) {
@@ -743,7 +749,7 @@ function GraphD3(_selector: HTMLDivElement, _options: any): IGraphD3 {
743
749
}
744
750
745
751
function dragged ( event , d ) {
746
- stickNode ( event , d )
752
+ stickNode ( this , event , d )
747
753
}
748
754
749
755
function dragStarted ( event , d ) {
@@ -812,13 +818,29 @@ function GraphD3(_selector: HTMLDivElement, _options: any): IGraphD3 {
812
818
}
813
819
} )
814
820
. on ( 'dblclick' , function onNodeDoubleClick ( event , d ) {
815
- stickNode ( event , d )
821
+ stickNode ( this , event , d )
816
822
817
823
if ( typeof options . onNodeDoubleClick === 'function' ) {
818
824
options . onNodeDoubleClick ( this , d , event )
819
825
}
820
826
821
- d3 . select ( '.graphd3-graph' ) . transition ( ) . call ( zoom . translateTo as any , d . x , d . y )
827
+ [ ...new Set ( nodes . map ( n => n . labels [ 0 ] ) ) ] . forEach ( l => {
828
+ if ( labels [ l ] === undefined ) {
829
+ labels [ l ] = labelCounter
830
+ labelCounter += 1
831
+ }
832
+ } )
833
+
834
+ // Pulse on double click
835
+ Utils . pulse ( d3 . select ( event . currentTarget ) . select ( '.outline' ) ) ;
836
+
837
+ // Calculating the next positio of the node takes some times
838
+ // so start transition only after the calculation. So delay
839
+ // starting the transition by some milliseconds.
840
+ setTimeout ( ( ) => d3 . select ( '.graphd3-graph' )
841
+ . transition ( )
842
+ . duration ( 500 )
843
+ . call ( zoom . translateTo as any , d . x , d . y ) , 10 )
822
844
} )
823
845
. on ( 'mouseenter' , function onNodeMouseEnter ( event , d ) {
824
846
if ( info ) {
@@ -1252,26 +1274,20 @@ function GraphD3(_selector: HTMLDivElement, _options: any): IGraphD3 {
1252
1274
function initSimulation ( ) {
1253
1275
const spreadFactor = 1.25
1254
1276
return d3 . forceSimulation ( )
1255
- // .force('x', d3.forceCollide().strength(0.002))
1256
- // .force('y', d3.forceCollide().strength(0.002))
1257
- // .force('y', d3.force().strength(0.002))
1258
- . velocityDecay ( 0.4 )
1259
- . force ( 'collide' , d3 . forceCollide ( ) . radius ( ( ) => options . minCollision * spreadFactor ) . iterations ( 10 ) )
1260
- . force ( 'charge' , d3 . forceManyBody ( ) . strength ( - 400 ) )
1261
- . force ( 'link' , d3 . forceLink ( ) . id ( ( d : IRelationship ) => d . id ) )
1262
- . force ( 'center' , d3 . forceCenter ( svg . node ( ) . parentElement . parentElement . clientWidth / 2 ,
1263
- svg . node ( ) . parentElement . parentElement . clientHeight / 2 ) )
1264
- . force ( 'centerX' , d3 . forceX ( 0 ) . strength ( 0.03 ) )
1265
- . force ( 'centerX' , d3 . forceX ( 0 ) . strength ( 0.03 ) )
1266
- . on ( 'tick' , ( ) => {
1267
- tick ( )
1268
- } )
1269
- . on ( 'end' , ( ) => {
1270
- if ( options . zoomFit && ! justLoaded ) {
1271
- justLoaded = true
1272
- zoomFit ( )
1273
- }
1274
- } )
1277
+ . force ( 'link' , d3 . forceLink ( ) . id ( ( d : IRelationship ) => d . id ) . distance ( 70 ) )
1278
+ . force ( 'charge' , d3 . forceManyBody ( ) . strength ( ( d , i ) => i ? - 5000 : 500 ) )
1279
+ . force ( "y" , d3 . forceY ( svg . node ( ) . parentElement . parentElement . clientHeight / 2 ) )
1280
+ . force ( 'center' , d3 . forceCenter ( svg . node ( ) . parentElement . parentElement . clientWidth / 2 ,
1281
+ svg . node ( ) . parentElement . parentElement . clientHeight / 2 ) )
1282
+ . on ( 'tick' , ( ) => {
1283
+ tick ( )
1284
+ } )
1285
+ . on ( 'end' , ( ) => {
1286
+ if ( options . zoomFit && ! justLoaded ) {
1287
+ justLoaded = true
1288
+ zoomFit ( )
1289
+ }
1290
+ } )
1275
1291
}
1276
1292
1277
1293
function init ( ) {
@@ -1298,7 +1314,22 @@ function GraphD3(_selector: HTMLDivElement, _options: any): IGraphD3 {
1298
1314
} else {
1299
1315
console . error ( 'Error: graphData is empty!' )
1300
1316
}
1301
- }
1317
+
1318
+ [ ...new Set ( nodes . map ( n => n . labels [ 0 ] ) ) ] . forEach ( l => {
1319
+ if ( labels [ l ] === undefined ) {
1320
+ labels [ l ] = labelCounter
1321
+ labelCounter += 1
1322
+ }
1323
+ } ) ;
1324
+
1325
+ simulation
1326
+ . force ( "x" , d3 . forceX ( d => d . angleX || 0 ) )
1327
+ . force ( "y" , d3 . forceY ( d => d . angleY || 0 ) )
1328
+ . force ( 'center' , d3 . forceCenter ( svg . node ( ) . parentElement . parentElement . clientWidth / 2 ,
1329
+ svg . node ( ) . parentElement . parentElement . clientHeight / 2 ) )
1330
+ . force ( 'centerX' , d3 . forceX ( 0 ) . strength ( 0.03 ) )
1331
+ . force ( 'centerX' , d3 . forceX ( 0 ) . strength ( 0.03 ) )
1332
+ }
1302
1333
1303
1334
init ( )
1304
1335
@@ -1421,10 +1452,12 @@ function GraphD3(_selector: HTMLDivElement, _options: any): IGraphD3 {
1421
1452
1422
1453
1423
1454
function mapData ( d : IGraph ) {
1424
- d . relationships . map ( ( r ) => {
1455
+ d . relationships . map ( r => {
1425
1456
let source = findNode ( r . startNode , d . nodes )
1426
1457
let target = findNode ( r . endNode , d . nodes ) ;
1427
1458
1459
+ source . links = source . links ? Array . from ( new Set ( [ ...source . links , target . labels [ 0 ] ] ) ) : [ target . labels [ 0 ] ] ;
1460
+
1428
1461
( r . source = source ) ,
1429
1462
( r . target = target ) ,
1430
1463
( r . naturalAngle = 0 ) ,
@@ -1433,6 +1466,37 @@ function GraphD3(_selector: HTMLDivElement, _options: any): IGraphD3 {
1433
1466
} )
1434
1467
return r
1435
1468
} )
1469
+
1470
+ nodes . map ( n => {
1471
+ if ( n . links !== undefined ) {
1472
+ let labels = { }
1473
+ n . links . forEach ( ( l , i ) => {
1474
+ labels [ l ] = i ;
1475
+ } ) ;
1476
+
1477
+ const equalAngles = 360 / Object . keys ( labels ) . length
1478
+ let angleIterator = 0
1479
+ Object . keys ( labels ) . map ( l => {
1480
+ labels [ l ] = angleIterator ;
1481
+ angleIterator += equalAngles ;
1482
+ } ) ;
1483
+
1484
+ n . targetLabels = labels ;
1485
+ }
1486
+ } )
1487
+
1488
+ d . relationships . map ( r => {
1489
+ const radius = 1300
1490
+ const onlyOne = Object . keys ( r . source . targetLabels ) . length === 1
1491
+
1492
+ const degree = Math . PI * 2 * r . source . targetLabels [ r . target . labels [ 0 ] ] / 360 ;
1493
+ const angleX = onlyOne ? 0 : radius * Math . sin ( degree )
1494
+ const angleY = onlyOne ? 0 : radius * Math . cos ( degree )
1495
+
1496
+ r . target . angleX = angleX ;
1497
+ r . target . angleY = angleY ;
1498
+ } )
1499
+
1436
1500
}
1437
1501
1438
1502
function groupedRelationships ( ) : NodePair [ ] {
@@ -1441,7 +1505,7 @@ function GraphD3(_selector: HTMLDivElement, _options: any): IGraphD3 {
1441
1505
} = { }
1442
1506
for ( const relationship of Array . from ( relationships ) ) {
1443
1507
let nodePair = new NodePair ( relationship . source , relationship . target )
1444
- nodePair = groups [ nodePair . toString ( ) ] != null ? groups [ nodePair . toString ( ) ] : nodePair
1508
+ nodePair = groups [ nodePair . toString ( ) ] != null ? groups [ nodePair . toString ( ) ] : nodePair
1445
1509
nodePair . relationships . push ( relationship )
1446
1510
groups [ nodePair . toString ( ) ] = nodePair
1447
1511
}
0 commit comments