Skip to content

Commit fccaf5a

Browse files
allan-chencopybara-github
authored andcommitted
feat(circular-progress): implement component
#500 PiperOrigin-RevId: 322248153
1 parent 3cb7406 commit fccaf5a

File tree

8 files changed

+422
-0
lines changed

8 files changed

+422
-0
lines changed
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
{
2+
"name": "@material/mwc-circular-progress",
3+
"version": "0.17.2",
4+
"description": "Material Design circular progress web component",
5+
"keywords": [
6+
"material design",
7+
"web components",
8+
"circular progress"
9+
],
10+
"main": "mwc-circular-progress.js",
11+
"module": "mwc-circular-progress.js",
12+
"repository": {
13+
"type": "git",
14+
"url": "https://github.com/material-components/material-components-web-components.git",
15+
"directory": "packages/circular-progress"
16+
},
17+
"license": "Apache-2.0",
18+
"dependencies": {
19+
"@material/circular-progress": "=8.0.0-canary.b2edaeead.0",
20+
"@material/mwc-base": "^0.17.2",
21+
"@material/theme": "=8.0.0-canary.b2edaeead.0",
22+
"lit-element": "^2.3.0",
23+
"tslib": "^1.10.0"
24+
},
25+
"publishConfig": {
26+
"access": "public"
27+
}
28+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/**
2+
@license
3+
Copyright 2020 Google Inc. All Rights Reserved.
4+
5+
Licensed under the Apache License, Version 2.0 (the "License");
6+
you may not use this file except in compliance with the License.
7+
You may obtain a copy of the License at
8+
9+
http://www.apache.org/licenses/LICENSE-2.0
10+
11+
Unless required by applicable law or agreed to in writing, software
12+
distributed under the License is distributed on an "AS IS" BASIS,
13+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
See the License for the specific language governing permissions and
15+
limitations under the License.
16+
*/
17+
18+
@use 'sass:map';
19+
@use '@material/circularprogress' as circularprogress;
20+
@use '@material/theme';
21+
22+
$light-theme: (
23+
bar: theme.prop-value(primary),
24+
);
25+
26+
@mixin theme($theme: $light-theme) {
27+
$bar-color: map.get($theme, bar);
28+
@if $bar-color {
29+
--mdc-theme-primary: #{$bar-color};
30+
}
31+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/**
2+
@license
3+
Copyright 2020 Google Inc. All Rights Reserved.
4+
5+
Licensed under the Apache License, Version 2.0 (the "License");
6+
you may not use this file except in compliance with the License.
7+
You may obtain a copy of the License at
8+
9+
http://www.apache.org/licenses/LICENSE-2.0
10+
11+
Unless required by applicable law or agreed to in writing, software
12+
distributed under the License is distributed on an "AS IS" BASIS,
13+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
See the License for the specific language governing permissions and
15+
limitations under the License.
16+
*/
17+
@use '@material/theme/custom-properties';
18+
@use '@material/circularprogress' as circularprogress;
19+
@use '@material/theme';
20+
21+
@mixin core-styles() {
22+
@include circularprogress.core-styles();
23+
24+
:host {
25+
display: inline-block;
26+
}
27+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
/**
2+
@license
3+
Copyright 2020 Google Inc. All Rights Reserved.
4+
5+
Licensed under the Apache License, Version 2.0 (the "License");
6+
you may not use this file except in compliance with the License.
7+
You may obtain a copy of the License at
8+
9+
http://www.apache.org/licenses/LICENSE-2.0
10+
11+
Unless required by applicable law or agreed to in writing, software
12+
distributed under the License is distributed on an "AS IS" BASIS,
13+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
See the License for the specific language governing permissions and
15+
limitations under the License.
16+
*/
17+
18+
@forward './circular-progress-theme';
Lines changed: 191 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,191 @@
1+
/**
2+
@license
3+
Copyright 2020 Google Inc. All Rights Reserved.
4+
5+
Licensed under the Apache License, Version 2.0 (the "License");
6+
you may not use this file except in compliance with the License.
7+
You may obtain a copy of the License at
8+
9+
http://www.apache.org/licenses/LICENSE-2.0
10+
11+
Unless required by applicable law or agreed to in writing, software
12+
distributed under the License is distributed on an "AS IS" BASIS,
13+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
See the License for the specific language governing permissions and
15+
limitations under the License.
16+
*/
17+
import {html, internalProperty, LitElement, property} from 'lit-element';
18+
import {classMap} from 'lit-html/directives/class-map.js';
19+
import {ifDefined} from 'lit-html/directives/if-defined.js';
20+
import {styleMap} from 'lit-html/directives/style-map.js';
21+
22+
/** @soyCompatible */
23+
export class CircularProgressBase extends LitElement {
24+
@property({type: Boolean, reflect: true}) indeterminate = false;
25+
26+
@property({type: Number, reflect: true}) progress = 0;
27+
28+
@property({type: Number, reflect: true}) density = 0;
29+
30+
@property({type: Boolean, reflect: true}) closed = false;
31+
32+
@property({type: String}) ariaLabel = '';
33+
34+
@internalProperty() containerSideLength = 0;
35+
36+
@internalProperty() circleRadius = 0;
37+
38+
@internalProperty() determinateStrokeDashOffset = 0;
39+
40+
@internalProperty() strokeWidth = 0;
41+
42+
open() {
43+
this.closed = false;
44+
}
45+
46+
close() {
47+
this.closed = true;
48+
}
49+
50+
/**
51+
* @soyCompatible
52+
*/
53+
protected render() {
54+
/** @classMap */
55+
const classes = {
56+
'mdc-circular-progress--closed': this.closed,
57+
'mdc-circular-progress--indeterminate': this.indeterminate,
58+
};
59+
60+
const styles = {
61+
'width': `${this.containerSideLength}px`,
62+
'height': `${this.containerSideLength}px`,
63+
};
64+
65+
return html`
66+
<div
67+
class="mdc-circular-progress ${classMap(classes)}"
68+
style="${styleMap(styles)}"
69+
role="progressbar"
70+
aria-label="${this.ariaLabel}"
71+
aria-valuemin="0"
72+
aria-valuemax="1"
73+
aria-valuenow="${
74+
ifDefined(this.indeterminate ? undefined : this.progress)}">
75+
${this.renderDeterminateContainer()}
76+
${this.renderIndeterminateContainer()}
77+
</div>`;
78+
}
79+
80+
/**
81+
* @soyCompatible
82+
*/
83+
private renderDeterminateContainer() {
84+
const center = this.containerSideLength / 2;
85+
86+
return html`
87+
<div class="mdc-circular-progress__determinate-container">
88+
<svg class="mdc-circular-progress__determinate-circle-graphic"
89+
viewBox="0 0 ${this.containerSideLength} ${
90+
this.containerSideLength}">
91+
<circle class="mdc-circular-progress__determinate-circle"
92+
cx="${center}" cy="${center}" r="${this.circleRadius}"
93+
stroke-dasharray="${2 * 3.1415926 * this.circleRadius}"
94+
stroke-dashoffset="${this.determinateStrokeDashOffset}"
95+
stroke-width="${this.strokeWidth}"></circle>
96+
</svg>
97+
</div>`;
98+
}
99+
100+
/**
101+
* @soyCompatible
102+
*/
103+
protected renderIndeterminateContainer() {
104+
return html`
105+
<div class="mdc-circular-progress__indeterminate-container">
106+
${this.renderIndeterminateSpinnerLayer()}
107+
</div>`;
108+
}
109+
110+
/**
111+
* @soyCompatible
112+
*/
113+
protected renderIndeterminateSpinnerLayer(classes: string = '') {
114+
const center = this.containerSideLength / 2;
115+
const circumference = 2 * 3.1415926 * this.circleRadius;
116+
const halfCircumference = 0.5 * circumference;
117+
118+
return html`
119+
<div class="mdc-circular-progress__spinner-layer ${classes}">
120+
<div class="mdc-circular-progress__circle-clipper mdc-circular-progress__circle-left">
121+
<svg class="mdc-circular-progress__indeterminate-circle-graphic"
122+
viewBox="0 0 ${this.containerSideLength} ${
123+
this.containerSideLength}">
124+
<circle cx="${center}" cy="${center}" r="${this.circleRadius}"
125+
stroke-dasharray="${circumference}"
126+
stroke-dashoffset="${halfCircumference}"
127+
stroke-width="${this.strokeWidth}"></circle>
128+
</svg>
129+
</div><div class="mdc-circular-progress__gap-patch">
130+
<svg class="mdc-circular-progress__indeterminate-circle-graphic"
131+
viewBox="0 0 ${this.containerSideLength} ${
132+
this.containerSideLength}">
133+
<circle cx="${center}" cy="${center}" r="${this.circleRadius}"
134+
stroke-dasharray="${circumference}"
135+
stroke-dashoffset="${halfCircumference}"
136+
stroke-width="${this.strokeWidth * 0.8}"></circle>
137+
</svg>
138+
</div><div class="mdc-circular-progress__circle-clipper mdc-circular-progress__circle-right">
139+
<svg class="mdc-circular-progress__indeterminate-circle-graphic"
140+
viewBox="0 0 ${this.containerSideLength} ${
141+
this.containerSideLength}">
142+
<circle cx="${center}" cy="${center}" r="${this.circleRadius}"
143+
stroke-dasharray="${circumference}"
144+
stroke-dashoffset="${halfCircumference}"
145+
stroke-width="${this.strokeWidth}"></circle>
146+
</svg>
147+
</div>
148+
</div>`;
149+
}
150+
151+
update(changedProperties: Map<string, string>) {
152+
super.update(changedProperties);
153+
154+
this.containerSideLength = this.getContainerSideLength();
155+
this.circleRadius = this.getCircleRadius();
156+
this.determinateStrokeDashOffset = this.getDeterminateStrokeDashOffset();
157+
this.strokeWidth = this.getStrokeWidth();
158+
159+
// Bound progress value in interval [0, 1].
160+
if (changedProperties.has('progress')) {
161+
if (this.progress > 1) {
162+
this.progress = 1;
163+
}
164+
165+
if (this.progress < 0) {
166+
this.progress = 0
167+
}
168+
}
169+
}
170+
171+
private getContainerSideLength() {
172+
return 48 + this.density * 4;
173+
}
174+
175+
private getDeterminateStrokeDashOffset(): number {
176+
const circleRadius = this.getCircleRadius();
177+
const circumference = 2 * 3.1415926 * circleRadius;
178+
179+
return (1 - this.progress) * circumference;
180+
}
181+
182+
private getCircleRadius() {
183+
return this.density >= -3 ? 18 + this.density * 11 / 6 :
184+
12.5 + (this.density + 3) * 5 / 4;
185+
}
186+
187+
private getStrokeWidth() {
188+
return this.density >= -3 ? 4 + this.density * (1 / 3) :
189+
3 + (this.density + 3) * (1 / 6);
190+
}
191+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/**
2+
@license
3+
Copyright 2018 Google Inc. All Rights Reserved.
4+
5+
Licensed under the Apache License, Version 2.0 (the "License");
6+
you may not use this file except in compliance with the License.
7+
You may obtain a copy of the License at
8+
9+
http://www.apache.org/licenses/LICENSE-2.0
10+
11+
Unless required by applicable law or agreed to in writing, software
12+
distributed under the License is distributed on an "AS IS" BASIS,
13+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
See the License for the specific language governing permissions and
15+
limitations under the License.
16+
*/
17+
@use './circular-progress';
18+
19+
@include circular-progress.core-styles();
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/**
2+
@license
3+
Copyright 2018 Google Inc. All Rights Reserved.
4+
5+
Licensed under the Apache License, Version 2.0 (the "License");
6+
you may not use this file except in compliance with the License.
7+
You may obtain a copy of the License at
8+
9+
http://www.apache.org/licenses/LICENSE-2.0
10+
11+
Unless required by applicable law or agreed to in writing, software
12+
distributed under the License is distributed on an "AS IS" BASIS,
13+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
See the License for the specific language governing permissions and
15+
limitations under the License.
16+
*/
17+
import {customElement} from 'lit-element';
18+
19+
import {CircularProgressBase} from './mwc-circular-progress-base.js';
20+
import {style} from './mwc-circular-progress-css.js';
21+
22+
declare global {
23+
interface HTMLElementTagNameMap {
24+
'mwc-circular-progress': CircularProgressBase;
25+
}
26+
}
27+
28+
/** @soyCompatible */
29+
@customElement('mwc-circular-progress')
30+
export class CircularProgress extends CircularProgressBase {
31+
static styles = style;
32+
}

0 commit comments

Comments
 (0)