You need to enable JavaScript to run this app. 如何在ApexCharts中实现缩放时年-月-日数据逐级下钻更新
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.16 06:45:03