# `PhxDemo.Zoom`
[🔗](https://github.com/thenatespack/phoenix_demo/blob/main/lib/phx_demo/zoom.ex#L1)

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.

# `filter`

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

# `keyframes`

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`

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"

---

*Consult [api-reference.md](api-reference.md) for complete listing*
