Hello, I am drawing a chart and trying to place a ...
# compose
n
Hello, I am drawing a chart and trying to place a snippet on top of each arc but but next arc overlaps the snippet of previous one. How can I make all snippets being on top of the whole chart? Code in thread
👀 1
Sorry for some math here. But you can ignore and focus on Canvas methods 🙂
Copy code
partitions.forEach { partition ->
    val sweepAngle = partition.sweepAngle

    // Draw Circle
    drawArc(
        startAngle = startAngle,
        sweepAngle = sweepAngle,
        size = arcSize,
        progressBrush = partition.style,
        strokeWidthInPx = progressStrokeWidthInPx
    )

    // Draw Snippet
    val snippet = partition.snippet
    if (snippet != null) {
        val snippetText = snippet.text
        val snippetBackground = snippet.background

        val textWidth = snippetText.rect.width()
        val textHeight = snippetText.rect.height()
        val padding = snippetBackground.paddingInPx

        val angleMidpoint = startAngle + (sweepAngle / 2)
        val angleMidpointInRadians = angleToRadian(angleMidpoint)

        val snippetWidth = textWidth + (padding * 2)
        val snippetHeight = textHeight + (padding * 2)

        // Find polar coordinates of snippet center and convert them to cartesian coordinates
        // A great source for learning about coordinates: <https://varun.ca/polar-coords/>
        val snippetCenterXCoordinate =
            centerX + (((progressStrokeWidthInPx + snippetWidth) / 2) + radius) * cos(angleMidpointInRadians)
        val snippetCenterYCoordinate =
            centerY + (((progressStrokeWidthInPx + snippetHeight) / 2) + radius) * sin(
                angleMidpointInRadians
            )
        // Calculate the snippet so it is drawn based on its center points
        val snippetXCoordinate = snippetCenterXCoordinate - (snippetWidth / 2)
        val snippetYCoordinate = snippetCenterYCoordinate - (snippetHeight / 2)

        val textXCoordinate = snippetXCoordinate + padding
        val textYCoordinate = snippetYCoordinate + textHeight + padding

        // Snippet background stroke
        val snippetStroke = snippetBackground.stroke
        if (snippetStroke != null) {
            drawRoundRect(
                brush = snippetStroke.style,
                x = snippetXCoordinate,
                y = snippetYCoordinate,
                width = snippetWidth,
                height = snippetHeight,
                style = Stroke(width = snippetStroke.widthInPx),
                cornerRadiusInPx = snippetBackground.cornerRadiusInPx
            )
        }

        // Snippet background fill
        drawRoundRect(
            brush = snippetBackground.style,
            x = snippetXCoordinate,
            y = snippetYCoordinate,
            width = snippetWidth,
            height = snippetHeight,
            style = Fill,
            cornerRadiusInPx = snippetBackground.cornerRadiusInPx
        )

        drawLine(
            Color.Red,
            start = Offset(centerX, centerY),
            end = Offset(textXCoordinate, textYCoordinate)
        )
        drawLine(
            Color.Green,
            start = Offset(centerX, centerY),
            end = Offset(snippetCenterXCoordinate, snippetCenterYCoordinate)
        )

        // Snippet text
        drawText(
            x = textXCoordinate,
            y = textYCoordinate,
            value = snippetText.value,
            style = snippetText.style
        )
    }

    startAngle += sweepAngle
}
o
You should draw all your
arcs
in one for-each and snippets in another one, so that all snippets are drawn “after” all
arc
segments.
n
Thanks @Oleksandr Balan yeah I know that’s one solution but can I achieve the same using BlendMode or something like this?
z
Im actually working on something similar myself! I havent really figured out a perfect approach yet, but my thinking is that you could use the previous snippets location to determine the offset for the current one (if any). That by itself will probably look awkward since it always pushes them to the right, but you could follow the same practice to figure out which ones will overlap, and then push the previous one 50% to the left, and the current one 50% to the right. Hope that makes sense 😅 In theory that should work unless Im missing something fundamental.
n
Thanks, that sounds a bit more complex than having 2 for each loops 😄 For now I went for 2 for each but thanks for the heads up, I’ll deffo consider 🙂
z
Yeah Im hoping for a simpler solution as well, but its really not that complicated when you think about it! I guess Ill see once I get back to working on this myself 😁 Does two for loops work? I understand that theyre drawn at the end of each slice that way, but in your picture the slices end so close to each other - Id think that theyre still drawn on top of each other?
Oh, whoops. Ill just.. homer disappear