I'm trying to create a pie chart in Jetpack Compose. I'm trying to make corners round for each Pie in the Chart. But, I'm having issues making corner rounds. I tried using cap = StrokeCap.Round
in drawArc
in canvas, but did not get any luck making just the corners rounds.
This is what I have so far, and the result looks like this. As you can see the corners of each pies are rectangle. Is there a way to make them round?
@Composable
fun Chart() {
Canvas(
modifier = Modifier
.fillMaxWidth()
.aspectRatio(1f)
) {
drawIntoCanvas {
val width = size.width
val radius = width / 2f
val strokeWidth = radius * .3f
var startAngle = 0f
val items = listOf(25f, 25f, 25f, 25f, 25f, 25f, 25f, 25f)
items.forEach {
val sweepAngle = it.toAngle
drawArc(
color = Color.Gray,
startAngle = startAngle,
sweepAngle = sweepAngle - 5,
useCenter = false,
topLeft = Offset(strokeWidth / 2, strokeWidth / 2),
size = Size(width - strokeWidth, width - strokeWidth),
style = Stroke(strokeWidth)
)
startAngle += sweepAngle
}
}
}
}
private val Float.toAngle: Float
get() = this * 180 / 100
@Preview(showBackground = true)
@Composable
fun GreetingPreview() {
MyApplicationTheme {
Chart()
}
}
Iβm trying to make it so the arc looks like this
I found a workaround by drawing two arcs one with style = Fill
and one with style = Stroke
. Hope this helps someone.
Another way to do it without using stroke is to do it using complex trig. That includes converting between polar and cartesian.
Using these formulas and given outer/inner radius and angle you can calculate all 4 corners of an arc.
x1 = r1 cos (π)
y1 = r1 sin (π)
x2 = r2 cos (π)
y3 = r2 sin (π)
where radius = r1 = outerRadius, r2 = innerRadius and π = Math.toRadians(sweepAngle)
using the math above you should be able to find x and y
points of an arc.
then using Path
you can draw
Path().apply{
moveTo(x, y) // start of arc in top left - rounded edge
arcTo(Rect(..), startAngle, sweepAngle, false) // or you can use `quadTo` or `curveTo` but you'll have to find control points
quadTo(..) // to draw the rounded corner - top right
lineTo(..) // line to next point - bottom right
quadTo(..) // draw rounded corner in bottom right
arcTo() // inner arc to bottom left corner - rounded edge
quadTo() // bottom left corner
lineTo() // line to top left corner
quadTo() // top left corner
close()
}
// Example with stroke..
@Composable
fun Chart() {
Canvas(
modifier = Modifier
.fillMaxWidth()
.aspectRatio(1f)
) {
drawIntoCanvas {
val width = size.width
val radius = width / 2f
val innerRadius = radius - 40f
var startAngle = 0f
val center = Offset(size.width / 2f, size.height / 2f)
val items = listOf(25f, 25f, 25f, 25f, 25f, 25f, 25f, 25f)
items.forEach {
val sweepAngle = it.toAngle
val path = Path().apply{
drawArc(
Rect(
center.x - radius,
center.y - radius,
center.x + radius,
center.y + radius
),
startAngle,
sweepAngle,
false
)
drawArc(
Rect(
center.x - innerRadius,
center.y - innerRadius,
center.x + innerRadius,
center.y + innerRadius
),
startAngle + sweepAngle,
-sweepAngle,
false
)
}
drawPath(path, Color.Red, style = Fill)
drawPath(path, Color.Red, style = Stroke(30f, StrokeCap.Round, StrokeJoin.Round))
startAngle += sweepAngle
}
}
}
}