Search code examples
kotlincanvasgraphicsandroid-jetpack-composecompose-multiplatform

How to draw an intersection of circles in Jetpack Compose


I'm trying to draw an intersection of 2 circles using BlendMode.DstIn on the second one to mask the first one, but the result shows only the first circle without any modifications.

@Composable
fun BlendModeTest() {
    Canvas(
        modifier = Modifier
            .fillMaxSize()
            .graphicsLayer(alpha = 0.99f, compositingStrategy = CompositingStrategy.Offscreen)
    ) {
        drawCircle(Color.Cyan, 300f, Offset(500f, 500f))
        drawCircle(Color.Black, 300f, Offset(700f, 500f), blendMode = BlendMode.DstIn)
    }
}

Expected result: like a lens

Actual: only 1st circle

What am I doing wrong, am I supposed to use different BlendMode?


Solution

  • You are applying BlendMode to black circle. The most it can interact with cyan circle is intersection but left section of cyan circle will remain present because no blend mode is applied to that section.

    Check link below. When blend mode is applied to source image which covers other image depending on which blendmode it is is applied to every pixel.

    https://developer.android.com/reference/android/graphics/PorterDuff.Mode

    You can use paths with PathOperation.Intersection to have desired outcome.

    @Preview
    @Composable
    fun IntersectionTest() {
        
        val path = remember {
            Path()
        }
    
        
        Canvas(
            modifier = Modifier
                .fillMaxSize()
        ) {
    
            if (path.isEmpty) {
    
    
                val tempPath1 = Path().apply {
                    addOval(
                        Rect(
                            radius = 300f,
                            center = Offset(500f, 500f)
                        )
                    )
                }
    
                val tempPath2 = Path().apply {
                    addOval(
                        Rect(
                            radius = 300f,
                            center = Offset(700f, 500f)
                        )
                    )
                }
    
                val diffPath = Path.combine(
                    operation = PathOperation.Intersect,
                    path1 = tempPath1,
                    path2 = tempPath2
                )
    
                path.addPath(diffPath)
    
            }
    
            drawPath(path, color = Color.Cyan)
        }
    }