/** * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import { BarSeriesOption, LineSeriesOption, HeatmapSeriesOption, PieSeriesOption, SankeySeriesOption, } from "echarts/charts"; import { TitleComponentOption, TooltipComponentOption, GridComponentOption, DatasetComponentOption, LegendComponentOption, } from "echarts/components"; import type { Ref } from "vue"; import { useTimeoutFn } from "./useTimeout"; import { tryOnUnmounted } from "@vueuse/core"; import { unref, nextTick, watch, computed, ref } from "vue"; import { useDebounceFn } from "@vueuse/core"; import { useEventListener } from "./useEventListener"; import { useBreakpoint } from "./useBreakpoint"; import echarts from "@/utils/echarts"; export type ECOption = echarts.ComposeOption< | BarSeriesOption | LineSeriesOption | TitleComponentOption | TooltipComponentOption | GridComponentOption | DatasetComponentOption | LegendComponentOption | HeatmapSeriesOption | PieSeriesOption | SankeySeriesOption >; export function useECharts( elRef: Ref, theme: "light" | "dark" | "default" = "default" ): any { const getDarkMode = computed(() => { return theme === "default" ? "light" : theme; }); let chartInstance: Nullable = null; let resizeFn: Fn = resize; const cacheOptions = ref({}) as Ref; let removeResizeFn: Fn = () => ({}); resizeFn = useDebounceFn(resize, 200); const getOptions = computed(() => { if (getDarkMode.value !== "dark") { return cacheOptions.value as ECOption; } return { backgroundColor: "transparent", ...cacheOptions.value, } as ECOption; }); function initCharts(t = theme) { const el = unref(elRef); if (!el || !unref(el)) { return; } const { width, height } = el.getBoundingClientRect(); if (!width || !height) { return; } chartInstance = echarts.init(el, t); const { removeEvent } = useEventListener({ el: window, name: "resize", listener: resizeFn, }); removeResizeFn = removeEvent; const { widthRef, screenEnum } = useBreakpoint(); if (unref(widthRef) <= screenEnum.MD || el.offsetHeight === 0) { useTimeoutFn(() => { resizeFn(); }, 30); } } function setOptions(options: ECOption, clear = true) { cacheOptions.value = options; if (unref(elRef)?.offsetHeight === 0) { useTimeoutFn(() => { setOptions(unref(getOptions)); }, 30); return; } nextTick(() => { useTimeoutFn(() => { if (!chartInstance) { initCharts(getDarkMode.value as "default"); if (!chartInstance) return; } clear && chartInstance?.clear(); chartInstance?.setOption(unref(getOptions)); }, 30); }); } function resize() { chartInstance?.resize(); } watch( () => getDarkMode.value, (theme) => { if (chartInstance) { chartInstance.dispose(); initCharts(theme as "default"); setOptions(cacheOptions.value); } } ); tryOnUnmounted(() => { if (!chartInstance) return; removeResizeFn(); chartInstance.dispose(); chartInstance = null; }); function getInstance(): Nullable { if (!chartInstance) { initCharts(getDarkMode.value as "default"); } return chartInstance; } return { setOptions, resize, echarts, getInstance, }; }