PhxDemo.Zoom (phx_demo v0.1.1)

Copy Markdown View Source

Auto-zoom from the cursor targets recorded by glide/3, and from the target boxes of :upload events (upload/4, drop_files/4), so the view holds on the file input or drop zone while the upload runs.

Glides that happen close together form a cluster. For each cluster the view eases in on the first target, pans between targets, holds after the last one, then eases back out. Each target's zoom is capped so the whole element (with margin) stays in frame.

The result is an ffmpeg zoompan filter, driven by the input timestamp (it), with smoothstep easing between keyframes.

Summary

Functions

The zoompan filter for keyframes, producing out (%{width:, height:}) frames from input whose CSS-pixel viewport is viewport.

Keyframes {t_ms, zoom, cx, cy} in CSS pixels from a plan's events. Returns [] when zoom is off or there are no glides.

A piecewise ffmpeg expression over it (seconds) that eases between keyframe values with smoothstep.

Functions

filter(keyframes, viewport, out, fps)

The zoompan filter for keyframes, producing out (%{width:, height:}) frames from input whose CSS-pixel viewport is viewport.

keyframes(events, viewport, setting)

Keyframes {t_ms, zoom, cx, cy} in CSS pixels from a plan's events. Returns [] when zoom is off or there are no glides.

piecewise(keyframes, value)

A piecewise ffmpeg expression over it (seconds) that eases between keyframe values with smoothstep.

It's a flat sum, the first value plus each segment's change scaled by its progress (0 before the segment, 1 after it), rather than nested if()s: ffmpeg's expression parser gives up past about 100 levels of nesting, which a few minutes of demo reaches. Segments that don't change the value add nothing.

iex> PhxDemo.Zoom.piecewise([{0, 1.0, 0, 0}, {1000, 2.0, 0, 0}], fn {_, z, _, _} -> z end)
"1.0+(1.0)*clip((it-0.0)/1.0,0,1)*clip((it-0.0)/1.0,0,1)*(3-2*clip((it-0.0)/1.0,0,1))"

iex> PhxDemo.Zoom.piecewise([{0, 1.5, 0, 0}, {800, 1.5, 0, 0}], fn {_, z, _, _} -> z end)
"1.5"