donut chart
by Jose Quichiz
HTML
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>
<template id="ppchart">
<div class="donut-chart">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="400" height="250" viewBox="0 0 400 200" enable-background="new 0 0 400 250" xml:space="preserve">
<!--defs>
<linearGradient id="quotaDonut__gradient">
<stop :stop-color="finalColor" offset="0%"></stop>
<stop :stop-color="initialColor" class="quotaDonut__gradientStopEnd" offset="100%"></stop>
</linearGradient>
</defs-->
<g transform="translate(200, 200)">
<circle :r="svgValues.backCircle.radius" class="circle-back" :style="{strokeDasharray: svgValues.backCircle.strokeDasharray + 'px',strokeDashoffset: svgValues.backCircle.strokeDashoffset + 'px', strokeWidth: thickness + 'px'}" />
<circle :r="svgValues.topBorderCircle.radius" class="circle-border top" :style="{strokeDasharray: svgValues.topBorderCircle.strokeDasharray + 'px',strokeDashoffset: svgValues.topBorderCircle.strokeDashoffset + 'px'}" />
<circle :r="svgValues.bottomBorderCircle.radius" class="circle-border bottom" :style="{strokeDasharray: svgValues.bottomBorderCircle.strokeDasharray + 'px',strokeDashoffset: svgValues.bottomBorderCircle.strokeDashoffset + 'px'}"/>
<circle :r="svgValues.frontCircle.radius" class="circle-front" :style="{strokeDasharray: svgValues.frontCircle.strokeDasharray + 'px',strokeDashoffset: svgValues.frontCircle.strokeDashoffset + 'px', strokeWidth: thickness + 'px', stroke: strokeColor}" />
<text x="-160" y="25" font-family="monospace" font-size="20px" text-anchor="middle" fill="black">{{minValue}}</text>
<text x="160" y="25" font-family="monospace" font-size="20px" text-anchor="middle" fill="black">{{maxValue}}</text>
<text x="0" y="-50" font-family="monospace" font-size="25px" text-anchor="middle"...
CSS
.donut {
margin: 20px;
}
circle {
fill: none;
transform: rotate(180deg);
}
.circle-back {
stroke: #E0E0E0;
}
.circle-border {
stroke: #e5e5e5;
stroke-width: 1px;
}
.circle-front {
/* stroke: url(#quotaDonut__gradient); */
/* 2 * Math.PI * radius + 1 */
/* stroke-dashoffset: 620px;*/
transition: stroke-dashoffset .5s ease, stroke .5s;
}
JavaScript
Vue.component('donnut-chart', {
props: {
currentValue: {
type: Number,
default: 100
},
initialColor: {
type: String,
default: '#f50'
},
finalColor: {
type: String,
default: '#fc0023'
},
strokeColorByPercentage: {
type: Array,
default: function(){
return [
[33.3, "#8BC34A"],
[66.6, "#FFC107"],
[100, "#FF5722"]
]
}
},
minValue: {
type: Number,
default: 0
},
maxValue: {
type: Number,
default: 100
},
thickness: {
type: Number,
default: 35
}
},
computed: {
percentage: function(){
const curr = this.currentValue - this.minValue
const top = this.maxValue - this.minValue
return (curr * 100) / top
},
strokeColor: function(){
for(var i = 0; i < this.strokeColorByPercentage.length; i++){
if(this.currentValue <= this.strokeColorByPercentage[i][0]){
return this.strokeColorByPercentage[i][1]
}
}
return "black"
},
svgValues: function(){
const r = 200
const borderOffset = this.thickness / 2
const strokeCircle = 2 * Math.PI * (r - borderOffset)
const strokeOutCircle = 2 * Math.PI * r
const strokeInCircle = 2 * Math.PI * (r - borderOffset * 2)
return {
backCircle: {
radius: r - borderOffset,
strokeDasharray: strokeCircle,
strokeDashoffset: strokeCircle/2,
},
frontCircle: {
radius: r - borderOffset,
strokeDasharray: strokeCircle,
strokeDashoffset: strokeCircle * (1 - this.percentage / 200),
},
topBorderCircle: {
radius: r,
strokeDasharray: strokeOutCircle,
strokeDashoffset: strokeOutCircle/2,
},
bottomBorderCircle: {
radius: r - borderOffset * 2,
strokeDasharray: strokeInCircle,
strokeDashoffset: strokeInCircle/2,
...