Skip to content

Commit 15b9ebd

Browse files
committed
feat: echart config
1 parent ca052fa commit 15b9ebd

1 file changed

Lines changed: 126 additions & 51 deletions

File tree

  • src/components/stateless/EChartsCommon

src/components/stateless/EChartsCommon/index.tsx

Lines changed: 126 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ const state = {
1515
height: '100%',
1616
}
1717

18+
// 注册地图数据
1819
echarts.registerMap('china', china as unknown as GeoJSONCompressed)
1920

2021
const EChartsCommon = (props: {
@@ -26,77 +27,151 @@ const EChartsCommon = (props: {
2627
}) => {
2728
const drawDomRef = useRef<HTMLDivElement>(null)
2829
const chartRef = useRef<EChartsType | null>(null)
30+
const isInitializedRef = useRef(false)
31+
const resizeObserverRef = useRef<ResizeObserver | null>(null)
2932

30-
const dispose = () => {
31-
if (!chartRef.current) {
32-
return
33+
// 安全地销毁图表实例
34+
const dispose = useCallback(() => {
35+
if (chartRef.current) {
36+
try {
37+
chartRef.current.dispose()
38+
} catch (error) {
39+
console.error('ECharts dispose error:', error)
40+
}
41+
chartRef.current = null
42+
isInitializedRef.current = false
43+
}
44+
}, [])
45+
46+
// 使用 ResizeObserver 替代 window.resize 事件
47+
const setupResizeObserver = useCallback(() => {
48+
if (!drawDomRef.current || !chartRef.current) return
49+
50+
// 清理旧的观察者
51+
if (resizeObserverRef.current) {
52+
resizeObserverRef.current.disconnect()
3353
}
34-
chartRef.current.dispose()
35-
chartRef.current = null
36-
}
3754

38-
const resize = debounce(() => {
39-
chartRef?.current?.resize()
40-
}, 100)
55+
// 创建新的观察者
56+
resizeObserverRef.current = new ResizeObserver(
57+
debounce(() => {
58+
if (chartRef.current) {
59+
try {
60+
chartRef.current.resize()
61+
} catch (error) {
62+
console.error('ECharts resize error:', error)
63+
}
64+
}
65+
}, 100)
66+
)
4167

68+
resizeObserverRef.current.observe(drawDomRef.current)
69+
}, [])
70+
71+
// 安全地设置图表配置
4272
const setOption = useCallback(
4373
(option: OptionType) => {
4474
if (!chartRef.current) {
75+
console.warn('ECharts instance is not available')
4576
return
4677
}
47-
const { notMerge } = props
48-
const { lazyUpdate } = props
49-
chartRef.current.setOption(option, notMerge, lazyUpdate)
78+
79+
try {
80+
const { notMerge = false, lazyUpdate = false } = props
81+
chartRef.current.setOption(option, notMerge, lazyUpdate)
82+
} catch (error) {
83+
console.error('ECharts setOption error:', error)
84+
// 尝试重新初始化图表
85+
dispose()
86+
initChart(drawDomRef.current)
87+
}
88+
},
89+
[props.notMerge, props.lazyUpdate, dispose]
90+
)
91+
92+
// 初始化图表
93+
const initChart = useCallback(
94+
(dom: HTMLDivElement | null) => {
95+
if (!dom || chartRef.current) return
96+
97+
try {
98+
// 确保 DOM 元素有尺寸
99+
if (dom.clientWidth === 0 || dom.clientHeight === 0) {
100+
console.warn('Chart container has zero size, delaying initialization')
101+
return
102+
}
103+
104+
const renderer = props.renderer || 'canvas'
105+
chartRef.current = echarts.init(dom, null, {
106+
renderer,
107+
width: 'auto',
108+
height: 'auto',
109+
})
110+
111+
isInitializedRef.current = true
112+
113+
// 执行初始化回调
114+
if (props.instanceHandle) {
115+
props.instanceHandle(chartRef.current)
116+
}
117+
118+
// 设置初始配置
119+
setOption(props.option)
120+
121+
// 设置尺寸观察
122+
setupResizeObserver()
123+
} catch (error) {
124+
console.error('ECharts initialization error:', error)
125+
chartRef.current = null
126+
isInitializedRef.current = false
127+
}
50128
},
51-
// eslint-disable-next-line react-hooks/exhaustive-deps
52-
[props.notMerge, props.lazyUpdate]
129+
[props, setOption, setupResizeObserver]
53130
)
54131

55-
// 初始化组件
56-
const initChart = (dom: HTMLDivElement | null) => {
57-
if (chartRef.current) return
58-
if (!dom) return
59-
// renderer 用于配置渲染方式 可以是 svg 或者 canvas
60-
const renderer = props.renderer || 'canvas'
61-
chartRef.current = echarts.init(dom, null, {
62-
renderer,
63-
width: 'auto',
64-
height: 'auto',
65-
})
66-
// 执行初始化的任务,例如注册地图
67-
if (props.instanceHandle) props.instanceHandle(chartRef.current)
68-
setOption(props.option)
69-
// 监听屏幕缩放,重新绘制 echart 图表
70-
window.addEventListener('resize', resize)
71-
}
72-
73-
const initHandle = () => {
74-
// 还没实例走初始化
75-
if (!chartRef.current) {
132+
// 处理图表初始化或更新
133+
const initHandle = useCallback(() => {
134+
if (!chartRef.current || !isInitializedRef.current) {
76135
initChart(drawDomRef.current)
77136
} else {
78137
setOption(props.option)
79138
}
80-
}
81-
82-
useEffect(
83-
() =>
84-
// 组件卸载
85-
() => {
86-
window.removeEventListener('resize', resize)
87-
dispose()
88-
},
89-
// eslint-disable-next-line react-hooks/exhaustive-deps
90-
[]
91-
)
139+
}, [initChart, setOption, props.option])
92140

93-
// 每次更新组件都重置
141+
// 组件挂载和卸载
94142
useEffect(() => {
95143
initHandle()
96-
// eslint-disable-next-line react-hooks/exhaustive-deps
97-
}, [props.option])
98144

99-
return <div className="default-chart" ref={drawDomRef} style={{ width: state.width, height: state.height }} />
145+
return () => {
146+
// 清理 ResizeObserver
147+
if (resizeObserverRef.current) {
148+
resizeObserverRef.current.disconnect()
149+
resizeObserverRef.current = null
150+
}
151+
152+
// 销毁图表实例
153+
dispose()
154+
}
155+
}, [initHandle, dispose])
156+
157+
// 当 option 变化时更新图表
158+
useEffect(() => {
159+
if (isInitializedRef.current) {
160+
setOption(props.option)
161+
}
162+
}, [props.option, setOption])
163+
164+
return (
165+
<div
166+
className="default-chart"
167+
ref={drawDomRef}
168+
style={{
169+
width: state.width,
170+
height: state.height,
171+
minHeight: '200px', // 确保容器有最小高度
172+
}}
173+
/>
174+
)
100175
}
101176

102177
export default EChartsCommon

0 commit comments

Comments
 (0)