1 import { Component, Input, ViewChild, OnChanges, SimpleChanges } from '@angular/core';
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';
13 selector: 'cd-dashboard-area-chart',
14 templateUrl: './dashboard-area-chart.component.html',
15 styleUrls: ['./dashboard-area-chart.component.scss']
17 export class DashboardAreaChartComponent implements OnChanges {
18 @ViewChild(BaseChartDirective) chart: BaseChartDirective;
27 dataArray?: Array<Array<[number, string]>>; // Array of query results
29 labelsArray?: string[] = []; // Array of chart labels
31 decimals?: number = 1;
33 truncateLabel = false;
35 isMultiCluster?: boolean = false;
37 currentDataUnits: string;
39 maxConvertedValue?: number;
40 maxConvertedValueUnits?: string;
42 chartDataUnits: string;
43 chartData: any = { dataset: [] };
45 currentChartData: any = {};
47 chartColors: any[] = [
49 this.cssHelper.propertyValue('chart-color-strong-blue'),
50 this.cssHelper.propertyValue('chart-color-translucent-blue')
53 this.cssHelper.propertyValue('chart-color-orange'),
54 this.cssHelper.propertyValue('chart-color-translucent-orange')
57 this.cssHelper.propertyValue('chart-color-green'),
58 this.cssHelper.propertyValue('chart-color-translucent-green')
61 this.cssHelper.propertyValue('chart-color-cyan'),
62 this.cssHelper.propertyValue('chart-color-translucent-cyan')
65 this.cssHelper.propertyValue('chart-color-purple'),
66 this.cssHelper.propertyValue('chart-color-translucent-purple')
69 this.cssHelper.propertyValue('chart-color-red'),
70 this.cssHelper.propertyValue('chart-color-translucent-red')
74 public chartAreaBorderPlugin: any[] = [
76 beforeDraw(chart: any) {
77 if (!chart.options.plugins.borderArea) {
82 chartArea: { left, top, width, height }
85 ctx.strokeStyle = chart.options.plugins.chartAreaBorder.borderColor;
86 ctx.lineWidth = chart.options.plugins.chartAreaBorder.borderWidth;
87 ctx.setLineDash(chart.options.plugins.chartAreaBorder.borderDash || []);
88 ctx.lineDashOffset = chart.options.plugins.chartAreaBorder.borderDashOffset;
89 ctx.strokeRect(left, top, width, height);
96 private cssHelper: CssHelper,
97 private dimlessBinary: DimlessBinaryPipe,
98 private dimlessBinaryPerSecond: DimlessBinaryPerSecondPipe,
99 private dimlessPipe: DimlessPipe,
100 private formatter: FormatterService,
101 private numberFormatter: NumberFormatterService
110 external: function (tooltipModel: any) {
111 tooltipModel.tooltip.x = 10;
112 tooltipModel.tooltip.y = 0;
116 backgroundColor: this.cssHelper.propertyValue('chart-color-tooltip-background'),
118 title: function (tooltipItem: any): any {
119 return tooltipItem[0].xLabel;
121 label: (context: any) => {
124 context.dataset.label +
126 context.formattedValue +
135 borderColor: this.cssHelper.propertyValue('chart-color-slight-dark-gray'),
140 maintainAspectRatio: false,
158 tooltipFormat: 'DD/MM/YYYY - HH:mm:ss'
162 afterFit: (scaleInstance: any) => (scaleInstance.width = 100),
175 ngOnChanges(changes: SimpleChanges): void {
176 this.updateChartData(changes);
180 this.updateChartData(null);
183 private updateChartData(changes: SimpleChanges): void {
184 this.labelsArray.forEach((_label: string, index: number) => {
185 const colorIndex = index % this.chartColors?.length;
186 this.chartData.dataset[index] = {
190 pointBackgroundColor: this.chartColors[colorIndex][0],
191 backgroundColor: this.chartColors[colorIndex][1],
192 borderColor: this.chartColors[colorIndex][0],
198 this.chartData.dataset[index].label = this.labelsArray[index];
201 this.setChartTicks();
203 if (this.dataArray?.[0]?.length) {
204 this.dataArray = changes?.dataArray?.currentValue || this.dataArray;
205 this.currentChartData = this.chartData;
206 this.dataArray?.forEach((_data: Array<[number, string]>, index: number) => {
207 this.chartData.dataset[index].data = this.formatData(this.dataArray[index]);
208 let currentDataValue = this.dataArray?.[index]?.[this.dataArray[index]?.length - 1]
209 ? this.dataArray[index][this.dataArray[index]?.length - 1][1]
211 if (currentDataValue) {
213 this.currentChartData.dataset[index]['currentData'],
214 this.currentChartData.dataset[index]['currentDataUnits']
215 ] = this.convertUnits(currentDataValue).split(' ');
216 [this.maxConvertedValue, this.maxConvertedValueUnits] = this.convertUnits(
219 this.currentChartData.dataset[index]['currentDataValue'] = currentDataValue;
222 this.currentChartData.dataset.sort(
223 (a: { currentDataValue: string }, b: { currentDataValue: string }) =>
224 parseFloat(b['currentDataValue']) - parseFloat(a['currentDataValue'])
229 this.chart.chart.update();
233 private formatData(array: Array<any>): any {
234 let formattedData = {};
235 formattedData = array?.map((data: any) => ({
237 y: Number(this.convertToChartDataUnits(data[1]).replace(/[^\d,.]+/g, ''))
239 return formattedData;
242 private convertToChartDataUnits(data: any): any {
243 let dataWithUnits: string = '';
244 if (this.chartDataUnits !== null) {
245 if (this.dataUnits === 'B') {
246 dataWithUnits = this.numberFormatter.formatBytesFromTo(
252 } else if (this.dataUnits === 'B/s') {
253 dataWithUnits = this.numberFormatter.formatBytesPerSecondFromTo(
259 } else if (this.dataUnits === 'ms') {
260 dataWithUnits = this.numberFormatter.formatSecondsFromTo(
267 dataWithUnits = this.numberFormatter.formatUnitlessFromTo(
275 return dataWithUnits;
278 private convertUnits(data: any): any {
279 let dataWithUnits: string = '';
280 if (this.dataUnits === 'B') {
281 dataWithUnits = this.dimlessBinary.transform(data, this.decimals);
282 } else if (this.dataUnits === 'B/s') {
283 dataWithUnits = this.dimlessBinaryPerSecond.transform(data, this.decimals);
284 } else if (this.dataUnits === 'ms') {
285 dataWithUnits = this.formatter.format_number(data, 1000, ['ms', 's'], this.decimals);
287 dataWithUnits = this.dimlessPipe.transform(data, this.decimals);
289 return dataWithUnits;
292 private setChartTicks() {
294 this.chartDataUnits = '';
299 let maxValueDataUnits = '';
301 const allDataValues = this.dataArray?.reduce((array: string[], data) => {
302 return array.concat(data?.map((values: [number, string]) => values[1]));
305 maxValue = allDataValues ? Math.max(...allDataValues.map(Number)) : 0;
306 [maxValue, maxValueDataUnits] = this.convertUnits(maxValue).split(' ');
308 const yAxesTicks = this.chart.chart.options.scales.y;
309 yAxesTicks.ticks.callback = (value: any) => {
313 if (!maxValueDataUnits) {
316 return `${value} ${maxValueDataUnits}`;
318 this.chartDataUnits = maxValueDataUnits || '';
319 this.chart.chart.update();