Skip to content

Commit 6fffa43

Browse files
adds yoyo and reverse animation options (#19)
1 parent a445fc8 commit 6fffa43

File tree

5 files changed

+260
-14
lines changed

5 files changed

+260
-14
lines changed
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
module Examples.Animations.Directions exposing (examples)
2+
3+
import Element exposing (..)
4+
import Element.Background as Background
5+
import Element.Border as Border
6+
import Simple.Animation as Animation exposing (Animation)
7+
import Simple.Animation.Property as P
8+
import Utils.Animated as Animated
9+
import Utils.UI exposing (blue, group, groups, large)
10+
11+
12+
13+
-- Directions
14+
15+
16+
fall : List Animation.Option -> Animation
17+
fall options =
18+
Animation.fromTo
19+
{ duration = 1500
20+
, options = Animation.loop :: options
21+
}
22+
[ P.y 0 ]
23+
[ P.y 50 ]
24+
25+
26+
regularDirection : Element msg
27+
regularDirection =
28+
Animated.el (fall []) [] circle
29+
30+
31+
reversedDirection : Element msg
32+
reversedDirection =
33+
Animated.el (fall [ Animation.reverse ]) [] circle
34+
35+
36+
alternatingDirection : Element msg
37+
alternatingDirection =
38+
Animated.el (fall [ Animation.yoyo ]) [] circle
39+
40+
41+
examples : Element msg -> Element msg
42+
examples =
43+
groups
44+
[ row [ spacing large ]
45+
[ group "Regular Direction" regularDirection
46+
, group "Reversed Direction" reversedDirection
47+
, group "Alternating Direction" alternatingDirection
48+
]
49+
]
50+
51+
52+
circle : Element msg
53+
circle =
54+
el
55+
[ Background.color blue
56+
, Border.rounded 50
57+
, width (px 50)
58+
, height (px 50)
59+
]
60+
none

examples/src/Main.elm

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ module Main exposing (main)
33
import Browser
44
import Element exposing (..)
55
import Element.Font as Font
6+
import Examples.Animations.Directions as Directions
67
import Examples.Animations.FromTo as FromTo
78
import Examples.Animations.Progress as Progress
89
import Examples.Animations.Renderers as Renderers
@@ -49,6 +50,7 @@ type TransitionExample
4950
type AnimationExample
5051
= FromTo
5152
| Steps
53+
| Directions
5254
| Sequence
5355
| Renderers
5456
| Progress
@@ -101,6 +103,9 @@ examples model =
101103
Animation Steps ->
102104
Steps.examples
103105

106+
Animation Directions ->
107+
Directions.examples
108+
104109
Animation Sequence ->
105110
Sequence.examples
106111

@@ -166,6 +171,7 @@ animationButtons =
166171
List.map (Tuple.mapFirst Animation)
167172
[ ( FromTo, "FromTo" )
168173
, ( Steps, "Steps" )
174+
, ( Directions, "Directions" )
169175
, ( Sequence, "Sequence" )
170176
, ( Renderers, "Renderers" )
171177
, ( Progress, "Progress" )

src/Internal/Animation.elm

Lines changed: 122 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ type Option
2828
= Iteration Iteration
2929
| Delay Millis
3030
| Ease Ease
31+
| Yoyo
32+
| Reverse
3133

3234

3335
type Frame
@@ -47,6 +49,21 @@ type alias Millis =
4749
Unit.Millis
4850

4951

52+
type alias Options =
53+
{ delay : Maybe Millis
54+
, timingFunction : Maybe Ease
55+
, iteration : Maybe Iteration
56+
, isYoyo : Bool
57+
, reversed : Bool
58+
}
59+
60+
61+
type Direction
62+
= Alternate_
63+
| Reverse_
64+
| AlternateReverse_
65+
66+
5067

5168
-- Render
5269

@@ -92,25 +109,54 @@ renderFrame (Frame percent properties) =
92109

93110
renderOptions : Animation -> List String
94111
renderOptions =
95-
options_ >> List.concatMap renderOption
112+
options_ >> renderOptions_ >> List.filterMap identity
96113

97114

98115
animationDuration : Animation -> String
99116
animationDuration anim =
100117
Unit.ms (duration_ anim)
101118

102119

103-
renderOption : Option -> List String
104-
renderOption o =
105-
case o of
106-
Delay n ->
107-
[ "animation-delay: " ++ Unit.ms n ]
120+
renderOptions_ : Options -> List (Maybe String)
121+
renderOptions_ opts =
122+
[ renderOption "animation-delay" Unit.ms opts.delay
123+
, renderOption "animation-timing-function" Ease.toString opts.timingFunction
124+
, renderOption "animation-iteration-count" renderIteration opts.iteration
125+
, renderOption "animation-direction" renderDirection (toDirection opts)
126+
]
108127

109-
Ease e ->
110-
[ "animation-timing-function: " ++ Ease.toString e ]
111128

112-
Iteration i ->
113-
[ "animation-iteration-count: " ++ renderIteration i ]
129+
toDirection : Options -> Maybe Direction
130+
toDirection opts =
131+
if opts.isYoyo && opts.reversed then
132+
Just AlternateReverse_
133+
134+
else if opts.reversed then
135+
Just Reverse_
136+
137+
else if opts.isYoyo then
138+
Just Alternate_
139+
140+
else
141+
Nothing
142+
143+
144+
renderOption : String -> (a -> String) -> Maybe a -> Maybe String
145+
renderOption name toProp =
146+
Maybe.map (\x -> name ++ ": " ++ toProp x)
147+
148+
149+
renderDirection : Direction -> String
150+
renderDirection d =
151+
case d of
152+
Alternate_ ->
153+
"alternate"
154+
155+
Reverse_ ->
156+
"reverse"
157+
158+
AlternateReverse_ ->
159+
"alternate-reverse"
114160

115161

116162
renderIteration : Iteration -> String
@@ -154,6 +200,12 @@ optionName o =
154200
Iteration i ->
155201
iterationName i
156202

203+
Yoyo ->
204+
"yoyo"
205+
206+
Reverse ->
207+
"rev"
208+
157209

158210
frameName : Frame -> String
159211
frameName (Frame dur props) =
@@ -179,8 +231,66 @@ iterationName i =
179231
-- Helpers
180232

181233

182-
options_ : Animation -> List Option
183-
options_ (Animation _ o _) =
234+
options_ : Animation -> Options
235+
options_ =
236+
rawOptions_
237+
>> List.foldl collectOption defaults
238+
>> normalise
239+
240+
241+
normalise : Options -> Options
242+
normalise opts =
243+
if opts.isYoyo then
244+
{ opts | iteration = Just (iterationForYoyo opts) }
245+
246+
else
247+
opts
248+
249+
250+
iterationForYoyo : Options -> Iteration
251+
iterationForYoyo opts =
252+
case opts.iteration of
253+
Just Loop ->
254+
Loop
255+
256+
Just (Count n) ->
257+
Count (n * 2)
258+
259+
Nothing ->
260+
Count 2
261+
262+
263+
collectOption : Option -> Options -> Options
264+
collectOption o opts =
265+
case o of
266+
Delay ms ->
267+
{ opts | delay = Just ms }
268+
269+
Iteration i ->
270+
{ opts | iteration = Just i }
271+
272+
Ease e ->
273+
{ opts | timingFunction = Just e }
274+
275+
Yoyo ->
276+
{ opts | isYoyo = True }
277+
278+
Reverse ->
279+
{ opts | reversed = True }
280+
281+
282+
defaults : Options
283+
defaults =
284+
{ delay = Nothing
285+
, timingFunction = Nothing
286+
, iteration = Nothing
287+
, isYoyo = False
288+
, reversed = False
289+
}
290+
291+
292+
rawOptions_ : Animation -> List Option
293+
rawOptions_ (Animation _ o _) =
184294
o
185295

186296

src/Simple/Animation.elm

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
module Simple.Animation exposing
22
( Animation, Millis, fromTo, steps
33
, Step, step, set, wait, waitTillComplete
4-
, Option, loop, count, delay
4+
, Option, loop, count, delay, reverse, yoyo
55
, linear, easeIn, easeOut, easeInOut, cubic
66
, easeInSine, easeOutSine, easeInOutSine, easeInQuad, easeOutQuad, easeInOutQuad, easeInCubic, easeOutCubic, easeInOutCubic, easeInQuart, easeOutQuart, easeInOutQuart, easeInQuint, easeOutQuint, easeInOutQuint, easeInExpo, easeOutExpo, easeInOutExpo, easeInCirc, easeOutCirc, easeInOutCirc, easeInBack, easeOutBack, easeInOutBack
77
, duration
@@ -26,7 +26,7 @@ Build up a multi step animation
2626
2727
Customise the feel and behaviour of an animation
2828
29-
@docs Option, loop, count, delay
29+
@docs Option, loop, count, delay, reverse, yoyo
3030
3131
3232
# Standard Eases
@@ -308,6 +308,20 @@ count =
308308
Iteration << Count
309309

310310

311+
{-| Play animation in reverse
312+
-}
313+
reverse : Option
314+
reverse =
315+
Reverse
316+
317+
318+
{-| When animation completes, play it in reverse
319+
-}
320+
yoyo : Option
321+
yoyo =
322+
Yoyo
323+
324+
311325
{-| Delay the start of an animation (repeats like `loop` or `count` are not affected by this)
312326
-}
313327
delay : Millis -> Option

tests/DirectionTest.elm

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
module DirectionTest exposing (suite)
2+
3+
import Simple.Animation as Animation exposing (Animation)
4+
import Simple.Animation.Property as P
5+
import Test exposing (..)
6+
import Utils.Expect as Expect
7+
8+
9+
suite : Test
10+
suite =
11+
describe "Direction"
12+
[ test "applies reverse" <|
13+
\_ ->
14+
animation [ Animation.reverse ]
15+
|> Expect.classProperties
16+
[ "animation-direction: reverse"
17+
]
18+
, test "Adds a 2 count iteration for yoyo with no iteration specified" <|
19+
\_ ->
20+
animation [ Animation.yoyo ]
21+
|> Expect.classProperties
22+
[ "animation-direction: alternate"
23+
, "animation-iteration-count: 2"
24+
]
25+
, test "Doubles actual iteration count if specified with yoyo" <|
26+
\_ ->
27+
animation [ Animation.yoyo, Animation.count 2 ]
28+
|> Expect.classProperties
29+
[ "animation-direction: alternate"
30+
, "animation-iteration-count: 4"
31+
]
32+
, test "Combines yoyo and loop" <|
33+
\_ ->
34+
animation [ Animation.yoyo, Animation.loop ]
35+
|> Expect.classProperties
36+
[ "animation-direction: alternate"
37+
, "animation-iteration-count: infinite"
38+
]
39+
, test "Combines yoyo and reverse into single property" <|
40+
\_ ->
41+
animation [ Animation.yoyo, Animation.reverse, Animation.loop ]
42+
|> Expect.classProperties
43+
[ "animation-direction: alternate-reverse"
44+
, "animation-iteration-count: infinite"
45+
]
46+
]
47+
48+
49+
animation : List Animation.Option -> Animation
50+
animation options =
51+
Animation.fromTo
52+
{ duration = 1000
53+
, options = options
54+
}
55+
[ P.opacity 0 ]
56+
[ P.opacity 1 ]

0 commit comments

Comments
 (0)