export function renderBars()

in packages/charts/src/chart_types/xy_chart/rendering/bars.ts [34:170]


export function renderBars(
  measureText: TextMeasure,
  orderIndex: number,
  dataSeries: DataSeries,
  xScale: ScaleContinuous | ScaleBand,
  yScale: ScaleContinuous,
  panel: Dimensions,
  chartRotation: number,
  minBarHeight: number,
  color: Color,
  isBandedSpec: boolean,
  sharedSeriesStyle: BarSeriesStyle,
  displayValueSettings?: DisplayValueSpec,
  styleAccessor?: BarStyleAccessor,
  stackMode?: StackMode,
): BarTuple {
  const { fontSize, fontFamily } = sharedSeriesStyle.displayValue;
  const initialBarTuple: BarTuple = { barGeometries: [], indexedGeometryMap: new IndexedGeometryMap() } as BarTuple;
  const y1Fn = getY1ScaledValueFn(yScale);
  const y0Fn = getY0ScaledValueFn(yScale);

  return dataSeries.data.reduce((barTuple: BarTuple, datum) => {
    const xScaled = xScale.scale(datum.x);
    if (!xScale.isValueInDomain(datum.x) || Number.isNaN(xScaled)) {
      return barTuple; // don't create a bar if not within the xScale domain
    }
    const { barGeometries, indexedGeometryMap } = barTuple;
    const { y1, initialY1, filled } = datum;

    const y1Scaled = y1Fn(datum);
    const y0Scaled = y0Fn(datum);

    // orientation independent height
    const yDiff = Math.abs(y1Scaled - y0Scaled);
    // amount required to reach the minBarHeight requested
    const addedMinBarHeight = yDiff === 0 || yDiff >= minBarHeight ? 0 : minBarHeight - yDiff;

    // the y coordinate in screen-space.
    const yScreenSpaceCoord =
      Math.min(y1Scaled, y0Scaled) +
      // adding half of the required minBarHeight if banded bar chart
      // and reduce the y coordinate if the Y value is positive to render correctly the increased bar height
      (isBandedSpec ? -addedMinBarHeight / 2 : -addedMinBarHeight * ((y1 ?? 0) >= 0 ? 1 : 0));
    // the actual height of the bar
    const height = yDiff + addedMinBarHeight;

    const seriesIdentifier: XYChartSeriesIdentifier = getSeriesIdentifierFromDataSeries(dataSeries);
    const seriesStyle = getBarStyleOverrides(datum, seriesIdentifier, sharedSeriesStyle, styleAccessor);

    const maxPixelWidth = clamp(seriesStyle.rect.widthRatio ?? 1, 0, 1) * xScale.bandwidth;
    const minPixelWidth = clamp(seriesStyle.rect.widthPixel ?? 0, 0, maxPixelWidth);

    const width = clamp(seriesStyle.rect.widthPixel ?? xScale.bandwidth, minPixelWidth, maxPixelWidth);
    const x = xScaled + xScale.bandwidth * orderIndex + xScale.bandwidth / 2 - width / 2;

    const y1Value = getDatumYValue(datum, false, isBandedSpec, stackMode);
    const formattedDisplayValue = displayValueSettings?.valueFormatter?.(y1Value);

    // only show displayValue for even bars if showOverlappingValue
    const displayValueText =
      displayValueSettings?.isAlternatingValueLabel && barGeometries.length % 2 ? undefined : formattedDisplayValue;

    const { displayValueWidth, fixedFontScale } = computeBoxWidth(displayValueText ?? '', {
      padding: PADDING,
      fontSize,
      fontFamily,
      measureText,
    });

    const isHorizontalRotation = chartRotation % 180 === 0;
    // Pick the right side of the label's box to use as factor reference
    const referenceWidth = Math.max(isHorizontalRotation ? displayValueWidth : fixedFontScale, 1);

    const textScalingFactor = getFinalFontScalingFactor(
      (width * FONT_SIZE_FACTOR) / referenceWidth,
      fixedFontScale,
      fontSize,
    );
    const overflowConstraints: Set<LabelOverflowConstraint> = new Set(
      displayValueSettings?.overflowConstraints ?? [
        LabelOverflowConstraint.ChartEdges,
        LabelOverflowConstraint.BarGeometry,
      ],
    );

    // Based on rotation scale the width of the text box
    const bboxWidthFactor = isHorizontalRotation ? textScalingFactor : 1;

    const displayValue: BarGeometry['displayValue'] | undefined =
      displayValueText && displayValueSettings?.showValueLabel
        ? {
            fontScale: textScalingFactor,
            fontSize: fixedFontScale,
            text: displayValueText,
            width: bboxWidthFactor * displayValueWidth,
            height: textScalingFactor * fixedFontScale,
            overflowConstraints,
          }
        : undefined;

    const barGeometry: BarGeometry = {
      displayValue,
      x,
      y: yScreenSpaceCoord,
      transform: { x: 0, y: 0 },
      width,
      height,
      color,
      value: { x: datum.x, y: y1Value, mark: null, accessor: BandedAccessorType.Y1, datum: datum.datum },
      seriesIdentifier,
      seriesStyle,
      panel,
    };

    if (isBandedSpec) {
      // index also the Y0 value with the same geometry
      indexedGeometryMap.set({
        ...barGeometry,
        value: {
          x: datum.x,
          y: getDatumYValue(datum, true, isBandedSpec, stackMode),
          mark: null,
          accessor: BandedAccessorType.Y0,
          datum: datum.datum,
        },
      });
    }

    indexedGeometryMap.set(barGeometry);

    if (y1 !== null && initialY1 !== null && filled?.y1 === undefined) {
      barGeometries.push(barGeometry);
    }

    return barTuple;
  }, initialBarTuple);
}