import { ViewChild , Input , NgZone , ElementRef , OnInit , AfterViewInit } from '@angular/core' ; import * as CanvasGauges from 'canvas-gauges' ; import * as Rx from 'rx-dom-html' ; const toCamelCase = ( str ) => str . replace ( /(\-\w)/g , ( matches ) => matches [ 1 ] . toUpperCase ( ) ) ; const toKebabCase = ( str ) => str . replace ( /([a-z0-9])([A-Z])/g , '$1-$2' ) . toLowerCase ( ) ; const attributeName2PropertyName = ( attrName ) => toCamelCase ( attrName ) ; /**
 * Base gauge component for the Gauges rendering
 * T - Type of the Gauge to be rendered (Currently RadialGauge, LinearGauge from the original library)
 * T2 - Type of config options used by the particular gauge (RadialGaugeOptions, LinearGaugeOptions)
 */ export abstract class BaseGauge < T extends CanvasGauges . BaseGauge , T2 extends CanvasGauges . GenericOptions > implements OnInit , AfterViewInit { /**
     * Canvas element on the template used by the library to draw gauge element
     */ @ ViewChild ( 'gauge' ) protected canvas : ElementRef ; /**
     * A gauge instance responsible for rendering and updates on the canvas.
     * Subclasses should initialize in their ngOnInit implementation.
     */ protected gauge : T ; /**
     * Flag indicating that OnViewInit life-cycle has completed
     */ private isInited = false ; /**
     * value property of gauge prior to component view initialization
     */ private preInitValue : number ; /**
     * options property of gauge prior to component view initialization
     */ private preInitOptions : T2 ; /**
     * Listen for attribute changes, i.e., options properties that are stored
     * as attributes on this ElementRef
     */ private domListener : MutationObserver ; param el param zone constructor ( private el , public zone ) { } /**
     * Subclasses should instantiate the CanvasGauge object in the child component
     */ abstract ngOnInit ( ) ; returns public get options ( ) : T2 { const options = { } as T2 ; options . renderTo = this . canvas . nativeElement ; for ( const attr of this . el . nativeElement . attributes ) { const prop = attributeName2PropertyName ( attr . name ) ; options [ prop ] = CanvasGauges . DomObserver . parse ( attr . value ) ; } for ( const prop in this . preInitOptions ) { options [ prop ] = this . preInitOptions [ prop ] ; } if ( this . isInited ) { this . preInitOptions = null ; } return options ; } param newOptions @ Input ( ) public set options ( newOptions ) { if ( ! this . isInited ) { this . preInitOptions = newOptions ; return ; } this . update ( newOptions ) ; } param newValue @ Input ( ) public set value ( newValue ) { if ( ! this . isInited ) { this . preInitValue = newValue ; return ; } this . zone . runOutsideAngular ( ( ) => { this . gauge . value = newValue ; } ) ; } param newOptions public update ( newOptions ) { if ( ! newOptions ) { return ; } for ( const prop in newOptions ) { const val = newOptions [ prop ] . toString ( ) ; if ( prop === 'value' ) { this . value = CanvasGauges . DomObserver . parse ( val ) ; } else { const attrName = toKebabCase ( prop ) ; this . el . nativeElement . setAttribute ( attrName , val ) ; } } } /**
     * Perform gauge initialization.
     * Subclasses that override this method must this super version
     * for proper operation.
     */ public ngAfterViewInit ( ) { this . initGauge ( ) ; this . listenForDOMEvents ( ) ; this . isInited = true ; } /**
     * Listen for attribute-change events that are created when updating
     * the options of this gauge.
     */ protected listenForDOMEvents ( ) { this . domListener = Rx . DOM . fromMutationObserver ( this . el . nativeElement , { attributes : true } ) . subscribe ( changes => { const newOptions = { } as T2 ; changes . forEach ( change => { if ( 'attributes' === change . type ) { newOptions [ attributeName2PropertyName ( change . attributeName ) ] = CanvasGauges . DomObserver . parse ( this . el . nativeElement . getAttribute ( change . attributeName ) ) ; } } ) ; this . basicUpdate ( newOptions ) ; } ) ; } /**
     * Discontinue listening for attribute change events.
     */ protected stopListeningForDOMEvents ( ) { if ( this . domListener ) { this . domListener . disconnect ( ) ; this . domListener = null ; } } /**
     * Initalize the gauge with all options defined by attributes and
     * parent component options.
     */ protected initGauge ( ) { const options = this . options ; if ( this . preInitValue ) { options . value = this . preInitValue ; } if ( ! options . hasOwnProperty ( 'renderTo' ) || ! options . renderTo ) { options . renderTo = this . canvas . nativeElement ; } this . basicUpdate ( options ) ; } param options protected basicUpdate ( options ) { if ( typeof options . value === 'number' ) { this . value = options . value ; delete options . value ; } if ( Object . keys ( options ) . length ) { this . gauge . update ( options ) ; } } }