Compose Charts

repository·master·Indexed 21 days ago

https://github.com/ehsannarmani/composecharts

A Kotlin Multiplatform library for creating charts in Jetpack Compose, supporting Android, Desktop, iOS, and WasmJS. It provides components like ColumnChart, RowChart, and LineChart with extensive customization options for animations, axis properties, bar and dot styling, grid lines, indicators, labels, and interactive popups.

Tokens
11.4K
Snippets
35
Records
39
Agent score
75%

What's inside Compose Charts

  1. Use LabelMode.OnPie for Pie Chart Labeling

    master

    The LabelMode.OnPie() mode allows you to display labels directly on or around the pie slices. It supports two types of labels:

    1. Outer Label: Displays the slice's label outside the slice, connected by a guide line.
    2. Inner Label: Displays content inside the slice (defaults to the slice percentage).

    Configuration Options for LabelMode.OnPie()

    ParameterDescriptionDefault
    outerLineSizeLength of the guide line (radial segment to horizontal segment).12.dp to 16.dp
    outerLineStyleAppearance of the guide line (width, stroke style, etc.).Stroke(width = 1.5.dp)
    innerLabelStyleText style for the inner label.White, 12.sp, Bold
    showCallback to determine if a slice should show labels.{ true }
    innerLabelContentControls the content inside the slice.PieInnerLabelContent.Percentage()
    animationSpecAnimation used when labels appear.tween(300, delayMillis = 100)

    Customizing Inner Label Content

    Use PieInnerLabelContent to change what is displayed inside the slice:

    • PieInnerLabelContent.Custom { pie -> ... }: Provide a custom string based on the Pie object.
    • PieInnerLabelContent.Percentage { percentage -> ... }: Provide a custom string based on the calculated percentage.
    // Custom text content
    labelMode = LabelMode.OnPie(
        innerLabelContent = PieInnerLabelContent.Custom { pie -> "Hello ${pie.id}" }
    )
    
    // Custom percentage formatting
    labelMode = LabelMode.OnPie(
        innerLabelContent = PieInnerLabelContent.Percentage { percentage -> "${percentage} of total" }
    )
  2. How IndicatorCount works: CountBased vs StepBased

    master

    The count property accepts an IndicatorCount type, which determines how the indicator values are calculated between the chart's minimum and maximum values:

    • CountBased: Divides the range to ensure exactly the requested number of indicators are shown.
    • StepBased: Uses a stepBy value to split the range. It starts from the maximum value and subtracts the step until it reaches the minimum value (e.g., if max is 20, min is -10, and step is 5, indicators will be 20, 15, 10, 5, 0, -5, -10).
    // CountBased example
    count = IndicatorCount.CountBased(count = 5)
    
    // StepBased example (conceptual)
    // count = IndicatorCount.StepBased(stepBy = 5.0)
  3. Configure animation modes for Row, Column, and Line charts

    master

    You can control how animations are executed in RowChart, ColumnChart, and LineChart using the animationMode parameter. This allows you to decide whether animations happen sequentially, simultaneously, or not at all.

    Available modes:

    • AnimationMode.OneByOne: Animations run sequentially. For example, in a LineChart, each line will finish its drawing animation before the next one begins.
    • AnimationMode.Together: Animations run asynchronously. You can provide a delayBuilder to stagger the start of each animation relative to the previous one.
    • AnimationMode.None: Disables all animations.
    // Sequential animations
    LineChart(
        ...,
        animationMode = AnimationMode.OneByOne
    )
    
    // Staggered animations (each starts 200ms after the previous one)
    LineChart(
       ...,
       animationMode = AnimationMode.Together(delayBuilder = { index -> index * 200 })
    )
  4. Handle negative values in ColumnChart

    master

    The ColumnChart supports negative values. You can explicitly define the scale of the chart using maxValue and minValue parameters.

    Default Behavior:

    • maxValue: Defaults to the highest value in the provided data.
    • minValue:
      • If all values are $\ge 0$, minValue defaults to 0.
      • If there are values $< 0$, minValue defaults to -maxValue.
    ColumnChart(
        data = remember {
            listOf(
                Bars(
                    label = "1",
                    values = listOf(
                        Bars.Data(value = -40.0, color = Color.Blue)
                    )
                ),
                Bars(
                    label = "2",
                    values = listOf(
                        Bars.Data(value = 50.0, color = Color.Blue)
                    )
                )
            )
        },
        maxValue = 75.0,
        minValue = -75.0
    )
  5. Show Pie Chart Labels Conditionally

    master

    Use the show parameter within LabelMode.OnPie() to control label visibility. This is useful for hiding labels on small slices or only showing labels for selected items to maintain readability.

    PieChart(
        ...,
        labelMode = LabelMode.OnPie(
            show = { pie ->
                pie.id == selectedPie?.id
            }
        )
    )
        PieChart(
            ...,
            labelMode = LabelMode.OnPie(
                show = { pie ->
                    pie.id == selectedPie?.id
                }
            )
        )
  6. Implement a basic LineChart

    master

    Use the LineChart composable to render one or more lines. Each line is defined by a Line object containing a label, a list of values, and styling options like color and drawStyle. You can control the animation of the lines using animationMode.

    LineChart(
        modifier = Modifier.fillMaxSize().padding(horizontal = 22.dp),
        data = remember {
            listOf(
                Line(
                    label = "Windows",
                    values = listOf(28.0, 41.0, 5.0, 10.0, 35.0),
                    color = SolidColor(Color(0xFF23af92)),
                    firstGradientFillColor = Color(0xFF2BC0A1).copy(alpha = .5f),
                    secondGradientFillColor = Color.Transparent,
                    strokeAnimationSpec = tween(2000, easing = EaseInOutCubic),
                    gradientAnimationDelay = 1000,
                    drawStyle = DrawStyle.Stroke(width = 2.dp),
                )
            )
        },
        animationMode = AnimationMode.Together(delayBuilder = {
            it * 500L
        }),
    )
  7. Stagger animations using AnimationMode.Together

    master

    To create a staggered animation effect where each element starts its animation after a specific delay relative to the previous element, use AnimationMode.Together with a delayBuilder. The delayBuilder is a lambda that receives the current index of the animation and returns a delay in milliseconds.

    For example, delayBuilder = { index -> index * 200 } will cause the first animation to start at 0ms, the second at 200ms, the third at 400ms, and so on.

    LineChart(
       ...,
       animationMode = AnimationMode.Together(delayBuilder = { index -> index * 200 })
    )
  8. Implement a Pie Chart

    master

    Use the PieChart component to render a pie chart. You provide a list of Pie data objects, which include a label, data value, color, and selectedColor. You can handle user interaction via the onPieClick callback to manage selection states.

    var data by remember {
        mutableStateOf(
            listOf(
                Pie(label = "Android", data = 20.0, color = Color.Red, selectedColor = Color.Green),
                Pie(label = "Windows", data = 45.0, color = Color.Cyan, selectedColor = Color.Blue),
                Pie(label = "Linux", data = 35.0, color = Color.Gray, selectedColor = Color.Yellow),
            )
        )
    }
    PieChart(
        modifier = Modifier.size(200.dp),
        data = data,
        onPieClick = {
            val pieIndex = data.indexOf(it)
            data = data.mapIndexed { mapIndex, pie -> pie.copy(selected = pieIndex == mapIndex) }
        },
        selectedScale = 1.2f,
        style = Pie.Style.Fill
    )
    var data by remember {
        mutableStateOf(
            listOf(
                Pie(label = "Android", data = 20.0, color = Color.Red, selectedColor = Color.Green),
                Pie(label = "Windows", data = 45.0, color = Color.Cyan, selectedColor = Color.Blue),
                Pie(label = "Linux", data = 35.0, color = Color.Gray, selectedColor = Color.Yellow),
            )
        )
    }
    PieChart(
        modifier = Modifier.size(200.dp),
        data = data,
        onPieClick = {
            println("${it.label} Clicked")
            val pieIndex = data.indexOf(it)
            data = data.mapIndexed { mapIndex, pie -> pie.copy(selected = pieIndex == mapIndex) }
        },
        selectedScale = 1.2f,
        scaleAnimEnterSpec = spring<Float>(
            dampingRatio = Spring.DampingRatioMediumBouncy,
            stiffness = Spring.StiffnessLow
        ),
        colorAnimEnterSpec = tween(300),
        colorAnimExitSpec = tween(300),
        scaleAnimExitSpec = tween(300),
        spaceDegreeAnimExitSpec = tween(300),
        style = Pie.Style.Fill
    )