Flutter中charts_flutter散点图点击显示数据实现需求
实现charts_flutter散点图点击显示对应数据的方案
需求:为charts_flutter的散点图添加点击交互,点击圆点时显示对应的数据。此前使用SfCircularChart可实现类似效果,但Sf散点图为收费功能,需基于现有代码改造。
改造步骤及完整代码
要实现点击显示数据,需将原StatelessWidget改为StatefulWidget,添加选择监听行为并维护选中数据状态,最后通过弹窗或文本展示数据:
import 'package:flutter/material.dart'; import 'package:charts_flutter/flutter.dart' as charts; class SimpleScatterPlotChart extends StatefulWidget { final List<charts.Series<_HeartRateData, num>> seriesList; final bool animate; const SimpleScatterPlotChart({ required this.seriesList, this.animate = false, Key? key, }) : super(key: key); factory SimpleScatterPlotChart.withSampleData() { return SimpleScatterPlotChart( seriesList: _createSampleData(), animate: false, ); } @override State<SimpleScatterPlotChart> createState() => _SimpleScatterPlotChartState(); } class _SimpleScatterPlotChartState extends State<SimpleScatterPlotChart> { _HeartRateData? _selectedData; @override Widget build(BuildContext context) { return Stack( alignment: Alignment.center, children: [ Container( height: 250, width: 350, child: charts.ScatterPlotChart( widget.seriesList, animate: widget.animate, primaryMeasureAxis: const charts.NumericAxisSpec( renderSpec: charts.GridlineRendererSpec( labelStyle: charts.TextStyleSpec( color: charts.Color.fromHex(code: '#7A7A7A'), ), ), ), domainAxis: const charts.NumericAxisSpec( showAxisLine: false, renderSpec: charts.NoneRenderSpec(), ), // 添加点击选择监听 behaviors: [ charts.SelectionModelConfig( type: charts.SelectionModelType.info, changedListener: (charts.SelectionModel model) { if (model.hasDatumSelection) { setState(() { _selectedData = model.selectedDatum[0].datum as _HeartRateData; }); // 可选:弹出自动消失的Tooltip _showDataTooltip(context, _selectedData!); } else { setState(() { _selectedData = null; }); } }, ), ], ), ), // 图表中心悬浮显示选中数据 if (_selectedData != null) Container( padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), decoration: BoxDecoration( color: Colors.black.withOpacity(0.7), borderRadius: BorderRadius.circular(8), ), child: Text( "日期: ${_selectedData!.date}\n心率: ${_selectedData!.heartRate}", style: const TextStyle(color: Colors.white, fontSize: 12), textAlign: TextAlign.center, ), ), ], ); } // 弹出自动关闭的Tooltip void _showDataTooltip(BuildContext context, _HeartRateData data) { final overlay = Overlay.of(context); final overlayEntry = OverlayEntry( builder: (context) => Positioned( top: MediaQuery.of(context).size.height / 2 - 100, left: MediaQuery.of(context).size.width / 2 - 80, child: Material( color: Colors.transparent, child: Container( padding: const EdgeInsets.all(10), decoration: BoxDecoration( color: Colors.blueGrey, borderRadius: BorderRadius.circular(6), ), child: Text( "心率: ${data.heartRate}\n时间点: ${data.date}", style: const TextStyle(color: Colors.white), ), ), ), ), ); overlay.insert(overlayEntry); Future.delayed(const Duration(seconds: 3)).then((_) => overlayEntry.remove()); } /// 创建示例数据(替换为你的apiData) static List<charts.Series<_HeartRateData, num>> _createSampleData() { final apiData = [ _HeartRateData(date: 1, heartRate: 55, radius: 8), _HeartRateData(date: 2, heartRate: 78, radius: 8), _HeartRateData(date: 3, heartRate: 105, radius: 8), ]; return [ charts.Series<_HeartRateData, num>( id: '心率', colorFn: (_HeartRateData sales, _) { if (sales.heartRate < 61) { return charts.Color.fromHex(code: '#F8D277'); } else if (sales.heartRate < 100) { return charts.Color.fromHex(code: '#61D2A4'); } else { return charts.Color.fromHex(code: '#DD5571'); } }, domainFn: (_HeartRateData sales, _) => sales.date, measureFn: (_HeartRateData sales, _) => sales.heartRate, radiusPxFn: (_HeartRateData sales, _) => sales.radius, data: apiData, ), ]; } } // 心率数据模型 class _HeartRateData { final int date; final int heartRate; final int radius; _HeartRateData({ required this.date, required this.heartRate, required this.radius, }); }
关键说明
- 转为StatefulWidget:通过
_selectedData变量维护选中的数据状态 - SelectionModelConfig监听:配置图表的选择行为,点击散点时触发回调获取选中的数据源
- 数据展示方式:提供两种可选方案:
- 利用Stack在图表中心悬浮显示选中数据
- 通过Overlay弹出自动关闭的Tooltip
- 数据适配:确保
_HeartRateData包含所有需要展示的字段,替换示例数据为你的apiData即可
内容的提问来源于stack exchange,提问作者Nutdanai
相关产品推荐
相关产品推荐

