DemuMesDataV/components/concentricArcChart/index.vue

180 lines
4.0 KiB
Vue
Raw Normal View History

2018-12-09 16:50:02 +08:00
<template>
<div class="concentric-arc-chart">
2019-01-16 16:56:11 +08:00
<loading v-if="!status" />
2018-12-09 16:50:02 +08:00
2019-01-16 16:56:11 +08:00
<div class="canvas-container">
<canvas :ref="ref" />
</div>
2018-12-09 16:50:02 +08:00
</div>
</template>
<script>
2019-01-16 16:56:11 +08:00
import colorsMixin from '../../mixins/colorsMixin.js'
import canvasMixin from '../../mixins/canvasMixin.js'
2018-12-09 16:50:02 +08:00
export default {
name: 'ConcentricArcChart',
2019-01-16 16:56:11 +08:00
props: ['data', 'colors'],
mixins: [colorsMixin, canvasMixin],
2018-12-09 16:50:02 +08:00
data () {
return {
ref: `concentric-arc-chart-${(new Date()).getTime()}`,
2019-01-16 16:56:11 +08:00
status: false,
2018-12-09 16:50:02 +08:00
arcOriginPos: [],
defaultArcRadiusArea: [0.2, 0.8],
defaultArcGap: 3,
2018-12-11 14:11:12 +08:00
defaultArcColor: ['#00c0ff', '#3de7c9'],
2018-12-09 16:50:02 +08:00
arcRadius: [],
arcRadian: [],
arcLineWidth: 0,
arcColor: ''
}
},
watch: {
2019-01-16 16:56:11 +08:00
data () {
const { checkData, draw } = this
2018-12-09 16:50:02 +08:00
2019-01-16 16:56:11 +08:00
checkData() && draw()
2018-12-09 16:50:02 +08:00
}
},
methods: {
2019-01-16 16:56:11 +08:00
async init () {
const { initCanvas, initColors, checkData, draw } = this
2018-12-09 16:50:02 +08:00
2019-01-16 16:56:11 +08:00
await initCanvas()
2018-12-09 16:50:02 +08:00
2019-01-16 16:56:11 +08:00
initColors()
2018-12-09 16:50:02 +08:00
2019-01-16 16:56:11 +08:00
checkData() && draw()
2018-12-09 16:50:02 +08:00
},
2019-01-16 16:56:11 +08:00
checkData () {
const { data } = this
2018-12-09 16:50:02 +08:00
2019-01-16 16:56:11 +08:00
this.status = false
2018-12-09 16:50:02 +08:00
2019-01-16 16:56:11 +08:00
if (!data || !data.series) return false
2018-12-09 16:50:02 +08:00
2019-01-16 16:56:11 +08:00
this.status = true
2018-12-09 16:50:02 +08:00
2019-01-16 16:56:11 +08:00
return true
2018-12-09 16:50:02 +08:00
},
draw () {
2019-01-16 16:56:11 +08:00
const { clearCanvas, calcArcRadius, calcArcRadian, calcArcColor, drawArc, drawTitle } = this
2018-12-09 16:50:02 +08:00
2019-01-16 16:56:11 +08:00
clearCanvas()
2018-12-09 16:50:02 +08:00
calcArcRadius()
calcArcRadian()
calcArcColor()
drawArc()
drawTitle()
},
calcArcRadius () {
2019-01-16 16:56:11 +08:00
const { data: { series, arcArea, arcGap }, centerPos, defaultArcRadiusArea, defaultArcGap } = this
2018-12-09 16:50:02 +08:00
2019-01-16 16:56:11 +08:00
const arcNum = series.length
2018-12-09 16:50:02 +08:00
2019-01-16 16:56:11 +08:00
const fullRadius = (centerPos[0] > centerPos[1] ? centerPos[1] : centerPos[0])
2018-12-09 16:50:02 +08:00
const currentArcArea = arcArea || defaultArcRadiusArea
const maxRadius = fullRadius * Math.max(...currentArcArea)
const minRadius = fullRadius * Math.min(...currentArcArea)
const currentArcGap = arcGap || defaultArcGap
const arcLineWidth = this.arcLineWidth = (maxRadius - minRadius - currentArcGap * (arcNum - 1)) / arcNum
const fullArcLineWidth = arcLineWidth + currentArcGap
const halfArcLineWidth = arcLineWidth / 2
this.arcRadius = new Array(arcNum).fill(0).map((t, i) => maxRadius - halfArcLineWidth - fullArcLineWidth * i)
},
calcArcRadian () {
2019-01-16 16:56:11 +08:00
const { data: { series } } = this
2018-12-09 16:50:02 +08:00
const fullRadian = Math.PI / 2 * 3
const offsetRadian = Math.PI * 0.5
2019-01-16 16:56:11 +08:00
this.arcRadian = new Array(series.length).fill(0).map((t, i) => series[i].value * fullRadian - offsetRadian)
2018-12-09 16:50:02 +08:00
},
calcArcColor () {
2018-12-11 14:11:12 +08:00
const { ctx, arcLineWidth, defaultArcColor, canvas: { getLinearGradientColor } } = this
2018-12-09 16:50:02 +08:00
2019-01-16 16:56:11 +08:00
const { drawColors, arcRadius: [ radius ], centerPos: [x, y] } = this
2018-12-09 16:50:02 +08:00
2019-01-16 16:56:11 +08:00
const colors = drawColors || defaultArcColor
2018-12-09 16:50:02 +08:00
2018-12-11 14:11:12 +08:00
this.arcColor = getLinearGradientColor(ctx,
[x, y - radius - arcLineWidth],
[x, y + radius + arcLineWidth], colors)
2018-12-09 16:50:02 +08:00
},
drawArc () {
2019-01-16 16:56:11 +08:00
const { ctx, arcRadius, arcRadian, centerPos, arcLineWidth, arcColor } = this
2018-12-09 16:50:02 +08:00
const offsetRadian = Math.PI / -2
ctx.lineWidth = arcLineWidth
ctx.strokeStyle = arcColor
arcRadius.forEach((radius, i) => {
ctx.beginPath()
2019-01-16 16:56:11 +08:00
ctx.arc(...centerPos, radius, offsetRadian, arcRadian[i])
2018-12-09 16:50:02 +08:00
ctx.stroke()
})
},
drawTitle () {
2019-01-16 16:56:11 +08:00
const { ctx, data: { series, fontSize }, arcRadius, centerPos: [ x, y ], arcLineWidth } = this
2018-12-09 16:50:02 +08:00
const textEndX = x - 10
ctx.font = `${fontSize || arcLineWidth}px Arial`
ctx.textAlign = 'right'
ctx.textBaseline = 'middle'
ctx.fillStyle = '#fff'
ctx.beginPath()
2019-01-16 16:56:11 +08:00
series.forEach(({ title }, i) => {
2018-12-09 16:50:02 +08:00
ctx.fillText(title, textEndX, y - arcRadius[i])
})
}
},
mounted () {
const { init } = this
init()
}
}
</script>
<style lang="less">
.concentric-arc-chart {
position: relative;
2019-01-16 16:56:11 +08:00
display: flex;
flex-direction: column;
color: #fff;
.canvas-container {
position: relative;
flex: 1;
}
2018-12-09 16:50:02 +08:00
canvas {
width: 100%;
height: 100%;
}
}
</style>