<template>
|
<div ref="chartRef" :style="{ width, height }" />
|
</template>
|
|
<script lang="ts" setup>
|
import { ref, onMounted, onBeforeUnmount, watch } from 'vue';
|
import * as echarts from 'echarts/core';
|
import { BarChart, LineChart, PieChart } from 'echarts/charts';
|
import {
|
TitleComponent,
|
TooltipComponent,
|
GridComponent,
|
DatasetComponent,
|
TransformComponent,
|
LegendComponent,
|
} from 'echarts/components';
|
import { LabelLayout, UniversalTransition } from 'echarts/features';
|
import { CanvasRenderer } from 'echarts/renderers';
|
import type { ChartProps } from './types';
|
import { defaultChartConfig } from './config'
|
import { processNumberFormat } from './utils';
|
import { cloneDeep } from 'lodash-es';
|
|
// 按需注册必要的组件
|
echarts.use([
|
BarChart,
|
LineChart,
|
PieChart,
|
TitleComponent,
|
TooltipComponent,
|
GridComponent,
|
DatasetComponent,
|
TransformComponent,
|
LabelLayout,
|
UniversalTransition,
|
CanvasRenderer,
|
LegendComponent,
|
]);
|
|
const props = defineProps<ChartProps>();
|
|
const emit = defineEmits<{
|
chartReady: [instance: echarts.ECharts];
|
}>();
|
|
const chartRef = ref<HTMLElement>();
|
let chartInstance: echarts.ECharts | null = null;
|
|
// 初始化图表
|
const initChart = () => {
|
if (!chartRef.value) return;
|
|
try {
|
chartInstance = echarts.init(chartRef.value, props.theme);
|
|
// 先应用默认配置
|
if (Object.keys(defaultChartConfig).length > 0) {
|
chartInstance.setOption(defaultChartConfig);
|
}
|
|
// 再应用用户配置
|
let finalOptions = cloneDeep(props.options);
|
if (props.extendedConfig?.enableNumberFormat) {
|
finalOptions = processNumberFormat(finalOptions);
|
}
|
|
chartInstance.setOption(finalOptions, { notMerge: false });
|
emit('chartReady', chartInstance);
|
} catch (error) {
|
console.error('Chart initialization failed:', error);
|
}
|
};
|
|
// 监听options变化
|
watch(
|
() => props.options,
|
(newVal) => {
|
if (!chartInstance) return;
|
|
try {
|
let finalOptions = cloneDeep(newVal);
|
if (props.extendedConfig?.enableNumberFormat) {
|
finalOptions = processNumberFormat(finalOptions);
|
}
|
|
chartInstance.setOption(finalOptions, {
|
notMerge: false,
|
lazyUpdate: true
|
});
|
} catch (error) {
|
console.error('Chart update failed:', error);
|
}
|
},
|
{ deep: true }
|
);
|
|
// 监听主题变化
|
watch(
|
() => props.theme,
|
() => {
|
if (chartInstance) {
|
chartInstance.dispose();
|
initChart();
|
}
|
}
|
);
|
|
// 处理窗口大小变化
|
const handleResize = () => {
|
chartInstance?.resize();
|
};
|
|
onMounted(() => {
|
initChart();
|
window.addEventListener('resize', handleResize);
|
});
|
|
onBeforeUnmount(() => {
|
if (chartInstance) {
|
chartInstance.dispose();
|
chartInstance = null;
|
}
|
window.removeEventListener('resize', handleResize);
|
});
|
</script>
|