{"id":13447557,"url":"https://github.com/anvaka/panzoom","last_synced_at":"2025-05-14T03:05:43.832Z","repository":{"id":37588547,"uuid":"55361353","full_name":"anvaka/panzoom","owner":"anvaka","description":"Universal pan and zoom library (DOM, SVG, Custom)","archived":false,"fork":false,"pushed_at":"2024-10-10T04:41:56.000Z","size":1243,"stargazers_count":1815,"open_issues_count":167,"forks_count":292,"subscribers_count":25,"default_branch":"main","last_synced_at":"2024-10-29T15:04:19.632Z","etag":null,"topics":["pan","panzoom","scene","svg","transform","zoom"],"latest_commit_sha":null,"homepage":"https://anvaka.github.io/panzoom/demo/attach-via-script.html","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/anvaka.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2016-04-03T18:15:21.000Z","updated_at":"2024-10-29T09:50:16.000Z","dependencies_parsed_at":"2024-11-18T23:04:23.197Z","dependency_job_id":"0b483d7c-165a-4ff4-adf2-3cd602e56750","html_url":"https://github.com/anvaka/panzoom","commit_stats":{"total_commits":311,"total_committers":31,"mean_commits":10.03225806451613,"dds":"0.14147909967845662","last_synced_commit":"e2eb1545dceece3fd03fdb6f84165cdcc8dcc9a1"},"previous_names":[],"tags_count":89,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/anvaka%2Fpanzoom","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/anvaka%2Fpanzoom/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/anvaka%2Fpanzoom/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/anvaka%2Fpanzoom/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/anvaka","download_url":"https://codeload.github.com/anvaka/panzoom/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247246933,"owners_count":20907881,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["pan","panzoom","scene","svg","transform","zoom"],"created_at":"2024-07-31T05:01:20.909Z","updated_at":"2025-04-08T23:04:57.954Z","avatar_url":"https://github.com/anvaka.png","language":"JavaScript","funding_links":[],"categories":["JavaScript"],"sub_categories":[],"readme":"# panzoom [![build status](https://github.com/anvaka/panzoom/actions/workflows/tests.yaml/badge.svg)](https://github.com/anvaka/panzoom/actions/workflows/tests.yaml)\n\nExtensible, mobile friendly pan and zoom framework (supports DOM and SVG).\n\n# Demo\n\n * [Regular DOM object](https://anvaka.github.io/panzoom/demo/dom.html)\n * [Standalone page](https://anvaka.github.io/panzoom/demo/index.html) - this repository\n * [SVG Tiger](https://jsfiddle.net/anvaka/9twnb7zr/) - js fiddle\n\n# Usage\n\nGrab it from npm and use with your favorite bundler:\n\n```\nnpm install panzoom --save\n```\n\nOr download from CDN:\n\n``` html\n\u003cscript src='https://unpkg.com/panzoom@9.4.0/dist/panzoom.min.js'\u003e\u003c/script\u003e\n```\n\nIf you download from CDN the library will be available under `panzoom` global name.\n\n## Pan and zoom DOM subtree\n\n``` js\n// just grab a DOM element\nvar element = document.querySelector('#scene')\n\n// And pass it to panzoom\npanzoom(element)\n```\n\n## SVG panzoom example\n\n``` html\n\u003c!-- this is your html file with svg --\u003e\n\u003cbody\u003e\n  \u003csvg\u003e\n    \u003c!-- this is the draggable root --\u003e\n    \u003cg id='scene'\u003e \n      \u003ccircle cx='10' cy='10' r='5' fill='pink'\u003e\u003c/circle\u003e\n    \u003c/g\u003e\n  \u003c/svg\u003e\n\u003c/body\u003e\n```\n\n``` js\n// In the browser panzoom is already on the\n// window. If you are in common.js world, then \n// var panzoom = require('panzoom')\n\n// grab the DOM SVG element that you want to be draggable/zoomable:\nvar element = document.getElementById('scene')\n\n// and forward it it to panzoom.\npanzoom(element)\n```\n\nIf require a dynamic behavior (e.g. you want to make an `element` not \ndraggable anymore, or even completely delete an SVG element) make sure to call\n`dispose()` method:\n\n``` js\nvar instance = panzoom(element)\n// do work\n// ...\n// then at some point you decide you don't need this anymore:\ninstance.dispose()\n```\n\nThis will make sure that all event handlers are cleared and you are not leaking\nmemory\n\n## Events notification\n\nThe library allows to subscribe to transformation changing events. E.g. when\nuser starts/ends dragging the `element`, the `element` will fire `panstart`/`panend`\nevents. Here is example of all supported events:\n\n``` js\nvar instance = panzoom(element);\ninstance.on('panstart', function(e) {\n  console.log('Fired when pan is just started ', e);\n  // Note: e === instance.\n});\n\ninstance.on('pan', function(e) {\n  console.log('Fired when the `element` is being panned', e);\n});\n\ninstance.on('panend', function(e) {\n  console.log('Fired when pan ended', e);\n});\n\ninstance.on('zoom', function(e) {\n  console.log('Fired when `element` is zoomed', e);\n});\n\ninstance.on('zoomend', function(e) {\n  console.log('Fired when zoom animation ended', e);\n});\n\ninstance.on('transform', function(e) {\n  // This event will be called along with events above.\n  console.log('Fired when any transformation has happened', e);\n});\n```\n\nSee [JSFiddle](https://jsfiddle.net/uwxcmbyg/609/) console for a demo.\n\n## Ignore mouse wheel\n\nSometimes zooming interferes with scrolling. If you want to alleviate it you\ncan provide a custom filter, which will allow zooming only when modifier key is\ndown. E.g.\n\n``` js\npanzoom(element, {\n  beforeWheel: function(e) {\n    // allow wheel-zoom only if altKey is down. Otherwise - ignore\n    var shouldIgnore = !e.altKey;\n    return shouldIgnore;\n  }\n});\n```\n\nSee [JSFiddle](https://jsfiddle.net/Laxq9jLu/) for the demo. The tiger will be\nzoomable only when `Alt` key is down.\n\n\n## Ignore mouse down\n\nIf you want to disable panning or filter it by pressing a specific key, use the\n`beforeMouseDown()` option. E.g.\n\n``` js\npanzoom(element, {\n  beforeMouseDown: function(e) {\n    // allow mouse-down panning only if altKey is down. Otherwise - ignore\n    var shouldIgnore = !e.altKey;\n    return shouldIgnore;\n  }\n});\n```\n\nNote that it only works when the mouse initiates the panning and would not work\nfor touch initiated events.\n\n## Ignore keyboard events\n\nBy default, panzoom will listen to keyboard events, so that users can navigate the scene\nwith arrow keys and `+`, `-` signs to zoom out. If you don't want this behavior you can\npass the `filterKey()` predicate that returns truthy value to prevent panzoom's default\nbehavior:\n\n``` js\npanzoom(element, {\n  filterKey: function(/* e, dx, dy, dz */) {\n    // don't let panzoom handle this event:\n    return true;\n  }\n});\n```\n\n## Zoom Speed\n\nYou can adjust how fast it zooms, by passing optional `zoomSpeed` argument:\n\n``` js\npanzoom(element, {\n  zoomSpeed: 0.065 // 6.5% per mouse wheel event\n});\n```\n\n## Pinch Speed\n\nOn touch devices zoom is achieved by \"pinching\" and depends on distance between\ntwo fingers. We try to match the zoom speed with pinch, but if you find\nthat too slow (or fast), you can adjust it:\n\n``` js\npanzoom(element, {\n  pinchSpeed: 2 // zoom two times faster than the distance between fingers\n});\n```\n\n## Get current transform (scale, offset)\n\nTo get the current zoom (scale) level use the `getTransform()` method:\n\n```\nconsole.log(instance.getTransform()); // prints {scale: 1.2, x: 10, y: 10}\n```\n\n## Fixed transform origin when zooming\n\nBy default when you use mouse wheel or pinch to zoom, `panzoom` uses mouse\ncoordinates to determine the central point of the zooming operation.\n\nIf you want to override this behavior and always zoom into `center` of the\nscreen pass `transformOrigin` to the options:\n\n``` js\npanzoom(element, {\n  // now all zoom operations will happen based on the center of the screen\n  transformOrigin: {x: 0.5, y: 0.5}\n});\n```\n\nYou specify `transformOrigin` as a pair of `{x, y}` coordinates. Here are some examples:\n\n``` js\n// some of the possible values:\nlet topLeft = {x: 0, y: 0};\nlet topRight = {x: 1, y: 0};\nlet bottomLeft = {x: 0, y: 1};\nlet bottomRight = {x: 1, y: 1};\nlet centerCenter = {x: 0.5, y: 0.5};\n\n// now let's use it:\npanzoom(element, {\n  transformOrigin: centerCenter\n});\n```\n\nTo get or set new transform origin use the following API:\n\n``` js\nlet instance = panzoom(element, {\n  // now all zoom operations will happen based on the center of the screen\n  transformOrigin: {x: 0.5, y: 0.5}\n});\n\nlet origin = instance.getTransformOrigin(); // {x: 0.5, y: 0.5}\n\ninstance.setTransformOrigin({x: 0, y: 0}); // now it is topLeft\ninstance.setTransformOrigin(null); // remove transform origin\n```\n\n## Min Max Zoom\n\nYou can set min and max zoom, by passing optional `minZoom` and `maxZoom` argument:\n\n``` js\nvar instance = panzoom(element, {\n  maxZoom: 1,\n  minZoom: 0.1\n});\n```\n\nYou can later get the values using `getMinZoom()` and `getMaxZoom()`\n\n``` js\nassert(instance.getMaxZoom() === 1);\nassert(instance.getMinZoom() === 0.1);\n```\n\n## Disable Smooth Scroll\n\nYou can disable smooth scroll, by passing optional `smoothScroll` argument:\n\n``` js\npanzoom(element, {\n  smoothScroll: false\n});\n```\n\nWith this setting the momentum is disabled.\n\n## Pause/resume the panzoom\n\nYou can pause and resume the panzoom by calling the following methods:\n\n``` js\nvar element = document.getElementById('scene');\nvar instance = panzoom(element);\n\ninstance.isPaused(); //  returns false\ninstance.pause();    //  Pauses event handling\ninstance.isPaused(); //  returns true now\ninstance.resume();   //  Resume panzoom\ninstance.isPaused(); //  returns false again\n```\n\n## Script attachment\n\nIf you want to quickly play with panzoom without using javascript, you can configure it via\n`script` tag:\n\n``` html\n\u003c!-- this is your html file --\u003e\n\u003c!DOCTYPE html\u003e\n\u003chtml\u003e\n\u003chead\u003e\n  \u003cscript src='https://unpkg.com/panzoom@9.4.0/dist/panzoom.min.js'\n    query='#scene' name='pz'\u003e\u003c/script\u003e\n\u003c/head\u003e\n\u003cbody\u003e\n  \u003csvg\u003e\n    \u003c!-- this is the draggable root --\u003e\n    \u003cg id='scene'\u003e \n      \u003ccircle cx='10' cy='10' r='5' fill='pink'\u003e\u003c/circle\u003e\n    \u003c/g\u003e\n  \u003c/svg\u003e\n\u003c/body\u003e\n\u003c/html\u003e\n```\n\nMost importantly, you can see `query` attribute that points to CSS selector. Once the element is found \npanzoom is attached to this element. The controller will become available under `window.pz` name. And you\ncan pass additional options to the panzoom via attributes prefixed with `pz-`.\n\nHere is a demo: [Script based attributes](https://anvaka.github.io/panzoom/demo/attach-via-script.html)\n\n## Adjust Double Click Zoom\n\nYou can adjust the double click zoom multiplier, by passing optional `zoomDoubleClickSpeed` argument.\n\nWhen double clicking, zoom is multiplied by `zoomDoubleClickSpeed`, which means that a value of 1 will disable double click zoom completely. \n\n``` js\npanzoom(element, {\n  zoomDoubleClickSpeed: 1, \n});\n```\n\n## Set Initial Position And Zoom\n\nYou can set the initial position and zoom, by chaining the `zoomAbs` function with x position, y position and zoom as arguments:\n\n``` js\npanzoom(element, {\n  maxZoom: 1,\n  minZoom: 0.1,\n  initialX: 300,\n  initialY: 500,\n  initialZoom: 0.5\n});\n```\n\n## Handling touch events\n\nThe library will handle `ontouch` events very aggressively, it will `preventDefault`, and\n`stopPropagation` for the touch events inside container. [Sometimes](https://github.com/anvaka/panzoom/issues/12) this is not a desirable behavior.\n\nIf you want to take care about this yourself, you can pass `onTouch` callback to the options object:\n\n``` js\npanzoom(element, {\n  onTouch: function(e) {\n    // `e` - is current touch event.\n\n    return false; // tells the library to not preventDefault.\n  }\n});\n```\n\nNote: if you don't `preventDefault` yourself - make sure you test the page behavior on iOS devices.\nSometimes this may cause page to [bounce undesirably](https://stackoverflow.com/questions/23862204/disable-ios-safari-elastic-scrolling). \n\n\n## Handling double click events\n\nBy default panzoom will prevent default action on double click events - this is done to avoid\naccidental text selection (which is default browser action on double click). If you prefer to\nallow default action, you can pass `onDoubleClick()` callback to options. If this callback\nreturns false, then the library will not prevent default action:\n\n``` js\npanzoom(element, {\n  onDoubleClick: function(e) {\n    // `e` - is current double click event.\n\n    return false; // tells the library to not preventDefault, and not stop propagation\n  }\n});\n```\n\n## Bounds on Panzoom\n\nBy default panzoom will not prevent Image from Panning out of the Container. `bounds` (boolean) and \n`boundsPadding` (number)  can be defined so that it doesn't fall out. Default value for `boundsPadding` is `0.05` .\n \n\n``` js\npanzoom(element, {\n  bounds: true,\n  boundsPadding: 0.1\n});\n```\n\n## Triggering Pan \n\nTo Pan the object using Javascript use `moveTo(\u003cnumber\u003e,\u003cnumber\u003e)` function. It expects x, y value to where to move.\n\n``` js\ninstance.moveTo(0, 0);\n```\n\nTo pan in a smooth way use `smoothMoveTo(\u003cnumber\u003e,\u003cnumber\u003e)`:\n\n``` js\ninstance.smoothMoveTo(0, 0);\n```\n\n\n## Triggering Zoom\n\nTo Zoom the object using Javascript use `zoomTo(\u003cnumber\u003e,\u003cnumber\u003e,\u003cnumber\u003e)` function. It expects x, y value as coordinates of where to zoom. It also expects the zoom factor as the third argument. If zoom factor is greater than 1, apply zoom IN. If zoom factor is less than 1, apply zoom OUT.\n\n``` js\ninstance.zoomTo(0, 0, 2);\n```\n\nTo zoom in a smooth way use `smoothZoom(\u003cnumber\u003e,\u003cnumber\u003e,\u003cnumber\u003e)`:\n\n``` js\ninstance.smoothZoom(0, 0, 0.5);\n```\n\n## Custom UI to trigger zoom\n\nOne of the common use case is to have a custom UI to trigger zoom. For example, you can use a button to zoom in/out.\nSince this library does not depend on any popular framework (react, vue, etc.) you can implement it yourself\nfollowing this example:\n\n* [Live demo](https://anvaka.github.io/panzoom/demo/buttons.html)\n* [Source code of the demo](https://github.com/anvaka/panzoom/blob/3731bff2e15f2b4299405c2a59a24f30c3549a17/demo/buttons.html#L851)\n\n# license\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fanvaka%2Fpanzoom","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fanvaka%2Fpanzoom","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fanvaka%2Fpanzoom/lists"}