1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129
| <template> <svg :height="option.size" :width="option.size" x-mlns="http://www.w3.org/200/svg" class="progress" > <circle :r="option.radius" :cx="option.cx" :cy="option.cy" :stroke="option.backColor" :stroke-width="option.strokeWidth" fill="none" /> <circle v-for="(item, index) in arcArr" :key="index" :r="option.radius" :cx="option.cx" :cy="option.cy" :stroke="item.color" :stroke-dasharray="item.arcLength" :stroke-width="option.strokeWidth" fill="none" stroke-linecap="round" /> <text v-if="option.showProgressText" :x="option.cx" :y="option.cy" text-anchor="middle" dominant-baseline="middle" :font-size="option.progressTextSize" :fill="option.progressTextColor" :font-weight="option.progressTextWeight" :font-family="option.progressTextFamily" class="progress-text" > {{ progressPercentage }} </text> </svg> </template> <script>
export default { name: 'circular-progress-bar', props: { progress: { type: Number, required: true, default: 0, validator (value) { return value >= 0 && value <= 1 } }, progressOption: { type: Object, default: () => { } } }, computed: { progressPercentage () { return parseFloat((this.progress * 100).toFixed(2)).toFixed(2) + '%' }, arcArr () { if (this.progress === 0) return [] const circleLength = Math.floor(2 * Math.PI * this.option.radius) const progressLength = this.progress * circleLength const step = 100 const gradientColor = (startRGB, endRGB, step) => { const startR = startRGB[0] const startG = startRGB[1] const startB = startRGB[2] const endR = endRGB[0] const endG = endRGB[1] const endB = endRGB[2] const sR = (endR - startR) / step const sG = (endG - startG) / step const sB = (endB - startB) / step const colorArr = [] for (let i = 0; i < step; i++) { const color = `rgb(${Math.floor(sR * i + startR)},${Math.floor(sG * i + startG)},${Math.floor(sB * i + startB)})` colorArr.push(color) } return colorArr } const colorArr = gradientColor(this.option.startColor, this.option.endColor, step) const arcLengthArr = colorArr.map((color, index) => ({ arcLength: `${index * (progressLength / 100)},100000000`, color: color })) arcLengthArr.reverse() return arcLengthArr }, option () { const baseOption = { radius: 50, strokeWidth: 10, backColor: 'white', startColor: [160, 209, 236], endColor: [179, 160, 236], progressTextColor: 'black', progressTextSize: 20, progressTextWeight: 'normal', progressTextFamily: '', showProgressText: true } Object.assign(baseOption, this.progressOption) baseOption.cy = baseOption.cx = baseOption.radius + baseOption.strokeWidth baseOption.size = (baseOption.radius + baseOption.strokeWidth) * 2 return baseOption } } } </script> <style scoped lang="stylus"> .progress transform: rotate(-90deg) .progress-text transform: rotate(90deg) transform-origin: 50% 50% </style>
|