useECharts.ts 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. import type { EChartsOption } from 'echarts';
  2. import type { Ref } from 'vue';
  3. import { useTimeoutFn } from '@/hooks/core/useTimeout';
  4. import { tryOnUnmounted } from '@vueuse/core';
  5. import { unref, nextTick, watch, computed, ref } from 'vue';
  6. import { useDebounceFn } from '@vueuse/core';
  7. import { useEventListener } from '@/hooks/event/useEventListener';
  8. import { useBreakpoint } from '@/hooks/event/useBreakpoint';
  9. import echarts from '@/utils/lib/echarts';
  10. import { useDesignSetting } from '@/hooks/setting/useDesignSetting';
  11. import { useProjectSetting } from '@/hooks/setting/useProjectSetting';
  12. export function useECharts(
  13. elRef: Ref<HTMLDivElement>,
  14. theme: 'light' | 'dark' | 'default' = 'light',
  15. ) {
  16. const { getDarkTheme } = useDesignSetting();
  17. const { getMenuSetting } = useProjectSetting();
  18. const getDarkMode = computed(() => {
  19. const appTheme = getDarkTheme.value ? 'dark' : 'light';
  20. return theme === 'default' ? appTheme : theme;
  21. });
  22. let chartInstance: echarts.ECharts | null = null;
  23. let resizeFn: Fn = resize;
  24. const cacheOptions = ref({}) as Ref<EChartsOption>;
  25. let removeResizeFn: Fn = () => {};
  26. resizeFn = useDebounceFn(resize, 200);
  27. const getOptions = computed((): EChartsOption => {
  28. if (getDarkMode.value !== 'dark') {
  29. return cacheOptions.value as EChartsOption;
  30. }
  31. return {
  32. backgroundColor: 'transparent',
  33. ...cacheOptions.value,
  34. } as EChartsOption;
  35. });
  36. function initCharts(t = theme) {
  37. const el = unref(elRef);
  38. if (!el || !unref(el)) {
  39. return;
  40. }
  41. chartInstance = echarts.init(el, t);
  42. const { removeEvent } = useEventListener({
  43. el: window,
  44. name: 'resize',
  45. listener: resizeFn,
  46. });
  47. removeResizeFn = removeEvent;
  48. const { widthRef, screenEnum } = useBreakpoint();
  49. if (unref(widthRef) <= screenEnum.MD || el.offsetHeight === 0) {
  50. useTimeoutFn(() => {
  51. resizeFn();
  52. }, 30);
  53. }
  54. }
  55. function setOptions(options: EChartsOption, clear = true) {
  56. cacheOptions.value = options;
  57. return new Promise((resolve) => {
  58. if (unref(elRef)?.offsetHeight === 0) {
  59. useTimeoutFn(() => {
  60. setOptions(unref(getOptions));
  61. resolve(null);
  62. }, 30);
  63. }
  64. nextTick(() => {
  65. useTimeoutFn(() => {
  66. if (!chartInstance) {
  67. initCharts(getDarkMode.value as 'default');
  68. if (!chartInstance) return;
  69. }
  70. clear && chartInstance?.clear();
  71. chartInstance?.setOption(unref(getOptions));
  72. resolve(null);
  73. }, 30);
  74. });
  75. });
  76. }
  77. function resize() {
  78. chartInstance?.resize();
  79. }
  80. watch(
  81. () => getDarkMode.value,
  82. (theme) => {
  83. if (chartInstance) {
  84. chartInstance.dispose();
  85. initCharts(theme as 'default');
  86. setOptions(cacheOptions.value);
  87. }
  88. },
  89. );
  90. tryOnUnmounted(() => {
  91. if (!chartInstance) return;
  92. removeResizeFn();
  93. chartInstance.dispose();
  94. chartInstance = null;
  95. });
  96. function getInstance(): echarts.ECharts | null {
  97. if (!chartInstance) {
  98. initCharts(getDarkMode.value as 'default');
  99. }
  100. return chartInstance;
  101. }
  102. watch(getMenuSetting.value, (_) => {
  103. useTimeoutFn(() => {
  104. resizeFn();
  105. }, 300);
  106. });
  107. return {
  108. setOptions,
  109. resize,
  110. echarts,
  111. getInstance,
  112. };
  113. }