Skip to content
A library for panning and zooming elements using CSS transforms 🔍
TypeScript JavaScript
Branch: master
Clone or download
Type Name Latest commit message Commit time
Failed to load latest commit information.
.github chore(github): remove old Jan 14, 2020
demo docs(demo): add special rotation examples Jan 16, 2020
src fix(zoomtopoint): should be able to override animate Jan 16, 2020
tasks feat(panzoom): add the force option Oct 30, 2019
test fix(reset): ignore disable and panOnlyWhenZoomed options Dec 31, 2019
.babelrc feat(*): clean slate with typescript, rollup, and semantic-release Jul 27, 2019
.editorconfig feat(*): clean slate with typescript, rollup, and semantic-release Jul 27, 2019
.eslintignore build(demo): eslint should ignore demo folder Nov 18, 2019
.eslintrc.json chore(linting): migrate tslint to eslint Nov 14, 2019
.gitignore build(demo): add log to clarify demo/panzoom.js purpose Nov 18, 2019
.prettierignore build(*): set up testing environment Jul 27, 2019
.travis.yml ci: upgrade lts node to version 12 Oct 30, 2019
MIT-License.txt feat(*): clean slate with typescript, rollup, and semantic-release Jul 27, 2019 chore(release): 4.0.2 [skip ci] Jan 16, 2020
commitlint.config.js docs(panzoom): the force option should not be passed to Panzoom or se… Oct 30, 2019
karma.conf.js test(contain): fix inconsistent contain test Nov 18, 2019
package.json Update cross-env to the latest version 🚀 (#444) Jan 26, 2020
rollup.config.js docs: consolidate docs into README Aug 8, 2019
tsconfig.json feat(*): basic panning and zooming functionality Jul 27, 2019
webpack.config.js fix(zoom): need the before and after dimensions to constrain Nov 18, 2019
yarn.lock Update cross-env to the latest version 🚀 (#444) Jan 26, 2020


Build Status Greenkeeper badge


Panzoom is a small library (~3.5kb gzipped) to add panning and zooming functionality to an element. Rather than using absolute positioning or setting width and height, Panzoom uses CSS transforms to take advantage of hardware/GPU acceleration in the browser, which means the element can be anything: an image, a video, an iframe, a canvas, text, WHATEVER.

For common support questions, see the FAQ.

Browser support

Here is a list of currently supported browsers.

Mobile support

iOS, Android, and Windows Mobile are supported.

Panzoom includes support for touch gestures and even supports pinch gestures for zooming. It is perfectly suited for both mobile and desktop browsers. It uses pointer events by default wherever supported.

SVG support

Panzoom supports panning and zooming SVG elements directly.

In IE11, CSS animations/transitions do not work on SVG elements, at least for the transform style. They do work in other browsers.

One could implement transitions manually in IE11 using the setTransform option and integrating a tweening library for javascript animations (such as tween.js).


With npm:

$ npm install --save @panzoom/panzoom

With yarn:

$ yarn add @panzoom/panzoom

Panzoom uses UMD and can be loaded a lot of ways.

With ES6 imports:

import Panzoom from '@panzoom/panzoom'

With commonjs or browserify:

const Panzoom = require('@panzoom/panzoom')

With an AMD loader in an anonymous module:

define(['@panzoom/panzoom'], function(Panzoom) {

With a script tag:

<script src="/js/panzoom.js"></script>


const elem = document.getElementById('panzoom-element')
const panzoom = Panzoom(elem, {
  maxScale: 5
panzoom.pan(10, 10)
panzoom.zoom(2, { animate: true })

// Panning and pinch zooming are bound automatically (unless disablePan is true).
// There are several available methods for zooming
// that can be bound on button clicks or mousewheel.
button.addEventListener('click', panzoom.zoomIn)
elem.parentElement.addEventListener('wheel', panzoom.zoomWithWheel)


1. What is transform-origin and why is it added to the panzoom element?

  • The transform-origin is the origin from which transforms are applied. Panzoom ensures the defaults are set to what it expects to calculate focal point zooming.
  • HTML elements default to '50% 50%'.
  • SVG elements default to '0 0'.

2. I am using Panzoom with an <object> tag and it's not working. What's wrong?

Object elements can eat up events, making it so they never reach Panzoom. To fix this, disable pointer events (pointer-events: none) on the <object> tag and call Panzoom using a wrapper.

3. My links aren't working! How do I enable an anchor within a panzoom element?

Add class options.excludeClass (default is "panzoom-exclude") to whatever element you want to be clickable. Panzoom will check for this class before handling the event. Alternatively, add a reference to the element to the exclude option, or call event.stopImmediatePropagation() in an event handler on the clickable element.

A note on the async nature of Panzoom

In some cases, setting one thing and then setting another synchronously will not work as intended.

For instance, the following usually works fine.

const panzoom = Panzoom(elem)
panzoom.pan(100, 100)

However, you might find that the things start breaking when the contain option is set.

This is due to the fact that in order for Panzoom to retrieve proper dimensions, the scale needs to be painted.

If you find that things aren't looking quite right, try the following instead...

setTimeout(() => panzoom.pan(100, 100))


Panzoom(elem: HTMLElement | SVGElement, options?: Omit‹PanzoomOptions, "force"›): PanzoomObject

Defined in panzoom.ts:49


Name Type
elem HTMLElement | SVGElement
options? Omit‹PanzoomOptions, "force"›

Returns: PanzoomObject


Includes MiscOptions, PanOptions, and ZoomOptions



animate? : boolean (Default: false)

Defined in types.ts:13

Whether to animate transitions


duration? : number (Default: 200)

Defined in types.ts:15

Duration of the transition (ms)


easing? : string (Default: "ease-in-out")

Defined in types.ts:17

CSS Easing used for transitions


exclude? : Element[]

Defined in types.ts:24

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.


excludeClass? : string (Default: "panzoom-exclude")

Defined in types.ts:31

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.


force? : boolean

Defined in types.ts:47

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).

// Overrides disablePan and panOnlyWhenZoomed
panzoom.pan(50, 100, { force: true })
// Overrides disableZoom
panzoom.zoom(1, { force: true })


handleStartEvent? : function

Defined in types.ts:71

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 necesity, 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.

// Only call preventDefault()
Panzoom(elem, {
  handleStartEvent: (event) => {
// Do nothing (this probably breaks things on mobile tho)
Panzoom(elem, {
  handleStartEvent: () => {}

Type declaration:

▸ (event: Event): void


Name Type
event Event


origin? : string

Defined in types.ts:85

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.


overflow? : string (Default: "hidden")

Defined in types.ts:87

The overflow CSS value for the parent. Defaults to 'hidden'


setTransform? : setTransform

Defined in types.ts:105

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.

// 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)`)


silent? : boolean

Defined in types.ts:107

Silence all events


startScale? : number (Default: 1)

Defined in types.ts:113

Scale used to set the beginning transform


startX? : number (Default: 0)

Defined in types.ts:109

X Value used to set the beginning transform


startY? : number (Default: 0)

Defined in types.ts:111

Y Value used to set the beginning transform


Includes MiscOptions


contain? : "inside" | "outside"

Defined in types.ts:130

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.


cursor? : string (Default: "move")

Defined in types.ts:132

The cursor style to set on the panzoom element


disablePan? : boolean (Default: false)

Defined in types.ts:138

Disable panning functionality. Note: disablePan does not affect focal point zooming or the constrain option. The element will still pan accordingly.


disableXAxis? : boolean (Default: false)

Defined in types.ts:140

Pan only on the Y axis


disableYAxis? : boolean (Default: false)

Defined in types.ts:142

Pan only on the X axis


panOnlyWhenZoomed? : boolean (Default: false)

Defined in types.ts:146

Disable panning while the scale is equal to the starting value


relative? : boolean (Default: false)

Defined in types.ts:144

When passing x and y values to .pan(), treat the values as relative to their current values


Includes MiscOptions


disableZoom? : boolean (Default: false)

Defined in types.ts:151

Disable zooming functionality


focal? : object

Defined in types.ts:158

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.

Type declaration:

  • x: number

  • y: number


maxScale? : number (Default: 4)

Defined in types.ts:162

The maximum scale when zooming


minScale? : number (Default: 0.125)

Defined in types.ts:160

The minimum scale when zooming


step? : number (Default: 0.3)

Defined in types.ts:164

The step affects zoom calculation when zooming with a mouse wheel, when pinch zooming, or when using zoomIn/zoomOut


These methods are available after initializing Panzoom


destroy: function

Defined in types.ts:179

Remove all event listeners bind to the the Panzoom element

Signature with return type:

▸ (): void


getOptions: function

Defined in types.ts:185

Returns a copy of the current options object

Signature with return type:

▸ (): PanzoomOptions


getPan: function

Defined in types.ts:181

Get the current x/y translation

Signature with return type:

▸ (): object

  • x: number

  • y: number


getScale: function

Defined in types.ts:183

Get the current scale

Signature with return type:

▸ (): number


pan: function

Defined in types.ts:196

Pan the Panzoom element to the given x and y coordinates

// 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 })

Signature with return type:

▸ (x: number | string, y: number | string, panOptions?: PanOptions): CurrentValues


Name Type
x number | string
y number | string
panOptions? PanOptions


reset: function

Defined in types.ts:209

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.

panzoom.reset({ animate: false })

Signature with return type:

▸ (resetOptions?: PanzoomOptions): CurrentValues


Name Type
resetOptions? PanzoomOptions


setOptions: function

Defined in types.ts:211

Change options for the Panzoom instance

Signature with return type:

▸ (options?: PanzoomOptions): void


Name Type
options? PanzoomOptions


setStyle: function

Defined in types.ts:213

A convenience method for setting prefixed styles on the Panzoom element

Signature with return type:

▸ (name: string, value: string): void


Name Type
name string
value string


zoom: function

Defined in types.ts:222

Zoom the Panzoom element to the given scale

panzoom.zoom(2.2, { animate: true })

Signature with return type:

▸ (scale: number, zoomOptions?: ZoomOptions): CurrentValues


Name Type
scale number
zoomOptions? ZoomOptions


zoomIn: function

Defined in types.ts:233

Zoom in using the predetermined increment set in options. Animates by default, ignoring the global option. Pass { animate: false } to override.

panzoom.zoomIn({ animate: false })

Signature with return type:

▸ (zoomOptions?: ZoomOptions): CurrentValues


Name Type
zoomOptions? ZoomOptions


zoomOut: function

Defined in types.ts:244

Zoom out using the predetermined increment set in options. Animates by default, ignoring the global option. Pass { animate: false } to override.

panzoom.zoomOut({ animate: false })

Signature with return type:

▸ (zoomOptions?: ZoomOptions): CurrentValues


Name Type
zoomOptions? ZoomOptions


zoomToPoint: function

Defined in types.ts:255

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.

panzoom.zoomToPoint(1.2, pointerEvent)

Signature with return type:

▸ (scale: number, point: object, zoomOptions?: ZoomOptions): CurrentValues


scale: number

point: object

Name Type
clientX number
clientY number

Optional zoomOptions: ZoomOptions


zoomWithWheel: function

Defined in types.ts:284

Zoom the Panzoom element to a focal point using the given WheelEvent

disablePan will prevent the focal point adjustment and will only zoom.

zoomWithWheel normally uses deltaY to determine the scale, but will fall back to deltaX in case the shift modifier is used with the wheel event. On a mac, that usually translates to horizontal scrolling, but this method assumes the desired behavior is zooming.

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.

// Bind to mousewheel
elem.parentElement.addEventListener('wheel', panzoom.zoomWithWheel)
// Bind to shift+mousewheel
elem.parentElement.addEventListener('wheel', function(event) {
  if (!event.shiftKey) return

Signature with return type:

▸ (event: WheelEvent, zoomOptions?: ZoomOptions): CurrentValues


Name Type
event WheelEvent
zoomOptions? ZoomOptions



scale: number

Defined in types.ts:174


x: number

Defined in types.ts:172


y: number

Defined in types.ts:173


The following events are available as custom events on the panzoom element using the native CustomEvent API. Add listeners the same way you would any other event.

elem.addEventListener('panzoomchange', (event) => {
  console.log(event.detail) // => { x: 0, y: 0, scale: 1 }

Notes about all events

  • The event object passed as an argument to the listener will always have a detail property with the current x, y, and scale values.
  • Events can be silenced when the silent option is set to true, either globally or when passed to pan, any zoom method, or reset.
  • Avoid putting too much logic in these event handlers as it could effect the performance of panning or zooming.


Fired when the user starts a move or pinch zoom gesture on mobile.


Fired whenever there is a pan, zoom, or reset. Note that direct calls to options.setTransform do not fire this event.


Fired whenever the zoom is changed by any Panzoom zoom method, directly or internally.


Fired whenever the zoom is changed by the pan method, directly or internally.


Fired when the user finishes a move or finishes a pinch zoom gesture on mobile.


Fired whenever reset is called.

You can’t perform that action at this time.