Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

radar chart crash #882

Closed
nodelinker opened this issue Jan 25, 2022 · 7 comments · Fixed by #1076
Closed

radar chart crash #882

nodelinker opened this issue Jan 25, 2022 · 7 comments · Fixed by #1076

Comments

@nodelinker
Copy link

nodelinker commented Jan 25, 2022

fl_chart 4.1.0 if you got one RawDataSet and values are same.

E/DartVM ( 5843): Exhausted heap space, trying to allocate 268435464 bytes.

════════ Exception caught by rendering library ═════════════════════════════════
The following OutOfMemoryError was thrown during paint():
Out of Memory

radarchart sample code

import 'package:flutter/material.dart';

const gridColor = Color(0xff68739f);
const titleColor = Color(0xff8c95db);
const fashionColor = Color(0xffe15665);
const artColor = Color(0xff63e7e5);
const boxingColor = Color(0xff83dea7);
const entertainmentColor = Colors.white70;
const offRoadColor = Color(0xFFFFF59D);

class RadarChartSample1 extends StatefulWidget {
  const RadarChartSample1({Key? key}) : super(key: key);

  @override
  _RadarChartSample1State createState() => _RadarChartSample1State();
}

class _RadarChartSample1State extends State<RadarChartSample1> {
  int selectedDataSetIndex = -1;

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.all(16.0),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          GestureDetector(
            onTap: () {
              setState(() {
                selectedDataSetIndex = -1;
              });
            },
            child: Text(
              'Categories'.toUpperCase(),
              style: const TextStyle(
                color: titleColor,
                fontSize: 32,
                fontWeight: FontWeight.w300,
              ),
            ),
          ),
          const SizedBox(height: 4),
          Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: rawDataSets()
                .asMap()
                .map((index, value) {
                  final isSelected = index == selectedDataSetIndex;
                  return MapEntry(
                    index,
                    GestureDetector(
                      onTap: () {
                        setState(() {
                          selectedDataSetIndex = index;
                        });
                      },
                      child: AnimatedContainer(
                        duration: const Duration(milliseconds: 300),
                        margin: const EdgeInsets.symmetric(vertical: 2),
                        height: 26,
                        decoration: BoxDecoration(
                          color: isSelected
                              ? gridColor.withOpacity(0.5)
                              : Colors.transparent,
                          borderRadius: BorderRadius.circular(46),
                        ),
                        padding: const EdgeInsets.symmetric(
                            vertical: 4.0, horizontal: 6),
                        child: Row(
                          mainAxisSize: MainAxisSize.min,
                          children: [
                            AnimatedContainer(
                              duration: const Duration(milliseconds: 400),
                              curve: Curves.easeInToLinear,
                              padding: EdgeInsets.all(isSelected ? 8 : 6),
                              decoration: BoxDecoration(
                                color: value.color,
                                shape: BoxShape.circle,
                              ),
                            ),
                            const SizedBox(width: 8),
                            AnimatedDefaultTextStyle(
                              duration: const Duration(milliseconds: 300),
                              curve: Curves.easeInToLinear,
                              style: TextStyle(
                                color: isSelected ? value.color : gridColor,
                              ),
                              child: Text(value.title),
                            ),
                          ],
                        ),
                      ),
                    ),
                  );
                })
                .values
                .toList(),
          ),
          AspectRatio(
            aspectRatio: 1.3,
            child: RadarChart(
              RadarChartData(
                radarTouchData: RadarTouchData(
                    touchCallback: (FlTouchEvent event, response) {
                  if (!event.isInterestedForInteractions) {
                    setState(() {
                      selectedDataSetIndex = -1;
                    });
                    return;
                  }
                  setState(() {
                    selectedDataSetIndex =
                        response?.touchedSpot?.touchedDataSetIndex ?? -1;
                  });
                }),
                dataSets: showingDataSets(),
                radarBackgroundColor: Colors.transparent,
                borderData: FlBorderData(show: false),
                radarBorderData: const BorderSide(color: Colors.transparent),
                titlePositionPercentageOffset: 0.2,
                titleTextStyle:
                    const TextStyle(color: titleColor, fontSize: 14),
                getTitle: (index) {
                  switch (index) {
                    case 0:
                      return 'Mobile or Tablet';
                    case 2:
                      return 'Desktop';
                    case 1:
                      return 'TV';
                    default:
                      return '';
                  }
                },
                tickCount: 1,
                ticksTextStyle:
                    const TextStyle(color: Colors.transparent, fontSize: 10),
                tickBorderData: const BorderSide(color: Colors.transparent),
                gridBorderData: const BorderSide(color: gridColor, width: 2),
              ),
              swapAnimationDuration: const Duration(milliseconds: 400),
            ),
          ),
        ],
      ),
    );
  }

  List<RadarDataSet> showingDataSets() {
    return rawDataSets().asMap().entries.map((entry) {
      var index = entry.key;
      var rawDataSet = entry.value;

      final isSelected = index == selectedDataSetIndex
          ? true
          : selectedDataSetIndex == -1
              ? true
              : false;

      return RadarDataSet(
        fillColor: isSelected
            ? rawDataSet.color.withOpacity(0.2)
            : rawDataSet.color.withOpacity(0.05),
        borderColor:
            isSelected ? rawDataSet.color : rawDataSet.color.withOpacity(0.25),
        entryRadius: isSelected ? 3 : 2,
        dataEntries:
            rawDataSet.values.map((e) => RadarEntry(value: e)).toList(),
        borderWidth: isSelected ? 2.3 : 2,
      );
    }).toList();
  }

  List<RawDataSet> rawDataSets() {
    return [
      RawDataSet(
        title: 'Fashion',
        color: fashionColor,
        values: [
          50,
          50,
          50,
        ],
      ),
      // RawDataSet(
      //   title: 'Art & Tech',
      //   color: artColor,
      //   values: [
      //     250,
      //     100,
      //     200,
      //   ],
      // ),
      // RawDataSet(
      //   title: 'Entertainment',
      //   color: entertainmentColor,
      //   values: [
      //     200,
      //     150,
      //     50,
      //   ],
      // ),
      // RawDataSet(
      //   title: 'Off-road Vehicle',
      //   color: offRoadColor,
      //   values: [
      //     150,
      //     200,
      //     150,
      //   ],
      // ),
      // RawDataSet(
      //   title: 'Boxing',
      //   color: boxingColor,
      //   values: [
      //     100,
      //     250,
      //     100,
      //   ],
      // ),
    ];
  }
}```

class RawDataSet {
  final String title;
  final Color color;
  final List<double> values;

  RawDataSet({
    required this.title,
    required this.color,
    required this.values,
  });
}
`


