]> git.proxmox.com Git - ceph.git/blob - ceph/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard-v3/dashboard-pie/dashboard-pie.component.ts
update ceph source to reef 18.1.2
[ceph.git] / ceph / src / pybind / mgr / dashboard / frontend / src / app / ceph / dashboard-v3 / dashboard-pie / dashboard-pie.component.ts
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 }