useECharts.ts 3.3 KB

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