import type { SimpleChanges , AfterViewInit , OnChanges , OnDestroy } from '@angular/core' ; import type { AmChart } from './amcharts3-angular.service' ; import { Directive , ElementRef , Input , NgZone } from '@angular/core' ; import { AmChartsService } from './amcharts3-angular.service' ; function getType ( x ) { return { } . toString . call ( x ) ; } function hasOwnKey ( obj , key ) { return { } . hasOwnProperty . call ( obj , key ) ; } function copyObject ( x ) { const output = { } ; for ( const key in x ) { if ( hasOwnKey ( x , key ) ) { output [ key ] = copy ( x [ key ] ) ; } } return output ; } function copyArray ( x ) { const length = x . length ; const output = new Array ( length ) ; for ( let i = 0 ; i < length ; ++ i ) { output [ i ] = copy ( x [ i ] ) ; } return output ; } function copy ( x ) { switch ( getType ( x ) ) { case '[object Array]' : return copyArray ( x ) ; case '[object Object]' : return copyObject ( x ) ; case '[object Date]' : return new Date ( x . getTime ( ) ) ; default : return x ; } } function isNaN ( x ) { return x !== x ; } function isNumberEqual ( x , y ) { return x === y || ( isNaN ( x ) && isNaN ( y ) ) ; } function removeChartListeners ( chart , x , y ) { if ( x !== y ) { if ( x == null ) { x = [ ] ; } if ( y == null ) { y = [ ] ; } const xLength = x . length ; const yLength = y . length ; for ( let i = 0 ; i < xLength ; ++ i ) { const xValue = x [ i ] ; let has = false ; for ( let j = 0 ; j < yLength ; ++ j ) { const yValue = y [ j ] ; if ( xValue . event === yValue . event && xValue . method === yValue . method ) { has = true ; break ; } } if ( ! has ) { chart . removeListener ( chart , xValue . event , xValue . method ) ; } } } } function updateArray ( a , x , y ) { let didUpdate = false ; if ( x !== y ) { const xLength = x . length ; const yLength = y . length ; if ( xLength !== yLength ) { a . length = yLength ; didUpdate = true ; } for ( let i = 0 ; i < yLength ; ++ i ) { if ( i < xLength ) { if ( update ( a , i , x [ i ] , y [ i ] ) ) { didUpdate = true ; } } else { a [ i ] = copy ( y [ i ] ) ; didUpdate = true ; } } } return didUpdate ; } function update ( obj , key , x , y ) { let didUpdate = false ; if ( x !== y ) { const xType = getType ( x ) ; const yType = getType ( y ) ; if ( xType === yType ) { switch ( xType ) { case '[object Array]' : if ( updateArray ( obj [ key ] , x , y ) ) { didUpdate = true ; } break ; case '[object Object]' : if ( updateObject ( obj [ key ] , x , y ) ) { didUpdate = true ; } break ; case '[object Date]' : if ( x . getTime ( ) !== y . getTime ( ) ) { obj [ key ] = copy ( y ) ; didUpdate = true ; } break ; case '[object Number]' : if ( ! isNumberEqual ( x , y ) ) { obj [ key ] = copy ( y ) ; didUpdate = true ; } break ; default : if ( x !== y ) { obj [ key ] = copy ( y ) ; didUpdate = true ; } break ; } } else { obj [ key ] = copy ( y ) ; didUpdate = true ; } } return didUpdate ; } function updateObject ( chart , oldObj , newObj ) { let didUpdate = false ; if ( oldObj !== newObj ) { for ( const key in newObj ) { if ( hasOwnKey ( newObj , key ) ) { if ( hasOwnKey ( oldObj , key ) ) { if ( key === 'listeners' ) { removeChartListeners ( chart , oldObj [ key ] , newObj [ key ] ) ; } if ( update ( chart , key , oldObj [ key ] , newObj [ key ] ) ) { didUpdate = true ; } } else { chart [ key ] = copy ( newObj [ key ] ) ; didUpdate = true ; } } } for ( const key in oldObj ) { if ( hasOwnKey ( oldObj , key ) && ! hasOwnKey ( newObj , key ) ) { if ( key === 'listeners' ) { removeChartListeners ( chart , oldObj [ key ] , [ ] ) ; } delete chart [ key ] ; didUpdate = true ; } } } return didUpdate ; } @ Directive ( { selector : 'amCharts' } ) export class AmChartsDirective implements AfterViewInit , OnChanges , OnDestroy { @ Input ( ) id ! : string ; @ Input ( ) options : any ; @ Input ( ) delay = 0 ; private chart : AmChart | undefined ; constructor ( private el , private AmCharts , private zone ) { } ngAfterViewInit ( ) { const props = copy ( this . options ) ; const el = this . el . nativeElement ; el . id = this . id ; el . style . display = 'block' ; this . chart = this . AmCharts . makeChart ( this . id , props , this . delay ) ; } ngOnChanges ( x ) { const el = this . el . nativeElement ; if ( x . id ) { el . id = x . id . currentValue ; } if ( x . options ) { if ( this . chart ) { this . zone . runOutsideAngular ( ( ) => { const didUpdate = updateObject ( this . chart , x . options . previousValue , x . options . currentValue ) ; if ( didUpdate ) { this . chart ! . validateNow ( true ) ; } } ) ; } } } ngOnDestroy ( ) { if ( this . chart ) { this . AmCharts . destroyChart ( this . chart ) ; } } }