Skip to content

Commit 381ce6f

Browse files
authored
progress ring impl (#171)
1 parent 8cab1fd commit 381ce6f

File tree

6 files changed

+236
-3
lines changed

6 files changed

+236
-3
lines changed

docs/wired-calendar.md

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,6 @@ npm i wired-elements
1616
Import module in your code:
1717

1818
```javascript
19-
import { WiredCalendar } from 'wired-elements';
20-
// or
2119
import { WiredCalendar } from 'wired-elements/lib/wired-calendar.js';
2220
```
2321

docs/wired-progress-ring.md

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
# wired-progress-ring
2+
Hand-drawn sketchy progress-ring web component.
3+
4+
For demo and view the complete set of wired-elememts: [wiredjs.com](http://wiredjs.com/)
5+
6+
## Usage
7+
8+
Add wired-elements to your JavaScript project:
9+
```
10+
npm i wired-elements
11+
```
12+
13+
Import module in your code:
14+
15+
```javascript
16+
import { WiredProgressRing } from 'wired-elements';
17+
// or
18+
import { WiredProgressRing } from 'wired-elements/lib/wired-progress-ring.js';
19+
```
20+
21+
Or load directly into your HTML page:
22+
```html
23+
<script type="module" src="https://unpkg.com/wired-elements/lib/wired-progress-ring.js?module"></script>
24+
```
25+
26+
Use it in your HTML:
27+
```html
28+
<wired-progress-ring value="25"></wired-progress-ring>
29+
<wired-progress-ring value="10" min="5" max="15"></wired-progress-ring>
30+
```
31+
32+
## Properties
33+
34+
**value** - Numeric value of the progress.
35+
36+
**min** - Minimum value. Default is 0.
37+
38+
**max** - Maximum value. Default is 100.
39+
40+
**hideLabel** - Hide the label in the center of the ring. This label shows the current value. Default is `false`.
41+
42+
**showLabelAsPercent** - When showing the label, show the value as a percentage. Default value is `false`.
43+
44+
**precision** - When showing the label as a percentage, this value can be set to specify the precision to round the value to. By default, the value rounded to a whole number.
45+
46+
## Custom CSS Variables
47+
48+
**--wired-progress-color** Color of the progress bar. Default is `blue`.
49+
50+
The font and color of the label can be set the by styling the `wired-progress-ring` element.
51+
52+
## License
53+
[MIT License](https://github.com/rough-stuff/wired-elements/blob/master/LICENSE) (c) [Preet Shihn](https://twitter.com/preetster)

examples/progress-ring.html

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
<html>
2+
3+
<head>
4+
<script type="module" src="../lib/wired-progress-ring.js"></script>
5+
<script type="module" src="../lib/wired-button.js"></script>
6+
7+
<style>
8+
body {
9+
margin: 0;
10+
padding: 10px;
11+
font-family: sans-serif;
12+
line-height: 1.5;
13+
}
14+
15+
wired-progress-ring {
16+
margin: 16px 0;
17+
}
18+
19+
#wp2 {
20+
--wired-progress-color: red;
21+
}
22+
23+
wired-button {
24+
margin: 0 10px;
25+
}
26+
</style>
27+
</head>
28+
29+
<body>
30+
<wired-progress-ring value="25" hideLabel></wired-progress-ring>
31+
<br>
32+
<wired-progress-ring id="wp2" min="-100" max="100" value="0"></wired-progress-ring>
33+
<br>
34+
<section style="margin-top: 16px;">
35+
<wired-progress-ring id="progress" showLabelAsPercent></wired-progress-ring>
36+
<div style="margin-top: 16px;">
37+
<wired-button id="btns">Start</wired-button>
38+
<wired-button id="btnr">Stop</wired-button>
39+
</div>
40+
</section>
41+
42+
<script>
43+
const prog = document.getElementById('progress')
44+
let timer = 0;
45+
document.getElementById('btns').addEventListener('click', () => {
46+
if (timer) {
47+
window.clearInterval(timer);
48+
}
49+
timer = window.setInterval(() => {
50+
if (prog.value >= 100) {
51+
prog.value = 0;
52+
} else {
53+
prog.value = prog.value + 1;
54+
}
55+
}, 100);
56+
});
57+
document.getElementById('btnr').addEventListener('click', () => {
58+
if (timer) {
59+
window.clearInterval(timer);
60+
timer = 0;
61+
}
62+
prog.value = 0;
63+
});
64+
</script>
65+
</body>
66+
67+
</html>

src/wired-elements.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,5 @@ export * from './wired-tab';
2121
export * from './wired-tabs';
2222
export * from './wired-textarea';
2323
export * from './wired-toggle';
24-
export * from './wired-video';
24+
export * from './wired-video';
25+
export * from './wired-progress-ring';

src/wired-lib.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {
55
rectangle as roughRectangle,
66
ellipse as roughEllipse,
77
polygon as roughPolygon,
8+
arc as roughArc,
89
doubleLineFillOps,
910
generateEllipseParams
1011
} from 'roughjs/bin/renderer';
@@ -110,6 +111,12 @@ export function ellipse(parent: SVGElement, x: number, y: number, width: number,
110111
return createPathNode(roughEllipse(x, y, width, height, options(seed)), parent);
111112
}
112113

114+
export function arc(parent: SVGElement, x: number, y: number, width: number, height: number, start: number, stop: number, seed: number): SVGElement {
115+
width = Math.max(width > 10 ? width - 4 : width - 1, 1);
116+
height = Math.max(height > 10 ? height - 4 : height - 1, 1);
117+
return createPathNode(roughArc(x, y, width, height, start, stop, false, false, options(seed)), parent);
118+
}
119+
113120
export function hachureFill(points: Point[], seed: number): SVGElement {
114121
const hf = new ZigZagFiller(fillHelper);
115122
const ops = hf.fillPolygon(points, options(seed));

src/wired-progress-ring.ts

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
import { WiredBase, BaseCSS, Point } from './wired-base';
2+
import { ellipse, arc } from './wired-lib';
3+
import { css, TemplateResult, html, CSSResultArray } from 'lit';
4+
import { customElement, property } from 'lit/decorators.js';
5+
6+
@customElement('wired-progress-ring')
7+
export class WiredProgressRing extends WiredBase {
8+
@property({ type: Number }) value = 0;
9+
@property({ type: Number }) min = 0;
10+
@property({ type: Number }) max = 100;
11+
@property({ type: Boolean }) hideLabel = false;
12+
@property({ type: Boolean }) showLabelAsPercent = false;
13+
@property({ type: Number }) precision = 0;
14+
15+
private progArc?: SVGElement;
16+
17+
static get styles(): CSSResultArray {
18+
return [
19+
BaseCSS,
20+
css`
21+
:host {
22+
display: inline-block;
23+
position: relative;
24+
width: 200px;
25+
font-family: sans-serif;
26+
}
27+
#overlay {
28+
position: relative;
29+
}
30+
path.progressArc {
31+
stroke-width: 10px;
32+
stroke: var(--wired-progress-color, blue);
33+
}
34+
#labelPanel {
35+
position: absolute;
36+
top: 0;
37+
left: 0;
38+
width: 100%;
39+
height: 100%;
40+
display: grid;
41+
align-content: center;
42+
align-items: center;
43+
justify-content: center;
44+
justify-items: center;
45+
}
46+
`
47+
];
48+
}
49+
50+
render(): TemplateResult {
51+
let label = `${this.value}`;
52+
if (this.showLabelAsPercent) {
53+
const pct = 100 * Math.min(1, Math.max(0, (this.value - this.min) / (this.max - this.min)));
54+
if (this.precision) {
55+
label = `${pct.toPrecision(this.precision)}%`;
56+
} else {
57+
label = `${Math.round(pct)}%`;
58+
}
59+
}
60+
return html`
61+
<div id="overlay" class="overlay">
62+
<svg></svg>
63+
</div>
64+
65+
${this.hideLabel ? '' : html`
66+
<div id="labelPanel">
67+
<div>${label}</div>
68+
</div>
69+
`}
70+
71+
`;
72+
}
73+
74+
wiredRender(force = false) {
75+
super.wiredRender(force);
76+
this.refreshProgressFill();
77+
}
78+
79+
protected canvasSize(): Point {
80+
const s = this.getBoundingClientRect();
81+
return [s.width, s.width];
82+
}
83+
84+
protected draw(svg: SVGSVGElement, size: Point) {
85+
const [x, y, w, h] = [size[0] / 2, size[1] / 2, size[0] - 10, size[1] - 10];
86+
ellipse(svg, x, y, w, h, this.seed);
87+
88+
}
89+
90+
private refreshProgressFill() {
91+
if (this.progArc) {
92+
if (this.progArc.parentElement) {
93+
this.progArc.parentElement.removeChild(this.progArc);
94+
}
95+
this.progArc = undefined;
96+
}
97+
if (this.svg) {
98+
const size = this.canvasSize();
99+
const [x, y, w, h] = [size[0] / 2, size[1] / 2, size[0] - 10, size[1] - 10];
100+
const pct = Math.min(1, Math.max(0, (this.value - this.min) / (this.max - this.min)));
101+
if (pct) {
102+
this.progArc = arc(this.svg, x, y, w, h, -Math.PI / 2, 2 * Math.PI * pct - Math.PI / 2, this.seed);
103+
this.progArc.classList.add('progressArc');
104+
}
105+
}
106+
}
107+
}

0 commit comments

Comments
 (0)