The relevant error-causing widget was
RadarChart
lib\radar_sample.dart:104
When the exception was thrown, this was the stack
#0      new _List (dart:core-patch/array.dart)
#1      List._allocateData (dart:core-patch/growable_array.dart:363:16)
#2      List._grow (dart:core-patch/growable_array.dart:370:19)
#3      List._growToNextCapacity (dart:core-patch/growable_array.dart:390:5)
#4      RadarChartPainter.drawTicks
package:fl_chart/…/radar_chart/radar_chart_painter.dart:97
#5      RadarChartPainter.paint
package:fl_chart/…/radar_chart/radar_chart_painter.dart:58
#6      RenderRadarChart.paint
package:fl_chart/…/radar_chart/radar_chart_renderer.dart:75
#7      RenderObject._paintWithContext
package:flutter/…/rendering/object.dart:2403
#8      PaintingContext.paintChild
package:flutter/…/rendering/object.dart:189
#9      RenderProxyBoxMixin.paint
package:flutter/…/rendering/proxy_box.dart:140
#10     RenderObject._paintWithContext
package:flutter/…/rendering/object.dart:2403
#11     PaintingContext.paintChild
package:flutter/…/rendering/object.dart:189
@nodelinker
Copy link
Author

image
cause is the values same, there will got a infinite loop.

@imaNNeo
Copy link
Owner

imaNNeo commented Feb 11, 2022

Any reproducible code?

@owjoh
Copy link

owjoh commented Jun 28, 2022

Having the same issue when all RadarEntry have the same value.

@ateich
Copy link
Contributor

ateich commented Jun 30, 2022

I'm able to reproduce the issue with the following code:

import 'package:fl_chart/fl_chart.dart';
import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      home: Scaffold(
        body: Center(
          child: UsageRadarChart(),
        ),
      ),
    );
  }
}

class UsageRadarChart extends StatelessWidget {
  const UsageRadarChart({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return SizedBox(
      width: 300,
      height: 300,
      child: RadarChart(
        RadarChartData(
          dataSets: [
            RadarDataSet(
              dataEntries: [
                const RadarEntry(value: 10),
                const RadarEntry(value: 10),
                const RadarEntry(value: 10),
              ],
            ),
          ],
        ),
      ),
    );
  }
}

@ateich
Copy link
Contributor

ateich commented Jun 30, 2022

Found an infinite loop

I'll start working on a fix and submit a pull request as soon as I can

ateich added a commit to ateich/fl_chart that referenced this issue Jun 30, 2022
If the max and min values in a RadarDataSet are equal, the `drawTicks` method in `radar_chart_painter.dart` will enter an infinite loop.

This is due to a for loop that fails to be incremented if the max and min values are equal, causing the loop to never meet its exit condition.

I have replaced the for loop with one that will always exit.

Resolves imaNNeo#882
imaNNeo pushed a commit that referenced this issue Jul 1, 2022
If the max and min values in a RadarDataSet are equal, the `drawTicks` method in `radar_chart_painter.dart` will enter an infinite loop.

This is due to a for loop that fails to be incremented if the max and min values are equal, causing the loop to never meet its exit condition.

I have replaced the for loop with one that will always exit.

Resolves #882
@codertiany
Copy link

Hi, I have the same problem too.
When will a new version be released @imaNNeoFighT

@imaNNeo
Copy link
Owner

imaNNeo commented Aug 3, 2022

Fixed in 0.55.1. Check it out!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants