192 lines
4.8 KiB
JavaScript
192 lines
4.8 KiB
JavaScript
import { unref, nextTick, watch, computed, ref } from 'vue';
|
|
import { useDebounceFn, tryOnUnmounted } from '@vueuse/core';
|
|
import { useTimeoutFn } from './useTimeout';
|
|
import { useEventListener } from './useEventListener';
|
|
import { useBreakpoint } from './useBreakpoint';
|
|
import echarts from '../utils/echarts';
|
|
|
|
export const useEcharts = (elRef, theme = 'default') => {
|
|
// 新增轮播相关状态
|
|
const autoPlayTimer = ref(null);
|
|
const currentIndex = ref(-1);
|
|
const dataLength = ref(0);
|
|
|
|
// 新增方法 - 启动轮播
|
|
const startAutoPlay = (options = {}) => {
|
|
const {
|
|
interval = 2000, // 轮播间隔(ms)
|
|
seriesIndex = 0, // 默认操作第一个系列
|
|
showTooltip = true, // 是否显示提示框
|
|
} = options;
|
|
|
|
stopAutoPlay(); // 先停止已有轮播
|
|
|
|
// 获取数据长度
|
|
const seriesData = unref(getOptions).series?.[seriesIndex]?.data;
|
|
dataLength.value = seriesData?.length || 0;
|
|
if (dataLength.value === 0) return;
|
|
|
|
autoPlayTimer.value = setInterval(() => {
|
|
currentIndex.value = (currentIndex.value + 1) % dataLength.value;
|
|
|
|
// 执行轮播动作
|
|
chartInstance?.dispatchAction({
|
|
type: 'downplay',
|
|
seriesIndex: seriesIndex,
|
|
});
|
|
chartInstance?.dispatchAction({
|
|
type: 'highlight',
|
|
seriesIndex: seriesIndex,
|
|
dataIndex: currentIndex.value,
|
|
});
|
|
if (showTooltip) {
|
|
chartInstance?.dispatchAction({
|
|
type: 'showTip',
|
|
seriesIndex: seriesIndex,
|
|
dataIndex: currentIndex.value,
|
|
});
|
|
}
|
|
}, interval);
|
|
};
|
|
|
|
// 新增方法 - 停止轮播
|
|
const stopAutoPlay = () => {
|
|
if (autoPlayTimer.value) {
|
|
clearInterval(autoPlayTimer.value);
|
|
autoPlayTimer.value = null;
|
|
}
|
|
};
|
|
|
|
const getDarkMode = computed(() => {
|
|
return theme === 'default' ? 'dark' : theme;
|
|
});
|
|
let chartInstance = null;
|
|
let resizeFn = resize;
|
|
const cacheOptions = ref({});
|
|
let removeResizeFn = null;
|
|
|
|
resizeFn = useDebounceFn(resize, 200);
|
|
|
|
const getOptions = computed(() => {
|
|
if (getDarkMode.value !== 'dark') {
|
|
return cacheOptions.value;
|
|
}
|
|
return {
|
|
backgroundColor: 'transparent',
|
|
...cacheOptions.value,
|
|
};
|
|
});
|
|
|
|
function initCharts(t = theme) {
|
|
const el = unref(elRef);
|
|
if (!el || !unref(el)) {
|
|
return;
|
|
}
|
|
nextTick(() => {
|
|
if (el.offsetWidth === 0 || el.offsetHeight === 0) {
|
|
console.warn('图表容器不可见,延迟初始化');
|
|
useTimeoutFn(() => initCharts(t), 100);
|
|
return;
|
|
}
|
|
|
|
chartInstance = echarts.init(el, t);
|
|
const { removeEvent } = useEventListener({
|
|
el: window,
|
|
name: 'resize',
|
|
listener: resizeFn,
|
|
});
|
|
removeResizeFn = removeEvent;
|
|
const { widthRef } = useBreakpoint();
|
|
if (unref(widthRef) <= 768 || el.offsetHeight === 0) {
|
|
useTimeoutFn(() => {
|
|
resizeFn();
|
|
}, 30);
|
|
}
|
|
});
|
|
}
|
|
|
|
function setOptions(options = {}, clear = true) {
|
|
const mergedOptions = {
|
|
animation: true,
|
|
animationDuration: 3000,
|
|
animationEasing: 'cubicOut',
|
|
...unref(options),
|
|
animationThreshold: 2000, // 数据量超过2000自动关闭动画
|
|
animationDelayUpdate: (idx) => idx * 50, // 数据项延迟
|
|
};
|
|
cacheOptions.value = mergedOptions;
|
|
cacheOptions.value = options;
|
|
if (unref(elRef)?.offsetHeight === 0) {
|
|
useTimeoutFn(() => {
|
|
setOptions(unref(getOptions));
|
|
}, 30);
|
|
return;
|
|
}
|
|
nextTick(() => {
|
|
useTimeoutFn(() => {
|
|
if (!chartInstance) {
|
|
initCharts(getDarkMode.value ?? 'default');
|
|
|
|
if (!chartInstance) return;
|
|
}
|
|
clear && chartInstance?.clear();
|
|
|
|
chartInstance?.setOption(unref(getOptions));
|
|
}, 30);
|
|
});
|
|
}
|
|
|
|
function resize() {
|
|
chartInstance?.resize();
|
|
}
|
|
|
|
/**
|
|
* 注册地图数据
|
|
* @param {string} mapName - 地图名称
|
|
* @param {object} geoJSON - GeoJSON 数据
|
|
*/
|
|
function registerMap(mapName, geoJSON) {
|
|
if (!mapName || !geoJSON) {
|
|
console.warn('地图名称或 GeoJSON 数据无效');
|
|
return;
|
|
}
|
|
echarts.registerMap(mapName, geoJSON);
|
|
}
|
|
|
|
watch(
|
|
() => getDarkMode.value,
|
|
(theme) => {
|
|
if (chartInstance) {
|
|
chartInstance.dispose();
|
|
initCharts(theme);
|
|
setOptions(cacheOptions.value);
|
|
}
|
|
}
|
|
);
|
|
|
|
tryOnUnmounted(() => {
|
|
stopAutoPlay(); // 清理定时器
|
|
if (!chartInstance) return;
|
|
removeResizeFn();
|
|
chartInstance.dispose();
|
|
chartInstance = null;
|
|
});
|
|
|
|
function getInstance() {
|
|
if (!chartInstance) {
|
|
initCharts(getDarkMode.value ?? 'default');
|
|
}
|
|
return chartInstance;
|
|
}
|
|
|
|
return {
|
|
setOptions,
|
|
resize,
|
|
echarts,
|
|
getInstance: () => chartInstance,
|
|
registerMap,
|
|
startAutoPlay, // 暴露轮播方法
|
|
stopAutoPlay,
|
|
};
|
|
};
|