I have such a bar chart and want to show a tooltip...
# compose
n
I have such a bar chart and want to show a tooltip when click on any item. How do I implement click listener for Canvas?
Copy code
Canvas(
    Modifier
        .fillMaxWidth()
        .height(88.dp)
        .padding(horizontal = TRTheme.spacing.default)
) {
    var xOffset = 0f
    val containerWidth = size.width - (2 * (proportions.size - 1)).dp.toPx()
    proportions.forEachIndexed { i, proportion ->
        val itemWidth = containerWidth * proportion / 100
        drawRoundRect(
            color = colors[i],
            size = Size(itemWidth, 88.dp.toPx()),
            cornerRadius = CornerRadius(4.dp.toPx(), 4.dp.toPx()),
            topLeft = Offset(xOffset, 0f)
        )
        xOffset += itemWidth + 2.dp.toPx()
    }
}
I have a list of percentages like
listOf(50, 25, 12.5, 12.5)
and want to show the respective percentage in a tooltip when clicking. E.g. if I click on the first box, I want to see
%50
, etc
z
You can use
pointerInput
with
detectTapGestures
, but it’s probably better to make each rectangle a separate composable and then apply the
clickable
modifier to each – that way you get things like accessibility, focus, etc. for free.
n
You mean I shouldn't use Canvas?
z
I think it’s going to end up being a lot more work to use canvas
n
Hmm it depends, how would you draw a pie chart without Canvas?
s
A pie chart is different, e.g. you need to draw arcs. However, the chart shown in the image is simple and it could be implemented with a
Row
and `Spacer`s with their own
Modifier.weight
Copy code
Row(
    horizontalArrangement = Arrangement.spacedBy(2.dp),
    modifier = Modifier
        .fillMaxWidth()
        .height(88.dp)
        .padding(horizontal = TRTheme.spacing.default)
) {
    proportions.forEachIndexed { i, proportion ->
        Spacer(
            modifier = Modifier
                .clickable {
                    println("clicked: $i, $proportion")
                }
                .background(color = colors[i], shape = RoundedCornerShape(4.dp))
                .weight(proportion / 100)
                .fillMaxWidth()
        )
    }
}
n
Yes, my question, if this would be a pie chart how could I achieve to implement click listener? Because this is just a prototype, I might also be exposed to implement pie chart instead
s
In that case, you'd need a
Canvas
. Otherwise, you could create a custom
Shape
to draw an arc (but I don't know how that would play with
clickable
):
Copy code
class ArcShape(/* your params */) : Shape {
    override fun createOutline(
        size: Size,
        layoutDirection: LayoutDirection,
        density: Density
    ): Outline {
        return Outline.Generic(
            path = Path().apply { 
                addArc(/* stuff */)
            }
        )
    }
}
I honestly think the
Canvas
approach is better
z
You can do it with a canvas, but you also need to handle semantics yourself then. For more complex charts you'd probably have to do that anyway though.