diff --git a/src/PercentageCircle.vue b/src/PercentageCircle.vue index 61f0692..655ce25 100644 --- a/src/PercentageCircle.vue +++ b/src/PercentageCircle.vue @@ -2,8 +2,8 @@
- {{percent}}% + :class="[`p${innerPercent}`, !complete ? activeColor : completeColor, size]"> + {{innerPercent}}%
@@ -29,11 +29,67 @@ completeColor: { type: String, default: '' + }, + animate: { + type: Boolean, + default: false } }, computed: { complete() { - return this.percent == 100 + return this.innerPercent == 100 + } + }, + watch: { + percent(percent) { + this.checkAnimateTo() + } + }, + data() { + return { + innerPercent: 0, + timeout: null, + animationFrame: null + } + }, + mounted() { + this.checkAnimateTo() + }, + methods: { + checkAnimateTo() { + if (this.animate) { + this.animateTo(true) + } else { + this.innerPercent = this.percent + } + }, + clearTimeout() { + clearTimeout(this.timeout) + Object.assign(this, { + timeout: null + }) + }, + animateTo(topFrame = false) { + + + if (topFrame) { + this.clearTimeout() + } + + if (this.percent > this.innerPercent && !this.complete) { + this.innerPercent++ + } + + if (this.percent < this.innerPercent && this.innerPercent > 0) { + this.innerPercent-- + } + + if (this.innerPercent !== this.percent) { + this.timeout = setTimeout(() =>{ + this.animateTo() + }, 5) + return + } } } } diff --git a/stories/1-ProgressCircle.stories.js b/stories/1-ProgressCircle.stories.js index 6bb1d71..560606f 100644 --- a/stories/1-ProgressCircle.stories.js +++ b/stories/1-ProgressCircle.stories.js @@ -16,14 +16,22 @@ const percentOptions = { step: 1, } - const sizeOptions = { Small: 'small', Medium: '', Large: 'big', Micro: 'micro', None: 'small', -}; +} + +const colorOptions = { + Blue: '', + DarkMode: 'dark', + Green: 'green', + GreenDarkmode: 'green dark', + Orange: 'orange', + OrangeDark: 'orange dark', +} export const KitchenSink = () => ({ components: { PercentageCircle }, @@ -33,7 +41,58 @@ export const KitchenSink = () => ({ }, size: { default: select('Size', sizeOptions, 'small') + }, + activeColor: { + default: select('Active Color', colorOptions, '') + }, + completeColor: { + default: select('Complete Color', colorOptions, '') + } + }, + template: '', +}); + + +export const Animated = () => ({ + components: { PercentageCircle }, + props: { + percent: { + default: number('Percent', 50, percentOptions) + }, + size: { + default: select('Size', sizeOptions, 'small') + }, + activeColor: { + default: select('Active Color', colorOptions, '') + }, + completeColor: { + default: select('Complete Color', colorOptions, '') + } + }, + template: ` + + `, + data() { + return { + percent: 100, + timeout: null } }, - template: '', + methods: { + recountUp() { + clearTimeout(this.timeout) + this.percent = 0 + this.$nextTick(() => this.countUp()) + }, + countUp() { + this.percent = 100 + this.timeout = setTimeout(() => this.percent = 0, 2000) + } + } }); \ No newline at end of file