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

Flutter graphic库堆叠柱状图8月16日显示异常排查求助

Flutter graphic库堆叠柱状图单类型日期柱形显示异常问题

问题场景

在Web项目中使用Flutter 3.7.10和graphic ^2.2.0实现堆叠柱状图时,发现8月16日仅存在Type 3数据的柱形显示异常。仅使用两类数据(如Type1+Type2)时图表显示正常,尝试过重新排序日期、为缺失类型补充空值(value=0),但问题仍未解决。

问题原因

核心原因是StackModifier在计算堆叠位置时,依赖同一日期下所有类型的数据元组做基准计算。当某一日期只有单个类型数据时,缺少其他类型的空值元组会导致堆叠逻辑的起点判断异常,无法正确从y=0开始绘制柱形。

解决方案

补全所有日期下的全类型数据,缺失类型的value设为0,确保每个日期都包含所有类型的数据项,让StackModifier能正确计算堆叠基准。

修改后的完整代码

import 'package:flutter/material.dart';
import 'package:graphic/graphic.dart';

class MyWidget extends StatelessWidget {
  const MyWidget({super.key});

  @override
  Widget build(BuildContext context) {
    // 补全所有日期的全类型数据,缺失项value设为0
    final data = [
      // 8月11日
      {'id': DateTime(2023, 8, 11), 'type': 'Type 1', 'value': 2},
      {'id': DateTime(2023, 8, 11), 'type': 'Type 2', 'value': 2},
      {'id': DateTime(2023, 8, 11), 'type': 'Type 3', 'value': 0},
      // 8月14日
      {'id': DateTime(2023, 8, 14), 'type': 'Type 1', 'value': 4},
      {'id': DateTime(2023, 8, 14), 'type': 'Type 2', 'value': 4},
      {'id': DateTime(2023, 8, 14), 'type': 'Type 3', 'value': 0},
      // 8月16日
      {'id': DateTime(2023, 8, 16), 'type': 'Type 1', 'value': 0},
      {'id': DateTime(2023, 8, 16), 'type': 'Type 2', 'value': 0},
      {'id': DateTime(2023, 8, 16), 'type': 'Type 3', 'value': 1},
      // 8月18日
      {'id': DateTime(2023, 8, 18), 'type': 'Type 1', 'value': 3},
      {'id': DateTime(2023, 8, 18), 'type': 'Type 2', 'value': 3},
      {'id': DateTime(2023, 8, 18), 'type': 'Type 3', 'value': 0},
    ];

    final types = {
      'Type 1': const Color(0xfff39e58),
      'Type 2': const Color(0xff707070),
      'Type 3': const Color(0xffffc107)
    };

    final listOfTicks = [
      DateTime(2023, 8, 6),
      DateTime(2023, 8, 7),
      DateTime(2023, 8, 8),
      DateTime(2023, 8, 9),
      DateTime(2023, 8, 10),
      DateTime(2023, 8, 11),
      DateTime(2023, 8, 12),
      DateTime(2023, 8, 13),
      DateTime(2023, 8, 14),
      DateTime(2023, 8, 15),
      DateTime(2023, 8, 16),
      DateTime(2023, 8, 17),
      DateTime(2023, 8, 18),
      DateTime(2023, 8, 19),
      DateTime(2023, 8, 20),
    ];

    return Chart(
      data: data,
      variables: {
        'id': Variable(
          accessor: (Map<dynamic, dynamic> datum) => datum['id'] as DateTime,
          scale: TimeScale(
            formatter: (p0) => p0.day.toString(),
            max: listOfTicks.last,
            min: listOfTicks.first,
            ticks: listOfTicks,
          ),
        ),
        'type': Variable(
          accessor: (Map map) => map['type'] as String,
        ),
        'value': Variable(
          accessor: (Map map) => map['value'] as num,
          scale: LinearScale(min: 0, max: 10),
        ),
      },
      marks: [
        IntervalMark(
          position: Varset('id') * Varset('value') / Varset('type'),
          shape: ShapeEncode(
            value: RectShape(
              labelPosition: 0.5,
            ),
          ),
          color: ColorEncode(
            variable: 'type',
            values: types.values.toList(),
          ),
          label: LabelEncode(
            encoder: (tuple) => tuple['value'] == 0
                ? Label('')
                : Label(
                    tuple['value'].toString(),
                    LabelStyle(
                      textStyle: Theme.of(context)
                          .textTheme
                          .bodySmall!
                          .copyWith(color: Colors.white),
                    ),
                  ),
          ),
          size: SizeEncode(value: 24),
          modifiers: [StackModifier()],
        )
      ],
      coord: RectCoord(),
      axes: [
        Defaults.horizontalAxis,
        Defaults.verticalAxis,
      ],
      selections: {
        'tap': PointSelection(
          variable: 'id',
        )
      },
      tooltip: TooltipGuide(multiTuples: true),
      crosshair: CrosshairGuide(),
    );
  }
}

自动化补全工具函数(可选)

如果手动补数据繁琐,可以用以下函数自动生成完整数据:

List<Map<String, dynamic>> completeData(List<Map<String, dynamic>> rawData, List<String> allTypes, List<DateTime> allDates) {
  final result = <Map<String, dynamic>>[];
  for (final date in allDates) {
    final dateData = rawData.where((d) => d['id'] == date).toList();
    final existingTypes = dateData.map((d) => d['type'] as String).toSet();
    for (final type in allTypes) {
      if (existingTypes.contains(type)) {
        result.add(dateData.firstWhere((d) => d['type'] == type));
      } else {
        result.add({'id': date, 'type': type, 'value': 0});
      }
    }
  }
  return result;
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 20:12:54