lottie-ios 4.1.2 → 4.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Lottie.xcworkspace/xcuserdata/calstephens.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
- package/README.md +3 -3
- package/Rakefile +5 -1
- package/Sources/Private/CoreAnimation/Animations/LayerProperty.swift +9 -2
- package/Sources/Private/CoreAnimation/Animations/TransformAnimations.swift +58 -9
- package/Sources/Private/CoreAnimation/Extensions/Keyframes+combined.swift +16 -12
- package/Sources/Private/CoreAnimation/Layers/BaseCompositionLayer.swift +19 -4
- package/Sources/Private/CoreAnimation/Layers/ImageLayer.swift +2 -2
- package/Sources/Private/CoreAnimation/Layers/PreCompLayer.swift +1 -1
- package/Sources/Private/CoreAnimation/Layers/RepeaterLayer.swift +13 -2
- package/Sources/Private/MainThread/LayerContainers/Utility/LayerTransformNode.swift +13 -4
- package/Sources/Private/MainThread/NodeRenderSystem/Nodes/RenderContainers/GroupNode.swift +17 -5
- package/Sources/Private/MainThread/NodeRenderSystem/Nodes/Text/TextAnimatorNode.swift +25 -6
- package/Sources/Private/Model/Objects/Transform.swift +58 -17
- package/Sources/Private/Model/ShapeItems/Repeater.swift +41 -7
- package/Sources/Private/Model/ShapeItems/ShapeTransform.swift +61 -7
- package/Sources/Private/Model/Text/TextAnimator.swift +37 -5
- package/Sources/Private/Utility/Primitives/ColorExtension.swift +10 -13
- package/Sources/Private/Utility/Primitives/VectorsExtensions.swift +28 -6
- package/Sources/Public/Animation/LottieAnimationView.swift +161 -159
- package/Sources/Public/DotLottie/DotLottieFileHelpers.swift +9 -3
- package/Sources/Public/iOS/Compatibility/CompatibleAnimationView.swift +32 -0
- package/Sources/Public/iOS/LottieAnimationViewBase.swift +1 -1
- package/Sources/Public/macOS/LottieAnimationViewBase.macOS.swift +1 -1
- package/lottie-ios.podspec +1 -1
- package/package.json +1 -1
|
@@ -22,8 +22,19 @@ final class Repeater: ShapeItem {
|
|
|
22
22
|
.decodeIfPresent(KeyframeGroup<LottieVector1D>.self, forKey: .startOpacity) ?? KeyframeGroup(LottieVector1D(100))
|
|
23
23
|
endOpacity = try transformContainer
|
|
24
24
|
.decodeIfPresent(KeyframeGroup<LottieVector1D>.self, forKey: .endOpacity) ?? KeyframeGroup(LottieVector1D(100))
|
|
25
|
-
rotation = try transformContainer
|
|
26
|
-
|
|
25
|
+
if let rotation = try transformContainer.decodeIfPresent(KeyframeGroup<LottieVector1D>.self, forKey: .rotation) {
|
|
26
|
+
rotationZ = rotation
|
|
27
|
+
} else if let rotation = try transformContainer.decodeIfPresent(KeyframeGroup<LottieVector1D>.self, forKey: .rotationZ) {
|
|
28
|
+
rotationZ = rotation
|
|
29
|
+
} else {
|
|
30
|
+
rotationZ = KeyframeGroup(LottieVector1D(0))
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
rotationX = try transformContainer
|
|
34
|
+
.decodeIfPresent(KeyframeGroup<LottieVector1D>.self, forKey: .rotationX) ?? KeyframeGroup(LottieVector1D(0))
|
|
35
|
+
rotationY = try transformContainer
|
|
36
|
+
.decodeIfPresent(KeyframeGroup<LottieVector1D>.self, forKey: .rotationY) ?? KeyframeGroup(LottieVector1D(0))
|
|
37
|
+
|
|
27
38
|
position = try transformContainer
|
|
28
39
|
.decodeIfPresent(KeyframeGroup<LottieVector3D>.self, forKey: .position) ??
|
|
29
40
|
KeyframeGroup(LottieVector3D(x: Double(0), y: 0, z: 0))
|
|
@@ -58,10 +69,22 @@ final class Repeater: ShapeItem {
|
|
|
58
69
|
} else {
|
|
59
70
|
endOpacity = KeyframeGroup(LottieVector1D(100))
|
|
60
71
|
}
|
|
72
|
+
if let rotationDictionary = transformDictionary[TransformKeys.rotationX.rawValue] as? [String: Any] {
|
|
73
|
+
rotationX = try KeyframeGroup<LottieVector1D>(dictionary: rotationDictionary)
|
|
74
|
+
} else {
|
|
75
|
+
rotationX = KeyframeGroup(LottieVector1D(0))
|
|
76
|
+
}
|
|
77
|
+
if let rotationDictionary = transformDictionary[TransformKeys.rotationY.rawValue] as? [String: Any] {
|
|
78
|
+
rotationY = try KeyframeGroup<LottieVector1D>(dictionary: rotationDictionary)
|
|
79
|
+
} else {
|
|
80
|
+
rotationY = KeyframeGroup(LottieVector1D(0))
|
|
81
|
+
}
|
|
61
82
|
if let rotationDictionary = transformDictionary[TransformKeys.rotation.rawValue] as? [String: Any] {
|
|
62
|
-
|
|
83
|
+
rotationZ = try KeyframeGroup<LottieVector1D>(dictionary: rotationDictionary)
|
|
84
|
+
} else if let rotationDictionary = transformDictionary[TransformKeys.rotationZ.rawValue] as? [String: Any] {
|
|
85
|
+
rotationZ = try KeyframeGroup<LottieVector1D>(dictionary: rotationDictionary)
|
|
63
86
|
} else {
|
|
64
|
-
|
|
87
|
+
rotationZ = KeyframeGroup(LottieVector1D(0))
|
|
65
88
|
}
|
|
66
89
|
if let positionDictionary = transformDictionary[TransformKeys.position.rawValue] as? [String: Any] {
|
|
67
90
|
position = try KeyframeGroup<LottieVector3D>(dictionary: positionDictionary)
|
|
@@ -95,8 +118,14 @@ final class Repeater: ShapeItem {
|
|
|
95
118
|
/// End opacity
|
|
96
119
|
let endOpacity: KeyframeGroup<LottieVector1D>
|
|
97
120
|
|
|
98
|
-
/// The rotation
|
|
99
|
-
let
|
|
121
|
+
/// The rotation on X axis
|
|
122
|
+
let rotationX: KeyframeGroup<LottieVector1D>
|
|
123
|
+
|
|
124
|
+
/// The rotation on Y axis
|
|
125
|
+
let rotationY: KeyframeGroup<LottieVector1D>
|
|
126
|
+
|
|
127
|
+
/// The rotation on Z axis
|
|
128
|
+
let rotationZ: KeyframeGroup<LottieVector1D>
|
|
100
129
|
|
|
101
130
|
/// Anchor Point
|
|
102
131
|
let anchorPoint: KeyframeGroup<LottieVector3D>
|
|
@@ -115,7 +144,9 @@ final class Repeater: ShapeItem {
|
|
|
115
144
|
var transformContainer = container.nestedContainer(keyedBy: TransformKeys.self, forKey: .transform)
|
|
116
145
|
try transformContainer.encode(startOpacity, forKey: .startOpacity)
|
|
117
146
|
try transformContainer.encode(endOpacity, forKey: .endOpacity)
|
|
118
|
-
try transformContainer.encode(
|
|
147
|
+
try transformContainer.encode(rotationX, forKey: .rotationX)
|
|
148
|
+
try transformContainer.encode(rotationY, forKey: .rotationY)
|
|
149
|
+
try transformContainer.encode(rotationZ, forKey: .rotationZ)
|
|
119
150
|
try transformContainer.encode(position, forKey: .position)
|
|
120
151
|
try transformContainer.encode(anchorPoint, forKey: .anchorPoint)
|
|
121
152
|
try transformContainer.encode(scale, forKey: .scale)
|
|
@@ -131,6 +162,9 @@ final class Repeater: ShapeItem {
|
|
|
131
162
|
|
|
132
163
|
private enum TransformKeys: String, CodingKey {
|
|
133
164
|
case rotation = "r"
|
|
165
|
+
case rotationX = "rx"
|
|
166
|
+
case rotationY = "ry"
|
|
167
|
+
case rotationZ = "rz"
|
|
134
168
|
case startOpacity = "so"
|
|
135
169
|
case endOpacity = "eo"
|
|
136
170
|
case anchorPoint = "a"
|
|
@@ -22,8 +22,25 @@ final class ShapeTransform: ShapeItem {
|
|
|
22
22
|
scale = try container
|
|
23
23
|
.decodeIfPresent(KeyframeGroup<LottieVector3D>.self, forKey: .scale) ??
|
|
24
24
|
KeyframeGroup(LottieVector3D(x: Double(100), y: 100, z: 100))
|
|
25
|
-
|
|
26
|
-
|
|
25
|
+
|
|
26
|
+
rotationX = try container
|
|
27
|
+
.decodeIfPresent(KeyframeGroup<LottieVector1D>.self, forKey: .rotationX) ?? KeyframeGroup(LottieVector1D(0))
|
|
28
|
+
rotationY = try container
|
|
29
|
+
.decodeIfPresent(KeyframeGroup<LottieVector1D>.self, forKey: .rotationY) ?? KeyframeGroup(LottieVector1D(0))
|
|
30
|
+
if
|
|
31
|
+
let rotation = try container
|
|
32
|
+
.decodeIfPresent(KeyframeGroup<LottieVector1D>.self, forKey: .rotation)
|
|
33
|
+
{
|
|
34
|
+
rotationZ = rotation
|
|
35
|
+
} else if
|
|
36
|
+
let rotation = try container
|
|
37
|
+
.decodeIfPresent(KeyframeGroup<LottieVector1D>.self, forKey: .rotationZ)
|
|
38
|
+
{
|
|
39
|
+
rotationZ = rotation
|
|
40
|
+
} else {
|
|
41
|
+
rotationZ = KeyframeGroup(LottieVector1D(0))
|
|
42
|
+
}
|
|
43
|
+
|
|
27
44
|
opacity = try container
|
|
28
45
|
.decodeIfPresent(KeyframeGroup<LottieVector1D>.self, forKey: .opacity) ?? KeyframeGroup(LottieVector1D(100))
|
|
29
46
|
skew = try container.decodeIfPresent(KeyframeGroup<LottieVector1D>.self, forKey: .skew) ?? KeyframeGroup(LottieVector1D(0))
|
|
@@ -57,14 +74,39 @@ final class ShapeTransform: ShapeItem {
|
|
|
57
74
|
} else {
|
|
58
75
|
scale = KeyframeGroup(LottieVector3D(x: Double(100), y: 100, z: 100))
|
|
59
76
|
}
|
|
77
|
+
|
|
78
|
+
if
|
|
79
|
+
let rotationDictionary = dictionary[CodingKeys.rotationX.rawValue] as? [String: Any],
|
|
80
|
+
let rotation = try? KeyframeGroup<LottieVector1D>(dictionary: rotationDictionary)
|
|
81
|
+
{
|
|
82
|
+
rotationX = rotation
|
|
83
|
+
} else {
|
|
84
|
+
rotationX = KeyframeGroup(LottieVector1D(0))
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if
|
|
88
|
+
let rotationDictionary = dictionary[CodingKeys.rotationY.rawValue] as? [String: Any],
|
|
89
|
+
let rotation = try? KeyframeGroup<LottieVector1D>(dictionary: rotationDictionary)
|
|
90
|
+
{
|
|
91
|
+
rotationY = rotation
|
|
92
|
+
} else {
|
|
93
|
+
rotationY = KeyframeGroup(LottieVector1D(0))
|
|
94
|
+
}
|
|
95
|
+
|
|
60
96
|
if
|
|
61
97
|
let rotationDictionary = dictionary[CodingKeys.rotation.rawValue] as? [String: Any],
|
|
62
98
|
let rotation = try? KeyframeGroup<LottieVector1D>(dictionary: rotationDictionary)
|
|
63
99
|
{
|
|
64
|
-
|
|
100
|
+
rotationZ = rotation
|
|
101
|
+
} else if
|
|
102
|
+
let rotationDictionary = dictionary[CodingKeys.rotationZ.rawValue] as? [String: Any],
|
|
103
|
+
let rotation = try? KeyframeGroup<LottieVector1D>(dictionary: rotationDictionary)
|
|
104
|
+
{
|
|
105
|
+
rotationZ = rotation
|
|
65
106
|
} else {
|
|
66
|
-
|
|
107
|
+
rotationZ = KeyframeGroup(LottieVector1D(0))
|
|
67
108
|
}
|
|
109
|
+
|
|
68
110
|
if
|
|
69
111
|
let opacityDictionary = dictionary[CodingKeys.opacity.rawValue] as? [String: Any],
|
|
70
112
|
let opacity = try? KeyframeGroup<LottieVector1D>(dictionary: opacityDictionary)
|
|
@@ -89,6 +131,7 @@ final class ShapeTransform: ShapeItem {
|
|
|
89
131
|
} else {
|
|
90
132
|
skewAxis = KeyframeGroup(LottieVector1D(0))
|
|
91
133
|
}
|
|
134
|
+
|
|
92
135
|
try super.init(dictionary: dictionary)
|
|
93
136
|
}
|
|
94
137
|
|
|
@@ -103,8 +146,14 @@ final class ShapeTransform: ShapeItem {
|
|
|
103
146
|
/// Scale
|
|
104
147
|
let scale: KeyframeGroup<LottieVector3D>
|
|
105
148
|
|
|
106
|
-
/// Rotation
|
|
107
|
-
let
|
|
149
|
+
/// Rotation on X axis
|
|
150
|
+
let rotationX: KeyframeGroup<LottieVector1D>
|
|
151
|
+
|
|
152
|
+
/// Rotation on Y axis
|
|
153
|
+
let rotationY: KeyframeGroup<LottieVector1D>
|
|
154
|
+
|
|
155
|
+
/// Rotation on Z axis
|
|
156
|
+
let rotationZ: KeyframeGroup<LottieVector1D>
|
|
108
157
|
|
|
109
158
|
/// opacity
|
|
110
159
|
let opacity: KeyframeGroup<LottieVector1D>
|
|
@@ -130,7 +179,9 @@ final class ShapeTransform: ShapeItem {
|
|
|
130
179
|
try container.encode(anchor, forKey: .anchor)
|
|
131
180
|
try container.encode(position, forKey: .position)
|
|
132
181
|
try container.encode(scale, forKey: .scale)
|
|
133
|
-
try container.encode(
|
|
182
|
+
try container.encode(rotationX, forKey: .rotationX)
|
|
183
|
+
try container.encode(rotationY, forKey: .rotationY)
|
|
184
|
+
try container.encode(rotationZ, forKey: .rotationZ)
|
|
134
185
|
try container.encode(opacity, forKey: .opacity)
|
|
135
186
|
try container.encode(skew, forKey: .skew)
|
|
136
187
|
try container.encode(skewAxis, forKey: .skewAxis)
|
|
@@ -143,6 +194,9 @@ final class ShapeTransform: ShapeItem {
|
|
|
143
194
|
case position = "p"
|
|
144
195
|
case scale = "s"
|
|
145
196
|
case rotation = "r"
|
|
197
|
+
case rotationX = "rx"
|
|
198
|
+
case rotationY = "ry"
|
|
199
|
+
case rotationZ = "rz"
|
|
146
200
|
case opacity = "o"
|
|
147
201
|
case skew = "sk"
|
|
148
202
|
case skewAxis = "sa"
|
|
@@ -24,7 +24,15 @@ final class TextAnimator: Codable, DictionaryInitializable {
|
|
|
24
24
|
scale = try animatorContainer.decodeIfPresent(KeyframeGroup<LottieVector3D>.self, forKey: .scale)
|
|
25
25
|
skew = try animatorContainer.decodeIfPresent(KeyframeGroup<LottieVector1D>.self, forKey: .skew)
|
|
26
26
|
skewAxis = try animatorContainer.decodeIfPresent(KeyframeGroup<LottieVector1D>.self, forKey: .skewAxis)
|
|
27
|
-
|
|
27
|
+
rotationX = try animatorContainer.decodeIfPresent(KeyframeGroup<LottieVector1D>.self, forKey: .rotationX)
|
|
28
|
+
rotationY = try animatorContainer.decodeIfPresent(KeyframeGroup<LottieVector1D>.self, forKey: .rotationY)
|
|
29
|
+
if let rotation = try animatorContainer.decodeIfPresent(KeyframeGroup<LottieVector1D>.self, forKey: .rotation) {
|
|
30
|
+
rotationZ = rotation
|
|
31
|
+
} else if let rotation = try animatorContainer.decodeIfPresent(KeyframeGroup<LottieVector1D>.self, forKey: .rotationZ) {
|
|
32
|
+
rotationZ = rotation
|
|
33
|
+
} else {
|
|
34
|
+
rotationZ = nil
|
|
35
|
+
}
|
|
28
36
|
opacity = try animatorContainer.decodeIfPresent(KeyframeGroup<LottieVector1D>.self, forKey: .opacity)
|
|
29
37
|
}
|
|
30
38
|
|
|
@@ -76,11 +84,26 @@ final class TextAnimator: Codable, DictionaryInitializable {
|
|
|
76
84
|
} else {
|
|
77
85
|
skewAxis = nil
|
|
78
86
|
}
|
|
87
|
+
if let rotationDictionary = animatorDictionary[TextAnimatorKeys.rotationX.rawValue] as? [String: Any] {
|
|
88
|
+
rotationX = try? KeyframeGroup<LottieVector1D>(dictionary: rotationDictionary)
|
|
89
|
+
} else {
|
|
90
|
+
rotationX = nil
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if let rotationDictionary = animatorDictionary[TextAnimatorKeys.rotationY.rawValue] as? [String: Any] {
|
|
94
|
+
rotationY = try? KeyframeGroup<LottieVector1D>(dictionary: rotationDictionary)
|
|
95
|
+
} else {
|
|
96
|
+
rotationY = nil
|
|
97
|
+
}
|
|
98
|
+
|
|
79
99
|
if let rotationDictionary = animatorDictionary[TextAnimatorKeys.rotation.rawValue] as? [String: Any] {
|
|
80
|
-
|
|
100
|
+
rotationZ = try? KeyframeGroup<LottieVector1D>(dictionary: rotationDictionary)
|
|
101
|
+
} else if let rotationDictionary = animatorDictionary[TextAnimatorKeys.rotationZ.rawValue] as? [String: Any] {
|
|
102
|
+
rotationZ = try? KeyframeGroup<LottieVector1D>(dictionary: rotationDictionary)
|
|
81
103
|
} else {
|
|
82
|
-
|
|
104
|
+
rotationZ = nil
|
|
83
105
|
}
|
|
106
|
+
|
|
84
107
|
if let opacityDictionary = animatorDictionary[TextAnimatorKeys.opacity.rawValue] as? [String: Any] {
|
|
85
108
|
opacity = try KeyframeGroup<LottieVector1D>(dictionary: opacityDictionary)
|
|
86
109
|
} else {
|
|
@@ -107,8 +130,14 @@ final class TextAnimator: Codable, DictionaryInitializable {
|
|
|
107
130
|
/// Skew Axis
|
|
108
131
|
let skewAxis: KeyframeGroup<LottieVector1D>?
|
|
109
132
|
|
|
110
|
-
/// Rotation
|
|
111
|
-
let
|
|
133
|
+
/// Rotation on X axis
|
|
134
|
+
let rotationX: KeyframeGroup<LottieVector1D>?
|
|
135
|
+
|
|
136
|
+
/// Rotation on Y axis
|
|
137
|
+
let rotationY: KeyframeGroup<LottieVector1D>?
|
|
138
|
+
|
|
139
|
+
/// Rotation on Z axis
|
|
140
|
+
let rotationZ: KeyframeGroup<LottieVector1D>?
|
|
112
141
|
|
|
113
142
|
/// Opacity
|
|
114
143
|
let opacity: KeyframeGroup<LottieVector1D>?
|
|
@@ -159,6 +188,9 @@ final class TextAnimator: Codable, DictionaryInitializable {
|
|
|
159
188
|
case skew = "sk"
|
|
160
189
|
case skewAxis = "sa"
|
|
161
190
|
case rotation = "r"
|
|
191
|
+
case rotationX = "rx"
|
|
192
|
+
case rotationY = "ry"
|
|
193
|
+
case rotationZ = "rz"
|
|
162
194
|
case opacity = "o"
|
|
163
195
|
}
|
|
164
196
|
}
|
|
@@ -38,22 +38,18 @@ extension LottieColor: Codable {
|
|
|
38
38
|
b1 = 0
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
-
|
|
42
|
-
if !container.isAtEnd {
|
|
43
|
-
a1 = try container.decode(Double.self)
|
|
44
|
-
} else {
|
|
45
|
-
a1 = 1
|
|
46
|
-
}
|
|
47
|
-
if r1 > 1, g1 > 1, b1 > 1, a1 > 1 {
|
|
41
|
+
if r1 > 1, g1 > 1, b1 > 1 {
|
|
48
42
|
r1 = r1 / 255
|
|
49
43
|
g1 = g1 / 255
|
|
50
44
|
b1 = b1 / 255
|
|
51
|
-
a1 = a1 / 255
|
|
52
45
|
}
|
|
53
46
|
r = r1
|
|
54
47
|
g = g1
|
|
55
48
|
b = b1
|
|
56
|
-
|
|
49
|
+
|
|
50
|
+
// The Lottie JSON schema supports alpha values in theory, as the fourth value in this array.
|
|
51
|
+
// We intentionally do not support this, though, for consistency with Lottie on other platforms.
|
|
52
|
+
a = 1
|
|
57
53
|
}
|
|
58
54
|
|
|
59
55
|
// MARK: Public
|
|
@@ -79,17 +75,18 @@ extension LottieColor: AnyInitializable {
|
|
|
79
75
|
var r: Double = array.count > 0 ? array.removeFirst() : 0
|
|
80
76
|
var g: Double = array.count > 0 ? array.removeFirst() : 0
|
|
81
77
|
var b: Double = array.count > 0 ? array.removeFirst() : 0
|
|
82
|
-
|
|
83
|
-
if r > 1, g > 1, b > 1, a > 1 {
|
|
78
|
+
if r > 1, g > 1, b > 1 {
|
|
84
79
|
r /= 255
|
|
85
80
|
g /= 255
|
|
86
81
|
b /= 255
|
|
87
|
-
a /= 255
|
|
88
82
|
}
|
|
89
83
|
self.r = r
|
|
90
84
|
self.g = g
|
|
91
85
|
self.b = b
|
|
92
|
-
|
|
86
|
+
|
|
87
|
+
// The Lottie JSON schema supports alpha values in theory, as the fourth value in this array.
|
|
88
|
+
// We intentionally do not support this, though, for consistency with Lottie on other platforms.
|
|
89
|
+
a = 1
|
|
93
90
|
}
|
|
94
91
|
|
|
95
92
|
}
|
|
@@ -246,6 +246,10 @@ extension CGSize {
|
|
|
246
246
|
|
|
247
247
|
extension CATransform3D {
|
|
248
248
|
|
|
249
|
+
enum Axis {
|
|
250
|
+
case x, y, z
|
|
251
|
+
}
|
|
252
|
+
|
|
249
253
|
static func makeSkew(skew: CGFloat, skewAxis: CGFloat) -> CATransform3D {
|
|
250
254
|
let mCos = cos(skewAxis.toRadians())
|
|
251
255
|
let mSin = sin(skewAxis.toRadians())
|
|
@@ -311,20 +315,37 @@ extension CATransform3D {
|
|
|
311
315
|
anchor: CGPoint,
|
|
312
316
|
position: CGPoint,
|
|
313
317
|
scale: CGSize,
|
|
314
|
-
|
|
318
|
+
rotationX: CGFloat,
|
|
319
|
+
rotationY: CGFloat,
|
|
320
|
+
rotationZ: CGFloat,
|
|
315
321
|
skew: CGFloat?,
|
|
316
322
|
skewAxis: CGFloat?)
|
|
317
323
|
-> CATransform3D
|
|
318
324
|
{
|
|
319
325
|
if let skew = skew, let skewAxis = skewAxis {
|
|
320
|
-
return CATransform3DMakeTranslation(position.x, position.y, 0)
|
|
321
|
-
.
|
|
326
|
+
return CATransform3DMakeTranslation(position.x, position.y, 0)
|
|
327
|
+
.rotated(rotationX, axis: .x)
|
|
328
|
+
.rotated(rotationY, axis: .y)
|
|
329
|
+
.rotated(rotationZ, axis: .z)
|
|
330
|
+
.skewed(skew: -skew, skewAxis: skewAxis)
|
|
331
|
+
.scaled(scale * 0.01)
|
|
332
|
+
.translated(anchor * -1)
|
|
322
333
|
}
|
|
323
|
-
return CATransform3DMakeTranslation(position.x, position.y, 0)
|
|
334
|
+
return CATransform3DMakeTranslation(position.x, position.y, 0)
|
|
335
|
+
.rotated(rotationX, axis: .x)
|
|
336
|
+
.rotated(rotationY, axis: .y)
|
|
337
|
+
.rotated(rotationZ, axis: .z)
|
|
338
|
+
.scaled(scale * 0.01)
|
|
339
|
+
.translated(anchor * -1)
|
|
324
340
|
}
|
|
325
341
|
|
|
326
|
-
func rotated(_ degrees: CGFloat) -> CATransform3D {
|
|
327
|
-
CATransform3DRotate(
|
|
342
|
+
func rotated(_ degrees: CGFloat, axis: Axis) -> CATransform3D {
|
|
343
|
+
CATransform3DRotate(
|
|
344
|
+
self,
|
|
345
|
+
degrees.toRadians(),
|
|
346
|
+
axis == .x ? 1 : 0,
|
|
347
|
+
axis == .y ? 1 : 0,
|
|
348
|
+
axis == .z ? 1 : 0)
|
|
328
349
|
}
|
|
329
350
|
|
|
330
351
|
func translated(_ translation: CGPoint) -> CATransform3D {
|
|
@@ -338,4 +359,5 @@ extension CATransform3D {
|
|
|
338
359
|
func skewed(skew: CGFloat, skewAxis: CGFloat) -> CATransform3D {
|
|
339
360
|
CATransform3DConcat(CATransform3D.makeSkew(skew: skew, skewAxis: skewAxis), self)
|
|
340
361
|
}
|
|
362
|
+
|
|
341
363
|
}
|