1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
| <!-- 双向堆叠柱状图 -->
| <template>
| <div ref="chartRef" :style="{ height: props.height }" v-loading="props.loading"> </div>
| </template>
|
| <script setup>
| import { useChartOps, useChartComponent } from '@/hooks/core/useChart'
| defineOptions({ name: 'ArtDualBarCompareChart' })
| const props = defineProps({
| height: { required: false, default: useChartOps().chartHeight },
| loading: { required: false, default: false },
| isEmpty: { required: false, default: false },
| colors: { required: false, default: () => useChartOps().colors },
| positiveData: { required: false, default: () => [] },
| negativeData: { required: false, default: () => [] },
| xAxisData: { required: false, default: () => [] },
| positiveName: { required: false, default: '正向数据' },
| negativeName: { required: false, default: '负向数据' },
| barWidth: { required: false, default: 16 },
| yAxisMin: { required: false, default: -100 },
| yAxisMax: { required: false, default: 100 },
| showDataLabel: { required: false, default: false },
| positiveBorderRadius: { required: false, default: () => [10, 10, 0, 0] },
| negativeBorderRadius: { required: false, default: () => [0, 0, 10, 10] },
| showAxisLabel: { required: false, default: true },
| showAxisLine: { required: false, default: false },
| showSplitLine: { required: false, default: false },
| showTooltip: { required: false, default: true },
| showLegend: { required: false, default: false },
| legendPosition: { required: false, default: 'bottom' }
| })
| const createSeriesConfig = (config) => {
| const { fontColor } = useChartOps()
| const animationConfig = getAnimationConfig()
| return {
| name: config.name,
| type: 'bar',
| stack: 'total',
| barWidth: props.barWidth,
| barGap: '-100%',
| data: config.data,
| itemStyle: {
| borderRadius: config.borderRadius,
| color: props.colors[config.colorIndex]
| },
| label: {
| show: props.showDataLabel,
| position: config.labelPosition,
| formatter: config.formatter || ((params) => String(params.value)),
| color: fontColor,
| fontSize: 12
| },
| ...animationConfig
| }
| }
| const {
| chartRef,
| getAxisLineStyle,
| getAxisLabelStyle,
| getAxisTickStyle,
| getSplitLineStyle,
| getAnimationConfig,
| getTooltipStyle,
| getLegendStyle,
| getGridWithLegend
| } = useChartComponent({
| props,
| checkEmpty: () => {
| return (
| props.isEmpty ||
| !props.positiveData.length ||
| !props.negativeData.length ||
| (props.positiveData.every((val) => val === 0) &&
| props.negativeData.every((val) => val === 0))
| )
| },
| watchSources: [
| () => props.positiveData,
| () => props.negativeData,
| () => props.xAxisData,
| () => props.colors
| ],
| generateOptions: () => {
| const processedNegativeData = props.negativeData.map((val) => (val > 0 ? -val : val))
| const gridConfig = {
| top: props.showLegend ? 50 : 20,
| right: 0,
| left: 0,
| bottom: 0,
| // 增加底部间距
| containLabel: true
| }
| const options = {
| backgroundColor: 'transparent',
| animation: true,
| animationDuration: 1e3,
| animationEasing: 'cubicOut',
| grid: getGridWithLegend(props.showLegend, props.legendPosition, gridConfig),
| // 优化的提示框配置
| tooltip: props.showTooltip
| ? {
| ...getTooltipStyle(),
| trigger: 'axis',
| axisPointer: {
| type: 'none'
| // 去除指示线
| }
| }
| : void 0,
| // 图例配置
| legend: props.showLegend
| ? {
| ...getLegendStyle(props.legendPosition),
| data: [props.negativeName, props.positiveName]
| }
| : void 0,
| // X轴配置
| xAxis: {
| type: 'category',
| data: props.xAxisData,
| axisTick: getAxisTickStyle(),
| axisLine: getAxisLineStyle(props.showAxisLine),
| axisLabel: getAxisLabelStyle(props.showAxisLabel),
| boundaryGap: true
| },
| // Y轴配置
| yAxis: {
| type: 'value',
| min: props.yAxisMin,
| max: props.yAxisMax,
| axisLabel: getAxisLabelStyle(props.showAxisLabel),
| axisLine: getAxisLineStyle(props.showAxisLine),
| splitLine: getSplitLineStyle(props.showSplitLine)
| },
| // 系列配置
| series: [
| // 负向数据系列
| createSeriesConfig({
| name: props.negativeName,
| data: processedNegativeData,
| borderRadius: props.negativeBorderRadius,
| labelPosition: 'bottom',
| colorIndex: 1,
| formatter: (params) => String(Math.abs(params.value))
| }),
| // 正向数据系列
| createSeriesConfig({
| name: props.positiveName,
| data: props.positiveData,
| borderRadius: props.positiveBorderRadius,
| labelPosition: 'top',
| colorIndex: 0
| })
| ]
| }
| return options
| }
| })
| </script>
|
|