更具体地说,我遇到的错误是:
Execution of the command buffer was aborted due to an error during execution. Too much geometry to support memoryless render pass attachments. (0000000d:kIOGPUCommandBufferCallbackErrorOutOfMemoryForParameterBuffer)
这是我一直在测试的一个最小示例:
import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:fl_chart/fl_chart.dart';
import 'package:intl/intl.dart';
class Playground extends HookConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
List<Color> gradientColors = [
Theme.of(context).colorScheme.primary.withOpacity(.5),
Theme.of(context).colorScheme.primary,
];
List<FlSpot> test_spots = [
// FlSpot(
// Timestamp.fromDate(DateTime.now().subtract(const Duration(days: 4))).millisecondsSinceEpoch.toDouble() / 1000,
// 167.0
// )
];
double minx = Timestamp.fromDate(DateTime.now().subtract(const Duration(days: 6))).millisecondsSinceEpoch.toDouble() / 1000;
double maxx = Timestamp.fromDate(DateTime.now()).millisecondsSinceEpoch.toDouble() / 1000;
double miny = 150;
double maxy = 200;
return Padding(
padding: const EdgeInsets.fromLTRB(0, 100, 0, 0),
child: Stack(
children: <Widget>[
AspectRatio(
aspectRatio: 1.70,
child: Padding(
padding: const EdgeInsets.only(
right: 18,
left: 12,
top: 24,
bottom: 12,
),
child: LineChart(
LineChartData(
gridData: FlGridData(
show: true,
drawVerticalLine: true,
horizontalInterval: 1,
verticalInterval: 1,
getDrawingHorizontalLine: (value) {
return const FlLine(
color: Colors.white,
strokeWidth: 1,
);
},
getDrawingVerticalLine: (value) {
return const FlLine(
color: Colors.white,
strokeWidth: 1,
);
},
),
titlesData: const FlTitlesData(
show: true,
rightTitles: AxisTitles(
sideTitles: SideTitles(showTitles: false),
),
topTitles: AxisTitles(
sideTitles: SideTitles(showTitles: false),
),
bottomTitles: AxisTitles(
sideTitles: SideTitles(
showTitles: true,
reservedSize: 30,
getTitlesWidget: bottomTitleWidgets,
),
),
leftTitles: AxisTitles(
sideTitles: SideTitles(
showTitles: true,
getTitlesWidget: leftTitleWidgets,
reservedSize: 42,
),
),
),
borderData: FlBorderData(
show: true,
border: Border.all(color: Theme.of(context).colorScheme.tertiary),
),
minX: minx,
maxX: maxx,
minY: miny,
maxY: maxy,
lineBarsData: [
LineChartBarData(
spots: test_spots,
isCurved: false,
gradient: LinearGradient(
colors: gradientColors,
),
barWidth: 3,
isStrokeCapRound: true,
dotData: const FlDotData(
show: false,
),
belowBarData: BarAreaData(
show: true,
gradient: LinearGradient(
colors: gradientColors
.map((color) => color.withOpacity(0.3))
.toList(),
),
),
),
],
)
),
),
),
],
)
);
}
}
Widget bottomTitleWidgets(double value, TitleMeta meta) {
if(value == meta.min || value == meta.max){
return const Text("");
}
Widget text = Text(
DateFormat('Md').format(DateTime.fromMillisecondsSinceEpoch((value * 1000).round())),
style: TextStyle(
color: Colors.grey[600],
fontSize: 10,
)
);
return SideTitleWidget(
axisSide: meta.axisSide,
child: text,
);
}
Widget leftTitleWidgets(double value, TitleMeta meta) {
return Text(
value.toInt().toString(),
style: TextStyle(
color: Colors.grey[600],
fontSize: 15,
),
textAlign: TextAlign.center
);
}
如果我将
minx
设置为 Timestamp.fromDate(DateTime.now().subtract(const Duration(days: 4))).millisecondsSinceEpoch.toDouble() / 1000;
(4 天而不是 6 天),图表渲染得很好。它并不总是触发,但热重载一两次就应该触发。我也在 IOS(物理设备)上测试是否相关。
关于如何解决这个问题有什么建议吗? 文档示例都没有提供精细的日期时间数据。
我最好的猜测是,由于 DateTime 双精度的较大性质,折线图可能在图表上渲染了太多点,并且没有进行任何平均以减少几何负载 - 例如3 天是 1720744251.983 到 1721003451.983,可以说生成 300 个几何点(明显更多,但让我感到高兴),然后 6 天生成 600 个,而不是平均下降到 300 个,这是渲染失败的截止值。如果 fl 图表中没有考虑到这一点,我会感到惊讶,但我不确定还可能是什么。
争论切换到另一个图形包 - 想法?
re https://github.com/imaNNeo/fl_chart/issues/54
这里的解决方案是在传递到图表之前手动缩放日期值,如下所示:
double dateToDouble(Timestamp d) => d.millisecondsSinceEpoch.toDouble();
double scaleDate(Timestamp d, List<double> minmaxDates) => (dateToDouble(d) - minmaxDates[0]) / (minmaxDates[1] - minmaxDates[0]); // returns a value btw 0 and 1
并使用以下内容取消缩放它们(例如轴标签):
double unscaleDate(double d, List<double> minmaxDates) => d * (minmaxDates[1] - minmaxDates[0]) + minmaxDates[0];