diff options
| author | Somhairle H. Marisol <[email protected]> | 2026-09-17 14:32:37 +0800 |
|---|---|---|
| committer | Somhairle H. Marisol <[email protected]> | 2026-09-17 14:32:37 +0800 |
| commit | 5c0ba37eda80d39e6ceca59bb1d5f4942f858995 (patch) | |
| tree | 948723f9cedf7ccb0707fa6ee516bd30fe20fd10 /frontend/src/components/Chart.svelte | |
| download | strategy-lab-5c0ba37eda80d39e6ceca59bb1d5f4942f858995.tar.gz | |
chore: establish Strategy Lab source baseline (development, not release)
Diffstat (limited to 'frontend/src/components/Chart.svelte')
| -rw-r--r-- | frontend/src/components/Chart.svelte | 67 |
1 files changed, 67 insertions, 0 deletions
diff --git a/frontend/src/components/Chart.svelte b/frontend/src/components/Chart.svelte new file mode 100644 index 0000000..ca8f4f8 --- /dev/null +++ b/frontend/src/components/Chart.svelte @@ -0,0 +1,67 @@ +<script lang="ts"> + import { onMount, onDestroy } from 'svelte'; + import type * as echartsNS from 'echarts'; + + interface Props { + option: echartsNS.EChartsOption; + height?: number; + ariaLabel?: string; + } + let { option, height = 360, ariaLabel = '图表' }: Props = $props(); + + let host: HTMLDivElement; + let chart: echartsNS.ECharts | null = null; + let observer: ResizeObserver | null = null; + + onMount(async () => { + // ECharts chunk loads lazily when a result/comparison view is opened. + const echarts = (await import('echarts')) as typeof echartsNS; + if (!host) return; + // Pass explicit sizes when the host has no layout yet (jsdom regression + // tests report 0×0 and ECharts warns "Can't get DOM width or height"). + // In a real browser clientWidth/clientHeight are non-zero, so the measured + // size is used exactly as before; responsive resizing still works through + // the ResizeObserver below. + chart = echarts.init(host, undefined, { + renderer: 'svg', + width: host.clientWidth || 640, + height: host.clientHeight || height + }); + observer = new ResizeObserver(() => { + if (!chart) return; + // re-measure on EVERY resize callback and pass the measured size + // explicitly: echarts keeps the width given at init/resize, so a + // desktop->mobile viewport change would otherwise leave the SVG at the + // old width and overflow the page (real, re-verified live bug). + const w = host.clientWidth || undefined; + const h = host.clientHeight || undefined; + if (w === undefined && h === undefined) return; + chart.resize({ width: w, height: h }); + }); + observer.observe(host); + chart?.setOption(option, { notMerge: true }); + }); + + onDestroy(() => { + observer?.disconnect(); + chart?.dispose(); + chart = null; + }); + + $effect(() => { + chart?.setOption(option, { notMerge: true }); + }); +</script> + +<div + bind:this={host} + style="height:{height}px; width:100%; min-width:0;" + role="img" + aria-label={ariaLabel} +></div> + +<style> + div { + display: block; + } +</style> |
