LoginSignup
10
3

More than 3 years have passed since last update.

elm-animatorでアニメーション(Animator.Inline)

Last updated at Posted at 2020-12-04

output.gif

まえおき

今日はElmでアニメーションをサポートするパッケージの一つをさくっと紹介します。

elm-animatorelm-ui の作者でもあるmdgriffithさんが開発する Elm でアニメーションを扱うためのパッケージです。

  • Animator : 時間経過によるデータの変化を管理するTimelineを扱う
  • Animatior.Css : TimelineでCSSのkeyframesを使ったアニメーションを扱う。いろいろできる
  • Animator.Inline : 座標移動とか背景色のアニメーションとか限られた用途を手軽に扱う

中心となるのはAnimatorで,これだけでもアニメーションは可能です(今やっている仕事ではelm-uiでアニメーションを扱う場合にAnimatorのみを使っている)。
これにAnimator.CssAnimator.Inlineを組み合わせるとCSSアニメーションがより簡単に実現できます。

では,一番簡単なAnimator + Animator.Inline で冒頭にあるようなメニューを作りましょう。

Timeline

import Animator exposing (Timeline)

type Content
    = Whippet
    | BorderCollie
    | Kooikerhondje

type Model = 
    { content : Timeline Content
    } 

initialModel : Model
initialModel =
    { content = Animator.init Whippet
    }

アニメーションと関連させたいデータをTimeline型でラップします。
初期化の際にはAnimator.initを使いましょう。

Animator

type Msg
    = Tick Time.Posix  -- 時間経過ごとに呼び出される
    | Select Content   -- メニュー切り替え時に呼び出される

animator : Animator.Animator Model
animator =
    Animator.animator
        |> Animator.watching .content (\content model -> { model | content = content })

subscriptions : Model -> Sub Msg
subscriptions model =
                Animator.toSubscription Tick model animator

Animator.Timeline を更新するための型が Animator.Animator です。

elm-animatorは時間経過とともにTimelineの状態を更新するのでsubscriptionsで時間経過を監視します。

Update

update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
    case msg of
        -- 時間経過とともにアニメーションする
        Tick posix ->
            ( Animator.update posix animator model, Cmd.none )

        -- メニューの項目クリック時に次のアニメーションの指定をする
        Select content ->
            ( { model
                | content = Animator.go Animator.slowly content model.content
              }
            , Cmd.none
            )

Tickの場合の処理は大抵これになると思います。
Selectの方でTimelineの状態を更新しています, このとき Animator.slowyAnimator.millisなどでアニメーションのスピードを指定できます。

View

viewIndicator : Model -> Html Msg
viewIndicator model =
    div
        [ style "width" "160px"
        , style "background-color" "orange"
        , style "height" "8px"
        , Inline.xy model.content <|
            \state ->
                { x =
                    let
                        index = 
                            [Whippet, BorderCollie, Kooikerhondje]
                            |> List.elemIndex state
                            |> Maybe.withDefault 0
                    in 
                        Animator.at (toFloat (index * 160))
                , y = Animator.at 0
                }
        ]
        []

viewのうち,今回アニメーションさせたインジケータ部分のコード。
選択中のContentがメニューのn番目にあるかを求めて, x座標を(n*160)pxまでアニメーションするようにしています。y座標は常に0です。

ソースコード

今回のコードをEllieに貼っておきます。
https://ellie-app.com/bFxqJFhDhHBa1

所感

ElmでCSSアニメーションをやるのであれば,elm-cssがあるし,そもそも外部のCSSファイルを使うのが手軽です。
ただelm-animatorはモデルの状態とアニメーションの関係が比較的分かりやすいのと, CSS以外のアニメーションも同じ仕組みで扱えるので個人的には気に入って使っています。

将来的にはelm-uiにもアニメーションを扱えるための仕組みを取り入れようと調査中らしいので,このelm-animatorなんかがベースになりそうな感じです。

10
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
3