import { unref, nextTick, watch, computed, ref, markRaw } 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); let mapClickHandler = null; // 新增方法 - 启动轮播 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 = markRaw(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 handleMapClick(params) { console.info('handleMapClick', params); // 执行注册的回调函数 if (typeof mapClickHandler === 'function') { console.info('mapClickHandler', params); mapClickHandler(params); } } function onMapClick(handler) { mapClickHandler = handler; // 返回解绑方法 return () => { mapClickHandler = null; }; } function setOptions(options = {}, clear = true) { const mergedOptions = { animation: true, animationDuration: 1000, animationEasing: 'cubicOut', ...unref(options), animationThreshold: 2000, // 数据量超过2000自动关闭动画 animationDelayUpdate: (idx) => idx * 50, // 数据项延迟 }; cacheOptions.value = mergedOptions; 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)); // 立即绑定事件 chartInstance.off('click'); chartInstance.on('click', handleMapClick); }, 30); }); } function resize() { chartInstance?.resize(); } /** * 注册地图数据 * @param {string} mapName - 地图名称 * @param {object} geoJSON - GeoJSON 数据 */ function regMap(mapName, geoJSON) { if (!mapName || !geoJSON) { console.warn('地图名称或 GeoJSON 数据无效'); return; } console.info('getMap', echarts.getMap(mapName)); if (!echarts.getMap(mapName)) { echarts.registerMap(mapName, geoJSON, { override: true }); } } watch( () => getDarkMode.value, (theme) => { if (chartInstance) { chartInstance.dispose(); initCharts(theme); setOptions(cacheOptions.value); } } ); tryOnUnmounted(() => { stopAutoPlay(); // 清理定时器 if (!chartInstance) return; if (chartInstance) { chartInstance.off('click', handleMapClick); } removeResizeFn(); chartInstance.dispose(); chartInstance = null; }); function getInstance() { if (!chartInstance) { initCharts(getDarkMode.value ?? 'default'); } return chartInstance; } return { setOptions, resize, echarts, getInstance: () => chartInstance, regMap, startAutoPlay, // 暴露轮播方法 stopAutoPlay, onMapClick, }; };