@@ -2,24 +2,22 @@ import type { AppTheme } from '../../utils/types';
2
2
3
3
import * as echarts from 'echarts' ;
4
4
import { cloneDeep , merge } from 'lodash' ;
5
- import React , { useEffect , useImperativeHandle , useRef , useState } from 'react' ;
5
+ import { useEffect , useRef , useState } from 'react' ;
6
6
7
- import { useAsync , useResize , useStorage } from '@react-devui/hooks' ;
7
+ import { useAsync , useResize } from '@react-devui/hooks' ;
8
8
import { getClassName } from '@react-devui/utils' ;
9
9
10
- import { STORAGE_KEY } from '../../config/storage' ;
11
10
import chartTheme from './theme.json' ;
12
11
13
- echarts . registerTheme ( 'light' , chartTheme . light ) ;
14
- echarts . registerTheme ( 'dark' , merge ( cloneDeep ( chartTheme . light ) , chartTheme . dark ) ) ;
15
-
16
- export interface AppChartProps < O extends echarts . EChartsOption > extends Omit < React . HTMLAttributes < HTMLDivElement > , 'children' > {
17
- aOption : O | null ;
12
+ export interface AppChartProps extends Omit < React . HTMLAttributes < HTMLDivElement > , 'children' > {
13
+ aRenderer ?: 'canvas' | 'svg' ;
14
+ onInit : ( instance : echarts . ECharts ) => void ;
18
15
}
19
16
20
- function Chart < O extends echarts . EChartsOption > ( props : AppChartProps < O > , ref : React . ForwardedRef < echarts . ECharts > ) : JSX . Element | null {
17
+ export function AppChart ( props : AppChartProps ) : JSX . Element | null {
21
18
const {
22
- aOption,
19
+ aRenderer = 'canvas' ,
20
+ onInit,
23
21
24
22
...restProps
25
23
} = props ;
@@ -35,41 +33,62 @@ function Chart<O extends echarts.EChartsOption>(props: AppChartProps<O>, ref: Re
35
33
36
34
const async = useAsync ( ) ;
37
35
38
- const themeStorage = useStorage < AppTheme > ( ...STORAGE_KEY . theme ) ;
39
-
40
- const [ instance , setInstance ] = useState < echarts . ECharts | null > ( null ) ;
36
+ const [ theme , setTheme ] = useState < AppTheme | null > ( null ) ;
41
37
42
38
useEffect ( ( ) => {
43
- const instance = containerRef . current ? echarts . init ( containerRef . current , themeStorage . value , { renderer : 'svg' } ) : null ;
44
- setInstance ( instance ) ;
39
+ for ( const theme of [ 'light' , 'dark' ] as const ) {
40
+ if ( document . body . className . includes ( theme ) ) {
41
+ setTheme ( theme ) ;
42
+ break ;
43
+ }
44
+ }
45
+
46
+ const observer = new MutationObserver ( ( ) => {
47
+ setTheme ( document . body . className . includes ( 'dark' ) ? 'dark' : 'light' ) ;
48
+ } ) ;
49
+ observer . observe ( document . body , { attributeFilter : [ 'class' ] } ) ;
50
+
45
51
return ( ) => {
46
- instance ?. dispose ( ) ;
52
+ observer . disconnect ( ) ;
47
53
} ;
48
- } , [ themeStorage . value ] ) ;
54
+ } , [ ] ) ;
49
55
50
56
useEffect ( ( ) => {
51
- if ( instance && aOption ) {
52
- instance . setOption ( aOption ) ;
57
+ if ( containerRef . current && theme ) {
58
+ const instance = echarts . init (
59
+ containerRef . current ,
60
+ JSON . parse (
61
+ JSON . stringify ( theme === 'light' ? chartTheme . light : merge ( cloneDeep ( chartTheme . light ) , chartTheme . dark ) ) . replace (
62
+ / v a r \( ( .+ ?) \) / g,
63
+ ( match , p1 ) => {
64
+ return getComputedStyle ( document . body ) . getPropertyValue ( p1 ) ;
65
+ }
66
+ )
67
+ ) ,
68
+ { renderer : aRenderer }
69
+ ) ;
70
+ onInit ( instance ) ;
71
+ return ( ) => {
72
+ instance . dispose ( ) ;
73
+ } ;
53
74
}
54
- } , [ aOption , instance ] ) ;
75
+ // eslint-disable-next-line react-hooks/exhaustive-deps
76
+ } , [ aRenderer , theme ] ) ;
55
77
56
78
useResize ( elRef , ( ) => {
57
- if ( instance ) {
58
- dataRef . current . clearTid ?.( ) ;
59
- dataRef . current . clearTid = async . setTimeout ( ( ) => {
60
- dataRef . current . clearTid = undefined ;
61
- instance . resize ( { animation : { duration : 200 } } ) ;
62
- } , 100 ) ;
63
- }
79
+ dataRef . current . clearTid ?.( ) ;
80
+ dataRef . current . clearTid = async . setTimeout ( ( ) => {
81
+ dataRef . current . clearTid = undefined ;
82
+ if ( containerRef . current ) {
83
+ const instance = echarts . getInstanceByDom ( containerRef . current ) ;
84
+ instance ?. resize ( { animation : { duration : 200 } } ) ;
85
+ }
86
+ } , 100 ) ;
64
87
} ) ;
65
88
66
- useImperativeHandle < echarts . ECharts | null , echarts . ECharts | null > ( ref , ( ) => instance , [ instance ] ) ;
67
-
68
89
return (
69
90
< div { ...restProps } ref = { elRef } className = { getClassName ( restProps . className , 'app-chart' ) } >
70
91
< div ref = { containerRef } className = "app-chart__container" > </ div >
71
92
</ div >
72
93
) ;
73
94
}
74
-
75
- export const AppChart = React . forwardRef ( Chart ) ;
0 commit comments