update method

  1. @override
void update(
  1. List<ImmutableSeries<D>> seriesList,
  2. bool isAnimatingThisDraw
)
inherited

Generates rendering data needed to paint the data on the chart.

This is called during the post layout phase of the chart draw cycle.

Implementation

@override
void update(List<ImmutableSeries<D>> seriesList, bool isAnimatingThisDraw) {
  _currentKeys.clear();
  _currentGroupsStackKeys.clear();

  final orderedSeriesList = getOrderedSeriesList(seriesList);

  for (final series in orderedSeriesList) {
    final domainAxis = series.getAttr(domainAxisKey)! as ImmutableAxis<D>;
    final domainFn = series.domainFn;
    final measureAxis = series.getAttr(measureAxisKey)! as ImmutableAxis<num>;
    final measureFn = series.measureFn;
    final colorFn = series.colorFn;
    final dashPatternFn = series.dashPatternFn;
    final fillColorFn = series.fillColorFn;
    final seriesStackKey = series.getAttr(stackKeyKey);
    final barGroupCount = series.getAttr(barGroupCountKey);
    final barGroupIndex = series.getAttr(barGroupIndexKey);
    final previousBarGroupWeight = series.getAttr(previousBarGroupWeightKey);
    final barGroupWeight = series.getAttr(barGroupWeightKey);
    final allBarGroupWeights = series.getAttr(allBarGroupWeightsKey);
    final measureAxisPosition = measureAxis.getLocation(0.0);

    final elementsList = series.getAttr(barElementsKey);

    // Save off domainAxis for getNearest.
    _prevDomainAxis = domainAxis;

    for (var barIndex = 0; barIndex < series.data.length; barIndex++) {
      final Object? datum = series.data[barIndex];
      final details = elementsList![barIndex];
      final domainValue = domainFn(barIndex);

      final measureValue = measureFn(barIndex);
      // TODO: remove this explicit `bool` type when no longer
      // needed to work around
      // https://github.com/dart-lang/language/issues/1785
      final measureIsNull = measureValue == null;
      final measureIsNegative = !measureIsNull && measureValue < 0;

      // Each bar should be stored in barStackMap in a structure that mirrors
      // the visual rendering of the bars. Thus, they should be grouped by
      // domain value, series category (by way of the stack keys that were
      // generated for each series in the preprocess step), and bar group
      // index to account for all combinations of grouping and stacking.
      final barStackMapKey = '$domainValue'
          '__'
          '$seriesStackKey'
          '__'
          '${measureIsNegative ? 'pos' : 'neg'}'
          '__'
          '$barGroupIndex';

      final barKey = '$barStackMapKey${details.barStackIndex}';

      final barStackList = _barStackMap.putIfAbsent(barStackMapKey, () => []);

      // If we already have an AnimatingBar for that index, use it.
      var animatingBar =
          barStackList.firstWhereOrNull((bar) => bar.key == barKey);

      // If we don't have any existing bar element, create a new bar and have
      // it animate in from the domain axis.
      // TODO: Animate bars in the middle of a stack from their
      // nearest neighbors, instead of the measure axis.
      if (animatingBar == null) {
        // If the measure is null and there was no existing animating bar, it
        // means we don't need to draw this bar at all.
        if (!measureIsNull) {
          animatingBar = makeAnimatedBar(
            key: barKey,
            series: series,
            datum: datum,
            barGroupIndex: barGroupIndex!,
            previousBarGroupWeight: previousBarGroupWeight,
            barGroupWeight: barGroupWeight,
            allBarGroupWeights: allBarGroupWeights,
            color: colorFn!(barIndex),
            dashPattern: dashPatternFn!(barIndex),
            details: details as R,
            domainValue: domainFn(barIndex),
            domainAxis: domainAxis,
            domainWidth: domainAxis.rangeBand.round(),
            fillColor: fillColorFn!(barIndex),
            fillPattern: details.fillPattern,
            measureValue: 0.0,
            measureOffsetValue: 0.0,
            measureAxisPosition: measureAxisPosition,
            measureAxis: measureAxis,
            numBarGroups: barGroupCount!,
            strokeWidthPx: details.strokeWidthPx,
            measureIsNull: measureIsNull,
            measureIsNegative: measureIsNegative,
          );

          barStackList.add(animatingBar);
        }
      } else {
        animatingBar
          ..datum = datum
          ..series = series
          ..domainValue = domainValue;
      }

      if (animatingBar == null) {
        continue;
      }

      // Update the set of bars that still exist in the series data.
      _currentKeys.add(barKey);

      // Store off stack keys for each bar group to help getNearest identify
      // groups of stacks.
      _currentGroupsStackKeys
          .putIfAbsent(domainValue, () => <String>{})
          .add(barStackMapKey);

      // Get the barElement we are going to setup.
      // Optimization to prevent allocation in non-animating case.
      final BaseBarRendererElement barElement = makeBarRendererElement(
        barGroupIndex: barGroupIndex!,
        previousBarGroupWeight: previousBarGroupWeight,
        barGroupWeight: barGroupWeight,
        allBarGroupWeights: allBarGroupWeights,
        color: colorFn!(barIndex),
        dashPattern: dashPatternFn!(barIndex),
        details: details as R,
        domainValue: domainFn(barIndex),
        domainAxis: domainAxis,
        domainWidth: domainAxis.rangeBand.round(),
        fillColor: fillColorFn!(barIndex),
        fillPattern: details.fillPattern,
        measureValue: measureValue,
        measureOffsetValue: details.measureOffset!,
        measureAxisPosition: measureAxisPosition,
        measureAxis: measureAxis,
        numBarGroups: barGroupCount!,
        strokeWidthPx: details.strokeWidthPx,
        measureIsNull: measureIsNull,
        measureIsNegative: measureIsNegative,
      );

      animatingBar.setNewTarget(barElement as R);
    }
  }

  // Animate out bars that don't exist anymore.
  _barStackMap.forEach((key, barStackList) {
    for (var barIndex = 0; barIndex < barStackList.length; barIndex++) {
      final bar = barStackList[barIndex];
      if (!_currentKeys.contains(bar.key)) {
        bar.animateOut();
      }
    }
  });
}