All Downloads are FREE. Search and download functionalities are using the official Maven repository.

commonMain.jetbrains.datalore.plot.builder.interact.GeomInteractionBuilder.kt Maven / Gradle / Ivy

There is a newer version: 4.5.3-alpha1
Show newest version
/*
 * Copyright (c) 2019. JetBrains s.r.o.
 * Use of this source code is governed by the MIT license that can be found in the LICENSE file.
 */

package jetbrains.datalore.plot.builder.interact

import jetbrains.datalore.plot.base.Aes
import jetbrains.datalore.plot.base.interact.GeomTargetLocator.LookupSpace
import jetbrains.datalore.plot.base.interact.GeomTargetLocator.LookupStrategy
import jetbrains.datalore.plot.builder.tooltip.TooltipSpecification
import jetbrains.datalore.plot.builder.tooltip.TooltipLine
import jetbrains.datalore.plot.builder.tooltip.ValueSource
import jetbrains.datalore.plot.builder.tooltip.MappingValue
import jetbrains.datalore.plot.builder.tooltip.ConstantValue

class GeomInteractionBuilder(private val mySupportedAesList: List>) {
    private var myIgnoreInvisibleTargets: Boolean = false
    lateinit var locatorLookupSpace: LookupSpace
        private set
    lateinit var locatorLookupStrategy: LookupStrategy
        private set
    private var myAxisTooltipVisibilityFromFunctionKind: Boolean = false
    private var myAxisTooltipVisibilityFromConfig: Boolean? = null
    private var myAxisAesFromFunctionKind: List>? = null
    private lateinit var myTooltipAxisAes: List>
    private lateinit var myTooltipAes: List>
    private lateinit var myTooltipOutlierAesList: List>
    private var myTooltipConstantsAesList: Map, Any>? = null
    private var myUserTooltipSpec: TooltipSpecification? = null
    private var myIsCrosshairEnabled: Boolean = false

    val getAxisFromFunctionKind: List>
        get() = myAxisAesFromFunctionKind ?: emptyList()

    val isAxisTooltipEnabled: Boolean
        get() = if (myAxisTooltipVisibilityFromConfig == null)
            myAxisTooltipVisibilityFromFunctionKind
        else
            myAxisTooltipVisibilityFromConfig!!

    val tooltipLines: List
        get() = prepareTooltipValueSources()

    val tooltipProperties: TooltipSpecification.TooltipProperties
        get() = myUserTooltipSpec?.tooltipProperties ?: TooltipSpecification.TooltipProperties.NONE

    val isCrosshairEnabled: Boolean
        get() = myIsCrosshairEnabled

    fun showAxisTooltip(isTrue: Boolean): GeomInteractionBuilder {
        myAxisTooltipVisibilityFromConfig = isTrue
        return this
    }

    fun tooltipAes(aes: List>): GeomInteractionBuilder {
        myTooltipAes = aes
        return this
    }

    fun axisAes(axisAes: List>): GeomInteractionBuilder {
        myTooltipAxisAes = axisAes
        return this
    }

    fun tooltipOutliers(aes: List>): GeomInteractionBuilder {
        myTooltipOutlierAesList = aes
        return this
    }

    fun tooltipConstants(constantsMap:  Map, Any>): GeomInteractionBuilder {
        myTooltipConstantsAesList = constantsMap
        return this
    }

    fun tooltipLinesSpec(tooltipSpec: TooltipSpecification): GeomInteractionBuilder {
        myUserTooltipSpec = tooltipSpec
        return this
    }

    fun setIsCrosshairEnabled(isTrue: Boolean): GeomInteractionBuilder {
        myIsCrosshairEnabled = isTrue
        return this
    }

    fun multilayerLookupStrategy(): GeomInteractionBuilder {
        locatorLookupStrategy = LookupStrategy.NEAREST
        locatorLookupSpace = LookupSpace.XY
        return this
    }

    fun univariateFunction(lookupStrategy: LookupStrategy): GeomInteractionBuilder {
        myAxisAesFromFunctionKind = AES_X
        locatorLookupStrategy = lookupStrategy
        myAxisTooltipVisibilityFromFunctionKind = true
        locatorLookupSpace = LookupSpace.X
        initDefaultTooltips()
        return this
    }

    fun bivariateFunction(area: Boolean): GeomInteractionBuilder {
        myAxisAesFromFunctionKind = AES_XY

        if (area) {
            locatorLookupStrategy = LookupStrategy.HOVER
            myAxisTooltipVisibilityFromFunctionKind = false
        } else {
            locatorLookupStrategy = LookupStrategy.NEAREST
            myAxisTooltipVisibilityFromFunctionKind = true
        }
        locatorLookupSpace = LookupSpace.XY
        initDefaultTooltips()
        return this
    }

