import { OnDestroy , OnInit , OnChanges , EventEmitter , ElementRef , Input , Output , SimpleChanges , Directive } from '@angular/core' ; import { Color } from './color.service' ; import { Colors } from './colors.service' ; import { isPlatformBrowser } from '@angular/common' ; import { PLATFORM_ID , Inject } from '@angular/core' ; declare var Chart ; @ Directive ( { selector : 'canvas[mdbChart]' , exportAs : 'mdb-base-chart' } ) export class BaseChartDirective implements OnDestroy , OnChanges , OnInit , Colors { public static defaultColors : Array < number [ ] > = [ [ 255 , 99 , 132 ] , [ 54 , 162 , 235 ] , [ 255 , 206 , 86 ] , [ 231 , 233 , 237 ] , [ 75 , 192 , 192 ] , [ 151 , 187 , 205 ] , [ 220 , 220 , 220 ] , [ 247 , 70 , 74 ] , [ 70 , 191 , 189 ] , [ 253 , 180 , 92 ] , [ 148 , 159 , 177 ] , [ 77 , 83 , 96 ] ] ; @ Input ( ) public data : number [ ] | any [ ] ; @ Input ( ) public datasets : any [ ] ; @ Input ( ) public labels : Array < any > = [ ] ; @ Input ( ) public options : any = { legend : { display : false } } ; @ Input ( ) public chartType : string ; @ Input ( ) public colors : Array < any > ; @ Input ( ) public legend = false ; @ Output ( ) public chartClick : EventEmitter < any > = new EventEmitter ( ) ; @ Output ( ) public chartHover : EventEmitter < any > = new EventEmitter ( ) ; public ctx : any ; public chart : any ; cvs : any ; initFlag = false ; element : ElementRef ; isBrowser : any = false ; public constructor ( element , @ Inject ( PLATFORM_ID ) platformId ) { this . element = element ; this . isBrowser = isPlatformBrowser ( platformId ) ; } public ngOnInit ( ) { if ( this . isBrowser ) { this . ctx = this . element . nativeElement . getContext ( '2d' ) ; this . cvs = this . element . nativeElement ; this . initFlag = true ; if ( this . data || this . datasets ) { this . refresh ( ) ; } } } public ngOnChanges ( changes ) { if ( this . initFlag ) { if ( changes . hasOwnProperty ( 'data' ) || changes . hasOwnProperty ( 'datasets' ) ) { if ( changes [ 'data' ] ) { this . updateChartData ( changes [ 'data' ] . currentValue ) ; } else { this . updateChartData ( changes [ 'datasets' ] . currentValue ) ; } this . chart . update ( ) ; } else { this . refresh ( ) ; } } } public ngOnDestroy ( ) { if ( this . chart ) { this . chart . destroy ( ) ; this . chart = void 0 ; } } public getChartBuilder ( ctx ) { const datasets = this . getDatasets ( ) ; const options = Object . assign ( { } , this . options ) ; if ( this . legend === false ) { options . legend = { display : false } ; } options . hover = options . hover || { } ; if ( ! options . hover . onHover ) { options . hover . onHover = ( event , active ) => { if ( active && active . length ) { this . chartHover . emit ( { event , active } ) ; } } ; } if ( ! options . onClick ) { options . onClick = ( event , active ) => { this . chartClick . emit ( { event , active } ) ; } ; } const opts = { type : this . chartType , data : { labels : this . labels , datasets : datasets } , options : options } ; return new Chart ( ctx , opts ) ; } private updateChartData ( newDataValues ) { if ( Array . isArray ( newDataValues [ 0 ] . data ) ) { this . chart . data . datasets . forEach ( ( dataset , i ) => { dataset . data = newDataValues [ i ] . data ; if ( newDataValues [ i ] . label ) { dataset . label = newDataValues [ i ] . label ; } } ) ; } else { this . chart . data . datasets [ 0 ] . data = newDataValues ; } } private getDatasets ( ) { let datasets = void 0 ; if ( ! this . datasets || ! this . datasets . length && ( this . data && this . data . length ) ) { if ( Array . isArray ( this . data [ 0 ] ) ) { datasets = ( this . data as Array < number [ ] > ) . map ( ( data , index ) => { return { data , label : this . labels [ index ] || `Label ${ index }` } ; } ) ; } else { datasets = [ { data : this . data , label : `Label 0` } ] ; } } if ( this . datasets && this . datasets . length || ( datasets && datasets . length ) ) { datasets = ( this . datasets || datasets ) . map ( ( elm , index ) => { const newElm = Object . assign ( { } , elm ) ; if ( this . colors && this . colors . length ) { Object . assign ( newElm , this . colors [ index ] ) ; } else { Object . assign ( newElm , getColors ( this . chartType , index , newElm . data . length ) ) ; } return newElm ; } ) ; } if ( ! datasets ) { throw new Error ( `ng-charts configuration error,
      data or datasets field are required to render char ${ this . chartType }` ) ; } return datasets ; } private refresh ( ) { this . ngOnDestroy ( ) ; this . chart = this . getChartBuilder ( this . ctx ) ; } } function rgba ( colour , alpha ) { return 'rgba(' + colour . concat ( alpha ) . join ( ',' ) + ')' ; } function getRandomInt ( min , max ) { return Math . floor ( Math . random ( ) * ( max - min + 1 ) ) + min ; } function formatLineColor ( colors ) { return { backgroundColor : rgba ( colors , 0.4 ) , borderColor : rgba ( colors , 1 ) , pointBackgroundColor : rgba ( colors , 1 ) , pointBorderColor : '#fff' , pointHoverBackgroundColor : '#fff' , pointHoverBorderColor : rgba ( colors , 0.8 ) } ; } function formatBarColor ( colors ) { return { backgroundColor : rgba ( colors , 0.6 ) , borderColor : rgba ( colors , 1 ) , hoverBackgroundColor : rgba ( colors , 0.8 ) , hoverBorderColor : rgba ( colors , 1 ) } ; } function formatPieColors ( colors ) { return { backgroundColor : colors . map ( ( color ) => rgba ( color , 0.6 ) ) , borderColor : colors . map ( ( ) => '#fff' ) , pointBackgroundColor : colors . map ( ( color ) => rgba ( color , 1 ) ) , pointBorderColor : colors . map ( ( ) => '#fff' ) , pointHoverBackgroundColor : colors . map ( ( color ) => rgba ( color , 1 ) ) , pointHoverBorderColor : colors . map ( ( color ) => rgba ( color , 1 ) ) } ; } function formatPolarAreaColors ( colors ) { return { backgroundColor : colors . map ( ( color ) => rgba ( color , 0.6 ) ) , borderColor : colors . map ( ( color ) => rgba ( color , 1 ) ) , hoverBackgroundColor : colors . map ( ( color ) => rgba ( color , 0.8 ) ) , hoverBorderColor : colors . map ( ( color ) => rgba ( color , 1 ) ) } ; } function getRandomColor ( ) { return [ getRandomInt ( 0 , 255 ) , getRandomInt ( 0 , 255 ) , getRandomInt ( 0 , 255 ) ] ; } param index returns { number [ ] | Color } function generateColor ( index ) { return BaseChartDirective . defaultColors [ index ] || getRandomColor ( ) ; } param count returns { Colors } function generateColors ( count ) { const colorsArr = new Array ( count ) ; for ( let i = 0 ; i < count ; i ++ ) { colorsArr [ i ] = BaseChartDirective . defaultColors [ i ] || getRandomColor ( ) ; } return colorsArr ; } param chartType param index param count returns { Color } function getColors ( chartType , index , count ) { if ( chartType === 'pie' || chartType === 'doughnut' ) { return formatPieColors ( generateColors ( count ) ) ; } if ( chartType === 'polarArea' ) { return formatPolarAreaColors ( generateColors ( count ) ) ; } if ( chartType === 'line' || chartType === 'radar' ) { return formatLineColor ( generateColor ( index ) ) ; } if ( chartType === 'bar' || chartType === 'horizontalBar' ) { return formatBarColor ( generateColor ( index ) ) ; } return generateColor ( index ) ; }