-
Notifications
You must be signed in to change notification settings - Fork 1
/
progress-arc.tsx
106 lines (88 loc) · 2.85 KB
/
progress-arc.tsx
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 { h, Component, Prop, Watch, Element, Host } from "@stencil/core";
@Component({
tag: "hattrick-progress-arc",
styleUrl: "progress-arc.css",
shadow: true,
})
export class ProgressArc {
@Element() private host: HTMLElement;
/** Size of element in pixels. */
@Prop() size: number;
/* Color/appearance of stroke */
// @Prop() stroke: string = "black";
/** Indicating if the progress should instead be counter clockwise */
@Prop() counterClockwise: boolean = false;
/** Expression evaluating to float [0.0, 1.0] */
@Prop() complete: number;
@Watch("complete") completeChanged() {
this.updateRadius();
}
@Prop() angle: number = 0;
@Prop() circumference: number = 360;
private strokeWidth: number;
private offset: number;
componentWillLoad() {
this.updateRadius();
}
componentWillUpdate() {
this.updateRadius();
}
private updateRadius() {
this.strokeWidth = parseInt(
getComputedStyle(this.host)
.getPropertyValue("--progress-arc-stroke-width")
?.replace("px", ""),
);
if (!this.strokeWidth) {
this.strokeWidth = 8;
}
this.offset = this.angle - 90;
}
render() {
const { size, strokeWidth, offset, circumference } = this;
const circumferenceDecimal = circumference / 360;
let trackDashArray = 100 * circumferenceDecimal;
let progressDashArray = 100;
let progressDashOffset = 100 - this.complete * 100 * circumferenceDecimal;
// If the circumference is 360, we don't need a dash array since we'll just fill the whole thing.
if (circumference === 360) trackDashArray = null;
// The dash array creates a gap in the stroke, so if we want a full circle we
// simply don't use the dash array since we'll just fill the whole thing.
if (this.complete === 1 && circumference === 360) progressDashArray = null;
return (
<Host role="meter" aria-valuemin={0} aria-valuemax={100} aria-valuenow={100 * this.complete}>
<svg
style={{
width: this.size + "px",
height: this.size + "px",
transform: `rotate(${offset}deg)`,
}}
>
<circle
class="track"
cx={size / 2}
cy={size / 2}
r={(size - strokeWidth) / 2}
fill="none"
stroke-width={strokeWidth}
stroke-dasharray={trackDashArray}
pathLength={100}
></circle>
{this.complete > 0 && (
<circle
class="progress"
cx={size / 2}
cy={size / 2}
r={(size - strokeWidth) / 2}
fill="none"
stroke-width={strokeWidth}
stroke-dasharray={progressDashArray}
stroke-dashoffset={progressDashOffset}
pathLength={100}
></circle>
)}
</svg>
</Host>
);
}
}