]> git.proxmox.com Git - ceph.git/blame - ceph/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard/health-pie/health-pie.component.ts
update source to Ceph Pacific 16.2.2
[ceph.git] / ceph / src / pybind / mgr / dashboard / frontend / src / app / ceph / dashboard / health-pie / health-pie.component.ts
CommitLineData
11fdf7f2
TL
1import {
2 Component,
3 ElementRef,
4 EventEmitter,
5 Input,
6 OnChanges,
7 OnInit,
8 Output,
9 ViewChild
10} from '@angular/core';
11
12import * as Chart from 'chart.js';
f67539c2 13import _ from 'lodash';
f91f0fd5 14import { PluginServiceGlobalRegistrationAndOptions } from 'ng2-charts';
11fdf7f2 15
f67539c2
TL
16import { ChartTooltip } from '~/app/shared/models/chart-tooltip';
17import { DimlessBinaryPipe } from '~/app/shared/pipes/dimless-binary.pipe';
18import { DimlessPipe } from '~/app/shared/pipes/dimless.pipe';
19import styles from '~/styles.scss';
11fdf7f2
TL
20
21@Component({
22 selector: 'cd-health-pie',
23 templateUrl: './health-pie.component.html',
24 styleUrls: ['./health-pie.component.scss']
25})
26export class HealthPieComponent implements OnChanges, OnInit {
9f95a23c 27 @ViewChild('chartCanvas', { static: true })
11fdf7f2 28 chartCanvasRef: ElementRef;
9f95a23c 29 @ViewChild('chartTooltip', { static: true })
11fdf7f2
TL
30 chartTooltipRef: ElementRef;
31
32 @Input()
33 data: any;
34 @Input()
81eedcae 35 config = {};
11fdf7f2
TL
36 @Input()
37 isBytesData = false;
38 @Input()
11fdf7f2 39 tooltipFn: any;
81eedcae
TL
40 @Input()
41 showLabelAsTooltip = false;
11fdf7f2
TL
42 @Output()
43 prepareFn = new EventEmitter();
44
45 chartConfig: any = {
f91f0fd5 46 chartType: 'doughnut',
11fdf7f2
TL
47 dataset: [
48 {
49 label: null,
50 borderWidth: 0
51 }
52 ],
f91f0fd5
TL
53 colors: [
54 {
55 backgroundColor: [
f67539c2
TL
56 styles.chartHealthColorGreen,
57 styles.chartHealthColorYellow,
58 styles.chartHealthColorOrange,
59 styles.chartHealthColorRed,
60 styles.chartHealthColorBlue
f91f0fd5
TL
61 ]
62 }
63 ],
11fdf7f2 64 options: {
f91f0fd5
TL
65 cutoutPercentage: 90,
66 events: ['click', 'mouseout', 'touchstart'],
11fdf7f2 67 legend: {
81eedcae 68 display: true,
11fdf7f2 69 position: 'right',
f91f0fd5
TL
70 labels: {
71 boxWidth: 10,
72 usePointStyle: false
11fdf7f2
TL
73 }
74 },
f91f0fd5
TL
75 plugins: {
76 center_text: true
77 },
11fdf7f2 78 tooltips: {
f91f0fd5
TL
79 enabled: true,
80 displayColors: false,
f67539c2 81 backgroundColor: styles.chartHealthTootlipBgColor,
f91f0fd5
TL
82 cornerRadius: 0,
83 bodyFontSize: 14,
84 bodyFontStyle: '600',
85 position: 'nearest',
86 xPadding: 12,
87 yPadding: 12,
88 callbacks: {
89 label: (item: Record<string, any>, data: Record<string, any>) => {
90 let text = data.labels[item.index];
91 if (!text.includes('%')) {
92 text = `${text} (${data.datasets[item.datasetIndex].data[item.index]}%)`;
93 }
94 return text;
95 }
96 }
81eedcae
TL
97 },
98 title: {
99 display: false
11fdf7f2
TL
100 }
101 }
102 };
11fdf7f2 103
f91f0fd5
TL
104 public doughnutChartPlugins: PluginServiceGlobalRegistrationAndOptions[] = [
105 {
106 id: 'center_text',
107 beforeDraw(chart: Chart) {
f91f0fd5
TL
108 const defaultFontFamily = 'Helvetica Neue, Helvetica, Arial, sans-serif';
109 Chart.defaults.global.defaultFontFamily = defaultFontFamily;
110 const ctx = chart.ctx;
111 if (!chart.options.plugins.center_text || !chart.data.datasets[0].label) {
11fdf7f2
TL
112 return;
113 }
114
f91f0fd5
TL
115 ctx.save();
116 const label = chart.data.datasets[0].label.split('\n');
11fdf7f2 117
f91f0fd5
TL
118 const centerX = (chart.chartArea.left + chart.chartArea.right) / 2;
119 const centerY = (chart.chartArea.top + chart.chartArea.bottom) / 2;
120 ctx.textAlign = 'center';
11fdf7f2
TL
121 ctx.textBaseline = 'middle';
122
f91f0fd5 123 ctx.font = `24px ${defaultFontFamily}`;
f67539c2 124 ctx.fillStyle = styles.chartHealthCenterTextColor;
f91f0fd5 125 ctx.fillText(label[0], centerX, centerY - 10);
11fdf7f2 126
f91f0fd5
TL
127 if (label.length > 1) {
128 ctx.font = `14px ${defaultFontFamily}`;
f67539c2 129 ctx.fillStyle = styles.chartHealthCenterTextDescriptionColor;
f91f0fd5
TL
130 ctx.fillText(label[1], centerX, centerY + 10);
131 }
132 ctx.restore();
11fdf7f2 133 }
f91f0fd5
TL
134 }
135 ];
136
137 constructor(private dimlessBinary: DimlessBinaryPipe, private dimless: DimlessPipe) {}
11fdf7f2 138
f91f0fd5 139 ngOnInit() {
9f95a23c 140 const getStyleTop = (tooltip: any, positionY: number) => {
11fdf7f2
TL
141 return positionY + tooltip.caretY - tooltip.height - 10 + 'px';
142 };
143
9f95a23c 144 const getStyleLeft = (tooltip: any, positionX: number) => {
11fdf7f2
TL
145 return positionX + tooltip.caretX + 'px';
146 };
147
148 const chartTooltip = new ChartTooltip(
149 this.chartCanvasRef,
150 this.chartTooltipRef,
151 getStyleLeft,
152 getStyleTop
153 );
154
f91f0fd5 155 chartTooltip.getBody = (body: any) => {
11fdf7f2
TL
156 return this.getChartTooltipBody(body);
157 };
158
81eedcae
TL
159 _.merge(this.chartConfig, this.config);
160
11fdf7f2
TL
161 this.prepareFn.emit([this.chartConfig, this.data]);
162 }
163
164 ngOnChanges() {
165 this.prepareFn.emit([this.chartConfig, this.data]);
11fdf7f2
TL
166 this.setChartSliceBorderWidth();
167 }
168
9f95a23c 169 private getChartTooltipBody(body: string[]) {
11fdf7f2
TL
170 const bodySplit = body[0].split(': ');
171
81eedcae
TL
172 if (this.showLabelAsTooltip) {
173 return bodySplit[0];
11fdf7f2
TL
174 }
175
81eedcae
TL
176 bodySplit[1] = this.isBytesData
177 ? this.dimlessBinary.transform(bodySplit[1])
178 : this.dimless.transform(bodySplit[1]);
11fdf7f2 179
81eedcae 180 return bodySplit.join(': ');
11fdf7f2
TL
181 }
182
183 private setChartSliceBorderWidth() {
184 let nonZeroValueSlices = 0;
e306af50 185 _.forEach(this.chartConfig.dataset[0].data, function (slice) {
11fdf7f2
TL
186 if (slice > 0) {
187 nonZeroValueSlices += 1;
188 }
189 });
190
191 this.chartConfig.dataset[0].borderWidth = nonZeroValueSlices > 1 ? 1 : 0;
192 }
11fdf7f2 193}