LOTKeyframe.m 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  1. //
  2. // LOTKeyframe.m
  3. // Pods
  4. //
  5. // Created by brandon_withrow on 7/10/17.
  6. //
  7. //
  8. #import "LOTKeyframe.h"
  9. #import "CGGeometry+LOTAdditions.h"
  10. @implementation LOTKeyframe
  11. - (instancetype)initWithKeyframe:(NSDictionary *)keyframe {
  12. self = [super init];
  13. if (self) {
  14. _keyframeTime = keyframe[@"t"];
  15. _inTangent = CGPointZero;
  16. _outTangent = CGPointZero;
  17. _spatialInTangent = CGPointZero;
  18. _spatialOutTangent = CGPointZero;
  19. NSDictionary *timingOutTangent = keyframe[@"o"];
  20. NSDictionary *timingInTangent = keyframe[@"i"];
  21. if (timingInTangent) {
  22. _inTangent = [self _pointFromValueDict:timingInTangent];
  23. }
  24. if (timingOutTangent) {
  25. _outTangent = [self _pointFromValueDict:timingOutTangent];
  26. }
  27. if ([keyframe[@"h"] boolValue]) {
  28. _isHold = YES;
  29. }
  30. if (keyframe[@"to"]) {
  31. NSArray *to = keyframe[@"to"];
  32. _spatialOutTangent = [self _pointFromValueArray:to];
  33. }
  34. if (keyframe[@"ti"]) {
  35. NSArray *ti = keyframe[@"ti"];
  36. _spatialInTangent = [self _pointFromValueArray:ti];
  37. }
  38. id data = keyframe[@"s"];
  39. if (data) {
  40. [self setupOutputWithData:data];
  41. }
  42. }
  43. return self;
  44. }
  45. - (instancetype)initWithValue:(id)value {
  46. self = [super init];
  47. if (self) {
  48. _keyframeTime = @0;
  49. _isHold = YES;
  50. [self setupOutputWithData:value];
  51. }
  52. return self;
  53. }
  54. - (instancetype)initWithLOTKeyframe:(LOTKeyframe *)keyframe {
  55. self = [super init];
  56. if (self) {
  57. _keyframeTime = [keyframe.keyframeTime copy];
  58. _inTangent = keyframe.inTangent;
  59. _outTangent = keyframe.outTangent;
  60. _spatialInTangent = keyframe.spatialInTangent;
  61. _spatialOutTangent = keyframe.spatialOutTangent;
  62. _isHold = keyframe.isHold;
  63. }
  64. return self;
  65. }
  66. - (LOTKeyframe *)copyWithData:(id)data {
  67. LOTKeyframe *newFrame = [[LOTKeyframe alloc] initWithLOTKeyframe:self];
  68. [newFrame setData:data];
  69. return newFrame;
  70. }
  71. - (void)setData:(id)data {
  72. [self setupOutputWithData:data];
  73. }
  74. - (void)remapValueWithBlock:(CGFloat (^)(CGFloat inValue))remapBlock {
  75. _floatValue = remapBlock(_floatValue);
  76. _pointValue = CGPointMake(remapBlock(_pointValue.x), remapBlock(_pointValue.y));
  77. _sizeValue = CGSizeMake(remapBlock(_sizeValue.width), remapBlock(_sizeValue.height));
  78. }
  79. - (void)setupOutputWithData:(id)data {
  80. if ([data isKindOfClass:[NSNumber class]]) {
  81. _floatValue = [(NSNumber *)data floatValue];
  82. }
  83. if ([data isKindOfClass:[NSArray class]] &&
  84. [[(NSArray *)data firstObject] isKindOfClass:[NSNumber class]]) {
  85. NSArray *numberArray = (NSArray *)data;
  86. if (numberArray.count > 0) {
  87. _floatValue = [(NSNumber *)numberArray[0] floatValue];
  88. }
  89. if (numberArray.count > 1) {
  90. _pointValue = CGPointMake(_floatValue = [(NSNumber *)numberArray[0] floatValue],
  91. _floatValue = [(NSNumber *)numberArray[1] floatValue]);
  92. _sizeValue = CGSizeMake(_pointValue.x, _pointValue.y);
  93. }
  94. if (numberArray.count > 3) {
  95. _colorValue = [self _colorValueFromArray:numberArray];
  96. }
  97. _arrayValue = numberArray;
  98. } else if ([data isKindOfClass:[NSArray class]] &&
  99. [[(NSArray *)data firstObject] isKindOfClass:[NSDictionary class]]) {
  100. _pathData = [[LOTBezierData alloc] initWithData:[(NSArray *)data firstObject]];
  101. } else if ([data isKindOfClass:[NSDictionary class]]) {
  102. _pathData = [[LOTBezierData alloc] initWithData:data];
  103. }
  104. }
  105. - (CGPoint)_pointFromValueArray:(NSArray *)values {
  106. CGPoint returnPoint = CGPointZero;
  107. if (values.count > 1) {
  108. returnPoint.x = [(NSNumber *)values[0] floatValue];
  109. returnPoint.y = [(NSNumber *)values[1] floatValue];
  110. }
  111. return returnPoint;
  112. }
  113. - (CGPoint)_pointFromValueDict:(NSDictionary *)values {
  114. NSNumber *xValue = @0, *yValue = @0;
  115. if ([values[@"x"] isKindOfClass:[NSNumber class]]) {
  116. xValue = values[@"x"];
  117. } else if ([values[@"x"] isKindOfClass:[NSArray class]]) {
  118. xValue = values[@"x"][0];
  119. }
  120. if ([values[@"y"] isKindOfClass:[NSNumber class]]) {
  121. yValue = values[@"y"];
  122. } else if ([values[@"y"] isKindOfClass:[NSArray class]]) {
  123. yValue = values[@"y"][0];
  124. }
  125. return CGPointMake([xValue floatValue], [yValue floatValue]);
  126. }
  127. - (UIColor *)_colorValueFromArray:(NSArray<NSNumber *> *)colorArray {
  128. if (colorArray.count == 4) {
  129. BOOL shouldUse255 = NO;
  130. for (NSNumber *number in colorArray) {
  131. if (number.floatValue > 1) {
  132. shouldUse255 = YES;
  133. }
  134. }
  135. return [UIColor colorWithRed:colorArray[0].floatValue / (shouldUse255 ? 255.f : 1.f)
  136. green:colorArray[1].floatValue / (shouldUse255 ? 255.f : 1.f)
  137. blue:colorArray[2].floatValue / (shouldUse255 ? 255.f : 1.f)
  138. alpha:colorArray[3].floatValue / (shouldUse255 ? 255.f : 1.f)];
  139. }
  140. return nil;
  141. }
  142. @end
  143. @implementation LOTKeyframeGroup
  144. - (instancetype)initWithData:(id)data {
  145. self = [super init];
  146. if (self) {
  147. if ([data isKindOfClass:[NSDictionary class]] &&
  148. [(NSDictionary *)data valueForKey:@"k"]) {
  149. [self buildKeyframesFromData:[(NSDictionary *)data valueForKey:@"k"]];
  150. } else {
  151. [self buildKeyframesFromData:data];
  152. }
  153. }
  154. return self;
  155. }
  156. - (void)buildKeyframesFromData:(id)data {
  157. if ([data isKindOfClass:[NSArray class]] &&
  158. [[(NSArray *)data firstObject] isKindOfClass:[NSDictionary class]] &&
  159. [(NSArray *)data firstObject][@"t"]) {
  160. // Array of Keyframes
  161. NSArray *keyframes = (NSArray *)data;
  162. NSMutableArray *keys = [NSMutableArray array];
  163. NSDictionary *previousFrame = nil;
  164. for (NSDictionary *keyframe in keyframes) {
  165. NSMutableDictionary *currentFrame = [NSMutableDictionary dictionary];
  166. if (keyframe[@"t"]) {
  167. // Set time
  168. currentFrame[@"t"] = keyframe[@"t"];
  169. }
  170. if (keyframe[@"s"]) {
  171. // Set Value for Keyframe
  172. currentFrame[@"s"] = keyframe[@"s"];
  173. } else if (previousFrame[@"e"]) {
  174. // Set Value for Keyframe
  175. currentFrame[@"s"] = previousFrame[@"e"];
  176. }
  177. if (keyframe[@"o"]) {
  178. // Set out tangent
  179. currentFrame[@"o"] = keyframe[@"o"];
  180. }
  181. if (previousFrame[@"i"]) {
  182. currentFrame[@"i"] = previousFrame[@"i"];
  183. }
  184. if (keyframe[@"to"]) {
  185. // Set out tangent
  186. currentFrame[@"to"] = keyframe[@"to"];
  187. }
  188. if (previousFrame[@"ti"]) {
  189. currentFrame[@"ti"] = previousFrame[@"ti"];
  190. }
  191. if (keyframe[@"h"]) {
  192. currentFrame[@"h"] = keyframe[@"h"];
  193. }
  194. LOTKeyframe *key = [[LOTKeyframe alloc] initWithKeyframe:currentFrame];
  195. [keys addObject:key];
  196. previousFrame = keyframe;
  197. }
  198. _keyframes = keys;
  199. } else {
  200. LOTKeyframe *key = [[LOTKeyframe alloc] initWithValue:data];
  201. _keyframes = @[key];
  202. }
  203. }
  204. - (void)remapKeyframesWithBlock:(CGFloat (^)(CGFloat))remapBlock {
  205. for (LOTKeyframe *keyframe in _keyframes) {
  206. [keyframe remapValueWithBlock:remapBlock];
  207. }
  208. }
  209. @end
  210. /*
  211. +KeyFrameObject has
  212. + i (PointObject) // Timing curve in tangent
  213. + o (PointObject) // Timing curve out tangent
  214. + n (array of string) // String representation of timing curve
  215. + t (integer) // Keyframe time for start of keyframe
  216. + s (float or array of float or PathObject) // The key information
  217. + e (float or array of float or PathObject) // The end key information
  218. + to (array of float) // For spacial bezier path interpolation, the in tangent
  219. + ti (array of float) // For spacial bezier path interpolation, the out tangent
  220. + h (integer) // If the keyframe is a Hold keyframe or not
  221. */