    fun none(): GeomInteractionBuilder {
        myAxisAesFromFunctionKind = ArrayList(mySupportedAesList)
        locatorLookupStrategy = LookupStrategy.NONE
        myAxisTooltipVisibilityFromFunctionKind = true
        locatorLookupSpace = LookupSpace.NONE
        initDefaultTooltips()
        return this
    }

    private fun initDefaultTooltips() {
        myTooltipAxisAes = if (!isAxisTooltipEnabled) emptyList() else getAxisFromFunctionKind
        myTooltipAes = mySupportedAesList - getAxisFromFunctionKind
        myTooltipOutlierAesList = emptyList()
    }

    private fun prepareTooltipValueSources(): List {

        return when {
            myUserTooltipSpec == null -> {
                // No user tooltip specification => use default tooltips
                defaultValueSourceTooltipLines(
                    myTooltipAes,
                    myTooltipAxisAes,
                    myTooltipOutlierAesList,
                    userDefinedValueSources = null,
                    constantsMap = myTooltipConstantsAesList
                )
            }
            myUserTooltipSpec!!.tooltipLinePatterns == null -> {
                // No user line patterns => use default tooltips with the given formatted valueSources
                defaultValueSourceTooltipLines(
                    myTooltipAes,
                    myTooltipAxisAes,
                    myTooltipOutlierAesList,
                    myUserTooltipSpec!!.valueSources,
                    myTooltipConstantsAesList
                )
            }
            myUserTooltipSpec!!.tooltipLinePatterns!!.isEmpty() -> {
                // User list is empty => not show tooltips
                emptyList()
            }
            else -> {
                // Form value sources: user list + axis + outliers
                val geomOutliers = myTooltipOutlierAesList.toMutableList()

                // Remove outlier tooltip if the mappedAes is used in the general tooltip
                myUserTooltipSpec!!.tooltipLinePatterns!!.forEach { line ->
                    val userDataAesList = line.fields.filterIsInstance().map { it.aes }
                    geomOutliers.removeAll(userDataAesList)
                }
                val axisValueSources = myTooltipAxisAes.map { aes -> MappingValue(aes, isOutlier = true, isAxis = true) }
                val geomOutlierValueSources = geomOutliers.map { aes ->
                    val formatted = myUserTooltipSpec!!.valueSources.filterIsInstance().find { it.aes == aes }
                    formatted?.toOutlier() ?: MappingValue(aes, isOutlier = true)
                }

                myUserTooltipSpec!!.tooltipLinePatterns!! + (axisValueSources + geomOutlierValueSources).map(TooltipLine.Companion::defaultLineForValueSource)
            }
        }
    }

    fun build(): GeomInteraction {
        return GeomInteraction(this)
    }

    fun ignoreInvisibleTargets(isTrue: Boolean): GeomInteractionBuilder {
        myIgnoreInvisibleTargets = isTrue
        return this
    }

    fun isIgnoringInvisibleTargets(): Boolean {
        return myIgnoreInvisibleTargets
    }


    companion object {
        const val AREA_GEOM = true
        const val NON_AREA_GEOM = false

        private val AES_X = listOf(Aes.X)
        private val AES_XY = listOf(Aes.X, Aes.Y)

        fun defaultValueSourceTooltipLines(
            aesListForTooltip: List>,
            axisAes: List>,
            outliers: List>,
            userDefinedValueSources: List? = null,
            constantsMap: Map, Any>? = null
        ): List {
            val axisValueSources = axisAes.map { aes -> MappingValue(aes, isOutlier = true, isAxis = true) }
            val outlierValueSources = outliers.map { aes ->
                val userDefined = userDefinedValueSources?.filterIsInstance()?.find { it.aes == aes }
                userDefined?.toOutlier() ?: MappingValue(aes, isOutlier = true)
            }
            val aesValueSources = aesListForTooltip.map { aes ->
                val userDefined = userDefinedValueSources?.filterIsInstance()?.find { it.aes == aes }
                userDefined ?: MappingValue(aes)
            }
            val constantValues = constantsMap?.map { (_, value) -> ConstantValue(value, format = null) } ?: emptyList()
            return (aesValueSources + axisValueSources + outlierValueSources + constantValues).map(TooltipLine.Companion::defaultLineForValueSource)
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy