Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 60 additions & 0 deletions examples/src/Examples/Animations/Directions.elm
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
module Examples.Animations.Directions exposing (examples)

import Element exposing (..)
import Element.Background as Background
import Element.Border as Border
import Simple.Animation as Animation exposing (Animation)
import Simple.Animation.Property as P
import Utils.Animated as Animated
import Utils.UI exposing (blue, group, groups, large)



-- Directions


fall : List Animation.Option -> Animation
fall options =
Animation.fromTo
{ duration = 1500
, options = Animation.loop :: options
}
[ P.y 0 ]
[ P.y 50 ]


regularDirection : Element msg
regularDirection =
Animated.el (fall []) [] circle


reversedDirection : Element msg
reversedDirection =
Animated.el (fall [ Animation.reverse ]) [] circle


alternatingDirection : Element msg
alternatingDirection =
Animated.el (fall [ Animation.yoyo ]) [] circle


examples : Element msg -> Element msg
examples =
groups
[ row [ spacing large ]
[ group "Regular Direction" regularDirection
, group "Reversed Direction" reversedDirection
, group "Alternating Direction" alternatingDirection
]
]


circle : Element msg
circle =
el
[ Background.color blue
, Border.rounded 50
, width (px 50)
, height (px 50)
]
none
6 changes: 6 additions & 0 deletions examples/src/Main.elm
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ module Main exposing (main)
import Browser
import Element exposing (..)
import Element.Font as Font
import Examples.Animations.Directions as Directions
import Examples.Animations.FromTo as FromTo
import Examples.Animations.Progress as Progress
import Examples.Animations.Renderers as Renderers
Expand Down Expand Up @@ -49,6 +50,7 @@ type TransitionExample
type AnimationExample
= FromTo
| Steps
| Directions
| Sequence
| Renderers
| Progress
Expand Down Expand Up @@ -101,6 +103,9 @@ examples model =
Animation Steps ->
Steps.examples

Animation Directions ->
Directions.examples

Animation Sequence ->
Sequence.examples

