You need to enable JavaScript to run this app. Flutter基于charts_flutter开发时间序列图,如何实现选中刻度后展示关联数据
优惠活动
大模型
产品
解决方案
定价
更多

Flutter基于charts_flutter开发时间序列图,如何实现选中刻度后展示关联数据

实现选中时间刻度展示关联数据的修改方案

核心修改逻辑(基于现有代码)

1. 开启图表的domain选中交互支持

在charts.TimeSeriesChart配置中补充选中相关参数,让坐标轴刻度可响应点击:

  • 开启信息类选中模型
  • 配置渲染器支持按域值就近选中(点击刻度自动匹配对应时间)
  • 绑定选中变化监听回调

2. 状态管理改造

把原无状态的EndPointsAxisTimeSeriesChart改为有状态组件,保存当前选中的时间与对应数值,触发UI刷新。

3. 选中事件匹配逻辑

从选中模型中取出当前选中的时间域值,遍历两个时间序列的数据源,匹配对应时间的业务数值,处理时间精度对齐(避免因毫秒差导致匹配失败)。

4. 展示层适配

在原有标题区域下方、图表上方的文本区域,新增选中数据的展示,复用原有UI风格,无选中时保留默认统计值。

具体代码修改示例

(1)改造EndPointsAxisTimeSeriesChart为有状态组件,新增选中逻辑

// 替换原有无状态类,新增选中回调参数(选中域值时触发,传入选中时间、两个系列的对应数值)
class EndPointsAxisTimeSeriesChart extends StatefulWidget {
  final List<charts.Series<TimeSeriesSales, DateTime>> seriesList;
  final bool animate;
  final void Function(DateTime? selectedTime, double? series1Value, double? series2Value)? onDomainSelected;

  const EndPointsAxisTimeSeriesChart(
    this.seriesList, {
    super.key,
    this.animate = false,
    this.onDomainSelected,
  });

  @override
  State<EndPointsAxisTimeSeriesChart> createState() => _EndPointsAxisTimeSeriesChartState();
}

class _EndPointsAxisTimeSeriesChartState extends State<EndPointsAxisTimeSeriesChart> {
  DateTime? _selectedTime;

  @override
  Widget build(BuildContext context) {
    return charts.TimeSeriesChart(
      widget.seriesList,
      animate: widget.animate,
      // 保留原有配置
      domainAxis: const charts.DateTimeAxisSpec(),
      dateTimeFactory: const charts.LocalDateTimeFactory(),
      primaryMeasureAxis: charts.NumericAxisSpec(
        tickProviderSpec: const charts.BasicNumericTickProviderSpec(desiredTickCount: 4),
      ),
      // 新增:选中交互配置
      selectionModelType: charts.SelectionModelType.info, // 开启信息选中模型
      onSelectionChanged: _handleSelectionChange, // 绑定选中变化回调
      defaultRenderer: charts.LineRendererConfig(
        includePoints: false,
        includeArea: false,
        // 新增:点击任意位置(含坐标轴刻度)自动匹配最近的时间域值
        selectNearestByDomain: true,
      ),
    );
  }

