Created
February 8, 2018 05:40
-
-
Save ajmas/6edeeb7f69cbc0b10e04143390bd53f6 to your computer and use it in GitHub Desktop.
Vue Component for drawing a circular progress bar
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!-- | |
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