如何在ApexCharts中实现缩放时年-月-日数据逐级下钻更新
实现方案
ApexCharts原生支持该交互需求,核心通过zoomed事件监听缩放范围,结合粒度判断动态替换数据即可实现年→月→日的层级下钻缩放效果。
核心实现步骤
- 替换原分类类型x轴为时间类型x轴:可直接获取缩放的时间戳范围,无需手动映射分类下标
- 新增粒度状态标识:在state中新增
currentGranularity字段,可选值为year/month/day,初始值设为year - 改写
zoomed事件逻辑:每次缩放完成后计算选中的时间跨度,结合当前粒度判断是否需要加载下一级粒度的数据 - 适配数据更新逻辑:加载对应粒度的新数据后,直接更新state的
series和options.xaxis配置即可触发图表自动重绘 - 新增缩放重置回调:用户点击工具栏的重置缩放按钮时,可直接切回初始年度粒度数据
修改后的完整代码
import React from "react"; import ReactApexChart from "react-apexcharts"; interface StackedGraphProps {} type SeriesType = { name: string; data: [number, number][]; // 时间戳+数值的格式,适配时间轴 }; interface StackedGraphState { series: SeriesType[]; options: any; currentGranularity: 'year' | 'month' | 'day'; } class StackedBarGraph extends React.Component< StackedGraphProps, StackedGraphState > { // 初始年度数据示例 initialYearSeries = [ { name: "Marine Sprite", data: [ [new Date('2008-01-01').getTime(), 44], [new Date('2009-01-01').getTime(), 55], [new Date('2010-01-01').getTime(), 41], [new Date('2011-01-01').getTime(), 37], [new Date('2012-01-01').getTime(), 22], [new Date('2013-01-01').getTime(), 43], [new Date('2014-01-01').getTime(), 21], ], }, { name: "Striking Calf", data: [ [new Date('2008-01-01').getTime(), 53], [new Date('2009-01-01').getTime(), 32], [new Date('2010-01-01').getTime(), 33], [new Date('2011-01-01').getTime(), 52], [new Date('2012-01-01').getTime(), 13], [new Date('2013-01-01').getTime(), 43], [new Date('2014-01-01').getTime(), 32], ], }, { name: "Tank Picture", data: [ [new Date('2008-01-01').getTime(), 12], [new Date('2009-01-01').getTime(), 17], [new Date('2010-01-01').getTime(), 11], [new Date('2011-01-01').getTime(), 9], [new Date('2012-01-01').getTime(), 15], [new Date('2013-01-01').getTime(), 11], [new Date('2014-01-01').getTime(), 20], ], }, ]; constructor(props: any) { super(props); this.state = { currentGranularity: 'year', series: this.initialYearSeries, options: { chart: { events: { zoomed: (chartContext: any, { xaxis }) => { const { min, max } = xaxis; const timeDiff = max - min; const ONE_YEAR = 365 * 24 * 3600 * 1000; const ONE_MONTH = 31 * 24 * 3600 * 1000; const { currentGranularity } = this.state; // 年度粒度下缩放范围小于1年,切换为月度数据 if (currentGranularity === 'year' && timeDiff <= ONE_YEAR) { const targetYear = new Date(min).getFullYear(); // 此处替换为你自己的接口请求逻辑,获取对应年份的月度数据 const newMonthSeries = [ // 示例:返回格式为[[时间戳, 数值], ...]的月度数据 ]; this.setState({ currentGranularity: 'month', series: newMonthSeries, options: { ...this.state.options, xaxis: { ...this.state.options.xaxis, min: new Date(`${targetYear}-01-01`).getTime(), max: new Date(`${targetYear}-12-31`).getTime() } } }) } // 月度粒度下缩放范围小于31天,切换为日度数据 else if (currentGranularity === 'month' && timeDiff <= ONE_MONTH) { const targetYear = new Date(min).getFullYear(); const targetMonth = new Date(min).getMonth() + 1; // 此处替换为你自己的接口请求逻辑,获取对应月份的日度数据 const newDaySeries = [ // 示例:返回格式为[[时间戳, 数值], ...]的日度数据 ]; this.setState({ currentGranularity: 'day', series: newDaySeries, options: { ...this.state.options, xaxis: { ...this.state.options.xaxis, min: new Date(`${targetYear}-${targetMonth}-01`).getTime(), max: new Date(targetYear, targetMonth, 0).getTime() } } }) } }, beforeResetZoom: () => { // 重置缩放时切回初始年度数据 this.setState({ currentGranularity: 'year', series: this.initialYearSeries, options: { ...this.state.options, xaxis: { ...this.state.options.xaxis, min: new Date('2008-01-01').getTime(), max: new Date('2014-12-31').getTime() } } }) }, selection: function (chartContext: any, { xaxis, yaxis }) { console.log("Selection", xaxis, yaxis); }, dataPointSelection: ( event: any, chartContext: any, config: any ) => { console.log("datapoint", chartContext, config); }, }, zoom: { enabled: true, type: "x", autoScaleYaxis: false, }, type: "bar", height: 350, stacked: true, }, toolbar: { show: true, }, plotOptions: { bar: { horizontal: false, }, }, stroke: { width: 1, colors: ["#fff"], }, grid: { row: { colors: ["#fff", "#f2f2f2f2"], }, }, title: { text: "", }, xaxis: { type: 'datetime', // 改为时间类型轴 tickPlacement: "on", labels: { formatter: function (val: any) { const date = new Date(val); // 根据当前粒度动态展示时间格式 if (this.state.currentGranularity === 'year') return date.getFullYear().toString(); if (this.state.currentGranularity === 'month') return `${date.getFullYear()}-${date.getMonth()+1}`; return `${date.getFullYear()}-${date.getMonth()+1}-${date.getDate()}`; }.bind(this) }, }, yaxis: { title: { text: undefined, }, }, tooltip: { y: { formatter: function (val: any) { return val + "K"; }, }, }, fill: { opacity: 1, }, legend: { position: "top", horizontalAlign: "left", offsetX: 40, }, }, }; } render() { return ( <div id="chart"> <ReactApexChart zoomEnabled={true} options={this.state.options} series={this.state.series} type="bar" height={350} /> </div> ); } } export default StackedBarGraph;
内容的提问来源于stack exchange,提问作者aditya kumar
相关产品推荐
相关产品推荐

