console
new Vue({
el: '#app',
data() {
return {
width: 100,
progress: 1,
strokeWidth: 10
}
},
computed: {
rootStyle() {
return {
'--width': `${this.width}px`,
'--stroke-width': `${this.strokeWidth}px`
}
},
path() {
const w = this.width
const w2 = w / 2
let tmp = this.progress
if (tmp === 1) {
tmp = tmp - 0.00001
}
let angle = 360 * tmp
angle = (90 - angle) * Math.PI / 180
x = w2 + Math.cos(angle) * w2
y = w2 - Math.sin(angle) * w2
const p = `M ${w2} ${w2} v ${-w2} A ${w2} ${w2} 0 1 1 ${x} ${y} L ${w2} ${w2} z`
return p
}
},
mounted() {
this.setProgress(0.5)
},
methods: {
setProgress(p) {
const cnt = 50
const time = 500
const interval = time / cnt
const step = p / cnt
console.log(interval, step)
let tmp = 0
this.progress = tmp
if (this.timer) {
clearInterval(this.timer)
}
this.timer = setInterval(() => {
tmp += step
if (tmp >= p) {
tmp = p
clearInterval(this.timer)
this.timer = null
}
this.progress = tmp
}, interval)
}
}
})
<div id="app" :style="[rootStyle]">
<svg class="svgwrap">
<defs>
<clippath id="path">
<path :d="path"></path>
</clippath>
</defs>
<circle class="circle gray"></circle>
<circle id="progress" class="circle" clip-path="url(#path)"></circle>
</svg>
</div>
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
#app {
width: var(--width);
height: var(--width);
border: 1px solid black;
}
.svgwrap {
width: 100%;
height: 100%;
transform: rotateX(60deg);
}
.circle {
cx: calc(var(--width)/2);
cy: calc(var(--width)/2);
r: calc(var(--width)/2 - var(--stroke-width)/2);
fill: none;
stroke: red;
stroke-width: var(--stroke-width);
stroke-dasharray: 10 5;
}
.circle.gray {
stroke: gray;
}