Barrufet
Barrufet

Reputation: 683

How to keep the same color alpha when 2 lines are being overlapped with Canvas

I'm using Canvas with the method drawLines(...) and I have 2 lines crossing/overlapping each other, these lines have a color alpha of 0.3f.

The issue is that when the cross each other this alpha is accumulated, converting their crosspoint with a color alpha of 0.6f.

Is there any way to keep the original alpha even if they cross each other?

Upvotes: 1

Views: 565

Answers (2)

Phil Dukhov
Phil Dukhov

Reputation: 87794

Step 1. create Path from start point, end point and stroke width:

fun linePath(start: Offset, end: Offset, strokeWidth: Float) =
    Path().apply {
        // calculations from https://stackoverflow.com/a/7854359/3585796
        val size = end - start
        val perpendicular = Offset(size.y, -size.x)
        val length = hypot(size.x, size.y)
        val normalized = Offset(perpendicular.x / length, perpendicular.y / length)
        val points = listOf(
            end + normalized * strokeWidth / 2f,
            start + normalized * strokeWidth / 2f,
            start - normalized * strokeWidth / 2f,
            end - normalized * strokeWidth / 2f,
        )
        moveTo(points.last())
        points.forEach(::lineTo)
    }

fun Path.moveTo(offset: Offset) =
    moveTo(offset.x, offset.y)

fun Path.lineTo(offset: Offset) =
    lineTo(offset.x, offset.y)

Step 2. Using clipPath draw needed parts of the lines:

Canvas(Modifier.fillMaxSize()) {
    val rect = Rect(Offset.Zero, size)
    val firstLinePath = linePath(
        start = rect.topLeft,
        end = rect.bottomRight,
        strokeWidth = 20f,
    )
    val firstLineColor = Color.Red
    val secondLinePath = linePath(
        start = rect.topRight,
        end = rect.bottomLeft,
        strokeWidth = 20f,
    )
    val secondLineColor = Color.Green
    val sharedAlpha = 0.5f

    // draw first line without intersection part 
    clipPath(secondLinePath, clipOp = ClipOp.Difference) {
        drawPath(firstLinePath, color = firstLineColor.copy(sharedAlpha))
    }
    // draw second line without intersection part
    clipPath(firstLinePath, clipOp = ClipOp.Difference) {
        drawPath(secondLinePath, color = secondLineColor.copy(sharedAlpha))
    }
    // draw intersection part with mixed color
    clipPath(secondLinePath) {
        val blendedColor = Color(
            ColorUtils.blendARGB(
                firstLineColor.toArgb(),
                secondLineColor.toArgb(),
                0.5f
            )
        )

        drawPath(firstLinePath, color = blendedColor.copy(sharedAlpha))
    }
}

Result:

Upvotes: 1

Richard Onslow Roper
Richard Onslow Roper

Reputation: 6835

No. This will not be possible since we would have to modify the value of alpha of a specific "portion" of the Composable, which is not something achievable easily. You need to change your approach.

Upvotes: 0

Related Questions