useECharts.ts 3.2 KB

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