まえおき
今日はElmでアニメーションをサポートするパッケージの一つをさくっと紹介します。
elm-animator は elm-ui の作者でもあるmdgriffithさんが開発する Elm でアニメーションを扱うためのパッケージです。
- Animator : 時間経過によるデータの変化を管理するTimelineを扱う
- Animatior.Css : TimelineでCSSのkeyframesを使ったアニメーションを扱う。いろいろできる
- Animator.Inline : 座標移動とか背景色のアニメーションとか限られた用途を手軽に扱う
中心となるのはAnimatorで,これだけでもアニメーションは可能です(今やっている仕事ではelm-uiでアニメーションを扱う場合にAnimatorのみを使っている)。
これにAnimator.CssやAnimator.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.slowyやAnimator.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なんかがベースになりそうな感じです。