Thank you for the recommendation! I got something working by tweaking a Bonito.jl example:
using Bonito, Bonito.Observables, Base.Threads
import Bonito.TailwindDashboard as D
function create_svg(sl_nsamples, sl_sample_step, sl_phase, sl_radii, color)
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
obs_phase = Observable(1.0)
app = App() do session
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)
svg = map(create_svg, sl_nsamples.value, sl_sample_step.value, obs_phase, sl_radii.value, color)
return DOM.div(D.FlexRow(D.FlexCol(sl_nsamples, sl_sample_step, obs_phase, sl_radii), svg))
end
@spawn for v in -10:0.01:10
obs_phase[] = v
sleep(0.01)
end
app
It’s quite straight-forward and it looks cool, props to @sdanisch !
Not quite sure how to make that logic work out per-user (maybe just moving the spawn and observable inside of the do), but I’ll figure it out.