0
# Transform Utilities
1
2
Transform utilities for applying transformations with custom origins and creating animated styles with translation effects.
3
4
```typescript
5
import type { TransformsStyle } from "react-native";
6
```
7
8
## Capabilities
9
10
### Transform Types
11
12
```typescript { .api }
13
/**
14
* React Native transform array type
15
*/
16
type RNTransform = Exclude<TransformsStyle["transform"], undefined>;
17
```
18
19
### Transform Origin
20
21
Apply transformations around a custom pivot point instead of the default center.
22
23
```typescript { .api }
24
/**
25
* Apply transformations with custom origin point
26
* @param origin - Origin point for transformations
27
* @param transformations - Array of React Native transform objects
28
* @returns Transform array with origin translations
29
*/
30
function transformOrigin(
31
origin: Vector,
32
transformations: RNTransform
33
): RNTransform;
34
35
/**
36
* Apply 2D transformations with custom origin point
37
* @param origin - Origin point for transformations
38
* @param transformations - Array of 2D transform objects
39
* @returns Transform array with origin translations
40
*/
41
function transformOrigin2d(
42
origin: Vector,
43
transformations: Transforms2d
44
): Transforms2d;
45
```
46
47
**Usage Example:**
48
49
```typescript
50
import { transformOrigin, vec2 } from "react-native-redash";
51
import { useAnimatedStyle, useSharedValue } from "react-native-reanimated";
52
53
export const CustomOriginRotation = () => {
54
const rotation = useSharedValue(0);
55
56
const animatedStyle = useAnimatedStyle(() => {
57
// Rotate around top-left corner instead of center
58
const topLeft = vec2(0, 0);
59
60
const transform = transformOrigin(topLeft, [
61
{ rotate: `${rotation.value}deg` },
62
{ scale: 1.2 }
63
]);
64
65
return { transform };
66
});
67
68
return (
69
<Animated.View
70
style={[
71
{ width: 100, height: 100, backgroundColor: 'blue' },
72
animatedStyle
73
]}
74
/>
75
);
76
};
77
```
78
79
### Translation Hook
80
81
Convenient hook for creating translation-based animated styles.
82
83
```typescript { .api }
84
/**
85
* Hook for translation animations using vector of SharedValues
86
* @param vector - Vector with SharedValue components for x and y translation
87
* @returns Animated style object with translation transform
88
*/
89
function useTranslation(vector: Vector<Animated.SharedValue<number>>): {
90
transform: { translateX: number; translateY: number }[];
91
};
92
```
93
94
**Usage Example:**
95
96
```typescript
97
import { useTranslation, useVector } from "react-native-redash";
98
import { useAnimatedGestureHandler } from "react-native-reanimated";
99
import { PanGestureHandler } from "react-native-gesture-handler";
100
101
export const DraggableElement = () => {
102
const position = useVector(0, 0);
103
const offset = useVector(0, 0);
104
105
// Use the translation hook for convenient styling
106
const translationStyle = useTranslation(position);
107
108
const gestureHandler = useAnimatedGestureHandler({
109
onStart: () => {
110
offset.x.value = position.x.value;
111
offset.y.value = position.y.value;
112
},
113
onActive: (event) => {
114
position.x.value = offset.x.value + event.translationX;
115
position.y.value = offset.y.value + event.translationY;
116
}
117
});
118
119
return (
120
<PanGestureHandler onGestureEvent={gestureHandler}>
121
<Animated.View
122
style={[
123
{ width: 100, height: 100, backgroundColor: 'red' },
124
translationStyle
125
]}
126
/>
127
</PanGestureHandler>
128
);
129
};
130
```
131
132
### Advanced Transform Origin Examples
133
134
```typescript
135
import { transformOrigin, transformOrigin2d, vec2 } from "react-native-redash";
136
import { useAnimatedStyle, useSharedValue } from "react-native-reanimated";
137
138
export const AdvancedTransforms = () => {
139
const rotation = useSharedValue(0);
140
const scale = useSharedValue(1);
141
142
// Rotate around bottom-right corner
143
const bottomRightRotation = useAnimatedStyle(() => {
144
const bottomRight = vec2(100, 100); // Assuming 100x100 element
145
146
return {
147
transform: transformOrigin(bottomRight, [
148
{ rotate: `${rotation.value}deg` }
149
])
150
};
151
});
152
153
// Scale from top-center
154
const topCenterScale = useAnimatedStyle(() => {
155
const topCenter = vec2(50, 0); // Center horizontally, top vertically
156
157
return {
158
transform: transformOrigin(topCenter, [
159
{ scale: scale.value }
160
])
161
};
162
});
163
164
// Combined transformations with custom origin
165
const combinedTransform = useAnimatedStyle(() => {
166
const customOrigin = vec2(75, 25); // 3/4 right, 1/4 down
167
168
return {
169
transform: transformOrigin(customOrigin, [
170
{ rotate: `${rotation.value}deg` },
171
{ scale: scale.value },
172
{ skewX: `${rotation.value * 0.1}deg` }
173
])
174
};
175
});
176
177
// Using 2D transform types
178
const matrix2dTransform = useAnimatedStyle(() => {
179
const origin = vec2(50, 50);
180
181
const transforms = transformOrigin2d(origin, [
182
{ rotateZ: `${rotation.value}deg` },
183
{ scaleX: scale.value },
184
{ scaleY: scale.value * 0.8 }
185
]);
186
187
return { transform: transforms };
188
});
189
190
return (
191
<View style={{ padding: 20 }}>
192
<Animated.View style={[styles.box, bottomRightRotation]} />
193
<Animated.View style={[styles.box, topCenterScale]} />
194
<Animated.View style={[styles.box, combinedTransform]} />
195
<Animated.View style={[styles.box, matrix2dTransform]} />
196
</View>
197
);
198
};
199
```
200
201
### Interactive Transform Origin
202
203
```typescript
204
import React from "react";
205
import { View, StyleSheet } from "react-native";
206
import { transformOrigin, useVector, vec2 } from "react-native-redash";
207
import {
208
useAnimatedGestureHandler,
209
useAnimatedStyle,
210
useSharedValue
211
} from "react-native-reanimated";
212
import { PanGestureHandler, RotationGestureHandler } from "react-native-gesture-handler";
213
214
export const InteractiveTransformOrigin = () => {
215
const rotation = useSharedValue(0);
216
const originPosition = useVector(50, 50); // Center of 100x100 element
217
const elementPosition = useVector(100, 100);
218
219
// Drag to change transform origin
220
const originGestureHandler = useAnimatedGestureHandler({
221
onActive: (event) => {
222
originPosition.x.value = event.x;
223
originPosition.y.value = event.y;
224
}
225
});
226
227
// Rotate the element
228
const rotationGestureHandler = useAnimatedGestureHandler({
229
onActive: (event) => {
230
rotation.value = event.rotation;
231
}
232
});
233
234
// Element style with custom origin
235
const elementStyle = useAnimatedStyle(() => {
236
const origin = vec2(originPosition.x.value, originPosition.y.value);
237
238
return {
239
transform: transformOrigin(origin, [
240
{ rotate: `${rotation.value}rad` }
241
])
242
};
243
});
244
245
// Origin indicator style
246
const originStyle = useAnimatedStyle(() => ({
247
transform: [
248
{ translateX: originPosition.x.value - 5 },
249
{ translateY: originPosition.y.value - 5 }
250
]
251
}));
252
253
return (
254
<View style={styles.container}>
255
{/* Transform origin indicator */}
256
<PanGestureHandler onGestureEvent={originGestureHandler}>
257
<Animated.View style={[styles.origin, originStyle]} />
258
</PanGestureHandler>
259
260
{/* Rotatable element */}
261
<RotationGestureHandler onGestureEvent={rotationGestureHandler}>
262
<Animated.View style={[styles.element, elementStyle]} />
263
</RotationGestureHandler>
264
</View>
265
);
266
};
267
268
const styles = StyleSheet.create({
269
container: {
270
flex: 1,
271
backgroundColor: '#f0f0f0'
272
},
273
element: {
274
position: 'absolute',
275
left: 100,
276
top: 100,
277
width: 100,
278
height: 100,
279
backgroundColor: 'blue',
280
borderRadius: 10
281
},
282
origin: {
283
position: 'absolute',
284
width: 10,
285
height: 10,
286
borderRadius: 5,
287
backgroundColor: 'red',
288
borderWidth: 1,
289
borderColor: 'white'
290
}
291
});
292
```
293
294
### Practical Use Cases
295
296
```typescript
297
import { transformOrigin, vec2 } from "react-native-redash";
298
299
// 1. Clock hands rotating from center-bottom
300
const clockHandStyle = useAnimatedStyle(() => {
301
const handOrigin = vec2(2, 100); // 2px from left (hand width/2), 100px from top (hand length)
302
303
return {
304
transform: transformOrigin(handOrigin, [
305
{ rotate: `${hourAngle.value}deg` }
306
])
307
};
308
});
309
310
// 2. Card flipping from left edge
311
const cardFlipStyle = useAnimatedStyle(() => {
312
const leftEdge = vec2(0, cardHeight / 2);
313
314
return {
315
transform: transformOrigin(leftEdge, [
316
{ rotateY: `${flipAngle.value}deg` }
317
])
318
};
319
});
320
321
// 3. Door opening from hinges
322
const doorStyle = useAnimatedStyle(() => {
323
const hingePoint = vec2(0, doorHeight / 2);
324
325
return {
326
transform: transformOrigin(hingePoint, [
327
{ rotateZ: `${doorAngle.value}deg` }
328
])
329
};
330
});
331
332
// 4. Scaling from bottom (like growing plants)
333
const growthStyle = useAnimatedStyle(() => {
334
const bottomCenter = vec2(elementWidth / 2, elementHeight);
335
336
return {
337
transform: transformOrigin(bottomCenter, [
338
{ scaleY: growthScale.value }
339
])
340
};
341
});
342
```
343
344
**Important Notes:**
345
346
- Transform origin calculations are done by adding translation transforms before and after the main transforms
347
- The pattern is: translate to origin → apply transforms → translate back
348
- Works with both React Native transforms and custom 2D transform types
349
- `useTranslation` is a convenience hook that's equivalent to manually creating translation transforms
350
- All transform origins are relative to the element's coordinate system (0,0 = top-left)