Skip to content

Commit a0ee8e4

Browse files
authored
Merge pull request #90 from setaman/v2-loader-option
V2 loader option
2 parents 75ac5b2 + 55e58c8 commit a0ee8e4

12 files changed

+167
-61
lines changed

README.md

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,8 @@ After you have initialized the component, use it everywhere you want in your app
7474
dash="60 0.9"
7575
animation="reverse 700 400"
7676
:noData="false"
77-
:loading="false"
77+
:loading="false"
78+
:loader="{ color: 'green' }"
7879
fontColor="white"
7980
:half="false"
8081
:gap="10"
@@ -115,6 +116,7 @@ This table below provides a quick overview over all available options. To gain m
115116
| **[`legendFormatter`](#legendformatter)** [![npm](https://img.shields.io/badge/v1.3.0-blue?style=flat-square)](#legendformatter) | Function | Function that returns formatted value | |
116117
| **[`animation`](#animation)** | String | "default \| rs \| loop \| reverse \| bounce [duration delay]" | "default 1000 400"|
117118
| **[`loading`](#loading)** | Boolean | |false|
119+
| **[`loader`](#loading)** | Object | { [thickness, color, lineMode, line, opacity ]} | |
118120
| **[`determinate`](#determinate)** | Boolean | |false|
119121
| **[`noData`](#nodata)** | Boolean | |false|
120122
| **[`angle`](#angle)** | Number | any Number |-90|
@@ -406,6 +408,21 @@ Forces loading state. The component provides an indeterminate loading state for
406408

407409
<br>
408410

411+
- ### `loader`
412+
413+
With this option defined as Object you can customize the loading circle that is shown in the states
414+
[loading](#loading) and [determinate](#determinate). Accepted properties are [`color`](#color), [`thickness`](#thickness), [`line`](#line),
415+
[`lineMode`](#linemode) and `opactity`. `opacity` is specific for loading circle and can be any valid CSS opacity value. If the option is not specified, the loading circle replicates the progress circle with a 0.55 default value for `opacity`.
416+
417+
###### Example: :scroll:
418+
419+
```vue
420+
<vue-ellipse-progress :loader="{ color: 'green', lineMode: 'in 10', opacity: '0.6' }" />
421+
422+
```
423+
424+
<br>
425+
409426
- ### `determinate`
410427

411428
Provides a determinate loading state that indicates that your data loading is still in progress but allows to show the **[`progress`](#progress)**.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "vue-ellipse-progress",
3-
"version": "2.0.0-alpha.2",
3+
"version": "2.0.0-alpha.3",
44
"private": false,
55
"description": "A Vue.js component to create beautiful animated circular progress bars",
66
"main": "./dist/vue-ellipse-progress.umd.min.js",

src/App.vue

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
:thickness="20"
4949
:empty-thickness="10"
5050
dot="10 red"
51+
:loader="{ thickness: 40, color: 'red' }"
5152
line-mode="bottom"
5253
:no-data="noData"
5354
:determinate="determinate"
@@ -73,6 +74,7 @@
7374
line-mode="out 20"
7475
:no-data="noData"
7576
:determinate="determinate"
77+
:loader="{ thickness: 40, color: 'red' }"
7678
>
7779
<template v-slot:legend-caption>
7880
<p slot="legend-caption">TASKS DONE</p>

src/components/Circle/Circle.vue

Lines changed: 3 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -25,26 +25,7 @@
2525
</circle>
2626
<fade-in-transition>
2727
<g v-if="isLoading">
28-
<g class="ep-circle--loading__container" :style="{ opacity: `${options.loading ? 1 : 0.45}` }">
29-
<circle
30-
class="ep-circle--loading animation__loading"
31-
:r="radius"
32-
:cx="position"
33-
:cy="position"
34-
fill="transparent"
35-
:stroke="computedColor"
36-
:stroke-width="thickness"
37-
:stroke-linecap="options.line"
38-
:stroke-dasharray="circumference"
39-
:style="{
40-
transitionTimingFunction: styles.transitionTimingFunction,
41-
transformOrigin: styles.transformOrigin,
42-
'--ep-loading-stroke-offset': styles['--ep-loading-stroke-offset'],
43-
'--ep-circumference': styles['--ep-circumference'],
44-
}"
45-
>
46-
</circle>
47-
</g>
28+
<circle-loader :options="options.loader" />
4829
</g>
4930
</fade-in-transition>
5031
<circle
@@ -67,10 +48,11 @@
6748
<script>
6849
import CircleMixin from "./circleMixin";
6950
import FadeInTransition from "../FadeInTransition.vue";
51+
import CircleLoader from "./CircleLoader.vue";
7052
7153
export default {
7254
name: "CircleProgress",
73-
components: { FadeInTransition },
55+
components: { CircleLoader, FadeInTransition },
7456
mixins: [CircleMixin],
7557
computed: {
7658
position() {

src/components/Circle/CircleContainer.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ import CircleProgress from "./Circle.vue";
2727
import CircleDot from "./CircleDot.vue";
2828
2929
export default {
30-
name: "EpCircleContainer",
30+
name: "CircleContainer",
3131
components: { CircleDot, CircleProgress, HalfCircleProgress, Gradient },
3232
props: {
3333
options: {
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
<template>
2+
<g class="ep-circle--loader__container" :style="{ opacity: opacity }">
3+
<circle
4+
class="ep-circle--loader animation__loading"
5+
:r="radius"
6+
:cx="position"
7+
:cy="position"
8+
fill="transparent"
9+
:stroke="computedColor"
10+
:stroke-width="thickness"
11+
:stroke-linecap="options.line"
12+
:stroke-dasharray="circumference"
13+
:style="{
14+
transitionTimingFunction: styles.transitionTimingFunction,
15+
transformOrigin: styles.transformOrigin,
16+
'--ep-loading-stroke-offset': styles['--ep-loading-stroke-offset'],
17+
'--ep-circumference': styles['--ep-circumference'],
18+
}"
19+
>
20+
</circle>
21+
</g>
22+
</template>
23+
24+
<script>
25+
import CircleMixin from "./circleMixin";
26+
27+
export default {
28+
name: "CircleLoader",
29+
mixins: [CircleMixin],
30+
computed: {
31+
position() {
32+
return this.options.size / 2;
33+
},
34+
circumference() {
35+
return this.radius * 2 * Math.PI;
36+
},
37+
opacity() {
38+
return this.options.opacity && this.options.opacity >= 0 ? this.options.opacity : 0.55;
39+
},
40+
},
41+
};
42+
</script>
43+
44+
<style scoped lang="scss"></style>

src/components/Circle/HalfCircle.vue

Lines changed: 3 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -24,25 +24,7 @@
2424
</path>
2525
<fade-in-transition>
2626
<g v-if="isLoading">
27-
<g :style="{ opacity: `${options.loading ? 1 : 0.45}` }">
28-
<path
29-
:stroke-width="thickness"
30-
class="ep-half-circle--loading animation__loading"
31-
:d="path"
32-
:fill="computedColorFill"
33-
:stroke="computedColor"
34-
:stroke-dasharray="circumference"
35-
:stroke-linecap="options.line"
36-
:style="{
37-
transitionTimingFunction: styles.transitionTimingFunction,
38-
transformOrigin: styles.transformOrigin,
39-
'--ep-loading-stroke-offset': styles['--ep-loading-stroke-offset'],
40-
'--ep-circumference': styles['--ep-circumference'],
41-
'--ep-negative-circumference': styles['--ep-negative-circumference'],
42-
}"
43-
>
44-
</path>
45-
</g>
27+
<half-circle-loader :options="options.loader" />
4628
</g>
4729
</fade-in-transition>
4830

@@ -63,10 +45,11 @@
6345
<script>
6446
import CircleMixin from "./circleMixin";
6547
import FadeInTransition from "../FadeInTransition.vue";
48+
import HalfCircleLoader from "./HalfCircleLoader.vue";
6649
6750
export default {
6851
name: "HalfCircleProgress",
69-
components: { FadeInTransition },
52+
components: { HalfCircleLoader, FadeInTransition },
7053
mixins: [CircleMixin],
7154
computed: {
7255
circumference() {
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
<template>
2+
<g :style="{ opacity: opacity }">
3+
<path
4+
:stroke-width="thickness"
5+
class="ep-half-circle--loader animation__loading"
6+
:d="path"
7+
:fill="computedColorFill"
8+
:stroke="computedColor"
9+
:stroke-dasharray="circumference"
10+
:stroke-linecap="options.line"
11+
:style="{
12+
transitionTimingFunction: styles.transitionTimingFunction,
13+
transformOrigin: styles.transformOrigin,
14+
'--ep-loading-stroke-offset': styles['--ep-loading-stroke-offset'],
15+
'--ep-circumference': styles['--ep-circumference'],
16+
'--ep-negative-circumference': styles['--ep-negative-circumference'],
17+
}"
18+
>
19+
</path>
20+
</g>
21+
</template>
22+
<script>
23+
import CircleMixin from "./circleMixin";
24+
25+
export default {
26+
name: "HalfCircleLoader",
27+
mixins: [CircleMixin],
28+
computed: {
29+
circumference() {
30+
return (this.radius * 2 * Math.PI) / 2;
31+
},
32+
path() {
33+
return ` M ${this.position}, ${this.options.size / 2} a ${this.radius},${this.radius} 0 1,1 ${this.radius * 2},0`;
34+
},
35+
emptyPath() {
36+
return ` M ${this.emptyPosition}, ${this.options.size / 2} a ${this.emptyRadius},${this.emptyRadius} 0 1,1 ${
37+
this.emptyRadius * 2
38+
},0`;
39+
},
40+
position() {
41+
return this.options.size / 2 - this.radius;
42+
},
43+
emptyPosition() {
44+
return this.options.size / 2 - this.emptyRadius;
45+
},
46+
opacity() {
47+
return this.options.opacity && this.options.opacity >= 0 ? this.options.opacity : 0.55;
48+
},
49+
},
50+
};
51+
</script>
52+
53+
<style scoped lang="scss">
54+
g.ep-half-circle {
55+
transform-origin: 50% 50%;
56+
}
57+
</style>

src/components/VueEllipseProgress.vue

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ import { getNumberIfValid, isValidNumber } from "../utils";
3939
import props from "./interface";
4040
import CircleContainer from "./Circle/CircleContainer.vue";
4141
import Counter from "./Counter.vue";
42-
import parseOptions from "./optionsParser";
42+
import { parseOptions, calcThickness, lineModeParser } from "./optionsParser";
4343
4444
export default {
4545
name: "VueEllipseProgress",
@@ -84,17 +84,19 @@ export default {
8484
const previousCircles = [];
8585
for (let i = 0; i < this.circlesData.length; i++) {
8686
const options = this.circlesData[i];
87-
normalizedCircles.push({
88-
...parseOptions({
89-
index: i,
90-
id: i,
91-
...options,
92-
globalDot: this.dot,
93-
globalGap: this.gap,
94-
globalThickness: this.thickness,
95-
previousCircles: [...previousCircles],
96-
}),
87+
const parsedOptions = parseOptions({
88+
index: i,
89+
id: i,
90+
...options,
91+
globalDot: this.dot,
92+
globalGap: this.gap,
93+
globalThickness: this.thickness,
94+
previousCircles: [...previousCircles],
9795
});
96+
const loaderOptions = { ...parsedOptions, ...parsedOptions.loader };
97+
loaderOptions.thickness = calcThickness(loaderOptions.thickness, parsedOptions.size);
98+
loaderOptions.lineMode = parsedOptions.loader.lineMode ? lineModeParser(loaderOptions) : parsedOptions.lineMode;
99+
normalizedCircles.push({ ...parsedOptions, loader: loaderOptions });
98100
const { gap, thickness, dot } = normalizedCircles[i];
99101
previousCircles.push({ gap, thickness, dot });
100102
}

src/components/interface.js

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,10 @@ const colorConfig = (defaultColor = "transparent") => ({
1313
},
1414
});
1515

16-
export default {
16+
const validateLoaderProps = (loaderOptions) =>
17+
Object.keys(loaderOptions).every((p) => options[p].validator(loaderOptions[p]));
18+
19+
const options = {
1720
data: {
1821
type: Array,
1922
required: false,
@@ -164,4 +167,20 @@ export default {
164167
type: Function,
165168
required: false,
166169
},
170+
loader: {
171+
type: Object,
172+
required: false,
173+
default: () => ({}),
174+
validator: (value) => {
175+
const propsAllowed = Object.keys(value).every((prop) =>
176+
["thickness", "color", "lineMode", "line", "opacity"].includes(prop)
177+
);
178+
if (propsAllowed) {
179+
return validateLoaderProps(value);
180+
}
181+
return false;
182+
},
183+
},
167184
};
185+
186+
export default options;

src/components/optionsParser.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { getNumberIfValid, isValidNumber } from "@/utils";
22

3-
const lineModeParser = (options) => {
3+
export const lineModeParser = (options) => {
44
const lineModeConfig = options.lineMode.trim().split(" ");
55
const mode = options.multiple ? "multiple" : lineModeConfig[0];
66
return {
@@ -49,12 +49,12 @@ const dotParser = (dot) => {
4949
};
5050
};
5151

52-
const calcThickness = (thickness, size) => {
52+
export const calcThickness = (thickness, size) => {
5353
const value = parseFloat(thickness);
5454
return thickness.toString().includes("%") ? (value * size) / 100 : value;
5555
};
5656

57-
export default (options) => {
57+
export const parseOptions = (options) => {
5858
const dot = dotParser(options.dot);
5959
const globalDot = dotParser(options.globalDot);
6060
return {

src/styles/animationsUsage.scss

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
}
1818
}
1919

20-
.ep-circle--loading {
20+
.ep-circle--loader {
2121
&.animation__loading {
2222
animation-name: ep-progress--loading, ep-progress--loading__rotation;
2323
animation-iteration-count: infinite !important;
@@ -26,7 +26,7 @@
2626
}
2727
}
2828

29-
.ep-half-circle--loading {
29+
.ep-half-circle--loader {
3030
&.animation__loading {
3131
animation-name: ep-half-progress--loading;
3232
animation-iteration-count: infinite !important;

0 commit comments

Comments
 (0)