]> git.apps.os.sepia.ceph.com Git - ceph.git/blob
4680fb850a144d0fbc7344384bff751b747dcc23
[ceph.git] /
1 import { Component, Input, OnChanges, OnInit } from '@angular/core';
2
3 import * as Chart from 'chart.js';
4 import _ from 'lodash';
5
6 import { CssHelper } from '~/app/shared/classes/css-helper';
7 import { DimlessBinaryPipe } from '~/app/shared/pipes/dimless-binary.pipe';
8
9 @Component({
10   selector: 'cd-dashboard-pie',
11   templateUrl: './dashboard-pie.component.html',
12   styleUrls: ['./dashboard-pie.component.scss']
13 })
14 export class DashboardPieComponent implements OnChanges, OnInit {
15   @Input()
16   data: any;
17   @Input()
18   highThreshold: number;
19   @Input()
20   lowThreshold: number;
21
22   color: string;
23
24   chartConfig: any;
25
26   public doughnutChartPlugins: any[] = [
27     {
28       id: 'center_text',
29       beforeDraw(chart: any) {
30         const cssHelper = new CssHelper();
31         const defaultFontFamily = 'Helvetica Neue, Helvetica, Arial, sans-serif';
32         Chart.defaults.font.family = defaultFontFamily;
33         const ctx = chart.ctx;
34         if (!chart.options.plugins.center_text || !chart.data.datasets[0].label) {
35           return;
36         }
37
38         ctx.save();
39         const label = chart.data.datasets[0].label[0].split('\n');
40
41         const centerX = (chart.chartArea.left + chart.chartArea.right) / 2;
42         const centerY = (chart.chartArea.top + chart.chartArea.bottom) / 2;
43         ctx.textAlign = 'center';
44         ctx.textBaseline = 'middle';
45
46         ctx.font = `24px ${defaultFontFamily}`;
47         ctx.fillText(label[0], centerX, centerY - 10);
48
49         if (label.length > 1) {
50           ctx.font = `14px ${defaultFontFamily}`;
51           ctx.fillStyle = cssHelper.propertyValue('chart-color-center-text-description');
52           ctx.fillText(label[1], centerX, centerY + 10);
53         }
54         ctx.restore();
55       }
56     }
57   ];
58
59   constructor(private cssHelper: CssHelper, private dimlessBinary: DimlessBinaryPipe) {
60     this.chartConfig = {
61       chartType: 'doughnut',
62       labels: ['', '', ''],
63       dataset: [
64         {
65           label: null,
66           backgroundColor: [
67             this.cssHelper.propertyValue('chart-color-light-gray'),
68             this.cssHelper.propertyValue('chart-color-slight-dark-gray'),
69             this.cssHelper.propertyValue('chart-color-dark-gray')
70           ]
71         },
72         {
73           label: null,
74           borderWidth: 0,
75           backgroundColor: [
76             this.cssHelper.propertyValue('chart-color-blue'),
77             this.cssHelper.propertyValue('chart-color-white')
78           ]
79         }
80       ],
81       options: {
82         cutout: '70%',
83         events: ['click', 'mouseout', 'touchstart'],
84         aspectRatio: 2,
85         plugins: {
86           center_text: true,
87           legend: {
88             display: true,
89             position: 'right',
90             labels: {
91               boxWidth: 10,
92               usePointStyle: false,
93               generateLabels: (chart: any) => {
94                 let labels = chart.data.labels.slice(0, this.chartConfig.labels.length);
95                 labels[0] = {
96                   text: $localize`Used: ${chart.data.datasets[1].data[2]}`,
97                   fillStyle: chart.data.datasets[1].backgroundColor[0],
98                   strokeStyle: chart.data.datasets[1].backgroundColor[0]
99                 };
100                 labels[1] = {
101                   text: $localize`Warning: ${chart.data.datasets[0].data[0]}%`,
102                   fillStyle: chart.data.datasets[0].backgroundColor[1],
103                   strokeStyle: chart.data.datasets[0].backgroundColor[1]
104                 };
105                 labels[2] = {
106                   text: $localize`Danger: ${
107                     chart.data.datasets[0].data[0] + chart.data.datasets[0].data[1]
108                   }%`,
109                   fillStyle: chart.data.datasets[0].backgroundColor[2],
110                   strokeStyle: chart.data.datasets[0].backgroundColor[2]
111                 };
112
113                 return labels;
114               }
115             }
116           },
117           tooltip: {
118             enabled: true,
119             displayColors: false,
120             backgroundColor: this.cssHelper.propertyValue('chart-color-tooltip-background'),
121             cornerRadius: 0,
122             bodyFontSize: 14,
123             bodyFontStyle: '600',
124             position: 'nearest',
125             xPadding: 12,
126             yPadding: 12,
127             filter: (tooltipItem: any) => {
128               return tooltipItem.datasetIndex === 1;
129             },
130             callbacks: {
131               label: (item: Record<string, any>, data: Record<string, any>) => {
132                 let text = data.labels[item.index];
133                 if (!text.includes('%')) {
134                   text = `${text} (${data.datasets[item.datasetIndex].data[item.index]}%)`;
135                 }
136                 return text;
137               }
138             }
139           },
140           title: {
141             display: false
142           }
143         }
144       }
145     };
146   }
147
148   ngOnInit() {
149     this.prepareRawUsage(this.chartConfig, this.data);
150   }
151
152   ngOnChanges() {
153     this.prepareRawUsage(this.chartConfig, this.data);
154   }
155
156   private prepareRawUsage(chart: Record<string, any>, data: Record<string, any>) {
157     const nearFullRatioPercent = this.lowThreshold * 100;
158     const fullRatioPercent = this.highThreshold * 100;
159     const percentAvailable = this.calcPercentage(data.max - data.current, data.max);
160     const percentUsed = this.calcPercentage(data.current, data.max);
161     if (percentUsed >= fullRatioPercent) {
162       this.color = 'chart-color-red';
163     } else if (percentUsed >= nearFullRatioPercent) {
164       this.color = 'chart-color-yellow';
165     } else {
166       this.color = 'chart-color-blue';
167     }
168
169     chart.dataset[0].data = [
170       Math.round(nearFullRatioPercent),
171       Math.round(Math.abs(nearFullRatioPercent - fullRatioPercent)),
172       Math.round(100 - fullRatioPercent)
173     ];
174
175     chart.dataset[1].data = [
176       percentUsed,
177       percentAvailable,
178       this.dimlessBinary.transform(data.current)
179     ];
180     chart.dataset[1].backgroundColor[0] = this.cssHelper.propertyValue(this.color);
181
182     chart.dataset[0].label = [`${percentUsed}%\nof ${this.dimlessBinary.transform(data.max)}`];
183   }
184
185   private calcPercentage(dividend: number, divisor: number) {
186     if (!_.isNumber(dividend) || !_.isNumber(divisor) || divisor === 0) {
187       return 0;
188     }
189     return Math.ceil((dividend / divisor) * 100 * 100) / 100;
190   }
191 }