Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Clock / Animations #269

Closed
cstjean opened this issue Nov 7, 2024 · 2 comments
Closed

Clock / Animations #269

cstjean opened this issue Nov 7, 2024 · 2 comments

Comments

@cstjean
Copy link

cstjean commented Nov 7, 2024

Pluto has a clock widget, which basically increases the value inside some Observable every N millisecond. This is convenient to drive animations. Is there something similar in Bonito.jl?

Associated discourse post

I've been able to get animations working with App by modifying one of the examples using @async (@spawn also works) but when serving it with Server, the whole GUI just doesn't respond.

using Bonito, Bonito.Observables, Base.Threads

import Bonito.TailwindDashboard as D

function create_svg(sl_nsamples, sl_sample_step, sl_phase, sl_radii, color)
    # COPY PASTED FROM DOCS
    width, height = 900, 300
    cxs_unscaled = [i*sl_sample_step + sl_phase for i in 1:sl_nsamples]
    cys = sin.(cxs_unscaled) .* height/3 .+ height/2
    cxs = cxs_unscaled .* width/4pi
    rr = sl_radii
    # DOM.div/svg/etc is just a convenience in Bonito for using Hyperscript, but circle isn't wrapped like that yet
    geom = [SVG.circle(cx=cxs[i], cy=cys[i], r=rr, fill=color(i)) for i in 1:sl_nsamples[]]
    return SVG.svg(SVG.g(geom...);
        width=width, height=height
    )
end

app = App() do session
    # COPY PASTED FROM DOCS, with obs_phase changed
    colors = ["black", "gray", "silver", "maroon", "red", "olive", "yellow", "green", "lime", "teal", "aqua", "navy", "blue", "purple", "fuchsia"]
    color(i) = colors[i%length(colors)+1]
    sl_nsamples = D.Slider("nsamples", 1:200, value=100)
    sl_sample_step = D.Slider("sample step", 0.01:0.01:1.0, value=0.1)
    sl_phase = D.Slider("phase", 0.0:0.1:6.0, value=0.0)
    sl_radii = D.Slider("radii", 0.1:0.1:60, value=10.0)
    obs_phase = Observable(1.0)
    svg = map(create_svg, sl_nsamples.value, sl_sample_step.value, obs_phase, sl_radii.value, color)

    # For animation
    @async for v in -10:0.002:10
        obs_phase[] = v
        sleep(0.01)
    end

    return DOM.div(D.FlexRow(D.FlexCol(sl_nsamples, sl_sample_step, obs_phase, sl_radii), svg))
end

app  # this works

# This doesn't: the web page renders, but there's no interactivity.
#port = 9384
#url = "0.0.0.0"
#server = Bonito.Server(app, url, port)

Incidentally, is there any way to debug these things? There's probably a stacktrace somewhere.

@async / @spawn being brittle is not particularly surprising; what are the alternatives?

@frankier
Copy link
Contributor

This may be relevant: #260

@cstjean
Copy link
Author

cstjean commented Jan 7, 2025

Found it!

@spawn begin
    sleep(2)
    for v in -10:0.002:10
        obs_phase[] = v
        sleep(0.01)
    end
end

works out. The sleep(2) is critical, otherwise none of the interactivity works. So indeed, it's probably #260, good eye @frankier.

While #260 is not ideal, this @spawn loop solution otherwise works well for driving animations. If the user clicked a button to start it off, there'd be no problem at all.

@cstjean cstjean closed this as completed Jan 7, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants