134 lines
		
	
	
		
			3.1 KiB
		
	
	
	
		
			Vue
		
	
	
	
	
	
			
		
		
	
	
			134 lines
		
	
	
		
			3.1 KiB
		
	
	
	
		
			Vue
		
	
	
	
	
	
| <template>
 | |
|   <div class="DonutChart" :id="id">
 | |
|     <canvas :id="canvasId"></canvas>
 | |
|     <div class="DonutChart-text">
 | |
|       <span>{{ ratio || 0 }}%</span>
 | |
|       <i>{{ text }}</i>
 | |
|     </div>
 | |
|   </div>
 | |
| </template>
 | |
| 
 | |
| <script>
 | |
|   export default {
 | |
|     props: ['ratio', 'text'],
 | |
| 
 | |
|     data () {
 | |
|       return {
 | |
|         id: `DonutChart-${Math.ceil(Math.random() * 10000)}`,
 | |
|         canvasId: `DonutChartCanvas-${Math.ceil(Math.random() * 10000)}`,
 | |
|         canvasWidth: 90,
 | |
|         canvasHeight: 90
 | |
|       }
 | |
|     },
 | |
| 
 | |
|     mounted () {
 | |
|       this.$nextTick(() => {
 | |
|         this.init()
 | |
|       })
 | |
|     },
 | |
| 
 | |
|     methods: {
 | |
|       drawLine(ctx, options) {
 | |
|         const { beginX, beginY, endX, endY, lineColor, lineWidth } = options
 | |
|         ctx.lineWidth = lineWidth
 | |
|         ctx.strokeStyle = lineColor
 | |
|         ctx.beginPath()
 | |
|         ctx.moveTo(beginX, beginY)
 | |
|         ctx.lineTo(endX, endY)
 | |
|         ctx.closePath()
 | |
|         ctx.stroke()
 | |
|       },
 | |
| 
 | |
|       angle (a, i, ox, oy, or) {
 | |
|         var hudu = (2 * Math.PI / 360) * a * i
 | |
|         var x = ox + Math.sin(hudu) * or
 | |
|         var y = oy - Math.cos(hudu) * or
 | |
|         return x + '_' + y
 | |
|       },
 | |
| 
 | |
|       mapColor (value) {
 | |
|         if (value < 25) {
 | |
|           return '#FFC139'
 | |
|         }
 | |
| 
 | |
|         if (value < 50) {
 | |
|           return '#21E03E'
 | |
|         }
 | |
| 
 | |
|         return '#05C8FF'
 | |
|       },
 | |
| 
 | |
|       init () {
 | |
|         const ctx = document.querySelector(`#${this.canvasId}`).getContext('2d')
 | |
|         const canvasWidth = document.querySelector(`#${this.id}`).offsetWidth
 | |
|         const canvasHeight = document.querySelector(`#${this.id}`).offsetHeight
 | |
|         const angle = this.ratio / 100 * 2
 | |
|         let radian = 0
 | |
| 
 | |
|         ctx.width = canvasWidth
 | |
|         ctx.height = canvasHeight
 | |
|         const x = canvasWidth / 2
 | |
|         const y = canvasHeight / 2
 | |
|         ctx.lineWidth = 2
 | |
|         ctx.strokeStyle = '#383f56'
 | |
|         ctx.beginPath();
 | |
|         ctx.arc(x, y, x - 3, 0, 2 * Math.PI)
 | |
|         ctx.stroke()
 | |
| 
 | |
|         ctx.beginPath()
 | |
|         ctx.lineWidth = 4
 | |
|         ctx.strokeStyle = 'rgba(76, 202, 227, 1)'
 | |
| 
 | |
|         if (this.ratio < 25) {
 | |
|           radian = 3 / 2 + angle
 | |
|           ctx.arc(x, y, x - 4, Math.PI + Math.PI / 2, Math.PI * radian, false)
 | |
|         } else if (this.ratio === 100) {
 | |
|           ctx.arc(x, y, x - 4, 0, Math.PI * 2)
 | |
|         } else {
 | |
|           radian = (this.ratio - 25) / 100 * 2
 | |
|           ctx.arc(x, y, x - 4, Math.PI + Math.PI / 2, Math.PI * radian, false)
 | |
|         }
 | |
|         ctx.stroke()
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| </script>
 | |
| 
 | |
| <style lang="scss" scoped>
 | |
|   .DonutChart {
 | |
|     position: relative;
 | |
|     width: 84px;
 | |
|     height: 84px;
 | |
|     overflow: hidden;
 | |
| 
 | |
|     .DonutChart-text {
 | |
|       display: flex;
 | |
|       position: absolute;
 | |
|       align-items: center;
 | |
|       justify-content: center;
 | |
|       flex-direction: column;
 | |
|       top: 50%;
 | |
|       left: 50%;
 | |
|       z-index: 1;
 | |
|       width: 100%;
 | |
|       height: 100%;
 | |
|       line-height: 1;
 | |
|       transform: translate(-50%, -50%);
 | |
| 
 | |
|       span {
 | |
|         margin-bottom: 8px;
 | |
|         font-size: 20px;
 | |
|         font-weight: bold;
 | |
|         color: #fff;
 | |
|         font-style: oblique;
 | |
|       }
 | |
| 
 | |
|       i {
 | |
|         font-size: 12px;
 | |
|         font-style: normal;
 | |
|         color: rgba(42, 183, 209, 1);
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| </style>
 |