layout method
Lays out the chart in horizontal (x) direction.
Evenly divides the available width to all labels (spacing included). First / Last vertical line is at the center of first / last label.
The layout is independent of whether the labels are tilted or not, in the sense that all tilting logic is hidden in LabelContainer, and queried by LabelContainer.layoutSize.
Implementation
@override
void layout(LayoutExpansion parentLayoutExpansion) {
// First clear any children that could be created on nested re-layout
_xLabelContainers = List.empty(growable: true);
ChartOptions options = chartTopContainer.data.chartOptions;
List<String> xUserLabels = chartTopContainer.data.xUserLabels;
double yTicksWidth = options.yContainerOptions.yLeftMinTicksWidth + options.yContainerOptions.yRightMinTicksWidth;
double availableWidth = parentLayoutExpansion.width - yTicksWidth;
double labelMaxAllowedWidth = availableWidth / xUserLabels.length;
_xGridStep = labelMaxAllowedWidth;
int numShownLabels = (xUserLabels.length ~/ labelLayoutStrategy.showEveryNthLabel);
_shownLabelsStepWidth = availableWidth / numShownLabels;
LabelStyle labelStyle = _styleForLabels(options);
// Core layout loop, creates a AxisLabelContainer from each xLabel,
// and lays out the XLabelContainers along X in _gridStepWidth increments.
for (int xIndex = 0; xIndex < xUserLabels.length; xIndex++) {
var xLabelContainer = AxisLabelContainer(
label: xUserLabels[xIndex],
labelMaxWidth: double.infinity,
labelTiltMatrix: labelLayoutStrategy.labelTiltMatrix, // Possibly tilted labels in XContainer
labelStyle: labelStyle,
);
xLabelContainer.layout(LayoutExpansion.unused());
xLabelContainer.skipByParent = !_isLabelOnIndexShown(xIndex);
// Core of X layout calcs - lay out label to find the size that is takes,
// then find X middle of the bounding rectangle
ui.Rect labelBound = ui.Offset.zero & xLabelContainer.layoutSize;
double halfStepWidth = _xGridStep / 2;
double atIndexOffset = _xGridStep * xIndex;
double xTickX = halfStepWidth + atIndexOffset + options.yContainerOptions.yLeftMinTicksWidth;
double labelTopY = options.xContainerOptions.xLabelsPadTB; // down by XContainer padding
xLabelContainer.parentOffsetTick = xTickX;
// tickX and label centers are same. labelLeftTop = label paint start.
var labelLeftTop = ui.Offset(
xTickX - labelBound.width / 2,
labelTopY,
);
// labelLeftTop + offset for envelope
xLabelContainer.applyParentOffset(labelLeftTop + xLabelContainer.tiltedLabelEnvelopeTopLeft);
_xLabelContainers.add(xLabelContainer);
}
// Set the layout size calculated by this layout
layoutSize = ui.Size(
parentLayoutExpansion.width,
xLabelsMaxHeight + 2 * options.xContainerOptions.xLabelsPadTB,
);
if (!chartTopContainer.data.chartOptions.xContainerOptions.isXContainerShown) {
// Before re-layout, return and make the layout height (vertical-Y size) 0.
// We cannot skip the code above entirely, as the xTickX are calculated from labesl, and used late in the
// layout and painting of the DataContainer in ChartContainer - see xTickXs
layoutSize = ui.Size(layoutSize.width, 0.0);
return;
}
// This achieves auto-layout of labels to fit along X axis.
// Iterative call to this layout method, until fit or max depth is reached,
// whichever comes first.
labelLayoutStrategy.reLayout(parentLayoutExpansion);
}