FlChart实现X轴AM/PM格式折线图时模拟器无响应问题
问题
尝试使用FlChart绘制过去12小时的折线图,要求X轴标签以「12pm、5am」这类12小时制格式显示,且仅展示首尾标签。但运行代码后模拟器无响应且无报错。
sensorData包含12个按小时存储的DateTime类型对象,相关代码如下:
final Color lineColor; final List<SpatialGrowSensor> sensorData; const SensorLineChart({ Key? key, required this.sensorData, required this.lineColor, }) : super(key: key); LineChartData sampleData1(List<SpatialGrowSensor> sensorData) { return LineChartData( lineTouchData: lineTouchData1(), gridData: gridData(), titlesData: titlesData1(), borderData: borderData(), lineBarsData: lineBarsData1(), minY: 0, maxY: 10, ); } LineTouchData lineTouchData1() => LineTouchData( handleBuiltInTouches: true, touchTooltipData: LineTouchTooltipData( tooltipBgColor: Colors.blueGrey.withOpacity(0.8), ), ); FlTitlesData titlesData1() => FlTitlesData( bottomTitles: AxisTitles( sideTitles: bottomTitles(), ), rightTitles: AxisTitles( sideTitles: SideTitles(showTitles: false), ), topTitles: AxisTitles( sideTitles: SideTitles(showTitles: false), ), leftTitles: AxisTitles( sideTitles: leftTitles(), ), ); List<LineChartBarData> lineBarsData1() => [ lineChartBarData1_1(), ]; Widget leftTitleWidgets(double value, TitleMeta meta) { const style = TextStyle( color: Colors.white, fontWeight: FontWeight.bold, fontSize: 16, ); return Text(value.toString(), style: style, textAlign: TextAlign.center); } SideTitles leftTitles() => SideTitles( getTitlesWidget: leftTitleWidgets, showTitles: true, reservedSize: 32, interval: 2, ); Widget bottomTitleWidgets(double value, TitleMeta meta) { const style = TextStyle( color: Colors.white, fontWeight: FontWeight.bold, fontSize: 16, ); // format datetime as '12pm' String dateFormated = DateFormat('ha').format(DateTime.fromMillisecondsSinceEpoch(value.toInt(), isUtc: true)); Widget text = Text(dateFormated, style: style); return SideTitleWidget( axisSide: meta.axisSide, space: 10, child: text, ); } SideTitles bottomTitles() => SideTitles( showTitles: true, reservedSize: 32, interval: 6, getTitlesWidget: bottomTitleWidgets, ); FlGridData gridData() => FlGridData(show: false); FlBorderData borderData() => FlBorderData( show: true, border: const Border( bottom: BorderSide(color: Color(0xff4e4965), width: 4), left: BorderSide(color: Colors.transparent), right: BorderSide(color: Colors.transparent), top: BorderSide(color: Colors.transparent), ), ); LineChartBarData lineChartBarData1_1() { final flSpotData = sensorData.map((sensor) { return FlSpot(sensor.dateTime.millisecondsSinceEpoch.toDouble(), sensor.sensorValue); }).toList(); return LineChartBarData( isCurved: true, color: lineColor, barWidth: 4, dotData: FlDotData(show: false), belowBarData: BarAreaData(show: false), preventCurveOverShooting: true, spots: flSpotData, ); } @override Widget build(BuildContext context) { return Padding( padding: const EdgeInsets.all(16.0), child: Container( decoration: BoxDecoration( borderRadius: BorderRadius.circular(8), color: HexColor('#0c110a'), ), child: SizedBox( height: 200, child: Padding( padding: const EdgeInsets.all(32.0), child: LineChart( sampleData1(sensorData), ), ), ), ), ); }
解决方案
问题根源
模拟器无响应的核心原因是X轴interval设置错误:你设置了interval: 6,但X轴数值是毫秒级时间戳,6毫秒的间隔会让FlChart尝试生成海量标签,直接耗尽计算资源导致卡死。同时当前逻辑无法实现仅显示首尾标签的需求。
修复代码
修改bottomTitles方法,移除错误的interval参数,通过判断时间戳是否为首尾数据的时间戳,仅渲染首尾标签:
SideTitles bottomTitles() => SideTitles( showTitles: true, reservedSize: 32, getTitlesWidget: (value, meta) { // 空数据判断,避免运行报错 if (sensorData.isEmpty) return const SizedBox.shrink(); // 获取首尾数据的时间戳 final firstTimestamp = sensorData.first.dateTime.millisecondsSinceEpoch.toDouble(); final lastTimestamp = sensorData.last.dateTime.millisecondsSinceEpoch.toDouble(); // 仅对首尾时间戳生成标签 if (value == firstTimestamp || value == lastTimestamp) { const style = TextStyle( color: Colors.white, fontWeight: FontWeight.bold, fontSize: 16, ); // 格式化时间为12小时制 String dateFormated = DateFormat('ha').format( DateTime.fromMillisecondsSinceEpoch(value.toInt(), isUtc: true) ); return SideTitleWidget( axisSide: meta.axisSide, space: 10, child: Text(dateFormated, style: style), ); } // 其他位置返回空组件,不显示标签 return const SizedBox.shrink(); }, );
额外注意事项
- 时区检查:如果
sensorData中的DateTime是本地时间而非UTC时间,需要移除isUtc: true参数,否则时间格式化会出现偏差。 - 数据有效性:确保
sensorData不为空且至少包含2个数据点,否则首尾标签逻辑无法生效。
内容的提问来源于stack exchange,提问作者Demarily
相关产品推荐
相关产品推荐

