Fix image zoom focal point

This commit is contained in:
iris committed 2026-09-12 20:16:25 -04:00
1 parent 62cb6c91d5
commit 0b4da64062
2 files changed
+67 -5

No files matched your search

@@ -23,6 +23,7 @@ import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.FilterQuality
import androidx.compose.ui.graphics.ImageBitmap
@@ -242,17 +243,28 @@ private fun ZoomableImage(image: ImageBitmap) {
modifier =
Modifier.fillMaxSize()
.pointerInput(Unit) {
detectTransformGestures { _, pan, zoom, _ ->
detectTransformGestures { centroid, pan, zoom, _ ->
// Floor of 1 so the image cannot be pinched smaller than fitted, which is
// already the whole of it; a ceiling so it cannot be lost off-screen.
scale = (scale * zoom).coerceIn(1f, 8f)
if (scale > 1f) {
offsetX += pan.x
offsetY += pan.y
val oldScale = scale
val newScale = (oldScale * zoom).coerceIn(1f, 8f)
if (newScale > 1f) {
val offset =
zoomOffset(
Offset(offsetX, offsetY),
centroid,
pan,
oldScale,
newScale,
Offset(size.width / 2f, size.height / 2f),
)
offsetX = offset.x
offsetY = offset.y
} else {
offsetX = 0f
offsetY = 0f
}
scale = newScale
}
}
.graphicsLayer {
@@ -263,3 +275,16 @@ private fun ZoomableImage(image: ImageBitmap) {
},
)
}
/** Keeps the image point beneath [centroid] beneath the fingers as its scale changes. */
internal fun zoomOffset(
offset: Offset,
centroid: Offset,
pan: Offset,
oldScale: Float,
newScale: Float,
viewportCenter: Offset,
): Offset {
val scaleChange = newScale / oldScale
return offset * scaleChange + (centroid - viewportCenter) * (1f - scaleChange) + pan
}