@@ -45,10 +45,7 @@ function sankeyModel(layout, d, traceIndex) {
4545 if ( circular ) {
4646 sankey = d3SankeyCircular
4747 . sankeyCircular ( )
48- . circularLinkGap ( 0 )
49- . nodeId ( function ( d ) {
50- return d . pointNumber ;
51- } ) ;
48+ . circularLinkGap ( 0 ) ;
5249 } else {
5350 sankey = d3Sankey . sankey ( ) ;
5451 }
@@ -58,6 +55,9 @@ function sankeyModel(layout, d, traceIndex) {
5855 . size ( horizontal ? [ width , height ] : [ height , width ] )
5956 . nodeWidth ( nodeThickness )
6057 . nodePadding ( nodePad )
58+ . nodeId ( function ( d ) {
59+ return d . pointNumber ;
60+ } )
6161 . nodes ( nodes )
6262 . links ( links ) ;
6363
@@ -67,6 +67,30 @@ function sankeyModel(layout, d, traceIndex) {
6767 Lib . warn ( 'node.pad was reduced to ' , sankey . nodePadding ( ) , ' to fit within the figure.' ) ;
6868 }
6969
70+ // Create transient nodes for animations
71+ Object . keys ( calcData . _groupLookup ) . forEach ( function ( nodePointNumber ) {
72+ var groupIndex = parseInt ( calcData . _groupLookup [ nodePointNumber ] ) ;
73+
74+ var groupingNode ;
75+ for ( var i = 0 ; i < graph . nodes . length ; i ++ ) {
76+ if ( graph . nodes [ i ] . pointNumber === groupIndex ) {
77+ groupingNode = graph . nodes [ i ] ;
78+ break ;
79+ }
80+ }
81+
82+ graph . nodes . push ( {
83+ pointNumber : parseInt ( nodePointNumber ) ,
84+ x0 : groupingNode . x0 ,
85+ x1 : groupingNode . x1 ,
86+ y0 : groupingNode . y0 ,
87+ y1 : groupingNode . y1 ,
88+ partOfGroup : true ,
89+ sourceLinks : [ ] ,
90+ targetLinks : [ ]
91+ } ) ;
92+ } ) ;
93+
7094 function computeLinkConcentrations ( ) {
7195 var i , j , k ;
7296 for ( i = 0 ; i < graph . nodes . length ; i ++ ) {
@@ -343,7 +367,7 @@ function linkPath() {
343367 return path ;
344368}
345369
346- function nodeModel ( d , n , i ) {
370+ function nodeModel ( d , n ) {
347371 var tc = tinycolor ( n . color ) ;
348372 var zoneThicknessPad = c . nodePadAcross ;
349373 var zoneLengthPad = d . nodePad / 2 ;
@@ -352,8 +376,11 @@ function nodeModel(d, n, i) {
352376 var visibleThickness = n . dx ;
353377 var visibleLength = Math . max ( 0.5 , n . dy ) ;
354378
355- var basicKey = n . label ;
356- var key = basicKey + '__' + i ;
379+ var key = 'node_' + n . pointNumber ;
380+ // If it's a group, it's mutable and should be unique
381+ if ( n . group ) {
382+ key = 'group_' + Math . floor ( 1e12 * ( 1 + Math . random ( ) ) ) ;
383+ }
357384
358385 // for event data
359386 n . trace = d . trace ;
@@ -362,6 +389,8 @@ function nodeModel(d, n, i) {
362389 return {
363390 index : n . pointNumber ,
364391 key : key ,
392+ partOfGroup : n . partOfGroup || false ,
393+ group : n . group ,
365394 traceId : d . key ,
366395 node : n ,
367396 nodePad : d . nodePad ,
@@ -540,7 +569,10 @@ function attachDragHandler(sankeyNode, sankeyLink, callbacks) {
540569function attachForce ( sankeyNode , forceKey , d ) {
541570 // Attach force to nodes in the same column (same x coordinate)
542571 switchToForceFormat ( d . graph . nodes ) ;
543- var nodes = d . graph . nodes . filter ( function ( n ) { return n . originalX === d . node . originalX ; } ) ;
572+ var nodes = d . graph . nodes
573+ . filter ( function ( n ) { return n . originalX === d . node . originalX ; } )
574+ // Filter out children
575+ . filter ( function ( n ) { return ! n . partOfGroup ; } ) ;
544576 d . forceLayouts [ forceKey ] = d3Force . forceSimulation ( nodes )
545577 . alphaDecay ( 0 )
546578 . force ( 'collide' , d3Force . forceCollide ( )
@@ -683,7 +715,6 @@ module.exports = function(gd, svg, calcData, layout, callbacks) {
683715 sankeyLink
684716 . enter ( ) . append ( 'path' )
685717 . classed ( c . cn . sankeyLink , true )
686- . attr ( 'd' , linkPath ( ) )
687718 . call ( attachPointerEvents , sankey , callbacks . linkEvents ) ;
688719
689720 sankeyLink
@@ -701,13 +732,17 @@ module.exports = function(gd, svg, calcData, layout, callbacks) {
701732 } )
702733 . style ( 'stroke-width' , function ( d ) {
703734 return salientEnough ( d ) ? d . linkLineWidth : 1 ;
704- } ) ;
735+ } )
736+ . attr ( 'd' , linkPath ( ) ) ;
705737
706- sankeyLink . transition ( )
707- . ease ( c . ease ) . duration ( c . duration )
708- . attr ( 'd' , linkPath ( ) ) ;
738+ sankeyLink
739+ . style ( 'opacity' , 0 )
740+ . transition ( )
741+ . ease ( c . ease ) . duration ( c . duration )
742+ . style ( 'opacity' , 1 ) ;
709743
710- sankeyLink . exit ( ) . transition ( )
744+ sankeyLink . exit ( )
745+ . transition ( )
711746 . ease ( c . ease ) . duration ( c . duration )
712747 . style ( 'opacity' , 0 )
713748 . remove ( ) ;
@@ -733,24 +768,26 @@ module.exports = function(gd, svg, calcData, layout, callbacks) {
733768 var nodes = d . graph . nodes ;
734769 persistOriginalPlace ( nodes ) ;
735770 return nodes
736- . filter ( function ( n ) { return n . value ; } )
737- . map ( nodeModel . bind ( null , d ) ) ;
771+ . map ( nodeModel . bind ( null , d ) ) ;
738772 } , keyFun ) ;
739773
740774 sankeyNode . enter ( )
741775 . append ( 'g' )
742776 . classed ( c . cn . sankeyNode , true )
743777 . call ( updateNodePositions )
744- . call ( attachPointerEvents , sankey , callbacks . nodeEvents ) ;
778+ . style ( 'opacity' , 0 ) ;
745779
746780 sankeyNode
781+ . call ( attachPointerEvents , sankey , callbacks . nodeEvents )
747782 . call ( attachDragHandler , sankeyLink , callbacks ) ; // has to be here as it binds sankeyLink
748783
749784 sankeyNode . transition ( )
750785 . ease ( c . ease ) . duration ( c . duration )
751- . call ( updateNodePositions ) ;
786+ . call ( updateNodePositions )
787+ . style ( 'opacity' , function ( n ) { return n . partOfGroup ? 0 : 1 ; } ) ;
752788
753- sankeyNode . exit ( ) . transition ( )
789+ sankeyNode . exit ( )
790+ . transition ( )
754791 . ease ( c . ease ) . duration ( c . duration )
755792 . style ( 'opacity' , 0 )
756793 . remove ( ) ;
0 commit comments