  // 新增:选中事件处理逻辑
  void _handleSelectionChange(charts.SelectionModel model) {
    final selectedDomain = model.selectedDomain;
    if (selectedDomain == null) {
      setState(() => _selectedTime = null);
      widget.onDomainSelected?.call(null, null, null);
      return;
    }

    // 裁剪时间精度,避免毫秒差导致匹配失败(可根据业务粒度调整裁剪规则)
    final targetTime = DateTime(
      selectedDomain.year,
      selectedDomain.month,
      selectedDomain.day,
      selectedDomain.hour,
      selectedDomain.minute,
    );

    // 匹配第一个系列(Consumos)的对应值
    final series1Data = widget.seriesList.firstWhere((s) => s.id == 'Consumos').data;
    double? value1;
    for (final item in series1Data) {
      final itemTime = DateTime(
        item.time.year,
        item.time.month,
        item.time.day,
        item.time.hour,
        item.time.minute,
      );
      if (itemTime == targetTime) {
        value1 = item.sales;
        break;
      }
    }

    // 匹配第二个系列(Consumos2)的对应值
    final series2Data = widget.seriesList.firstWhere((s) => s.id == 'Consumos2').data;
    double? value2;
    for (final item in series2Data) {
      final itemTime = DateTime(
        item.time.year,
        item.time.month,
        item.time.day,
        item.time.hour,
        item.time.minute,
      );
      if (itemTime == targetTime) {
        value2 = item.sales;
        break;
      }
    }

    // 更新状态并触发上层回调
    setState(() => _selectedTime = selectedDomain);
    widget.onDomainSelected?.call(targetTime, value1, value2);
  }
}

(2)适配上层graficoLinealDoble方法,展示选中数据

修改原有上层UI的文本区域,监听选中态变化,替换原有默认统计值:

Widget graficoLinealDoble(BuildContext context, List<DateTime> listOfFechas, List<double> listOfCantidades, List<DateTime> listOfFechas2, List<double> listOfCantidades2,String titulo, String subtitulo, String medidaSubtitulo, [String color = '#E0B872', String color2 = '#E5E5E9']) {
  // 用ValueNotifier管理选中态,兼容现有函数式写法(也可抽成独立Stateful组件管理)
  final selectedValueNotifier = ValueNotifier<(DateTime?, double?, double?)>((null, null, null));

  return Column(
    children: <Widget>[
      const SizedBox(height: 8.0),
      Text(
        titulo,
        maxLines: 1,
        overflow: TextOverflow.fade,
        softWrap: false,
        style: TextStyle(
          fontSize: 18.0,
          color: Theme.of(context).primaryColor,
          fontWeight: FontWeight.bold,
        ),
      ),
      // 改造原有数值展示区域,监听选中态变化
      ValueListenableBuilder(
        valueListenable: selectedValueNotifier,
        builder: (context, selectedData, _) {
          final selectedTime = selectedData.$1;
          final value1 = selectedData.$2;
          final value2 = selectedData.$3;
          // 有选中时展示对应数据,无选中时展示原有默认值
          final displayText = selectedTime == null
              ? subtitulo
              // 可自定义选中时间的格式化展示,比如仅显示日期/时分
              : '${value1?.toStringAsFixed(1) ?? '-'} / ${value2?.toStringAsFixed(1) ?? '-'}';
          final displayUnit = selectedTime == null ? medidaSubtitulo : medidaSubtitulo;
          return Row(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              Text(
                displayText,
                style: const TextStyle(fontSize: 26.0, color: Colors.grey),
              ),
              Text(
                displayUnit,
                style: TextStyle(
                  fontSize: 16.0,
                  color: Theme.of(context).primaryColor,
                ),
                strutStyle: const StrutStyle(fontSize: 26.0),
              ),
            ],
          );
        },
      ),
      Flexible(
        child: EndPointsAxisTimeSeriesChart(
          _crearLinea(
            listOfFechas,
            listOfCantidades,
            color,
            listOfFechas2,
            listOfCantidades2,
            color2,
          ),
          animate: true,
          // 绑定选中回调,更新选中态
          onDomainSelected: (time, v1, v2) {
            selectedValueNotifier.value = (time, v1, v2);
          },
        ),
      ),
    ],
  );
}

补充说明

  • 时间匹配的精度裁剪规则可根据实际业务调整:如果时间粒度按天,可去掉比对时、分部分;如果是按小时,可去掉分钟比对。
  • 可新增刻度选中高亮效果:在domainAxis的renderSpec中配置TickRendererSpec的labelStyle,结合_selectedTime动态修改选中刻度的颜色或背景。
  • 封装的onDomainSelected回调可直接复用在不同业务页面,无需修改图表内部逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.29 23:45:04