1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 | #import "RCTConvert+Transform.h"
|
9 |
|
10 | static const NSUInteger kMatrixArrayLength = 4 * 4;
|
11 |
|
12 | @implementation RCTConvert (Transform)
|
13 |
|
14 | + (CGFloat)convertToRadians:(id)json
|
15 | {
|
16 | if ([json isKindOfClass:[NSString class]]) {
|
17 | NSString *stringValue = (NSString *)json;
|
18 | if ([stringValue hasSuffix:@"deg"]) {
|
19 | CGFloat degrees = [[stringValue substringToIndex:stringValue.length - 3] floatValue];
|
20 | return degrees * M_PI / 180;
|
21 | }
|
22 | if ([stringValue hasSuffix:@"rad"]) {
|
23 | return [[stringValue substringToIndex:stringValue.length - 3] floatValue];
|
24 | }
|
25 | }
|
26 | return [json floatValue];
|
27 | }
|
28 |
|
29 | + (CATransform3D)CATransform3DFromMatrix:(id)json
|
30 | {
|
31 | CATransform3D transform = CATransform3DIdentity;
|
32 | if (!json) {
|
33 | return transform;
|
34 | }
|
35 | if (![json isKindOfClass:[NSArray class]]) {
|
36 | RCTLogConvertError(json, @"a CATransform3D. Expected array for transform matrix.");
|
37 | return transform;
|
38 | }
|
39 | if ([json count] != kMatrixArrayLength) {
|
40 | RCTLogConvertError(json, @"a CATransform3D. Expected 4x4 matrix array.");
|
41 | return transform;
|
42 | }
|
43 | for (NSUInteger i = 0; i < kMatrixArrayLength; i++) {
|
44 | ((CGFloat *)&transform)[i] = [RCTConvert CGFloat:json[i]];
|
45 | }
|
46 | return transform;
|
47 | }
|
48 |
|
49 | + (CATransform3D)CATransform3D:(id)json
|
50 | {
|
51 | CATransform3D transform = CATransform3DIdentity;
|
52 | if (!json) {
|
53 | return transform;
|
54 | }
|
55 | if (![json isKindOfClass:[NSArray class]]) {
|
56 | RCTLogConvertError(json, @"a CATransform3D. Did you pass something other than an array?");
|
57 | return transform;
|
58 | }
|
59 | // legacy matrix support
|
60 | if ([(NSArray *)json count] == kMatrixArrayLength && [json[0] isKindOfClass:[NSNumber class]]) {
|
61 | RCTLogWarn(@"[RCTConvert CATransform3D:] has deprecated a matrix as input. Pass an array of configs (which can contain a matrix key) instead.");
|
62 | return [self CATransform3DFromMatrix:json];
|
63 | }
|
64 |
|
65 | CGFloat zeroScaleThreshold = FLT_EPSILON;
|
66 |
|
67 | for (NSDictionary *transformConfig in (NSArray<NSDictionary *> *)json) {
|
68 | if (transformConfig.count != 1) {
|
69 | RCTLogConvertError(json, @"a CATransform3D. You must specify exactly one property per transform object.");
|
70 | return transform;
|
71 | }
|
72 | NSString *property = transformConfig.allKeys[0];
|
73 | id value = transformConfig[property];
|
74 |
|
75 | if ([property isEqualToString:@"matrix"]) {
|
76 | transform = [self CATransform3DFromMatrix:value];
|
77 |
|
78 | } else if ([property isEqualToString:@"perspective"]) {
|
79 | transform.m34 = -1 / [value floatValue];
|
80 |
|
81 | } else if ([property isEqualToString:@"rotateX"]) {
|
82 | CGFloat rotate = [self convertToRadians:value];
|
83 | transform = CATransform3DRotate(transform, rotate, 1, 0, 0);
|
84 |
|
85 | } else if ([property isEqualToString:@"rotateY"]) {
|
86 | CGFloat rotate = [self convertToRadians:value];
|
87 | transform = CATransform3DRotate(transform, rotate, 0, 1, 0);
|
88 |
|
89 | } else if ([property isEqualToString:@"rotate"] || [property isEqualToString:@"rotateZ"]) {
|
90 | CGFloat rotate = [self convertToRadians:value];
|
91 | transform = CATransform3DRotate(transform, rotate, 0, 0, 1);
|
92 |
|
93 | } else if ([property isEqualToString:@"scale"]) {
|
94 | CGFloat scale = [value floatValue];
|
95 | scale = ABS(scale) < zeroScaleThreshold ? zeroScaleThreshold : scale;
|
96 | transform = CATransform3DScale(transform, scale, scale, 1);
|
97 |
|
98 | } else if ([property isEqualToString:@"scaleX"]) {
|
99 | CGFloat scale = [value floatValue];
|
100 | scale = ABS(scale) < zeroScaleThreshold ? zeroScaleThreshold : scale;
|
101 | transform = CATransform3DScale(transform, scale, 1, 1);
|
102 |
|
103 | } else if ([property isEqualToString:@"scaleY"]) {
|
104 | CGFloat scale = [value floatValue];
|
105 | scale = ABS(scale) < zeroScaleThreshold ? zeroScaleThreshold : scale;
|
106 | transform = CATransform3DScale(transform, 1, scale, 1);
|
107 |
|
108 | } else if ([property isEqualToString:@"translate"]) {
|
109 | NSArray *array = (NSArray<NSNumber *> *)value;
|
110 | CGFloat translateX = [array[0] floatValue];
|
111 | CGFloat translateY = [array[1] floatValue];
|
112 | CGFloat translateZ = array.count > 2 ? [array[2] floatValue] : 0;
|
113 | transform = CATransform3DTranslate(transform, translateX, translateY, translateZ);
|
114 |
|
115 | } else if ([property isEqualToString:@"translateX"]) {
|
116 | CGFloat translate = [value floatValue];
|
117 | transform = CATransform3DTranslate(transform, translate, 0, 0);
|
118 |
|
119 | } else if ([property isEqualToString:@"translateY"]) {
|
120 | CGFloat translate = [value floatValue];
|
121 | transform = CATransform3DTranslate(transform, 0, translate, 0);
|
122 |
|
123 | } else if ([property isEqualToString:@"skewX"]) {
|
124 | CGFloat skew = [self convertToRadians:value];
|
125 | transform.m21 = tanf(skew);
|
126 |
|
127 | } else if ([property isEqualToString:@"skewY"]) {
|
128 | CGFloat skew = [self convertToRadians:value];
|
129 | transform.m12 = tanf(skew);
|
130 |
|
131 | } else {
|
132 | RCTLogError(@"Unsupported transform type for a CATransform3D: %@.", property);
|
133 | }
|
134 | }
|
135 | return transform;
|
136 | }
|
137 |
|
138 | @end
|