From f8c2ada86938cf17bdbfa9f7bb9be38a8f2e07d3 Mon Sep 17 00:00:00 2001
From: jiaming <743192023@qq.com>
Date: Thu, 20 Dec 2018 18:25:49 +0800
Subject: [PATCH] abtract label line component
---
src/components/radarChart/index.vue | 31 +--
src/mixins/axisMixin.js | 305 ++++++++++++++++++++++++++++
src/mixins/canvasMixin.js | 43 ++++
src/mixins/colorsMixin.js | 18 ++
src/plugins/canvasExtend.js | 9 +-
src/plugins/methodsExtend.js | 23 +++
src/views/demo/chart.vue | 46 +++++
7 files changed, 444 insertions(+), 31 deletions(-)
create mode 100644 src/mixins/axisMixin.js
create mode 100644 src/mixins/canvasMixin.js
create mode 100644 src/mixins/colorsMixin.js
diff --git a/src/components/radarChart/index.vue b/src/components/radarChart/index.vue
index 92b08c2..56bb58c 100644
--- a/src/components/radarChart/index.vue
+++ b/src/components/radarChart/index.vue
@@ -7,14 +7,7 @@
-
+
@@ -539,27 +532,5 @@ export default {
width: 100%;
height: 100%;
}
-
- .label-line {
- display: flex;
- flex-direction: row;
- flex-wrap: wrap;
- justify-content: center;
- font-size: 10px;
-
- .label-item {
- height: 20px;
- display: flex;
- flex-direction: row;
- align-items: center;
- margin: 0px 5px 5px 5px;
-
- :nth-child(1) {
- width: 10px;
- height: 10px;
- margin-right: 5px;
- }
- }
- }
}
diff --git a/src/mixins/axisMixin.js b/src/mixins/axisMixin.js
new file mode 100644
index 0000000..025b46e
--- /dev/null
+++ b/src/mixins/axisMixin.js
@@ -0,0 +1,305 @@
+export default {
+ data () {
+ return {
+ defaultHorizon: false,
+ defaultXAxisFS: 10,
+ defaultYAxisFS: 10,
+ defaultXOffset: 30,
+ defaultRotateAngel: 30,
+
+ defaultXAxisLineColor: 'rgba(255, 255, 255, 0.3)',
+ defaultYAxisLineColor: 'rgba(255, 255, 255, 0.3)',
+
+ horizon: false,
+ // user data's max and min value
+ valueMaxMin: [],
+ // axis's max and min value
+ axisMaxMin: [],
+ // label's max width where x and y Axis
+ labelXYMaxWidth: [],
+ valueAxisTag: [],
+ labelAxisTag: [],
+ xyAxisFS: [],
+ xyAxisUnitWidth: [],
+ axisMargin: [],
+ axisOriginPos: [],
+ axisWH: [],
+ valueTagPos: [],
+ labelTagPos: [],
+ valueTagGap: 0,
+ labelTagGap: 0,
+ xTagColor: '',
+ yTagColor: '',
+ xTagColorMul: false,
+ yTagColorMul: false
+ }
+ },
+ methods: {
+ initAxis () {
+ const { calcMaxMinValue, calcValueAxisTag, calcLabelAxisTag, calcXYAxisFS } = this
+
+ calcMaxMinValue()
+
+ calcValueAxisTag()
+
+ calcLabelAxisTag()
+
+ calcXYAxisFS()
+
+ const { calcXYLabelMaxWidth, calcAxisMargin, calcAxisOriginPos } = this
+
+ calcXYLabelMaxWidth()
+
+ calcAxisMargin()
+
+ calcAxisOriginPos()
+
+ const { calcAxisWH, calcValueTagPos, calcLabelTagPos, calcTagGap, calcTagColor } = this
+
+ calcAxisWH()
+
+ calcValueTagPos()
+
+ calcLabelTagPos()
+
+ calcTagGap()
+
+ calcTagColor()
+ },
+ calcMaxMinValue () {
+ const { data: { data }, multipleSum, filterNull, getArrayMaxMin } = this
+
+ const trueValue = data.map(item =>
+ item.map(v =>
+ v ? (typeof v === 'number' ? v : multipleSum(...filterNull(v))) : false))
+
+ this.valueMaxMin = getArrayMaxMin(trueValue)
+ },
+ calcValueAxisTag () {
+ const { valueMaxMin: [ valueMax, valueMin ], data, defaultHorizon } = this
+
+ const { horizon } = data
+
+ this.horizon = horizon || defaultHorizon
+
+ let { max, min, num, fixed } = data[horizon ? 'x' : 'y']
+
+ let [trueMax, trueMin] = [max, min]
+
+ const thirdValueMinus = parseInt((valueMax - valueMin) / 3)
+
+ !max && (max !== 0) && (trueMax = valueMax + thirdValueMinus)
+ !min && (min !== 0) && (trueMin = valueMin - thirdValueMinus)
+
+ const trueMinus = trueMax - trueMin
+
+ !num && trueMinus < 9 && (num = trueMinus + 1)
+ !num && (num = 10)
+
+ const valueGap = trueMinus / (num - 1)
+
+ const valueAxisTag = this.valueAxisTag = Array(num).fill(0).map((t, i) =>
+ (trueMin + i * valueGap).toFixed(fixed))
+
+ const lastValueAxisTagIndex = valueAxisTag.length - 1
+
+ this.axisMaxMin = [parseFloat(valueAxisTag[lastValueAxisTagIndex]), parseFloat(valueAxisTag[0])]
+ },
+ calcLabelAxisTag () {
+ const { data, horizon } = this
+
+ this.labelAxisTag = data[horizon ? 'y' : 'x'].data
+ },
+ calcXYAxisFS () {
+ const { defaultXAxisFS, defaultYAxisFS } = this
+
+ const { data: { x: { fontSize: xfs }, y: { fontSize: yfs } } } = this
+
+ this.xyAxisFS = [xfs || defaultXAxisFS, yfs || defaultYAxisFS]
+ },
+ calcXYLabelMaxWidth () {
+ const { ctx, valueAxisTag, labelAxisTag, horizon, xyAxisFS } = this
+
+ const { canvas: { getTextsWidth } } = this
+
+ const { data: { x: { unit: xUN }, y: { unit: yUN } } } = this
+
+ ctx.font = `${xyAxisFS[0]}px Arial`
+
+ this.labelXYMaxWidth[0] = Math.max(...getTextsWidth(ctx, horizon ? labelAxisTag : valueAxisTag))
+
+ this.xyAxisUnitWidth[0] = ctx.measureText(xUN || '').width
+
+ ctx.font = `${xyAxisFS[1]}px Arial`
+
+ this.labelXYMaxWidth[1] = Math.max(...getTextsWidth(ctx, horizon ? valueAxisTag : labelAxisTag))
+
+ this.xyAxisUnitWidth[1] = ctx.measureText(yUN || '').width
+ },
+ calcAxisMargin () {
+ const { defaultXOffset, labelXYMaxWidth, data, xyAxisUnitWidth } = this
+
+ const { offset: xOF, unitWidth: xUW } = data.x
+
+ const { offset: yOF, unitHeight: yUH } = data.y
+
+ this.axisMargin[0] = yUH || defaultXOffset
+ this.axisMargin[1] = xUW || xyAxisUnitWidth[0] + 10
+ this.axisMargin[2] = xOF || defaultXOffset
+ this.axisMargin[3] = yOF || labelXYMaxWidth[1] + 10
+ },
+ calcAxisOriginPos () {
+ const { axisMargin, canvasWH } = this
+
+ this.axisOriginPos[0] = axisMargin[3]
+ this.axisOriginPos[1] = canvasWH[1] - axisMargin[2]
+
+ this.ctx.arc(...this.axisOriginPos, 3, 0, Math.PI * 2)
+ },
+ calcAxisWH () {
+ const { axisMargin, canvasWH } = this
+
+ this.axisWH[0] = canvasWH[0] - axisMargin[1] - axisMargin[3]
+ this.axisWH[1] = canvasWH[1] - axisMargin[0] - axisMargin[2]
+ },
+ calcValueTagPos () {
+ const { axisWH, valueAxisTag, horizon, axisOriginPos: [x, y] } = this
+
+ const valueTagNum = valueAxisTag.length
+
+ const gapWidth = (horizon ? axisWH[0] : axisWH[1]) / (valueTagNum - 1)
+
+ this.valueTagPos = new Array(valueTagNum).fill(0).map((t, i) =>
+ horizon ? [x + gapWidth * i, y + 5] : [x - 5, y - gapWidth * i])
+ },
+ calcLabelTagPos () {
+ const { axisWH, labelAxisTag, horizon, axisOriginPos: [x, y], data, axisType } = this
+
+ const { boundaryGap } = data
+
+ const labelNum = labelAxisTag.length
+
+ const gapAllWidth = horizon ? axisWH[1] : axisWH[0]
+
+ const tempArray = new Array(labelNum).fill(0)
+
+ if (axisType === 'column' || (axisType === 'line' && boundaryGap)) {
+ const gapWidth = gapAllWidth / labelNum
+
+ const halfGapWidth = gapWidth / 2
+
+ this.labelTagPos = tempArray.map((t, i) =>
+ horizon ? [x - 5, y - gapWidth * i - halfGapWidth] : [x + gapWidth * i + halfGapWidth, y + 5])
+ }
+
+ if (axisType === 'line' && !boundaryGap) {
+ const gapWidth = gapAllWidth / (labelNum - 1)
+
+ this.labelTagPos = tempArray.map((t, i) =>
+ horizon ? [x - 5, y - gapWidth] : [x + gapWidth * i, y + 5])
+ }
+ },
+ calcTagGap () {
+ const { horizon, valueTagPos, labelTagPos } = this
+
+ const v = horizon ? '0' : '1'
+
+ this.valueTagGap = Math.abs(valueTagPos[0][v] - valueTagPos[1][v])
+
+ const l = horizon ? '1' : '0'
+
+ this.labelTagGap = Math.abs(labelTagPos[0][l] - labelTagPos[1][l])
+ },
+ calcTagColor () {
+ const { defaultXAxisLineColor, defaultYAxisLineColor, drawColors, data } = this
+
+ const { x: { color: xc }, y: { color: yc } } = data
+
+ let xTagColor = xc || defaultXAxisLineColor
+
+ xTagColor === 'colors' && (xTagColor = drawColors)
+
+ let yTagColor = yc || defaultYAxisLineColor
+
+ yTagColor === 'colors' && (yTagColor = drawColors)
+
+ this.xTagColor = xTagColor
+
+ this.xTagColorMul = xTagColor instanceof Array
+
+ this.yTagColor = yTagColor
+
+ this.yTagColorMul = yTagColor instanceof Array
+ },
+ drawAxis () {
+ const { drawAxisLine, drawAxisTag } = this
+
+ drawAxisLine()
+
+ drawAxisTag()
+ },
+ drawAxisLine () {
+ const { ctx, defaultXAxisLineColor, defaultYAxisLineColor, axisOriginPos, axisWH, data } = this
+
+ const { x: { lineColor: xlc }, y: { lineColor: ylc } } = data
+
+ ctx.lineWidth = 1
+
+ ctx.strokeStyle = xlc || defaultXAxisLineColor
+ ctx.beginPath()
+ ctx.moveTo(...axisOriginPos)
+ ctx.lineTo(axisOriginPos[0] + axisWH[0], axisOriginPos[1])
+ ctx.stroke()
+
+ ctx.strokeStyle = ylc || defaultYAxisLineColor
+ ctx.beginPath()
+ ctx.moveTo(...axisOriginPos)
+ ctx.lineTo(axisOriginPos[0], axisOriginPos[1] - axisWH[1])
+
+ ctx.stroke()
+ },
+ drawAxisTag () {
+ const { ctx, horizon, valueTagPos, labelTagPos, valueAxisTag, labelAxisTag } = this
+
+ const { xTagColor, xTagColorMul, yTagColor, yTagColorMul, xyAxisFS } = this
+
+ const xAxisData = horizon ? valueTagPos : labelTagPos
+ const yAxisData = horizon ? labelTagPos : valueTagPos
+
+ const xTagData = horizon ? valueAxisTag : labelAxisTag
+ const yTagData = horizon ? labelAxisTag : valueAxisTag
+
+ !xTagColorMul && (ctx.fillStyle = xTagColor)
+
+ const xTagColorNum = xTagColor.length
+
+ ctx.font = `${xyAxisFS[0]}px Arial`
+
+ ctx.textAlign = 'center'
+ ctx.textBaseline = 'top'
+
+ xAxisData.forEach((pos, i) => {
+ xTagColorMul && (ctx.fillStyle = xTagColor[i % xTagColorNum])
+
+ ctx.fillText(xTagData[i], ...pos)
+ })
+
+ !yTagColorMul && (ctx.fillStyle = yTagColor)
+
+ const yTagColorNum = yTagColor.length
+
+ ctx.font = `${xyAxisFS[1]}px Arial`
+
+ ctx.textAlign = 'right'
+ ctx.textBaseline = 'middle'
+
+ yAxisData.forEach((pos, i) => {
+ xTagColorMul && (ctx.fillStyle = yTagColor[i % yTagColorNum])
+
+ ctx.fillText(yTagData[i], ...pos)
+ })
+
+ this.ctx.fill()
+ }
+ }
+}
diff --git a/src/mixins/canvasMixin.js b/src/mixins/canvasMixin.js
new file mode 100644
index 0000000..c52720c
--- /dev/null
+++ b/src/mixins/canvasMixin.js
@@ -0,0 +1,43 @@
+export default {
+ data () {
+ return {
+ canvasDom: '',
+ canvasWH: [0, 0],
+ ctx: '',
+ centerPos: []
+ }
+ },
+ methods: {
+ initCanvas () {
+ const { $nextTick } = this
+
+ return new Promise(resolve => {
+ $nextTick(e => {
+ const { $refs, ref, labelRef, canvasWH, centerPos } = this
+
+ const canvas = this.canvasDom = $refs[ref]
+
+ this.labelDom = $refs[labelRef]
+
+ canvasWH[0] = canvas.clientWidth
+ canvasWH[1] = canvas.clientHeight
+
+ canvas.setAttribute('width', canvasWH[0])
+ canvas.setAttribute('height', canvasWH[1])
+
+ this.ctx = canvas.getContext('2d')
+
+ centerPos[0] = canvasWH[0] / 2
+ centerPos[1] = canvasWH[1] / 2
+
+ resolve()
+ })
+ })
+ },
+ clearCanvas () {
+ const { ctx, canvasWH } = this
+
+ ctx.clearRect(0, 0, ...canvasWH)
+ }
+ }
+}
diff --git a/src/mixins/colorsMixin.js b/src/mixins/colorsMixin.js
new file mode 100644
index 0000000..b2684f5
--- /dev/null
+++ b/src/mixins/colorsMixin.js
@@ -0,0 +1,18 @@
+import defaultColors from '../config/color.js'
+
+export default {
+ data () {
+ return {
+ defaultColors,
+
+ drawColors: ''
+ }
+ },
+ methods: {
+ initColors () {
+ const { colors, defaultColors } = this
+
+ this.drawColors = colors || defaultColors
+ }
+ }
+}
diff --git a/src/plugins/canvasExtend.js b/src/plugins/canvasExtend.js
index 4f27fad..771075c 100644
--- a/src/plugins/canvasExtend.js
+++ b/src/plugins/canvasExtend.js
@@ -169,6 +169,12 @@ export function getCircleRadianPoint (x, y, radius, radian) {
return [x + cos(radian) * radius, y + sin(radian) * radius]
}
+export function getTextsWidth (ctx, texts) {
+ if (!ctx || !texts) return
+
+ return texts.map(text => ctx.measureText(text).width)
+}
+
const canvas = {
drawLine,
drawPolylinePath,
@@ -180,7 +186,8 @@ const canvas = {
drawPoints,
getLinearGradientColor,
getRadialGradientColor,
- getCircleRadianPoint
+ getCircleRadianPoint,
+ getTextsWidth
}
export default function (Vue) {
diff --git a/src/plugins/methodsExtend.js b/src/plugins/methodsExtend.js
index 07843be..a84ec21 100644
--- a/src/plugins/methodsExtend.js
+++ b/src/plugins/methodsExtend.js
@@ -62,6 +62,26 @@ export function getPointToLineDistance (point, linePointOne, linePointTwo) {
return 0.5 * Math.sqrt((a + b + c) * (a + b - c) * (a + c - b) * (b + c - a)) / c
}
+export function getArrayMaxMin (array) {
+ if (!array) return false
+
+ return [getArrayMax(array), getArrayMin(array)]
+}
+
+export function getArrayMax (array) {
+ if (!array) return false
+
+ return Math.max(...filterNull(array).map(n =>
+ n instanceof Array ? getArrayMax(n) : n))
+}
+
+export function getArrayMin (array) {
+ if (!array) return false
+
+ return Math.min(...filterNull(array).map(n =>
+ n instanceof Array ? getArrayMin(n) : n))
+}
+
export default function (Vue) {
Vue.prototype.deepClone = deepClone
Vue.prototype.deleteArrayAllItems = deleteArrayAllItems
@@ -71,4 +91,7 @@ export default function (Vue) {
Vue.prototype.filterNull = filterNull
Vue.prototype.getPointDistance = getPointDistance
Vue.prototype.getPointToLineDistance = getPointToLineDistance
+ Vue.prototype.getArrayMaxMin = getArrayMaxMin
+ Vue.prototype.getArrayMax = getArrayMax
+ Vue.prototype.getArrayMin = getArrayMin
}
diff --git a/src/views/demo/chart.vue b/src/views/demo/chart.vue
index 2038dfc..9f9aa24 100644
--- a/src/views/demo/chart.vue
+++ b/src/views/demo/chart.vue
@@ -36,6 +36,23 @@ colors: ['#9cf4a7', '#66d7ee', '#eee966', '#a866ee', '#ee8f66', '#ee66aa']
+
+
+
+
+
Column-Chart
+
+<column-chart :data="data" :colors="colors" />
+
+
+
+data: {
+ data: []
+}
+
+
+
+
@@ -483,12 +500,41 @@ export default {
title: 'Attention',
target: 'attention'
},
+ {
+ title: 'Column-Chart',
+ target: 'column-chart'
+ },
{
title: 'Radar-Chart',
target: 'radar-chart'
}
],
+ columnChartData1: {
+ data: [
+ [180, 290, 420, 200, 350, 219],
+ [
+ [45, 32, 66],
+ [122, 49, 218],
+ [40, 129, 216],
+ [45, 66, 45],
+ [110, 120, 201],
+ [23, 40, 12]
+ ]
+ ],
+ x: {
+ data: ['西峡', '周口', '南阳', '驻马店', '郑州', '洛阳']
+ },
+ y: {
+ grid: true,
+ unit: '次',
+ min: 0,
+ max: 600
+ },
+ columnBG: 'rgba(250, 250, 250, 0.2)',
+ roundColumn: true
+ },
+
radarChartData1: {
data: [
{