Skip to content

Commit 58b096c

Browse files
add centroid param to updateZoomState for natural zoom calculations
1 parent a3f9215 commit 58b096c

File tree

6 files changed

+112
-82
lines changed

6 files changed

+112
-82
lines changed

image/src/main/java/com/smarttoolfactory/image/beforeafter/BeforeAfterImageImpl.kt

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -166,13 +166,14 @@ internal fun BeforeAfterImageImpl(
166166

167167
val transformModifier = Modifier.pointerInput(Unit) {
168168
detectTransformGestures(
169-
onGesture = { _: Offset, panChange: Offset, zoomChange: Float, _, _, _ ->
169+
onGesture = { centroid: Offset, panChange: Offset, zoomChange: Float, _, _, _ ->
170170

171171
coroutineScope.launch {
172172
zoomState.updateZoomState(
173173
size,
174-
gesturePan = panChange,
175-
gestureZoom = zoomChange
174+
centroid = centroid,
175+
panChange = panChange,
176+
zoomChange = zoomChange
176177
)
177178
}
178179
}

image/src/main/java/com/smarttoolfactory/image/beforeafter/BeforeAfterLayoutImpl.kt

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -86,13 +86,14 @@ internal fun Layout(
8686

8787
val transformModifier = Modifier.pointerInput(Unit) {
8888
detectTransformGestures(
89-
onGesture = { _: Offset, panChange: Offset, zoomChange: Float, _, _, _ ->
89+
onGesture = { centroid: Offset, panChange: Offset, zoomChange: Float, _, _, _ ->
9090

9191
coroutineScope.launch {
9292
zoomState.updateZoomState(
9393
size,
94-
gesturePan = panChange,
95-
gestureZoom = zoomChange
94+
centroid = centroid,
95+
panChange = panChange,
96+
zoomChange = zoomChange
9697
)
9798
}
9899
}

image/src/main/java/com/smarttoolfactory/image/zoom/EnhancedZoomModifier.kt

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -40,12 +40,12 @@ fun Modifier.enhancedZoom(
4040

4141
coroutineScope.launch {
4242
enhancedZoomState.onGesture(
43-
centroid,
44-
pan,
45-
zoom,
46-
rotate,
47-
mainPointer,
48-
pointerList
43+
centroid = centroid,
44+
pan = pan,
45+
zoom = zoom,
46+
rotation = rotate,
47+
mainPointer = mainPointer,
48+
changes = pointerList
4949
)
5050
}
5151

image/src/main/java/com/smarttoolfactory/image/zoom/EnhancedZoomStateImpl.kt

Lines changed: 70 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import com.smarttoolfactory.image.util.coerceIn
1212
import com.smarttoolfactory.image.util.getCropRect
1313
import kotlinx.coroutines.coroutineScope
1414

15-
1615
/**
1716
* * State of the zoom. Allows the developer to change zoom, pan, translate,
1817
* or get current state by
@@ -26,21 +25,23 @@ import kotlinx.coroutines.coroutineScope
2625
*/
2726
open class EnhancedZoomState constructor(
2827
val imageSize: IntSize,
29-
val containerSize: IntSize,
28+
containerSize: IntSize,
3029
initialZoom: Float = 1f,
3130
minZoom: Float = .5f,
3231
maxZoom: Float = 5f,
33-
val flingGestureEnabled: Boolean = true,
34-
val moveToBoundsEnabled: Boolean = true,
32+
flingGestureEnabled: Boolean = true,
33+
moveToBoundsEnabled: Boolean = true,
3534
zoomEnabled: Boolean = true,
3635
panEnabled: Boolean = true,
3736
rotationEnabled: Boolean = false,
3837
limitPan: Boolean = false
39-
) : ZoomState(
38+
) : BaseEnhancedZoomState(
39+
containerSize = containerSize,
4040
initialZoom = initialZoom,
41-
initialRotation = 1f,
4241
minZoom = minZoom,
4342
maxZoom = maxZoom,
43+
flingGestureEnabled = flingGestureEnabled,
44+
moveToBoundsEnabled = moveToBoundsEnabled,
4445
zoomEnabled = zoomEnabled,
4546
panEnabled = panEnabled,
4647
rotationEnabled = rotationEnabled,
@@ -52,8 +53,6 @@ open class EnhancedZoomState constructor(
5253
size = Size(containerSize.width.toFloat(), containerSize.height.toFloat())
5354
)
5455

55-
private val velocityTracker = VelocityTracker()
56-
5756
val enhancedZoomData: EnhancedZoomData
5857
get() = EnhancedZoomData(
5958
zoom = animatableZoom.targetValue,
@@ -63,7 +62,64 @@ open class EnhancedZoomState constructor(
6362
cropRect = calculateRectBounds()
6463
)
6564

66-
private fun getBounds(): Offset {
65+
private fun calculateRectBounds(): Rect {
66+
67+
val width = containerSize.width
68+
val height = containerSize.height
69+
val zoom = animatableZoom.targetValue
70+
val pan = animatablePan.targetValue
71+
72+
// Offset for interpolating offset from (imageWidth/2,-imageWidth/2) interval
73+
// to (0, imageWidth) interval when
74+
// transform origin is TransformOrigin(0.5f,0.5f)
75+
val horizontalCenterOffset = width * (zoom - 1) / 2f
76+
val verticalCenterOffset = height * (zoom - 1) / 2f
77+
78+
val bounds = getBounds()
79+
80+
val offsetX = (horizontalCenterOffset - pan.x.coerceIn(-bounds.x, bounds.x))
81+
.coerceAtLeast(0f) / zoom
82+
val offsetY = (verticalCenterOffset - pan.y.coerceIn(-bounds.y, bounds.y))
83+
.coerceAtLeast(0f) / zoom
84+
85+
val offset = Offset(offsetX, offsetY)
86+
87+
return getCropRect(
88+
bitmapWidth = imageSize.width,
89+
bitmapHeight = imageSize.height,
90+
containerWidth = width.toFloat(),
91+
containerHeight = height.toFloat(),
92+
pan = offset,
93+
zoom = zoom,
94+
rectSelection = rectDraw
95+
)
96+
}
97+
}
98+
99+
open class BaseEnhancedZoomState constructor(
100+
val containerSize: IntSize,
101+
initialZoom: Float = 1f,
102+
minZoom: Float = .5f,
103+
maxZoom: Float = 5f,
104+
val flingGestureEnabled: Boolean = true,
105+
val moveToBoundsEnabled: Boolean = true,
106+
zoomEnabled: Boolean = true,
107+
panEnabled: Boolean = true,
108+
rotationEnabled: Boolean = false,
109+
limitPan: Boolean = false
110+
) : ZoomState(
111+
initialZoom = initialZoom,
112+
initialRotation = 1f,
113+
minZoom = minZoom,
114+
maxZoom = maxZoom,
115+
zoomEnabled = zoomEnabled,
116+
panEnabled = panEnabled,
117+
rotationEnabled = rotationEnabled,
118+
limitPan = limitPan
119+
) {
120+
private val velocityTracker = VelocityTracker()
121+
122+
protected fun getBounds(): Offset {
67123
return getBounds(containerSize)
68124
}
69125

@@ -74,7 +130,7 @@ open class EnhancedZoomState constructor(
74130

75131
open suspend fun onMove(change: PointerInputChange) {}
76132

77-
open suspend fun onUp(change: PointerInputChange) {}
133+
open suspend fun onUp(change: PointerInputChange, onFinish: () -> Unit) {}
78134

79135
/*
80136
Transform Gesture Events
@@ -92,9 +148,10 @@ open class EnhancedZoomState constructor(
92148

93149
updateZoomState(
94150
size = containerSize,
95-
gestureZoom = zoom,
96-
gesturePan = pan,
97-
gestureRotate = rotation
151+
centroid = centroid,
152+
zoomChange = zoom,
153+
panChange = pan,
154+
rotationChange = rotation
98155
)
99156

100157
// Fling Gesture
@@ -161,38 +218,4 @@ open class EnhancedZoomState constructor(
161218
private fun resetTracking() {
162219
velocityTracker.resetTracking()
163220
}
164-
165-
private fun calculateRectBounds(): Rect {
166-
167-
val width = containerSize.width
168-
val height = containerSize.height
169-
val zoom = animatableZoom.targetValue
170-
val pan = animatablePan.targetValue
171-
172-
// Offset for interpolating offset from (imageWidth/2,-imageWidth/2) interval
173-
// to (0, imageWidth) interval when
174-
// transform origin is TransformOrigin(0.5f,0.5f)
175-
val horizontalCenterOffset = width * (zoom - 1) / 2f
176-
val verticalCenterOffset = height * (zoom - 1) / 2f
177-
178-
val bounds = getBounds()
179-
180-
val offsetX = (horizontalCenterOffset - pan.x.coerceIn(-bounds.x, bounds.x))
181-
.coerceAtLeast(0f) / zoom
182-
val offsetY = (verticalCenterOffset - pan.y.coerceIn(-bounds.y, bounds.y))
183-
.coerceAtLeast(0f) / zoom
184-
185-
val offset = Offset(offsetX, offsetY)
186-
187-
val rect = getCropRect(
188-
bitmapWidth = imageSize.width,
189-
bitmapHeight = imageSize.height,
190-
containerWidth = width.toFloat(),
191-
containerHeight = height.toFloat(),
192-
pan = offset,
193-
zoom = zoom,
194-
rectSelection = rectDraw
195-
)
196-
return rect
197-
}
198221
}

image/src/main/java/com/smarttoolfactory/image/zoom/ZoomModifier.kt

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -56,14 +56,15 @@ fun Modifier.zoom(
5656
onGestureEnd = {
5757
onGestureEnd(zoomState.zoomData)
5858
},
59-
onGesture = { _, gesturePan, gestureZoom, gestureRotate, _, _ ->
59+
onGesture = { centroid, pan, zoom, rotation, _, _ ->
6060

6161
coroutineScope.launch {
6262
zoomState.updateZoomState(
6363
size = size,
64-
gestureZoom = gestureZoom,
65-
gesturePan = gesturePan,
66-
gestureRotate = gestureRotate
64+
centroid = centroid,
65+
panChange = pan,
66+
zoomChange = zoom,
67+
rotationChange = rotation
6768
)
6869
}
6970

@@ -164,14 +165,15 @@ fun Modifier.zoom(
164165
onGestureEnd = {
165166
onGestureEnd(zoomState.zoomData)
166167
},
167-
onGesture = { _, gesturePan, gestureZoom, gestureRotate, _, _ ->
168+
onGesture = { centroid, pan, zoom, rotation, _, _ ->
168169

169170
coroutineScope.launch {
170171
zoomState.updateZoomState(
171172
size = size,
172-
gestureZoom = gestureZoom,
173-
gesturePan = gesturePan,
174-
gestureRotate = gestureRotate
173+
centroid = centroid,
174+
panChange = pan,
175+
zoomChange = zoom,
176+
rotationChange = rotation
175177
)
176178
}
177179

@@ -272,14 +274,15 @@ fun Modifier.zoom(
272274
onGestureEnd = {
273275
onGestureEnd(zoomState.zoomData)
274276
},
275-
onGesture = { _, gesturePan, gestureZoom, gestureRotate, _, _ ->
277+
onGesture = { centroid, pan, zoom, rotation, _, _ ->
276278

277279
coroutineScope.launch {
278280
zoomState.updateZoomState(
279281
size = size,
280-
gestureZoom = gestureZoom,
281-
gesturePan = gesturePan,
282-
gestureRotate = gestureRotate
282+
centroid = centroid,
283+
panChange = pan,
284+
zoomChange = zoom,
285+
rotationChange = rotation
283286
)
284287
}
285288

image/src/main/java/com/smarttoolfactory/image/zoom/ZoomStateImpl.kt

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -84,30 +84,32 @@ open class ZoomState(
8484
return Offset(maxX, maxY)
8585
}
8686

87-
open suspend fun updateZoomState(
87+
open suspend fun updateZoomState(
8888
size: IntSize,
89-
gesturePan: Offset,
90-
gestureZoom: Float,
91-
gestureRotate: Float = 1f,
89+
centroid: Offset,
90+
panChange: Offset,
91+
zoomChange: Float,
92+
rotationChange: Float = 1f,
9293
) {
93-
val zoomChange = (zoom * gestureZoom).coerceIn(zoomMin, zoomMax)
94-
snapZoomTo(zoomChange)
95-
val rotationChange = if (rotationEnabled) {
96-
rotation + gestureRotate
94+
val newZoom = (this.zoom * zoomChange).coerceIn(zoomMin, zoomMax)
95+
96+
snapZoomTo(newZoom)
97+
val newRotation = if (rotationEnabled) {
98+
this.rotation + rotationChange
9799
} else {
98100
0f
99101
}
100-
snapRotationTo(rotationChange)
102+
snapRotationTo(newRotation)
101103

102104
if (panEnabled) {
103-
val panChange = pan + gesturePan.times(zoom)
105+
val newPan = this.pan + panChange.times(this.zoom)
104106
val boundPan = limitPan && !rotationEnabled
105107

106108
if (boundPan) {
107109
val bound = getBounds(size)
108110
updateBounds(bound.times(-1f), bound)
109111
}
110-
snapPanTo(panChange)
112+
snapPanTo(newPan)
111113
}
112114
}
113115

0 commit comments

Comments
 (0)