Skip to content

Instantly share code, notes, and snippets.

@ardakazanci
Created February 15, 2024 18:09
Show Gist options
  • Save ardakazanci/22600c58d30b7af26bf64d94808c6f71 to your computer and use it in GitHub Desktop.
Save ardakazanci/22600c58d30b7af26bf64d94808c6f71 to your computer and use it in GitHub Desktop.
Interactive Canvas for jetpack compose
@Composable
fun InteractiveCanvas(maxWidth: Int, maxHeight: Int) {
val random = remember { Random.Default }
var touchPosition by remember { mutableStateOf(Offset.Unspecified) }
val heartSize = 75F
val heartPath = createHeartPath(heartSize)
val heartOffsets = remember { mutableStateListOf<Offset>() }
val heartColors = remember { mutableStateListOf<Color>() }
if (heartOffsets.isEmpty()) {
for (i in 0 until maxWidth step (heartSize * 2).toInt()) {
for (j in 0 until maxHeight step (heartSize * 2).toInt()) {
val offsetX = i.toFloat() + random.nextFloat() * heartSize - heartSize / 2
val offsetY = j.toFloat() + random.nextFloat() * heartSize - heartSize / 2
heartOffsets.add(Offset(offsetX, offsetY))
val randomColor = Color(
red = random.nextFloat(),
green = random.nextFloat(),
blue = random.nextFloat(),
alpha = 1f
)
heartColors.add(randomColor)
}
}
}
Canvas(
modifier = Modifier
.fillMaxSize()
.pointerInput(Unit) {
detectDragGestures { change, _ ->
touchPosition = change.position
}
}
) {
for ((index, offset) in heartOffsets.withIndex()) {
val pullDistance = 300f
val distance = if (touchPosition == Offset.Unspecified) {
0f
} else {
sqrt((offset.x - touchPosition.x).pow(2) + (offset.y - touchPosition.y).pow(2))
}
val direction = if (touchPosition == Offset.Unspecified) {
Offset.Zero
} else {
Offset(
x = (offset.x - touchPosition.x) / distance,
y = (offset.y - touchPosition.y) / distance
)
}
val moveDistance = if (distance < pullDistance) (pullDistance - distance) * 0.5f else 0f
val movedOffset = offset + direction * moveDistance
drawHeart(heartPath, movedOffset, heartColors[index])
}
}
}
fun DrawScope.drawHeart(heartPath: Path, offset: Offset, color: Color) {
val translatedPath = Path().apply {
addPath(heartPath, offset)
}
clipPath(translatedPath) {
drawPath(
path = translatedPath,
color = color
)
}
}
fun createHeartPath(size: Float): Path {
return Path().apply {
val width = size
val height = size * 0.9f
moveTo(width / 2, height / 4)
cubicTo(0f, 0f, 0f, height, width / 2, height)
cubicTo(width, height, width, 0f, width / 2, height / 4)
close()
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment