Charts
Installation
caveui components are copy-paste Jetpack Compose built entirely on Material 3 — there's no caveui dependency to add. Make sure Material 3 is on your classpath (it ships with the Compose BOM), then copy the Usage snippet below into your project.
kotlin
// build.gradle.kts (module)
dependencies {
implementation(platform("androidx.compose:compose-bom:2025.06.00"))
implementation("androidx.compose.material3:material3")
}Usage
kotlin
@Composable
fun Sankey(
flows: List<Triple<Int, Int, Float>> = listOf(
Triple(0, 0, 0.5f), Triple(0, 1, 0.3f),
Triple(1, 1, 0.4f), Triple(1, 2, 0.25f),
),
modifier: Modifier = Modifier,
) {
val reveal by animateFloatAsState(1f, tween(1000, easing = EaseOutCubic), label = "r")
val palette = listOf(Color(0xFF6366F1), Color(0xFF10B981))
Canvas(modifier.fillMaxWidth().height(130.dp)) {
val lx = 12.dp.toPx()
val rx = size.width - 12.dp.toPx()
clipRect(right = lx + (rx - lx) * reveal) {
flows.forEachIndexed { i, (src, dst, w) ->
val y0 = size.height * (0.25f + src * 0.3f)
val y1 = size.height * (0.2f + dst * 0.28f)
val ribbon = Path().apply {
moveTo(lx, y0)
cubicTo((lx + rx) / 2, y0, (lx + rx) / 2, y1, rx, y1)
lineTo(rx, y1 + size.height * w * 0.4f)
cubicTo((lx + rx) / 2, y1 + size.height * w * 0.4f, (lx + rx) / 2, y0 + size.height * w * 0.4f, lx, y0 + size.height * w * 0.4f)
close()
}
drawPath(ribbon, palette[src % 2].copy(alpha = 0.4f))
}
}
listOf(lx, rx).forEach { x ->
drawRoundRect(Color(0xFF111827), Offset(x - 5.dp.toPx(), 0f), Size(10.dp.toPx(), size.height), CornerRadius(3.dp.toPx()))
}
}
}