From 42c7978e82e91d3cf00e2f77f720a3ae820c4683 Mon Sep 17 00:00:00 2001 From: xiejay97 Date: Wed, 5 Jul 2023 19:31:47 +0800 Subject: [PATCH] feat(platform): support `'canvas'` chart --- .../src/app/components/chart/Chart.tsx | 81 ++++++++++++------- .../app/routes/dashboard/echarts/ECharts.tsx | 32 ++++---- 2 files changed, 66 insertions(+), 47 deletions(-) diff --git a/packages/platform/src/app/components/chart/Chart.tsx b/packages/platform/src/app/components/chart/Chart.tsx index dcc7df56..795dd4a5 100644 --- a/packages/platform/src/app/components/chart/Chart.tsx +++ b/packages/platform/src/app/components/chart/Chart.tsx @@ -2,24 +2,22 @@ import type { AppTheme } from '../../utils/types'; import * as echarts from 'echarts'; import { cloneDeep, merge } from 'lodash'; -import React, { useEffect, useImperativeHandle, useRef, useState } from 'react'; +import { useEffect, useRef, useState } from 'react'; -import { useAsync, useResize, useStorage } from '@react-devui/hooks'; +import { useAsync, useResize } from '@react-devui/hooks'; import { getClassName } from '@react-devui/utils'; -import { STORAGE_KEY } from '../../config/storage'; import chartTheme from './theme.json'; -echarts.registerTheme('light', chartTheme.light); -echarts.registerTheme('dark', merge(cloneDeep(chartTheme.light), chartTheme.dark)); - -export interface AppChartProps extends Omit, 'children'> { - aOption: O | null; +export interface AppChartProps extends Omit, 'children'> { + aRenderer?: 'canvas' | 'svg'; + onInit: (instance: echarts.ECharts) => void; } -function Chart(props: AppChartProps, ref: React.ForwardedRef): JSX.Element | null { +export function AppChart(props: AppChartProps): JSX.Element | null { const { - aOption, + aRenderer = 'canvas', + onInit, ...restProps } = props; @@ -35,41 +33,62 @@ function Chart(props: AppChartProps, ref: Re const async = useAsync(); - const themeStorage = useStorage(...STORAGE_KEY.theme); - - const [instance, setInstance] = useState(null); + const [theme, setTheme] = useState(null); useEffect(() => { - const instance = containerRef.current ? echarts.init(containerRef.current, themeStorage.value, { renderer: 'svg' }) : null; - setInstance(instance); + for (const theme of ['light', 'dark'] as const) { + if (document.body.className.includes(theme)) { + setTheme(theme); + break; + } + } + + const observer = new MutationObserver(() => { + setTheme(document.body.className.includes('dark') ? 'dark' : 'light'); + }); + observer.observe(document.body, { attributeFilter: ['class'] }); + return () => { - instance?.dispose(); + observer.disconnect(); }; - }, [themeStorage.value]); + }, []); useEffect(() => { - if (instance && aOption) { - instance.setOption(aOption); + if (containerRef.current && theme) { + const instance = echarts.init( + containerRef.current, + JSON.parse( + JSON.stringify(theme === 'light' ? chartTheme.light : merge(cloneDeep(chartTheme.light), chartTheme.dark)).replace( + /var\((.+?)\)/g, + (match, p1) => { + return getComputedStyle(document.body).getPropertyValue(p1); + } + ) + ), + { renderer: aRenderer } + ); + onInit(instance); + return () => { + instance.dispose(); + }; } - }, [aOption, instance]); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [aRenderer, theme]); useResize(elRef, () => { - if (instance) { - dataRef.current.clearTid?.(); - dataRef.current.clearTid = async.setTimeout(() => { - dataRef.current.clearTid = undefined; - instance.resize({ animation: { duration: 200 } }); - }, 100); - } + dataRef.current.clearTid?.(); + dataRef.current.clearTid = async.setTimeout(() => { + dataRef.current.clearTid = undefined; + if (containerRef.current) { + const instance = echarts.getInstanceByDom(containerRef.current); + instance?.resize({ animation: { duration: 200 } }); + } + }, 100); }); - useImperativeHandle(ref, () => instance, [instance]); - return (
); } - -export const AppChart = React.forwardRef(Chart); diff --git a/packages/platform/src/app/routes/dashboard/echarts/ECharts.tsx b/packages/platform/src/app/routes/dashboard/echarts/ECharts.tsx index 9e24a531..88f4696b 100644 --- a/packages/platform/src/app/routes/dashboard/echarts/ECharts.tsx +++ b/packages/platform/src/app/routes/dashboard/echarts/ECharts.tsx @@ -1,7 +1,5 @@ -import { useState } from 'react'; import { useTranslation } from 'react-i18next'; -import { useMount } from '@react-devui/hooks'; import { DCard } from '@react-devui/ui'; import { AppChart, AppRouteHeader } from '../../../components'; @@ -11,13 +9,8 @@ import { barOptions, lineOptions, nightingaleOptions, pieOptions, scatterOptions import styles from './ECharts.module.scss'; const ECharts = AppRoute(() => { - const [options, setOptions] = useState([]); const { t } = useTranslation(); - useMount(() => { - setOptions([lineOptions, stackedLineOptions, barOptions, stackedBarOptions, pieOptions, nightingaleOptions, scatterOptions]); - }); - return ( <> @@ -31,15 +24,22 @@ const ECharts = AppRoute(() => {
- {options.map((option, index) => ( -
- - - - - -
- ))} + {[lineOptions, stackedLineOptions, barOptions, stackedBarOptions, pieOptions, nightingaleOptions, scatterOptions].map( + (option, index) => ( +
+ + + { + instance.setOption(option); + }} + /> + + +
+ ) + )}