Skip to content

Instantly share code, notes, and snippets.

@JyotimoyKashyap
Created April 19, 2025 18:55
Show Gist options
  • Select an option

  • Save JyotimoyKashyap/e75b5e8885df9cb219bdd29efe697901 to your computer and use it in GitHub Desktop.

Select an option

Save JyotimoyKashyap/e75b5e8885df9cb219bdd29efe697901 to your computer and use it in GitHub Desktop.
Bar Chart
@Composable
fun StackedBarChart(
data: List<Float>,
colors: List<Color>,
) {
val proportions = data.map { it.div(data.sum()) }.filter { it > 0 }.toMutableStateList()
val oldValues = rememberSaveable { mutableListOf<Float>() }
val animatedProportions = List(proportions.size) { remember { Animatable(0f) } }
val visibility = remember { mutableStateOf(false) }
LaunchedEffect(proportions) {
visibility.value = true
animatedProportions.forEachIndexed { index, animate ->
launch {
if(oldValues.getOrNull(index) == null) {
oldValues.add(index, 0f)
}
val startValue = oldValues.getOrElse(index) { 0f }
animate.snapTo(startValue)
animate.animateTo(
targetValue = proportions[index],
animationSpec = tween(
durationMillis = 3000,
easing = FastOutSlowInEasing
)
)
oldValues[index] = proportions[index]
}
}
}
AppTheme {
Column {
Canvas(
modifier = Modifier
.height(15.dp)
.fillMaxWidth(),
) {
var startX = 0f
val cornerRadius = size.height.div(2).dp.toPx()
drawRoundRect(
color = Color.LightGray,
topLeft = Offset(0f, 0f),
size = Size(size.width, size.height),
cornerRadius = CornerRadius(cornerRadius, cornerRadius),
style = Stroke(width = 0.5.dp.toPx(), cap = StrokeCap.Round, join = StrokeJoin.Round)
)
animatedProportions.forEachIndexed { index, proportion ->
val segmentWidth = size.width * proportion.value
val isFirst = index == 0
val isLast = index == proportions.size - 1
val path = Path().apply {
addRoundRect(
RoundRect(
rect = Rect(
offset = Offset(startX, 0f),
size = Size(segmentWidth, size.height)
),
topLeft = if (isFirst) CornerRadius(cornerRadius, cornerRadius) else CornerRadius.Zero,
bottomLeft = if (isFirst) CornerRadius(cornerRadius, cornerRadius) else CornerRadius.Zero,
topRight = if (isLast) CornerRadius(cornerRadius, cornerRadius) else CornerRadius.Zero,
bottomRight = if (isLast) CornerRadius(cornerRadius, cornerRadius) else CornerRadius.Zero
)
)
}
drawPath(path, color = colors[index])
startX += segmentWidth
}
}
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.Start
) {
proportions.forEachIndexed { _, proportion ->
Box(
modifier = Modifier
.weight(proportion)
.height(22.dp)
.padding(start = 4.dp)
) {
this@Row.AnimatedVisibility(
visible = visibility.value,
enter = fadeIn(animationSpec = tween(durationMillis = 3000))
) {
Text(
text = "${(proportion * 100).toInt()}%",
fontSize = MaterialTheme.typography.labelSmall.fontSize,
color = MaterialTheme.colorScheme.onSurface
)
}
}
}
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment