{"_id":"@alphanull/zoomer","name":"@alphanull/zoomer","dist-tags":{"latest":"1.0.0"},"versions":{"1.0.0":{"name":"@alphanull/zoomer","license":"MIT","version":"1.0.0","description":"Zoomer is a lightweight, dependency-free, physics-based pan/zoom/rotate library for the browser designed to feel like native iOS interaction.","keywords":["javascript","typescript","zoom","pan","rotate","pinch","gesture","physics","inertia","rubber-banding","ui"],"author":{"name":"Frank Kudermann","email":"kudermann@alphanull.de","url":"https://alphanull.de"},"repository":{"type":"git","url":"git+https://github.com/alphanull/Zoomer.git"},"homepage":"https://github.com/alphanull/Zoomer#readme","bugs":{"url":"https://github.com/alphanull/Zoomer/issues"},"type":"module","main":"./dist/Zoomer.min.cjs","module":"./dist/Zoomer.min.js","types":"./dist/Zoomer.d.ts","exports":{"import":{"types":"./dist/Zoomer.d.ts","default":"./dist/Zoomer.min.js"},"require":{"types":"./dist/Zoomer.d.ts","default":"./dist/Zoomer.min.cjs"}},"publishConfig":{"access":"public"},"sideEffects":false,"engines":{"node":">=16.0.0"},"devDependencies":{"@eslint/js":"^9.39.2","@rollup/plugin-node-resolve":"^16.0.3","@rollup/plugin-terser":"^0.4.4","@stylistic/eslint-plugin":"^5.6.1","@vitest/coverage-v8":"^4.0.16","eslint":"^9.39.2","eslint-plugin-jsdoc":"^61.5.0","globals":"^16.5.0","jsdoc":"^4.0.5","jsdoc-to-markdown":"^9.1.3","jsdom":"^27.4.0","rollup":"^4.54.0","rollup-plugin-delete":"^3.0.2","typescript":"^5.9.3","vitest":"^4.0.16"},"scripts":{"doc":"jsdoc2md --private --separators --template ./scripts/docTemplate.hbs --files ./src/*.js > ./docs/Zoomer.md","lint":"echo 'Running ESLint...' && eslint src/ test/ --max-warnings=0","test":"tsc --noEmit && vitest run --config scripts/vitest.config.js","test:watch":"vitest --config scripts/vitest.config.js","test:coverage":"vitest run --config scripts/vitest.config.js --coverage","build":"npm run lint && npm run test && rollup -c ./scripts/rollup.config.js && cp src/Zoomer.d.ts dist/","demo":"npx serve . -p 3000"},"gitHead":"17e712f35131e4cebd73fa037ec9f0f400d4af67","_id":"@alphanull/zoomer@1.0.0","_nodeVersion":"22.13.1","_npmVersion":"11.7.0","dist":{"integrity":"sha512-sE2xdJQdZ0GzWm26siXFGi1IJ8A5nqoaXx5EFvPK5Vwz94LDSeBpFdJ9l3PfVlqvkbSiQ2qika3R2hefgjNJdA==","shasum":"c3bf4bd3a3b7f0eed13b663f9b6261e6e427564b","tarball":"https://registry.npmjs.org/@alphanull/zoomer/-/zoomer-1.0.0.tgz","fileCount":7,"unpackedSize":83389,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIBclEaPXHr7DUvbsj4VUZHT18iN2LbQ46zjf1qKy16RHAiBeK+s/zGWxd/CQZO6OYVlMoDP1Ek1N0JZXDpOumTFDlg=="}]},"_npmUser":{"name":"alphanull","email":"kudermann@alphanull.de"},"directories":{},"maintainers":[{"name":"alphanull","email":"kudermann@alphanull.de"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/zoomer_1.0.0_1766878150786_0.13820496615345013"},"_hasShrinkwrap":false}},"time":{"created":"2025-12-27T23:29:10.685Z","1.0.0":"2025-12-27T23:29:10.937Z","modified":"2025-12-27T23:29:11.264Z"},"maintainers":[{"name":"alphanull","email":"kudermann@alphanull.de"}],"description":"Zoomer is a lightweight, dependency-free, physics-based pan/zoom/rotate library for the browser designed to feel like native iOS interaction.","homepage":"https://github.com/alphanull/Zoomer#readme","keywords":["javascript","typescript","zoom","pan","rotate","pinch","gesture","physics","inertia","rubber-banding","ui"],"repository":{"type":"git","url":"git+https://github.com/alphanull/Zoomer.git"},"author":{"name":"Frank Kudermann","email":"kudermann@alphanull.de","url":"https://alphanull.de"},"bugs":{"url":"https://github.com/alphanull/Zoomer/issues"},"license":"MIT","readme":"![License](https://img.shields.io/github/license/alphanull/zoomer)\n![Version](https://img.shields.io/npm/v/@alphanull/zoomer)\n[![JSDoc](https://img.shields.io/badge/docs-JSDoc-blue)](./docs/Zoomer.md)\n![npm package minimized gzipped size](https://img.shields.io/bundlejs/size/@alphanull/zoomer)\n\n# Zoomer\n\n**Zoomer** is a lightweight, dependency-free physics engine for ultra-smooth pan, zoom, and rotate interactions in the browser. Designed to bring a polished, iOS-like tactile feel to any web element, it features natural inertia, elastic boundaries (rubber-banding), and precision pivot tracking.\n\n## Why Zoomer?\n\nMost pan-and-zoom libraries feel mechanical. Zoomer is built with a custom physics engine to make interactions feel **alive** and **organic**. Whether you're building an image gallery, a map viewer, or a complex workspace, Zoomer provides the high-end haptics users expect from modern touch interfaces.\n\n## Demo\n\nTo see Zoomer in action, hop over to: [https://alphanull.github.io/Zoomer/](https://alphanull.github.io/Zoomer/)\n\n## Features\n\n- **Direct Manipulation**: Naturally pan, zoom, and rotate using multi-touch gestures or mouse, including mousewheel support.\n- **iOS-style Physics**: Built-in inertia, friction, and elastic rubber-band resistance at boundaries.\n- **Precision Pivot Tracking**: Zooming and rotating always happen around the center of the gesture, keeping your focus point stable.\n- **Mousewheel Precision**: Smooth, cursor-centered zooming with automatic pivot adjustment.\n- **Intelligent Fitting**: Built-in `contain` and `cover` strategies to perfectly align elements within their containers, with optional `autoMinScale` to prevent zooming below the fit scale.\n- **SVG Lossless Zoom Support**: Crisp, pixel-perfect SVG rendering at any zoom level. Automatically optimized for inline SVG, `<img>` SVG, and CSS background SVG. No pixelation, even at extreme zoom levels.\n- **Smart GPU Acceleration**: Selective GPU layer creation - `will-change` is only set during active interaction, saving resources when idle. Perfect for complex SVGs on mobile devices.\n- **High Performance**: Optimized with a layout cache and `ResizeObserver` to eliminate layout thrashing. Zero CPU usage when idle.\n- **Highly Customizable**: Fine-tune every aspect with 20+ options - from physics parameters (friction, stiffness, elasticity) to interaction modes (pan axes, touch behavior) and lifecycle callbacks.\n- **Zero Dependencies**: Pure Vanilla JS, lightweight, and ready to drop into any project.\n\n## Installation\n\n### via NPM\n\n```bash\nnpm install @alphanull/zoomer\n```\n\n### via CDN\n\n[Download latest version](https://cdn.jsdelivr.net/npm/@alphanull/zoomer@1/dist/Zoomer.min.js) from jsDelivr\n[Download latest version](https://unpkg.com/@alphanull/zoomer@1/dist/Zoomer.min.js) from unpkg\n\n## Initialization\n\nZoomer can be used as ES6 module (recommended) but also via `require` in NodeJS or with direct access to a global variable:\n\n### ES6\n\n```javascript\nimport Zoomer from '@alphanull/zoomer';\n```\n\n### CommonJS\n\n```javascript\nconst Zoomer = require('@alphanull/zoomer');\n```\n\n### Global Variable\n\n```html\n<script src=\"path/to/Zoomer.min.cjs\"></script>\n```\n\n```javascript\nconst Zoomer = window.Zoomer;\n```\n\n## Usage\n\n```javascript\nconst element = document.querySelector('.my-element');\nconst container = document.querySelector('.container'); // container defines boundaries\n\nconst zoomer = new Zoomer(element, {\n  container: container,\n  fitContainer: 'contain',\n  boundsEnabled: true,\n  minScale: 1,\n  maxScale: 4\n});\n\nzoomer.applyTransform({ x: 0, y: 0, scale: 2, rotation: 45 });\n```\n\n## Configuration Options\n\n| Option               | Default    | Description                                                               |\n|----------------------|------------|---------------------------------------------------------------------------|\n| `initialX`           | `0`        | Initial horizontal translation.                                           |\n| `initialY`           | `0`        | Initial vertical translation.                                             |\n| `initialScale`       | `1`        | Initial scale factor.                                                     |\n| `initialRotation`    | `0`        | Initial rotation in degrees.                                              |\n| `minScale`           | `0.5`      | Minimum allowed scale factor.                                             |\n| `maxScale`           | `2`        | Maximum allowed scale factor.                                             |\n| `friction`           | `0.1`      | Friction factor (0 to 1). Higher values stop faster.                      |\n| `springStiffness`    | `0.2`      | Strength of the bounce-back effect.                                       |\n| `resistance`         | `0.8`      | Resistance at boundaries (0 to 1). 1 = hard limit.                        |\n| `maxElasticity`      | `100`      | Max pixels the element can stretch beyond limits.                         |\n| `physicsEnabled`     | `true`     | Enable/disable inertia and spring-back.                                   |\n| `panEnabled`         | `'on'`     | Panning mode: `'on'`, `'off'`, `'xAxis'`, or `'yAxis'`.                   |\n| `panMultiTouchOnly`  | `false`    | If `true`, panning with single touch is disabled (allows normal scrolling on touch devices). |\n| `zoomEnabled`        | `true`     | Enable/disable zooming (touch & wheel).                                   |\n| `rotationEnabled`    | `true`     | Enable/disable rotation (touch).                                          |\n| `keyboardEnabled`    | `true`     | Enable/disable keyboard controls (arrows, +/-).                           |\n| `doubleTapEnabled`   | `true`     | Enable/disable double tap to toggle zoom.                                 |\n| `wheelModifier`      | `'none'`   | Modifier key for wheel zoom: `'none'`, `'alt'`, `'control'`, or `'meta'`. |\n| `wheelRotationModifier` | `'alt'` | Modifier key for wheel rotation: `'none'`, `'alt'`, `'control'`, `'meta'`, or `'shift'`. |\n| `container`          | `null`     | DOM element used for boundaries and initial fitting.                      |\n| `boundsEnabled`      | `false`    | If `true`, the element will be contained within the `container`.          |\n| `fitContainer`       | `'none'`   | Initial scaling strategy: `'none'`, `'cover'`, or `'contain'`. |\n| `autoMinScale`       | `false`    | If `true`, prevents zooming below `fitScale` when `fitContainer` is set. |\n| `onRender`           | `null`     | Custom render function: `(state, element) => void`.                       |\n| `onUpdate`           | `null`     | Callback for state updates: `(state) => void`.                            |\n| `onInteractionStart` | `null`     | Triggered when user starts interaction.                                   |\n| `onInteractionEnd`   | `null`     | Triggered when user stops interaction.                                    |\n\n## Public API\n\n| Method           | Arguments                               | Description                                                     |\n|------------------|-----------------------------------------|-----------------------------------------------------------------|\n| `reset`          | `immediate: boolean`                    | Resets the element to its initial state.                        |\n| `applyTransform` | `transform: object, immediate: boolean` | Programmatically sets X, Y, Scale, and/or Rotation.             |\n| `updateLayout`   | `applyFit: boolean`                     | Re-calculates layout. Set `true` to re-apply container fitting. |\n| `destroy`        | -                                       | Removes all listeners and stops the update loop.                |\n\n### Arguments\n\n- **`immediate`** (boolean): If `true`, the element jumps to the new state instantly. If `false` (default), the transition is handled by the physics engine for a smooth \"homing\" effect.\n- **`transform`** (object): A partial state object. You only need to provide the properties you want to change:\n  - `x` (number): Target horizontal translation.\n  - `y` (number): Target vertical translation.\n  - `scale` (number): Target scale factor.\n  - `rotation` (number): Target rotation in degrees.\n\n### Zoomer State\n\nThe `state` object (accessible via `zoomer.state` or in callbacks) contains the current transformation and velocity:\n\n| Property       | Type      | Description                                              |\n|----------------|-----------|----------------------------------------------------------|\n| `x`            | `number`  | Current horizontal translation in pixels.                |\n| `y`            | `number`  | Current vertical translation in pixels.                  |\n| `scale`       | `number`  | Current scale factor.                                    |\n| `rotation`    | `number`  | Current rotation in degrees.                             |\n| `pivotX`      | `number`  | Last zoom/rotation pivot X (local coordinates).          |\n| `pivotY`      | `number`  | Last zoom/rotation pivot Y (local coordinates).          |\n| `vx`           | `number`  | Current velocity on the X axis.                          |\n| `vy`           | `number`  | Current velocity on the Y axis.                          |\n| `vs`           | `number`  | Current scale velocity.                                  |\n| `vr`           | `number`  | Current rotation velocity in degrees/frame.              |\n| `isInteracting` | `boolean` | Whether a user interaction is currently in progress.    |\n\n## Development\n\n```bash\n# Install dependencies\nnpm install\n# Build the minified library\nnpm run build\n# Run tests\nnpm run test\n# Generate docs\nnpm run doc\n# Run the demo\nnpm run demo\n```\n\n## Docs\n\nFor more detailed docs, see [JSDoc Documentation](docs/Zoomer.md)\n\n## Browser Support\n\nZoomer supports all major browsers on all platforms (i.e. macOS, iOS, Windows, Android & Linux) released since ~2019-2020 and later, including Chrome (v79+), Firefox (v75+) and Safari (v13+).\n\n### SVG Rendering\n\nZoomer includes optimizations for crisp SVG rendering at high zoom levels:\n\n- **Chrome/Safari**: Perfect sharp rendering for all SVG types (inline SVG, `<img>` SVG, CSS background SVG)\n- **Firefox**:\n  - ✅ **Inline SVG**: Sharp rendering (best quality)\n  - ⚠️ **`<img>` SVG**: Improved but may show blur at high zoom\n  - ⚠️ **CSS background SVG**: Improved but may show stronger blur at high zoom\n\nFor the best rendering quality across all browsers, **inline SVG is recommended**. The library automatically detects SVG elements and applies appropriate rendering optimizations.\n\n## License\n\n[MIT](https://opensource.org/license/MIT)\n\nCopyright © 2025-present Frank Kudermann @ alphanull.de\n","readmeFilename":"README.md","_rev":"1-9e794bf6398a65332dd9c871f440225e"}