@@ -22,10 +22,19 @@ import {
2222
2323import merge from 'lodash-es/merge' ;
2424
25- import { Chart , ChartConfiguration , ChartType , DefaultDataPoint , registerables } from 'chart.js' ;
25+ import {
26+ Chart as ChartJS ,
27+ ChartConfiguration ,
28+ ChartData ,
29+ ChartOptions ,
30+ ChartType ,
31+ InteractionItem ,
32+ Plugin ,
33+ registerables
34+ } from 'chart.js' ;
2635import { customTooltips as cuiCustomTooltips } from '@coreui/chartjs' ;
2736
28- Chart . register ( ...registerables ) ;
37+ ChartJS . register ( ...registerables ) ;
2938
3039let nextId = 0 ;
3140
@@ -39,26 +48,70 @@ let nextId = 0;
3948 // eslint-disable-next-line @angular-eslint/no-host-metadata-property
4049 // host: { ngSkipHydration: 'true' }
4150} )
42- export class ChartjsComponent < TType extends ChartType = ChartType , TData = DefaultDataPoint < TType > , TLabel = unknown > implements AfterViewInit , OnDestroy , OnChanges {
43-
44- @Input ( ) customTooltips = true ;
45- @Input ( ) data ?: ChartConfiguration < TType , TData , TLabel > [ 'data' ] ;
46-
51+ export class ChartjsComponent implements AfterViewInit , OnDestroy , OnChanges {
52+
53+ /**
54+ * Enables custom html based tooltips instead of standard tooltips.
55+ * @type boolean
56+ * @default true
57+ */
58+ @Input ( { transform : booleanAttribute } ) customTooltips : boolean = true ;
59+
60+ /**
61+ * The data object that is passed into the Chart.js chart (more info).
62+ */
63+ @Input ( ) data ?: ChartData ;
64+
65+ /**
66+ * Height attribute applied to the rendered canvas.
67+ * @type number | undefined
68+ * @default 150
69+ */
4770 @HostBinding ( 'style.height.px' )
48- @Input ( { transform : ( value : string | number ) => numberAttribute ( value , undefined ) } ) height ?: string | number ;
49-
50- @Input ( ) id = `c-chartjs-${ nextId ++ } ` ;
51- @Input ( ) options ?: ChartConfiguration < TType , TData , TLabel > [ 'options' ] ;
52- @Input ( ) plugins : ChartConfiguration < TType , TData , TLabel > [ 'plugins' ] = [ ] ;
53-
54- @Input ( { transform : booleanAttribute } ) redraw : string | boolean = false ;
55-
56- @Input ( ) type : ChartConfiguration < TType , TData , TLabel > [ 'type' ] = 'bar' as TType ;
57-
71+ @Input ( { transform : ( value : string | number ) => numberAttribute ( value , undefined ) } ) height ?: number ;
72+
73+ /**
74+ * ID attribute applied to the rendered canvas.
75+ * @type string
76+ */
77+ @Input ( ) id : string = `c-chartjs-${ nextId ++ } ` ;
78+
79+ /**
80+ * The options object that is passed into the Chart.js chart.
81+ */
82+ @Input ( ) options ?: ChartOptions = { } ;
83+
84+ /**
85+ * The plugins array that is passed into the Chart.js chart
86+ */
87+ @Input ( ) plugins : Plugin [ ] = [ ] ;
88+
89+ /**
90+ * If true, will tear down and redraw chart on all updates.
91+ * @type boolean
92+ * @default false
93+ */
94+ @Input ( { transform : booleanAttribute } ) redraw : boolean = false ;
95+
96+ /**
97+ * Chart.js chart type.
98+ * @type {'line' | 'bar' | 'radar' | 'doughnut' | 'polarArea' | 'bubble' | 'pie' | 'scatter' }
99+ */
100+ @Input ( ) type : ChartType = 'bar' ;
101+
102+ /**
103+ * Width attribute applied to the rendered canvas.
104+ * @type number | undefined
105+ * @default 300
106+ */
58107 @HostBinding ( 'style.width.px' )
59- @Input ( { transform : ( value : string | number ) => numberAttribute ( value , undefined ) } ) width ?: string | number ;
108+ @Input ( { transform : ( value : string | number ) => numberAttribute ( value , undefined ) } ) width ?: number ;
60109
61- @Input ( ) wrapper = true ;
110+ /**
111+ * Put the chart into the wrapper div element.
112+ * @default true
113+ */
114+ @Input ( { transform : booleanAttribute } ) wrapper = true ;
62115
63116 @Output ( ) readonly getDatasetAtEvent = new EventEmitter < any > ( ) ;
64117 @Output ( ) readonly getElementAtEvent = new EventEmitter < any > ( ) ;
@@ -68,7 +121,7 @@ export class ChartjsComponent<TType extends ChartType = ChartType, TData = Defau
68121
69122 @ViewChild ( 'canvasElement' ) canvasElement ! : ElementRef ;
70123
71- chart ! : Chart < TType , TData , TLabel > ;
124+ chart ! : ChartJS ;
72125 ctx ! : CanvasRenderingContext2D ;
73126
74127 @HostBinding ( 'class' )
@@ -79,10 +132,9 @@ export class ChartjsComponent<TType extends ChartType = ChartType, TData = Defau
79132 }
80133
81134 constructor (
82- private elementRef : ElementRef ,
83- private ngZone : NgZone ,
84- private renderer : Renderer2 ,
85- private changeDetectorRef : ChangeDetectorRef
135+ private readonly ngZone : NgZone ,
136+ private readonly renderer : Renderer2 ,
137+ private readonly changeDetectorRef : ChangeDetectorRef
86138 ) {
87139 // todo: verify afterRender / afterNextRender for chartjs (spec fails with 17.0.10)
88140 afterRender ( ( ) => {
@@ -110,13 +162,13 @@ export class ChartjsComponent<TType extends ChartType = ChartType, TData = Defau
110162 return ;
111163 }
112164
113- const datasetAtEvent = this . chart . getElementsAtEventForMode ( $event , 'dataset' , { intersect : true } , false ) ;
165+ const datasetAtEvent : InteractionItem [ ] = this . chart . getElementsAtEventForMode ( $event , 'dataset' , { intersect : true } , false ) ;
114166 this . getDatasetAtEvent . emit ( datasetAtEvent ) ;
115167
116- const elementAtEvent = this . chart . getElementsAtEventForMode ( $event , 'nearest' , { intersect : true } , false ) ;
168+ const elementAtEvent : InteractionItem [ ] = this . chart . getElementsAtEventForMode ( $event , 'nearest' , { intersect : true } , false ) ;
117169 this . getElementAtEvent . emit ( elementAtEvent ) ;
118170
119- const elementsAtEvent = this . chart . getElementsAtEventForMode ( $event , 'index' , { intersect : true } , false ) ;
171+ const elementsAtEvent : InteractionItem [ ] = this . chart . getElementsAtEventForMode ( $event , 'index' , { intersect : true } , false ) ;
120172 this . getElementsAtEvent . emit ( elementsAtEvent ) ;
121173 }
122174
@@ -126,15 +178,15 @@ export class ChartjsComponent<TType extends ChartType = ChartType, TData = Defau
126178 }
127179
128180 public chartRender ( ) {
129- if ( ! this . canvasElement ?. nativeElement || ! this . ctx ) {
181+ if ( ! this . canvasElement ?. nativeElement || ! this . ctx || this . chart ) {
130182 return ;
131183 }
132184
133185 this . ngZone . runOutsideAngular ( ( ) => {
134186 const config = this . chartConfig ( ) ;
135187 if ( config ) {
136- setTimeout ( ( ) => {
137- this . chart = new Chart ( this . ctx , config ) ;
188+ this . chart = new ChartJS ( this . ctx , config ) ;
189+ this . ngZone . run ( ( ) => {
138190 this . renderer . setStyle ( this . canvasElement . nativeElement , 'display' , 'block' ) ;
139191 this . changeDetectorRef . markForCheck ( ) ;
140192 this . chartRef . emit ( this . chart ) ;
@@ -150,13 +202,11 @@ export class ChartjsComponent<TType extends ChartType = ChartType, TData = Defau
150202
151203 if ( this . redraw ) {
152204 this . chartDestroy ( ) ;
153- setTimeout ( ( ) => {
154- this . chartRender ( ) ;
155- } ) ;
205+ this . chartRender ( ) ;
156206 return ;
157207 }
158208
159- const config = this . chartConfig ( ) ;
209+ const config : ChartConfiguration = this . chartConfig ( ) ;
160210
161211 if ( this . options ) {
162212 Object . assign ( this . chart . options ?? { } , config . options ?? { } ) ;
@@ -180,7 +230,9 @@ export class ChartjsComponent<TType extends ChartType = ChartType, TData = Defau
180230 setTimeout ( ( ) => {
181231 this . ngZone . runOutsideAngular ( ( ) => {
182232 this . chart ?. update ( ) ;
183- this . changeDetectorRef . markForCheck ( ) ;
233+ this . ngZone . run ( ( ) => {
234+ this . changeDetectorRef . markForCheck ( ) ;
235+ } ) ;
184236 } ) ;
185237 } ) ;
186238 }
@@ -189,18 +241,18 @@ export class ChartjsComponent<TType extends ChartType = ChartType, TData = Defau
189241 return this . chart ?. toBase64Image ( ) ;
190242 }
191243
192- private chartDataConfig ( ) : ChartConfiguration < TType , TData , TLabel > [ 'data' ] {
244+ private chartDataConfig ( ) : ChartData {
193245 return {
194246 labels : this . data ?. labels ?? [ ] ,
195247 datasets : this . data ?. datasets ?? [ ]
196248 } ;
197249 }
198250
199- private chartOptions ( ) : ChartConfiguration < TType , TData , TLabel > [ 'options' ] {
200- return this . options ;
251+ private chartOptions ( ) : ChartOptions {
252+ return this . options ?? { } ;
201253 }
202254
203- private chartConfig ( ) : ChartConfiguration < TType , TData , TLabel > {
255+ private chartConfig ( ) : ChartConfiguration {
204256 this . chartCustomTooltips ( ) ;
205257 return {
206258 data : this . chartDataConfig ( ) ,
@@ -213,9 +265,7 @@ export class ChartjsComponent<TType extends ChartType = ChartType, TData = Defau
213265 private chartCustomTooltips ( ) {
214266 if ( this . customTooltips ) {
215267 const options = this . options ;
216- // @ts -ignore
217268 const plugins = this . options ?. plugins ;
218- // @ts -ignore
219269 const tooltip = this . options ?. plugins ?. tooltip ;
220270 this . options = merge ( {
221271 ...options ,
0 commit comments