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