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