import { useEffect, useRef, useImperativeHandle } from 'react' import * as echarts from 'echarts' import type { EchartUIProps } from './types' import { useWidgetRef } from '../../hooks' import { observeResize } from './shared-resize-observer' /** * Presentational component that initializes and manages an Apache ECharts instance. * * @remarks * Handles chart lifecycle (init, dispose), option updates, resize observation, and event listener management. * Uses SVG renderer with a default height of 304px. */ export function EchartUI(props: EchartUIProps) { const { id, ref, init, option, className, style, onEvents } = props const { ref: chartRef, instance: chartInstanceRef } = useWidgetRef(id) const chartInstance = useRef(null) useImperativeHandle(ref, () => chartInstance.current!, []) useEffect(() => { if (!chartRef.current) return chartInstance.current = echarts.init(chartRef.current, null, { renderer: 'svg', height: 304, ...init, }) chartInstanceRef.current = chartInstance.current // Cleanup function return () => { chartInstance.current?.dispose() chartInstance.current = null chartInstanceRef.current = null } }, [chartInstanceRef, chartRef, init]) // Update chart when options change useEffect(() => { chartInstance.current?.setOption(option, { lazyUpdate: true, notMerge: true, }) }, [option]) // Handle resize using shared ResizeObserver (single instance for all charts) useEffect(() => { if (!chartRef.current) return return observeResize(chartRef.current, () => { chartInstance.current?.resize() }) }, [chartRef]) useEffect(() => { const _onEvents = { ...(onEvents ?? {}) } if (!_onEvents.click) { _onEvents.mousemove = () => { chartInstance.current?.getZr().setCursorStyle('default') } } // Attach event listeners Object.entries(_onEvents).forEach(([event, handler]) => { chartInstance.current?.on(event, handler) }) // Cleanup function to remove event listeners return () => { Object.entries(_onEvents).forEach(([event]) => { chartInstance.current?.off(event) }) } }, [onEvents]) return
}