Controlling Animations¶
All animation engines provide control functions to manipulate running animations.
Control Functions¶
| Function | Transition | Keyframe | Sub | WAAPI |
|---|---|---|---|---|
stop |
✓ | ✓ | ✓ | ✓ |
reset |
✓ | ✓ | ✓ | ✓ |
restart |
✓ | ✓ | ✓ | |
pause |
✓ | ✓ | ✓ | |
resume |
✓ | ✓ | ✓ |
The Transition Engine has limited control because of CSS itself, not the engine.
Example¶
Control the ball animation with the buttons.
View Examples
View Source Code
module Animation.Transition.ControllingAnimations.Main exposing (main)
import Anim.Builder exposing (AnimBuilder)
import Anim.Engine.Transition as Transition
import Anim.Property.Translate as Translate
import Anim.Unit exposing (Unit(..))
import Browser
import Html exposing (Html, button, div, text)
import Html.Attributes exposing (class, style)
import Html.Events exposing (onClick)
import Motion.Easing exposing (Easing(..))
-- MAIN
main : Program () Model Msg
main =
Browser.element
{ init = \_ -> init
, view = view
, update = update
, subscriptions = \_ -> Sub.none
}
-- MODEL
type alias Model =
{ animState : Transition.AnimState }
-- INIT
init : ( Model, Cmd Msg )
init =
( { animState =
Transition.init
[ Translate.initY animGroup 0 >> Translate.cssUnitY Cqh ]
}
, Cmd.none
)
animGroup : String
animGroup =
"bouncingBall"
{-| Ball size as a percentage of the canvas height (in `cqh` units).
-}
ballSize : Float
ballSize =
12
ballSizeCqh : String
ballSizeCqh =
String.fromFloat ballSize ++ "cqh"
-- ANIMATION
dropBall : AnimBuilder { eng | withTiming : () } -> AnimBuilder { eng | withTiming : () }
dropBall =
Translate.begin
>> Translate.fromY 0
>> Translate.toY (100 - ballSize)
>> Translate.speed 75
>> Translate.easing BounceOut
>> Translate.end
-- UPDATE
type Msg
= Animate
| Stop
| Reset
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
case msg of
Animate ->
( { model
| animState =
Transition.animate model.animState <|
Transition.for animGroup
>> dropBall
}
, Cmd.none
)
Stop ->
( { model | animState = Transition.stop animGroup model.animState }
, Cmd.none
)
Reset ->
( { model | animState = Transition.reset animGroup model.animState }
, Cmd.none
)
-- VIEW
view : Model -> Html Msg
view model =
div [ class "example-stage" ]
[ div [ class "example-controls" ]
[ button [ onClick Animate, class "ui-action-button primary" ] [ text "🏀 Animate" ]
, button [ onClick Stop, class "ui-action-button warning" ] [ text "⏹️ Stop" ]
, button [ onClick Reset, class "ui-action-button purple" ] [ text "⏮️ Reset" ]
]
, animationArea model.animState
]
animationArea : Transition.AnimState -> Html msg
animationArea animState =
div
[ class "example-canvas--fluid"
, style "border-bottom" "2px solid #333"
, style "container-type" "size"
]
[ div
(Transition.attributes animGroup animState
++ [ style "position" "absolute"
, style "left" ("calc(50% - " ++ String.fromFloat (ballSize / 2) ++ "cqh)")
, style "width" ballSizeCqh
, style "height" ballSizeCqh
, style "font-size" ballSizeCqh
, style "line-height" ballSizeCqh
]
)
[ text "🏀" ]
]
module Animation.Keyframe.ControllingAnimations.Main exposing (main)
import Anim.Builder exposing (AnimBuilder)
import Anim.Engine.Keyframe as Keyframe
import Anim.Property.Opacity as Opacity
import Anim.Property.Translate as Translate
import Anim.Unit exposing (Unit(..))
import Browser
import Html exposing (Html, button, div, text)
import Html.Attributes exposing (class, style)
import Html.Events exposing (onClick)
import Motion.Easing exposing (Easing(..))
-- MAIN
main : Program () Model Msg
main =
Browser.element
{ init = \_ -> init
, view = view
, update = update
, subscriptions = always Sub.none
}
-- MODEL
type alias Model =
{ animState : Keyframe.AnimState }
init : ( Model, Cmd Msg )
init =
( { animState =
Keyframe.init
[ Translate.initY animGroup 0 >> Translate.cssUnitY Cqh ]
}
, Cmd.none
)
-- ANIMATION
animGroup : String
animGroup =
"bouncingBall"
{-| Ball size as a percentage of the canvas height (in `cqh` units).
-}
ballSize : Float
ballSize =
12
ballSizeCqh : String
ballSizeCqh =
String.fromFloat ballSize ++ "cqh"
dropBall : AnimBuilder { eng | withTiming : () } -> AnimBuilder { eng | withTiming : () }
dropBall =
Translate.begin
>> Translate.fromY 0
>> Translate.toY (100 - ballSize)
>> Translate.speed 75
>> Translate.easing BounceOut
>> Translate.end
fadeIn : AnimBuilder eng -> AnimBuilder eng
fadeIn =
Opacity.begin
>> Opacity.from 0
>> Opacity.to 1
>> Opacity.end
-- UPDATE
type Msg
= Animate
| Stop
| Pause
| Resume
| Reset
| Restart
| GotAnimMsg Keyframe.AnimMsg
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
case msg of
Animate ->
( { model
| animState =
Keyframe.animate model.animState <|
Keyframe.for animGroup
>> dropBall
}
, Cmd.none
)
Stop ->
( { model | animState = Keyframe.stop animGroup model.animState }
, Cmd.none
)
Pause ->
let
( newState, pauseCmd ) =
Keyframe.pause animGroup GotAnimMsg model.animState
in
( { model | animState = newState }, pauseCmd )
Resume ->
let
( newState, resumeCmd ) =
Keyframe.resume animGroup GotAnimMsg model.animState
in
( { model | animState = newState }, resumeCmd )
Reset ->
( { model | animState = Keyframe.reset animGroup model.animState }
, Cmd.none
)
Restart ->
let
( newState, restartCmd ) =
Keyframe.restart animGroup GotAnimMsg model.animState
in
( { model | animState = newState }, restartCmd )
GotAnimMsg _ ->
( model, Cmd.none )
-- VIEW
view : Model -> Html Msg
view model =
div [ class "example-stage" ]
[ Keyframe.styleNodeFor animGroup model.animState
, div [ class "example-controls" ]
[ button [ onClick Animate, class "ui-action-button primary" ] [ text "🏀 Animate" ]
, button [ onClick Pause, class "ui-action-button success" ] [ text "⏸️ Pause" ]
, button [ onClick Resume, class "ui-action-button success" ] [ text "▶️ Resume" ]
, button [ onClick Stop, class "ui-action-button warning" ] [ text "⏹️ Stop" ]
, button [ onClick Reset, class "ui-action-button purple" ] [ text "⏮️ Reset" ]
, button [ onClick Restart, class "ui-action-button purple" ] [ text "🔄 Restart" ]
]
, animationArea model.animState
]
animationArea : Keyframe.AnimState -> Html msg
animationArea animState =
div
[ class "example-canvas--fluid"
, style "border-bottom" "2px solid #333"
, style "container-type" "size"
]
[ div
(Keyframe.attributes animGroup animState
++ [ style "position" "absolute"
, style "left" ("calc(50% - " ++ String.fromFloat (ballSize / 2) ++ "cqh)")
, style "width" ballSizeCqh
, style "height" ballSizeCqh
, style "font-size" ballSizeCqh
, style "line-height" ballSizeCqh
]
)
[ text "🏀" ]
]
module Animation.Sub.ControllingAnimations.Main exposing (main)
import Anim.Builder exposing (AnimBuilder)
import Anim.Engine.Sub as Sub
import Anim.Property.Translate as Translate
import Anim.Unit exposing (Unit(..))
import Browser
import Html exposing (Html, button, div, text)
import Html.Attributes exposing (class, style)
import Html.Events exposing (onClick)
import Motion.Easing as Easing exposing (Easing(..))
-- MAIN
main : Program () Model Msg
main =
Browser.element
{ init = \_ -> init
, view = view
, update = update
, subscriptions = subscriptions
}
-- MODEL
type alias Model =
{ animState : Sub.AnimState }
animGroup : String
animGroup =
"bouncingBall"
ballSize : Float
ballSize =
12
ballSizeCqh : String
ballSizeCqh =
String.fromFloat ballSize ++ "cqh"
-- INIT
init : ( Model, Cmd Msg )
init =
( { animState =
Sub.init
[ Translate.initY animGroup 0 >> Translate.cssUnitY Cqh ]
}
, Cmd.none
)
-- ANIMATION
dropBall : AnimBuilder { eng | withTiming : () } -> AnimBuilder { eng | withTiming : () }
dropBall =
Translate.begin
>> Translate.fromY 0
>> Translate.toY (100 - ballSize)
>> Translate.speed 75
>> Translate.easing BounceOut
>> Translate.end
-- UPDATE
type Msg
= Animate
| Stop
| Pause
| Resume
| Reset
| Restart
| GotSubMsg Sub.AnimMsg
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
case msg of
GotSubMsg subMsg ->
let
( newAnimState, _ ) =
Sub.update subMsg model.animState
in
( { model | animState = newAnimState }
, Cmd.none
)
Animate ->
( { model
| animState =
Sub.animate model.animState <|
Sub.for animGroup
>> dropBall
}
, Cmd.none
)
Stop ->
( { model | animState = Sub.stop animGroup model.animState }
, Cmd.none
)
Pause ->
( { model | animState = Sub.pause animGroup model.animState }
, Cmd.none
)
Resume ->
( { model | animState = Sub.resume animGroup model.animState }
, Cmd.none
)
Reset ->
( { model | animState = Sub.reset animGroup model.animState }
, Cmd.none
)
Restart ->
( { model | animState = Sub.restart animGroup model.animState }
, Cmd.none
)
-- SUBSCRIPTIONS
subscriptions : Model -> Sub Msg
subscriptions model =
Sub.subscriptions GotSubMsg model.animState
-- VIEW
view : Model -> Html Msg
view model =
div [ class "example-stage" ]
[ div [ class "example-controls" ]
[ button [ onClick Animate, class "ui-action-button primary" ] [ text "🏀 Animate" ]
, button [ onClick Pause, class "ui-action-button success" ] [ text "⏸️ Pause" ]
, button [ onClick Resume, class "ui-action-button success" ] [ text "▶️ Resume" ]
, button [ onClick Stop, class "ui-action-button warning" ] [ text "⏹️ Stop" ]
, button [ onClick Reset, class "ui-action-button purple" ] [ text "⏮️ Reset" ]
, button [ onClick Restart, class "ui-action-button purple" ] [ text "🔄 Restart" ]
]
, animationArea model.animState
]
animationArea : Sub.AnimState -> Html msg
animationArea animState =
div
[ class "example-canvas--fluid"
, style "border-bottom" "2px solid #333"
, style "container-type" "size"
]
[ div
(Sub.attributes animGroup animState
++ [ style "position" "absolute"
, style "left" ("calc(50% - " ++ String.fromFloat (ballSize / 2) ++ "cqh)")
, style "width" ballSizeCqh
, style "height" ballSizeCqh
, style "font-size" ballSizeCqh
, style "line-height" ballSizeCqh
]
)
[ text "🏀" ]
]
port module Animation.WAAPI.ControllingAnimations.Main exposing (main)
import Anim.Builder exposing (AnimBuilder)
import Anim.Engine.WAAPI as WAAPI
import Anim.Property.Translate as Translate
import Anim.Unit exposing (Unit(..))
import Browser
import Html exposing (Html, button, div, text)
import Html.Attributes exposing (class, style)
import Html.Events exposing (onClick)
import Json.Encode as Encode
import Motion.Easing exposing (Easing(..))
-- PORTS
port motionCmd : Encode.Value -> Cmd msg
port motionMsg : (Encode.Value -> msg) -> Sub msg
-- MAIN
main : Program () Model Msg
main =
Browser.element
{ init = \_ -> init
, view = view
, update = update
, subscriptions = subscriptions
}
-- MODEL
type alias Model =
{ animState : WAAPI.AnimState Msg
}
-- INIT
init : ( Model, Cmd Msg )
init =
let
animState =
WAAPI.init motionCmd motionMsg <|
[ Translate.initY animGroup 0 >> Translate.cssUnitY Cqh ]
in
( { animState = animState }
, Cmd.none
)
-- ANIMATION
animGroup : String
animGroup =
"bouncingBall"
{-| Ball size as a percentage of the canvas height (in `cqh` units).
-}
ballSize : Float
ballSize =
12
ballSizeCqh : String
ballSizeCqh =
String.fromFloat ballSize ++ "cqh"
dropBall : AnimBuilder { eng | withTiming : () } -> AnimBuilder { eng | withTiming : () }
dropBall =
Translate.begin
>> Translate.fromY 0
>> Translate.toY (100 - ballSize)
>> Translate.speed 75
>> Translate.easing BounceOut
>> Translate.end
-- UPDATE
type Msg
= Animate
| Stop
| Pause
| Resume
| Reset
| Restart
| GotWaapiMsg WAAPI.AnimMsg
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
case msg of
GotWaapiMsg subMsg ->
let
( newAnimState, _ ) =
WAAPI.update subMsg model.animState
in
( { model | animState = newAnimState }
, Cmd.none
)
Animate ->
let
( newAnimState, animCmd ) =
WAAPI.animate model.animState <|
WAAPI.for animGroup
>> dropBall
in
( { model | animState = newAnimState }
, animCmd
)
Stop ->
let
( newAnimState, stopCmd ) =
WAAPI.stop animGroup model.animState
in
( { model | animState = newAnimState }
, stopCmd
)
Pause ->
let
( newAnimState, pauseCmd ) =
WAAPI.pause animGroup model.animState
in
( { model | animState = newAnimState }
, pauseCmd
)
Resume ->
let
( newAnimState, resumeCmd ) =
WAAPI.resume animGroup model.animState
in
( { model | animState = newAnimState }
, resumeCmd
)
Reset ->
let
( newAnimState, resetCmd ) =
WAAPI.reset animGroup model.animState
in
( { model | animState = newAnimState }
, resetCmd
)
Restart ->
let
( newAnimState, restartCmd ) =
WAAPI.restart animGroup model.animState
in
( { model | animState = newAnimState }
, restartCmd
)
-- SUBSCRIPTIONS
subscriptions : Model -> Sub Msg
subscriptions model =
WAAPI.subscriptions GotWaapiMsg model.animState
-- VIEW
view : Model -> Html Msg
view model =
div [ class "example-stage" ]
[ div [ class "example-controls" ]
[ button [ onClick Animate, class "ui-action-button primary" ] [ text "🏀 Animate" ]
, button [ onClick Pause, class "ui-action-button success" ] [ text "⏸️ Pause" ]
, button [ onClick Resume, class "ui-action-button success" ] [ text "▶️ Resume" ]
, button [ onClick Stop, class "ui-action-button warning" ] [ text "⏹️ Stop" ]
, button [ onClick Reset, class "ui-action-button purple" ] [ text "⏮️ Reset" ]
, button [ onClick Restart, class "ui-action-button purple" ] [ text "🔄 Restart" ]
]
, animationArea model.animState
]
animationArea : WAAPI.AnimState msg -> Html msg
animationArea animState =
div
[ class "example-canvas--fluid"
, style "border-bottom" "2px solid #333"
, style "container-type" "size"
]
[ div
(WAAPI.attributes animGroup animState
++ [ style "position" "absolute"
, style "left" ("calc(50% - " ++ String.fromFloat (ballSize / 2) ++ "cqh)")
, style "width" ballSizeCqh
, style "height" ballSizeCqh
, style "font-size" ballSizeCqh
, style "line-height" ballSizeCqh
]
)
[ text "🏀" ]
]
Control Functions¶
All control functions take an animation group name and the current AnimState, returning the updated state, and sometimes a Cmd msg.
Stop¶
Immediately jumps to the animation's end state and stops playback.
View Source Code
Reset¶
Immediately jumps back to the animation's start state and stops.
View Source Code
Restart¶
Resets to the start state, then immediately begins playing the animation again.
View Source Code
Transition doesn't support restart.
Pause¶
Freezes the animation at its current position. The animation can be resumed later.
View Source Code
Transition doesn't support pause.
Resume¶
Continues a paused animation from exactly where it was frozen.
View Source Code
Transition doesn't support resume.
Next Steps¶
Learn about Timing for animations.