preprocessSeries method
Pre-calculates some details for the series that will be needed later during the drawing phase.
Implementation
@override
void preprocessSeries(List<MutableSeries<D>> seriesList) {
var stackIndex = 0;
_hasMeasureBounds = seriesList.any(
(series) =>
series.measureUpperBoundFn != null &&
series.measureLowerBoundFn != null,
);
for (final series in seriesList) {
final colorFn = series.colorFn;
final areaColorFn = series.areaColorFn;
final domainFn = series.domainFn;
final measureFn = series.measureFn;
final strokeWidthPxFn = series.strokeWidthPxFn;
series.dashPatternFn ??= (_) => config.dashPattern;
final dashPatternFn = series.dashPatternFn!;
final styleSegments = <_LineRendererElement<D>>[];
var styleSegmentsIndex = 0;
final usedKeys = <String>{};
// Configure style segments for each series.
String? previousSegmentKey;
_LineRendererElement<D>? currentDetails;
for (var index = 0; index < series.data.length; index++) {
final domain = domainFn(index);
final measure = measureFn(index);
if (domain == null || measure == null) {
continue;
}
final color = colorFn!(index);
final areaColor = areaColorFn!(index);
final dashPattern = dashPatternFn(index);
final strokeWidthPx =
strokeWidthPxFn?.call(index)?.toDouble() ?? config.strokeWidthPx;
// Create a style key for this datum, and then compare it to the
// previous datum.
//
// Compare strokeWidthPx to 2 decimals of precision. Any less and you
// can't see any difference in the canvas anyways.
final strokeWidthPxRounded = (strokeWidthPx * 100).round() / 100;
var styleKey = '${series.id}__${styleSegmentsIndex}__$color'
'__${dashPattern}__$strokeWidthPxRounded';
if (styleKey != previousSegmentKey) {
// If we have a repeated style segment, update the repeat index and
// create a new key.
// TODO: Paint repeated styles with multiple clip regions.
if (usedKeys.isNotEmpty && usedKeys.contains(styleKey)) {
styleSegmentsIndex++;
styleKey = '${series.id}__${styleSegmentsIndex}__$color'
'__${dashPattern}__$strokeWidthPxRounded';
}
// Make sure that the previous style segment extends to the current
// domain value. This will ensure that the style of the line changes
// right at the point of the datum that changes the style.
if (currentDetails != null) {
currentDetails.domainExtent.includePoint(domain);
}
// Create a new style segment.
currentDetails = _LineRendererElement<D>(
color: color,
areaColor: areaColor,
dashPattern: dashPattern,
domainExtent: _Range<D>(domain, domain),
strokeWidthPx: strokeWidthPx,
styleKey: styleKey,
roundEndCaps: config.roundEndCaps,
);
styleSegments.add(currentDetails);
usedKeys.add(styleKey);
previousSegmentKey = styleKey;
} else {
// Extend the range of the current segment to include the current
// domain value.
currentDetails!.domainExtent.includePoint(domain);
}
}
series
..setAttr(styleSegmentsKey, styleSegments)
..setAttr(lineStackIndexKey, stackIndex);
if (config.stacked) {
stackIndex++;
}
}
if (config.includePoints) {
_pointRenderer.preprocessSeries(seriesList);
}
// If we are stacking, generate new stacking measure offset functions for
// each series. Each datum should have a measure offset consisting of the
// sum of the measure and measure offsets of each datum with the same domain
// value in series below it in the stack. The first series will be treated
// as the bottom of the stack.
if (config.stacked && seriesList.isNotEmpty) {
var curOffsets = _createInitialOffsetMap(seriesList[0]);
var nextOffsets = <D, num>{};
for (var i = 0; i < seriesList.length; i++) {
final series = seriesList[i];
final measureOffsetFn = _createStackedMeasureOffsetFunction(
series,
curOffsets,
nextOffsets,
);
if (i > 0) {
series.measureOffsetFn = measureOffsetFn;
}
curOffsets = nextOffsets;
nextOffsets = <D, num>{};
}
}
}