@@ -23,6 +23,8 @@ var repeat = gup.repeat;
23
23
var unwrap = gup . unwrap ;
24
24
var interpolateNumber = require ( 'd3-interpolate' ) . interpolateNumber ;
25
25
26
+ var Plotly = require ( '../../plot_api/plot_api' ) ;
27
+
26
28
// view models
27
29
28
30
function sankeyModel ( layout , d , traceIndex ) {
@@ -163,6 +165,25 @@ function sankeyModel(layout, d, traceIndex) {
163
165
}
164
166
computeLinkConcentrations ( ) ;
165
167
168
+ // Force node position
169
+ if ( trace . node . x . length !== 0 && trace . node . y . length !== 0 ) {
170
+ var i ;
171
+ for ( i = 0 ; i < Math . min ( trace . node . x . length , trace . node . y . length , graph . nodes . length ) ; i ++ ) {
172
+ if ( trace . node . x [ i ] && trace . node . y [ i ] ) {
173
+ var pos = [ trace . node . x [ i ] * width , trace . node . y [ i ] * height ] ;
174
+ graph . nodes [ i ] . x0 = pos [ 0 ] - nodeThickness / 2 ;
175
+ graph . nodes [ i ] . x1 = pos [ 0 ] + nodeThickness / 2 ;
176
+
177
+ var nodeHeight = graph . nodes [ i ] . y1 - graph . nodes [ i ] . y0 ;
178
+ graph . nodes [ i ] . y0 = pos [ 1 ] - nodeHeight / 2 ;
179
+ graph . nodes [ i ] . y1 = pos [ 1 ] + nodeHeight / 2 ;
180
+ }
181
+ }
182
+ // Update links
183
+ sankey . update ( graph ) ;
184
+ }
185
+
186
+
166
187
return {
167
188
circular : circular ,
168
189
key : traceIndex ,
@@ -399,6 +420,7 @@ function nodeModel(d, n) {
399
420
partOfGroup : n . partOfGroup || false ,
400
421
group : n . group ,
401
422
traceId : d . key ,
423
+ trace : d . trace ,
402
424
node : n ,
403
425
nodePad : d . nodePad ,
404
426
nodeLineColor : d . nodeLineColor ,
@@ -425,7 +447,8 @@ function nodeModel(d, n) {
425
447
graph : d . graph ,
426
448
arrangement : d . arrangement ,
427
449
uniqueNodeLabelPathId : [ d . guid , d . key , key ] . join ( '_' ) ,
428
- interactionState : d . interactionState
450
+ interactionState : d . interactionState ,
451
+ figure : d
429
452
} ;
430
453
}
431
454
@@ -509,7 +532,7 @@ function attachPointerEvents(selection, sankey, eventSet) {
509
532
} ) ;
510
533
}
511
534
512
- function attachDragHandler ( sankeyNode , sankeyLink , callbacks ) {
535
+ function attachDragHandler ( sankeyNode , sankeyLink , callbacks , gd ) {
513
536
var dragBehavior = d3 . behavior . drag ( )
514
537
. origin ( function ( d ) {
515
538
return {
@@ -520,6 +543,9 @@ function attachDragHandler(sankeyNode, sankeyLink, callbacks) {
520
543
521
544
. on ( 'dragstart' , function ( d ) {
522
545
if ( d . arrangement === 'fixed' ) return ;
546
+ Lib . ensureSingle ( gd . _fullLayout . _infolayer , 'g' , 'dragcover' , function ( s ) {
547
+ gd . _fullLayout . _dragCover = s ;
548
+ } ) ;
523
549
Lib . raiseToTop ( this ) ;
524
550
d . interactionState . dragInProgress = d . node ;
525
551
@@ -533,9 +559,9 @@ function attachDragHandler(sankeyNode, sankeyLink, callbacks) {
533
559
if ( d . forceLayouts [ forceKey ] ) {
534
560
d . forceLayouts [ forceKey ] . alpha ( 1 ) ;
535
561
} else { // make a forceLayout if needed
536
- attachForce ( sankeyNode , forceKey , d ) ;
562
+ attachForce ( sankeyNode , forceKey , d , gd ) ;
537
563
}
538
- startForce ( sankeyNode , sankeyLink , d , forceKey ) ;
564
+ startForce ( sankeyNode , sankeyLink , d , forceKey , gd ) ;
539
565
}
540
566
} )
541
567
@@ -553,8 +579,9 @@ function attachDragHandler(sankeyNode, sankeyLink, callbacks) {
553
579
d . node . x0 = x - d . visibleWidth / 2 ;
554
580
d . node . x1 = x + d . visibleWidth / 2 ;
555
581
}
556
- d . node . y0 = Math . max ( 0 , Math . min ( d . size - d . visibleHeight , y ) ) ;
557
- d . node . y1 = d . node . y0 + d . visibleHeight ;
582
+ y = Math . max ( 0 , Math . min ( d . size - d . visibleHeight / 2 , y ) ) ;
583
+ d . node . y0 = y - d . visibleHeight / 2 ;
584
+ d . node . y1 = y + d . visibleHeight / 2 ;
558
585
}
559
586
560
587
saveCurrentDragPosition ( d . node ) ;
@@ -570,14 +597,15 @@ function attachDragHandler(sankeyNode, sankeyLink, callbacks) {
570
597
d . node . childrenNodes [ i ] . x = d . node . x ;
571
598
d . node . childrenNodes [ i ] . y = d . node . y ;
572
599
}
600
+ if ( d . arrangement !== 'snap' ) persistFinalNodePositions ( d , gd ) ;
573
601
} ) ;
574
602
575
603
sankeyNode
576
604
. on ( '.drag' , null ) // remove possible previous handlers
577
605
. call ( dragBehavior ) ;
578
606
}
579
607
580
- function attachForce ( sankeyNode , forceKey , d ) {
608
+ function attachForce ( sankeyNode , forceKey , d , gd ) {
581
609
// Attach force to nodes in the same column (same x coordinate)
582
610
switchToForceFormat ( d . graph . nodes ) ;
583
611
var nodes = d . graph . nodes
@@ -590,11 +618,11 @@ function attachForce(sankeyNode, forceKey, d) {
590
618
. radius ( function ( n ) { return n . dy / 2 + d . nodePad / 2 ; } )
591
619
. strength ( 1 )
592
620
. iterations ( c . forceIterations ) )
593
- . force ( 'constrain' , snappingForce ( sankeyNode , forceKey , nodes , d ) )
621
+ . force ( 'constrain' , snappingForce ( sankeyNode , forceKey , nodes , d , gd ) )
594
622
. stop ( ) ;
595
623
}
596
624
597
- function startForce ( sankeyNode , sankeyLink , d , forceKey ) {
625
+ function startForce ( sankeyNode , sankeyLink , d , forceKey , gd ) {
598
626
window . requestAnimationFrame ( function faster ( ) {
599
627
var i ;
600
628
for ( i = 0 ; i < c . forceTicksPerFrame ; i ++ ) {
@@ -609,6 +637,14 @@ function startForce(sankeyNode, sankeyLink, d, forceKey) {
609
637
610
638
if ( d . forceLayouts [ forceKey ] . alpha ( ) > 0 ) {
611
639
window . requestAnimationFrame ( faster ) ;
640
+ } else {
641
+ // Make sure the final x position is equal to its original value
642
+ // necessary because the force simulation will have numerical error
643
+ var x = d . node . originalX ;
644
+ d . node . x0 = x - d . visibleWidth / 2 ;
645
+ d . node . x1 = x + d . visibleWidth / 2 ;
646
+
647
+ persistFinalNodePositions ( d , gd ) ;
612
648
}
613
649
} ) ;
614
650
}
@@ -628,13 +664,31 @@ function snappingForce(sankeyNode, forceKey, nodes, d) {
628
664
maxVelocity = Math . max ( maxVelocity , Math . abs ( n . vx ) , Math . abs ( n . vy ) ) ;
629
665
}
630
666
if ( ! d . interactionState . dragInProgress && maxVelocity < 0.1 && d . forceLayouts [ forceKey ] . alpha ( ) > 0 ) {
631
- d . forceLayouts [ forceKey ] . alpha ( 0 ) ;
667
+ d . forceLayouts [ forceKey ] . alpha ( 0 ) ; // This will stop the animation loop
632
668
}
633
669
} ;
634
670
}
635
671
636
672
// basic data utilities
637
673
674
+ function persistFinalNodePositions ( d , gd ) {
675
+ var x = [ ] ;
676
+ var y = [ ] ;
677
+ for ( var i = 0 ; i < d . graph . nodes . length ; i ++ ) {
678
+ var nodeX = ( d . graph . nodes [ i ] . x0 + d . graph . nodes [ i ] . x1 ) / 2 ;
679
+ var nodeY = ( d . graph . nodes [ i ] . y0 + d . graph . nodes [ i ] . y1 ) / 2 ;
680
+ x . push ( nodeX / d . figure . width ) ;
681
+ y . push ( nodeY / d . figure . height ) ;
682
+ }
683
+ Plotly . restyle ( gd , {
684
+ 'node.x' : [ x ] ,
685
+ 'node.y' : [ y ]
686
+ } , d . trace . index )
687
+ . then ( function ( ) {
688
+ if ( gd . _fullLayout . _dragCover ) gd . _fullLayout . _dragCover . remove ( ) ;
689
+ } ) ;
690
+ }
691
+
638
692
function persistOriginalPlace ( nodes ) {
639
693
var distinctLayerPositions = [ ] ;
640
694
var i ;
@@ -795,7 +849,7 @@ module.exports = function(gd, svg, calcData, layout, callbacks) {
795
849
796
850
sankeyNode
797
851
. call ( attachPointerEvents , sankey , callbacks . nodeEvents )
798
- . call ( attachDragHandler , sankeyLink , callbacks ) ; // has to be here as it binds sankeyLink
852
+ . call ( attachDragHandler , sankeyLink , callbacks , gd ) ; // has to be here as it binds sankeyLink
799
853
800
854
sankeyNode . transition ( )
801
855
. ease ( c . ease ) . duration ( c . duration )
0 commit comments