livebook-dev / kino

Client-driven interactive widgets for Livebook

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Simpler interface for `Kino.animate/3`

BrooklinJazz opened this issue · comments

Right now, the interface for Kino.animate/3 is:

Kino.animate(100, 0, fn i ->
  md = Kino.Markdown.new("**Iteration: `#{i}`**")
  {:cont, md, i + 1}
end)

Would there be an interest in providing an alternative interface using ranges (or any collection)? I.e.

Kino.animate(1..10, fn i -> Kino.Markdown.new("**Iteration: `#{i}`**") end)

Configuration could be done with options such as :interval (with the default being 1000) and :repeat (with the default being true). I.e.

Kino.animate(1..10, fn i -> Kino.Markdown.new("**Iteration: `#{i}`**") end, interval: 100, repeat: false)

I'm happy to implement this if there's an interest!

Kino.animate is a wrapper around Kino.Frame, so you can do this today as:

frame = Kino.Frame.new

for i <- 1..10 do
  Kino.Frame.render(frame, Kino.Markdown.new("**Iteration: `#{i}`**"))
end

Or:

frame = Kino.Frame.new

for i <- Stream.interval(100) |> Stream.zip(1..10) do
  Kino.Frame.render(frame, Kino.Markdown.new("**Iteration: `#{i}`**"))
end

We were even discussing getting rid of Kino.animate altogether but there was no conclusion.

To add my two cents to the discussion - I think that Kino.animate/3 is useful to demonstrate that animations are possible. It's also a nice wrapper that could be made even better. IMO for devs new to the library, it's not obvious that we can use Kino.Frame to handle animations.

I suppose that could be handled with demo documentation in Kino.Frame like you mentioned.
However, I like the lightweight option with Kino.animate/3

Just my two cents! I wouldn't be severely affected if y'all decided it was best to remove Kino.animate/3, and I'd be happy to help with the documentation if that's the direction things go.

Please feel free to close this issue :) Thank you for your response @josevalim!

Yes, let's leave it open because the discussion also relates to Kino.Control.stream. We should unify those as much as we can and I assume the range case would also be useful for streams.

The main thing about Kino.animate is that it takes care of the frame and updates, so I would extend the API to either of those:

Stream.interval(100)
|> Stream.take(10)
|> Stream.map(fn i -> Kino.Markdown.new("**Iteration: `#{i}`**") end)
|> Kino.animate()

or

Stream.interval(100)
|> Stream.take(10)
|> Kino.animate(fn i -> Kino.Markdown.new("**Iteration: `#{i}`**") end)

The feed could very well be Kino.Control.stream! @josevalim wdyt?