{"id":49416473,"url":"https://github.com/piliugin-anton/panandzoom","last_synced_at":"2026-04-29T03:10:45.976Z","repository":{"id":57318445,"uuid":"122817848","full_name":"piliugin-anton/PanAndZoom","owner":"piliugin-anton","description":"Low-level interface for calculating pan and zoom transformations.","archived":false,"fork":false,"pushed_at":"2022-09-14T04:29:27.000Z","size":335,"stargazers_count":1,"open_issues_count":0,"forks_count":2,"subscribers_count":0,"default_branch":"master","last_synced_at":"2025-09-22T18:51:16.573Z","etag":null,"topics":["math","matrix","pan","transformation-matrix","zoom"],"latest_commit_sha":null,"homepage":"https://npmjs.com/package/pan-and-zoom","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"isc","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/piliugin-anton.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-02-25T08:18:47.000Z","updated_at":"2024-02-06T12:56:54.000Z","dependencies_parsed_at":"2023-01-18T07:00:48.526Z","dependency_job_id":null,"html_url":"https://github.com/piliugin-anton/PanAndZoom","commit_stats":null,"previous_names":["alhadis/panandzoom"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/piliugin-anton/PanAndZoom","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/piliugin-anton%2FPanAndZoom","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/piliugin-anton%2FPanAndZoom/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/piliugin-anton%2FPanAndZoom/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/piliugin-anton%2FPanAndZoom/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/piliugin-anton","download_url":"https://codeload.github.com/piliugin-anton/PanAndZoom/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/piliugin-anton%2FPanAndZoom/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32408549,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-29T02:37:21.628Z","status":"ssl_error","status_checked_at":"2026-04-29T02:36:50.947Z","response_time":110,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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":["math","matrix","pan","transformation-matrix","zoom"],"created_at":"2026-04-29T03:10:45.181Z","updated_at":"2026-04-29T03:10:45.970Z","avatar_url":"https://github.com/piliugin-anton.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"Pan and Zoom\n============\n\nLow-level interface for calculating pan and zoom transformations.\nIdeal for CSS and HTML5 `\u003ccanvas\u003e` transforms, or anywhere where\nlow overhead resize effects are needed.\n\nNote this component won't make elements interactive for you. You\nmust configure this behaviour yourself (using your UI library of\nchoice). It does, however, simplify the task of calculating zoom\nand pan effects in an efficient, object-oriented manner. Because\nthe component is environment agnostic, it can be used anywhere a\nJavaScript module can be loaded.\n\n\nUsage\n-----\n\n~~~shell\nnpm install --save pan-and-zoom\n~~~\n\nIn your project's JavaScript:\n\n~~~js\nimport { PanAndZoom } from \"pan-and-zoom\";\n\nconst paz = new PanAndZoom({\n\n\t// Callback fired after changing a `PanAndZoom' object's properties\n\tupdate(){\n\t\tconst el = document.getElementById(\"some-huge-thing\");\n\t\tel.style.transform = paz; // Calls paz.toString() implicitly\n\n\t\t// Or for canvas:\n\t\tconst canvas = document.getElementById(\"canvas\");\n\t\tconst canvasRenderContext2D = canvas.getContext(\"2d\");\n\t\tcanvasRenderContext2D.setTransform(...paz);\n\t},\n});\n\npaz.zoom = 1.5; // +150% scale\npaz.panX = 300; // Move horizontally 300 units\n~~~\n\nOr in Node.js:\n\n~~~js\nconst { PanAndZoom } = require(\"pan-and-zoom\");\n\nconst paz = new PanAndZoom({\n\tupdate(){\n\t\tconsole.log(`CSS transform: ${paz}`);\n\t\tconsole.log('Canvas transformation matrix:', ...paz);\n\t},\n});\n\npaz.zoom = 1.5; // +150% scale\npaz.panX = 300; // Move horizontally 300 units\n~~~\n\n\nProperties\n----------\nChanging any one of these properties causes a call to `update()` to be queued,\nwhich is fired asynchronously. This allows multiple properties to be changed\nwith only one invocation fired, reducing overhead and potentially expensive\nDOM transactions.\n\n\u003c!-- TODO: Use a real documentation language instead of Markdown --\u003e\n\n### Panning\n\n#### `pan`\n**Default:**         `[0, 0]`  \n**Type:**            [`Array`][]  \n**Fires callbacks:** [`updatePan`][], [`update`][]\n\nAn array containing the values of [`panX`][] and [`panY`][].\n\n\n#### `panX`\n**Default:**         `0`  \n**Type:**            [`Number`][]  \n**Fires callbacks:** [`updatePan`][], [`update`][]\n\nHorizontal pan offset.\n\n\n#### `panY`\n**Default:**         `0`  \n**Type:**            [`Number`][]  \n**Fires callbacks:** [`updatePan`][], [`update`][]\n\nVertical pan offset.\n\n\n#### `minPanX`\n**Default:**         [`Number.NEGATIVE_INFINITY`][]  \n**Type:**            [`Number`][]\n\nMinimum possible [`panX`][] value.\n\n\n#### `minPanY`\n**Default:**         [`Number.NEGATIVE_INFINITY`][]  \n**Type:**            [`Number`][]\n\nMinimum possible [`panY`][] value.\n\n\n#### `maxPanX`\n**Default:**         [`Number.POSITIVE_INFINITY`][]  \n**Type:**            [`Number`][]\n\nMaximum possible [`panX`][] value.\n\n\n#### `maxPanY`\n**Default:**         [`Number.POSITIVE_INFINITY`][]  \n**Type:**            [`Number`][]\n\nMaximum possible [`panY`][] value.\n\n\n### Transform origin\n\n#### `origin`\n**Default:**         `[0, 0]`  \n**Type:**            [`Array`][]  \n**Fires callbacks:** [`updateOrigin`][], [`update`][]\n\nAn array containing the values of [`originX`][] and [`originY`][].\n\n\n#### `originX`\n**Default:**         `0`  \n**Type:**            [`Number`][]  \n**Fires callbacks:** [`updateOrigin`][], [`update`][]\n\nHorizontal ordinate of transformation centre.\n\n\n#### `originY`\n**Default:**         `0`  \n**Type:**            [`Number`][]  \n**Fires callbacks:** [`updateOrigin`][], [`update`][]\n\nVertical ordinate of transformation centre.\n\n\n#### `minOriginX`\n**Default:**        [`Number.NEGATIVE_INFINITY`][]  \n**Type:**           [`Number`][]\n\nMinimum possible [`originX`][] value.\n\n\n#### `minOriginY`\n**Default:**        [`Number.NEGATIVE_INFINITY`][]  \n**Type:**           [`Number`][]\n\nMinimum possible [`originY`][] value.\n\n\n#### `maxOriginX`\n**Default:**        [`Number.POSITIVE_INFINITY`][]  \n**Type:**           [`Number`][]\n\nMaximum possible [`originX`][] value.\n\n\n#### `maxOriginY`\n**Default:**        [`Number.POSITIVE_INFINITY`][]  \n**Type:**           [`Number`][]\n\nMaximum possible [`originY`][] value.\n\n\n### Zooming\n\n#### `zoom`\n**Default:**         `1.0`  \n**Type:**            [`Number`][]  \n**Fires callbacks:** [`updateZoom`][], [`update`][]\n\nMagnification amount, expressed as a positive multiplier.\n\n\n#### `minZoom`\n**Default:**         `0`  \n**Type:**            [`Number`][]\n\nMinimum possible [`zoom`][] value.\n\n\n#### `maxZoom`\n**Default:**         [`Number.POSITIVE_INFINITY`][]  \n**Type:**            [`Number`][]\n\nMaximum possible [`zoom`][] value.\n\n\n### Callbacks\n\n#### `update`\n**Default:**         `() =\u003e {}` (noop)  \n**Type:**            [`Function`][]  \n**Arguments:**       None\n\nCallback to trigger each time a property is modified.\n\n\n#### `updateOrigin`\n**Default:**         `() =\u003e {}` (noop)  \n**Type:**            [`Function`][]  \n**Arguments:**       `[fromX, fromY]`, `[toX, toY]`\n\nCallback to trigger each time [`originX`][] or [`originY`][] are modified.\n\n\n#### `updatePan`\n**Default:**         `() =\u003e {}` (noop)  \n**Type:**            [`Function`][]  \n**Arguments:**       `[fromX, fromY]`, `[toX, toY]`\n\nCallback to trigger each time [`panX`][] or [`panY`][] are modified.\n\n\n#### `updateZoom`\n**Default:**         `() =\u003e {}` (noop)  \n**Type:**            [`Function`][]  \n**Arguments:**       `from`, `to`\n\nCallback to trigger each time [`zoom`][] is modified.\n\n\n#### `updateDelay`\n**Default:**         `0`  \n**Type:**            [`Number`][]\n\nMilliseconds to delay callbacks by whenever properties change.\nUsed by the class's [`debounce`][] method when throttling callback functions.\n\n\n#### `updateEarly`\n**Default:**        `true`  \n**Type:**           [`Boolean`][]\n\nWhether to fire callbacks before or after waiting for [`updateDelay`][]\nmilliseconds to elapse. This property only makes sense when `updateDelay`\nis assigned a value greater than zero, and when multiple successive updates\nare expected (such as during a click-and-drag operation).\n\n\n### Misc\n\n#### `transform`\n**Type:** [`Array`][]  \n**Read-only**\n\nA 3x3 affine transform matrix composed from the current values of the\ninstance's [`pan`][] and [`zoom`][] properties.\n\n\n\n\nMethods\n-------\nThe majority of methods described below are used internally, but exposed for\ngeneral-purpose usage.\n\n\n### Constructor\nInitialise a new pan/zoom controller.\n\n*\t`args` **(Optional)**  \n\tInitial property values, which may be any of the items\n\tdescribed under [Properties](#properties).\n\n\n\u003ca name=\"applytransform\"\u003e\u003c/a\u003e\n### `applyTransform(points)`\nApply the current transformation matrix to an array of points:\n\n*\t`points`  \n\tAn array of points, each expressed as a pair of [`Number`][] values.\n\nReturns a new array of points with modified values.\n\n__Example:__\n~~~js\npaz.zoom = 2.0; // 200% scale\npaz.applyTransform([\n\t[0,   0],\n\t[100, 0],   // Coordinates representing\n\t[100, 100], // a 100px-sized square.\n\t[0,   100],\n]) == [\n\t[0,   0],\n\t[200, 0],   // Returns new coordinates for\n\t[200, 200], // a 200px-sized square.\n\t[0,   200],\n];\n~~~\n\n\n\u003ca name=\"mergematrices\"\u003e\u003c/a\u003e\n### `mergeMatrices(...matrices)`\nConcatenate two or more affine transformation matrices.\n\n*\t`...matrices`  \n\tTwo or more 3x3-sized matrices (each expressed as an\n\tarray of nine [`Number`][] values).\n\nReturns the concatenation of the given matrices as a new array.\n\n__Example:__\n~~~js\npaz.mergeMatrices(\n\t[1, 0, 100, // Pan X: 100\n\t 0, 1, 400, // Pan Y: 400\n\t 0, 0, 1],\n\t\n\t[2, 0, 0,   // 200% scale\n\t 0, 2, 0,\n\t 0, 0, 1],\n) == [\n\t2, 0, 100,\n\t0, 2, 400,\n\t0, 0, 1,\n];\n~~~\n\n\u003ca name=\"debounce\"\u003e\u003c/a\u003e\n### `debounce(fn)`\nStop a callback function from firing too quickly.\n\n*\t`fn`  \n\tA function with which to throttle, using the instance's\n\t[`updateDelay`][] and [`updateEarly`][] properties.\n\nReturns a throttled version of the supplied function.\n\n\n[Referenced links]:_____________________________________________\n[`transform`]:    #transform\n[`pan`]:          #pan\n[`panX`]:         #panx\n[`panY`]:         #pany\n[`minPanX`]:      #minpanx\n[`minPanY`]:      #minpany\n[`maxPanX`]:      #maxpanx\n[`maxPanY`]:      #maxpany\n[`origin`]:       #origin\n[`originX`]:      #originx\n[`originY`]:      #originy\n[`minOriginX`]:   #minoriginx\n[`minOriginY`]:   #minoriginy\n[`maxOriginX`]:   #maxoriginx\n[`maxOriginY`]:   #maxoriginy\n[`zoom`]:         #zoom\n[`minZoom`]:      #minzoom\n[`maxZoom`]:      #maxzoom\n[`update`]:       #update\n[`updateOrigin`]: #updateorigin\n[`updatePan`]:    #updatepan\n[`updateZoom`]:   #updatezoom\n[`updateDelay`]:  #updatedelay\n[`updateEarly`]:  #updateearly\n[`debounce`]:     #debounce\n\n[`Array`]:        http://mdn.io/Array\n[`Boolean`]:      http://mdn.io/Boolean\n[`Function`]:     http://mdn.io/Function\n[`Number`]:       http://mdn.io/Number\n[`Number.NEGATIVE_INFINITY`]: http://mdn.io/Number.NEGATIVE_INFINITY\n[`Number.POSITIVE_INFINITY`]: http://mdn.io/Number.POSITIVE_INFINITY\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpiliugin-anton%2Fpanandzoom","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpiliugin-anton%2Fpanandzoom","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpiliugin-anton%2Fpanandzoom/lists"}