'use strict' ; import type PointOptions from '../Core/Series/PointOptions' ; import type SeriesOptions from '../Core/Series/SeriesOptions' ; import type { StatesOptionsKey } from '../Core/Series/StatesOptions' ; import Point from '../Core/Series/Point.js' ; import Series from '../Core/Series/Series.js' ; import U from '../Core/Utilities.js' ; const { defined , extend , find , pick } = U ; declare module '../Core/Series/PointLike' { interface PointLike { name ? : string ; } } declare module '../Core/Series/SeriesLike' { interface SeriesLike { nodes ? : Array < NodesComposition . PointComposition > ; } } namespace NodesComposition { export declare class PointComposition extends Point { public className : string ; public formatPrefix : string ; public from : string ; public fromNode : PointComposition ; public id : string ; public isNode : true ; public level ? : unknown ; public linksFrom : Array < PointComposition > ; public linksTo : Array < PointComposition > ; public mass : number ; public options : PointCompositionOptions ; public series : SeriesComposition ; public to : string ; public toNode : PointComposition ; public weight ? : number ; public y ? : ( number | null ) ; public getSum ( ) ; public hasShape ( ) ; public init ( series , options ) ; public offset ( point , coll ) ; public setNodeState ( state ? ) ; } export interface PointCompositionOptions extends PointOptions { id ? : string ; level ? : number ; mass ? : number ; outgoing ? : boolean ; weight ? : ( number | null ) ; } export declare class SeriesComposition extends Series { public data : Array < PointComposition > ; public nodeLookup : Record < string , PointComposition > ; public nodes : Array < PointComposition > ; public options : SeriesCompositionOptions ; public pointClass : typeof PointComposition ; public points : Array < PointComposition > ; public createNode ( id ) ; public generatePoints ( ) ; } export interface SeriesCompositionOptions extends SeriesOptions { mass ? : number ; nodes ? : Array < PointCompositionOptions > ; } const composedClasses = [ ] ; private export function compose < T extends typeof Series > ( PointClass , SeriesClass ) { if ( composedClasses . indexOf ( PointClass ) === - 1 ) { composedClasses . push ( PointClass ) ; const pointProto = PointClass . prototype as PointComposition ; pointProto . setNodeState = setNodeState ; pointProto . setState = setNodeState ; } if ( composedClasses . indexOf ( SeriesClass ) === - 1 ) { composedClasses . push ( SeriesClass ) ; const seriesProto = SeriesClass . prototype as SeriesComposition ; seriesProto . destroy = destroy ; seriesProto . setData = setData ; } return SeriesClass as ( T & SeriesComposition ) ; } private export function createNode ( this , id ) { const PointClass = this . pointClass , findById = < T > ( nodes , id ) : ( T | undefined ) => find ( nodes , ( node ) : boolean => ( node as any ) . id === id ) ; let node = findById ( this . nodes , id ) , options ; if ( ! node ) { options = this . options . nodes && findById ( this . options . nodes , id ) ; node = ( new PointClass ( ) ) . init ( this , extend ( { className : 'highcharts-node' , isNode : true , id : id , y : 1 } as PointCompositionOptions , options as any ) ) ; node . linksTo = [ ] ; node . linksFrom = [ ] ; node . formatPrefix = 'node' ; node . name = node . name || node . options . id || '' ; node . mass = pick ( node . options . mass , node . options . marker && node . options . marker . radius , this . options . marker && this . options . marker . radius , 4 ) ; private node . getSum = function ( ) : number { let sumTo = 0 , sumFrom = 0 ; ( node as any ) . linksTo . forEach ( function ( link ) : void { sumTo += link . weight as any ; } ) ; ( node as any ) . linksFrom . forEach ( function ( link ) : void { sumFrom += link . weight as any ; } ) ; return Math . max ( sumTo , sumFrom ) ; } ; private node . offset = function ( point , coll ) : ( number | undefined ) { let offset = 0 ; for ( let i = 0 ; i < ( node as any ) [ coll ] . length ; i ++ ) { if ( ( node as any ) [ coll ] [ i ] === point ) { return offset ; } offset += ( node as any ) [ coll ] [ i ] . weight ; } } ; node . hasShape = function ( ) : boolean { let outgoing = 0 ; ( node as any ) . linksTo . forEach ( function ( link ) : void { if ( link . outgoing ) { outgoing ++ ; } } ) ; return ( ! ( node as any ) . linksTo . length || outgoing !== ( node as any ) . linksTo . length ) ; } ; this . nodes . push ( node ) ; } return node ; } private export function destroy ( this ) { this . data = ( [ ] as Array < PointComposition > ) . concat ( this . points || [ ] , this . nodes ) ; return Series . prototype . destroy . apply ( this , arguments as any ) ; } /**
     * Extend generatePoints by adding the nodes, which are Point objects
     * but pushed to the this.nodes array.
     */ export function generatePoints ( this ) { const chart = this . chart , nodeLookup = { } as Record < string , PointComposition > ; Series . prototype . generatePoints . call ( this ) ; if ( ! this . nodes ) { this . nodes = [ ] ; } this . colorCounter = 0 ; this . nodes . forEach ( function ( node ) : void { node . linksFrom . length = 0 ; node . linksTo . length = 0 ; node . level = node . options . level ; } ) ; this . points . forEach ( function ( point ) : void { if ( defined ( point . from ) ) { if ( ! nodeLookup [ point . from ] ) { nodeLookup [ point . from ] = this . createNode ( point . from ) ; } nodeLookup [ point . from ] . linksFrom . push ( point ) ; point . fromNode = nodeLookup [ point . from ] ; if ( chart . styledMode ) { point . colorIndex = pick ( point . options . colorIndex , nodeLookup [ point . from ] . colorIndex ) ; } else { point . color = point . options . color || nodeLookup [ point . from ] . color ; } } if ( defined ( point . to ) ) { if ( ! nodeLookup [ point . to ] ) { nodeLookup [ point . to ] = this . createNode ( point . to ) ; } nodeLookup [ point . to ] . linksTo . push ( point ) ; point . toNode = nodeLookup [ point . to ] ; } point . name = point . name || point . id ; } , this ) ; this . nodeLookup = nodeLookup ; } private function setData ( this ) { if ( this . nodes ) { this . nodes . forEach ( function ( node ) : void { node . destroy ( ) ; } ) ; this . nodes . length = 0 ; } Series . prototype . setData . apply ( this , arguments as any ) ; } /**
     * When hovering node, highlight all connected links. When hovering a link,
     * highlight all connected nodes.
     */ export function setNodeState ( this , state ? ) { const args = arguments , others = this . isNode ? this . linksTo . concat ( this . linksFrom ) : [ this . fromNode , this . toNode ] ; if ( state !== 'select' ) { others . forEach ( function ( linkOrNode ) : void { if ( linkOrNode && linkOrNode . series ) { Point . prototype . setState . apply ( linkOrNode , args as any ) ; if ( ! linkOrNode . isNode ) { if ( linkOrNode . fromNode . graphic ) { Point . prototype . setState . apply ( linkOrNode . fromNode , args as any ) ; } if ( linkOrNode . toNode && linkOrNode . toNode . graphic ) { Point . prototype . setState . apply ( linkOrNode . toNode , args as any ) ; } } } } ) ; } Point . prototype . setState . apply ( this , args as any ) ; } } export default NodesComposition ;