]> git.apps.os.sepia.ceph.com Git - ceph.git/blob
cbf97691d27dc803a3beb591c316e880da6979a6
[ceph.git] /
1 import { Component, Input, OnChanges, SimpleChanges, ViewChild } from '@angular/core';
2
3 import { CssHelper } from '~/app/shared/classes/css-helper';
4 import { DimlessBinaryPipe } from '~/app/shared/pipes/dimless-binary.pipe';
5 import { DimlessBinaryPerSecondPipe } from '~/app/shared/pipes/dimless-binary-per-second.pipe';
6 import { FormatterService } from '~/app/shared/services/formatter.service';
7 import { BaseChartDirective } from 'ng2-charts';
8 import { DimlessPipe } from '~/app/shared/pipes/dimless.pipe';
9 import { NumberFormatterService } from '~/app/shared/services/number-formatter.service';
10 import 'chartjs-adapter-moment';
11
12 @Component({
13   selector: 'cd-dashboard-area-chart',
14   templateUrl: './dashboard-area-chart.component.html',
15   styleUrls: ['./dashboard-area-chart.component.scss']
16 })
17 export class DashboardAreaChartComponent implements OnChanges {
18   @ViewChild(BaseChartDirective) chart: BaseChartDirective;
19
20   @Input()
21   chartTitle: string;
22   @Input()
23   maxValue?: number;
24   @Input()
25   dataUnits: string;
26   @Input()
27   data: Array<[number, string]>;
28   @Input()
29   data2?: Array<[number, string]>;
30   @Input()
31   label: string;
32   @Input()
33   label2?: string;
34   @Input()
35   decimals?: number = 1;
36
37   currentDataUnits: string;
38   currentData: number;
39   currentDataUnits2?: string;
40   currentData2?: number;
41   maxConvertedValue?: number;
42   maxConvertedValueUnits?: string;
43
44   chartDataUnits: string;
45   chartData: any;
46   options: any;
47
48   public chartAreaBorderPlugin: any[] = [
49     {
50       beforeDraw(chart: any) {
51         if (!chart.options.plugins.borderArea) {
52           return;
53         }
54         const {
55           ctx,
56           chartArea: { left, top, width, height }
57         } = chart;
58         ctx.save();
59         ctx.strokeStyle = chart.options.plugins.chartAreaBorder.borderColor;
60         ctx.lineWidth = chart.options.plugins.chartAreaBorder.borderWidth;
61         ctx.setLineDash(chart.options.plugins.chartAreaBorder.borderDash || []);
62         ctx.lineDashOffset = chart.options.plugins.chartAreaBorder.borderDashOffset;
63         ctx.strokeRect(left, top, width, height);
64         ctx.restore();
65       }
66     }
67   ];
68
69   constructor(
70     private cssHelper: CssHelper,
71     private dimlessBinary: DimlessBinaryPipe,
72     private dimlessBinaryPerSecond: DimlessBinaryPerSecondPipe,
73     private dimlessPipe: DimlessPipe,
74     private formatter: FormatterService,
75     private numberFormatter: NumberFormatterService
76   ) {
77     this.chartData = {
78       dataset: [
79         {
80           label: '',
81           data: [{ x: 0, y: 0 }],
82           tension: 0.2,
83           pointBackgroundColor: this.cssHelper.propertyValue('chart-color-strong-blue'),
84           backgroundColor: this.cssHelper.propertyValue('chart-color-translucent-blue'),
85           borderColor: this.cssHelper.propertyValue('chart-color-strong-blue'),
86           borderWidth: 1,
87           fill: {
88             target: 'origin'
89           }
90         },
91         {
92           label: '',
93           data: [],
94           tension: 0.2,
95           pointBackgroundColor: this.cssHelper.propertyValue('chart-color-orange'),
96           backgroundColor: this.cssHelper.propertyValue('chart-color-translucent-yellow'),
97           borderColor: this.cssHelper.propertyValue('chart-color-orange'),
98           borderWidth: 1,
99           fill: {
100             target: 'origin'
101           }
102         }
103       ]
104     };
105
106     this.options = {
107       plugins: {
108         legend: {
109           display: false
110         },
111         tooltip: {
112           mode: 'index',
113           external: function (tooltipModel: any) {
114             tooltipModel.tooltip.x = 10;
115             tooltipModel.tooltip.y = 0;
116           }.bind(this),
117           intersect: false,
118           displayColors: true,
119           backgroundColor: this.cssHelper.propertyValue('chart-color-tooltip-background'),
120           callbacks: {
121             title: function (tooltipItem: any): any {
122               return tooltipItem[0].xLabel;
123             },
124             label: (context: any) => {
125               return (
126                 ' ' +
127                 context.dataset.label +
128                 ' - ' +
129                 context.formattedValue +
130                 ' ' +
131                 this.chartDataUnits
132               );
133             }
134           }
135         },
136         borderArea: true,
137         chartAreaBorder: {
138           borderColor: this.cssHelper.propertyValue('chart-color-slight-dark-gray'),
139           borderWidth: 1
140         }
141       },
142       responsive: true,
143       maintainAspectRatio: false,
144       animation: false,
145       elements: {
146         point: {
147           radius: 0
148         }
149       },
150       hover: {
151         intersect: false
152       },
153       scales: {
154         x: {
155           display: false,
156           type: 'time',
157           grid: {
158             display: false
159           },
160           time: {
161             tooltipFormat: 'DD/MM/YYYY - HH:mm:ss'
162           }
163         },
164         y: {
165           afterFit: (scaleInstance: any) => (scaleInstance.width = 100),
166           grid: {
167             display: false
168           },
169           beginAtZero: true,
170           ticks: {
171             maxTicksLimit: 4
172           }
173         }
174       }
175     };
176   }
177
178   ngOnChanges(changes: SimpleChanges): void {
179     this.updateChartData(changes);
180   }
181
182   private updateChartData(changes: SimpleChanges): void {
183     this.chartData.dataset[0].label = this.label;
184     this.chartData.dataset[1].label = this.label2;
185     this.setChartTicks();
186     if (changes.data && changes.data.currentValue) {
187       this.data = changes.data.currentValue;
188       this.chartData.dataset[0].data = this.formatData(this.data);
189       [this.currentData, this.currentDataUnits] = this.convertUnits(
190         this.data[this.data.length - 1][1]
191       ).split(' ');
192       [this.maxConvertedValue, this.maxConvertedValueUnits] = this.convertUnits(
193         this.maxValue
194       ).split(' ');
195     }
196     if (changes.data2 && changes.data2.currentValue) {
197       this.data2 = changes.data2.currentValue;
198       this.chartData.dataset[1].data = this.formatData(this.data2);
199       [this.currentData2, this.currentDataUnits2] = this.convertUnits(
200         this.data2[this.data2.length - 1][1]
201       ).split(' ');
202     }
203     if (this.chart) {
204       this.chart.chart.update();
205     }
206   }
207
208   private formatData(array: Array<any>): any {
209     let formattedData = {};
210     formattedData = array.map((data: any) => ({
211       x: data[0] * 1000,
212       y: Number(this.convertToChartDataUnits(data[1]).replace(/[^\d,.]+/g, ''))
213     }));
214     return formattedData;
215   }
216
217   private convertToChartDataUnits(data: any): any {
218     let dataWithUnits: string = '';
219     if (this.chartDataUnits !== null) {
220       if (this.dataUnits === 'B') {
221         dataWithUnits = this.numberFormatter.formatBytesFromTo(
222           data,
223           this.dataUnits,
224           this.chartDataUnits,
225           this.decimals
226         );
227       } else if (this.dataUnits === 'B/s') {
228         dataWithUnits = this.numberFormatter.formatBytesPerSecondFromTo(
229           data,
230           this.dataUnits,
231           this.chartDataUnits,
232           this.decimals
233         );
234       } else if (this.dataUnits === 'ms') {
235         dataWithUnits = this.numberFormatter.formatSecondsFromTo(
236           data,
237           this.dataUnits,
238           this.chartDataUnits,
239           this.decimals
240         );
241       } else {
242         dataWithUnits = this.numberFormatter.formatUnitlessFromTo(
243           data,
244           this.dataUnits,
245           this.chartDataUnits,
246           this.decimals
247         );
248       }
249     }
250     return dataWithUnits;
251   }
252
253   private convertUnits(data: any): any {
254     let dataWithUnits: string = '';
255     if (this.dataUnits === 'B') {
256       dataWithUnits = this.dimlessBinary.transform(data, this.decimals);
257     } else if (this.dataUnits === 'B/s') {
258       dataWithUnits = this.dimlessBinaryPerSecond.transform(data, this.decimals);
259     } else if (this.dataUnits === 'ms') {
260       dataWithUnits = this.formatter.format_number(data, 1000, ['ms', 's'], this.decimals);
261     } else {
262       dataWithUnits = this.dimlessPipe.transform(data, this.decimals);
263     }
264     return dataWithUnits;
265   }
266
267   private setChartTicks() {
268     if (!this.chart) {
269       this.chartDataUnits = '';
270       return;
271     }
272
273     let maxValue = 0;
274     let maxValueDataUnits = '';
275
276     if (this.data) {
277       let maxValueData = Math.max(...this.data.map((values: any) => values[1]));
278       if (this.data2) {
279         let maxValueData2 = Math.max(...this.data2.map((values: any) => values[1]));
280         maxValue = Math.max(maxValueData, maxValueData2);
281       } else {
282         maxValue = maxValueData;
283       }
284       [maxValue, maxValueDataUnits] = this.convertUnits(maxValue).split(' ');
285     }
286
287     const yAxesTicks = this.chart.chart.options.scales.y;
288     yAxesTicks.ticks.callback = (value: any) => {
289       if (value === 0) {
290         return null;
291       }
292       if (!maxValueDataUnits) {
293         return `${value}`;
294       }
295       return `${value} ${maxValueDataUnits}`;
296     };
297     this.chartDataUnits = maxValueDataUnits || '';
298     this.chart.chart.update();
299   }
300 }