override fun doLayout()

in plot-builder/src/commonMain/kotlin/org/jetbrains/letsPlot/core/plot/builder/layout/axis/label/HorizontalMultilineLabelsLayout.kt [30:103]


    override fun doLayout(
        axisDomain: DoubleSpan,
        axisLength: Double,
    ): AxisLabelsLayoutInfo {

        val boundsByShelfIndex = ArrayList<DoubleRectangle>()
        val ticks = breaks.projectOnAxis(axisDomain, axisLength, isHorizontal = true)
        val boundsList = labelBoundsList(
            ticks, breaks.labels,
            HORIZONTAL_TICK_LOCATION
        )

        val shelfIndexForTickIndex: MutableList<Int> = ArrayList<Int>()
        for (labelBounds in boundsList) {
            // find shelf with no overlap
            var shelfIndex = 0
            while (true) {
                if (boundsByShelfIndex.size == shelfIndex) {
                    // First label on the shelf.
                    boundsByShelfIndex.add(labelBounds)
                    shelfIndexForTickIndex.add(shelfIndex)
                    break
                }

                val shelfBounds = boundsByShelfIndex[shelfIndex]
                // not overlapped?
                if (!shelfBounds.xRange()
                        .connected(DoubleSpan(labelBounds.left - MIN_DISTANCE, labelBounds.right + MIN_DISTANCE))
                ) {
                    shelfIndexForTickIndex.add(shelfIndex)
                    boundsByShelfIndex[shelfIndex] = shelfBounds.union(labelBounds)
                    break
                }

                shelfIndex++
            }
        }

        var bounds = if (boundsByShelfIndex.isEmpty()) {
            DoubleRectangle.ZERO
        } else {
            boundsByShelfIndex[0]
        }
        val h = labelSpec.height() * LINE_HEIGHT
        for ((i, shelfBounds) in boundsByShelfIndex.withIndex()) {
            bounds = bounds.union(shelfBounds.add(DoubleVector(0.0, i * h)))
        }

        val linesCount = boundsByShelfIndex.size
        val labelAdditionalOffsets = labelAdditionalOffsets(
            labelSpec,
            breaks,
            shelfIndexForTickIndex
        ).let { offsets ->
            when (orientation) {
                BOTTOM -> offsets
                else -> offsets.map { DoubleVector(it.x, -it.y) }
            }
        }

        val labelBounds = applyLabelMargins(bounds)
        val verticalAnchor = when (orientation) {
            TOP -> Text.VerticalAnchor.BOTTOM
            else -> Text.VerticalAnchor.TOP
        }
        return AxisLabelsLayoutInfo.Builder()
            .breaks(breaks)
            .bounds(labelBounds)
            .overlap(linesCount > maxLines)
            .labelAdditionalOffsets(labelAdditionalOffsets)
            .labelHorizontalAnchor(Text.HorizontalAnchor.MIDDLE)
            .labelVerticalAnchor(verticalAnchor)
            .build()
    }