export function getTickLabelMargins()

in src/axis/axis.ts [321:472]


export function getTickLabelMargins(
    viewport: powerbi.IViewport,
    yMarginLimit: number,
    textWidthMeasurer: ITextAsSVGMeasurer,
    textHeightMeasurer: ITextAsSVGMeasurer,
    axes: CartesianAxisProperties,
    bottomMarginLimit: number,
    properties: TextProperties,
    scrollbarVisible?: boolean,
    showOnRight?: boolean,
    renderXAxis?: boolean,
    renderY1Axis?: boolean,
    renderY2Axis?: boolean): TickLabelMargins /*IMargin - can't update this because custom visuals use it*/ {

    let xAxisProperties: IAxisProperties = axes.x;
    let y1AxisProperties: IAxisProperties = axes.y1;
    let y2AxisProperties: IAxisProperties = axes.y2;

    let xLabels = xAxisProperties.values;
    let y1Labels = y1AxisProperties.values;

    let leftOverflow = 0;
    let rightOverflow = 0;
    let maxWidthY1 = 0;
    let maxWidthY2 = 0;
    let xMax = 0; // bottom margin
    let ordinalLabelOffset = xAxisProperties.categoryThickness ? xAxisProperties.categoryThickness / 2 : 0;
    let scaleIsOrdinal = isOrdinalScale(xAxisProperties.scale);

    let hasHierarchy = !arrayIsEmpty(axes.xStack);

    let xLabelOuterPadding = 0;
    if (xAxisProperties.outerPadding !== undefined) {
        xLabelOuterPadding = xAxisProperties.outerPadding;
    }
    else if (xAxisProperties.xLabelMaxWidth !== undefined) {
        xLabelOuterPadding = Math.max(0, (viewport.width - xAxisProperties.xLabelMaxWidth * xLabels.length) / 2);
    }

    let textHeight: number;
    let rotation;
    if (scrollbarVisible || hasHierarchy)
        rotation = LabelLayoutStrategy.DefaultRotationWithScrollbar;
    else
        rotation = LabelLayoutStrategy.DefaultRotation;

    if (renderY1Axis) {
        for (let i = 0, len = y1Labels.length; i < len; i++) {
            properties.text = y1Labels[i];
            maxWidthY1 = Math.max(maxWidthY1, textWidthMeasurer(properties));
        }
    }

    if (y2AxisProperties && renderY2Axis) {
        let y2Labels = y2AxisProperties.values;
        for (let i = 0, len = y2Labels.length; i < len; i++) {
            properties.text = y2Labels[i];
            maxWidthY2 = Math.max(maxWidthY2, textWidthMeasurer(properties));
        }
    }

    textHeight = textHeightMeasurer(properties);
    let maxNumLines = Math.floor(bottomMarginLimit / textHeight);
    let xScale = xAxisProperties.scale;
    let xDomain = xScale.domain();
    if (renderXAxis && xLabels.length > 0) {
        for (let i = 0, len = xLabels.length; i < len; i++) {
            // find the max height of the x-labels, perhaps rotated or wrapped
            let height: number;
            properties.text = xLabels[i];
            let width = textWidthMeasurer(properties);
            if (xAxisProperties.willLabelsWordBreak) {
                // Split label and count rows
                let wordBreaks = wordBreaker.splitByWidth(properties.text, properties, textWidthMeasurer, xAxisProperties.xLabelMaxWidth, maxNumLines);
                height = wordBreaks.length * textHeight;
                // word wrapping will truncate at xLabelMaxWidth
                width = xAxisProperties.xLabelMaxWidth;
            }
            else if (!xAxisProperties.willLabelsFit && scaleIsOrdinal) {
                height = width * rotation.sine;
                width = width * rotation.cosine;
            }
            else {
                height = TextHeightConstant;
            }

            // calculate left and right overflow due to wide X labels
            // (Note: no right overflow when rotated)
            if (i === 0) {
                if (scaleIsOrdinal) {
                    if (!xAxisProperties.willLabelsFit /*rotated text*/)
                        leftOverflow = width - ordinalLabelOffset - xLabelOuterPadding;
                    else
                        leftOverflow = (width / 2) - ordinalLabelOffset - xLabelOuterPadding;
                    leftOverflow = Math.max(leftOverflow, 0);
                }
                else if (xDomain.length > 1) {
                    // Scalar - do some math
                    let xPos = xScale(xDomain[0]);
                    // xPos already incorporates xLabelOuterPadding, don't subtract it twice
                    leftOverflow = (width / 2) - xPos;
                    leftOverflow = Math.max(leftOverflow, 0);
                }
            } else if (i === len - 1) {
                if (scaleIsOrdinal) {
                    // if we are rotating text (!willLabelsFit) there won't be any right overflow
                    if (xAxisProperties.willLabelsFit || xAxisProperties.willLabelsWordBreak) {
                        // assume this label is placed near the edge
                        rightOverflow = (width / 2) - ordinalLabelOffset - xLabelOuterPadding;
                        rightOverflow = Math.max(rightOverflow, 0);
                    }
                }
                else if (xDomain.length > 1) {
                    // Scalar - do some math
                    let xPos = xScale(xDomain[1]);
                    // xPos already incorporates xLabelOuterPadding, don't subtract it twice
                    rightOverflow = (width / 2) - (viewport.width - xPos);
                    rightOverflow = Math.max(rightOverflow, 0);
                }
            }

            xMax = Math.max(xMax, height);
        }
        // trim any actual overflow to the limit
        leftOverflow = Math.min(leftOverflow, XLabelMaxAllowedOverflow);
        rightOverflow = Math.min(rightOverflow, XLabelMaxAllowedOverflow);
    }

    let rightMargin = 0,
        leftMargin = 0,
        bottomMargin = Math.min(Math.ceil(xMax), bottomMarginLimit);

    if (showOnRight) {
        leftMargin = Math.min(Math.max(leftOverflow, maxWidthY2), yMarginLimit);
        rightMargin = Math.min(Math.max(rightOverflow, maxWidthY1), yMarginLimit);
    }
    else {
        leftMargin = Math.min(Math.max(leftOverflow, maxWidthY1), yMarginLimit);
        rightMargin = Math.min(Math.max(rightOverflow, maxWidthY2), yMarginLimit);
    }

    if (hasHierarchy) {
        bottomMargin += (textHeight + stackedAxisPadding) * (axes.xStack.length - 1);
    }

    return {
        xMax: Math.ceil(bottomMargin),
        yLeft: Math.ceil(leftMargin),
        yRight: Math.ceil(rightMargin),
        stackHeight: textHeight + stackedAxisPadding,
    };
}