-
Notifications
You must be signed in to change notification settings - Fork 80
Expand file tree
/
Copy pathProgressCircle.tsx
More file actions
106 lines (96 loc) · 3.53 KB
/
Copy pathProgressCircle.tsx
File metadata and controls
106 lines (96 loc) · 3.53 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
import { createElement, CSSProperties, FunctionComponent, ReactNode, useCallback, useEffect, useState } from "react";
import classNames from "classnames";
import { Alert } from "@mendix/widget-plugin-component-kit/Alert";
import Circle from "./Circle/Circle";
import { ShapeOptions } from "./Circle/Types";
import { calculatePercentage } from "../util";
export interface ProgressCircleProps {
class: string;
style?: CSSProperties;
currentValue: number;
minValue: number;
maxValue: number;
onClick: (() => void) | undefined;
label: ReactNode;
}
const defaultOptions: ShapeOptions = {
duration: 800,
// These default values are necessary so that progressbar.js at least renders anything, which we override with custom styling.
// They also need to be equal to the largest size that we have available, since that will determine the size of the bounding box.
strokeWidth: 16,
trailWidth: 16
};
function getValuesErrorMessage(currentValue: number, minValue: number, maxValue: number): string | null {
if (maxValue < minValue) {
return "Error in progress circle values: The maximum value is lower than the minimum value.";
}
if (currentValue < minValue) {
return "Error in progress circle values: The progress value is lower than the minimum value.";
}
if (currentValue > maxValue) {
return "Error in progress circle values: The progress value is higher than the maximum value.";
}
return null;
}
export const ProgressCircle: FunctionComponent<ProgressCircleProps> = ({
class: className,
style,
currentValue,
minValue,
maxValue,
onClick,
label
}) => {
const [progressCircle, setProgressCircle] = useState<Circle>();
const alertMessage = getValuesErrorMessage(currentValue, minValue, maxValue);
const setProgressCircleElement = useCallback(
(node: any) => {
if (node !== null) {
const circleElement = new Circle(node, defaultOptions);
if (circleElement.path) {
circleElement.path.className.baseVal = "widget-progress-circle-path";
}
if (circleElement.trail) {
circleElement.trail.className.baseVal = "widget-progress-circle-trail-path";
}
setProgressCircle(circleElement);
}
},
[setProgressCircle]
);
useEffect(() => {
if (progressCircle) {
const percentage = calculatePercentage(currentValue, minValue, maxValue);
progressCircle.animate(percentage / 100);
}
}, [currentValue, minValue, maxValue, progressCircle]);
useEffect(() => {
return () => {
progressCircle?.destroy();
};
}, [progressCircle]);
return (
<div
className={classNames(
"widget-progress-circle",
"widget-progress-circle-primary",
"widget-progress-circle-thickness-medium",
className
)}
style={style}
>
<Alert bootstrapStyle="danger" role="alert">
{alertMessage}
</Alert>
<div
className={classNames("h2", "progress-circle-label-container", {
"widget-progress-circle-clickable": !!onClick
})}
onClick={onClick}
ref={setProgressCircleElement}
>
<div className={classNames("progressbar-text")}>{label}</div>
</div>
</div>
);
};