import type { Ref } from "vue"; import type { EChartsOption } from "echarts"; import * as echarts from "echarts"; import { unref, nextTick, watch, computed, ref } from "vue"; import { tryOnUnmounted, useDebounceFn, useEventListener } from "@vueuse/core"; export function useEcharts( elRef: Ref, theme: "default" | "dark" | "light" = "default" ) { let chartInstance: echarts.ECharts | null = null; let resizeFn: () => void = resize; const cacheOptions = ref({}); let removeResizeFn: () => void; const getOptions = computed(() => { return cacheOptions.value; }); resizeFn = useDebounceFn(resize, 200); function resize() { chartInstance?.resize({ animation: { duration: 300, easing: "quadraticIn", }, }); } function initCharts(t = theme) { const el = unref(elRef); if (!el || !unref(el)) { return; } chartInstance = echarts.init(el, t); const removeEvent = useEventListener(window, "resize", resizeFn); removeResizeFn = removeEvent; } function setOptions(options: EChartsOption, clear = false) { cacheOptions.value = options; return new Promise((resolve) => { if (unref(elRef)?.offsetHeight === 0) { setTimeout(() => { setOptions(unref(getOptions)); resolve(null); }, 30); } nextTick(() => { setTimeout(() => { if (!chartInstance) { initCharts("default"); if (!chartInstance) return; } clear && chartInstance?.clear(); chartInstance?.setOption(unref(getOptions)); resolve(null); }, 30); }); }); } watch( () => theme, (theme) => { if (chartInstance) { chartInstance.dispose(); initCharts(theme as "default"); setOptions(cacheOptions.value); } } ); tryOnUnmounted(() => { if (!chartInstance) return; removeResizeFn(); chartInstance.dispose(); chartInstance = null; }); function getInstance(): echarts.ECharts | null { if (!chartInstance) { initCharts("default"); } return chartInstance; } return { setOptions, resize, echarts, getInstance, }; }