RCTConvert+Transform.m 5.3 KB

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