diff --git a/README.md b/README.md index f5bf140d..235af710 100644 --- a/README.md +++ b/README.md @@ -75,7 +75,7 @@ With a script tag: With a script tag from a CDN: ```html - + ``` ## Usage @@ -155,7 +155,7 @@ See this [stackoverflow question](https://stackoverflow.com/questions/70428922/p > **Panzoom**(`elem`, `options`?): `[PanzoomObject](#PanzoomObject)` -Defined in: [panzoom.ts:59](https://github.com/timmywil/panzoom/blob/211bc595f528ed19b493a546219fe9bafe4b89a4/src/panzoom.ts#L59) +Defined in: [panzoom.ts:59](https://github.com/timmywil/panzoom/blob/c05ae3d25396d280b34dc17c7324768425d9c900/src/panzoom.ts#L59) ## Parameters @@ -179,7 +179,7 @@ Includes `MiscOptions`, `PanOptions`, and `ZoomOptions` These options can be passed to `Panzoom()`, as well as any pan or zoom function. One exception is `force`, which can only be passed to methods like `pan()` or `zoom()`, but not `Panzoom()` or `setOptions()` as it should not be set globally. -Defined in: [types.ts:19](https://github.com/timmywil/panzoom/blob/211bc595f528ed19b493a546219fe9bafe4b89a4/src/types.ts#L19) +Defined in: [types.ts:19](https://github.com/timmywil/panzoom/blob/c05ae3d25396d280b34dc17c7324768425d9c900/src/types.ts#L19) ## Indexable @@ -191,7 +191,7 @@ Defined in: [types.ts:19](https://github.com/timmywil/panzoom/blob/211bc595f528e > `optional` **animate**: `boolean` (Default: **false**) -Defined in: [types.ts:21](https://github.com/timmywil/panzoom/blob/211bc595f528ed19b493a546219fe9bafe4b89a4/src/types.ts#L21) +Defined in: [types.ts:21](https://github.com/timmywil/panzoom/blob/c05ae3d25396d280b34dc17c7324768425d9c900/src/types.ts#L21) Whether to animate transitions @@ -201,7 +201,7 @@ Whether to animate transitions > `optional` **canvas**: `boolean` (Default: **false**) -Defined in: [types.ts:32](https://github.com/timmywil/panzoom/blob/211bc595f528ed19b493a546219fe9bafe4b89a4/src/types.ts#L32) +Defined in: [types.ts:32](https://github.com/timmywil/panzoom/blob/c05ae3d25396d280b34dc17c7324768425d9c900/src/types.ts#L32) This option treats the Panzoom element's parent as a canvas. Effectively, Panzoom binds the @@ -218,7 +218,7 @@ where the `cursor` style is applied (i.e. the parent). > `optional` **duration**: `number` (Default: **200**) -Defined in: [types.ts:34](https://github.com/timmywil/panzoom/blob/211bc595f528ed19b493a546219fe9bafe4b89a4/src/types.ts#L34) +Defined in: [types.ts:34](https://github.com/timmywil/panzoom/blob/c05ae3d25396d280b34dc17c7324768425d9c900/src/types.ts#L34) Duration of the transition (ms) @@ -228,7 +228,7 @@ Duration of the transition (ms) > `optional` **easing**: `string` (Default: **"ease-in-out"**) -Defined in: [types.ts:36](https://github.com/timmywil/panzoom/blob/211bc595f528ed19b493a546219fe9bafe4b89a4/src/types.ts#L36) +Defined in: [types.ts:36](https://github.com/timmywil/panzoom/blob/c05ae3d25396d280b34dc17c7324768425d9c900/src/types.ts#L36) CSS Easing used for transitions @@ -238,7 +238,7 @@ CSS Easing used for transitions > `optional` **exclude**: `Element`[] (Default: **[]**) -Defined in: [types.ts:43](https://github.com/timmywil/panzoom/blob/211bc595f528ed19b493a546219fe9bafe4b89a4/src/types.ts#L43) +Defined in: [types.ts:43](https://github.com/timmywil/panzoom/blob/c05ae3d25396d280b34dc17c7324768425d9c900/src/types.ts#L43) Add elements to this array that should be excluded from Panzoom handling. @@ -251,7 +251,7 @@ e.g. links and buttons that should not propagate the click event. > `optional` **excludeClass**: `string` (Default: **"panzoom-exclude"**) -Defined in: [types.ts:50](https://github.com/timmywil/panzoom/blob/211bc595f528ed19b493a546219fe9bafe4b89a4/src/types.ts#L50) +Defined in: [types.ts:50](https://github.com/timmywil/panzoom/blob/c05ae3d25396d280b34dc17c7324768425d9c900/src/types.ts#L50) Add this class to any element within the Panzoom element that you want to exclude from Panzoom handling. That @@ -264,7 +264,7 @@ e.g. links and buttons that should not propagate the click event. > `optional` **force**: `boolean` -Defined in: [types.ts:66](https://github.com/timmywil/panzoom/blob/211bc595f528ed19b493a546219fe9bafe4b89a4/src/types.ts#L66) +Defined in: [types.ts:66](https://github.com/timmywil/panzoom/blob/c05ae3d25396d280b34dc17c7324768425d9c900/src/types.ts#L66) `force` should be used sparingly to temporarily override and ignore options such as disablePan, @@ -291,7 +291,7 @@ panzoom.zoom(1, { force: true }) }\*\*) -Defined in: [types.ts:91](https://github.com/timmywil/panzoom/blob/211bc595f528ed19b493a546219fe9bafe4b89a4/src/types.ts#L91) +Defined in: [types.ts:91](https://github.com/timmywil/panzoom/blob/c05ae3d25396d280b34dc17c7324768425d9c900/src/types.ts#L91) On the first pointer event, when panning starts, the default Panzoom behavior is to call @@ -332,7 +332,7 @@ Panzoom(elem, { > `optional` **noBind**: `boolean` -Defined in: [types.ts:95](https://github.com/timmywil/panzoom/blob/211bc595f528ed19b493a546219fe9bafe4b89a4/src/types.ts#L95) +Defined in: [types.ts:95](https://github.com/timmywil/panzoom/blob/c05ae3d25396d280b34dc17c7324768425d9c900/src/types.ts#L95) Skip binding the default Panzoom event listeners @@ -342,7 +342,7 @@ Skip binding the default Panzoom event listeners > `optional` **origin**: `string` -Defined in: [types.ts:109](https://github.com/timmywil/panzoom/blob/211bc595f528ed19b493a546219fe9bafe4b89a4/src/types.ts#L109) +Defined in: [types.ts:109](https://github.com/timmywil/panzoom/blob/c05ae3d25396d280b34dc17c7324768425d9c900/src/types.ts#L109) **Change this at your own risk.** The `transform-origin` is the origin from which transforms are applied. @@ -362,7 +362,7 @@ And again, changing this for SVG in IE doesn't work at all. > `optional` **overflow**: `string` (Default: **"hidden"**) -Defined in: [types.ts:111](https://github.com/timmywil/panzoom/blob/211bc595f528ed19b493a546219fe9bafe4b89a4/src/types.ts#L111) +Defined in: [types.ts:111](https://github.com/timmywil/panzoom/blob/c05ae3d25396d280b34dc17c7324768425d9c900/src/types.ts#L111) The overflow CSS value for the parent. Defaults to 'hidden' @@ -372,7 +372,7 @@ The overflow CSS value for the parent. Defaults to 'hidden' > `optional` **pinchAndPan**: `boolean` (Default: **false**) -Defined in: [types.ts:124](https://github.com/timmywil/panzoom/blob/211bc595f528ed19b493a546219fe9bafe4b89a4/src/types.ts#L124) +Defined in: [types.ts:124](https://github.com/timmywil/panzoom/blob/c05ae3d25396d280b34dc17c7324768425d9c900/src/types.ts#L124) Set to true to enable panning during pinch zoom. Note: this is zooming to a point and panning in the same @@ -391,7 +391,7 @@ https://github.com/timmywil/panzoom/issues/606 > `optional` **setTransform**: (`elem`, `__namedParameters`, `_options`?) => `void` -Defined in: [types.ts:128](https://github.com/timmywil/panzoom/blob/211bc595f528ed19b493a546219fe9bafe4b89a4/src/types.ts#L128) +Defined in: [types.ts:128](https://github.com/timmywil/panzoom/blob/c05ae3d25396d280b34dc17c7324768425d9c900/src/types.ts#L128) Set the transform using the proper prefix. @@ -437,7 +437,7 @@ const panzoom = Panzoom(elem, { > `optional` **silent**: `boolean` -Defined in: [types.ts:130](https://github.com/timmywil/panzoom/blob/211bc595f528ed19b493a546219fe9bafe4b89a4/src/types.ts#L130) +Defined in: [types.ts:130](https://github.com/timmywil/panzoom/blob/c05ae3d25396d280b34dc17c7324768425d9c900/src/types.ts#L130) Silence all events @@ -447,7 +447,7 @@ Silence all events > `optional` **startScale**: `number` (Default: **1**) -Defined in: [types.ts:136](https://github.com/timmywil/panzoom/blob/211bc595f528ed19b493a546219fe9bafe4b89a4/src/types.ts#L136) +Defined in: [types.ts:136](https://github.com/timmywil/panzoom/blob/c05ae3d25396d280b34dc17c7324768425d9c900/src/types.ts#L136) Scale used to set the beginning transform @@ -457,7 +457,7 @@ Scale used to set the beginning transform > `optional` **startX**: `number` (Default: **0**) -Defined in: [types.ts:132](https://github.com/timmywil/panzoom/blob/211bc595f528ed19b493a546219fe9bafe4b89a4/src/types.ts#L132) +Defined in: [types.ts:132](https://github.com/timmywil/panzoom/blob/c05ae3d25396d280b34dc17c7324768425d9c900/src/types.ts#L132) X Value used to set the beginning transform @@ -467,7 +467,7 @@ X Value used to set the beginning transform > `optional` **startY**: `number` (Default: **0**) -Defined in: [types.ts:134](https://github.com/timmywil/panzoom/blob/211bc595f528ed19b493a546219fe9bafe4b89a4/src/types.ts#L134) +Defined in: [types.ts:134](https://github.com/timmywil/panzoom/blob/c05ae3d25396d280b34dc17c7324768425d9c900/src/types.ts#L134) Y Value used to set the beginning transform @@ -477,7 +477,7 @@ Y Value used to set the beginning transform > `optional` **touchAction**: `string` (Default: **"none"**) -Defined in: [types.ts:146](https://github.com/timmywil/panzoom/blob/211bc595f528ed19b493a546219fe9bafe4b89a4/src/types.ts#L146) +Defined in: [types.ts:146](https://github.com/timmywil/panzoom/blob/c05ae3d25396d280b34dc17c7324768425d9c900/src/types.ts#L146) This value is used to set touch-action on both the Panzoom element and its parent. @@ -489,7 +489,7 @@ cannot work at the same time. ## PanOptions (includes MiscOptions) -Defined in: [types.ts:151](https://github.com/timmywil/panzoom/blob/211bc595f528ed19b493a546219fe9bafe4b89a4/src/types.ts#L151) +Defined in: [types.ts:151](https://github.com/timmywil/panzoom/blob/c05ae3d25396d280b34dc17c7324768425d9c900/src/types.ts#L151) ## Properties @@ -497,7 +497,7 @@ Defined in: [types.ts:151](https://github.com/timmywil/panzoom/blob/211bc595f528 > `optional` **contain**: `"inside"` \| `"outside"` -Defined in: [types.ts:165](https://github.com/timmywil/panzoom/blob/211bc595f528ed19b493a546219fe9bafe4b89a4/src/types.ts#L165) +Defined in: [types.ts:165](https://github.com/timmywil/panzoom/blob/c05ae3d25396d280b34dc17c7324768425d9c900/src/types.ts#L165) Contain the panzoom element either inside or outside the parent. @@ -517,7 +517,7 @@ empty space around the element will be shown. > `optional` **cursor**: `string` (Default: **"move"**) -Defined in: [types.ts:167](https://github.com/timmywil/panzoom/blob/211bc595f528ed19b493a546219fe9bafe4b89a4/src/types.ts#L167) +Defined in: [types.ts:167](https://github.com/timmywil/panzoom/blob/c05ae3d25396d280b34dc17c7324768425d9c900/src/types.ts#L167) The cursor style to set on the panzoom element @@ -527,7 +527,7 @@ The cursor style to set on the panzoom element > `optional` **disablePan**: `boolean` (Default: **false**) -Defined in: [types.ts:173](https://github.com/timmywil/panzoom/blob/211bc595f528ed19b493a546219fe9bafe4b89a4/src/types.ts#L173) +Defined in: [types.ts:173](https://github.com/timmywil/panzoom/blob/c05ae3d25396d280b34dc17c7324768425d9c900/src/types.ts#L173) Disable panning functionality. Note: disablePan does not affect focal point zooming or the contain option. @@ -539,7 +539,7 @@ The element will still pan accordingly. > `optional` **disableXAxis**: `boolean` (Default: **false**) -Defined in: [types.ts:175](https://github.com/timmywil/panzoom/blob/211bc595f528ed19b493a546219fe9bafe4b89a4/src/types.ts#L175) +Defined in: [types.ts:175](https://github.com/timmywil/panzoom/blob/c05ae3d25396d280b34dc17c7324768425d9c900/src/types.ts#L175) Pan only on the Y axis @@ -549,7 +549,7 @@ Pan only on the Y axis > `optional` **disableYAxis**: `boolean` (Default: **false**) -Defined in: [types.ts:177](https://github.com/timmywil/panzoom/blob/211bc595f528ed19b493a546219fe9bafe4b89a4/src/types.ts#L177) +Defined in: [types.ts:177](https://github.com/timmywil/panzoom/blob/c05ae3d25396d280b34dc17c7324768425d9c900/src/types.ts#L177) Pan only on the X axis @@ -559,7 +559,7 @@ Pan only on the X axis > `optional` **panOnlyWhenZoomed**: `boolean` (Default: **false**) -Defined in: [types.ts:181](https://github.com/timmywil/panzoom/blob/211bc595f528ed19b493a546219fe9bafe4b89a4/src/types.ts#L181) +Defined in: [types.ts:181](https://github.com/timmywil/panzoom/blob/c05ae3d25396d280b34dc17c7324768425d9c900/src/types.ts#L181) Disable panning while the scale is equal to the starting value @@ -569,7 +569,7 @@ Disable panning while the scale is equal to the starting value > `optional` **relative**: `boolean` (Default: **false**) -Defined in: [types.ts:179](https://github.com/timmywil/panzoom/blob/211bc595f528ed19b493a546219fe9bafe4b89a4/src/types.ts#L179) +Defined in: [types.ts:179](https://github.com/timmywil/panzoom/blob/c05ae3d25396d280b34dc17c7324768425d9c900/src/types.ts#L179) When passing x and y values to .pan(), treat the values as relative to their current values @@ -579,7 +579,7 @@ When passing x and y values to .pan(), treat the values as relative to their cur > `optional` **roundPixels**: `boolean` -Defined in: [types.ts:190](https://github.com/timmywil/panzoom/blob/211bc595f528ed19b493a546219fe9bafe4b89a4/src/types.ts#L190) +Defined in: [types.ts:190](https://github.com/timmywil/panzoom/blob/c05ae3d25396d280b34dc17c7324768425d9c900/src/types.ts#L190) Round x and y values to whole numbers. This can help prevent images and text from looking blurry, @@ -590,7 +590,7 @@ zooming in when using this option. ## ZoomOptions (includes MiscOptions) -Defined in: [types.ts:193](https://github.com/timmywil/panzoom/blob/211bc595f528ed19b493a546219fe9bafe4b89a4/src/types.ts#L193) +Defined in: [types.ts:193](https://github.com/timmywil/panzoom/blob/c05ae3d25396d280b34dc17c7324768425d9c900/src/types.ts#L193) ## Properties @@ -598,7 +598,7 @@ Defined in: [types.ts:193](https://github.com/timmywil/panzoom/blob/211bc595f528 > `optional` **disableZoom**: `boolean` (Default: **false**) -Defined in: [types.ts:195](https://github.com/timmywil/panzoom/blob/211bc595f528ed19b493a546219fe9bafe4b89a4/src/types.ts#L195) +Defined in: [types.ts:195](https://github.com/timmywil/panzoom/blob/c05ae3d25396d280b34dc17c7324768425d9c900/src/types.ts#L195) Disable zooming functionality @@ -608,7 +608,7 @@ Disable zooming functionality > `optional` **focal**: `object` -Defined in: [types.ts:202](https://github.com/timmywil/panzoom/blob/211bc595f528ed19b493a546219fe9bafe4b89a4/src/types.ts#L202) +Defined in: [types.ts:202](https://github.com/timmywil/panzoom/blob/c05ae3d25396d280b34dc17c7324768425d9c900/src/types.ts#L202) Zoom to the given point on the panzoom element. This point is expected to be relative to @@ -629,7 +629,7 @@ to the parent dimensions. > `optional` **maxScale**: `number` (Default: **4**) -Defined in: [types.ts:206](https://github.com/timmywil/panzoom/blob/211bc595f528ed19b493a546219fe9bafe4b89a4/src/types.ts#L206) +Defined in: [types.ts:206](https://github.com/timmywil/panzoom/blob/c05ae3d25396d280b34dc17c7324768425d9c900/src/types.ts#L206) The maximum scale when zooming @@ -639,7 +639,7 @@ The maximum scale when zooming > `optional` **minScale**: `number` (Default: **0.125**) -Defined in: [types.ts:204](https://github.com/timmywil/panzoom/blob/211bc595f528ed19b493a546219fe9bafe4b89a4/src/types.ts#L204) +Defined in: [types.ts:204](https://github.com/timmywil/panzoom/blob/c05ae3d25396d280b34dc17c7324768425d9c900/src/types.ts#L204) The minimum scale when zooming @@ -649,7 +649,7 @@ The minimum scale when zooming > `optional` **step**: `number` (Default: **0.3**) -Defined in: [types.ts:208](https://github.com/timmywil/panzoom/blob/211bc595f528ed19b493a546219fe9bafe4b89a4/src/types.ts#L208) +Defined in: [types.ts:208](https://github.com/timmywil/panzoom/blob/c05ae3d25396d280b34dc17c7324768425d9c900/src/types.ts#L208) The step affects zoom calculation when zooming with a mouse wheel, when pinch zooming, or when using zoomIn/zoomOut @@ -657,7 +657,7 @@ The step affects zoom calculation when zooming with a mouse wheel, when pinch zo These methods are available after initializing Panzoom. -Defined in: [types.ts:222](https://github.com/timmywil/panzoom/blob/211bc595f528ed19b493a546219fe9bafe4b89a4/src/types.ts#L222) +Defined in: [types.ts:222](https://github.com/timmywil/panzoom/blob/c05ae3d25396d280b34dc17c7324768425d9c900/src/types.ts#L222) ## Properties @@ -665,7 +665,7 @@ Defined in: [types.ts:222](https://github.com/timmywil/panzoom/blob/211bc595f528 > **bind**: () => `void` -Defined in: [types.ts:235](https://github.com/timmywil/panzoom/blob/211bc595f528ed19b493a546219fe9bafe4b89a4/src/types.ts#L235) +Defined in: [types.ts:235](https://github.com/timmywil/panzoom/blob/c05ae3d25396d280b34dc17c7324768425d9c900/src/types.ts#L235) Bind the default down, move, and up event listeners to the Panzoom element. This does not normally need to be called. @@ -688,7 +688,7 @@ panzoom.bind() > **destroy**: () => `void` -Defined in: [types.ts:237](https://github.com/timmywil/panzoom/blob/211bc595f528ed19b493a546219fe9bafe4b89a4/src/types.ts#L237) +Defined in: [types.ts:237](https://github.com/timmywil/panzoom/blob/c05ae3d25396d280b34dc17c7324768425d9c900/src/types.ts#L237) Remove all event listeners bound to the the Panzoom element @@ -702,7 +702,7 @@ Remove all event listeners bound to the the Panzoom element > **eventNames**: `object` -Defined in: [types.ts:243](https://github.com/timmywil/panzoom/blob/211bc595f528ed19b493a546219fe9bafe4b89a4/src/types.ts#L243) +Defined in: [types.ts:243](https://github.com/timmywil/panzoom/blob/c05ae3d25396d280b34dc17c7324768425d9c900/src/types.ts#L243) This object exposes the event names used by Panzoom, depending on the current browser's support for @@ -726,7 +726,7 @@ Pointer or Touch events. > **getOptions**: () => `PanzoomOptions` -Defined in: [types.ts:249](https://github.com/timmywil/panzoom/blob/211bc595f528ed19b493a546219fe9bafe4b89a4/src/types.ts#L249) +Defined in: [types.ts:249](https://github.com/timmywil/panzoom/blob/c05ae3d25396d280b34dc17c7324768425d9c900/src/types.ts#L249) Returns a _copy_ of the current options object @@ -740,7 +740,7 @@ Returns a _copy_ of the current options object > **getPan**: () => `object` -Defined in: [types.ts:245](https://github.com/timmywil/panzoom/blob/211bc595f528ed19b493a546219fe9bafe4b89a4/src/types.ts#L245) +Defined in: [types.ts:245](https://github.com/timmywil/panzoom/blob/c05ae3d25396d280b34dc17c7324768425d9c900/src/types.ts#L245) Get the current x/y translation @@ -762,7 +762,7 @@ Get the current x/y translation > **getScale**: () => `number` -Defined in: [types.ts:247](https://github.com/timmywil/panzoom/blob/211bc595f528ed19b493a546219fe9bafe4b89a4/src/types.ts#L247) +Defined in: [types.ts:247](https://github.com/timmywil/panzoom/blob/c05ae3d25396d280b34dc17c7324768425d9c900/src/types.ts#L247) Get the current scale @@ -776,7 +776,7 @@ Get the current scale > **handleDown**: (`event`) => `void` -Defined in: [types.ts:271](https://github.com/timmywil/panzoom/blob/211bc595f528ed19b493a546219fe9bafe4b89a4/src/types.ts#L271) +Defined in: [types.ts:271](https://github.com/timmywil/panzoom/blob/c05ae3d25396d280b34dc17c7324768425d9c900/src/types.ts#L271) handleDown, handleMove, and handleUp are the exact event handlers that Panzoom @@ -814,7 +814,7 @@ document.addEventListener('pointerup', panzoom.handleUp) > **handleMove**: (`event`) => `void` -Defined in: [types.ts:272](https://github.com/timmywil/panzoom/blob/211bc595f528ed19b493a546219fe9bafe4b89a4/src/types.ts#L272) +Defined in: [types.ts:272](https://github.com/timmywil/panzoom/blob/c05ae3d25396d280b34dc17c7324768425d9c900/src/types.ts#L272) #### Parameters @@ -832,7 +832,7 @@ Defined in: [types.ts:272](https://github.com/timmywil/panzoom/blob/211bc595f528 > **handleUp**: (`event`) => `void` -Defined in: [types.ts:273](https://github.com/timmywil/panzoom/blob/211bc595f528ed19b493a546219fe9bafe4b89a4/src/types.ts#L273) +Defined in: [types.ts:273](https://github.com/timmywil/panzoom/blob/c05ae3d25396d280b34dc17c7324768425d9c900/src/types.ts#L273) #### Parameters @@ -850,7 +850,7 @@ Defined in: [types.ts:273](https://github.com/timmywil/panzoom/blob/211bc595f528 > **pan**: (`x`, `y`, `panOptions`?) => `[CurrentValues](#CurrentValues)` -Defined in: [types.ts:284](https://github.com/timmywil/panzoom/blob/211bc595f528ed19b493a546219fe9bafe4b89a4/src/types.ts#L284) +Defined in: [types.ts:284](https://github.com/timmywil/panzoom/blob/c05ae3d25396d280b34dc17c7324768425d9c900/src/types.ts#L284) Pan the Panzoom element to the given x and y coordinates @@ -885,7 +885,7 @@ panzoom.pan(10, 10, { relative: true }) > **reset**: (`resetOptions`?) => `[CurrentValues](#CurrentValues)` -Defined in: [types.ts:297](https://github.com/timmywil/panzoom/blob/211bc595f528ed19b493a546219fe9bafe4b89a4/src/types.ts#L297) +Defined in: [types.ts:297](https://github.com/timmywil/panzoom/blob/c05ae3d25396d280b34dc17c7324768425d9c900/src/types.ts#L297) Reset the pan and zoom to startX, startY, and startScale. Animates by default, ignoring the global option. @@ -914,7 +914,7 @@ panzoom.reset({ animate: false }) > **resetStyle**: () => `void` -Defined in: [types.ts:306](https://github.com/timmywil/panzoom/blob/211bc595f528ed19b493a546219fe9bafe4b89a4/src/types.ts#L306) +Defined in: [types.ts:306](https://github.com/timmywil/panzoom/blob/c05ae3d25396d280b34dc17c7324768425d9c900/src/types.ts#L306) Reset the styles set on the Panzoom element and its parent (such as overflow, cursor, etc.) @@ -933,7 +933,7 @@ panzoom.resetStyle() > **setOptions**: (`options`?) => `void` -Defined in: [types.ts:319](https://github.com/timmywil/panzoom/blob/211bc595f528ed19b493a546219fe9bafe4b89a4/src/types.ts#L319) +Defined in: [types.ts:319](https://github.com/timmywil/panzoom/blob/c05ae3d25396d280b34dc17c7324768425d9c900/src/types.ts#L319) Change any number of options on a Panzoom instance. Setting some options will have side-effects. @@ -962,7 +962,7 @@ panzoom.setOptions({ cursor: 'default' }) > **setStyle**: (`name`, `value`) => `void` -Defined in: [types.ts:321](https://github.com/timmywil/panzoom/blob/211bc595f528ed19b493a546219fe9bafe4b89a4/src/types.ts#L321) +Defined in: [types.ts:321](https://github.com/timmywil/panzoom/blob/c05ae3d25396d280b34dc17c7324768425d9c900/src/types.ts#L321) A convenience method for setting prefixed styles on the Panzoom element @@ -986,7 +986,7 @@ A convenience method for setting prefixed styles on the Panzoom element > **zoom**: (`scale`, `zoomOptions`?) => `[CurrentValues](#CurrentValues)` -Defined in: [types.ts:330](https://github.com/timmywil/panzoom/blob/211bc595f528ed19b493a546219fe9bafe4b89a4/src/types.ts#L330) +Defined in: [types.ts:330](https://github.com/timmywil/panzoom/blob/c05ae3d25396d280b34dc17c7324768425d9c900/src/types.ts#L330) Zoom the Panzoom element to the given scale @@ -1015,7 +1015,7 @@ panzoom.zoom(2.2, { animate: true }) > **zoomIn**: (`zoomOptions`?) => `[CurrentValues](#CurrentValues)` -Defined in: [types.ts:341](https://github.com/timmywil/panzoom/blob/211bc595f528ed19b493a546219fe9bafe4b89a4/src/types.ts#L341) +Defined in: [types.ts:341](https://github.com/timmywil/panzoom/blob/c05ae3d25396d280b34dc17c7324768425d9c900/src/types.ts#L341) Zoom in using the predetermined increment set in options. Animates by default, ignoring the global option. @@ -1042,7 +1042,7 @@ panzoom.zoomIn({ animate: false }) > **zoomOut**: (`zoomOptions`?) => `[CurrentValues](#CurrentValues)` -Defined in: [types.ts:352](https://github.com/timmywil/panzoom/blob/211bc595f528ed19b493a546219fe9bafe4b89a4/src/types.ts#L352) +Defined in: [types.ts:352](https://github.com/timmywil/panzoom/blob/c05ae3d25396d280b34dc17c7324768425d9c900/src/types.ts#L352) Zoom out using the predetermined increment set in options. Animates by default, ignoring the global option. @@ -1069,7 +1069,7 @@ panzoom.zoomOut({ animate: false }) > **zoomToPoint**: (`scale`, `point`, `zoomOptions`?) => `[CurrentValues](#CurrentValues)` -Defined in: [types.ts:363](https://github.com/timmywil/panzoom/blob/211bc595f528ed19b493a546219fe9bafe4b89a4/src/types.ts#L363) +Defined in: [types.ts:363](https://github.com/timmywil/panzoom/blob/c05ae3d25396d280b34dc17c7324768425d9c900/src/types.ts#L363) Zoom the Panzoom element to a focal point using the given pointer/touch/mouse event or constructed point. @@ -1110,7 +1110,7 @@ panzoom.zoomToPoint(1.2, pointerEvent) > **zoomWithWheel**: (`event`, `zoomOptions`?) => `[CurrentValues](#CurrentValues)` -Defined in: [types.ts:396](https://github.com/timmywil/panzoom/blob/211bc595f528ed19b493a546219fe9bafe4b89a4/src/types.ts#L396) +Defined in: [types.ts:396](https://github.com/timmywil/panzoom/blob/c05ae3d25396d280b34dc17c7324768425d9c900/src/types.ts#L396) Zoom the Panzoom element to a focal point using the given WheelEvent @@ -1155,7 +1155,7 @@ elem.parentElement.addEventListener('wheel', function (event) { ## $1 -Defined in: [types.ts:215](https://github.com/timmywil/panzoom/blob/211bc595f528ed19b493a546219fe9bafe4b89a4/src/types.ts#L215) +Defined in: [types.ts:215](https://github.com/timmywil/panzoom/blob/c05ae3d25396d280b34dc17c7324768425d9c900/src/types.ts#L215) ## Properties @@ -1163,7 +1163,7 @@ Defined in: [types.ts:215](https://github.com/timmywil/panzoom/blob/211bc595f528 > `optional` **isSVG**: `boolean` -Defined in: [types.ts:219](https://github.com/timmywil/panzoom/blob/211bc595f528ed19b493a546219fe9bafe4b89a4/src/types.ts#L219) +Defined in: [types.ts:219](https://github.com/timmywil/panzoom/blob/c05ae3d25396d280b34dc17c7324768425d9c900/src/types.ts#L219) --- @@ -1171,7 +1171,7 @@ Defined in: [types.ts:219](https://github.com/timmywil/panzoom/blob/211bc595f528 > **scale**: `number` -Defined in: [types.ts:218](https://github.com/timmywil/panzoom/blob/211bc595f528ed19b493a546219fe9bafe4b89a4/src/types.ts#L218) +Defined in: [types.ts:218](https://github.com/timmywil/panzoom/blob/c05ae3d25396d280b34dc17c7324768425d9c900/src/types.ts#L218) --- @@ -1179,7 +1179,7 @@ Defined in: [types.ts:218](https://github.com/timmywil/panzoom/blob/211bc595f528 > **x**: `number` -Defined in: [types.ts:216](https://github.com/timmywil/panzoom/blob/211bc595f528ed19b493a546219fe9bafe4b89a4/src/types.ts#L216) +Defined in: [types.ts:216](https://github.com/timmywil/panzoom/blob/c05ae3d25396d280b34dc17c7324768425d9c900/src/types.ts#L216) --- @@ -1187,7 +1187,7 @@ Defined in: [types.ts:216](https://github.com/timmywil/panzoom/blob/211bc595f528 > **y**: `number` -Defined in: [types.ts:217](https://github.com/timmywil/panzoom/blob/211bc595f528ed19b493a546219fe9bafe4b89a4/src/types.ts#L217) +Defined in: [types.ts:217](https://github.com/timmywil/panzoom/blob/c05ae3d25396d280b34dc17c7324768425d9c900/src/types.ts#L217) ## Events diff --git a/dist/panzoom.es.js b/dist/panzoom.es.js new file mode 100644 index 00000000..76187491 --- /dev/null +++ b/dist/panzoom.es.js @@ -0,0 +1,792 @@ +/** +* Panzoom 4.6.0 for panning and zooming elements using CSS transforms +* Copyright Timmy Willison and other contributors +* https://github.com/timmywil/panzoom/blob/main/MIT-License.txt +*/ +/****************************************************************************** +Copyright (c) Microsoft Corporation. + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THIS SOFTWARE. +***************************************************************************** */ +/* global Reflect, Promise, SuppressedError, Symbol, Iterator */ + + +var __assign = function() { + __assign = Object.assign || function __assign(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; + } + return t; + }; + return __assign.apply(this, arguments); +}; + +typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) { + var e = new Error(message); + return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e; +}; + +if (typeof window !== 'undefined') { + // Support: IE11 only + if (window.NodeList && !NodeList.prototype.forEach) { + NodeList.prototype.forEach = Array.prototype.forEach; + } + // Support: IE11 only + // CustomEvent is an object instead of a constructor + if (typeof window.CustomEvent !== 'function') { + window.CustomEvent = function CustomEvent(event, params) { + params = params || { bubbles: false, cancelable: false, detail: null }; + var evt = document.createEvent('CustomEvent'); + evt.initCustomEvent(event, params.bubbles, params.cancelable, params.detail); + return evt + }; + } +} + +var isIE = typeof document !== 'undefined' && !!document.documentMode; +/** + * Lazy creation of a CSS style declaration + */ +var divStyle; +function createStyle() { + if (divStyle) { + return divStyle; + } + return (divStyle = document.createElement('div').style); +} +/** + * Proper prefixing for cross-browser compatibility + */ +var prefixes = ['webkit', 'moz', 'ms']; +var prefixCache = {}; +function getPrefixedName(name) { + if (prefixCache[name]) { + return prefixCache[name]; + } + var divStyle = createStyle(); + if (name in divStyle) { + return (prefixCache[name] = name); + } + var capName = name[0].toUpperCase() + name.slice(1); + var i = prefixes.length; + while (i--) { + var prefixedName = "".concat(prefixes[i]).concat(capName); + if (prefixedName in divStyle) { + return (prefixCache[name] = prefixedName); + } + } +} +/** + * Gets a style value expected to be a number + */ +function getCSSNum(name, style) { + return parseFloat(style[getPrefixedName(name)]) || 0; +} +function getBoxStyle(elem, name, style) { + if (style === undefined) { style = window.getComputedStyle(elem); } + // Support: FF 68+ + // Firefox requires specificity for border + var suffix = name === 'border' ? 'Width' : ''; + return { + left: getCSSNum("".concat(name, "Left").concat(suffix), style), + right: getCSSNum("".concat(name, "Right").concat(suffix), style), + top: getCSSNum("".concat(name, "Top").concat(suffix), style), + bottom: getCSSNum("".concat(name, "Bottom").concat(suffix), style) + }; +} +/** + * Set a style using the properly prefixed name + */ +function setStyle(elem, name, value) { + elem.style[getPrefixedName(name)] = value; +} +/** + * Constructs the transition from panzoom options + * and takes care of prefixing the transition and transform + */ +function setTransition(elem, options) { + var transform = getPrefixedName('transform'); + setStyle(elem, 'transition', "".concat(transform, " ").concat(options.duration, "ms ").concat(options.easing)); +} +/** + * Set the transform using the proper prefix + * + * Override the transform setter. + * This is exposed mostly so the user could + * set other parts of a transform + * aside from scale and translate. + * Default is defined in src/css.ts. + * + * ```js + * // This example always sets a rotation + * // when setting the scale and translation + * const panzoom = Panzoom(elem, { + * setTransform: (elem, { scale, x, y }) => { + * panzoom.setStyle('transform', `rotate(0.5turn) scale(${scale}) translate(${x}px, ${y}px)`) + * } + * }) + * ``` + */ +function setTransform(elem, _a, _options) { + var x = _a.x, y = _a.y, scale = _a.scale, isSVG = _a.isSVG; + setStyle(elem, 'transform', "scale(".concat(scale, ") translate(").concat(x, "px, ").concat(y, "px)")); + if (isSVG && isIE) { + var matrixValue = window.getComputedStyle(elem).getPropertyValue('transform'); + elem.setAttribute('transform', matrixValue); + } +} +/** + * Dimensions used in containment and focal point zooming + */ +function getDimensions(elem) { + var parent = elem.parentNode; + var style = window.getComputedStyle(elem); + var parentStyle = window.getComputedStyle(parent); + var rectElem = elem.getBoundingClientRect(); + var rectParent = parent.getBoundingClientRect(); + return { + elem: { + style: style, + width: rectElem.width, + height: rectElem.height, + top: rectElem.top, + bottom: rectElem.bottom, + left: rectElem.left, + right: rectElem.right, + margin: getBoxStyle(elem, 'margin', style), + border: getBoxStyle(elem, 'border', style) + }, + parent: { + style: parentStyle, + width: rectParent.width, + height: rectParent.height, + top: rectParent.top, + bottom: rectParent.bottom, + left: rectParent.left, + right: rectParent.right, + padding: getBoxStyle(parent, 'padding', parentStyle), + border: getBoxStyle(parent, 'border', parentStyle) + } + }; +} + +var events = { + down: 'mousedown', + move: 'mousemove', + up: 'mouseup mouseleave' +}; +if (typeof window !== 'undefined') { + if (typeof window.PointerEvent === 'function') { + events = { + down: 'pointerdown', + move: 'pointermove', + up: 'pointerup pointerleave pointercancel' + }; + } + else if (typeof window.TouchEvent === 'function') { + events = { + down: 'touchstart', + move: 'touchmove', + up: 'touchend touchcancel' + }; + } +} +function onPointer(event, elem, handler, eventOpts) { + events[event].split(' ').forEach(function (name) { + elem.addEventListener(name, handler, eventOpts); + }); +} +function destroyPointer(event, elem, handler) { + events[event].split(' ').forEach(function (name) { + elem.removeEventListener(name, handler); + }); +} + +/** + * Utilites for working with multiple pointer events + */ +function findEventIndex(pointers, event) { + var i = pointers.length; + while (i--) { + if (pointers[i].pointerId === event.pointerId) { + return i; + } + } + return -1; +} +function addPointer(pointers, event) { + var i; + // Add touches if applicable + if (event.touches) { + i = 0; + for (var _i = 0, _a = event.touches; _i < _a.length; _i++) { + var touch = _a[_i]; + touch.pointerId = i++; + addPointer(pointers, touch); + } + return; + } + i = findEventIndex(pointers, event); + // Update if already present + if (i > -1) { + pointers.splice(i, 1); + } + pointers.push(event); +} +function removePointer(pointers, event) { + // Add touches if applicable + if (event.touches) { + // Remove all touches + while (pointers.length) { + pointers.pop(); + } + return; + } + var i = findEventIndex(pointers, event); + if (i > -1) { + pointers.splice(i, 1); + } +} +/** + * Calculates a center point between + * the given pointer events, for panning + * with multiple pointers. + */ +function getMiddle(pointers) { + // Copy to avoid changing by reference + pointers = pointers.slice(0); + var event1 = pointers.pop(); + var event2; + while ((event2 = pointers.pop())) { + event1 = { + clientX: (event2.clientX - event1.clientX) / 2 + event1.clientX, + clientY: (event2.clientY - event1.clientY) / 2 + event1.clientY + }; + } + return event1; +} +/** + * Calculates the distance between two points + * for pinch zooming. + * Limits to the first 2 + */ +function getDistance(pointers) { + if (pointers.length < 2) { + return 0; + } + var event1 = pointers[0]; + var event2 = pointers[1]; + return Math.sqrt(Math.pow(Math.abs(event2.clientX - event1.clientX), 2) + + Math.pow(Math.abs(event2.clientY - event1.clientY), 2)); +} + +/** + * Determine if an element is attached to the DOM + * Panzoom requires this so events work properly + */ +function isAttached(node) { + var currentNode = node; + while (currentNode && currentNode.parentNode) { + if (currentNode.parentNode === document) + return true; + currentNode = + currentNode.parentNode instanceof ShadowRoot + ? currentNode.parentNode.host + : currentNode.parentNode; + } + return false; +} + +function getClass(elem) { + return (elem.getAttribute('class') || '').trim(); +} +function hasClass(elem, className) { + return elem.nodeType === 1 && " ".concat(getClass(elem), " ").indexOf(" ".concat(className, " ")) > -1; +} +function isExcluded(elem, options) { + for (var cur = elem; cur != null; cur = cur.parentNode) { + if (hasClass(cur, options.excludeClass) || options.exclude.indexOf(cur) > -1) { + return true; + } + } + return false; +} + +/** + * Determine if an element is SVG by checking the namespace + * Exception: the element itself should be treated like HTML + */ +var rsvg = /^http:[\w\.\/]+svg$/; +function isSVGElement(elem) { + return rsvg.test(elem.namespaceURI) && elem.nodeName.toLowerCase() !== 'svg'; +} + +function shallowClone(obj) { + var clone = {}; + for (var key in obj) { + if (obj.hasOwnProperty(key)) { + clone[key] = obj[key]; + } + } + return clone; +} + +var defaultOptions = { + animate: false, + canvas: false, + cursor: 'move', + disablePan: false, + disableZoom: false, + disableXAxis: false, + disableYAxis: false, + duration: 200, + easing: 'ease-in-out', + exclude: [], + excludeClass: 'panzoom-exclude', + handleStartEvent: function (e) { + e.preventDefault(); + e.stopPropagation(); + }, + maxScale: 4, + minScale: 0.125, + overflow: 'hidden', + panOnlyWhenZoomed: false, + pinchAndPan: false, + relative: false, + setTransform: setTransform, + startX: 0, + startY: 0, + startScale: 1, + step: 0.3, + touchAction: 'none' +}; +function Panzoom(elem, options) { + if (!elem) { + throw new Error('Panzoom requires an element as an argument'); + } + if (elem.nodeType !== 1) { + throw new Error('Panzoom requires an element with a nodeType of 1'); + } + if (!isAttached(elem)) { + throw new Error('Panzoom should be called on elements that have been attached to the DOM'); + } + options = __assign(__assign({}, defaultOptions), options); + var isSVG = isSVGElement(elem); + var parent = elem.parentNode; + // Set parent styles + parent.style.overflow = options.overflow; + parent.style.userSelect = 'none'; + // This is important for mobile to + // prevent scrolling while panning + parent.style.touchAction = options.touchAction; + (options.canvas ? parent : elem).style.cursor = options.cursor; + // Set element styles + elem.style.userSelect = 'none'; + elem.style.touchAction = options.touchAction; + // The default for HTML is '50% 50%' + // The default for SVG is '0 0' + // SVG can't be changed in IE + setStyle(elem, 'transformOrigin', typeof options.origin === 'string' ? options.origin : isSVG ? '0 0' : '50% 50%'); + function resetStyle() { + parent.style.overflow = ''; + parent.style.userSelect = ''; + parent.style.touchAction = ''; + parent.style.cursor = ''; + elem.style.cursor = ''; + elem.style.userSelect = ''; + elem.style.touchAction = ''; + setStyle(elem, 'transformOrigin', ''); + } + function setOptions(opts) { + if (opts === undefined) { opts = {}; } + for (var key in opts) { + if (opts.hasOwnProperty(key)) { + options[key] = opts[key]; + } + } + // Handle option side-effects + if (opts.hasOwnProperty('cursor') || opts.hasOwnProperty('canvas')) { + parent.style.cursor = elem.style.cursor = ''; + (options.canvas ? parent : elem).style.cursor = options.cursor; + } + if (opts.hasOwnProperty('overflow')) { + parent.style.overflow = opts.overflow; + } + if (opts.hasOwnProperty('touchAction')) { + parent.style.touchAction = opts.touchAction; + elem.style.touchAction = opts.touchAction; + } + } + var x = 0; + var y = 0; + var scale = 1; + var isPanning = false; + zoom(options.startScale, { animate: false, force: true }); + // Wait for scale to update + // for accurate dimensions + // to constrain initial values + setTimeout(function () { + pan(options.startX, options.startY, { animate: false, force: true }); + }); + function trigger(eventName, detail, opts) { + if (opts.silent) { + return; + } + var event = new CustomEvent(eventName, { detail: detail }); + elem.dispatchEvent(event); + } + function setTransformWithEvent(eventName, opts, originalEvent) { + var value = { x: x, y: y, scale: scale, isSVG: isSVG, originalEvent: originalEvent }; + requestAnimationFrame(function () { + if (typeof opts.animate === 'boolean') { + if (opts.animate) { + setTransition(elem, opts); + } + else { + setStyle(elem, 'transition', 'none'); + } + } + opts.setTransform(elem, value, opts); + trigger(eventName, value, opts); + trigger('panzoomchange', value, opts); + }); + return value; + } + function constrainXY(toX, toY, toScale, panOptions) { + var opts = __assign(__assign({}, options), panOptions); + var result = { x: x, y: y, opts: opts }; + if (!opts.force && (opts.disablePan || (opts.panOnlyWhenZoomed && scale === opts.startScale))) { + return result; + } + toX = parseFloat(toX); + toY = parseFloat(toY); + if (!opts.disableXAxis) { + result.x = (opts.relative ? x : 0) + toX; + } + if (!opts.disableYAxis) { + result.y = (opts.relative ? y : 0) + toY; + } + if (opts.contain) { + var dims = getDimensions(elem); + var realWidth = dims.elem.width / scale; + var realHeight = dims.elem.height / scale; + var scaledWidth = realWidth * toScale; + var scaledHeight = realHeight * toScale; + var diffHorizontal = (scaledWidth - realWidth) / 2; + var diffVertical = (scaledHeight - realHeight) / 2; + if (opts.contain === 'inside') { + var minX = (-dims.elem.margin.left - dims.parent.padding.left + diffHorizontal) / toScale; + var maxX = (dims.parent.width - + scaledWidth - + dims.parent.padding.left - + dims.elem.margin.left - + dims.parent.border.left - + dims.parent.border.right + + diffHorizontal) / + toScale; + result.x = Math.max(Math.min(result.x, maxX), minX); + var minY = (-dims.elem.margin.top - dims.parent.padding.top + diffVertical) / toScale; + var maxY = (dims.parent.height - + scaledHeight - + dims.parent.padding.top - + dims.elem.margin.top - + dims.parent.border.top - + dims.parent.border.bottom + + diffVertical) / + toScale; + result.y = Math.max(Math.min(result.y, maxY), minY); + } + else if (opts.contain === 'outside') { + var minX = (-(scaledWidth - dims.parent.width) - + dims.parent.padding.left - + dims.parent.border.left - + dims.parent.border.right + + diffHorizontal) / + toScale; + var maxX = (diffHorizontal - dims.parent.padding.left) / toScale; + result.x = Math.max(Math.min(result.x, maxX), minX); + var minY = (-(scaledHeight - dims.parent.height) - + dims.parent.padding.top - + dims.parent.border.top - + dims.parent.border.bottom + + diffVertical) / + toScale; + var maxY = (diffVertical - dims.parent.padding.top) / toScale; + result.y = Math.max(Math.min(result.y, maxY), minY); + } + } + if (opts.roundPixels) { + result.x = Math.round(result.x); + result.y = Math.round(result.y); + } + return result; + } + function constrainScale(toScale, zoomOptions) { + var opts = __assign(__assign({}, options), zoomOptions); + var result = { scale: scale, opts: opts }; + if (!opts.force && opts.disableZoom) { + return result; + } + var minScale = options.minScale; + var maxScale = options.maxScale; + if (opts.contain) { + var dims = getDimensions(elem); + var elemWidth = dims.elem.width / scale; + var elemHeight = dims.elem.height / scale; + if (elemWidth > 1 && elemHeight > 1) { + var parentWidth = dims.parent.width - dims.parent.border.left - dims.parent.border.right; + var parentHeight = dims.parent.height - dims.parent.border.top - dims.parent.border.bottom; + var elemScaledWidth = parentWidth / elemWidth; + var elemScaledHeight = parentHeight / elemHeight; + if (options.contain === 'inside') { + maxScale = Math.min(maxScale, elemScaledWidth, elemScaledHeight); + } + else if (options.contain === 'outside') { + minScale = Math.max(minScale, elemScaledWidth, elemScaledHeight); + } + } + } + result.scale = Math.min(Math.max(toScale, minScale), maxScale); + return result; + } + function pan(toX, toY, panOptions, originalEvent) { + var result = constrainXY(toX, toY, scale, panOptions); + // Only try to set if the result is somehow different + if (x !== result.x || y !== result.y) { + x = result.x; + y = result.y; + return setTransformWithEvent('panzoompan', result.opts, originalEvent); + } + return { x: x, y: y, scale: scale, isSVG: isSVG, originalEvent: originalEvent }; + } + function zoom(toScale, zoomOptions, originalEvent) { + var result = constrainScale(toScale, zoomOptions); + var opts = result.opts; + if (!opts.force && opts.disableZoom) { + return; + } + toScale = result.scale; + var toX = x; + var toY = y; + if (opts.focal) { + // The difference between the point after the scale and the point before the scale + // plus the current translation after the scale + // neutralized to no scale (as the transform scale will apply to the translation) + var focal = opts.focal; + toX = (focal.x / toScale - focal.x / scale + x * toScale) / toScale; + toY = (focal.y / toScale - focal.y / scale + y * toScale) / toScale; + } + var panResult = constrainXY(toX, toY, toScale, { relative: false, force: true }); + x = panResult.x; + y = panResult.y; + scale = toScale; + return setTransformWithEvent('panzoomzoom', opts, originalEvent); + } + function zoomInOut(isIn, zoomOptions) { + var opts = __assign(__assign(__assign({}, options), { animate: true }), zoomOptions); + return zoom(scale * Math.exp((isIn ? 1 : -1) * opts.step), opts); + } + function zoomIn(zoomOptions) { + return zoomInOut(true, zoomOptions); + } + function zoomOut(zoomOptions) { + return zoomInOut(false, zoomOptions); + } + function zoomToPoint(toScale, point, zoomOptions, originalEvent) { + var dims = getDimensions(elem); + // Instead of thinking of operating on the panzoom element, + // think of operating on the area inside the panzoom + // element's parent + // Subtract padding and border + var effectiveArea = { + width: dims.parent.width - + dims.parent.padding.left - + dims.parent.padding.right - + dims.parent.border.left - + dims.parent.border.right, + height: dims.parent.height - + dims.parent.padding.top - + dims.parent.padding.bottom - + dims.parent.border.top - + dims.parent.border.bottom + }; + // Adjust the clientX/clientY to ignore the area + // outside the effective area + var clientX = point.clientX - + dims.parent.left - + dims.parent.padding.left - + dims.parent.border.left - + dims.elem.margin.left; + var clientY = point.clientY - + dims.parent.top - + dims.parent.padding.top - + dims.parent.border.top - + dims.elem.margin.top; + // Adjust the clientX/clientY for HTML elements, + // because they have a transform-origin of 50% 50% + if (!isSVG) { + clientX -= dims.elem.width / scale / 2; + clientY -= dims.elem.height / scale / 2; + } + // Convert the mouse point from it's position over the + // effective area before the scale to the position + // over the effective area after the scale. + var focal = { + x: (clientX / effectiveArea.width) * (effectiveArea.width * toScale), + y: (clientY / effectiveArea.height) * (effectiveArea.height * toScale) + }; + return zoom(toScale, __assign(__assign({}, zoomOptions), { animate: false, focal: focal }), originalEvent); + } + function zoomWithWheel(event, zoomOptions) { + // Need to prevent the default here + // or it conflicts with regular page scroll + event.preventDefault(); + var opts = __assign(__assign(__assign({}, options), zoomOptions), { animate: false }); + // Normalize to deltaX in case shift modifier is used on Mac + var delta = event.deltaY === 0 && event.deltaX ? event.deltaX : event.deltaY; + var wheel = delta < 0 ? 1 : -1; + var toScale = constrainScale(scale * Math.exp((wheel * opts.step) / 3), opts).scale; + return zoomToPoint(toScale, event, opts, event); + } + function reset(resetOptions) { + var opts = __assign(__assign(__assign({}, options), { animate: true, force: true }), resetOptions); + scale = constrainScale(opts.startScale, opts).scale; + var panResult = constrainXY(opts.startX, opts.startY, scale, opts); + x = panResult.x; + y = panResult.y; + return setTransformWithEvent('panzoomreset', opts); + } + var origX; + var origY; + var startClientX; + var startClientY; + var startScale; + var startDistance; + var pointers = []; + function handleDown(event) { + // Don't handle this event if the target is excluded + if (isExcluded(event.target, options)) { + return; + } + addPointer(pointers, event); + isPanning = true; + options.handleStartEvent(event); + origX = x; + origY = y; + trigger('panzoomstart', { x: x, y: y, scale: scale, isSVG: isSVG, originalEvent: event }, options); + // This works whether there are multiple + // pointers or not + var point = getMiddle(pointers); + startClientX = point.clientX; + startClientY = point.clientY; + startScale = scale; + startDistance = getDistance(pointers); + } + function handleMove(event) { + if (!isPanning || + origX === undefined || + origY === undefined || + startClientX === undefined || + startClientY === undefined) { + return; + } + addPointer(pointers, event); + var current = getMiddle(pointers); + var hasMultiple = pointers.length > 1; + var toScale = scale; + if (hasMultiple) { + // A startDistance of 0 means + // that there weren't 2 pointers + // handled on start + if (startDistance === 0) { + startDistance = getDistance(pointers); + } + // Use the distance between the first 2 pointers + // to determine the current scale + var diff = getDistance(pointers) - startDistance; + toScale = constrainScale((diff * options.step) / 80 + startScale).scale; + zoomToPoint(toScale, current, { animate: false }, event); + } + // Pan during pinch if pinchAndPan is true. + // Note: some calculations may be off because the zoom + // above has not yet rendered. However, the behavior + // was removed before the new scale was used in the following + // pan calculation. + // See https://github.com/timmywil/panzoom/issues/512 + // and https://github.com/timmywil/panzoom/issues/606 + if (!hasMultiple || options.pinchAndPan) { + pan(origX + (current.clientX - startClientX) / toScale, origY + (current.clientY - startClientY) / toScale, { + animate: false + }, event); + } + } + function handleUp(event) { + // Don't call panzoomend when panning with 2 touches + // until both touches end + if (pointers.length === 1) { + trigger('panzoomend', { x: x, y: y, scale: scale, isSVG: isSVG, originalEvent: event }, options); + } + // Note: don't remove all pointers + // Can restart without having to reinitiate all of them + // Remove the pointer regardless of the isPanning state + removePointer(pointers, event); + if (!isPanning) { + return; + } + isPanning = false; + origX = origY = startClientX = startClientY = undefined; + } + var bound = false; + function bind() { + if (bound) { + return; + } + bound = true; + onPointer('down', options.canvas ? parent : elem, handleDown); + onPointer('move', document, handleMove, { passive: true }); + onPointer('up', document, handleUp, { passive: true }); + } + function destroy() { + bound = false; + destroyPointer('down', options.canvas ? parent : elem, handleDown); + destroyPointer('move', document, handleMove); + destroyPointer('up', document, handleUp); + } + if (!options.noBind) { + bind(); + } + return { + bind: bind, + destroy: destroy, + eventNames: events, + getPan: function () { return ({ x: x, y: y }); }, + getScale: function () { return scale; }, + getOptions: function () { return shallowClone(options); }, + handleDown: handleDown, + handleMove: handleMove, + handleUp: handleUp, + pan: pan, + reset: reset, + resetStyle: resetStyle, + setOptions: setOptions, + setStyle: function (name, value) { return setStyle(elem, name, value); }, + zoom: zoom, + zoomIn: zoomIn, + zoomOut: zoomOut, + zoomToPoint: zoomToPoint, + zoomWithWheel: zoomWithWheel + }; +} +Panzoom.defaultOptions = defaultOptions; + +export { Panzoom as default }; diff --git a/dist/panzoom.js b/dist/panzoom.js new file mode 100644 index 00000000..980d865d --- /dev/null +++ b/dist/panzoom.js @@ -0,0 +1,800 @@ +/** +* Panzoom 4.6.0 for panning and zooming elements using CSS transforms +* Copyright Timmy Willison and other contributors +* https://github.com/timmywil/panzoom/blob/main/MIT-License.txt +*/ +(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : + typeof define === 'function' && define.amd ? define(factory) : + (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.Panzoom = factory()); +})(this, (function () { 'use strict'; + + /****************************************************************************** + Copyright (c) Microsoft Corporation. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + PERFORMANCE OF THIS SOFTWARE. + ***************************************************************************** */ + /* global Reflect, Promise, SuppressedError, Symbol, Iterator */ + + + var __assign = function() { + __assign = Object.assign || function __assign(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; + } + return t; + }; + return __assign.apply(this, arguments); + }; + + typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) { + var e = new Error(message); + return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e; + }; + + if (typeof window !== 'undefined') { + // Support: IE11 only + if (window.NodeList && !NodeList.prototype.forEach) { + NodeList.prototype.forEach = Array.prototype.forEach; + } + // Support: IE11 only + // CustomEvent is an object instead of a constructor + if (typeof window.CustomEvent !== 'function') { + window.CustomEvent = function CustomEvent(event, params) { + params = params || { bubbles: false, cancelable: false, detail: null }; + var evt = document.createEvent('CustomEvent'); + evt.initCustomEvent(event, params.bubbles, params.cancelable, params.detail); + return evt + }; + } + } + + var isIE = typeof document !== 'undefined' && !!document.documentMode; + /** + * Lazy creation of a CSS style declaration + */ + var divStyle; + function createStyle() { + if (divStyle) { + return divStyle; + } + return (divStyle = document.createElement('div').style); + } + /** + * Proper prefixing for cross-browser compatibility + */ + var prefixes = ['webkit', 'moz', 'ms']; + var prefixCache = {}; + function getPrefixedName(name) { + if (prefixCache[name]) { + return prefixCache[name]; + } + var divStyle = createStyle(); + if (name in divStyle) { + return (prefixCache[name] = name); + } + var capName = name[0].toUpperCase() + name.slice(1); + var i = prefixes.length; + while (i--) { + var prefixedName = "".concat(prefixes[i]).concat(capName); + if (prefixedName in divStyle) { + return (prefixCache[name] = prefixedName); + } + } + } + /** + * Gets a style value expected to be a number + */ + function getCSSNum(name, style) { + return parseFloat(style[getPrefixedName(name)]) || 0; + } + function getBoxStyle(elem, name, style) { + if (style === undefined) { style = window.getComputedStyle(elem); } + // Support: FF 68+ + // Firefox requires specificity for border + var suffix = name === 'border' ? 'Width' : ''; + return { + left: getCSSNum("".concat(name, "Left").concat(suffix), style), + right: getCSSNum("".concat(name, "Right").concat(suffix), style), + top: getCSSNum("".concat(name, "Top").concat(suffix), style), + bottom: getCSSNum("".concat(name, "Bottom").concat(suffix), style) + }; + } + /** + * Set a style using the properly prefixed name + */ + function setStyle(elem, name, value) { + elem.style[getPrefixedName(name)] = value; + } + /** + * Constructs the transition from panzoom options + * and takes care of prefixing the transition and transform + */ + function setTransition(elem, options) { + var transform = getPrefixedName('transform'); + setStyle(elem, 'transition', "".concat(transform, " ").concat(options.duration, "ms ").concat(options.easing)); + } + /** + * Set the transform using the proper prefix + * + * Override the transform setter. + * This is exposed mostly so the user could + * set other parts of a transform + * aside from scale and translate. + * Default is defined in src/css.ts. + * + * ```js + * // This example always sets a rotation + * // when setting the scale and translation + * const panzoom = Panzoom(elem, { + * setTransform: (elem, { scale, x, y }) => { + * panzoom.setStyle('transform', `rotate(0.5turn) scale(${scale}) translate(${x}px, ${y}px)`) + * } + * }) + * ``` + */ + function setTransform(elem, _a, _options) { + var x = _a.x, y = _a.y, scale = _a.scale, isSVG = _a.isSVG; + setStyle(elem, 'transform', "scale(".concat(scale, ") translate(").concat(x, "px, ").concat(y, "px)")); + if (isSVG && isIE) { + var matrixValue = window.getComputedStyle(elem).getPropertyValue('transform'); + elem.setAttribute('transform', matrixValue); + } + } + /** + * Dimensions used in containment and focal point zooming + */ + function getDimensions(elem) { + var parent = elem.parentNode; + var style = window.getComputedStyle(elem); + var parentStyle = window.getComputedStyle(parent); + var rectElem = elem.getBoundingClientRect(); + var rectParent = parent.getBoundingClientRect(); + return { + elem: { + style: style, + width: rectElem.width, + height: rectElem.height, + top: rectElem.top, + bottom: rectElem.bottom, + left: rectElem.left, + right: rectElem.right, + margin: getBoxStyle(elem, 'margin', style), + border: getBoxStyle(elem, 'border', style) + }, + parent: { + style: parentStyle, + width: rectParent.width, + height: rectParent.height, + top: rectParent.top, + bottom: rectParent.bottom, + left: rectParent.left, + right: rectParent.right, + padding: getBoxStyle(parent, 'padding', parentStyle), + border: getBoxStyle(parent, 'border', parentStyle) + } + }; + } + + var events = { + down: 'mousedown', + move: 'mousemove', + up: 'mouseup mouseleave' + }; + if (typeof window !== 'undefined') { + if (typeof window.PointerEvent === 'function') { + events = { + down: 'pointerdown', + move: 'pointermove', + up: 'pointerup pointerleave pointercancel' + }; + } + else if (typeof window.TouchEvent === 'function') { + events = { + down: 'touchstart', + move: 'touchmove', + up: 'touchend touchcancel' + }; + } + } + function onPointer(event, elem, handler, eventOpts) { + events[event].split(' ').forEach(function (name) { + elem.addEventListener(name, handler, eventOpts); + }); + } + function destroyPointer(event, elem, handler) { + events[event].split(' ').forEach(function (name) { + elem.removeEventListener(name, handler); + }); + } + + /** + * Utilites for working with multiple pointer events + */ + function findEventIndex(pointers, event) { + var i = pointers.length; + while (i--) { + if (pointers[i].pointerId === event.pointerId) { + return i; + } + } + return -1; + } + function addPointer(pointers, event) { + var i; + // Add touches if applicable + if (event.touches) { + i = 0; + for (var _i = 0, _a = event.touches; _i < _a.length; _i++) { + var touch = _a[_i]; + touch.pointerId = i++; + addPointer(pointers, touch); + } + return; + } + i = findEventIndex(pointers, event); + // Update if already present + if (i > -1) { + pointers.splice(i, 1); + } + pointers.push(event); + } + function removePointer(pointers, event) { + // Add touches if applicable + if (event.touches) { + // Remove all touches + while (pointers.length) { + pointers.pop(); + } + return; + } + var i = findEventIndex(pointers, event); + if (i > -1) { + pointers.splice(i, 1); + } + } + /** + * Calculates a center point between + * the given pointer events, for panning + * with multiple pointers. + */ + function getMiddle(pointers) { + // Copy to avoid changing by reference + pointers = pointers.slice(0); + var event1 = pointers.pop(); + var event2; + while ((event2 = pointers.pop())) { + event1 = { + clientX: (event2.clientX - event1.clientX) / 2 + event1.clientX, + clientY: (event2.clientY - event1.clientY) / 2 + event1.clientY + }; + } + return event1; + } + /** + * Calculates the distance between two points + * for pinch zooming. + * Limits to the first 2 + */ + function getDistance(pointers) { + if (pointers.length < 2) { + return 0; + } + var event1 = pointers[0]; + var event2 = pointers[1]; + return Math.sqrt(Math.pow(Math.abs(event2.clientX - event1.clientX), 2) + + Math.pow(Math.abs(event2.clientY - event1.clientY), 2)); + } + + /** + * Determine if an element is attached to the DOM + * Panzoom requires this so events work properly + */ + function isAttached(node) { + var currentNode = node; + while (currentNode && currentNode.parentNode) { + if (currentNode.parentNode === document) + return true; + currentNode = + currentNode.parentNode instanceof ShadowRoot + ? currentNode.parentNode.host + : currentNode.parentNode; + } + return false; + } + + function getClass(elem) { + return (elem.getAttribute('class') || '').trim(); + } + function hasClass(elem, className) { + return elem.nodeType === 1 && " ".concat(getClass(elem), " ").indexOf(" ".concat(className, " ")) > -1; + } + function isExcluded(elem, options) { + for (var cur = elem; cur != null; cur = cur.parentNode) { + if (hasClass(cur, options.excludeClass) || options.exclude.indexOf(cur) > -1) { + return true; + } + } + return false; + } + + /** + * Determine if an element is SVG by checking the namespace + * Exception: the element itself should be treated like HTML + */ + var rsvg = /^http:[\w\.\/]+svg$/; + function isSVGElement(elem) { + return rsvg.test(elem.namespaceURI) && elem.nodeName.toLowerCase() !== 'svg'; + } + + function shallowClone(obj) { + var clone = {}; + for (var key in obj) { + if (obj.hasOwnProperty(key)) { + clone[key] = obj[key]; + } + } + return clone; + } + + var defaultOptions = { + animate: false, + canvas: false, + cursor: 'move', + disablePan: false, + disableZoom: false, + disableXAxis: false, + disableYAxis: false, + duration: 200, + easing: 'ease-in-out', + exclude: [], + excludeClass: 'panzoom-exclude', + handleStartEvent: function (e) { + e.preventDefault(); + e.stopPropagation(); + }, + maxScale: 4, + minScale: 0.125, + overflow: 'hidden', + panOnlyWhenZoomed: false, + pinchAndPan: false, + relative: false, + setTransform: setTransform, + startX: 0, + startY: 0, + startScale: 1, + step: 0.3, + touchAction: 'none' + }; + function Panzoom(elem, options) { + if (!elem) { + throw new Error('Panzoom requires an element as an argument'); + } + if (elem.nodeType !== 1) { + throw new Error('Panzoom requires an element with a nodeType of 1'); + } + if (!isAttached(elem)) { + throw new Error('Panzoom should be called on elements that have been attached to the DOM'); + } + options = __assign(__assign({}, defaultOptions), options); + var isSVG = isSVGElement(elem); + var parent = elem.parentNode; + // Set parent styles + parent.style.overflow = options.overflow; + parent.style.userSelect = 'none'; + // This is important for mobile to + // prevent scrolling while panning + parent.style.touchAction = options.touchAction; + (options.canvas ? parent : elem).style.cursor = options.cursor; + // Set element styles + elem.style.userSelect = 'none'; + elem.style.touchAction = options.touchAction; + // The default for HTML is '50% 50%' + // The default for SVG is '0 0' + // SVG can't be changed in IE + setStyle(elem, 'transformOrigin', typeof options.origin === 'string' ? options.origin : isSVG ? '0 0' : '50% 50%'); + function resetStyle() { + parent.style.overflow = ''; + parent.style.userSelect = ''; + parent.style.touchAction = ''; + parent.style.cursor = ''; + elem.style.cursor = ''; + elem.style.userSelect = ''; + elem.style.touchAction = ''; + setStyle(elem, 'transformOrigin', ''); + } + function setOptions(opts) { + if (opts === undefined) { opts = {}; } + for (var key in opts) { + if (opts.hasOwnProperty(key)) { + options[key] = opts[key]; + } + } + // Handle option side-effects + if (opts.hasOwnProperty('cursor') || opts.hasOwnProperty('canvas')) { + parent.style.cursor = elem.style.cursor = ''; + (options.canvas ? parent : elem).style.cursor = options.cursor; + } + if (opts.hasOwnProperty('overflow')) { + parent.style.overflow = opts.overflow; + } + if (opts.hasOwnProperty('touchAction')) { + parent.style.touchAction = opts.touchAction; + elem.style.touchAction = opts.touchAction; + } + } + var x = 0; + var y = 0; + var scale = 1; + var isPanning = false; + zoom(options.startScale, { animate: false, force: true }); + // Wait for scale to update + // for accurate dimensions + // to constrain initial values + setTimeout(function () { + pan(options.startX, options.startY, { animate: false, force: true }); + }); + function trigger(eventName, detail, opts) { + if (opts.silent) { + return; + } + var event = new CustomEvent(eventName, { detail: detail }); + elem.dispatchEvent(event); + } + function setTransformWithEvent(eventName, opts, originalEvent) { + var value = { x: x, y: y, scale: scale, isSVG: isSVG, originalEvent: originalEvent }; + requestAnimationFrame(function () { + if (typeof opts.animate === 'boolean') { + if (opts.animate) { + setTransition(elem, opts); + } + else { + setStyle(elem, 'transition', 'none'); + } + } + opts.setTransform(elem, value, opts); + trigger(eventName, value, opts); + trigger('panzoomchange', value, opts); + }); + return value; + } + function constrainXY(toX, toY, toScale, panOptions) { + var opts = __assign(__assign({}, options), panOptions); + var result = { x: x, y: y, opts: opts }; + if (!opts.force && (opts.disablePan || (opts.panOnlyWhenZoomed && scale === opts.startScale))) { + return result; + } + toX = parseFloat(toX); + toY = parseFloat(toY); + if (!opts.disableXAxis) { + result.x = (opts.relative ? x : 0) + toX; + } + if (!opts.disableYAxis) { + result.y = (opts.relative ? y : 0) + toY; + } + if (opts.contain) { + var dims = getDimensions(elem); + var realWidth = dims.elem.width / scale; + var realHeight = dims.elem.height / scale; + var scaledWidth = realWidth * toScale; + var scaledHeight = realHeight * toScale; + var diffHorizontal = (scaledWidth - realWidth) / 2; + var diffVertical = (scaledHeight - realHeight) / 2; + if (opts.contain === 'inside') { + var minX = (-dims.elem.margin.left - dims.parent.padding.left + diffHorizontal) / toScale; + var maxX = (dims.parent.width - + scaledWidth - + dims.parent.padding.left - + dims.elem.margin.left - + dims.parent.border.left - + dims.parent.border.right + + diffHorizontal) / + toScale; + result.x = Math.max(Math.min(result.x, maxX), minX); + var minY = (-dims.elem.margin.top - dims.parent.padding.top + diffVertical) / toScale; + var maxY = (dims.parent.height - + scaledHeight - + dims.parent.padding.top - + dims.elem.margin.top - + dims.parent.border.top - + dims.parent.border.bottom + + diffVertical) / + toScale; + result.y = Math.max(Math.min(result.y, maxY), minY); + } + else if (opts.contain === 'outside') { + var minX = (-(scaledWidth - dims.parent.width) - + dims.parent.padding.left - + dims.parent.border.left - + dims.parent.border.right + + diffHorizontal) / + toScale; + var maxX = (diffHorizontal - dims.parent.padding.left) / toScale; + result.x = Math.max(Math.min(result.x, maxX), minX); + var minY = (-(scaledHeight - dims.parent.height) - + dims.parent.padding.top - + dims.parent.border.top - + dims.parent.border.bottom + + diffVertical) / + toScale; + var maxY = (diffVertical - dims.parent.padding.top) / toScale; + result.y = Math.max(Math.min(result.y, maxY), minY); + } + } + if (opts.roundPixels) { + result.x = Math.round(result.x); + result.y = Math.round(result.y); + } + return result; + } + function constrainScale(toScale, zoomOptions) { + var opts = __assign(__assign({}, options), zoomOptions); + var result = { scale: scale, opts: opts }; + if (!opts.force && opts.disableZoom) { + return result; + } + var minScale = options.minScale; + var maxScale = options.maxScale; + if (opts.contain) { + var dims = getDimensions(elem); + var elemWidth = dims.elem.width / scale; + var elemHeight = dims.elem.height / scale; + if (elemWidth > 1 && elemHeight > 1) { + var parentWidth = dims.parent.width - dims.parent.border.left - dims.parent.border.right; + var parentHeight = dims.parent.height - dims.parent.border.top - dims.parent.border.bottom; + var elemScaledWidth = parentWidth / elemWidth; + var elemScaledHeight = parentHeight / elemHeight; + if (options.contain === 'inside') { + maxScale = Math.min(maxScale, elemScaledWidth, elemScaledHeight); + } + else if (options.contain === 'outside') { + minScale = Math.max(minScale, elemScaledWidth, elemScaledHeight); + } + } + } + result.scale = Math.min(Math.max(toScale, minScale), maxScale); + return result; + } + function pan(toX, toY, panOptions, originalEvent) { + var result = constrainXY(toX, toY, scale, panOptions); + // Only try to set if the result is somehow different + if (x !== result.x || y !== result.y) { + x = result.x; + y = result.y; + return setTransformWithEvent('panzoompan', result.opts, originalEvent); + } + return { x: x, y: y, scale: scale, isSVG: isSVG, originalEvent: originalEvent }; + } + function zoom(toScale, zoomOptions, originalEvent) { + var result = constrainScale(toScale, zoomOptions); + var opts = result.opts; + if (!opts.force && opts.disableZoom) { + return; + } + toScale = result.scale; + var toX = x; + var toY = y; + if (opts.focal) { + // The difference between the point after the scale and the point before the scale + // plus the current translation after the scale + // neutralized to no scale (as the transform scale will apply to the translation) + var focal = opts.focal; + toX = (focal.x / toScale - focal.x / scale + x * toScale) / toScale; + toY = (focal.y / toScale - focal.y / scale + y * toScale) / toScale; + } + var panResult = constrainXY(toX, toY, toScale, { relative: false, force: true }); + x = panResult.x; + y = panResult.y; + scale = toScale; + return setTransformWithEvent('panzoomzoom', opts, originalEvent); + } + function zoomInOut(isIn, zoomOptions) { + var opts = __assign(__assign(__assign({}, options), { animate: true }), zoomOptions); + return zoom(scale * Math.exp((isIn ? 1 : -1) * opts.step), opts); + } + function zoomIn(zoomOptions) { + return zoomInOut(true, zoomOptions); + } + function zoomOut(zoomOptions) { + return zoomInOut(false, zoomOptions); + } + function zoomToPoint(toScale, point, zoomOptions, originalEvent) { + var dims = getDimensions(elem); + // Instead of thinking of operating on the panzoom element, + // think of operating on the area inside the panzoom + // element's parent + // Subtract padding and border + var effectiveArea = { + width: dims.parent.width - + dims.parent.padding.left - + dims.parent.padding.right - + dims.parent.border.left - + dims.parent.border.right, + height: dims.parent.height - + dims.parent.padding.top - + dims.parent.padding.bottom - + dims.parent.border.top - + dims.parent.border.bottom + }; + // Adjust the clientX/clientY to ignore the area + // outside the effective area + var clientX = point.clientX - + dims.parent.left - + dims.parent.padding.left - + dims.parent.border.left - + dims.elem.margin.left; + var clientY = point.clientY - + dims.parent.top - + dims.parent.padding.top - + dims.parent.border.top - + dims.elem.margin.top; + // Adjust the clientX/clientY for HTML elements, + // because they have a transform-origin of 50% 50% + if (!isSVG) { + clientX -= dims.elem.width / scale / 2; + clientY -= dims.elem.height / scale / 2; + } + // Convert the mouse point from it's position over the + // effective area before the scale to the position + // over the effective area after the scale. + var focal = { + x: (clientX / effectiveArea.width) * (effectiveArea.width * toScale), + y: (clientY / effectiveArea.height) * (effectiveArea.height * toScale) + }; + return zoom(toScale, __assign(__assign({}, zoomOptions), { animate: false, focal: focal }), originalEvent); + } + function zoomWithWheel(event, zoomOptions) { + // Need to prevent the default here + // or it conflicts with regular page scroll + event.preventDefault(); + var opts = __assign(__assign(__assign({}, options), zoomOptions), { animate: false }); + // Normalize to deltaX in case shift modifier is used on Mac + var delta = event.deltaY === 0 && event.deltaX ? event.deltaX : event.deltaY; + var wheel = delta < 0 ? 1 : -1; + var toScale = constrainScale(scale * Math.exp((wheel * opts.step) / 3), opts).scale; + return zoomToPoint(toScale, event, opts, event); + } + function reset(resetOptions) { + var opts = __assign(__assign(__assign({}, options), { animate: true, force: true }), resetOptions); + scale = constrainScale(opts.startScale, opts).scale; + var panResult = constrainXY(opts.startX, opts.startY, scale, opts); + x = panResult.x; + y = panResult.y; + return setTransformWithEvent('panzoomreset', opts); + } + var origX; + var origY; + var startClientX; + var startClientY; + var startScale; + var startDistance; + var pointers = []; + function handleDown(event) { + // Don't handle this event if the target is excluded + if (isExcluded(event.target, options)) { + return; + } + addPointer(pointers, event); + isPanning = true; + options.handleStartEvent(event); + origX = x; + origY = y; + trigger('panzoomstart', { x: x, y: y, scale: scale, isSVG: isSVG, originalEvent: event }, options); + // This works whether there are multiple + // pointers or not + var point = getMiddle(pointers); + startClientX = point.clientX; + startClientY = point.clientY; + startScale = scale; + startDistance = getDistance(pointers); + } + function handleMove(event) { + if (!isPanning || + origX === undefined || + origY === undefined || + startClientX === undefined || + startClientY === undefined) { + return; + } + addPointer(pointers, event); + var current = getMiddle(pointers); + var hasMultiple = pointers.length > 1; + var toScale = scale; + if (hasMultiple) { + // A startDistance of 0 means + // that there weren't 2 pointers + // handled on start + if (startDistance === 0) { + startDistance = getDistance(pointers); + } + // Use the distance between the first 2 pointers + // to determine the current scale + var diff = getDistance(pointers) - startDistance; + toScale = constrainScale((diff * options.step) / 80 + startScale).scale; + zoomToPoint(toScale, current, { animate: false }, event); + } + // Pan during pinch if pinchAndPan is true. + // Note: some calculations may be off because the zoom + // above has not yet rendered. However, the behavior + // was removed before the new scale was used in the following + // pan calculation. + // See https://github.com/timmywil/panzoom/issues/512 + // and https://github.com/timmywil/panzoom/issues/606 + if (!hasMultiple || options.pinchAndPan) { + pan(origX + (current.clientX - startClientX) / toScale, origY + (current.clientY - startClientY) / toScale, { + animate: false + }, event); + } + } + function handleUp(event) { + // Don't call panzoomend when panning with 2 touches + // until both touches end + if (pointers.length === 1) { + trigger('panzoomend', { x: x, y: y, scale: scale, isSVG: isSVG, originalEvent: event }, options); + } + // Note: don't remove all pointers + // Can restart without having to reinitiate all of them + // Remove the pointer regardless of the isPanning state + removePointer(pointers, event); + if (!isPanning) { + return; + } + isPanning = false; + origX = origY = startClientX = startClientY = undefined; + } + var bound = false; + function bind() { + if (bound) { + return; + } + bound = true; + onPointer('down', options.canvas ? parent : elem, handleDown); + onPointer('move', document, handleMove, { passive: true }); + onPointer('up', document, handleUp, { passive: true }); + } + function destroy() { + bound = false; + destroyPointer('down', options.canvas ? parent : elem, handleDown); + destroyPointer('move', document, handleMove); + destroyPointer('up', document, handleUp); + } + if (!options.noBind) { + bind(); + } + return { + bind: bind, + destroy: destroy, + eventNames: events, + getPan: function () { return ({ x: x, y: y }); }, + getScale: function () { return scale; }, + getOptions: function () { return shallowClone(options); }, + handleDown: handleDown, + handleMove: handleMove, + handleUp: handleUp, + pan: pan, + reset: reset, + resetStyle: resetStyle, + setOptions: setOptions, + setStyle: function (name, value) { return setStyle(elem, name, value); }, + zoom: zoom, + zoomIn: zoomIn, + zoomOut: zoomOut, + zoomToPoint: zoomToPoint, + zoomWithWheel: zoomWithWheel + }; + } + Panzoom.defaultOptions = defaultOptions; + + return Panzoom; + +})); diff --git a/dist/panzoom.min.js b/dist/panzoom.min.js new file mode 100644 index 00000000..b91b7f2e --- /dev/null +++ b/dist/panzoom.min.js @@ -0,0 +1,6 @@ +/** +* Panzoom 4.6.0 for panning and zooming elements using CSS transforms +* Copyright Timmy Willison and other contributors +* https://github.com/timmywil/panzoom/blob/main/MIT-License.txt +*/ +((t,e)=>{"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t="undefined"!=typeof globalThis?globalThis:t||self).Panzoom=e()})(this,function(){var a,X=function(){return(X=Object.assign||function(t){for(var e,n=1,o=arguments.length;n{for(var e=t;e&&e.parentNode;){if(e.parentNode===document)return 1;e=e.parentNode instanceof ShadowRoot?e.parentNode.host:e.parentNode}})(u))throw new Error("Panzoom should be called on elements that have been attached to the DOM");f=X(X({},q),f);t=u;var t,l=Z.test(t.namespaceURI)&&"svg"!==t.nodeName.toLowerCase(),n=u.parentNode;n.style.overflow=f.overflow,n.style.userSelect="none",n.style.touchAction=f.touchAction,(f.canvas?n:u).style.cursor=f.cursor,u.style.userSelect="none",u.style.touchAction=f.touchAction,C(u,"transformOrigin","string"==typeof f.origin?f.origin:l?"0 0":"50% 50%");var r,a,i,c,s,d,m=0,h=0,v=1,p=!1;function g(t,e,n){n.silent||(n=new CustomEvent(t,{detail:e}),u.dispatchEvent(n))}function y(o,r,t){var a={x:m,y:h,scale:v,isSVG:l,originalEvent:t};return requestAnimationFrame(function(){var t,e,n;"boolean"==typeof r.animate&&(r.animate?(t=u,e=r,n=Y("transform"),C(t,"transition","".concat(n," ").concat(e.duration,"ms ").concat(e.easing))):C(u,"transition","none")),r.setTransform(u,a,r),g(o,a,r),g("panzoomchange",a,r)}),a}function w(t,e,n,o){var r,a,i,c,l,s,d,o=X(X({},f),o),p={x:m,y:h,opts:o};return!o.force&&(o.disablePan||o.panOnlyWhenZoomed&&v===o.startScale)||(t=parseFloat(t),e=parseFloat(e),o.disableXAxis||(p.x=(o.relative?m:0)+t),o.disableYAxis||(p.y=(o.relative?h:0)+e),o.contain&&(e=((r=(e=(t=N(u)).elem.width/v)*n)-e)/2,i=((a=(i=t.elem.height/v)*n)-i)/2,"inside"===o.contain?(c=(-t.elem.margin.left-t.parent.padding.left+e)/n,l=(t.parent.width-r-t.parent.padding.left-t.elem.margin.left-t.parent.border.left-t.parent.border.right+e)/n,p.x=Math.max(Math.min(p.x,l),c),s=(-t.elem.margin.top-t.parent.padding.top+i)/n,d=(t.parent.height-a-t.parent.padding.top-t.elem.margin.top-t.parent.border.top-t.parent.border.bottom+i)/n,p.y=Math.max(Math.min(p.y,d),s)):"outside"===o.contain&&(c=(-(r-t.parent.width)-t.parent.padding.left-t.parent.border.left-t.parent.border.right+e)/n,l=(e-t.parent.padding.left)/n,p.x=Math.max(Math.min(p.x,l),c),s=(-(a-t.parent.height)-t.parent.padding.top-t.parent.border.top-t.parent.border.bottom+i)/n,d=(i-t.parent.padding.top)/n,p.y=Math.max(Math.min(p.y,d),s))),o.roundPixels&&(p.x=Math.round(p.x),p.y=Math.round(p.y))),p}function b(t,e){var n,o,r,a,e=X(X({},f),e),i={scale:v,opts:e};return!e.force&&e.disableZoom||(n=f.minScale,o=f.maxScale,e.contain&&(a=(e=N(u)).elem.width/v,r=e.elem.height/v,1{for(var n,o,r=t;null!=r;r=r.parentNode)if(n=r,o=e.excludeClass,1===n.nodeType&&-1<" ".concat((n.getAttribute("class")||"").trim()," ").indexOf(" ".concat(o," "))||-1 { + * panzoom.setStyle('transform', `rotate(0.5turn) scale(${scale}) translate(${x}px, ${y}px)`) + * } + * }) + * ``` + */ +export declare function setTransform(elem: HTMLElement | SVGElement, { x, y, scale, isSVG }: CurrentValues, _options?: PanzoomOptions): void; +/** + * Dimensions used in containment and focal point zooming + */ +export declare function getDimensions(elem: HTMLElement | SVGElement): { + elem: { + style: CSSStyleDeclaration; + width: number; + height: number; + top: number; + bottom: number; + left: number; + right: number; + margin: { + left: number; + right: number; + top: number; + bottom: number; + }; + border: { + left: number; + right: number; + top: number; + bottom: number; + }; + }; + parent: { + style: CSSStyleDeclaration; + width: number; + height: number; + top: number; + bottom: number; + left: number; + right: number; + padding: { + left: number; + right: number; + top: number; + bottom: number; + }; + border: { + left: number; + right: number; + top: number; + bottom: number; + }; + }; +}; diff --git a/dist/src/events.d.ts b/dist/src/events.d.ts new file mode 100644 index 00000000..f11acf2b --- /dev/null +++ b/dist/src/events.d.ts @@ -0,0 +1,8 @@ +declare let events: { + down: string; + move: string; + up: string; +}; +export { events as eventNames }; +export declare function onPointer(event: 'down' | 'move' | 'up', elem: HTMLElement | SVGElement | Document, handler: (event: PointerEvent) => void, eventOpts?: boolean | AddEventListenerOptions): void; +export declare function destroyPointer(event: 'down' | 'move' | 'up', elem: HTMLElement | SVGElement | Document, handler: (event: PointerEvent) => void): void; diff --git a/dist/src/isAttached.d.ts b/dist/src/isAttached.d.ts new file mode 100644 index 00000000..b7c3cd50 --- /dev/null +++ b/dist/src/isAttached.d.ts @@ -0,0 +1,5 @@ +/** + * Determine if an element is attached to the DOM + * Panzoom requires this so events work properly + */ +export default function isAttached(node: Node): boolean; diff --git a/dist/src/isExcluded.d.ts b/dist/src/isExcluded.d.ts new file mode 100644 index 00000000..7dc6bda8 --- /dev/null +++ b/dist/src/isExcluded.d.ts @@ -0,0 +1,2 @@ +import type { PanzoomOptions } from './types.js'; +export default function isExcluded(elem: Element, options: PanzoomOptions): boolean; diff --git a/dist/src/isSVGElement.d.ts b/dist/src/isSVGElement.d.ts new file mode 100644 index 00000000..a9722aad --- /dev/null +++ b/dist/src/isSVGElement.d.ts @@ -0,0 +1 @@ +export default function isSVGElement(elem: HTMLElement | SVGElement): boolean; diff --git a/dist/src/panzoom.d.ts b/dist/src/panzoom.d.ts new file mode 100644 index 00000000..c74ee0ee --- /dev/null +++ b/dist/src/panzoom.d.ts @@ -0,0 +1,17 @@ +/** + * Panzoom for panning and zooming elements using CSS transforms + * https://github.com/timmywil/panzoom + * + * Copyright Timmy Willison and other contributors + * Released under the MIT license + * https://github.com/timmywil/panzoom/blob/main/MIT-License.txt + * + */ +import './polyfills.js'; +import type { PanzoomObject, PanzoomOptions } from './types.js'; +declare function Panzoom(elem: HTMLElement | SVGElement, options?: Omit): PanzoomObject; +declare namespace Panzoom { + var defaultOptions: PanzoomOptions; +} +export * from './types.js'; +export default Panzoom; diff --git a/dist/src/pointers.d.ts b/dist/src/pointers.d.ts new file mode 100644 index 00000000..f68b3255 --- /dev/null +++ b/dist/src/pointers.d.ts @@ -0,0 +1,17 @@ +/** + * Utilites for working with multiple pointer events + */ +export declare function addPointer(pointers: PointerEvent[], event: PointerEvent): void; +export declare function removePointer(pointers: PointerEvent[], event: PointerEvent): void; +/** + * Calculates a center point between + * the given pointer events, for panning + * with multiple pointers. + */ +export declare function getMiddle(pointers: PointerEvent[]): Pick; +/** + * Calculates the distance between two points + * for pinch zooming. + * Limits to the first 2 + */ +export declare function getDistance(pointers: PointerEvent[]): number; diff --git a/dist/src/shallowClone.d.ts b/dist/src/shallowClone.d.ts new file mode 100644 index 00000000..a422b88d --- /dev/null +++ b/dist/src/shallowClone.d.ts @@ -0,0 +1 @@ +export default function shallowClone(obj: any): any; diff --git a/dist/src/types.d.ts b/dist/src/types.d.ts new file mode 100644 index 00000000..3d92d275 --- /dev/null +++ b/dist/src/types.d.ts @@ -0,0 +1,392 @@ +import { setTransform } from './css.js'; +export type PanzoomEvent = 'panzoomstart' | 'panzoomchange' | 'panzoompan' | 'panzoomzoom' | 'panzoomreset' | 'panzoomend'; +export interface PanzoomEventDetail { + x: number; + y: number; + scale: number; + isSVG: boolean; + originalEvent: PointerEvent | TouchEvent | MouseEvent; +} +export interface MiscOptions { + /** Whether to animate transitions */ + animate?: boolean; + /** + * This option treats the Panzoom element's parent + * as a canvas. Effectively, Panzoom binds the + * down handler to the parent instead of the Panzoom + * element, so that pointer events anywhere on the "canvas" + * moves its children. See issue #472. + * + * **Note**: setting this option to `true` also changes + * where the `cursor` style is applied (i.e. the parent). + */ + canvas?: boolean; + /** Duration of the transition (ms) */ + duration?: number; + /** CSS Easing used for transitions */ + easing?: string; + /** + * Add elements to this array that should be excluded + * from Panzoom handling. + * Ancestors of event targets are also checked. + * e.g. links and buttons that should not propagate the click event. + */ + exclude?: Element[]; + /** + * Add this class to any element within the Panzoom element + * that you want to exclude from Panzoom handling. That + * element's children will also be excluded. + * e.g. links and buttons that should not propagate the click event. + */ + excludeClass?: string; + /** + * `force` should be used sparingly to temporarily + * override and ignore options such as disablePan, + * disableZoom, and panOnlyWhenZoomed. + * This option cannot be passed to the + * Panzoom constructor or setOptions (to avoid + * setting this option globally). + * + * ```js + * // Overrides disablePan and panOnlyWhenZoomed + * panzoom.pan(50, 100, { force: true }) + * // Overrides disableZoom + * panzoom.zoom(1, { force: true }) + * ``` + */ + force?: boolean; + /** + * On the first pointer event, when panning starts, + * the default Panzoom behavior is to call + * `event.preventDefault()` and `event.stopPropagation()` + * on that event. The former is almost certainly a necessity; + * the latter enables Panzoom elements within Panzoom elements. + * + * But there are some cases where the default is + * not the desired behavior. Set this option to override that behavior. + * + * ```js + * // Only call preventDefault() + * Panzoom(elem, { + * handleStartEvent: (event) => { + * event.preventDefault() + * } + * }) + * // Do nothing. + * // This can change dragging behavior on mobile. + * Panzoom(elem, { + * handleStartEvent: () => {} + * }) + * ``` + */ + handleStartEvent?: (event: Event) => void; + /** + * Skip binding the default Panzoom event listeners + */ + noBind?: boolean; + /** + * **Change this at your own risk.** + * The `transform-origin` is the origin from which transforms are applied. + * Default: `'50% 50%'` for HTML and `'0 0'` for SVG. + * The defaults are set because changing the `transform-origin` on + * SVG elements doesn't work in IE. + * + * Changing this should work with many things, but + * it will break focal point zooming, which assumes the + * defaults are set to do the more complicated calculations. + * + * And again, changing this for SVG in IE doesn't work at all. + */ + origin?: string; + /** The overflow CSS value for the parent. Defaults to 'hidden' */ + overflow?: string; + /** + * Set to true to enable panning during pinch zoom. + * Note: this is zooming to a point and panning in the same + * frame. In other words, the zoom has not yet painted and + * therefore the pan is working with old dimensions. + * Essentially, it may be best to avoid using this option + * when using contain. + * + * Related issues: + * https://github.com/timmywil/panzoom/issues/512 + * https://github.com/timmywil/panzoom/issues/606 + */ + pinchAndPan?: boolean; + /** + * Set the transform using the proper prefix. + */ + setTransform?: typeof setTransform; + /** Silence all events */ + silent?: boolean; + /** X Value used to set the beginning transform */ + startX?: number; + /** Y Value used to set the beginning transform */ + startY?: number; + /** Scale used to set the beginning transform */ + startScale?: number; + /** + * This value is used to set touch-action on both the + * Panzoom element and its parent. + * It is needed because that the native scroll on mobile + * interferes with panning and pinch zooming. + * Set this to empty string to re-enable scrolling + * on mobile, but note that both scrolling and panning + * cannot work at the same time. + */ + touchAction?: string; + /** Pass through any options like data */ + [key: string]: any; +} +export interface PanOnlyOptions { + /** + * Contain the panzoom element either + * inside or outside the parent. + * Inside: The panzoom element is smaller + * than its parent and cannot be panned + * to the outside. + * Outside: The panzoom element is larger + * than its parent and cannot be panned + * to the inside. In other words, no + * empty space around the element will be shown. + * + * **Note**: the containment pan adjustment is not affected by the `disablePan` option. + */ + contain?: 'inside' | 'outside'; + /** The cursor style to set on the panzoom element */ + cursor?: string; + /** + * Disable panning functionality. + * Note: disablePan does not affect focal point zooming or the contain option. + * The element will still pan accordingly. + */ + disablePan?: boolean; + /** Pan only on the Y axis */ + disableXAxis?: boolean; + /** Pan only on the X axis */ + disableYAxis?: boolean; + /** When passing x and y values to .pan(), treat the values as relative to their current values */ + relative?: boolean; + /** Disable panning while the scale is equal to the starting value */ + panOnlyWhenZoomed?: boolean; + /** + * Round x and y values to whole numbers. + * This can help prevent images and text from looking blurry, + * but the higher the scale, the more it becomes + * necessary to use fractional pixels. + * Use your own judgment on how much to limit + * zooming in when using this option. + */ + roundPixels?: boolean; +} +export interface ZoomOnlyOptions { + /** Disable zooming functionality */ + disableZoom?: boolean; + /** + * Zoom to the given point on the panzoom element. + * This point is expected to be relative to + * the panzoom element's dimensions and is unrelated + * to the parent dimensions. + */ + focal?: { + x: number; + y: number; + }; + /** The minimum scale when zooming */ + minScale?: number; + /** The maximum scale when zooming */ + maxScale?: number; + /** The step affects zoom calculation when zooming with a mouse wheel, when pinch zooming, or when using zoomIn/zoomOut */ + step?: number; +} +export type PanOptions = MiscOptions & PanOnlyOptions; +export type ZoomOptions = MiscOptions & ZoomOnlyOptions; +export type PanzoomOptions = PanOptions & ZoomOptions & MiscOptions; +export interface CurrentValues { + x: number; + y: number; + scale: number; + isSVG?: boolean; +} +export interface PanzoomObject { + /** + * Bind the default down, move, and up event listeners to the Panzoom element. + * This does not normally need to be called. + * It gets called by default when creating a new Panzoom object, + * but can be skipped with the `noBind` option. + * + * ```js + * const panzoom = Panzoom(elem, { noBind: true }) + * // ... + * panzoom.bind() + * ``` + */ + bind: () => void; + /** Remove all event listeners bound to the the Panzoom element */ + destroy: () => void; + /** + * This object exposes the event names used by Panzoom, + * depending on the current browser's support for + * Pointer or Touch events. + */ + eventNames: { + down: string; + move: string; + up: string; + }; + /** Get the current x/y translation */ + getPan: () => { + x: number; + y: number; + }; + /** Get the current scale */ + getScale: () => number; + /** Returns a _copy_ of the current options object */ + getOptions: () => PanzoomOptions; + /** + * handleDown, handleMove, and handleUp + * are the exact event handlers that Panzoom + * binds to pointer events. They are exposed + * in case you prefer to bind your own events + * or extend them. + * Note that move and up are bound to the document, + * not the Panzoom element. Only the down event + * is bound to the Panzoom element. + * To avoid double-binding, also set noBind to true. + * + * ```js + * const panzoom = Panzoom(elem, { noBind: true }) + * elem.addEventListener('pointerdown', (event) => { + * console.log(event) + * panzoom.handleDown(event) + * }) + * document.addEventListener('pointermove', panzoom.handleMove) + * document.addEventListener('pointerup', panzoom.handleUp) + * ``` + */ + handleDown: (event: PointerEvent) => void; + handleMove: (event: PointerEvent) => void; + handleUp: (event: PointerEvent) => void; + /** + * Pan the Panzoom element to the given x and y coordinates + * + * ```js + * // Translates the element to 50px, 100px + * panzoom.pan(50, 100) + * // Pans the element right 10px and down 10px from its current position + * panzoom.pan(10, 10, { relative: true }) + * ``` + */ + pan: (x: number | string, y: number | string, panOptions?: PanOptions) => CurrentValues; + /** + * Reset the pan and zoom to startX, startY, and startScale. + * Animates by default, ignoring the global option. + * Pass `{ animate: false }` to override. + * Reset ignores the `disablePan`, `disableZoom`, and `panOnlyWhenZoomed` options. + * Pass `{ force: false }` to override. + * + * ```js + * panzoom.reset() + * panzoom.reset({ animate: false }) + * ``` + */ + reset: (resetOptions?: PanzoomOptions) => CurrentValues; + /** + * Reset the styles set on the Panzoom element + * and its parent (such as overflow, cursor, etc.) + * + * ```js + * panzoom.resetStyle() + * ``` + */ + resetStyle: () => void; + /** + * Change any number of options on a Panzoom instance. + * Setting some options will have side-effects. + * For instance, changing the cursor option + * will also set the cursor style. + * + * ```js + * const panzoom = Panzoom(elem, { cursor: 'move' }) + * // ... + * panzoom.setOptions({ cursor: 'default' }) + * ``` + */ + setOptions: (options?: PanzoomOptions) => void; + /** A convenience method for setting prefixed styles on the Panzoom element */ + setStyle: (name: string, value: string) => void; + /** + * Zoom the Panzoom element to the given scale + * + * ```js + * panzoom.zoom(2.2) + * panzoom.zoom(2.2, { animate: true }) + * ``` + */ + zoom: (scale: number, zoomOptions?: ZoomOptions) => CurrentValues; + /** + * Zoom in using the predetermined increment set in options. + * Animates by default, ignoring the global option. + * Pass `{ animate: false }` to override. + * + * ```js + * panzoom.zoomIn() + * panzoom.zoomIn({ animate: false }) + * ``` + */ + zoomIn: (zoomOptions?: ZoomOptions) => CurrentValues; + /** + * Zoom out using the predetermined increment set in options. + * Animates by default, ignoring the global option. + * Pass `{ animate: false }` to override. + * + * ```js + * panzoom.zoomOut() + * panzoom.zoomOut({ animate: false }) + * ``` + */ + zoomOut: (zoomOptions?: ZoomOptions) => CurrentValues; + /** + * Zoom the Panzoom element to a focal point using + * the given pointer/touch/mouse event or constructed point. + * The clientX/clientY values should be calculated + * the same way as a `pointermove` event on the Panzoom element's parent. + * + * ```js + * panzoom.zoomToPoint(1.2, pointerEvent) + * ``` + */ + zoomToPoint: (scale: number, point: { + clientX: number; + clientY: number; + }, zoomOptions?: ZoomOptions) => CurrentValues; + /** + * Zoom the Panzoom element to a focal point using the given WheelEvent + * + * This is a convenience function that may not handle all use cases. + * Other cases should handroll solutions using the `zoomToPoint` + * method or the `zoom` method's focal option. + * + * **Notes**: + * + * - the focal point zooming pan adjustment is + * not affected by the `disablePan` option. + * - animate should not be used when zooming with the wheel, + * and is therefore always disabled. + * + * ```js + * // Bind to mousewheel + * elem.parentElement.addEventListener('wheel', panzoom.zoomWithWheel) + * // Bind to shift+mousewheel + * elem.parentElement.addEventListener('wheel', function(event) { + * if (!event.shiftKey) return + * // Panzoom will automatically use `deltaX` here instead + * // of `deltaY`. On a mac, the shift modifier usually + * // translates to horizontal scrolling, but Panzoom assumes + * // the desired behavior is zooming. + * panzoom.zoomWithWheel(event) + * }) + * ``` + */ + zoomWithWheel: (event: WheelEvent, zoomOptions?: ZoomOptions) => CurrentValues; +} diff --git a/package-lock.json b/package-lock.json index d2ad1de0..e547610f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@panzoom/panzoom", - "version": "4.5.1", + "version": "4.6.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@panzoom/panzoom", - "version": "4.5.1", + "version": "4.6.0", "license": "MIT", "devDependencies": { "@babel/core": "^7.26.0", diff --git a/package.json b/package.json index a9da8e0d..281cf747 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@panzoom/panzoom", - "version": "4.5.1", + "version": "4.6.0", "description": "Pan and zoom elements anywhere using native transformations", "main": "dist/panzoom.js", "module": "dist/panzoom.es.js",