You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

无法在Syncfusion图表中实现日期分组标签,求解决方案

实现日期范围分组的X轴标签(Flutter Syncfusion Chart)

问题描述

我想要创建带日期范围分组标签的图表,尝试过多级标签但样式无法满足需求,希望不用多级标签,直接给主X轴的日期标签做分组。以下是我的代码:

SizedBox(
  height: 30.h,
  child: SfCartesianChart(
    onAxisLabelTapped: ((axisLabelTapArgs) => print(axisLabelTapArgs.value)),
    plotAreaBorderWidth: 0,
    primaryYAxis: ChartHelper.buildNumericYAxis(textTheme),
    primaryXAxis: ChartHelper.buildDateTimeXAxis(),
    enableAxisAnimation: true,
    zoomPanBehavior: ChartHelper.buildZoomPanBehavior(),
    series: <ChartSeries>[
      if (provider.showPainCurve) ChartHelper.buildPainCurve(),
      if (provider.showBleedingCurve) ChartHelper.buildBleedingCurve(),
    ],
  ),
),

static DateTimeAxis buildDateTimeXAxis() {
  return DateTimeAxis(
    axisLine: const AxisLine(width: 0),
    labelIntersectAction: AxisLabelIntersectAction.hide,
    enableAutoIntervalOnZooming: false,
    interval: 1,
    autoScrollingMode: AutoScrollingMode.end,
    isVisible: true,
    autoScrollingDelta: 20,
    autoScrollingDeltaType: DateTimeIntervalType.days,
    majorGridLines: const MajorGridLines(
      width: 0.5,
      color: Color(0xFFFFDBCE),
    ),
    majorTickLines: const MajorTickLines(size: 0, width: 0),
    labelStyle: const TextStyle(height: 0, color: Colors.transparent),
  );
}

解决方案

针对Syncfusion的SfCartesianChart,不用多级标签的话,推荐两种实现方式:

方式1:自定义轴标签渲染器

通过继承DateTimeAxisLabelRenderer,重写标签构建逻辑,给每个日期标签添加分组文本:

class CustomDateAxisLabelRenderer extends DateTimeAxisLabelRenderer {
  @override
  Widget buildLabel(BuildContext context, AxisLabelDetails details) {
    final DateTime date = details.value as DateTime;
    // 示例:按周分组,可根据需求改成月份/自定义周期
    int weekOfYear = DateTime(date.year, date.month, date.day).week;
    String groupText = "第$weekOfYear周";

    return Column(
      mainAxisSize: MainAxisSize.min,
      children: [
        Text(
          DateFormat("d").format(date), // 显示日期的日部分
          style: const TextStyle(color: Colors.black87, fontSize: 12),
        ),
        const SizedBox(height: 3),
        Text(
          groupText,
          style: const TextStyle(color: Colors.grey, fontSize: 9),
        ),
      ],
    );
  }
}

然后在buildDateTimeXAxis中注册这个渲染器,同时移除原有的透明标签样式:

static DateTimeAxis buildDateTimeXAxis() {
  return DateTimeAxis(
    axisLine: const AxisLine(width: 0),
    labelIntersectAction: AxisLabelIntersectAction.hide,
    enableAutoIntervalOnZooming: false,
    interval: 1,
    autoScrollingMode: AutoScrollingMode.end,
    isVisible: true,
    autoScrollingDelta: 20,
    autoScrollingDeltaType: DateTimeIntervalType.days,
    majorGridLines: const MajorGridLines(
      width: 0.5,
      color: Color(0xFFFFDBCE),
    ),
    majorTickLines: const MajorTickLines(size: 0, width: 0),
    // 替换原有透明样式,使用自定义渲染器
    labelRenderer: CustomDateAxisLabelRenderer(),
  );
}

方式2:图表下方添加独立分组栏

如果自定义渲染器不够灵活,可以在图表外层套Column,底部添加一个同步滚动的分组标签栏:

Column(
  children: [
    SizedBox(
      height: 30.h,
      child: SfCartesianChart(
        // 原有图表配置不变
        onAxisLabelTapped: ((axisLabelTapArgs) => print(axisLabelTapArgs.value)),
        plotAreaBorderWidth: 0,
        primaryYAxis: ChartHelper.buildNumericYAxis(textTheme),
        primaryXAxis: ChartHelper.buildDateTimeXAxis(),
        enableAxisAnimation: true,
        zoomPanBehavior: ChartHelper.buildZoomPanBehavior(),
        series: <ChartSeries>[
          if (provider.showPainCurve) ChartHelper.buildPainCurve(),
          if (provider.showBleedingCurve) ChartHelper.buildBleedingCurve(),
        ],
      ),
    ),
    // 自定义分组标签栏
    SizedBox(
      height: 22,
      child: ListView.builder(
        scrollDirection: Axis.horizontal,
        controller: chartScrollController, // 和图表的滚动控制器同步
        itemCount: dateGroups.length, // 你的分组数据列表长度
        itemBuilder: (context, index) {
          final group = dateGroups[index];
          return Container(
            width: calculateGroupWidth(group), // 根据分组包含的天数计算宽度
            alignment: Alignment.center,
            child: Text(
              group.label,
              style: const TextStyle(fontSize: 10, color: Colors.grey),
            ),
          );
        },
      ),
    ),
  ],
)

需要注意:要同步图表的滚动和分组栏的滚动,可通过ZoomPanBehavior的onZooming或onPanning回调来更新分组栏的滚动位置。

内容的提问来源于stack exchange,提问作者Muhammad Hamad Jamal

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 23:09:54