Reputation: 115
I'm trying to build a similar chart in Jetpack compose to the one from the screenshot. Let's assume that instead of those labels I'm trying to draw squares ( which should be icons actually but it does not change the problem). I managed to draw all the arches but when I draw the squares they are not possitioned as I would like them to be The issue is that the square is drawn from the top left corner. And it works fine if they are drawn from 0 to 90 degrees (clockwise). But how I can reposition the squares as if from 90 to 180 degrees they are drawn from the top right, from 180 to 270 they are drawn from the bottom right and from 270 to 360 they are drawn from bottom left.
Currently I have the following code for drawing the squares
val angle = spendingChartItem.startAngle + spendingChartItem.archAngle / 2f
val offset = Offset(
drawScope.center.x + (circleInnerRadius + chartBarWidth.toPx() / 2) * cos(
angle.degreeToRadians
),
drawScope.center.y + (circleInnerRadius + chartBarWidth.toPx() / 2) * sin(
angle.degreeToRadians
)
)
drawRect(
color = Color.Red,
size = androidx.compose.ui.geometry.Size(24f,24f),
topLeft = offset
)
Upvotes: 3
Views: 1244
Reputation: 67248
You need to take size of rectangle or image into consideration while setting position via angle.
val rectWidth = 20.dp.toPx()
drawRect(
color = Color.Red,
size = Size(rectWidth, rectWidth),
topLeft = Offset(
-rectWidth / 2 + center.x + (radius + strokeWidth) * cos(
angleInRadians
),
-rectWidth / 2 + center.y + (radius + strokeWidth) * sin(
angleInRadians
)
)
)
Full sample
@Preview
@Composable
private fun PieChartWithLabels() {
Box(
modifier = Modifier
.fillMaxSize(),
contentAlignment = Alignment.Center
) {
val chartDataList = listOf(
ChartData(Pink400, 10f),
ChartData(Orange400, 20f),
ChartData(Yellow400, 15f),
ChartData(Green400, 5f),
ChartData(Blue400, 50f),
)
Canvas(
modifier = Modifier
.fillMaxWidth(.7f)
.aspectRatio(1f)
) {
val width = size.width
val radius = width / 2f
val strokeWidth = 20.dp.toPx()
var startAngle = -90f
for (index in 0..chartDataList.lastIndex) {
val chartData = chartDataList[index]
val sweepAngle = chartData.data.asAngle
val angleInRadians = (startAngle + sweepAngle / 2).degreeToAngle
drawArc(
color = chartData.color,
startAngle = startAngle,
sweepAngle = sweepAngle,
useCenter = false,
topLeft = Offset(strokeWidth / 2, strokeWidth / 2),
size = Size(width - strokeWidth, width - strokeWidth),
style = Stroke(strokeWidth)
)
val rectWidth = 20.dp.toPx()
drawRect(
color = Color.Red,
size = Size(rectWidth, rectWidth),
topLeft = Offset(
-rectWidth / 2 + center.x + (radius + strokeWidth) * cos(
angleInRadians
),
-rectWidth / 2 + center.y + (radius + strokeWidth) * sin(
angleInRadians
)
)
)
startAngle += sweepAngle
}
}
}
}
private val Float.degreeToAngle
get() = (this * Math.PI / 180f).toFloat()
@Immutable
data class ChartData(val color: Color, val data: Float)
Upvotes: 1