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