elm-animator
elm-animator copied to clipboard
arrived returns incorrect state
Sometimes arrived
will return an old state. This is illustrated in this ellie. Code reproduced below for reference.
Basically the program is randomly incrementing an Int
every 50 - 150 ms, and updating the Timeline Int
with veryQuickly
which is 100 ms. When these timings overlap, the arrived
value occasionally reverts to the initial state for some reason. In the example, you'll see this as the third column occasionally zeroing out.
I haven't explored all the permutations of timings, but you can vary delayMillis
and fuzz
in the code below to experiment.
module Sandbox.AnimatorTest exposing (..)
import Animator exposing (Animator, Timeline, arrived, current, go, toSubscription, veryQuickly, watchingWith)
import Browser exposing (Document, element)
import Delay exposing (TimeUnit(..), after)
import Dict exposing (Dict, fromList)
import Html exposing (Html, div, text)
import Html.Attributes exposing (style)
import Random exposing (Seed, float, initialSeed, step)
import String exposing (fromInt)
import Time exposing (Posix)
type alias AnimatedModel =
{ real : Int
, timeline : Timeline Int
, seed : Seed
}
type AnimationMsg
= Tick Posix
| IncrementSomething
main : Program () AnimatedModel AnimationMsg
main =
element
{ init = init
, update = update
, view = view
, subscriptions = subscriptions
}
delayMillis =
100
fuzz =
50
limit =
8
init : () -> ( AnimatedModel, Cmd AnimationMsg )
init () =
( { real = 0
, timeline = Animator.init 0
, seed = initialSeed 1
}
, after delayMillis Millisecond IncrementSomething
)
update : AnimationMsg -> AnimatedModel -> ( AnimatedModel, Cmd AnimationMsg )
update msg model =
case msg of
Tick posix ->
( Animator.update posix animator model, Cmd.none )
IncrementSomething ->
let
newModel =
model.real + 1
( fuzzedDelay, newSeed ) =
step (float (delayMillis - fuzz) (delayMillis + fuzz)) model.seed
maybeKeepGoing =
if continue newModel then
after fuzzedDelay Millisecond IncrementSomething
else
Cmd.none
in
( { model
| real = newModel
, timeline = go veryQuickly newModel model.timeline
, seed = newSeed
}
, maybeKeepGoing
)
continue i =
i <= limit
view : AnimatedModel -> Html AnimationMsg
view model =
div
[ style "display" "flex"
, style "flex-direction" "row"
]
[ viewImpl "real" model.real
, viewImpl "current" <| current model.timeline
, viewImpl "arrived" <| arrived model.timeline
]
viewImpl : String -> Int -> Html msg
viewImpl label i =
div [ style "margin" "10px" ]
[ div [] [ text label ]
, div [] [ text <| fromInt i ]
]
animator : Animator AnimatedModel
animator =
let
updateTimeline nt m =
{ m | timeline = nt }
in
Animator.animator
|> watchingWith .timeline
updateTimeline
continue
subscriptions : AnimatedModel -> Sub AnimationMsg
subscriptions model =
toSubscription Tick model animator
I've simplified the example a bit.
I'm experiencing this issue as well, where my Timeline eventually reaches "Nothing", which is correctly returned by "current", but "arrived" still shows the previous "Just X".