// // LayerTransformPropertyMap.swift // lottie-swift // // Created by Brandon Withrow on 2/4/19. // import CoreGraphics import Foundation import QuartzCore // MARK: - LayerTransformProperties final class LayerTransformProperties: NodePropertyMap, KeypathSearchable { // MARK: Lifecycle init(transform: Transform) { anchor = NodeProperty(provider: KeyframeInterpolator(keyframes: transform.anchorPoint.keyframes)) scale = NodeProperty(provider: KeyframeInterpolator(keyframes: transform.scale.keyframes)) rotation = NodeProperty(provider: KeyframeInterpolator(keyframes: transform.rotation.keyframes)) opacity = NodeProperty(provider: KeyframeInterpolator(keyframes: transform.opacity.keyframes)) var propertyMap: [String: AnyNodeProperty] = [ "Anchor Point" : anchor, "Scale" : scale, "Rotation" : rotation, "Opacity" : opacity, ] if let positionKeyframesX = transform.positionX?.keyframes, let positionKeyframesY = transform.positionY?.keyframes { let xPosition: NodeProperty = NodeProperty(provider: KeyframeInterpolator(keyframes: positionKeyframesX)) let yPosition: NodeProperty = NodeProperty(provider: KeyframeInterpolator(keyframes: positionKeyframesY)) propertyMap["X Position"] = xPosition propertyMap["Y Position"] = yPosition positionX = xPosition positionY = yPosition position = nil } else if let positionKeyframes = transform.position?.keyframes { let position: NodeProperty = NodeProperty(provider: KeyframeInterpolator(keyframes: positionKeyframes)) propertyMap["Position"] = position self.position = position positionX = nil positionY = nil } else { position = nil positionY = nil positionX = nil } keypathProperties = propertyMap properties = Array(propertyMap.values) } // MARK: Internal let keypathProperties: [String: AnyNodeProperty] var keypathName = "Transform" let properties: [AnyNodeProperty] let anchor: NodeProperty let scale: NodeProperty let rotation: NodeProperty let position: NodeProperty? let positionX: NodeProperty? let positionY: NodeProperty? let opacity: NodeProperty var childKeypaths: [KeypathSearchable] { [] } } // MARK: - LayerTransformNode class LayerTransformNode: AnimatorNode { // MARK: Lifecycle init(transform: Transform) { transformProperties = LayerTransformProperties(transform: transform) } // MARK: Internal let outputNode: NodeOutput = PassThroughOutputNode(parent: nil) let transformProperties: LayerTransformProperties var parentNode: AnimatorNode? var hasLocalUpdates = false var hasUpstreamUpdates = false var lastUpdateFrame: CGFloat? = nil var isEnabled = true var opacity: Float = 1 var localTransform: CATransform3D = CATransform3DIdentity var globalTransform: CATransform3D = CATransform3DIdentity // MARK: Animator Node Protocol var propertyMap: NodePropertyMap & KeypathSearchable { transformProperties } func shouldRebuildOutputs(frame _: CGFloat) -> Bool { hasLocalUpdates || hasUpstreamUpdates } func rebuildOutputs(frame _: CGFloat) { opacity = Float(transformProperties.opacity.value.cgFloatValue) * 0.01 let position: CGPoint if let point = transformProperties.position?.value.pointValue { position = point } else if let xPos = transformProperties.positionX?.value.cgFloatValue, let yPos = transformProperties.positionY?.value.cgFloatValue { position = CGPoint(x: xPos, y: yPos) } else { position = .zero } localTransform = CATransform3D.makeTransform( anchor: transformProperties.anchor.value.pointValue, position: position, scale: transformProperties.scale.value.sizeValue, rotation: transformProperties.rotation.value.cgFloatValue, skew: nil, skewAxis: nil) if let parentNode = parentNode as? LayerTransformNode { globalTransform = CATransform3DConcat(localTransform, parentNode.globalTransform) } else { globalTransform = localTransform } } }