Flutter fl_chart LineChart 因超过 4 天的数据差异而出错

问题描述 投票:0回答:1

更具体地说,我遇到的错误是:

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 图表中没有考虑到这一点,我会感到惊讶,但我不确定还可能是什么。

争论切换到另一个图形包 - 想法?

flutter dart graph charts fl-chart
1个回答
0
投票

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];
© www.soinside.com 2019 - 2024. All rights reserved.