in plot-builder/src/commonMain/kotlin/org/jetbrains/letsPlot/core/plot/builder/tooltip/layout/LayoutManager.kt [33:130]
fun arrange(
tooltips: List<MeasuredTooltip>,
cursorCoord: DoubleVector,
geomBounds: DoubleRectangle,
hAxisTooltipPosition: HorizontalAxisTooltipPosition,
vAxisTooltipPosition: VerticalAxisTooltipPosition
): List<PositionedTooltip> {
myCursorCoord = cursorCoord
myVerticalSpace = DoubleSpan(myViewport.top, myViewport.bottom)
myVerticalAlignmentResolver = VerticalAlignmentResolver(myVerticalSpace)
myHorizontalTooltipSpace = DoubleSpan.withLowerEnd(geomBounds.left, geomBounds.width)
myVerticalTooltipSpace = DoubleSpan.withLowerEnd(geomBounds.top, geomBounds.height)
val desiredPosition = ArrayList<PositionedTooltip>()
// x-axis tooltip
tooltips
.firstOrNull { it.hintKind === X_AXIS_TOOLTIP }
?.let { xAxisTooltip ->
val positionedTooltip = calculateVerticalTooltipPosition(
xAxisTooltip,
preferredAlignment = when {
hAxisTooltipPosition.isBottom -> BOTTOM
hAxisTooltipPosition.isTop -> TOP
else -> error("Axis tooltips with BOTTOM or TOP positions are currently supported.")
},
ignoreCursor = true
)
if (isTooltipWithinBounds(positionedTooltip, geomBounds)) {
desiredPosition.add(positionedTooltip)
// Limit available vertical space for other tooltips by the axis or
// top/bottom side of the tooltip (if not fit under/above the axis)
myVerticalSpace = when {
hAxisTooltipPosition.isBottom -> {
DoubleSpan(
myViewport.top,
min(
positionedTooltip.stemCoord.y,
positionedTooltip.top
)
)
}
hAxisTooltipPosition.isTop -> {
DoubleSpan(
max(
positionedTooltip.stemCoord.y,
positionedTooltip.bottom
),
myViewport.bottom
)
}
else -> error("Axis tooltips with BOTTOM or TOP positions are currently supported.")
}
myVerticalAlignmentResolver = VerticalAlignmentResolver(myVerticalSpace)
}
}
// y-axis tooltip
tooltips
.firstOrNull { it.hintKind === Y_AXIS_TOOLTIP }
?.let {
val preferredAlignment = when {
vAxisTooltipPosition.isLeft -> HorizontalAlignment.LEFT
vAxisTooltipPosition.isRight -> HorizontalAlignment.RIGHT
else -> error("Axis tooltips with LEFT or RIGHT positions are currently supported.")
}
val positionedTooltip = calculateHorizontalTooltipPosition(it, preferredAlignment)
if (isTooltipWithinBounds(positionedTooltip, geomBounds)) {
desiredPosition.add(positionedTooltip)
}
}
// add corner tooltips - if the cursor is located within the visible boundaries
if (geomBounds.contains(cursorCoord)) {
desiredPosition += calculateCornerTooltipsPosition(tooltips)
}
// all other tooltips (axis and corner tooltips are ignored in this method)
desiredPosition += calculateDataTooltipsPosition(
tooltips,
// limit horizontal tooltips by y-axis tooltips
desiredPosition.select(Y_AXIS_TOOLTIP).map(PositionedTooltip::rect)
)
.filter { positionedTooltip ->
// Select tooltips within the visibility bounds
isTooltipWithinBounds(positionedTooltip, geomBounds)
}
// if general tooltips were removed => axis tooltips should also be hidden
if (tooltips.filterNot(::isAxisTooltip).isNotEmpty() && desiredPosition.all(::isAxisTooltip)) {
desiredPosition.clear()
}
return rearrangeWithoutOverlapping(desiredPosition)
}