Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Vue Component for drawing a circular progress bar
<!--
Vue Component for drawing a circular progress bar
-->
<template>
<div class="circular-progress" ref="circularProgress">
<svg :height="height" :width="width">
<path class="channel" :d="channel"/>
<path class="progress" :d="progress" />
<text x="55%" y="55%" :font-size="fontSize">
{{percent}}%
</text>
</svg>
</div>
</template>
<script>
export default {
data: function () {
return {
width: 0,
height: 0
};
},
props: {
'percent': {
type: Number,
default: 50
},
'spread': {
type: Number,
default: null
},
'radius': {
type: Number,
default: null
}
},
mounted () {
this.width = this.$refs.circularProgress.clientWidth;
this.height = this.$refs.circularProgress.clientHeight;
},
updated () {
this.width = this.$refs.circularProgress.clientWidth;
this.height = this.$refs.circularProgress.clientHeight;
},
methods: {
polarToCartesian(centerX, centerY, radius, angleInDegrees) {
var angleInRadians = (angleInDegrees-90) * Math.PI / 180.0;
return {
x: centerX + (radius * Math.cos(angleInRadians)),
y: centerY + (radius * Math.sin(angleInRadians))
};
},
describeArc(x, y, radius, spread, startAngle, endAngle){
var innerStart = this.polarToCartesian(x, y, radius, endAngle);
var innerEnd = this.polarToCartesian(x, y, radius, startAngle);
var outerStart = this.polarToCartesian(x, y, radius + spread, endAngle);
var outerEnd = this.polarToCartesian(x, y, radius + spread, startAngle);
var largeArcFlag = endAngle - startAngle <= 180 ? '0' : '1';
var d = [
'M', outerStart.x, outerStart.y,
'A', radius + spread, radius + spread, 0, largeArcFlag, 0, outerEnd.x, outerEnd.y,
'L', innerEnd.x, innerEnd.y,
'A', radius, radius, 0, largeArcFlag, 1, innerStart.x, innerStart.y,
'L', outerStart.x, outerStart.y, 'Z'
].join(' ');
return d;
}
},
computed: {
fontSize () {
const size = Math.min(this.width, this.height);
return 82 * (size/400);
},
impliedRadius () {
if (this.radius !== null) {
return this.radius;
} else {
return Math.round(Math.min(this.width, this.height)/2);
}
},
channel () {
const spread = this.spread || (20 * this.impliedRadius/200);
const radius = this.impliedRadius - spread;
return this.describeArc(
this.width/2, this.height/2,
radius, spread, 0, 359.9);
},
progress () {
let angle = 360 * (this.percent / 100);
const spread = this.spread || (20 * this.impliedRadius/200);
const radius = this.impliedRadius - spread;
return this.describeArc(
this.width/2, this.height/2,
radius, spread, 0, angle);
}
}
};
// ref: https://stackoverflow.com/questions/5736398/how-to-calculate-the-svg-path-for-an-arc-of-a-circle
</script>
<style scoped>
.channel {
stroke: #ddd;
fill: #ddd;
}
.progress {
stroke: aqua;
fill: aqua;
}
text {
text-anchor: middle;
/* font-size: 82px; */
}
</style>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.