2018-12-20 18:25:19 +08:00
|
|
|
<template>
|
|
|
|
<div class="column-chart">
|
2019-01-16 16:56:11 +08:00
|
|
|
<loading v-if="!status" />
|
2018-12-20 18:25:19 +08:00
|
|
|
|
|
|
|
<div class="canvas-container">
|
|
|
|
<canvas :ref="ref" />
|
|
|
|
</div>
|
|
|
|
|
2019-01-16 16:56:11 +08:00
|
|
|
<label-line :label="labelLine" :colors="drawColors" />
|
2018-12-24 18:24:52 +08:00
|
|
|
|
|
|
|
<for-slot><slot></slot></for-slot>
|
2018-12-20 18:25:19 +08:00
|
|
|
</div>
|
|
|
|
</template>
|
|
|
|
|
|
|
|
<script>
|
|
|
|
import colorsMixin from '../../mixins/colorsMixin.js'
|
|
|
|
|
|
|
|
import canvasMixin from '../../mixins/canvasMixin.js'
|
|
|
|
|
|
|
|
import axisMixin from '../../mixins/axisMixin.js'
|
|
|
|
|
|
|
|
export default {
|
|
|
|
name: 'ColumnChart',
|
|
|
|
mixins: [colorsMixin, canvasMixin, axisMixin],
|
2019-01-16 16:56:11 +08:00
|
|
|
props: ['data', 'labelLine', 'colors'],
|
2018-12-20 18:25:19 +08:00
|
|
|
data () {
|
|
|
|
return {
|
|
|
|
ref: `radar-chart-${(new Date()).getTime()}`,
|
|
|
|
|
2019-01-16 16:56:11 +08:00
|
|
|
status: false,
|
|
|
|
|
2018-12-23 19:06:42 +08:00
|
|
|
// axis base config
|
|
|
|
boundaryGap: true,
|
|
|
|
mulValueAdd: true,
|
|
|
|
horizon: false,
|
|
|
|
|
2018-12-23 22:33:45 +08:00
|
|
|
echelonOffset: 10,
|
2018-12-24 14:09:25 +08:00
|
|
|
defaultColumnBGColor: 'rgba(100, 100, 100, 0.2)',
|
|
|
|
|
|
|
|
defaultValueFontSize: 10,
|
2019-01-16 16:56:11 +08:00
|
|
|
defaultValueColor: '#666',
|
2018-12-23 22:33:45 +08:00
|
|
|
|
2018-12-23 19:06:42 +08:00
|
|
|
columnData: [],
|
|
|
|
columnItemSeriesNum: 0,
|
|
|
|
columnItemAllWidth: 0,
|
|
|
|
columnItemWidth: 0,
|
2018-12-24 14:09:25 +08:00
|
|
|
columnBGWidth: 0,
|
2018-12-23 19:06:42 +08:00
|
|
|
columnItemOffset: [],
|
|
|
|
|
2018-12-24 14:09:25 +08:00
|
|
|
valueTextOffset: [],
|
|
|
|
|
2018-12-23 19:06:42 +08:00
|
|
|
valuePointPos: []
|
2018-12-20 18:25:19 +08:00
|
|
|
}
|
|
|
|
},
|
2018-12-24 18:24:52 +08:00
|
|
|
watch: {
|
2019-01-16 16:56:11 +08:00
|
|
|
data () {
|
|
|
|
const { checkData, draw } = this
|
2018-12-24 18:24:52 +08:00
|
|
|
|
2019-01-16 16:56:11 +08:00
|
|
|
checkData() && draw()
|
2018-12-24 18:24:52 +08:00
|
|
|
}
|
|
|
|
},
|
2018-12-20 18:25:19 +08:00
|
|
|
methods: {
|
|
|
|
async init () {
|
2018-12-23 19:06:42 +08:00
|
|
|
const { initCanvas, initColors } = this
|
2018-12-20 18:25:19 +08:00
|
|
|
|
|
|
|
await initCanvas()
|
|
|
|
|
2018-12-23 19:06:42 +08:00
|
|
|
initColors()
|
|
|
|
|
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-23 19:06:42 +08:00
|
|
|
|
2019-01-16 16:56:11 +08:00
|
|
|
return true
|
2018-12-20 18:25:19 +08:00
|
|
|
},
|
|
|
|
draw () {
|
2018-12-23 19:06:42 +08:00
|
|
|
const { clearCanvas } = this
|
2018-12-20 18:25:19 +08:00
|
|
|
|
|
|
|
clearCanvas()
|
|
|
|
|
2018-12-23 19:06:42 +08:00
|
|
|
const { calcHorizon, initAxis, drawAxis } = this
|
|
|
|
|
|
|
|
calcHorizon()
|
2018-12-20 18:25:19 +08:00
|
|
|
|
|
|
|
initAxis()
|
|
|
|
|
|
|
|
drawAxis()
|
2018-12-20 22:36:07 +08:00
|
|
|
|
2018-12-23 19:06:42 +08:00
|
|
|
const { switchNormalOrCenterOriginType } = this
|
2018-12-20 22:36:07 +08:00
|
|
|
|
2018-12-23 19:06:42 +08:00
|
|
|
switchNormalOrCenterOriginType()
|
|
|
|
},
|
|
|
|
calcHorizon () {
|
|
|
|
const { data: { horizon } } = this
|
|
|
|
|
|
|
|
this.horizon = horizon
|
|
|
|
},
|
|
|
|
switchNormalOrCenterOriginType () {
|
|
|
|
const { centerOrigin, drawNormalTypeColumnChart, drawCenterOriginTypeColumnChart } = this
|
|
|
|
|
|
|
|
if (centerOrigin) drawCenterOriginTypeColumnChart()
|
|
|
|
|
|
|
|
if (!centerOrigin) drawNormalTypeColumnChart()
|
|
|
|
},
|
|
|
|
drawNormalTypeColumnChart () {
|
|
|
|
const { calcColumnConfig, calcColumnItemOffset, calcValuePointPos } = this
|
2018-12-20 22:36:07 +08:00
|
|
|
|
|
|
|
calcColumnConfig()
|
|
|
|
|
2018-12-23 19:06:42 +08:00
|
|
|
calcColumnItemOffset()
|
|
|
|
|
|
|
|
calcValuePointPos()
|
2018-12-20 22:36:07 +08:00
|
|
|
|
2018-12-24 14:09:25 +08:00
|
|
|
const { drawColumnBG, drawFigure, drawValueText } = this
|
|
|
|
|
|
|
|
drawColumnBG()
|
2018-12-20 22:36:07 +08:00
|
|
|
|
2018-12-23 19:06:42 +08:00
|
|
|
drawFigure()
|
2018-12-24 14:09:25 +08:00
|
|
|
|
|
|
|
drawValueText()
|
2018-12-20 22:36:07 +08:00
|
|
|
},
|
|
|
|
calcColumnConfig () {
|
2019-01-16 16:56:11 +08:00
|
|
|
const { data: { series, spaceBetween }, labelAxisTagPos, axisOriginPos, horizon } = this
|
2018-12-20 22:36:07 +08:00
|
|
|
|
2019-01-16 16:56:11 +08:00
|
|
|
const columnData = this.columnData = series.filter(({ type }) =>
|
2018-12-23 19:06:42 +08:00
|
|
|
!(type === 'polyline' || type === 'smoothline'))
|
2018-12-20 22:36:07 +08:00
|
|
|
|
2018-12-23 19:06:42 +08:00
|
|
|
const columnItemSeriesNum = this.columnItemSeriesNum = columnData.length
|
2018-12-20 22:36:07 +08:00
|
|
|
|
2018-12-23 19:06:42 +08:00
|
|
|
const columnItemAllWidth = this.columnItemAllWidth = (horizon
|
|
|
|
? axisOriginPos[1] - labelAxisTagPos[0][1]
|
|
|
|
: labelAxisTagPos[0][0] - axisOriginPos[0]) * 2
|
2018-12-20 22:36:07 +08:00
|
|
|
|
2018-12-24 14:09:25 +08:00
|
|
|
const columnItemWidth = this.columnItemWidth = columnItemAllWidth / (columnItemSeriesNum + 1)
|
|
|
|
|
|
|
|
const spaceGap = columnItemWidth / (columnItemSeriesNum + 1)
|
|
|
|
|
|
|
|
let columnBGWidth = columnItemWidth * columnItemSeriesNum
|
|
|
|
|
|
|
|
spaceBetween && (columnBGWidth += spaceGap * (columnItemSeriesNum - 1))
|
|
|
|
|
|
|
|
this.columnBGWidth = columnBGWidth
|
2018-12-23 19:06:42 +08:00
|
|
|
},
|
|
|
|
calcColumnItemOffset () {
|
|
|
|
const { columnItemSeriesNum, columnItemAllWidth, columnItemWidth } = this
|
2018-12-20 22:36:07 +08:00
|
|
|
|
2019-01-16 16:56:11 +08:00
|
|
|
const { data: { spaceBetween, series } } = this
|
2018-12-20 22:36:07 +08:00
|
|
|
|
2018-12-23 19:06:42 +08:00
|
|
|
const halfColumnWidth = columnItemWidth / 2
|
|
|
|
|
|
|
|
const halfColumnItemAllWidth = columnItemAllWidth / 2
|
|
|
|
|
|
|
|
let columnItemOffset = new Array(columnItemSeriesNum).fill(0)
|
|
|
|
|
|
|
|
if (spaceBetween) {
|
|
|
|
const spaceGap = columnItemWidth / (columnItemSeriesNum + 1)
|
|
|
|
|
2018-12-24 14:09:25 +08:00
|
|
|
columnItemOffset = columnItemOffset.map((t, i) =>
|
2018-12-23 19:06:42 +08:00
|
|
|
spaceGap * (i + 1) + columnItemWidth * i + halfColumnWidth - halfColumnItemAllWidth)
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!spaceBetween) {
|
2018-12-24 14:09:25 +08:00
|
|
|
columnItemOffset = columnItemOffset.map((t, i) =>
|
2018-12-23 19:06:42 +08:00
|
|
|
columnItemWidth * (i + 1) - halfColumnItemAllWidth)
|
|
|
|
}
|
2018-12-24 14:09:25 +08:00
|
|
|
|
2019-01-16 16:56:11 +08:00
|
|
|
this.columnItemOffset = series.map(({ type }) =>
|
2018-12-24 14:09:25 +08:00
|
|
|
(type === 'polyline' || type === 'smoothline')
|
|
|
|
? 0
|
|
|
|
: columnItemOffset.shift())
|
2018-12-20 22:36:07 +08:00
|
|
|
},
|
2018-12-23 19:06:42 +08:00
|
|
|
calcValuePointPos () {
|
|
|
|
const { getAxisPointsPos, valueAxisMaxMin, agValueAxisMaxMin } = this
|
|
|
|
|
|
|
|
const { labelAxisTagPos, deepClone, filterNull, multipleSum } = this
|
2018-12-20 22:36:07 +08:00
|
|
|
|
2019-01-16 16:56:11 +08:00
|
|
|
const { data: { series }, axisOriginPos, axisWH, horizon } = this
|
2018-12-20 22:36:07 +08:00
|
|
|
|
2019-01-16 16:56:11 +08:00
|
|
|
const dealAfterData = deepClone(series).map(({ value, againstAxis }) => {
|
|
|
|
if (!(value[0] instanceof Array)) return { value, againstAxis }
|
2018-12-20 22:36:07 +08:00
|
|
|
|
2019-01-16 16:56:11 +08:00
|
|
|
const valueData = value.map(valueSeries => valueSeries.map((v, i) => {
|
2018-12-23 19:06:42 +08:00
|
|
|
if (!v && v !== 0) return false
|
2018-12-20 22:36:07 +08:00
|
|
|
|
2019-01-16 16:56:11 +08:00
|
|
|
return multipleSum(...filterNull(valueSeries.slice(0, i + 1)))
|
2018-12-23 19:06:42 +08:00
|
|
|
}))
|
2018-12-20 22:36:07 +08:00
|
|
|
|
2019-01-16 16:56:11 +08:00
|
|
|
return { value: valueData, againstAxis }
|
2018-12-23 19:06:42 +08:00
|
|
|
})
|
2018-12-20 22:36:07 +08:00
|
|
|
|
2019-01-16 16:56:11 +08:00
|
|
|
this.valuePointPos = dealAfterData.map(({ value, againstAxis }) =>
|
2018-12-23 19:06:42 +08:00
|
|
|
getAxisPointsPos(
|
|
|
|
againstAxis ? agValueAxisMaxMin : valueAxisMaxMin,
|
2019-01-16 16:56:11 +08:00
|
|
|
value,
|
2018-12-23 19:06:42 +08:00
|
|
|
axisOriginPos,
|
|
|
|
axisWH,
|
|
|
|
labelAxisTagPos,
|
|
|
|
horizon
|
|
|
|
))
|
2018-12-20 22:36:07 +08:00
|
|
|
},
|
2018-12-24 14:09:25 +08:00
|
|
|
drawColumnBG () {
|
|
|
|
const { ctx, data: { showColumnBG, columnBGColor, roundColumn } } = this
|
|
|
|
|
|
|
|
if (!showColumnBG) return
|
|
|
|
|
|
|
|
const { columnBGWidth, defaultColumnBGColor, horizon, axisWH: [w, h], labelAxisTagPos } = this
|
|
|
|
|
|
|
|
const trueColumnColor = columnBGColor || defaultColumnBGColor
|
|
|
|
|
|
|
|
ctx.lineWidth = columnBGWidth
|
|
|
|
ctx.strokeStyle = trueColumnColor
|
|
|
|
ctx.setLineDash([10, 0])
|
|
|
|
|
2018-12-25 10:56:05 +08:00
|
|
|
const { getRoundColumnPoint, labelAxisTag } = this
|
2018-12-24 14:09:25 +08:00
|
|
|
|
|
|
|
ctx.lineCap = roundColumn ? 'round' : 'butt'
|
|
|
|
|
2018-12-25 10:56:05 +08:00
|
|
|
labelAxisTagPos.forEach(([x, y], i) => {
|
|
|
|
if (!labelAxisTag[i] && labelAxisTag[i] !== 0) return
|
|
|
|
|
2018-12-24 14:09:25 +08:00
|
|
|
const topPoint = horizon ? [x + w, y] : [x, y - h]
|
|
|
|
let columnBGPoints = [[x, y], topPoint]
|
|
|
|
|
|
|
|
roundColumn && (columnBGPoints = getRoundColumnPoint(columnBGPoints, columnBGWidth))
|
|
|
|
|
|
|
|
ctx.beginPath()
|
|
|
|
|
|
|
|
ctx.moveTo(...columnBGPoints[0])
|
|
|
|
ctx.lineTo(...columnBGPoints[1])
|
|
|
|
|
|
|
|
ctx.stroke()
|
|
|
|
})
|
|
|
|
},
|
2018-12-23 19:06:42 +08:00
|
|
|
drawFigure () {
|
2019-01-16 16:56:11 +08:00
|
|
|
const { data: { series }, valuePointPos } = this
|
2018-12-23 19:06:42 +08:00
|
|
|
|
2018-12-23 22:33:45 +08:00
|
|
|
const { drawColumn, drawEchelon, drawline } = this
|
2018-12-23 19:06:42 +08:00
|
|
|
|
2019-01-16 16:56:11 +08:00
|
|
|
series.forEach((valueSeries, i) => {
|
|
|
|
switch (valueSeries.type) {
|
2018-12-23 22:33:45 +08:00
|
|
|
case 'leftEchelon':
|
2019-01-16 16:56:11 +08:00
|
|
|
case 'rightEchelon': drawEchelon(valueSeries, valuePointPos[i], i)
|
2018-12-23 19:06:42 +08:00
|
|
|
break
|
2018-12-23 22:33:45 +08:00
|
|
|
|
|
|
|
case 'polyline':
|
2019-01-16 16:56:11 +08:00
|
|
|
case 'smoothline': drawline(valueSeries, valuePointPos[i], i)
|
2018-12-23 19:06:42 +08:00
|
|
|
break
|
|
|
|
|
2019-01-16 16:56:11 +08:00
|
|
|
default: drawColumn(valueSeries, valuePointPos[i], i)
|
2018-12-23 19:06:42 +08:00
|
|
|
break
|
|
|
|
}
|
|
|
|
})
|
|
|
|
},
|
|
|
|
getGradientColor (value, colors) {
|
|
|
|
const { data: { localGradient }, axisAnglePos, horizon } = this
|
2018-12-20 22:36:07 +08:00
|
|
|
|
2018-12-23 19:06:42 +08:00
|
|
|
const { ctx, canvas: { getLinearGradientColor } } = this
|
2018-12-20 22:36:07 +08:00
|
|
|
|
2018-12-23 19:06:42 +08:00
|
|
|
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)
|
|
|
|
}
|
|
|
|
},
|
|
|
|
drawColumn ({ fillColor }, points, i) {
|
2018-12-23 22:33:45 +08:00
|
|
|
const { ctx, columnItemWidth, drawColors } = this
|
2018-12-20 22:36:07 +08:00
|
|
|
|
2018-12-23 19:06:42 +08:00
|
|
|
ctx.setLineDash([10, 0])
|
|
|
|
ctx.lineWidth = columnItemWidth
|
2018-12-20 22:36:07 +08:00
|
|
|
|
2018-12-23 22:33:45 +08:00
|
|
|
const color = fillColor || drawColors[i]
|
|
|
|
const colorNum = color.length
|
|
|
|
const drawColorNum = drawColors.length
|
|
|
|
|
|
|
|
const { columnItemOffset, labelAxisTagPos, getOffsetPoint } = this
|
2018-12-20 22:36:07 +08:00
|
|
|
|
2018-12-24 14:09:25 +08:00
|
|
|
const currentOffset = columnItemOffset[i]
|
2018-12-23 22:33:45 +08:00
|
|
|
const offsetTagPos = labelAxisTagPos.map(p => getOffsetPoint(p, currentOffset))
|
2018-12-20 22:36:07 +08:00
|
|
|
|
2018-12-23 22:33:45 +08:00
|
|
|
const { getGradientColor, getRoundColumnPoint, data: { roundColumn } } = this
|
2018-12-20 22:36:07 +08:00
|
|
|
|
2018-12-23 22:33:45 +08:00
|
|
|
ctx.lineCap = roundColumn ? 'round' : 'butt'
|
2018-12-20 22:36:07 +08:00
|
|
|
|
2018-12-23 22:33:45 +08:00
|
|
|
const seriesColumn = points[0][0] instanceof Array
|
2018-12-20 22:36:07 +08:00
|
|
|
|
2018-12-24 14:09:25 +08:00
|
|
|
seriesColumn && points.forEach((series, j) => {
|
|
|
|
let lastEnd = offsetTagPos[j]
|
|
|
|
|
|
|
|
series.forEach((item, k) => {
|
|
|
|
if (!item && item !== 0) return
|
2018-12-20 22:36:07 +08:00
|
|
|
|
2018-12-23 22:33:45 +08:00
|
|
|
const currentPoint = getOffsetPoint(item, currentOffset)
|
2018-12-20 22:36:07 +08:00
|
|
|
|
2018-12-23 22:33:45 +08:00
|
|
|
let columnPoint = [lastEnd, currentPoint]
|
|
|
|
|
|
|
|
roundColumn && (columnPoint = getRoundColumnPoint(columnPoint))
|
|
|
|
|
|
|
|
if (typeof color === 'string') {
|
2018-12-24 14:09:25 +08:00
|
|
|
ctx.strokeStyle = drawColors[(i + k) % drawColorNum]
|
2018-12-23 22:33:45 +08:00
|
|
|
} else {
|
2018-12-24 14:09:25 +08:00
|
|
|
ctx.strokeStyle = color[k % colorNum]
|
2018-12-23 22:33:45 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
ctx.beginPath()
|
|
|
|
ctx.moveTo(...columnPoint[0])
|
|
|
|
ctx.lineTo(...columnPoint[1])
|
|
|
|
ctx.stroke()
|
|
|
|
|
|
|
|
lastEnd = currentPoint
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
!seriesColumn && points.forEach((point, i) => {
|
2018-12-24 14:09:25 +08:00
|
|
|
if (!point && point !== 0) return
|
|
|
|
|
2018-12-23 22:33:45 +08:00
|
|
|
let columnPoint = [offsetTagPos[i], getOffsetPoint(point, currentOffset)]
|
|
|
|
|
|
|
|
roundColumn && (columnPoint = getRoundColumnPoint(columnPoint))
|
2018-12-20 22:36:07 +08:00
|
|
|
|
|
|
|
ctx.beginPath()
|
2018-12-23 22:33:45 +08:00
|
|
|
ctx.strokeStyle = getGradientColor(point, color)
|
|
|
|
ctx.moveTo(...columnPoint[0])
|
|
|
|
ctx.lineTo(...columnPoint[1])
|
2018-12-20 22:36:07 +08:00
|
|
|
ctx.stroke()
|
|
|
|
})
|
|
|
|
},
|
2018-12-23 19:06:42 +08:00
|
|
|
getOffsetPoint ([x, y], offset) {
|
|
|
|
const { horizon } = this
|
2018-12-21 14:47:16 +08:00
|
|
|
|
2018-12-23 19:06:42 +08:00
|
|
|
return horizon
|
|
|
|
? [x, y + offset]
|
|
|
|
: [x + offset, y]
|
|
|
|
},
|
2018-12-24 14:09:25 +08:00
|
|
|
getOffsetPoints (points, offset) {
|
|
|
|
const { getOffsetPoint } = this
|
2018-12-23 22:33:45 +08:00
|
|
|
|
2018-12-24 18:24:52 +08:00
|
|
|
return points.map(point => point ? getOffsetPoint(point, offset) : false)
|
2018-12-24 14:09:25 +08:00
|
|
|
},
|
|
|
|
getRoundColumnPoint ([pa, pb], cw = false) {
|
|
|
|
const { horizon, columnItemWidth: dciw } = this
|
|
|
|
|
|
|
|
const columnWidth = cw || dciw
|
|
|
|
|
|
|
|
const radius = columnWidth / 2
|
2018-12-23 22:33:45 +08:00
|
|
|
|
|
|
|
let [a, b, c, d] = [0, 0, 0, 0]
|
|
|
|
|
|
|
|
if (horizon) {
|
|
|
|
a = pa[0] + radius
|
|
|
|
b = pa[1]
|
|
|
|
c = pb[0] - radius
|
|
|
|
d = pb[1]
|
|
|
|
} else {
|
|
|
|
a = pa[0]
|
|
|
|
b = pa[1] - radius
|
|
|
|
c = pb[0]
|
|
|
|
d = pb[1] + radius
|
|
|
|
}
|
|
|
|
|
|
|
|
return horizon ? [
|
|
|
|
[a > c ? c : a, b],
|
|
|
|
[c, d]
|
|
|
|
] : [
|
|
|
|
[a, b],
|
|
|
|
[c, b > d ? d : b]
|
|
|
|
]
|
|
|
|
},
|
|
|
|
drawline ({ lineColor, fillColor, pointColor, lineType, lineDash, type }, points, i) {
|
|
|
|
const { drawColors, ctx, axisOriginPos: [x, y], horizon } = this
|
|
|
|
|
|
|
|
const { color: { hexToRgb }, getGradientColor, getTopPoint } = this
|
|
|
|
|
|
|
|
const drawColorNum = drawColors.length
|
|
|
|
const currentColor = drawColors[i % drawColorNum]
|
|
|
|
|
|
|
|
let currentLineColor = hexToRgb(currentColor, 0.6)
|
|
|
|
let currentPointColor = currentColor
|
|
|
|
|
|
|
|
lineColor && (currentLineColor = lineColor)
|
|
|
|
pointColor && (currentPointColor = pointColor)
|
|
|
|
|
|
|
|
let currentLineType = lineType || 'line'
|
|
|
|
let currentLineDash = currentLineType === 'dashed' ? (lineDash || [5, 5]) : [10, 0]
|
|
|
|
|
|
|
|
ctx.strokeStyle = currentLineColor
|
|
|
|
|
|
|
|
const { canvas: { drawPolylinePath, drawPolyline, drawPoints } } = this
|
|
|
|
const { canvas: { drawSmoothlinePath, drawSmoothline } } = this
|
|
|
|
|
|
|
|
const lineFun = type === 'polyline' ? [drawPolylinePath, drawPolyline] : [drawSmoothlinePath, drawSmoothline]
|
|
|
|
|
|
|
|
if (fillColor) {
|
|
|
|
const lastPoint = points[points.length - 1]
|
|
|
|
|
|
|
|
ctx.fillStyle = getGradientColor(getTopPoint(points), fillColor)
|
|
|
|
|
|
|
|
lineFun[0](ctx, points, false, true, true)
|
|
|
|
ctx.lineTo(...(horizon ? [x, lastPoint[1]] : [lastPoint[0], y]))
|
|
|
|
ctx.lineTo(...(horizon ? [x, points[0][1]] : [points[0][0], y]))
|
|
|
|
|
|
|
|
ctx.closePath()
|
|
|
|
ctx.fill()
|
|
|
|
}
|
|
|
|
|
|
|
|
lineFun[1](ctx, points, 1, currentLineColor, false, currentLineDash, true, true)
|
|
|
|
|
|
|
|
drawPoints(ctx, points, 2, currentPointColor)
|
|
|
|
},
|
|
|
|
getTopPoint (points) {
|
|
|
|
const { horizon } = this
|
|
|
|
|
|
|
|
let topIndex = 0
|
|
|
|
|
|
|
|
const xPos = points.map(([x]) => x)
|
|
|
|
const yPos = points.map(([, y]) => y)
|
|
|
|
|
|
|
|
if (horizon) {
|
|
|
|
const top = Math.max(...xPos)
|
|
|
|
|
|
|
|
topIndex = xPos.findIndex(v => v === top)
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!horizon) {
|
|
|
|
const top = Math.min(...yPos)
|
|
|
|
|
|
|
|
topIndex = yPos.findIndex(v => v === top)
|
|
|
|
}
|
|
|
|
|
|
|
|
return points[topIndex]
|
|
|
|
},
|
|
|
|
drawEchelon ({ fillColor, type }, points, i) {
|
|
|
|
const { data: { roundColumn } } = this
|
|
|
|
|
|
|
|
const seriesColumn = points[0][0] instanceof Array
|
|
|
|
|
|
|
|
if (seriesColumn || roundColumn) return
|
|
|
|
|
|
|
|
const { ctx, columnItemOffset, labelAxisTagPos, getOffsetPoint } = this
|
|
|
|
|
2018-12-24 14:09:25 +08:00
|
|
|
const currentOffset = columnItemOffset[i]
|
2018-12-23 22:33:45 +08:00
|
|
|
const offsetTagPos = labelAxisTagPos.map(p => getOffsetPoint(p, currentOffset))
|
|
|
|
|
|
|
|
const { drawColors, getGradientColor, getEchelonPoints } = this
|
|
|
|
|
|
|
|
const drawColorsNum = drawColors.length
|
|
|
|
|
|
|
|
const color = fillColor || drawColors[i % drawColorsNum]
|
|
|
|
|
|
|
|
const { canvas: { drawPolylinePath } } = this
|
|
|
|
|
|
|
|
points.forEach((point, i) => {
|
|
|
|
const topPoint = getOffsetPoint(point, currentOffset)
|
|
|
|
const bottomPoint = offsetTagPos[i]
|
|
|
|
|
|
|
|
const echelonPoints = getEchelonPoints(topPoint, bottomPoint, type)
|
|
|
|
|
|
|
|
drawPolylinePath(ctx, echelonPoints, true, true)
|
|
|
|
|
|
|
|
ctx.fillStyle = getGradientColor(point, color)
|
|
|
|
|
|
|
|
ctx.fill()
|
|
|
|
})
|
|
|
|
},
|
|
|
|
getEchelonPoints ([tx, ty], [bx, by], type) {
|
|
|
|
const { columnItemWidth, echelonOffset, horizon } = this
|
|
|
|
|
|
|
|
const halfWidth = columnItemWidth / 2
|
|
|
|
|
|
|
|
const echelonPoint = []
|
|
|
|
|
|
|
|
if (horizon) {
|
|
|
|
let enhance = tx - bx < echelonOffset
|
|
|
|
|
|
|
|
if (type === 'leftEchelon') {
|
|
|
|
echelonPoint[0] = [tx, ty + halfWidth]
|
|
|
|
echelonPoint[1] = [bx, ty + halfWidth]
|
|
|
|
echelonPoint[2] = [bx + echelonOffset, by - halfWidth]
|
|
|
|
echelonPoint[3] = [tx, ty - halfWidth]
|
|
|
|
}
|
|
|
|
|
|
|
|
if (type === 'rightEchelon') {
|
|
|
|
echelonPoint[0] = [tx, ty - halfWidth]
|
|
|
|
echelonPoint[1] = [bx, ty - halfWidth]
|
|
|
|
echelonPoint[2] = [bx + echelonOffset, by + halfWidth]
|
|
|
|
echelonPoint[3] = [tx, ty + halfWidth]
|
|
|
|
}
|
|
|
|
|
|
|
|
if (enhance) echelonPoint.splice(2, 1)
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!horizon) {
|
|
|
|
let enhance = by - ty < echelonOffset
|
|
|
|
|
|
|
|
if (type === 'leftEchelon') {
|
|
|
|
echelonPoint[0] = [tx + halfWidth, ty]
|
|
|
|
echelonPoint[1] = [tx + halfWidth, by]
|
|
|
|
echelonPoint[2] = [tx - halfWidth, by - echelonOffset]
|
|
|
|
echelonPoint[3] = [tx - halfWidth, ty]
|
|
|
|
}
|
|
|
|
|
|
|
|
if (type === 'rightEchelon') {
|
|
|
|
echelonPoint[0] = [tx - halfWidth, ty]
|
|
|
|
echelonPoint[1] = [tx - halfWidth, by]
|
|
|
|
echelonPoint[2] = [tx + halfWidth, by - echelonOffset]
|
|
|
|
echelonPoint[3] = [tx + halfWidth, ty]
|
|
|
|
}
|
|
|
|
|
|
|
|
if (enhance) echelonPoint.splice(2, 1)
|
|
|
|
}
|
|
|
|
|
|
|
|
return echelonPoint
|
|
|
|
},
|
2018-12-24 14:09:25 +08:00
|
|
|
drawValueText () {
|
2018-12-25 15:54:36 +08:00
|
|
|
const { data: { showValueText }, horizon } = this
|
2018-12-21 14:47:16 +08:00
|
|
|
|
2018-12-24 14:09:25 +08:00
|
|
|
if (!showValueText) return
|
2018-12-21 14:47:16 +08:00
|
|
|
|
2019-01-16 16:56:11 +08:00
|
|
|
const { data: { valueTextFontSize, valueTextOffset, series } } = this
|
2018-12-21 14:47:16 +08:00
|
|
|
|
2018-12-25 15:54:36 +08:00
|
|
|
const { ctx, defaultValueFontSize } = this
|
2018-12-21 14:47:16 +08:00
|
|
|
|
2018-12-24 18:24:52 +08:00
|
|
|
const offset = horizon ? [5, 0] : [0, -5]
|
2018-12-21 14:47:16 +08:00
|
|
|
|
2018-12-24 14:09:25 +08:00
|
|
|
const trueOffset = valueTextOffset || offset
|
2018-12-21 14:47:16 +08:00
|
|
|
|
2018-12-24 14:09:25 +08:00
|
|
|
ctx.font = `${valueTextFontSize || defaultValueFontSize}px Arial`
|
2018-12-21 14:47:16 +08:00
|
|
|
|
2018-12-24 14:09:25 +08:00
|
|
|
ctx.textAlign = horizon ? 'left' : 'center'
|
|
|
|
ctx.textBaseline = horizon ? 'middle' : 'bottom'
|
2018-12-21 14:47:16 +08:00
|
|
|
|
2018-12-25 15:54:36 +08:00
|
|
|
const { drawSeriesTextValue } = this
|
2018-12-21 14:47:16 +08:00
|
|
|
|
2019-01-16 16:56:11 +08:00
|
|
|
series.forEach((seriesItem, i) => drawSeriesTextValue(seriesItem, i, trueOffset))
|
2018-12-25 15:54:36 +08:00
|
|
|
},
|
2019-01-16 16:56:11 +08:00
|
|
|
drawSeriesTextValue ({ value, valueTextColor, fillColor, lineColor }, i, trueOffset) {
|
2018-12-25 15:54:36 +08:00
|
|
|
const { ctx, valuePointPos, columnItemOffset, drawTexts, getOffsetPoints, drawColors } = this
|
2018-12-23 19:06:42 +08:00
|
|
|
|
2018-12-25 15:54:36 +08:00
|
|
|
const { data: { valueTextColor: outerValueTC }, defaultValueColor } = this
|
|
|
|
|
|
|
|
const drawColorsNum = drawColors.length
|
|
|
|
|
|
|
|
let currentColor = valueTextColor
|
|
|
|
currentColor === 'inherit' && (currentColor = fillColor || lineColor || drawColors[i % drawColorsNum])
|
|
|
|
const mulColor = currentColor instanceof Array
|
|
|
|
const colorNum = mulColor ? currentColor.length : 0
|
|
|
|
|
|
|
|
const currentPos = valuePointPos[i]
|
|
|
|
const currentOffset = columnItemOffset[i]
|
|
|
|
|
2019-01-16 16:56:11 +08:00
|
|
|
const mulSeries = value[0] instanceof Array
|
2018-12-25 15:54:36 +08:00
|
|
|
|
|
|
|
if (mulSeries) {
|
2019-01-16 16:56:11 +08:00
|
|
|
value.forEach((item, j) => {
|
2018-12-25 15:54:36 +08:00
|
|
|
const pointPos = getOffsetPoints(currentPos[j], currentOffset)
|
|
|
|
|
|
|
|
item.forEach((v, l) => {
|
|
|
|
!currentColor && (ctx.fillStyle = defaultValueColor)
|
|
|
|
currentColor && (ctx.fillStyle = mulColor ? currentColor[l % colorNum] : currentColor)
|
|
|
|
drawTexts(ctx, [item[l]], [pointPos[l]], trueOffset)
|
|
|
|
})
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!mulSeries) {
|
|
|
|
mulColor && (currentColor = currentColor[0])
|
|
|
|
|
|
|
|
ctx.fillStyle = currentColor || outerValueTC || defaultValueColor
|
2019-01-16 16:56:11 +08:00
|
|
|
drawTexts(ctx, value, getOffsetPoints(currentPos, currentOffset), trueOffset)
|
2018-12-25 15:54:36 +08:00
|
|
|
}
|
2018-12-24 14:09:25 +08:00
|
|
|
},
|
|
|
|
drawTexts (ctx, values, points, [x, y] = [0, 0]) {
|
|
|
|
values.forEach((v, i) => {
|
|
|
|
if (!v && v !== 0) return
|
2018-12-23 19:06:42 +08:00
|
|
|
|
2018-12-24 14:09:25 +08:00
|
|
|
ctx.fillText(v, points[i][0] + x, points[i][1] + y)
|
|
|
|
})
|
|
|
|
},
|
|
|
|
drawCenterOriginTypeColumnChart () {}
|
2018-12-20 18:25:19 +08:00
|
|
|
},
|
|
|
|
mounted () {
|
|
|
|
const { init } = this
|
|
|
|
|
|
|
|
init()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
</script>
|
|
|
|
|
|
|
|
<style lang="less">
|
|
|
|
.column-chart {
|
|
|
|
position: relative;
|
|
|
|
display: flex;
|
|
|
|
flex-direction: column;
|
|
|
|
|
|
|
|
.canvas-container {
|
|
|
|
flex: 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
canvas {
|
|
|
|
width: 100%;
|
|
|
|
height: 100%;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
</style>
|