@@ -61,6 +61,8 @@ export class SankeyChart {
6161 }
6262
6363 buildNodesConfig ( ) : Array < SeriesSankeyNodesOptionsObject > {
64+ const self = this ;
65+
6466 let nodes : Array < SeriesSankeyNodesOptionsObject > = [ ] ;
6567 nodes . push ( {
6668 id : String ( this . mainNodeId ) ,
@@ -69,10 +71,10 @@ export class SankeyChart {
6971 dataLabels : {
7072 className : "main-node-label" ,
7173 nodeFormatter : function ( ) : string {
72- const node = new SankeyNode ( this as Highcharts . SankeyNodeObject ) ;
73- return ` ${ this . name } : ${ node . getTotalWeight ( ) == 0 ? '' : numberFormatColored ( node . getTotalWeight ( ) ) } ` ;
74+ const node = new SankeyNode ( self , this as Highcharts . SankeyNodeObject ) ;
75+ return node . toString ( ) ;
7476 }
75- }
77+ } ,
7678 } ) ;
7779
7880 new Map ( [ ...config . categories ] . filter ( ( [ categoryId , category ] ) => categoryId !== this . mainNodeId ) )
@@ -134,39 +136,47 @@ export class SankeyChart {
134136 align : 'right' ,
135137 padding : 30 ,
136138 nodeFormatter : function ( ) : string {
137- const node = new SankeyNode ( this as Highcharts . SankeyNodeObject ) ;
139+ const node = new SankeyNode ( self , this as Highcharts . SankeyNodeObject ) ;
138140
139141 return node . name + ': ' + ( new NodeValidator ( node , config ) . validate ( ) ? '' : NodeValidator . warningSign )
140- + numberFormat ( node . getSum ( ) ) + ' '
142+ + numberFormat ( node . getValue ( ) ) + ' '
141143 + ( node . getPercentage ( ) && node . getPercentage ( ) < 100 ? "<span class='badge text-bg-secondary'>" + Math . round ( node . getPercentage ( ) ) + "% </span>" : "" ) ;
142144 }
143145 } ,
144146 tooltip : {
145147 // tooltip for link
146148 pointFormatter : function ( ) : string {
147149 const point = this as any ;
148- return point . fromNode . name + " → " + point . toNode . name + ": " + numberFormat ( point . weight / config . scalingFactor ) + "<br / ><br / ><span class='small'>(Klick entfernt die Kategorie aus dem Chart.)</span>" ;
150+ return point . fromNode . name + " → " + point . toNode . name + ": " + numberFormat ( point . weight / config . scalingFactor ) + "<br><br><span class='small'>(Klick entfernt die Kategorie aus dem Chart.)</span>" ;
149151 } ,
150152 // tooltip for node
151153 nodeFormatter : function ( ) : string {
152- const node = new SankeyNode ( this as Highcharts . SankeyNodeObject ) ;
154+ const node = new SankeyNode ( self , this as Highcharts . SankeyNodeObject ) ;
153155
154156 let weightsDetailTooltip = '' ;
155157 node . getLinksTo ( ) . filter ( link => link . from !== String ( self . mainNodeId ) && link . weight > 0 )
158+ . sort ( ( a , b ) => b . weight - a . weight )
156159 . forEach ( function ( link : any ) {
157- weightsDetailTooltip += '+ ' + numberFormat ( link . weight / config . scalingFactor ) + ' (' + link . fromNode . name + ')<br / >' ;
160+ weightsDetailTooltip += '+ ' + numberFormat ( link . weight / config . scalingFactor ) + ' (' + link . fromNode . name + ')<br>' ;
158161 } ) ;
162+ if ( node . isMain ) {
163+ weightsDetailTooltip += '= ' + numberFormat ( node . getTotalIncomingWeight ( ) ) + '<br><br>' ;
164+ }
159165
160166 node . getLinksFrom ( ) . filter ( link => link . to !== String ( self . mainNodeId ) && link . weight > 0 )
167+ . sort ( ( a , b ) => b . weight - a . weight )
161168 . forEach ( function ( link : any ) {
162- weightsDetailTooltip += '- ' + numberFormat ( link . weight / config . scalingFactor ) + ' (' + link . toNode . name + ')<br / >' ;
169+ weightsDetailTooltip += '- ' + numberFormat ( link . weight / config . scalingFactor ) + ' (' + link . toNode . name + ')<br>' ;
163170 } ) ;
171+ if ( node . isMain ) {
172+ weightsDetailTooltip += '= ' + numberFormat ( node . getTotalOutgoingWeight ( ) ) + '<br>' ;
173+ }
164174
165175 const validator = new NodeValidator ( node , config ) ;
166176 validator . validate ( ) ;
167177
168- return node . toString ( ) + '<br / >'
169- + weightsDetailTooltip + '<br / >'
178+ return node . toString ( ) + '<br>'
179+ + weightsDetailTooltip + '<br>'
170180 + validator . messages ;
171181 }
172182 } ,
@@ -185,9 +195,9 @@ export class SankeyChart {
185195 link . graphic . element . setAttribute ( 'data-testid' , `chart-link-${ link . custom ?. category ?. id } ` ) ;
186196 } ) ;
187197 ( ( this . series [ 0 ] as any ) . nodes as Array < Highcharts . SankeyNodeObject > ) . forEach ( ( point : any , index ) => {
188- const node = new SankeyNode ( point ) ;
198+ const node = new SankeyNode ( self , point ) ;
189199 point . graphic . element . setAttribute ( 'data-testid' , `chart-node-${ point . id } ` ) ;
190- point . graphic . element . setAttribute ( 'data-value' , point . id === '1' ? node . getTotalWeight ( ) : node . getSum ( ) ) ;
200+ point . graphic . element . setAttribute ( 'data-value' , node . getValue ( ) ) ;
191201 if ( point . dataLabel && point . dataLabel . element ) {
192202 point . dataLabel . element . setAttribute ( 'data-testid' , `chart-node-label-${ point . id } ` ) ;
193203 }
@@ -217,7 +227,7 @@ export class SankeyChart {
217227 throw new Error ( 'cannot find node with id ' + nodeId ) ;
218228 }
219229
220- return new SankeyNode ( node ) ;
230+ return new SankeyNode ( this , node ) ;
221231 }
222232
223233 getOutgoingWeights ( ) : Array < number > {
@@ -229,21 +239,30 @@ export class SankeyNode {
229239 public name : string = '' ;
230240 public categoryId : number ;
231241 public label : string = '' ;
232- private readonly node : SeriesSankeyNodesOptionsObject ;
242+ public isMain : boolean = false ;
243+ private readonly node : Highcharts . SankeyNodeObject ;
244+ private readonly chart : SankeyChart ;
233245
234- constructor ( node : SeriesSankeyNodesOptionsObject ) {
246+ constructor ( chart : SankeyChart , node : Highcharts . SankeyNodeObject ) {
247+ this . chart = chart ;
235248 this . node = node ;
236249 this . name = node . name ;
237250 // @ts -ignore
238251 this . label = node . dataLabels !== null && typeof node . dataLabels !== 'undefined' && node . dataLabels . length > 0 ? node . dataLabels [ 0 ] . textStr : '' ;
239252 this . categoryId = parseInt ( ( node as any ) . point . id ) ;
253+ this . isMain = this . categoryId === this . chart . mainNodeId ;
240254 }
241255
242256 public toString ( ) : string {
243- return `${ this . name } : ${ this . getSum ( ) == 0 ? '' : numberFormatColored ( this . getSum ( ) ) } ` ;
257+ const format = this . isMain ? numberFormatColored : numberFormat ;
258+ return `${ this . name } : ${ this . getValue ( ) == 0 ? '' : format ( this . getValue ( ) ) } ` ;
259+ }
260+
261+ public getValue ( ) : number {
262+ return this . isMain ? this . getTotalWeight ( ) : this . getSum ( ) ;
244263 }
245264
246- public getSum ( ) : number {
265+ private getSum ( ) : number {
247266 return 'getSum' in this . node ? ( this . node as any ) . getSum ( ) / config . scalingFactor : 0 ;
248267 }
249268
@@ -253,9 +272,9 @@ export class SankeyNode {
253272 return null ;
254273 }
255274
256- const parentNode = new SankeyNode ( ( linksTo [ 0 ] as any ) . fromNode ) ;
275+ const parentNode = new SankeyNode ( this . chart , ( linksTo [ 0 ] as any ) . fromNode ) ;
257276
258- return ( this . getSum ( ) / parentNode . getTotalOutgoingWeight ( ) ) * 100 ;
277+ return ( this . getValue ( ) / parentNode . getTotalOutgoingWeight ( ) ) * 100 ;
259278 }
260279
261280 public getLinksFrom ( ) : Array < PointOptionsObject > {
@@ -274,7 +293,7 @@ export class SankeyNode {
274293 return this . getLinksFrom ( ) . map ( point => point . weight ) . reduce ( ( pv , cv ) => pv + cv , 0 ) / config . scalingFactor ;
275294 }
276295
277- public getTotalWeight ( ) : number {
296+ private getTotalWeight ( ) : number {
278297 return this . getTotalIncomingWeight ( ) - this . getTotalOutgoingWeight ( ) ;
279298 }
280299}
0 commit comments