Skip to content

Instantly share code, notes, and snippets.

@gabrielbmoro
Last active March 12, 2023 00:39
Show Gist options
  • Save gabrielbmoro/4dec8c025ac107152da59aa03ffce3e2 to your computer and use it in GitHub Desktop.
Save gabrielbmoro/4dec8c025ac107152da59aa03ffce3e2 to your computer and use it in GitHub Desktop.
PieChart example using compose
package com.example.composecharts.ui.widgets
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.core.AnimationSpec
import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.animation.core.tween
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.material.Button
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.drawBehind
import androidx.compose.ui.geometry.Size
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import kotlin.math.roundToInt
data class PieDataItem(
val color: Color,
val label: String,
val value: Float
)
@Composable
private fun ChartLegend(
data: List<PieDataItem>,
modifier: Modifier
) {
val items = data.sortedBy { it.label }
Column {
Text(
text = "LEGEND",
style = MaterialTheme.typography.caption.copy(
fontSize = 16.sp,
fontWeight = FontWeight.Bold
)
)
items.forEach {
Row(modifier = Modifier.padding(4.dp)) {
Spacer(modifier = modifier.drawBehind {
drawRect(it.color, size = Size(40.dp.toPx(), 20.dp.toPx()))
})
Text(
"${it.label} - ${(it.value * 100f).roundToInt()}%",
modifier = Modifier.padding(horizontal = 50.dp)
)
}
}
}
}
@Composable
private fun PieChart(
items: List<PieDataItem>,
animationSpec: AnimationSpec<Float>,
isChartVisible: Boolean
) {
val sortedItems = items.sortedBy { it.value }
var startAngle = 0f
Box(
modifier = Modifier.size(200.dp)
) {
sortedItems.forEach { dataItem ->
val sweepValue = animateFloatAsState(
animationSpec = animationSpec,
targetValue = if (isChartVisible) dataItem.value * 360f else 0f
).value
Spacer(
modifier = Modifier
.size(200.dp)
.drawBehind {
drawArc(
color = dataItem.color,
startAngle = startAngle,
sweepAngle = sweepValue,
useCenter = true,
)
startAngle += sweepValue
}
.align(Alignment.Center)
)
}
}
}
@Composable
fun PieChartExample(data: List<PieDataItem>, modifier: Modifier = Modifier) {
var isChartVisible by remember { mutableStateOf(false) }
Column(
modifier = modifier
.background(Color.White)
.fillMaxSize(),
) {
Button(
onClick = {
isChartVisible = isChartVisible.not()
}
) {
val label = if (isChartVisible) "Hide" else "Show"
Text("$label Pie Chart")
}
PieChart(
items = data,
animationSpec = tween(
1200,
100
),
isChartVisible = isChartVisible
)
AnimatedVisibility(
visible = isChartVisible,
enter = fadeIn(
animationSpec = tween(
durationMillis = 1200,
delayMillis = 600
)
),
exit = fadeOut(
animationSpec = tween(
durationMillis = 1200,
delayMillis = 600
)
)
) {
ChartLegend(data, modifier)
}
}
}
@Preview
@Composable
fun PieChartExamplePreview() {
MaterialTheme {
PieChartExample(
data = listOf(
PieDataItem(value = 0.15f,/*15%*/color = Color.Red, label = "Red"),
PieDataItem(value = 0.05f, /*5%*/color = Color.Blue, label = "Blue"),
PieDataItem(value = 0.3f, /*30%*/color = Color.Green, label = "Green"),
PieDataItem(value = 0.25f, /*25%*/color = Color.Magenta, label = "Magenta"),
PieDataItem(value = 0.25f, /*25%*/ color = Color.Gray, label = "Gray")
)
)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment