fun arrange()

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