223 lines
4.3 KiB
Vue
223 lines
4.3 KiB
Vue
<template>
|
|
<div class="percent-arc">
|
|
<loading v-if="!percent || percent === 0" />
|
|
|
|
<div class="canvas-container">
|
|
<canvas :ref="ref" />
|
|
</div>
|
|
|
|
<div class="for-slot">
|
|
<slot></slot>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script>
|
|
import canvasMixin from '../../mixins/canvasMixin.js'
|
|
|
|
export default {
|
|
name: 'PercentArc',
|
|
props: ['percent', 'ringColor', 'arcColor', 'ringLineWidth', 'arcLineWidth', 'radius', 'arcType'],
|
|
mixins: [canvasMixin],
|
|
data () {
|
|
return {
|
|
ref: `percent-arc-${(new Date()).getTime()}`,
|
|
|
|
defaultRadius: 0.9,
|
|
defaultRingLineWidth: 4,
|
|
defaultArcLineWidth: 10,
|
|
defaultArcType: 'butt',
|
|
|
|
defaultRingColor: '#00BAFF',
|
|
defaultArcColor: ['#00BAFF', '#3DE7C9'],
|
|
|
|
trueArcType: '',
|
|
trueRadius: 0,
|
|
ringRadius: 0,
|
|
arcRadius: 0,
|
|
trueRingColor: '',
|
|
trueArcColor: '',
|
|
trueRingLineWidth: 0,
|
|
trueArcLineWidth: 0
|
|
}
|
|
},
|
|
watch: {
|
|
percent () {
|
|
const { init } = this
|
|
|
|
init()
|
|
},
|
|
ringColor () {
|
|
const { init } = this
|
|
|
|
init()
|
|
},
|
|
arcColor () {
|
|
const { init } = this
|
|
|
|
init()
|
|
},
|
|
ringLineWidth () {
|
|
const { init } = this
|
|
|
|
init()
|
|
},
|
|
arcLineWidth () {
|
|
const { init } = this
|
|
|
|
init()
|
|
},
|
|
radius () {
|
|
const { init } = this
|
|
|
|
init()
|
|
},
|
|
arcType () {
|
|
const { init } = this
|
|
|
|
init()
|
|
}
|
|
},
|
|
methods: {
|
|
async init () {
|
|
const { initCanvas, draw } = this
|
|
|
|
await initCanvas()
|
|
|
|
draw()
|
|
},
|
|
draw () {
|
|
const { percent } = this
|
|
|
|
if (!percent && percent !== 0) return
|
|
|
|
const { clearCanvas } = this
|
|
|
|
clearCanvas()
|
|
|
|
const { calcLineWidth, calcRaidus, calcColors } = this
|
|
|
|
calcLineWidth()
|
|
|
|
calcRaidus()
|
|
|
|
calcColors()
|
|
|
|
const { calcArcType, drawRing, drawArc } = this
|
|
|
|
calcArcType()
|
|
|
|
drawRing()
|
|
|
|
drawArc()
|
|
},
|
|
calcLineWidth () {
|
|
const { defaultRingLineWidth, defaultArcLineWidth, ringLineWidth, arcLineWidth } = this
|
|
|
|
this.trueRingLineWidth = ringLineWidth || defaultRingLineWidth
|
|
|
|
this.trueArcLineWidth = arcLineWidth || defaultArcLineWidth
|
|
},
|
|
calcRaidus () {
|
|
const { radius, defaultRadius, canvasWH } = this
|
|
|
|
const trueRadius = this.trueRadius = radius || defaultRadius
|
|
|
|
const ringRadius = this.ringRadius = Math.min(...canvasWH) * trueRadius / 2
|
|
|
|
const { trueRingLineWidth, trueArcLineWidth } = this
|
|
|
|
const halfRingLineWidth = trueRingLineWidth / 2
|
|
|
|
const halfArcLineWidth = trueArcLineWidth / 2
|
|
|
|
this.arcRadius = ringRadius - halfRingLineWidth - halfArcLineWidth
|
|
},
|
|
calcColors () {
|
|
const { ringColor, defaultRingColor } = this
|
|
|
|
this.trueRingColor = ringColor || defaultRingColor
|
|
|
|
const { arcColor, defaultArcColor } = this
|
|
|
|
this.trueArcColor = arcColor || defaultArcColor
|
|
},
|
|
calcArcType () {
|
|
const { arcType, defaultArcType } = this
|
|
|
|
this.trueArcType = arcType || defaultArcType
|
|
},
|
|
drawRing () {
|
|
const { ringRadius, ctx, trueRingLineWidth, centerPos, trueRingColor } = this
|
|
|
|
ctx.lineWidth = trueRingLineWidth
|
|
|
|
ctx.strokeStyle = trueRingColor
|
|
|
|
ctx.beginPath()
|
|
|
|
ctx.arc(...centerPos, ringRadius, 0, Math.PI * 2)
|
|
|
|
ctx.stroke()
|
|
},
|
|
drawArc () {
|
|
const { ctx, centerPos, percent, trueArcType, canvasWH } = this
|
|
|
|
const { trueArcLineWidth, arcRadius, trueArcColor } = this
|
|
|
|
const { canvas: { getLinearGradientColor } } = this
|
|
|
|
const fullArc = Math.PI * 2
|
|
|
|
const offsetArc = Math.PI / 2
|
|
|
|
const arcBegin = offsetArc * -1
|
|
|
|
const arcEnd = fullArc * percent / 100 - offsetArc
|
|
|
|
ctx.lineCap = trueArcType
|
|
|
|
ctx.lineWidth = trueArcLineWidth
|
|
|
|
ctx.strokeStyle = getLinearGradientColor(ctx, [0, 0], [0, canvasWH[1]], trueArcColor)
|
|
|
|
ctx.beginPath()
|
|
|
|
ctx.arc(...centerPos, arcRadius, arcBegin, arcEnd)
|
|
|
|
ctx.stroke()
|
|
}
|
|
},
|
|
mounted () {
|
|
const { init } = this
|
|
|
|
init()
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<style lang="less">
|
|
.percent-arc {
|
|
position: relative;
|
|
display: flex;
|
|
|
|
.canvas-container {
|
|
flex: 1;
|
|
|
|
canvas {
|
|
width: 100%;
|
|
height: 100%;
|
|
}
|
|
}
|
|
|
|
.for-slot {
|
|
position: absolute;
|
|
width: 100%;
|
|
height: 100%;
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
}
|
|
}
|
|
</style>
|