如何基于SvelteKit Store的数据刷新/更新Apache ECharts图表?
问题描述
尝试在SvelteKit中基于Store数据刷新Apache ECharts图表,点击按钮传入简单数据对象也无效。图表可通过onMount正常绘制,但响应式刷新和按钮触发重绘均失败。
组件代码(diagram.svelte)
<script> import * as echarts from "echarts"; import { onMount } from "svelte"; import { dummyStoreObj } from "$lib/stores.js"; export let data; let myChart; let chartDom; let myChart_option; function drawChart() { chartDom = document.getElementById("chartDiv"); myChart = echarts.init(chartDom); myChart_option = { dataset: { dimensions: ["start_time", "bucket", "folder", "name"], source: data, }, xAxis: { type: "time", name: "date/time", nameLocation: "middle", splitLine: { show: true }, }, yAxis: { type: "category", name: "# folder", nameGap: "1", splitLine: { show: true }, }, series: [ { type: "scatter", encode: { x: "start_time", y: "folder", }, }, ], }; myChart_option && myChart.setOption(myChart_option); } const reDrawChart = async () => { console.log("Redraw called"); myChart_option.source = dummyStoreObj.data; myChart.setOption(myChart_option); }; onMount(async () => { drawChart(); }); </script> <div> <button on:click={reDrawChart}>Redraw Chart</button> </div> <div id="chartDiv" /> <style> #chartDiv { height: 200px; width: auto; border: 1px solid #141413; } </style>
Store代码(stores.js)
const dummyStoreObj = { data: [{ start_time: '2023-01-31T07:45:11.286491+01:00', bucket: 'bucketName', folder: 'folderName', filename: 'filename.txt' }] }; export const storeData = writable( JSON.parse( dummyStoreObj || '', ));
问题原因
- Store使用错误:组件导入的是静态对象
dummyStoreObj,未使用实际的writablestore;JSON.parse(dummyStoreObj || '')会报错,因为dummyStoreObj是对象而非JSON字符串。 - 图表更新逻辑错误:
reDrawChart中直接修改myChart_option.source,但ECharts的数据源嵌套在dataset下,修改顶层source无法被正确识别。 - 未监听Store变化:组件未订阅Store的更新事件,Store数据变更时无法触发图表重绘。
修复方案
1. 修正Store定义(stores.js)
import { writable } from 'svelte/store'; const initialData = [{ start_time: '2023-01-31T07:45:11.286491+01:00', bucket: 'bucketName', folder: 'folderName', filename: 'filename.txt' }]; export const chartDataStore = writable(initialData);
2. 修正组件逻辑(diagram.svelte)
<script> import * as echarts from "echarts"; import { onMount, onDestroy } from "svelte"; import { chartDataStore } from "$lib/stores.js"; export let data; let myChart; let chartDom; let unsubscribe; // 通用图表更新函数 function updateChart(chartData) { if (!myChart) return; const option = { dataset: { dimensions: ["start_time", "bucket", "folder", "filename"], source: chartData, }, xAxis: { type: "time", name: "date/time", nameLocation: "middle", splitLine: { show: true }, }, yAxis: { type: "category", name: "# folder", nameGap: "1", splitLine: { show: true }, }, series: [ { type: "scatter", encode: { x: "start_time", y: "folder", }, }, ], }; // 强制替换旧配置,确保数据完全更新 myChart.setOption(option, true); } onMount(() => { chartDom = document.getElementById("chartDiv"); myChart = echarts.init(chartDom); // 初始渲染 updateChart(data); // 订阅Store变化,自动更新图表 unsubscribe = chartDataStore.subscribe(newData => { updateChart(newData); }); // 窗口大小变化时自适应 const handleResize = () => myChart?.resize(); window.addEventListener('resize', handleResize); return () => { window.removeEventListener('resize', handleResize); myChart?.dispose(); }; }); // 按钮触发:更新Store数据,自动触发图表重绘 const reDrawChart = () => { chartDataStore.update(current => [ ...current, { start_time: '2023-02-01T08:30:00+01:00', bucket: 'newBucket', folder: 'newFolder', filename: 'newFile.txt' } ]); }; onDestroy(() => { unsubscribe?.(); myChart?.dispose(); }); </script> <div> <button on:click={reDrawChart}>Redraw Chart</button> </div> <div id="chartDiv" /> <style> #chartDiv { height: 200px; width: auto; border: 1px solid #141413; } </style>
关键修复点
- 正确使用Store:导入并订阅
chartDataStore,数据变化时自动触发图表更新。 - 数据源字段匹配:修正
dimensions中的字段名,与数据源的filename保持一致。 - 强制更新配置:调用
setOption时传入第二个参数true,强制替换旧配置,确保数据完全生效。 - 资源清理:组件销毁时取消Store订阅、销毁ECharts实例、移除窗口resize监听,避免内存泄漏。
内容的提问来源于stack exchange,提问作者George.Ef
相关产品推荐
相关产品推荐

