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

commonMain.com.aay.compose.lineChart.components.DefaultLines.kt Maven / Gradle / Ivy

The newest version!
package com.aay.compose.lineChart.components

import androidx.compose.animation.core.Animatable
import androidx.compose.animation.core.AnimationVector1D
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.Path
import androidx.compose.ui.graphics.drawscope.DrawScope
import androidx.compose.ui.graphics.drawscope.Stroke
import androidx.compose.ui.graphics.drawscope.clipRect
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.ExperimentalTextApi
import androidx.compose.ui.text.TextMeasurer
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.times
import com.aay.compose.lineChart.model.LineParameters
import com.aay.compose.utils.clickedOnThisPoint
import com.aay.compose.utils.formatToThousandsMillionsBillions

private var lastClickedPoint: Pair? = null

@OptIn(ExperimentalTextApi::class)
internal fun DrawScope.drawDefaultLineWithShadow(
    line: LineParameters,
    lowerValue: Float,
    upperValue: Float,
    animatedProgress: Animatable,
    spacingX: Dp,
    spacingY: Dp,
    clickedPoints: MutableList>,
    textMeasure: TextMeasurer,
    xRegionWidth: Dp,
) {

    val strokePathOfDefaultLine = drawLineAsDefault(
        lineParameter = line,
        lowerValue = lowerValue,
        upperValue = upperValue,
        animatedProgress = animatedProgress,
        spacingY = spacingY,
        clickedPoints = clickedPoints,
        textMeasure = textMeasure,
        xRegionWidth = xRegionWidth
    )

    if (line.lineShadow) {
        val fillPath = strokePathOfDefaultLine.apply {
            lineTo(size.width - xRegionWidth.toPx() + 40.dp.toPx(), size.height * 40)
            lineTo(spacingX.toPx() * 2, size.height * 40)
            close()
        }
        clipRect(right = size.width * animatedProgress.value) {
            drawPath(
                path = fillPath, brush = Brush.verticalGradient(
                    colors = listOf(line.lineColor.copy(alpha = .3f), Color.Transparent),
                    endY = (size.height.toDp() - spacingY).toPx()
                )
            )
        }
    }
}

@OptIn(ExperimentalTextApi::class)
private fun DrawScope.drawLineAsDefault(
    lineParameter: LineParameters,
    lowerValue: Float,
    upperValue: Float,
    animatedProgress: Animatable,
    spacingY: Dp,
    clickedPoints: MutableList>,
    textMeasure: TextMeasurer,
    xRegionWidth: Dp,
) = Path().apply {
    val height = size.height.toDp()
    drawPathLineWrapper(
        lineParameter = lineParameter,
        strokePath = this,
        animatedProgress = animatedProgress,
    ) { lineParameter, index ->

        val yTextLayoutResult = textMeasure.measure(
            text = AnnotatedString(upperValue.formatToThousandsMillionsBillions()),
        ).size.width

        val info = lineParameter.data[index]
        val ratio = (info - lowerValue) / (upperValue - lowerValue)
        val startXPoint = (yTextLayoutResult * 1.5.toFloat().toDp()) + (index * xRegionWidth)
        val startYPoint =
            (height.toPx() + 8.dp.toPx() - spacingY.toPx() - (ratio * (height.toPx() - spacingY.toPx())))

        val tolerance = 20.dp.toPx()
        val savedClicks =
            clickedOnThisPoint(clickedPoints, startXPoint.toPx(), startYPoint, tolerance)


        if (savedClicks) {
            if (lastClickedPoint != null) {
                clickedPoints.clear()
                lastClickedPoint = null
            } else {
                lastClickedPoint = Pair(startXPoint.toPx(), startYPoint.toFloat())
                circleWithRectAndText(
                    x = startXPoint,
                    y = startYPoint,
                    textMeasure = textMeasure,
                    info = info,
                    stroke = Stroke(width = 2.dp.toPx()),
                    line = lineParameter,
                    animatedProgress = animatedProgress
                )
            }
        }

        if (index == 0) {
            moveTo(startXPoint.toPx(), startYPoint.toFloat())
        } else {
            lineTo(startXPoint.toPx(), startYPoint.toFloat())
        }
    }
}





© 2015 - 2025 Weber Informatics LLC | Privacy Policy