Skip to content

Commit

Permalink
Refactor Toggle to use tick updates instead of an async task for th…
Browse files Browse the repository at this point in the history
…e animation (#4482)

* make toggle update on ticks and add interaction video

* use click for toggle

* update ticks in custom recording function

* delete unused file

* add toggle interactive example

* fix setup block scope name
  • Loading branch information
jkrumbiegel authored Oct 15, 2024
1 parent 97a8bb0 commit 9f49bb0
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 23 deletions.
2 changes: 1 addition & 1 deletion docs/fake_interaction.jl
Original file line number Diff line number Diff line change
Expand Up @@ -129,8 +129,8 @@ function recordframe_with_cursor_overlay!(io, cursor_pos, viewport, cursor_img,
copy!(view(io.buffer, 1:xdim, 1:ydim), glnative)

render_cursor!(io.buffer, (xdim, ydim), cursor_pos, viewport, cursor_img, cursor_tip_frac)

write(io.io, io.buffer)
Makie.next_tick!(io.tick_controller)
return
end

Expand Down
56 changes: 44 additions & 12 deletions docs/src/reference/blocks/toggle.md
Original file line number Diff line number Diff line change
@@ -1,28 +1,60 @@


# Toggle

A toggle with an attribute `active` that can either be true or false, to enable
or disable properties of an interactive plot.

```@figure backend=GLMakie
```@example toggle
using GLMakie
GLMakie.activate!() # hide
fig = Figure()
ax = Axis(fig[1, 1])
ax = Axis(fig[1, 1], limits = (0, 600, -2, 2))
hidexdecorations!(ax)
toggles = [Toggle(fig, active = active) for active in [true, false]]
labels = [Label(fig, lift(x -> x ? "$l visible" : "$l invisible", t.active))
for (t, l) in zip(toggles, ["sine", "cosine"])]
t = Observable(0.0)
points = lift(t) do t
x = range(t-1, t+1, length = 500)
@. sin(x) * sin(2x) * sin(4x) * sin(23x)
end
fig[1, 2] = grid!(hcat(toggles, labels), tellheight = false)
lines!(ax, points, color = (1:500) .^ 2, linewidth = 2, colormap = [(:blue, 0.0), :blue])
line1 = lines!(0..10, sin, color = :blue, visible = false)
line2 = lines!(0..10, cos, color = :red)
gl = GridLayout(fig[2, 1], tellwidth = false)
Label(gl[1, 1], "Live Update")
toggle = Toggle(gl[1, 2], active = false)
connect!(line1.visible, toggles[1].active)
connect!(line2.visible, toggles[2].active)
on(fig.scene.events.tick) do tick
toggle.active[] || return
t[] += tick.delta_time
end
fig
nothing # hide
```

```@setup toggle
using ..FakeInteraction
events = [
Wait(0.5),
Lazy() do fig
MouseTo(relative_pos(toggle, (0.7, 0.3)))
end,
Wait(0.2),
LeftClick(),
Wait(2.0),
LeftClick(),
Wait(1.5),
LeftClick(),
Wait(2.0),
]
interaction_record(fig, "toggle_example.mp4", events)
```

```@raw html
<video autoplay loop muted playsinline src="./toggle_example.mp4" width="600"/>
```


Expand Down
25 changes: 15 additions & 10 deletions src/makielayout/blocks/toggle.jl
Original file line number Diff line number Diff line change
Expand Up @@ -46,37 +46,42 @@ function initialize_block!(t::Toggle)

mouseevents = addmouseevents!(topscene, t.layoutobservables.computedbbox)

onmouseleftdown(mouseevents) do event
updatefunc = Ref{Any}(nothing)

onmouseleftclick(mouseevents) do event
if animating[]
return Consume(true)
end
animating[] = true

tstart = time()

anim_posfrac = Animations.Animation(
[0, t.toggleduration[]],
t.active[] ? [1.0, 0.0] : [0.0, 1.0],
Animations.sineio())

coloranim = Animations.Animation(
[0, t.toggleduration[]],
t.active[] ? [t.framecolor_active[], t.framecolor_inactive[]] : [t.framecolor_inactive[], t.framecolor_active[]],
Animations.sineio())

t.active[] = !t.active[]
@async while true
tim = time() - tstart

tstart = topscene.events.tick[].time

updatefunc[] = on(topscene.events.tick) do tick
dt = tick.time - tstart
# request endpoint values in every frame if the layout changes during
# the animation
buttonpos[] = [Animations.linear_interpolate(anim_posfrac(tim),
buttonpos[] = [Animations.linear_interpolate(anim_posfrac(dt),
button_endpoint_inactive[], button_endpoint_active[])]
framecolor[] = coloranim(tim)
if tim >= t.toggleduration[]
framecolor[] = coloranim(dt)
if dt >= t.toggleduration[]
Observables.off(updatefunc[])
updatefunc[] = nothing
animating[] = false
break
end
sleep(1/FPS[])
end

return Consume(true)
end

Expand Down

0 comments on commit 9f49bb0

Please sign in to comment.