Expand Down Expand Up @@ -166,6 +171,7 @@ animationButtons =
List.map (Tuple.mapFirst Animation)
[ ( FromTo, "FromTo" )
, ( Steps, "Steps" )
, ( Directions, "Directions" )
, ( Sequence, "Sequence" )
, ( Renderers, "Renderers" )
, ( Progress, "Progress" )
Expand Down
134 changes: 122 additions & 12 deletions src/Internal/Animation.elm
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ type Option
= Iteration Iteration
| Delay Millis
| Ease Ease
| Yoyo
| Reverse


type Frame
Expand All @@ -47,6 +49,21 @@ type alias Millis =
Unit.Millis


type alias Options =
{ delay : Maybe Millis
, timingFunction : Maybe Ease
, iteration : Maybe Iteration
, isYoyo : Bool
, reversed : Bool
}


type Direction
= Alternate_
| Reverse_
| AlternateReverse_



-- Render

Expand Down Expand Up @@ -92,25 +109,54 @@ renderFrame (Frame percent properties) =

renderOptions : Animation -> List String
renderOptions =
options_ >> List.concatMap renderOption
options_ >> renderOptions_ >> List.filterMap identity


animationDuration : Animation -> String
animationDuration anim =
Unit.ms (duration_ anim)


renderOption : Option -> List String
renderOption o =
case o of
Delay n ->
[ "animation-delay: " ++ Unit.ms n ]
renderOptions_ : Options -> List (Maybe String)
renderOptions_ opts =
[ renderOption "animation-delay" Unit.ms opts.delay
, renderOption "animation-timing-function" Ease.toString opts.timingFunction
, renderOption "animation-iteration-count" renderIteration opts.iteration
, renderOption "animation-direction" renderDirection (toDirection opts)
]

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

Iteration i ->
[ "animation-iteration-count: " ++ renderIteration i ]
toDirection : Options -> Maybe Direction
toDirection opts =
if opts.isYoyo && opts.reversed then
Just AlternateReverse_

else if opts.reversed then
Just Reverse_

else if opts.isYoyo then
Just Alternate_

else
Nothing


renderOption : String -> (a -> String) -> Maybe a -> Maybe String
renderOption name toProp =
Maybe.map (\x -> name ++ ": " ++ toProp x)


renderDirection : Direction -> String
renderDirection d =
case d of
Alternate_ ->
"alternate"

Reverse_ ->
"reverse"

AlternateReverse_ ->
"alternate-reverse"


renderIteration : Iteration -> String
Expand Down Expand Up @@ -154,6 +200,12 @@ optionName o =
Iteration i ->
iterationName i

Yoyo ->
"yoyo"

Reverse ->
"rev"


frameName : Frame -> String
frameName (Frame dur props) =
Expand All @@ -179,8 +231,66 @@ iterationName i =
-- Helpers


options_ : Animation -> List Option
options_ (Animation _ o _) =
options_ : Animation -> Options
options_ =
rawOptions_
>> List.foldl collectOption defaults
>> normalise


normalise : Options -> Options
normalise opts =
if opts.isYoyo then
{ opts | iteration = Just (iterationForYoyo opts) }

else
opts


iterationForYoyo : Options -> Iteration
iterationForYoyo opts =
case opts.iteration of
Just Loop ->
Loop

Just (Count n) ->
Count (n * 2)

Nothing ->
Count 2


collectOption : Option -> Options -> Options
collectOption o opts =
case o of
Delay ms ->
{ opts | delay = Just ms }

Iteration i ->
{ opts | iteration = Just i }

Ease e ->
{ opts | timingFunction = Just e }

Yoyo ->
{ opts | isYoyo = True }

Reverse ->
{ opts | reversed = True }


defaults : Options
defaults =
{ delay = Nothing
, timingFunction = Nothing
, iteration = Nothing
, isYoyo = False
, reversed = False
}


rawOptions_ : Animation -> List Option
rawOptions_ (Animation _ o _) =
o


Expand Down
18 changes: 16 additions & 2 deletions src/Simple/Animation.elm
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
module Simple.Animation exposing
( Animation, Millis, fromTo, steps
, Step, step, set, wait, waitTillComplete
, Option, loop, count, delay
, Option, loop, count, delay, reverse, yoyo
, linear, easeIn, easeOut, easeInOut, cubic
, easeInSine, easeOutSine, easeInOutSine, easeInQuad, easeOutQuad, easeInOutQuad, easeInCubic, easeOutCubic, easeInOutCubic, easeInQuart, easeOutQuart, easeInOutQuart, easeInQuint, easeOutQuint, easeInOutQuint, easeInExpo, easeOutExpo, easeInOutExpo, easeInCirc, easeOutCirc, easeInOutCirc, easeInBack, easeOutBack, easeInOutBack
, duration
Expand All @@ -26,7 +26,7 @@ Build up a multi step animation

Customise the feel and behaviour of an animation

@docs Option, loop, count, delay
@docs Option, loop, count, delay, reverse, yoyo


# Standard Eases
Expand Down Expand Up @@ -308,6 +308,20 @@ count =
Iteration << Count


{-| Play animation in reverse
-}
reverse : Option
reverse =
Reverse


{-| When animation completes, play it in reverse
-}
yoyo : Option
yoyo =
Yoyo


{-| Delay the start of an animation (repeats like `loop` or `count` are not affected by this)
-}
delay : Millis -> Option
Expand Down
56 changes: 56 additions & 0 deletions tests/DirectionTest.elm
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
module DirectionTest exposing (suite)

import Simple.Animation as Animation exposing (Animation)
import Simple.Animation.Property as P
import Test exposing (..)
import Utils.Expect as Expect


suite : Test
suite =
describe "Direction"
[ test "applies reverse" <|
\_ ->
animation [ Animation.reverse ]
|> Expect.classProperties
[ "animation-direction: reverse"
]
, test "Adds a 2 count iteration for yoyo with no iteration specified" <|
\_ ->
animation [ Animation.yoyo ]
|> Expect.classProperties
[ "animation-direction: alternate"
, "animation-iteration-count: 2"
]
, test "Doubles actual iteration count if specified with yoyo" <|
\_ ->
animation [ Animation.yoyo, Animation.count 2 ]
|> Expect.classProperties
[ "animation-direction: alternate"
, "animation-iteration-count: 4"
]
, test "Combines yoyo and loop" <|
\_ ->
animation [ Animation.yoyo, Animation.loop ]
|> Expect.classProperties
[ "animation-direction: alternate"
, "animation-iteration-count: infinite"
]
, test "Combines yoyo and reverse into single property" <|
\_ ->
animation [ Animation.yoyo, Animation.reverse, Animation.loop ]
|> Expect.classProperties
[ "animation-direction: alternate-reverse"
, "animation-iteration-count: infinite"
]
]


animation : List Animation.Option -> Animation
animation options =
Animation.fromTo
{ duration = 1000
, options = options
}
[ P.opacity 0 ]
[ P.opacity 1 ]