DemuMesDataV/components/polylineChart/index.vue

282 lines
6.8 KiB
Vue
Raw Normal View History

2018-12-08 16:05:04 +08:00
<template>
<div class="polyline-chart">
2019-01-16 16:56:11 +08:00
<loading v-if="!status" />
2018-12-24 18:25:29 +08:00
2018-12-11 14:11:21 +08:00
<div class="canvas-container">
<canvas :ref="ref" />
</div>
2018-12-12 18:47:13 +08:00
2019-01-16 16:56:11 +08:00
<label-line :label="labelLine" :colors="drawColors" />
2018-12-08 19:06:13 +08:00
2018-12-24 18:25:29 +08:00
<for-slot><slot></slot></for-slot>
2018-12-08 16:05:04 +08:00
</div>
</template>
<script>
2018-12-24 18:25:29 +08:00
import colorsMixin from '../../mixins/colorsMixin.js'
import canvasMixin from '../../mixins/canvasMixin.js'
import axisMixin from '../../mixins/axisMixin.js'
2018-12-08 16:05:04 +08:00
export default {
name: 'PolylineChart',
2018-12-24 18:25:29 +08:00
mixins: [colorsMixin, canvasMixin, axisMixin],
2019-01-16 16:56:11 +08:00
props: ['data', 'labelLine', 'colors'],
2018-12-08 16:05:04 +08:00
data () {
return {
2018-12-10 18:22:16 +08:00
ref: `polyline-chart-${(new Date()).getTime()}`,
2018-12-24 18:25:29 +08:00
2019-01-16 16:56:11 +08:00
status: false,
2018-12-24 18:25:29 +08:00
// axis base config
boundaryGap: false,
mulValueAdd: false,
horizon: false,
2019-01-16 16:56:11 +08:00
defaultLineDash: [2, 2],
2018-12-24 18:25:29 +08:00
defaultPointRadius: 2,
defaultValueFontSize: 10,
defaultValueColor: '#999',
valuePointPos: []
2018-12-08 16:05:04 +08:00
}
},
2018-12-11 14:11:21 +08:00
watch: {
2018-12-26 15:01:52 +08:00
data (d) {
2019-01-16 16:56:11 +08:00
const { checkData, draw } = this
2018-12-26 15:01:52 +08:00
2019-01-16 16:56:11 +08:00
checkData() && draw()
2018-12-26 15:01:52 +08:00
}
2018-12-11 14:11:21 +08:00
},
2018-12-08 16:05:04 +08:00
methods: {
2018-12-24 18:25:29 +08:00
async init () {
const { initCanvas, initColors } = this
2018-12-10 18:22:16 +08:00
2018-12-24 18:25:29 +08:00
await initCanvas()
2018-12-08 16:05:04 +08:00
2018-12-24 18:25:29 +08:00
initColors()
2018-12-08 16:05:04 +08:00
2019-01-16 16:56:11 +08:00
const { checkData, draw } = this
checkData() && draw()
},
checkData () {
const { data } = this
this.status = false
if (!data || !data.series) return false
this.status = true
2018-12-08 16:05:04 +08:00
2019-01-16 16:56:11 +08:00
return true
2018-12-10 18:22:16 +08:00
},
draw () {
2018-12-24 18:25:29 +08:00
const { clearCanvas } = this
2018-12-10 18:22:16 +08:00
2018-12-24 18:25:29 +08:00
clearCanvas()
2018-12-10 18:22:16 +08:00
2018-12-24 18:25:29 +08:00
const { initAxisConfig, initAxis, drawAxis } = this
2018-12-10 18:22:16 +08:00
2018-12-24 18:25:29 +08:00
initAxisConfig()
2018-12-10 18:22:16 +08:00
2018-12-24 18:25:29 +08:00
initAxis()
2018-12-10 18:22:16 +08:00
drawAxis()
2018-12-24 18:25:29 +08:00
const { calcValuePointPos, drawLines, drawFills } = this
2018-12-10 18:22:16 +08:00
2018-12-24 18:25:29 +08:00
calcValuePointPos()
2018-12-10 18:22:16 +08:00
2018-12-24 18:25:29 +08:00
drawLines()
2018-12-11 14:11:21 +08:00
2018-12-24 18:25:29 +08:00
drawFills()
2018-12-10 18:22:16 +08:00
2018-12-24 18:25:29 +08:00
const { drawPoints, drawValues } = this
2018-12-11 14:11:21 +08:00
2018-12-24 18:25:29 +08:00
drawPoints()
2018-12-10 18:22:16 +08:00
2018-12-24 18:25:29 +08:00
drawValues()
2018-12-10 18:22:16 +08:00
},
2018-12-24 18:25:29 +08:00
initAxisConfig () {
const { data: { boundaryGap } } = this
2018-12-10 18:22:16 +08:00
2018-12-24 18:25:29 +08:00
this.boundaryGap = boundaryGap
2018-12-10 18:22:16 +08:00
},
2018-12-24 18:25:29 +08:00
calcValuePointPos () {
const { valueAxisMaxMin, axisOriginPos, axisWH, labelAxisTagPos, horizon } = this
2019-01-16 16:56:11 +08:00
const { data: { series }, getAxisPointsPos } = this
2018-12-24 18:25:29 +08:00
2019-01-16 16:56:11 +08:00
this.valuePointPos = series.map(({ value, againstAxis }) =>
2018-12-24 18:25:29 +08:00
getAxisPointsPos(
valueAxisMaxMin,
2019-01-16 16:56:11 +08:00
value,
2018-12-24 18:25:29 +08:00
axisOriginPos,
axisWH,
labelAxisTagPos,
horizon
))
2018-12-10 18:22:16 +08:00
},
2018-12-24 18:25:29 +08:00
drawLines () {
2019-01-16 16:56:11 +08:00
const { data: { series }, valuePointPos, drawLine } = this
2018-12-10 18:22:16 +08:00
2019-01-16 16:56:11 +08:00
series.forEach((line, i) => drawLine(line, valuePointPos[i], i))
2018-12-24 18:25:29 +08:00
},
drawLine ({ type, lineType, lineDash, lineColor }, points, i) {
const { ctx, drawColors, defaultLineDash } = this
2018-12-10 18:22:16 +08:00
2018-12-24 18:25:29 +08:00
const { canvas: { drawPolyline, drawSmoothline } } = this
2018-12-10 18:22:16 +08:00
2018-12-24 18:25:29 +08:00
const { color: { hexToRgb } } = this
2018-12-10 18:22:16 +08:00
2018-12-24 18:25:29 +08:00
let drawLineFun = drawPolyline
type === 'smoothline' && (drawLineFun = drawSmoothline)
2018-12-10 18:22:16 +08:00
2018-12-24 18:25:29 +08:00
let color = hexToRgb(drawColors[i], 0.8)
lineColor && (color = lineColor)
2018-12-10 18:22:16 +08:00
2018-12-24 18:25:29 +08:00
let tureLineType = lineType || 'line'
const tureLineDash = tureLineType === 'dashed' ? (lineDash || defaultLineDash) : [10, 0]
2018-12-10 18:22:16 +08:00
2018-12-24 18:25:29 +08:00
drawLineFun(ctx, points, 1, color, false, tureLineDash, true, true)
2018-12-10 18:22:16 +08:00
},
2018-12-24 18:25:29 +08:00
drawFills () {
2019-01-16 16:56:11 +08:00
const { data: { series }, valuePointPos, drawFill } = this
2018-12-10 18:22:16 +08:00
2019-01-16 16:56:11 +08:00
series.forEach((line, i) => drawFill(line, valuePointPos[i]))
2018-12-24 18:25:29 +08:00
},
2019-01-16 16:56:11 +08:00
drawFill ({ fillColor, type, value }, points) {
2018-12-24 18:25:29 +08:00
if (!fillColor) return
2018-12-10 18:22:16 +08:00
2018-12-24 18:25:29 +08:00
const { canvas: { drawPolylinePath, drawSmoothlinePath } } = this
2018-12-10 18:22:16 +08:00
2018-12-24 18:25:29 +08:00
const { ctx, getGradientColor, filterNull, axisOriginPos: [, y] } = this
2018-12-10 18:22:16 +08:00
2018-12-24 18:25:29 +08:00
let drawLineFun = drawPolylinePath
type === 'smoothline' && (drawLineFun = drawSmoothlinePath)
2018-12-10 18:22:16 +08:00
2019-01-16 16:56:11 +08:00
const maxValue = Math.max(...filterNull(value))
const maxValueIndex = value.findIndex(v => v === maxValue)
2018-12-10 18:22:16 +08:00
2018-12-24 18:25:29 +08:00
const color = getGradientColor(points[maxValueIndex], fillColor)
2018-12-10 18:22:16 +08:00
2018-12-24 18:25:29 +08:00
const lastPoint = points[points.length - 1]
2018-12-10 18:22:16 +08:00
2018-12-24 18:25:29 +08:00
ctx.fillStyle = color
2018-12-10 18:22:16 +08:00
2018-12-24 18:25:29 +08:00
drawLineFun(ctx, points, false, true, true)
2018-12-10 18:22:16 +08:00
2018-12-24 18:25:29 +08:00
ctx.lineTo(lastPoint[0], y)
ctx.lineTo(points[0][0], y)
2018-12-10 18:22:16 +08:00
2018-12-24 18:25:29 +08:00
ctx.closePath()
2018-12-10 18:22:16 +08:00
2018-12-24 18:25:29 +08:00
ctx.fill()
2018-12-10 18:22:16 +08:00
},
2018-12-24 18:25:29 +08:00
getGradientColor (value, colors) {
const { data: { localGradient }, axisAnglePos, horizon } = this
const { ctx, canvas: { getLinearGradientColor } } = this
if (localGradient) {
return getLinearGradientColor(ctx,
...(horizon
? [value, [axisAnglePos.leftTop[0], value[1]]]
: [value, [value[0], axisAnglePos.leftBottom[1]]]),
colors)
} else {
return getLinearGradientColor(ctx,
...(horizon
? [axisAnglePos.leftTop, axisAnglePos.rightTop]
: [axisAnglePos.leftTop, axisAnglePos.leftBottom]),
colors)
}
2018-12-10 18:22:16 +08:00
},
2018-12-24 18:25:29 +08:00
drawPoints () {
2019-01-16 16:56:11 +08:00
const { data: { series }, valuePointPos, drawPoint } = this
2018-12-11 14:11:21 +08:00
2019-01-16 16:56:11 +08:00
series.forEach((line, i) => drawPoint(line, valuePointPos[i], i))
2018-12-11 14:11:21 +08:00
},
2018-12-24 18:25:29 +08:00
drawPoint ({ pointColor }, points, i) {
const { ctx, drawColors, defaultPointRadius } = this
2018-12-10 18:22:16 +08:00
2018-12-24 18:25:29 +08:00
const { canvas: { drawPoints: drawPFun } } = this
2018-12-10 18:22:16 +08:00
2018-12-24 18:25:29 +08:00
const color = pointColor || drawColors[i]
2018-12-10 18:22:16 +08:00
2018-12-24 18:25:29 +08:00
drawPFun(ctx, points, defaultPointRadius, color)
2018-12-10 18:22:16 +08:00
},
2018-12-24 18:25:29 +08:00
drawValues () {
2019-01-16 16:56:11 +08:00
const { ctx, data: { series, showValueText, valueTextOffset, valueTextFontSize } } = this
2018-12-11 14:11:21 +08:00
2018-12-24 18:25:29 +08:00
if (!showValueText) return
2018-12-11 14:11:21 +08:00
2018-12-25 15:54:36 +08:00
const { defaultValueFontSize, drawValue } = this
2018-12-11 14:11:21 +08:00
2018-12-24 18:25:29 +08:00
const offset = valueTextOffset || [0, -5]
2018-12-11 14:11:21 +08:00
2018-12-24 18:25:29 +08:00
ctx.font = `${valueTextFontSize || defaultValueFontSize}px Arial`
2018-12-11 14:11:21 +08:00
2018-12-24 18:25:29 +08:00
ctx.textAlign = 'center'
ctx.textBaseline = 'bottom'
2018-12-11 14:11:21 +08:00
2019-01-16 16:56:11 +08:00
series.forEach((line, i) => drawValue(line, i, offset))
2018-12-24 18:25:29 +08:00
},
2019-01-16 16:56:11 +08:00
drawValue ({ value, valueTextColor, lineColor, pointColor, fillColor }, i, offset) {
2018-12-25 15:54:36 +08:00
const { ctx, getOffsetPoints, valuePointPos, drawColors, defaultValueColor } = this
const { data: { valueTextColor: outerValueTC } } = this
const drawColorsNum = drawColors.length
let currentColor = valueTextColor
currentColor === 'inherit' && (currentColor = pointColor || lineColor || fillColor || drawColors[i % drawColorsNum])
currentColor instanceof Array && (currentColor = currentColor[0])
ctx.fillStyle = currentColor || outerValueTC || defaultValueColor
const pointsPos = valuePointPos[i]
2018-12-11 14:11:21 +08:00
2018-12-25 15:54:36 +08:00
getOffsetPoints(pointsPos, offset).forEach((pos, i) => {
2019-01-16 16:56:11 +08:00
if (!value[i] && value[i] !== 0) return
2018-12-11 14:11:21 +08:00
2019-01-16 16:56:11 +08:00
ctx.fillText(value[i], ...pos)
2018-12-11 14:11:21 +08:00
})
2018-12-10 18:22:16 +08:00
},
2018-12-24 18:25:29 +08:00
getOffsetPoint ([x, y], [ox, oy]) {
return [x + ox, y + oy]
},
getOffsetPoints (points, offset) {
const { getOffsetPoint } = this
2018-12-10 18:22:16 +08:00
2018-12-24 18:25:29 +08:00
return points.map(point => point ? getOffsetPoint(point, offset) : false)
2018-12-08 16:05:04 +08:00
}
},
mounted () {
const { init } = this
init()
}
}
</script>
2018-12-08 19:06:13 +08:00
<style lang="less">
.polyline-chart {
position: relative;
2018-12-11 14:11:21 +08:00
display: flex;
flex-direction: column;
2018-12-08 19:06:13 +08:00
2018-12-11 14:11:21 +08:00
.canvas-container {
flex: 1;
canvas {
width: 100%;
height: 100%;
}
}
2018-12-08 19:06:13 +08:00
}
2018-12-08 16:05:04 +08:00
</style>