import { DeesElement, property, html, type TemplateResult, } from '@design.estate/dees-element'; import * as domtools from '@design.estate/dees-domtools'; import { DeesServiceLibLoader, type IEchartsBundle, type IEchartsInstance } from '../../services/index.js'; import { getEchartsThemeOptions } from './dees-chart-echarts-theme.js'; import '../00group-layout/dees-tile/dees-tile.js'; /** * Abstract base class for ECharts-based chart components. * Handles library loading, chart lifecycle, resize observation, and theme switching. * Subclasses implement `buildOption()` to define their chart configuration. */ export abstract class DeesChartEchartsBase extends DeesElement { @property() accessor label: string = 'Untitled Chart'; protected chartInstance: IEchartsInstance | null = null; protected echartsBundle: IEchartsBundle | null = null; private resizeObserver: ResizeObserver | null = null; constructor() { super(); domtools.elementBasic.setup(); this.registerGarbageFunction(async () => { if (this.resizeObserver) { this.resizeObserver.disconnect(); this.resizeObserver = null; } if (this.chartInstance) { try { this.chartInstance.dispose(); this.chartInstance = null; } catch (e) { console.error('Error disposing ECharts instance:', e); } } }); } public render(): TemplateResult { return html`
${this.label}
`; } public async firstUpdated() { await this.domtoolsPromise; this.echartsBundle = await DeesServiceLibLoader.getInstance().loadEcharts(); await new Promise(resolve => requestAnimationFrame(resolve)); const chartContainer = this.shadowRoot!.querySelector('.chartContainer') as HTMLDivElement; if (!chartContainer) return; try { this.chartInstance = this.echartsBundle.init(chartContainer); this.updateChart(); this.resizeObserver = new ResizeObserver(() => { this.chartInstance?.resize(); }); this.resizeObserver.observe(chartContainer); } catch (error) { console.error('Failed to initialize ECharts:', error); } } public async updated(changedProperties: Map) { super.updated(changedProperties); if (changedProperties.has('goBright') && this.chartInstance) { this.applyTheme(); } } protected abstract buildOption(): Record; protected updateChart(): void { if (!this.chartInstance) return; const themeOptions = getEchartsThemeOptions(this.goBright); const chartOption = this.buildOption(); // Merge theme defaults with chart-specific options const merged = { ...themeOptions, ...chartOption, textStyle: { ...themeOptions.textStyle, ...(chartOption.textStyle || {}) }, tooltip: { ...themeOptions.tooltip, ...(chartOption.tooltip || {}) }, }; this.chartInstance.setOption(merged, true); } protected applyTheme(): void { this.updateChart(); } public async forceResize(): Promise { this.chartInstance?.resize(); } }