# Pan and zoom

> A view onto a plane larger than the screen: moved by a drag, scaled about the point under the pointer.

A canvas, a diagram or a map is larger than the screen, or finer than it shows.
People move over it by panning and look closer by zooming, and they do both
constantly, without thinking. It has to feel like moving a sheet of paper under
the hand.

## Best practices

**Keep the point under the pointer still.** Zooming grows or shrinks the plane
around one point: the one under the pointer, or between two fingers. Zooming
about the middle of the view makes people chase what they were looking at.

**Let what is dragged stay under the pointer.** A pan moves the plane exactly as
far as the pointer moved, at any zoom.

**Make equal gestures equal.** Zoom multiplies: the same turn of a wheel or
spread of the fingers doubles the scale whether it began at 10% or at 1000%. A
turn one way and the same turn back return to the same view.

**Tell a pinch from a scroll.** On a trackpad two fingers scroll and a pinch
zooms; a mouse wheel scrolls, and zooms with the command or Control key. With
Shift, a wheel that has one axis scrolls sideways. A device that reports in
lines moves as far as one that reports in pixels.

**Hold zoom between limits, and stop there.** At a limit, a further zoom does
nothing — the view does not creep sideways.

**Step through the scales people know.** Zoom in and zoom out go to the next of
a few round scales — 50%, 100%, 200% — and from between two, to the nearer one
that way. Offer "fit" and "100%" by name.

**Fit what matters, with room around it.** Fitting shows the whole of a part of
the plane, as large as it will go, centred, with a margin. Fitting nothing, or
a single point, does not zoom.

**Reveal by the least movement.** Bringing something into view — the next
result of a search, a node reached by the keyboard — moves the view only as far
as needed, leaves a little room past it, and does nothing if it is already in
view. It does not change the zoom.

**Move the view along under a drag at its edge.** A drag that reaches the edge
of the view wants what lies beyond it. Within a margin of the edge the view
moves that way — at a walk at first, faster the further the pointer goes, past
the edge too — and stops the moment the pointer comes back. Only an edge the
drag has travelled toward pulls: a drag that begins beside an edge has not asked
for anything yet.

**Keep measurements on the screen in screen units.** A handle, a hit target and
the distance at which things snap are sizes on the screen: divide them by the
zoom, so that they are the same to the hand at any scale.

## Conventions

| Intent         | Pointer                                      | Keyboard                             | Touch                 |
| -------------- | -------------------------------------------- | ------------------------------------ | --------------------- |
| Pan            | Scroll; drag with Space or the middle button | Arrow keys, when nothing is selected | Drag with two fingers |
| Zoom           | Pinch; wheel with Command or Control         | Command-Plus, Command-Minus          | Pinch                 |
| Fit everything | —                                            | Shift-1                              | —                     |
| Actual size    | —                                            | Command-0                            | —                     |

Command is ⌘ on Apple platforms and Ctrl elsewhere.

See also [Snapping](https://ui.publictheta.com/foundations/snap.md).

## Behaviour

Each statement is verified by a test in Chromium, Chromium (touch), Firefox, WebKit, WebKit (touch), unless it names the environments it applies to or is marked open.

### Places

- A point of the plane, taken to the screen and back, is the same point.
- The view's corner is at the top-left of the screen, and a unit of the plane is `zoom` pixels.
- A part of the plane is on the screen where its corner is, `zoom` times as large.

### Far from zero

- There is a point to measure from that the view is never 4096 screen pixels past.
- The point stays the same while the view moves a little, so what is placed from it stays placed.
- The point is a whole number of the plane's units at any zoom the view allows.

### Panning

- What is shown moves with the drag: the point under the pointer stays under it.
- A pan of no distance is the same view.

### Zooming

- The point under the anchor stays under it, whatever the zoom.
- Zoom is held between its limits, and a view at a limit asked to go past it does not move.
- Zooming by a factor and then by its inverse returns to the same view.
- A step in or out goes to the next named scale, from on one or between two.
- A step past the last stop stays at it.

### Fitting

- A part of the plane is shown whole, in the middle, as large as the padding allows.
- A part with no size is centred at the zoom the view has.
- Fitting does not zoom beyond the limits.

### Revealing

- A part already in view leaves the view as it is.
- A part out of view is brought in by the least movement, with the margin to spare.
- After revealing, the part is within the view wherever it fits.
- A part larger than the view is shown from its start.

### The wheel

- A turn of the wheel scrolls: what is shown moves against the turn.
- With Shift, a wheel of one axis scrolls sideways.
- A pinch, or the wheel with the command or Control key, zooms: in for a turn away, out for a turn toward.
- Equal turns multiply the zoom equally, and a turn and its opposite undo each other.
- A wheel that reports in lines or pages moves as far as one that reports the same in pixels.
- One notch zooms by no more than a notch should, however large the device says it was.

### A drag near the edge

- A drag held clear of the edges moves the view nowhere.
- Within a margin of an edge the view moves that way, faster the further the pointer goes, past the edge too.
- It moves as fast as a list scrolls under a drag held as far past its edge.
- An edge does not pull a drag that has not travelled toward it: one begun beside an edge moves nothing until it heads for it.
- A view too small to have a middle clear of its edges has narrower margins: its middle half is still.

## Reference implementation

React: `npx shadcn@latest add https://ui.publictheta.com/r/viewport.json`
