123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243 |
- //
- // LOTKeyframe.m
- // Pods
- //
- // Created by brandon_withrow on 7/10/17.
- //
- //
- #import "LOTKeyframe.h"
- #import "CGGeometry+LOTAdditions.h"
- @implementation LOTKeyframe
- - (instancetype)initWithKeyframe:(NSDictionary *)keyframe {
- self = [super init];
- if (self) {
- _keyframeTime = keyframe[@"t"];
- _inTangent = CGPointZero;
- _outTangent = CGPointZero;
- _spatialInTangent = CGPointZero;
- _spatialOutTangent = CGPointZero;
- NSDictionary *timingOutTangent = keyframe[@"o"];
- NSDictionary *timingInTangent = keyframe[@"i"];
- if (timingInTangent) {
- _inTangent = [self _pointFromValueDict:timingInTangent];
- }
- if (timingOutTangent) {
- _outTangent = [self _pointFromValueDict:timingOutTangent];
- }
- if ([keyframe[@"h"] boolValue]) {
- _isHold = YES;
- }
- if (keyframe[@"to"]) {
- NSArray *to = keyframe[@"to"];
- _spatialOutTangent = [self _pointFromValueArray:to];
- }
- if (keyframe[@"ti"]) {
- NSArray *ti = keyframe[@"ti"];
- _spatialInTangent = [self _pointFromValueArray:ti];
- }
- id data = keyframe[@"s"];
- if (data) {
- [self setupOutputWithData:data];
- }
- }
- return self;
- }
- - (instancetype)initWithValue:(id)value {
- self = [super init];
- if (self) {
- _keyframeTime = @0;
- _isHold = YES;
- [self setupOutputWithData:value];
- }
- return self;
- }
- - (instancetype)initWithLOTKeyframe:(LOTKeyframe *)keyframe {
- self = [super init];
- if (self) {
- _keyframeTime = [keyframe.keyframeTime copy];
- _inTangent = keyframe.inTangent;
- _outTangent = keyframe.outTangent;
- _spatialInTangent = keyframe.spatialInTangent;
- _spatialOutTangent = keyframe.spatialOutTangent;
- _isHold = keyframe.isHold;
- }
- return self;
- }
- - (LOTKeyframe *)copyWithData:(id)data {
- LOTKeyframe *newFrame = [[LOTKeyframe alloc] initWithLOTKeyframe:self];
- [newFrame setData:data];
- return newFrame;
- }
- - (void)setData:(id)data {
- [self setupOutputWithData:data];
- }
- - (void)remapValueWithBlock:(CGFloat (^)(CGFloat inValue))remapBlock {
- _floatValue = remapBlock(_floatValue);
- _pointValue = CGPointMake(remapBlock(_pointValue.x), remapBlock(_pointValue.y));
- _sizeValue = CGSizeMake(remapBlock(_sizeValue.width), remapBlock(_sizeValue.height));
- }
- - (void)setupOutputWithData:(id)data {
- if ([data isKindOfClass:[NSNumber class]]) {
- _floatValue = [(NSNumber *)data floatValue];
- }
- if ([data isKindOfClass:[NSArray class]] &&
- [[(NSArray *)data firstObject] isKindOfClass:[NSNumber class]]) {
- NSArray *numberArray = (NSArray *)data;
- if (numberArray.count > 0) {
- _floatValue = [(NSNumber *)numberArray[0] floatValue];
- }
- if (numberArray.count > 1) {
- _pointValue = CGPointMake(_floatValue = [(NSNumber *)numberArray[0] floatValue],
- _floatValue = [(NSNumber *)numberArray[1] floatValue]);
- _sizeValue = CGSizeMake(_pointValue.x, _pointValue.y);
- }
- if (numberArray.count > 3) {
- _colorValue = [self _colorValueFromArray:numberArray];
- }
- _arrayValue = numberArray;
- } else if ([data isKindOfClass:[NSArray class]] &&
- [[(NSArray *)data firstObject] isKindOfClass:[NSDictionary class]]) {
- _pathData = [[LOTBezierData alloc] initWithData:[(NSArray *)data firstObject]];
- } else if ([data isKindOfClass:[NSDictionary class]]) {
- _pathData = [[LOTBezierData alloc] initWithData:data];
- }
- }
- - (CGPoint)_pointFromValueArray:(NSArray *)values {
- CGPoint returnPoint = CGPointZero;
- if (values.count > 1) {
- returnPoint.x = [(NSNumber *)values[0] floatValue];
- returnPoint.y = [(NSNumber *)values[1] floatValue];
- }
- return returnPoint;
- }
- - (CGPoint)_pointFromValueDict:(NSDictionary *)values {
- NSNumber *xValue = @0, *yValue = @0;
- if ([values[@"x"] isKindOfClass:[NSNumber class]]) {
- xValue = values[@"x"];
- } else if ([values[@"x"] isKindOfClass:[NSArray class]]) {
- xValue = values[@"x"][0];
- }
-
- if ([values[@"y"] isKindOfClass:[NSNumber class]]) {
- yValue = values[@"y"];
- } else if ([values[@"y"] isKindOfClass:[NSArray class]]) {
- yValue = values[@"y"][0];
- }
-
- return CGPointMake([xValue floatValue], [yValue floatValue]);
- }
- - (UIColor *)_colorValueFromArray:(NSArray<NSNumber *> *)colorArray {
- if (colorArray.count == 4) {
- BOOL shouldUse255 = NO;
- for (NSNumber *number in colorArray) {
- if (number.floatValue > 1) {
- shouldUse255 = YES;
- }
- }
- return [UIColor colorWithRed:colorArray[0].floatValue / (shouldUse255 ? 255.f : 1.f)
- green:colorArray[1].floatValue / (shouldUse255 ? 255.f : 1.f)
- blue:colorArray[2].floatValue / (shouldUse255 ? 255.f : 1.f)
- alpha:colorArray[3].floatValue / (shouldUse255 ? 255.f : 1.f)];
- }
- return nil;
- }
- @end
- @implementation LOTKeyframeGroup
- - (instancetype)initWithData:(id)data {
- self = [super init];
- if (self) {
- if ([data isKindOfClass:[NSDictionary class]] &&
- [(NSDictionary *)data valueForKey:@"k"]) {
- [self buildKeyframesFromData:[(NSDictionary *)data valueForKey:@"k"]];
- } else {
- [self buildKeyframesFromData:data];
- }
- }
- return self;
- }
- - (void)buildKeyframesFromData:(id)data {
- if ([data isKindOfClass:[NSArray class]] &&
- [[(NSArray *)data firstObject] isKindOfClass:[NSDictionary class]] &&
- [(NSArray *)data firstObject][@"t"]) {
- // Array of Keyframes
- NSArray *keyframes = (NSArray *)data;
- NSMutableArray *keys = [NSMutableArray array];
- NSDictionary *previousFrame = nil;
- for (NSDictionary *keyframe in keyframes) {
- NSMutableDictionary *currentFrame = [NSMutableDictionary dictionary];
- if (keyframe[@"t"]) {
- // Set time
- currentFrame[@"t"] = keyframe[@"t"];
- }
- if (keyframe[@"s"]) {
- // Set Value for Keyframe
- currentFrame[@"s"] = keyframe[@"s"];
- } else if (previousFrame[@"e"]) {
- // Set Value for Keyframe
- currentFrame[@"s"] = previousFrame[@"e"];
- }
- if (keyframe[@"o"]) {
- // Set out tangent
- currentFrame[@"o"] = keyframe[@"o"];
- }
- if (previousFrame[@"i"]) {
- currentFrame[@"i"] = previousFrame[@"i"];
- }
- if (keyframe[@"to"]) {
- // Set out tangent
- currentFrame[@"to"] = keyframe[@"to"];
- }
- if (previousFrame[@"ti"]) {
- currentFrame[@"ti"] = previousFrame[@"ti"];
- }
- if (keyframe[@"h"]) {
- currentFrame[@"h"] = keyframe[@"h"];
- }
- LOTKeyframe *key = [[LOTKeyframe alloc] initWithKeyframe:currentFrame];
- [keys addObject:key];
- previousFrame = keyframe;
- }
- _keyframes = keys;
-
- } else {
- LOTKeyframe *key = [[LOTKeyframe alloc] initWithValue:data];
- _keyframes = @[key];
- }
- }
- - (void)remapKeyframesWithBlock:(CGFloat (^)(CGFloat))remapBlock {
- for (LOTKeyframe *keyframe in _keyframes) {
- [keyframe remapValueWithBlock:remapBlock];
- }
- }
- @end
- /*
- +KeyFrameObject has
- + i (PointObject) // Timing curve in tangent
- + o (PointObject) // Timing curve out tangent
- + n (array of string) // String representation of timing curve
- + t (integer) // Keyframe time for start of keyframe
- + s (float or array of float or PathObject) // The key information
- + e (float or array of float or PathObject) // The end key information
- + to (array of float) // For spacial bezier path interpolation, the in tangent
- + ti (array of float) // For spacial bezier path interpolation, the out tangent
- + h (integer) // If the keyframe is a Hold keyframe or not
- */
|