juliansteenbakker / community_charts

This project is a fork of google/charts.
Apache License 2.0
89 stars 35 forks source link

Null safety crash #12

Closed pt-rick closed 1 year ago

pt-rick commented 1 year ago

Julian - First, thanks so much for taking this library on. Grateful for your efforts as it appears many else are as well!

This was likely introduced by the migration tool as I had several like instances with similar cases. Following null safety migration, our app is crashing when invoking a PieChart with the following error:

======== Exception caught by rendering library =====================================================
The following _TypeError was thrown during performLayout():
type 'List<ArcRendererElement<dynamic>>' is not a subtype of type 'List<ArcRendererElement<Object>>?' in type cast

The relevant error-causing widget was: 
  PieChart<dynamic> PieChart:file:///C:/Users/Rick/AndroidStudioProjects/pbapp/lib/common/macro-donutchart.dart:43:19
When the exception was thrown, this was the stack: 
#0      TypedRegistry.getAttr (package:community_charts_common/src/common/typed_registry.dart:20:27)
#1      MutableSeries.getAttr (package:community_charts_common/src/chart/common/processed_series.dart:213:48)
#2      ArcRenderer.update.<anonymous closure> (package:community_charts_common/src/chart/pie/arc_renderer.dart:164:18)
#3      List.forEach (dart:core-patch/growable_array.dart:416:8)
#4      ArcRenderer.update (package:community_charts_common/src/chart/pie/arc_renderer.dart:156:16)
#5      BaseChart.onPostLayout.<anonymous closure> (package:community_charts_common/src/chart/common/base_chart.dart:626:37)
#6      _LinkedHashMapMixin.forEach (dart:collection-patch/compact_hash.dart:625:13)
#7      BaseChart.onPostLayout (package:community_charts_common/src/chart/common/base_chart.dart:625:10)
[91 more...]
The following RenderObject was being processed when the exception was fired: ChartContainerRenderObject<dynamic>#f0cd4 NEEDS-LAYOUT NEEDS-PAINT
...  parentData: <none> (can use size)
...  constraints: BoxConstraints(w=232.5, h=190.0)
...  semantic boundary
...  size: MISSING
...  painter: ChartContainerCustomPaint#b6c7e()
RenderObject: ChartContainerRenderObject<dynamic>#f0cd4 NEEDS-LAYOUT NEEDS-PAINT
  parentData: <none> (can use size)
  constraints: BoxConstraints(w=232.5, h=190.0)
  semantic boundary
  size: MISSING
  painter: ChartContainerCustomPaint#b6c7e()
====================================================================================================

It's followed by asserts which I believe are due to it failing the render. e.g.:

======== Exception caught by rendering library =====================================================
The following assertion was thrown during performLayout():
RenderBox was not laid out: ChartContainerRenderObject<dynamic>#f0cd4 NEEDS-PAINT
'package:flutter/src/rendering/box.dart':
Failed assertion: line 1965 pos 12: 'hasSize'

Either the assertion indicates an error in the framework itself, or we should provide substantially more information in this error message to help you determine and fix the underlying cause.
In either case, please report this assertion by filing a bug on GitHub:
  https://github.com/flutter/flutter/issues/new?template=2_bug.yml

The relevant error-causing widget was: 
  PieChart<dynamic> PieChart:file:///C:/Users/Rick/AndroidStudioProjects/pbapp/lib/common/macro-donutchart.dart:43:19
When the exception was thrown, this was the stack: 
#2      RenderBox.size (package:flutter/src/rendering/box.dart:1965:12)
#3      RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:104:65)
#4      RenderObject.layout (package:flutter/src/rendering/object.dart:2493:7)
#5      RenderBox.layout (package:flutter/src/rendering/box.dart:2382:11)
#6      RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:104:21)
#7      RenderObject.layout (package:flutter/src/rendering/object.dart:2493:7)
#8      RenderBox.layout (package:flutter/src/rendering/box.dart:2382:11)
#9      MultiChildLayoutDelegate.layoutChild (package:flutter/src/rendering/custom_layout.dart:173:12)
[80 more...]
(elided 2 frames from class _AssertionError)
The following RenderObject was being processed when the exception was fired: RenderPointerListener#7d528 NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE
...  parentData: <none> (can use size)
...  constraints: BoxConstraints(w=232.5, h=190.0)
...  size: MISSING
...  behavior: deferToChild
...  listeners: down, panZoomStart
  child: ChartContainerRenderObject<dynamic>#f0cd4 NEEDS-PAINT
    parentData: <none> (can use size)
    constraints: BoxConstraints(w=232.5, h=190.0)
    semantic boundary
    size: MISSING
    painter: ChartContainerCustomPaint#b6c7e()
RenderObject: RenderPointerListener#7d528 NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE
  parentData: <none> (can use size)
  constraints: BoxConstraints(w=232.5, h=190.0)
  size: MISSING
  behavior: deferToChild
  listeners: down, panZoomStart
  child: ChartContainerRenderObject<dynamic>#f0cd4 NEEDS-PAINT
    parentData: <none> (can use size)
    constraints: BoxConstraints(w=232.5, h=190.0)
    semantic boundary
    size: MISSING
    painter: ChartContainerCustomPaint#b6c7e()
====================================================================================================

Here's our code invoking the PieChart:

class MacroDonutChart extends StatelessWidget {
  final List<MacroCounts> data;
  final List<charts.Color> palette;
  final bool animate;
  final Function(charts.SelectionModel model) selectCallback;
  final int selectedIndex;

  MacroDonutChart({required this.data, required this.palette, required this.animate, required this.selectCallback, required this.selectedIndex});

  List<charts.Series<MacroCounts, String>> _createSeries(BuildContext context) {
    return [
      charts.Series<MacroCounts, String>(
        id: "MacroDonut",
        data: data,
        domainFn: (MacroCounts macCount, _) => macCount.name,
        measureFn: (MacroCounts macCount, _) => macCount.total,
        labelAccessorFn: (MacroCounts macCount, _) => '${macCount.name}',
        colorFn: (_, index){
          if(selectedIndex == -1 || index == selectedIndex){
            return palette[index!];
          } else {
            return charts.ColorUtil.fromDartColor(Theme.of(context).disabledColor);
          }
          //return palette[index];
        },
      ),
    ];
  }

  @override
  Widget build(BuildContext context) {
    return charts.PieChart(
      _createSeries(context),
      animate: animate,
      selectionModels: [
        charts.SelectionModelConfig(
          type: charts.SelectionModelType.info,
          changedListener: (charts.SelectionModel model) {
            selectCallback(model);
          },
        )
      ],
      defaultRenderer: charts.ArcRendererConfig(
        arcWidth: 22,
        strokeWidthPx: 1,
      ),
    );
  }
}

Flutter doctor: [√] Flutter (Channel stable, 3.13.3, on Microsoft Windows [Version 10.0.19045.3448], locale en-US) • Flutter version 3.13.3 on channel stable at C:\Users\Rick\flutter • Upstream repository https://github.com/flutter/flutter.git • Framework revision 2524052335 (2 weeks ago), 2023-09-06 14:32:31 -0700 • Engine revision b8d35810e9 • Dart version 3.1.1 • DevTools version 2.25.0

Many thanks for looking into this. Rick

pt-rick commented 1 year ago

Looking at the original charts issues, this apparently is a carryover problem. In my case, there is a workaround by specifying the series type on the pie chart.

From... return charts.PieChart( to... return charts.PieChart<String>(