DESIGN.md §4-zoom — pinch, double-tap/click, wheel+ctrl, and three toolbar
buttons (zoom in/out/actual-size) all drive a single scale/pan state on
the active slide's <img> — never .shoji-slide-media itself, which the
rotateFlip plugin (§4) already transforms; nesting on the inner element
instead of fighting over the same transform string means a rotated and
zoomed photo behaves correctly for free (the outer rotate carries the
inner pan/scale along with it as a rigid unit, which is also the visually
expected result — see DESIGN.md's note on this plugin for the full
reasoning). Pinch/double-tap/wheel are core's own gesture relay (§2.4) —
scaffolding that existed specifically for this plugin to consume, not
reimplemented here. Pan (single-pointer drag while zoomed) is the one
piece core's relay doesn't cover — core's own drag-to-navigate/
drag-to-close would otherwise fight over the same drag — so this plugin
registers a zoom gate (Gallery.registerZoomGate, §4-zoom) that suspends
core's drag handling entirely while zoomed, and tracks pan with its own
minimal raw pointer listeners instead of reusing GestureEngine (whose
axis-locked model — pick horizontal or vertical per gesture — is the
wrong shape for a 2D pan that needs both at once).
DESIGN.md §4-zoom — pinch, double-tap/click, wheel+ctrl, and three toolbar buttons (zoom in/out/actual-size) all drive a single
scale/pan state on the active slide's<img>— never.shoji-slide-mediaitself, which the rotateFlip plugin (§4) already transforms; nesting on the inner element instead of fighting over the same transform string means a rotated and zoomed photo behaves correctly for free (the outer rotate carries the inner pan/scale along with it as a rigid unit, which is also the visually expected result — see DESIGN.md's note on this plugin for the full reasoning). Pinch/double-tap/wheel are core's own gesture relay (§2.4) — scaffolding that existed specifically for this plugin to consume, not reimplemented here. Pan (single-pointer drag while zoomed) is the one piece core's relay doesn't cover — core's own drag-to-navigate/ drag-to-close would otherwise fight over the same drag — so this plugin registers a zoom gate (Gallery.registerZoomGate, §4-zoom) that suspends core's drag handling entirely while zoomed, and tracks pan with its own minimal raw pointer listeners instead of reusingGestureEngine(whose axis-locked model — pick horizontal or vertical per gesture — is the wrong shape for a 2D pan that needs both at once).