UNPKG

5.05 kBPlain TextView Raw
1/*
2 * Copyright (c) Facebook, Inc. and its affiliates.
3 *
4 * This source code is licensed under the MIT license found in the
5 * LICENSE file in the root directory of this source tree.
6 */
7
8#import "RCTConvert+Transform.h"
9
10static 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