<!-- 柱状图 -->
|
<template>
|
<div ref="chartRef" :style="{ height: props.height }" v-loading="props.loading"> </div>
|
</template>
|
|
<script setup>
|
import { useChartOps, useChartComponent } from '@/hooks/core/useChart'
|
import { getCssVar } from '@/utils/ui'
|
import { graphic } from '@/plugins/echarts'
|
defineOptions({ name: 'ArtBarChart' })
|
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 },
|
borderRadius: { required: false, default: 4 },
|
data: { required: false, default: () => [0, 0, 0, 0, 0, 0, 0] },
|
xAxisData: { required: false, default: () => [] },
|
barWidth: { required: false, default: '40%' },
|
stack: { required: false, default: false },
|
showAxisLabel: { required: false, default: true },
|
showAxisLine: { required: false, default: true },
|
showSplitLine: { required: false, default: true },
|
showTooltip: { required: false, default: true },
|
showLegend: { required: false, default: false },
|
legendPosition: { required: false, default: 'bottom' }
|
})
|
const isMultipleData = computed(() => {
|
return (
|
Array.isArray(props.data) &&
|
props.data.length > 0 &&
|
typeof props.data[0] === 'object' &&
|
'name' in props.data[0]
|
)
|
})
|
const getColor = (customColor, index) => {
|
if (customColor) return customColor
|
if (index !== void 0) {
|
return props.colors[index % props.colors.length]
|
}
|
return new graphic.LinearGradient(0, 0, 0, 1, [
|
{
|
offset: 0,
|
color: getCssVar('--el-color-primary-light-4')
|
},
|
{
|
offset: 1,
|
color: getCssVar('--el-color-primary')
|
}
|
])
|
}
|
const createGradientColor = (color) => {
|
return new graphic.LinearGradient(0, 0, 0, 1, [
|
{
|
offset: 0,
|
color
|
},
|
{
|
offset: 1,
|
color
|
}
|
])
|
}
|
const getBaseItemStyle = (color) => ({
|
borderRadius: props.borderRadius,
|
color: typeof color === 'string' ? createGradientColor(color) : color
|
})
|
const createSeriesItem = (config) => {
|
const animationConfig = getAnimationConfig()
|
return {
|
name: config.name,
|
data: config.data,
|
type: 'bar',
|
stack: config.stack,
|
itemStyle: getBaseItemStyle(config.color),
|
barWidth: config.barWidth || props.barWidth,
|
...animationConfig
|
}
|
}
|
const {
|
chartRef,
|
getAxisLineStyle,
|
getAxisLabelStyle,
|
getAxisTickStyle,
|
getSplitLineStyle,
|
getAnimationConfig,
|
getTooltipStyle,
|
getLegendStyle,
|
getGridWithLegend
|
} = useChartComponent({
|
props,
|
checkEmpty: () => {
|
if (Array.isArray(props.data) && typeof props.data[0] === 'number') {
|
const singleData = props.data
|
return !singleData.length || singleData.every((val) => val === 0)
|
}
|
if (Array.isArray(props.data) && typeof props.data[0] === 'object') {
|
const multiData = props.data
|
return (
|
!multiData.length ||
|
multiData.every((item) => !item.data?.length || item.data.every((val) => val === 0))
|
)
|
}
|
return true
|
},
|
watchSources: [() => props.data, () => props.xAxisData, () => props.colors],
|
generateOptions: () => {
|
const options = {
|
grid: getGridWithLegend(props.showLegend && isMultipleData.value, props.legendPosition, {
|
top: 15,
|
right: 0,
|
left: 0
|
}),
|
tooltip: props.showTooltip ? getTooltipStyle() : void 0,
|
xAxis: {
|
type: 'category',
|
data: props.xAxisData,
|
axisTick: getAxisTickStyle(),
|
axisLine: getAxisLineStyle(props.showAxisLine),
|
axisLabel: getAxisLabelStyle(props.showAxisLabel)
|
},
|
yAxis: {
|
type: 'value',
|
axisLabel: getAxisLabelStyle(props.showAxisLabel),
|
axisLine: getAxisLineStyle(props.showAxisLine),
|
splitLine: getSplitLineStyle(props.showSplitLine)
|
}
|
}
|
if (props.showLegend && isMultipleData.value) {
|
options.legend = getLegendStyle(props.legendPosition)
|
}
|
if (isMultipleData.value) {
|
const multiData = props.data
|
options.series = multiData.map((item, index) => {
|
const computedColor = getColor(props.colors[index], index)
|
return createSeriesItem({
|
name: item.name,
|
data: item.data,
|
color: computedColor,
|
barWidth: item.barWidth,
|
stack: props.stack ? item.stack || 'total' : void 0
|
})
|
})
|
} else {
|
const singleData = props.data
|
const computedColor = getColor()
|
options.series = [
|
createSeriesItem({
|
data: singleData,
|
color: computedColor
|
})
|
]
|
}
|
return options
|
}
|
})
|
</script>
|