Files
dvcp_v2_webapp/packages/bigscreen/dv/components/DoughnutChart.vue
yanran200730 de3e4ef259 bug
2023-04-28 13:47:40 +08:00

191 lines
4.3 KiB
Vue

<template>
<div class="DoughnutChart-wrapper">
<div class="DoughnutChart" :id="id">
<canvas :id="canvasId"></canvas>
<div class="DonutChart-text">
<span>{{ ratio }}%</span>
</div>
</div>
<div class="DoughnutChart-explain">
<div class="item" v-for="(item, index) in value" :key="index">
<i></i>
<span :style="labelStyle">{{ item.key }}</span>
<p>{{ item.value }}</p>
</div>
</div>
</div>
</template>
<script>
export default {
props: ['ratio', 'value', 'labelStyle'],
data () {
return {
id: `DonutChart-${Math.ceil(Math.random() * 10000)}`,
canvasId: `DonutChartCanvas-${Math.ceil(Math.random() * 10000)}`,
canvasWidth: 90,
canvasHeight: 90
}
},
watch: {
ratio () {
this.init()
}
},
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 = 4
ctx.strokeStyle = 'rgba(102, 121, 138, 0.3)'
ctx.beginPath();
ctx.arc(x, y, x - 8, 0, 2 * Math.PI)
ctx.stroke()
ctx.beginPath()
ctx.lineWidth = 4
var g = ctx.createLinearGradient(0, 0, 0, 80)
g.addColorStop(0, 'rgba(44, 150, 231, 0.8)')
g.addColorStop(1, 'rgba(92, 255, 243, 1)')
ctx.strokeStyle = g
if (this.ratio < 25) {
radian = 3 / 2 + angle
ctx.arc(x, y, x - 8, Math.PI + Math.PI / 2, Math.PI * radian, false)
} else if (this.ratio === 100) {
ctx.arc(x, y, x - 8, 0, Math.PI * 2)
} else {
radian = (this.ratio - 25) / 100 * 2
ctx.arc(x, y, x - 8, Math.PI + Math.PI / 2, Math.PI * radian, false)
}
ctx.stroke()
ctx.beginPath()
ctx.strokeStyle = 'rgba(102, 121, 138, 0.4)'
ctx.lineWidth = 1
ctx.arc(x, y, x - 15, 0, 2 * Math.PI)
ctx.stroke()
}
}
}
</script>
<style lang="scss" scoped>
.DoughnutChart-wrapper {
display: flex;
align-items: center;
justify-content: space-between;
height: 100%;
padding-top: 12px;
.DoughnutChart-explain {
flex: 1;
margin-left: 10px;
.item {
display: flex;
align-items: center;
&:first-child {
margin-bottom: 10px;
}
i {
width: 8px;
height: 8px;
margin-right: 6px;
border-radius: 50%;
background: #5AF9F0;
}
span {
width: 78px;
font-weight: 400;
font-size: 14px;
color: #9BB7D4;
}
p {
font-size: 14px;
color: #FFFFFF;
}
&:last-child i {
background: rgba(102, 121, 138, 0.3);
}
}
}
.DoughnutChart {
position: relative;
width: 90px;
height: 90px;
overflow: hidden;
.DonutChart-text {
display: flex;
position: absolute;
justify-content: center;
top: 50%;
left: 50%;
z-index: 1;
transform: translate(-50%, -50%);
span {
font-size: 17px;
font-weight: bold;
color: #02FEFF;
}
}
}
}
</style>