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

Flutter Syncfusion堆叠条形图零值柱位显示无数据文本实现

Flutter Syncfusion 堆叠条形图零值显示「无可用数据」实现方案

需求说明

使用Syncfusion的SfCartesianChart控件构建堆叠条形图时,当柱形对应数值为0时,不在对应位置留空白,而是展示「无可用数据」文本。当前图表配置:Y轴为数值轴、X轴为类目轴,零值位置默认空白的实际效果、目标效果如下:

  • 实际运行效果(零值位置为空):
    实际运行效果
  • 预期实现效果:
    预期实现效果

核心实现思路

默认情况下StackedBarSeries对y值为0的数据点不会渲染柱形,也不会触发默认数据标签显示,通过两个核心配置即可实现需求:

  1. 开启系列的数据标签渲染能力
  2. 通过onDataLabelRender回调拦截标签渲染逻辑,对y值为0的数据点强制渲染「无可用数据」文本,同时调整标签位置到对应类目行的居中位置,避免偏移隐藏

代码修改

原有问题版本核心代码

SfCartesianChart(
    crosshairBehavior: _crosshairBehavior,
    primaryXAxis: CategoryAxis(
        majorTickLines: MajorTickLines(size: 20, width: 0),
        axisBorderType: AxisBorderType.withoutTopAndBottom,
        labelAlignment: LabelAlignment.center,
        borderWidth: 2.0,
        labelStyle: TextStyle(
            fontFamily: 'Roboto',
            fontSize: 14,
            fontStyle: FontStyle.normal,
            fontWeight: FontWeight.w500),
        labelPosition: ChartDataLabelPosition.outside,
        borderColor: Colors.blueGrey[800]),
    primaryYAxis: CategoryAxis(
      plotBands: <PlotBand>[
        PlotBand(
          isVisible: widget.isFleetAverageVisible,
          start: 30,
          end: 29,
          borderWidth: 0.3,
          borderColor: Colors.black,
        )
      ],
      interval: 25,
      maximumLabels: 4,
      maximum: 100,
      minimum: 0,
      majorTickLines: MajorTickLines(size: 15, width: 0),
      majorGridLines: MajorGridLines(dashArray: [5, 5]),
    ),
    series: stackedWidget(sortSelected != null
        ? sortSelected == true
            ? SortingOrder.ascending
            : SortingOrder.descending
        : SortingOrder.none),
    legend: Legend(
      isVisible: true,
      position: LegendPosition.bottom,
      overflowMode: LegendItemOverflowMode.wrap,
    ),
    onLegendTapped: (LegendTapArgs args) {

      },
),

List<ChartSeries> stackedWidget(SortingOrder sortingOrder) {
return <ChartSeries>[
    StackedBarSeries<ChartData, String>(
        sortingOrder: sortingOrder,
        legendIconType: LegendIconType.horizontalLine,
        legendItemText: "series1",
        width: 0.3,
        spacing: 0.2,
        dataSource: chartData,
        xValueMapper: (ChartData data, _) => data.x,
        yValueMapper: (ChartData data, _) => data.y1,
        sortFieldValueMapper: (ChartData sales, _) => sales.y1,
        color: Color.fromRGBO(51, 102, 255, 1))
];
}

注意:原代码中primaryYAxis误用了CategoryAxis,Y轴是0-100的数值类型,需要替换为NumericAxis否则轴渲染会异常。

修改后可实现需求的代码

在SfCartesianChart层级添加数据标签渲染回调,同时给每个StackedBarSeries配置数据标签参数:

SfCartesianChart(
    crosshairBehavior: _crosshairBehavior,
    primaryXAxis: CategoryAxis(
        majorTickLines: MajorTickLines(size: 20, width: 0),
        axisBorderType: AxisBorderType.withoutTopAndBottom,
        labelAlignment: LabelAlignment.center,
        borderWidth: 2.0,
        labelStyle: TextStyle(
            fontFamily: 'Roboto',
            fontSize: 14,
            fontStyle: FontStyle.normal,
            fontWeight: FontWeight.w500),
        labelPosition: ChartDataLabelPosition.outside,
        borderColor: Colors.blueGrey[800]),
    primaryYAxis: NumericAxis(
      plotBands: <PlotBand>[
        PlotBand(
          isVisible: widget.isFleetAverageVisible,
          start: 30,
          end: 29,
          borderWidth: 0.3,
          borderColor: Colors.black,
        )
      ],
      interval: 25,
      maximumLabels: 4,
      maximum: 100,
      minimum: 0,
      majorTickLines: MajorTickLines(size: 15, width: 0),
      majorGridLines: MajorGridLines(dashArray: [5, 5]),
    ),
    // 全局数据标签渲染回调
    onDataLabelRender: (DataLabelRenderArgs args) {
      // 获取当前渲染点的y值
      final num yValue = args.yValues![args.pointIndex!];
      if (yValue == 0) {
        // 零值替换为指定文本
        args.text = "无可用数据";
        // 配置零值文本样式
        args.textStyle = TextStyle(
          fontSize: 12,
          color: Colors.grey[700],
          fontWeight: FontWeight.w400
        );
        // 调整标签位置到X轴类目行居中位置,避免被隐藏
        args.labelAlignment = ChartDataLabelAlignment.middle;
      }
    },
    series: stackedWidget(sortSelected != null
        ? sortSelected == true
            ? SortingOrder.ascending
            : SortingOrder.descending
        : SortingOrder.none),
    legend: Legend(
      isVisible: true,
      position: LegendPosition.bottom,
      overflowMode: LegendItemOverflowMode.wrap,
    ),
    onLegendTapped: (LegendTapArgs args) {

      },
),

List<ChartSeries> stackedWidget(SortingOrder sortingOrder) {
return <ChartSeries>[
    StackedBarSeries<ChartData, String>(
        sortingOrder: sortingOrder,
        legendIconType: LegendIconType.horizontalLine,
        legendItemText: "series1",
        width: 0.3,
        spacing: 0.2,
        dataSource: chartData,
        xValueMapper: (ChartData data, _) => data.x,
        yValueMapper: (ChartData data, _) => data.y1,
        sortFieldValueMapper: (ChartData sales, _) => sales.y1,
        color: Color.fromRGBO(51, 102, 255, 1),
        // 开启数据标签显示
        dataLabelSettings: DataLabelSettings(
          isVisible: true,
          // 非零值标签默认显示在柱形内部居中
          labelAlignment: ChartDataLabelAlignment.middle,
          textStyle: TextStyle(
            fontSize: 12,
            color: Colors.white,
            fontWeight: FontWeight.w500
          )
        )
    )
    // 多堆叠系列同理,每个系列都配置dataLabelSettings即可
];
}

适配说明

  • 如果是多系列堆叠场景,判断逻辑可修改为:当前X轴位置所有系列的y值总和为0时,才显示「无可用数据」,避免单系列为0但其他系列有值时错误显示
  • 文本样式、位置可根据实际UI需求调整textStyle和labelAlignment参数

内容的提问来源于stack exchange,提问作者gopinath

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 15:36:24