Draw Text within DrawScope - Jetpack Compose Desktop
Asked Answered
A

1

5

I want to draw Text inside a canvas to display a label for a chart.

On Android, I can use the library: https://github.com/tehras/charts (For Compose: 1-alpha03) but on Desktop I can't.

Thus I tried to rewrite the broken parts. But I can't get the labels to display.

Original Code, which I try to change to work with Desktop Source:

    private val textPaint = android.graphics.Paint().apply {
        isAntiAlias = true
        color = labelTextColor.toLegacyInt()
    }
    private val textBounds = android.graphics.Rect()

    override fun drawAxisLabels(
        drawScope: DrawScope,
        canvas: Canvas,
        drawableArea: Rect,
        minValue: Float,
        maxValue: Float
    ) = with(drawScope) {
        val labelPaint = textPaint.apply {
            textSize = labelTextSize.toPx()
            textAlign = android.graphics.Paint.Align.RIGHT
        }
        val minLabelHeight = (labelTextSize.toPx() * labelRatio.toFloat())
        val totalHeight = drawableArea.height
        val labelCount = max((drawableArea.height / minLabelHeight).roundToInt(), 2)

        for (i in 0..labelCount) {
            val value = minValue + (i * ((maxValue - minValue) / labelCount))

            val label = labelValueFormatter(value)
            val x = drawableArea.right - axisLineThickness.toPx() - (labelTextSize.toPx() / 2f)

            labelPaint.getTextBounds(label, 0, label.length, textBounds)

            val y = drawableArea.bottom - (i * (totalHeight / labelCount)) + (textBounds.height() / 2f)

            canvas.nativeCanvas.drawText(label, x, y, labelPaint)
        }
    }

For me, the function at the end NativeCanvas::drawText does not exist on Compose Desktop. I tried to replace all the logic with a TextPainter but nothing was painted.

What could I try to make it work ? or
Are there dependencies I could import from Android to just make it work?

COMPOSE_DESKTOP_VERSION: "0.3.0-build138"
KOTLIN_VERSION: "1.4.21"

Allveta answered 4/1, 2021 at 16:13 Comment(0)
D
10

The Desktop Compose native canvas should have a couple of methods related to drawing text. Instead of canvas.nativeCanvas.drawText, you could try calling canvas.nativeCanvas.drawString(label, x, y, org.jetbrains.skija.Font(), labelPaint).

I got this using version 0.4.0-build177 of Desktop Compose, so YMMV on different versions.

This also comes with a few caveats:

  • If you want to style the text (other than color), you'll have to construct your own Font instance. The empty constructor seems to use some system defaults. I'm still learning the API myself, so I would suggest reading through the documentation (which at the moment is just the code, I think).
  • You might also need to change how you create the Paint since (at least on the version I was using) doesn't support textSize on the Paint - I had to specify this as part of the Font creation.
  • It seems to assume left alignment. A way that I found to get it to work was to use TextLine with the canvas.nativeCanvas.drawTextLine() function:
val textLine = TextLine.make(yourTextString, yourFont)
val xOffset = when (yourTextAlign) {
    // There are probably better ways to handle Start, End, and Justify...
    TextAlign.Left, TextAlign.Start -> 0f
    TextAlign.Right, TextAlign.End -> textLine.width
    TextAlign.Center, TextAlign.Justify -> textLine.width / 2f
}
val actualX = x - xOffset

canvas.nativeCanvas.drawTextLine(textLine, actualX, y, yourPaint)
Dozen answered 10/4, 2021 at 20:30 Comment(2)
Same in Desktop Compose 1.0.0-alpha3Pachysandra
Thanks for this. One more caveat: the computation of xOffset for TextAlign.Start and TextAlign.End should be reversed in a right-to-left layout.Joletta

© 2022 - 2024 — McMap. All rights reserved.