layout method

  1. @override
void layout(
  1. LayoutExpansion parentLayoutExpansion
)

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);
}