@zoompinch/elements 0.0.15 → 0.0.18

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,364 @@
1
+ # @zoompinch/elements
2
+
3
+ Web Components (Custom Elements) for [@zoompinch/core](https://github.com/ElyaConrad/zoompinch) - Apply a pinch-and-zoom experience that’s feels native and communicates the transform reactively and lets you project any layer on top of the transformed canvas.
4
+
5
+ **Play with the demo:** [https://zoompinch.pages.dev](https://zoompinch.pages.dev)
6
+
7
+ ![Mobile demo](https://zoompinch.pages.dev/zoompinch_demo.gif)
8
+
9
+ ### Mathematical correct pinch on touch
10
+
11
+ Unlike other libraries, _Zoompinch_ does not just uses the center point between two fingers as projection center. The fingers get correctly projected on the virtual canvas. This makes pinching on touch devices feel native-like.
12
+
13
+ ### Touch, Wheelm, Mouse and Trackpad Gestures!
14
+
15
+ Adside of touch, mouse and wheel events, **gesture events** (Safari Desktop) are supported as well! Try it out on the [demo](https://zoompinch.pages.dev)
16
+
17
+ ## Installation
18
+
19
+ ```bash
20
+ npm install @zoompinch/elements
21
+ ```
22
+
23
+ ## Complete Example
24
+
25
+ ```html
26
+ <!DOCTYPE html>
27
+ <html>
28
+ <head>
29
+ <script type="module">
30
+ import '@zoompinch/elements';
31
+ </script>
32
+ <style>
33
+ zoom-pinch {
34
+ display: block;
35
+ width: 800px;
36
+ height: 600px;
37
+ border: 1px solid #ddd;
38
+ }
39
+ </style>
40
+ </head>
41
+ <body>
42
+ <zoom-pinch
43
+ id="zoomPinch"
44
+ translate-x="0"
45
+ translate-y="0"
46
+ scale="1"
47
+ rotate="0"
48
+ min-scale="0.5"
49
+ max-scale="4"
50
+ offset-top="0"
51
+ offset-right="0"
52
+ offset-bottom="0"
53
+ offset-left="0"
54
+ clamp-bounds="false"
55
+ rotation="true"
56
+ >
57
+ <img width="1536" height="2048" src="https://imagedelivery.net/mudX-CmAqIANL8bxoNCToA/489df5b2-38ce-46e7-32e0-d50170e8d800/public" />
58
+
59
+ <svg slot="matrix" width="100%" height="100%">
60
+ <!-- Matrix overlay content -->
61
+ <circle id="centerMarker" r="8" fill="red" />
62
+ </svg>
63
+ </zoom-pinch>
64
+
65
+ <script type="module">
66
+ const zoomPinch = document.getElementById('zoomPinch');
67
+
68
+ // Listen for updates
69
+ zoomPinch.addEventListener('update', () => {
70
+ console.log('Transform:', {
71
+ translateX: zoomPinch.getAttribute('translate-x'),
72
+ translateY: zoomPinch.getAttribute('translate-y'),
73
+ scale: zoomPinch.getAttribute('scale'),
74
+ rotate: zoomPinch.getAttribute('rotate')
75
+ });
76
+
77
+ // Update matrix overlay
78
+ updateMatrix();
79
+ });
80
+
81
+ // Center on load
82
+ zoomPinch.addEventListener('init', () => {
83
+ zoomPinch.applyTransform(1, [0.5, 0.5], [0.5, 0.5]);
84
+ });
85
+
86
+ // Handle clicks
87
+ zoomPinch.addEventListener('click', (e) => {
88
+ const [x, y] = zoomPinch.normalizeClientCoords(e.clientX, e.clientY);
89
+ console.log('Canvas position:', x, y);
90
+ });
91
+
92
+ function updateMatrix() {
93
+ const centerMarker = document.getElementById('centerMarker');
94
+ const [cx, cy] = zoomPinch.composePoint(
95
+ zoomPinch.canvasWidth / 2,
96
+ zoomPinch.canvasHeight / 2
97
+ );
98
+ centerMarker.setAttribute('cx', cx);
99
+ centerMarker.setAttribute('cy', cy);
100
+ }
101
+ </script>
102
+ </body>
103
+ </html>
104
+ ```
105
+
106
+ ## API Reference
107
+
108
+ ### Attributes
109
+
110
+ | Attribute | Type | Default | Description |
111
+ |-----------|------|---------|-------------|
112
+ | `translate-x` | `number` | `0` | X translation in pixels |
113
+ | `translate-y` | `number` | `0` | Y translation in pixels |
114
+ | `scale` | `number` | `1` | Current scale factor |
115
+ | `rotate` | `number` | `0` | Rotation in radians |
116
+ | `min-scale` | `number` | `0.1` | Minimum scale (user gestures only) |
117
+ | `max-scale` | `number` | `10` | Maximum scale (user gestures only) |
118
+ | `offset-top` | `number` | `100` | Top padding in pixels |
119
+ | `offset-right` | `number` | `0` | Right padding in pixels |
120
+ | `offset-bottom` | `number` | `0` | Bottom padding in pixels |
121
+ | `offset-left` | `number` | `0` | Left padding in pixels |
122
+ | `clamp-bounds` | `"true"` \| `"false"` | `"false"` | Clamp panning within bounds (user gestures only) |
123
+ | `rotation` | `"true"` \| `"false"` | `"true"` | Enable rotation gestures |
124
+
125
+ **Note:** `min-scale`, `max-scale`, `rotation`, and `clamp-bounds` only apply during user interaction. Programmatic changes via methods are unrestricted.
126
+
127
+ ### Events
128
+
129
+ | Event | Description |
130
+ |-------|-------------|
131
+ | `update` | Fired when transform changes (attributes are updated) |
132
+ | `init` | Fired when the engine is ready |
133
+
134
+ ```javascript
135
+ zoomPinch.addEventListener('update', () => {
136
+ const translateX = zoomPinch.getAttribute('translate-x');
137
+ const translateY = zoomPinch.getAttribute('translate-y');
138
+ const scale = zoomPinch.getAttribute('scale');
139
+ const rotate = zoomPinch.getAttribute('rotate');
140
+ });
141
+ ```
142
+
143
+ ### Methods
144
+
145
+ Access methods directly on the element:
146
+
147
+ ```javascript
148
+ const zoomPinch = document.querySelector('zoom-pinch');
149
+
150
+ // Call methods
151
+ zoomPinch.applyTransform(scale, wrapperCoords, canvasCoords);
152
+ zoomPinch.normalizeClientCoords(clientX, clientY);
153
+ zoomPinch.composePoint(x, y);
154
+
155
+ // Access properties
156
+ zoomPinch.canvasWidth;
157
+ zoomPinch.canvasHeight;
158
+ ```
159
+
160
+ #### `applyTransform(scale, wrapperCoords, canvasCoords)`
161
+
162
+ Apply transform by anchoring a canvas point to a wrapper point.
163
+
164
+ **Parameters:**
165
+ - `scale: number` - Target scale
166
+ - `wrapperCoords: [number, number]` - Wrapper position (0-1, 0.5 = center)
167
+ - `canvasCoords: [number, number]` - Canvas position (0-1, 0.5 = center)
168
+
169
+ **Examples:**
170
+
171
+ ```javascript
172
+ // Center canvas at scale 1
173
+ zoomPinch.applyTransform(1, [0.5, 0.5], [0.5, 0.5]);
174
+
175
+ // Zoom to 2x, keep centered
176
+ zoomPinch.applyTransform(2, [0.5, 0.5], [0.5, 0.5]);
177
+
178
+ // Anchor canvas top-left to wrapper center
179
+ zoomPinch.applyTransform(1.5, [0.5, 0.5], [0, 0]);
180
+ ```
181
+
182
+ #### `normalizeClientCoords(clientX, clientY)`
183
+
184
+ Convert global client coordinates to canvas coordinates.
185
+
186
+ **Parameters:**
187
+ - `clientX: number` - Global X from event
188
+ - `clientY: number` - Global Y from event
189
+
190
+ **Returns:** `[number, number]` - Canvas coordinates in pixels
191
+
192
+ **Example:**
193
+
194
+ ```javascript
195
+ zoomPinch.addEventListener('click', (e) => {
196
+ const [x, y] = zoomPinch.normalizeClientCoords(e.clientX, e.clientY);
197
+ console.log('Canvas position:', x, y);
198
+ });
199
+ ```
200
+
201
+ #### `composePoint(x, y)`
202
+
203
+ Convert canvas coordinates to wrapper coordinates (accounts for transform).
204
+
205
+ **Parameters:**
206
+ - `x: number` - Canvas X in pixels
207
+ - `y: number` - Canvas Y in pixels
208
+
209
+ **Returns:** `[number, number]` - Wrapper coordinates in pixels
210
+
211
+ **Example:**
212
+
213
+ ```javascript
214
+ // Get wrapper position for canvas center
215
+ const [wrapperX, wrapperY] = zoomPinch.composePoint(
216
+ zoomPinch.canvasWidth / 2,
217
+ zoomPinch.canvasHeight / 2
218
+ );
219
+ ```
220
+
221
+ ### Properties
222
+
223
+ Access current canvas dimensions:
224
+
225
+ ```javascript
226
+ const width = zoomPinch.canvasWidth; // number
227
+ const height = zoomPinch.canvasHeight; // number
228
+ ```
229
+
230
+ ### Matrix Slot
231
+
232
+ Use `slot="matrix"` for overlay elements that follow the canvas transform.
233
+
234
+ **Note:** Matrix elements must be updated manually on the `update` event.
235
+
236
+ **Example:**
237
+
238
+ ```html
239
+ <zoom-pinch id="zoomPinch">
240
+ <img width="1920" height="1080" src="image.jpg" />
241
+
242
+ <svg slot="matrix" width="100%" height="100%">
243
+ <circle id="marker" r="8" fill="red" />
244
+ </svg>
245
+ </zoom-pinch>
246
+
247
+ <script>
248
+ const viewer = document.getElementById('zoomPinch');
249
+ const marker = document.getElementById('marker');
250
+
251
+ zoomPinch.addEventListener('update', () => {
252
+ const [cx, cy] = zoomPinch.composePoint(
253
+ zoomPinch.canvasWidth / 2,
254
+ zoomPinch.canvasHeight / 2
255
+ );
256
+ marker.setAttribute('cx', cx);
257
+ marker.setAttribute('cy', cy);
258
+ });
259
+ </script>
260
+ ```
261
+
262
+ ## Coordinate Systems
263
+
264
+ ### 1. Canvas Coordinates (Absolute)
265
+
266
+ Absolute pixels within canvas content.
267
+ - Origin: `(0, 0)` at top-left
268
+ - Range: `0` to `canvasWidth`, `0` to `canvasHeight`
269
+
270
+ ```javascript
271
+ const [canvasX, canvasY] = zoomPinch.normalizeClientCoords(event.clientX, event.clientY);
272
+ ```
273
+
274
+ ### 2. Wrapper Coordinates (Absolute)
275
+
276
+ Absolute pixels within viewport/wrapper.
277
+ - Origin: `(0, 0)` at top-left (accounting for offset)
278
+ - Range: `0` to `wrapperWidth`, `0` to `wrapperHeight`
279
+
280
+ ```javascript
281
+ const [wrapperX, wrapperY] = zoomPinch.composePoint(canvasX, canvasY);
282
+ ```
283
+
284
+ ### 3. Relative Coordinates (0-1)
285
+
286
+ Normalized coordinates for `applyTransform`.
287
+ - Range: `0.0` to `1.0`
288
+ - `0.5` = center, `1.0` = bottom-right
289
+
290
+ ```javascript
291
+ [0, 0] // top-left
292
+ [0.5, 0.5] // center
293
+ [1, 1] // bottom-right
294
+ ```
295
+
296
+ **Conversion Flow:**
297
+
298
+ ```
299
+ Client Coords → normalizeClientCoords() → Canvas Coords → composePoint() → Wrapper Coords
300
+ ```
301
+
302
+ ## Best Practices
303
+
304
+ 1. **Always specify image dimensions** to avoid layout shifts:
305
+ ```html
306
+ <img width="1920" height="1080" src="image.jpg" />
307
+ ```
308
+
309
+ 2. **Center content on init:**
310
+ ```javascript
311
+ zoomPinch.addEventListener('init', () => {
312
+ zoomPinch.applyTransform(1, [0.5, 0.5], [0.5, 0.5]);
313
+ });
314
+ ```
315
+
316
+ 3. **Prevent image drag:**
317
+ ```html
318
+ <img src="image.jpg" draggable="false" style="user-select: none;" />
319
+ ```
320
+
321
+ 4. **Update matrix overlays on transform change:**
322
+ ```javascript
323
+ zoomPinch.addEventListener('update', updateMatrix);
324
+ ```
325
+
326
+ ## Styling
327
+
328
+ The element uses Shadow DOM. Style the host:
329
+
330
+ ```css
331
+ zoom-pinch {
332
+ display: block;
333
+ width: 800px;
334
+ height: 600px;
335
+ border: 1px solid #ccc;
336
+ }
337
+ ```
338
+
339
+ **Internal structure (Shadow DOM):**
340
+
341
+ ```css
342
+ :host /* Container */
343
+ .content /* Wrapper */
344
+ .canvas /* Canvas wrapper */
345
+ .matrix /* Matrix overlay */
346
+ ```
347
+
348
+ ## Browser Support
349
+
350
+ - ✅ Chrome/Edge (latest)
351
+ - ✅ Firefox (latest)
352
+ - ✅ Safari (latest, including iOS)
353
+ - ✅ Mobile browsers (iOS Safari, Chrome Mobile)
354
+
355
+ ## License
356
+
357
+ MIT
358
+
359
+ ## Related
360
+
361
+ - [@zoompinch/core](https://www.npmjs.com/package/@zoompinch/core) - Core engine
362
+ - [@zoompinch/vue](https://www.npmjs.com/package/@zoompinch/vue) - Vue 3 bindings
363
+
364
+ Built with ❤️ by Elya Maurice Conrad
@@ -1,49 +1,49 @@
1
- var y = Object.defineProperty;
2
- var E = (r, t, e) => t in r ? y(r, t, { enumerable: !0, configurable: !0, writable: !0, value: e }) : r[t] = e;
3
- var b = (r, t, e) => E(r, typeof t != "symbol" ? t + "" : t, e);
4
- var x = Object.defineProperty, A = (r, t, e) => t in r ? x(r, t, { enumerable: !0, configurable: !0, writable: !0, value: e }) : r[t] = e, f = (r, t, e) => A(r, typeof t != "symbol" ? t + "" : t, e);
1
+ var N = Object.defineProperty;
2
+ var x = (r, t, e) => t in r ? N(r, t, { enumerable: !0, configurable: !0, writable: !0, value: e }) : r[t] = e;
3
+ var T = (r, t, e) => x(r, typeof t != "symbol" ? t + "" : t, e);
4
+ var y = Object.defineProperty, A = (r, t, e) => t in r ? y(r, t, { enumerable: !0, configurable: !0, writable: !0, value: e }) : r[t] = e, v = (r, t, e) => A(r, typeof t != "symbol" ? t + "" : t, e);
5
5
  function z(r) {
6
6
  return r * Math.PI / 180;
7
7
  }
8
- function T(r, t, e) {
8
+ function Y(r, t, e) {
9
9
  return Math.min(Math.max(r, t), e);
10
10
  }
11
- function v(r, t, e) {
12
- const [s, n] = r, [a, h] = t, o = Math.cos(e) * (s - a) - Math.sin(e) * (n - h) + a, c = Math.sin(e) * (s - a) + Math.cos(e) * (n - h) + h;
13
- return [o, c];
11
+ function w(r, t, e) {
12
+ const [s, n] = r, [a, i] = t, h = Math.cos(e) * (s - a) - Math.sin(e) * (n - i) + a, c = Math.sin(e) * (s - a) + Math.cos(e) * (n - i) + i;
13
+ return [h, c];
14
14
  }
15
- function w(r, t) {
15
+ function S(r, t) {
16
16
  const e = Math.pow(10, t);
17
17
  return Math.round(r * e) / e;
18
18
  }
19
- function I(r) {
19
+ function F(r) {
20
20
  var t = !1;
21
21
  return r.wheelDeltaY ? r.wheelDeltaY === r.deltaY * -3 && (t = !0) : r.deltaMode === 0 && (t = !0), t;
22
22
  }
23
- function C(r, t) {
23
+ function X(r, t) {
24
24
  const e = t.find((s) => r % s === 0);
25
25
  return e ? r / e : 1;
26
26
  }
27
- function W(r, t, e, s, n) {
28
- let a = r.left - t, h = r.top - e;
29
- const o = Math.cos(-n), c = Math.sin(-n);
30
- let l = a * o - h * c, u = a * c + h * o;
31
- const d = r.width / s, i = r.height / s;
32
- return l /= s, u /= s, { x: w(l, 4), y: w(u, 4), width: w(d, 4), height: w(i, 4) };
27
+ function I(r, t, e, s, n) {
28
+ let a = r.left - t, i = r.top - e;
29
+ const h = Math.cos(-n), c = Math.sin(-n);
30
+ let l = a * h - i * c, u = a * c + i * h;
31
+ const d = r.width / s, g = r.height / s;
32
+ return l /= s, u /= s, { x: S(l, 4), y: S(u, 4), width: S(d, 4), height: S(g, 4) };
33
33
  }
34
- class L extends EventTarget {
35
- constructor(t, e, s, n, a, h, o = 0.1, c = 10) {
36
- super(), f(this, "wrapperBounds"), f(this, "canvasBounds"), f(this, "gestureStartRotate", 0), f(this, "dragStart", null), f(this, "dragStartFrozenX", null), f(this, "dragStartFrozenY", null), f(this, "touchStarts", null), f(this, "touchStartTranslateX", 0), f(this, "touchStartTranslateY", 0), this.element = t, this.offset = e, this.translateX = s, this.translateY = n, this.scale = a, this.rotate = h, this.minScale = o, this.maxScale = c;
37
- const l = new ResizeObserver(() => {
38
- const { x: d, y: i, width: g, height: p } = this.element.getBoundingClientRect();
39
- this.wrapperBounds = { x: d, y: i, width: g, height: p }, this.update();
40
- }), u = new ResizeObserver(() => {
41
- const { x: d, y: i, width: g, height: p } = W(this.canvasElement.getBoundingClientRect(), this.renderingTranslateX, this.renderingTranslateY, this.renderinScale, this.renderingRotate);
42
- this.canvasBounds = { x: d, y: i, width: g, height: p }, this.update();
34
+ class W extends EventTarget {
35
+ constructor(t, e, s, n, a, i, h = 0.1, c = 10, l = !1, u = !0) {
36
+ super(), v(this, "wrapperBounds"), v(this, "canvasBounds"), v(this, "gestureStartRotate", 0), v(this, "dragStart", null), v(this, "dragStartFrozenX", null), v(this, "dragStartFrozenY", null), v(this, "touchStarts", null), v(this, "touchStartTranslateX", 0), v(this, "touchStartTranslateY", 0), this.element = t, this.offset = e, this.translateX = s, this.translateY = n, this.scale = a, this.rotate = i, this.minScale = h, this.maxScale = c, this.clampBounds = l, this.rotation = u;
37
+ const d = new ResizeObserver(() => {
38
+ const { x: o, y: p, width: m, height: f } = this.element.getBoundingClientRect();
39
+ this.wrapperBounds = { x: o, y: p, width: m, height: f }, this.update();
40
+ }), g = new ResizeObserver(() => {
41
+ const { x: o, y: p, width: m, height: f } = I(this.canvasElement.getBoundingClientRect(), this.renderingTranslateX, this.renderingTranslateY, this.renderinScale, this.renderingRotate);
42
+ this.canvasBounds = { x: o, y: p, width: m, height: f }, this.update();
43
43
  });
44
44
  requestAnimationFrame(() => {
45
45
  this.wrapperBounds = this.element.getBoundingClientRect(), this.canvasBounds = this.canvasElement.getBoundingClientRect(), this.update(), this.dispatchEvent(new Event("init"));
46
- }), u.observe(this.canvasElement), l.observe(this.element), console.log("INIT!");
46
+ }), g.observe(this.canvasElement), d.observe(this.element);
47
47
  }
48
48
  get canvasElement() {
49
49
  return this.element.querySelector(".canvas");
@@ -71,14 +71,23 @@ class L extends EventTarget {
71
71
  get naturalScale() {
72
72
  return this.canvasNaturalRatio >= this.wrapperInnerRatio ? this.wrapperInnerWidth / this.canvasBounds.width : this.wrapperInnerHeight / this.canvasBounds.height;
73
73
  }
74
+ // The clamping is an explicit user intention
75
+ // The reason is that we do not want side effects when toggling the clamp
76
+ setTranslateFromUserGesture(t, e) {
77
+ if (this.clampBounds) {
78
+ const s = this.clampTranslate({ translateX: t, translateY: e, scale: this.scale, rotate: this.rotate });
79
+ this.translateX = s.translateX, this.translateY = s.translateY, this.rotate = 0;
80
+ } else
81
+ this.translateX = t, this.translateY = e;
82
+ }
74
83
  handleGesturestart(t) {
75
84
  this.gestureStartRotate = this.rotate;
76
85
  }
77
86
  handleGesturechange(t) {
78
87
  const { clientX: e, clientY: s } = t, n = t.rotation;
79
- if (n === 0)
88
+ if (n === 0 || !this.rotation)
80
89
  return;
81
- const a = this.normalizeMatrixCoordinates(e, s);
90
+ const a = this.normalizeClientCoords(e, s);
82
91
  this.rotateCanvas(a[0], a[1], this.gestureStartRotate + z(n));
83
92
  }
84
93
  handleGestureend(t) {
@@ -92,19 +101,19 @@ class L extends EventTarget {
92
101
  handleMousemove(t) {
93
102
  if (t.preventDefault(), this.dragStart && this.dragStartFrozenX !== null && this.dragStartFrozenY !== null) {
94
103
  const e = t.clientX - this.dragStart[0], s = t.clientY - this.dragStart[1], n = this.dragStartFrozenX - -e, a = this.dragStartFrozenY - -s;
95
- this.translateX = n, this.translateY = a, this.update();
104
+ this.setTranslateFromUserGesture(n, a), this.update();
96
105
  }
97
106
  }
98
107
  handleWheel(t) {
99
108
  let { deltaX: e, deltaY: s, ctrlKey: n } = t;
100
- const a = [120, 100], h = 2;
101
- I(t) || ((Math.abs(e) === 120 || Math.abs(e) === 200) && (e = e / (100 / h * C(e, a)) * Math.sign(e)), (Math.abs(s) === 120 || Math.abs(s) === 200) && (s = s / (100 / h * C(s, a)) * Math.sign(s)));
102
- const o = this.scale;
109
+ const a = [120, 100], i = 2;
110
+ F(t) || ((Math.abs(e) === 120 || Math.abs(e) === 200) && (e = e / (100 / i * X(e, a)) * Math.sign(e)), (Math.abs(s) === 120 || Math.abs(s) === 200) && (s = s / (100 / i * X(s, a)) * Math.sign(s)));
111
+ const h = this.scale;
103
112
  if (n) {
104
- const c = -s / 100 * o, l = T(o + c, this.minScale, this.maxScale), u = this.relativeWrapperCoordinatesFromClientCoords(t.clientX, t.clientY), [d, i] = this.calcProjectionTranslate(l, u, this.normalizeMatrixCoordinates(t.clientX, t.clientY));
105
- this.translateX = d, this.translateY = i, this.scale = l;
113
+ const c = -s / 100 * h, l = Y(h + c, this.minScale, this.maxScale), u = this.relativeWrapperCoordinatesFromClientCoords(t.clientX, t.clientY), [d, g] = this.calcProjectionTranslate(l, u, this.normalizeMatrixCoordinates(t.clientX, t.clientY));
114
+ this.setTranslateFromUserGesture(d, g), this.scale = l;
106
115
  } else
107
- this.translateX = this.translateX - e, this.translateY = this.translateY - s;
116
+ this.setTranslateFromUserGesture(this.translateX - e, this.translateY - s);
108
117
  this.update(), t.preventDefault();
109
118
  }
110
119
  freezeTouches(t) {
@@ -124,15 +133,18 @@ class L extends EventTarget {
124
133
  const e = Array.from(t.touches).map((s) => this.clientCoordsToWrapperCoords(s.clientX, s.clientY));
125
134
  if (this.touchStarts) {
126
135
  if (e.length >= 2 && this.touchStarts.length >= 2) {
127
- const s = [this.touchStarts[0].canvasRel[0] * this.canvasBounds.width, this.touchStarts[0].canvasRel[1] * this.canvasBounds.height], n = [this.touchStarts[1].canvasRel[0] * this.canvasBounds.width, this.touchStarts[1].canvasRel[1] * this.canvasBounds.height], a = Math.sqrt(Math.pow(s[0] - n[0], 2) + Math.pow(s[1] - n[1], 2)), h = Math.sqrt(Math.pow(e[0][0] - e[1][0], 2) + Math.pow(e[0][1] - e[1][1], 2)) / this.naturalScale, o = T(h / a, this.minScale, this.maxScale), c = [e[0][0] / this.wrapperInnerWidth, e[0][1] / this.wrapperInnerHeight], l = this.touchStarts[0].canvasRel, [u, d] = this.calcProjectionTranslate(o, c, l, 0);
128
- let i = 0, g = 0, p = 0;
129
- const m = Math.atan2(n[1] - s[1], n[0] - s[0]);
130
- p = Math.atan2(e[1][1] - e[0][1], e[1][0] - e[0][0]) - m;
131
- const Y = (N, R) => [this.offset.left + this.canvasBounds.width * N * this.naturalScale * o + u, this.offset.top + this.canvasBounds.height * R * this.naturalScale * o + d], S = Y(0, 0), M = Y(this.touchStarts[0].canvasRel[0], this.touchStarts[0].canvasRel[1]), X = v(S, M, p);
132
- i = X[0] - S[0], g = X[1] - S[1], this.scale = o, this.rotate = p, this.translateX = u + i, this.translateY = d + g;
136
+ const s = [this.touchStarts[0].canvasRel[0] * this.canvasBounds.width, this.touchStarts[0].canvasRel[1] * this.canvasBounds.height], n = [this.touchStarts[1].canvasRel[0] * this.canvasBounds.width, this.touchStarts[1].canvasRel[1] * this.canvasBounds.height], a = Math.sqrt(Math.pow(s[0] - n[0], 2) + Math.pow(s[1] - n[1], 2)), i = Math.sqrt(Math.pow(e[0][0] - e[1][0], 2) + Math.pow(e[0][1] - e[1][1], 2)) / this.naturalScale, h = Y(i / a, this.minScale, this.maxScale), c = [e[0][0] / this.wrapperInnerWidth, e[0][1] / this.wrapperInnerHeight], l = this.touchStarts[0].canvasRel, [u, d] = this.calcProjectionTranslate(h, c, l, 0);
137
+ if (this.rotation) {
138
+ let g = 0, o = 0, p = 0;
139
+ const m = Math.atan2(n[1] - s[1], n[0] - s[0]);
140
+ p = Math.atan2(e[1][1] - e[0][1], e[1][0] - e[0][0]) - m;
141
+ const f = (R, E) => [this.offset.left + this.canvasBounds.width * R * this.naturalScale * h + u, this.offset.top + this.canvasBounds.height * E * this.naturalScale * h + d], b = f(0, 0), C = f(this.touchStarts[0].canvasRel[0], this.touchStarts[0].canvasRel[1]), B = w(b, C, p);
142
+ g = B[0] - b[0], o = B[1] - b[1], this.scale = h, this.rotate = p, this.setTranslateFromUserGesture(u + g, d + o);
143
+ } else
144
+ this.scale = h, this.setTranslateFromUserGesture(u, d);
133
145
  } else {
134
- const s = t.touches[0].clientX - this.touchStarts[0].client[0], n = t.touches[0].clientY - this.touchStarts[0].client[1], a = this.touchStartTranslateX + s, h = this.touchStartTranslateY + n;
135
- this.translateX = a, this.translateY = h;
146
+ const s = t.touches[0].clientX - this.touchStarts[0].client[0], n = t.touches[0].clientY - this.touchStarts[0].client[1], a = this.touchStartTranslateX + s, i = this.touchStartTranslateY + n;
147
+ this.setTranslateFromUserGesture(a, i);
136
148
  }
137
149
  this.update();
138
150
  }
@@ -141,17 +153,16 @@ class L extends EventTarget {
141
153
  t.touches.length === 0 ? this.touchStarts = null : (this.touchStarts = this.freezeTouches(t.touches), this.touchStartTranslateX = this.translateX, this.touchStartTranslateY = this.translateY);
142
154
  }
143
155
  calcProjectionTranslate(t, e, s, n) {
144
- const a = this.canvasBounds.width * this.naturalScale, h = this.canvasBounds.height * this.naturalScale, o = s[0] * a * t, c = s[1] * h * t, l = v([o, c], [0, 0], n ?? this.rotate), u = e[0] * this.wrapperInnerWidth, d = e[1] * this.wrapperInnerHeight, i = u - l[0], g = d - l[1];
145
- return [i, g];
156
+ const a = this.canvasBounds.width * this.naturalScale, i = this.canvasBounds.height * this.naturalScale, h = s[0] * a * t, c = s[1] * i * t, l = w([h, c], [0, 0], n ?? this.rotate), u = e[0] * this.wrapperInnerWidth, d = e[1] * this.wrapperInnerHeight, g = u - l[0], o = d - l[1];
157
+ return [g, o];
146
158
  }
147
159
  applyTransform(t, e, s) {
148
- console.log("....apply transform");
149
160
  const n = this.calcProjectionTranslate(t, e, s, 0);
150
- this.scale = t, this.translateX = n[0], this.translateY = n[1], this.update();
161
+ this.scale = t, this.setTranslateFromUserGesture(n[0], n[1]), this.update();
151
162
  }
152
- composeRelPoint(t, e, s, n, a, h) {
153
- s = s ?? this.scale, n = n ?? this.translateX, a = a ?? this.translateY, h = h ?? this.rotate;
154
- const o = [this.offset.left, this.offset.top], c = [this.offset.left + this.canvasBounds.width * (s * this.naturalScale) * t, this.offset.top + this.canvasBounds.height * (s * this.naturalScale) * e], l = v(c, o, h);
163
+ composeRelPoint(t, e, s, n, a, i) {
164
+ s = s ?? this.scale, n = n ?? this.translateX, a = a ?? this.translateY, i = i ?? this.rotate;
165
+ const h = [this.offset.left, this.offset.top], c = [this.offset.left + this.canvasBounds.width * (s * this.naturalScale) * t, this.offset.top + this.canvasBounds.height * (s * this.naturalScale) * e], l = w(c, h, i);
155
166
  return [l[0] + n, l[1] + a];
156
167
  }
157
168
  composePoint(t, e) {
@@ -159,16 +170,16 @@ class L extends EventTarget {
159
170
  return this.composeRelPoint(s, n);
160
171
  }
161
172
  getAnchorOffset(t, e, s, n, a = [0.5, 0.5]) {
162
- const h = this.calcProjectionTranslate(t, a, a, 0), o = [
163
- this.offset.left + h[0] + this.canvasBounds.width * (t * this.naturalScale) * a[0],
164
- this.offset.top + h[1] + this.canvasBounds.height * (t * this.naturalScale) * a[1]
165
- ], c = this.composeRelPoint(a[0], a[1], t, e, s, n), l = c[0] - o[0], u = c[1] - o[1];
173
+ const i = this.calcProjectionTranslate(t, a, a, 0), h = [
174
+ this.offset.left + i[0] + this.canvasBounds.width * (t * this.naturalScale) * a[0],
175
+ this.offset.top + i[1] + this.canvasBounds.height * (t * this.naturalScale) * a[1]
176
+ ], c = this.composeRelPoint(a[0], a[1], t, e, s, n), l = c[0] - h[0], u = c[1] - h[1];
166
177
  return [l, u];
167
178
  }
168
179
  // Converts absolute inner wrapper coordinates to relative canvas coordinates (0-1, 0-1)
169
180
  getCanvasCoordsRel(t, e) {
170
- const s = [0, 0], n = [t - this.translateX, e - this.translateY], a = v(n, s, -this.rotate), h = [a[0] / this.renderinScale, a[1] / this.renderinScale];
171
- return [h[0] / this.canvasBounds.width, h[1] / this.canvasBounds.height];
181
+ const s = [0, 0], n = [t - this.translateX, e - this.translateY], a = w(n, s, -this.rotate), i = [a[0] / this.renderinScale, a[1] / this.renderinScale];
182
+ return [i[0] / this.canvasBounds.width, i[1] / this.canvasBounds.height];
172
183
  }
173
184
  // Converts absolute client to coordinates to absolute inner-wrapper coorinates
174
185
  clientCoordsToWrapperCoords(t, e) {
@@ -190,8 +201,8 @@ class L extends EventTarget {
190
201
  return [s * this.canvasBounds.width, n * this.canvasBounds.height];
191
202
  }
192
203
  rotateCanvas(t, e, s) {
193
- const n = this.composeRelPoint(t, e, this.scale, 0, 0, s), a = this.composeRelPoint(t, e);
194
- this.translateX = a[0] - n[0], this.translateY = a[1] - n[1], this.rotate = s, this.update();
204
+ const n = t / this.canvasBounds.width, a = e / this.canvasBounds.height, i = this.composeRelPoint(n, a, this.scale, 0, 0, s), h = this.composeRelPoint(n, a);
205
+ this.setTranslateFromUserGesture(h[0] - i[0], h[1] - i[1]), this.rotate = s, this.update();
195
206
  }
196
207
  get renderinScale() {
197
208
  return this.naturalScale * this.scale;
@@ -205,16 +216,23 @@ class L extends EventTarget {
205
216
  get renderingRotate() {
206
217
  return this.rotate;
207
218
  }
219
+ clampTranslate(t, e = [0.5, 0.5]) {
220
+ const s = this.canvasBounds.width * this.naturalScale * t.scale, n = this.canvasBounds.height * this.naturalScale * t.scale, a = s - this.wrapperInnerWidth, i = n - this.wrapperInnerHeight, h = a > 0 ? -a : 0, c = Math.min(0, Math.max(t.translateX, h)), l = i > 0 ? -i : 0, u = Math.min(0, Math.max(t.translateY, l)), d = -Math.min(0, a) * e[0], g = -Math.min(0, i) * e[1];
221
+ return {
222
+ translateX: c + d,
223
+ translateY: u + g
224
+ };
225
+ }
208
226
  update() {
209
227
  this.canvasElement.style.transformOrigin = "top left", this.canvasElement.style.transform = `translateX(${this.renderingTranslateX}px) translateY(${this.renderingTranslateY}px) scale(${this.renderinScale}) rotate(${this.renderingRotate}rad)`, this.dispatchEvent(new Event("update"));
210
228
  }
211
229
  destroy() {
212
230
  }
213
231
  }
214
- class B extends HTMLElement {
232
+ class M extends HTMLElement {
215
233
  constructor() {
216
234
  super();
217
- b(this, "engine");
235
+ T(this, "engine");
218
236
  this.attachShadow({ mode: "open" });
219
237
  }
220
238
  get contentEl() {
@@ -259,8 +277,8 @@ class B extends HTMLElement {
259
277
  </div>
260
278
  </div>
261
279
  `;
262
- const e = Number(this.getAttribute("translate-x") || "0"), s = Number(this.getAttribute("translate-y") || "0"), n = Number(this.getAttribute("scale") || "1"), a = Number(this.getAttribute("rotate") || "0"), h = Number(this.getAttribute("min-scale")), o = Number(this.getAttribute("max-scale")), c = Number(this.getAttribute("offset-top")), l = Number(this.getAttribute("offset-right")), u = Number(this.getAttribute("offset-bottom")), d = Number(this.getAttribute("offset-left"));
263
- this.engine = new L(
280
+ const e = Number(this.getAttribute("translate-x") || "0"), s = Number(this.getAttribute("translate-y") || "0"), n = Number(this.getAttribute("scale") || "1"), a = Number(this.getAttribute("rotate") || "0"), i = Number(this.getAttribute("min-scale")), h = Number(this.getAttribute("max-scale")), c = Number(this.getAttribute("offset-top")), l = Number(this.getAttribute("offset-right")), u = Number(this.getAttribute("offset-bottom")), d = Number(this.getAttribute("offset-left")), g = this.getAttribute("clamp-bounds") === "true";
281
+ this.getAttribute("rotation"), this.engine = new W(
264
282
  this.contentEl,
265
283
  {
266
284
  top: isNaN(c) ? 100 : c,
@@ -272,11 +290,14 @@ class B extends HTMLElement {
272
290
  s,
273
291
  n,
274
292
  a,
293
+ isNaN(i) ? void 0 : i,
275
294
  isNaN(h) ? void 0 : h,
276
- isNaN(o) ? void 0 : o
277
- ), this.contentEl.addEventListener("wheel", (i) => this.engine.handleWheel(i)), this.contentEl.addEventListener("gesturestart", (i) => this.engine.handleGesturestart(i)), window.addEventListener("gesturechange", (i) => this.engine.handleGesturechange(i)), window.addEventListener("gestureend", (i) => this.engine.handleGestureend(i)), this.contentEl.addEventListener("mousedown", (i) => this.engine.handleMousedown(i)), window.addEventListener("mousemove", (i) => this.engine.handleMousemove(i)), window.addEventListener("mouseup", (i) => this.engine.handleMouseup(i)), this.contentEl.addEventListener("touchstart", (i) => this.engine.handleTouchstart(i)), window.addEventListener("touchmove", (i) => this.engine.handleTouchmove(i)), window.addEventListener("touchend", (i) => this.engine.handleTouchend(i)), this.engine.addEventListener("update", () => {
278
- const i = this.engine.translateX.toString(), g = this.engine.translateY.toString(), p = this.engine.scale.toString(), m = this.engine.rotate.toString();
279
- this.getAttribute("translate-x") !== i && this.setAttribute("translate-x", i), this.getAttribute("translate-y") !== g && this.setAttribute("translate-y", g), this.getAttribute("scale") !== p && this.setAttribute("scale", p), this.getAttribute("rotate") !== m && this.setAttribute("rotate", m), this.dispatchEvent(new Event("update"));
295
+ g
296
+ ), this.contentEl.addEventListener("wheel", (o) => this.engine.handleWheel(o)), this.contentEl.addEventListener("gesturestart", (o) => this.engine.handleGesturestart(o)), window.addEventListener("gesturechange", (o) => this.engine.handleGesturechange(o)), window.addEventListener("gestureend", (o) => this.engine.handleGestureend(o)), this.contentEl.addEventListener("mousedown", (o) => this.engine.handleMousedown(o)), window.addEventListener("mousemove", (o) => this.engine.handleMousemove(o)), window.addEventListener("mouseup", (o) => this.engine.handleMouseup(o)), this.contentEl.addEventListener("touchstart", (o) => this.engine.handleTouchstart(o)), window.addEventListener("touchmove", (o) => this.engine.handleTouchmove(o)), window.addEventListener("touchend", (o) => this.engine.handleTouchend(o)), this.engine.addEventListener("update", () => {
297
+ const o = this.engine.translateX.toString(), p = this.engine.translateY.toString(), m = this.engine.scale.toString(), f = this.engine.rotate.toString();
298
+ this.getAttribute("translate-x") !== o && this.setAttribute("translate-x", o), this.getAttribute("translate-y") !== p && this.setAttribute("translate-y", p), this.getAttribute("scale") !== m && this.setAttribute("scale", m), this.getAttribute("rotate") !== f && this.setAttribute("rotate", f), this.dispatchEvent(new Event("update"));
299
+ }), this.engine.addEventListener("init", () => {
300
+ this.dispatchEvent(new Event("init"));
280
301
  });
281
302
  }
282
303
  disconnectedCallback() {
@@ -290,12 +311,12 @@ class B extends HTMLElement {
290
311
  this.engine.translateX !== a && (this.engine.translateX = a, this.engine.update());
291
312
  break;
292
313
  case "translate-y":
293
- const h = Number(n);
294
- this.engine.translateY !== h && (this.engine.translateY = h, this.engine.update());
314
+ const i = Number(n);
315
+ this.engine.translateY !== i && (this.engine.translateY = i, this.engine.update());
295
316
  break;
296
317
  case "scale":
297
- const o = Number(n);
298
- this.engine.scale !== o && (this.engine.scale = o, this.engine.update());
318
+ const h = Number(n);
319
+ this.engine.scale !== h && (this.engine.scale = h, this.engine.update());
299
320
  break;
300
321
  case "rotate":
301
322
  const c = Number(n);
@@ -313,14 +334,21 @@ class B extends HTMLElement {
313
334
  case "offset-right":
314
335
  case "offset-bottom":
315
336
  case "offset-left":
316
- const d = Number(this.getAttribute("offset-top") || "0"), i = Number(this.getAttribute("offset-right") || "0"), g = Number(this.getAttribute("offset-bottom") || "0"), p = Number(this.getAttribute("offset-left") || "0");
337
+ const d = Number(this.getAttribute("offset-top") || "0"), g = Number(this.getAttribute("offset-right") || "0"), o = Number(this.getAttribute("offset-bottom") || "0"), p = Number(this.getAttribute("offset-left") || "0");
317
338
  this.engine.offset = {
318
339
  top: d,
319
- right: i,
320
- bottom: g,
340
+ right: g,
341
+ bottom: o,
321
342
  left: p
322
343
  }, this.engine.update();
323
344
  break;
345
+ case "clamp-bounds":
346
+ const m = n === "true";
347
+ this.engine.clampBounds !== m && (this.engine.clampBounds = m, this.engine.setTranslateFromUserGesture(this.engine.translateX, this.engine.translateY), this.engine.update());
348
+ break;
349
+ case "rotation":
350
+ const f = n === "true";
351
+ this.engine.rotation !== f && (this.engine.rotation = f, this.engine.update());
324
352
  }
325
353
  }
326
354
  get canvasWidth() {
@@ -339,5 +367,5 @@ class B extends HTMLElement {
339
367
  return this.engine.composePoint(e, s);
340
368
  }
341
369
  }
342
- b(B, "observedAttributes", ["translate-x", "translate-y", "scale", "rotate", "min-scale", "max-scale", "offset-top", "offset-right", "offset-bottom", "offset-left"]);
343
- customElements.get("zoom-pinch") || customElements.define("zoom-pinch", B);
370
+ T(M, "observedAttributes", ["translate-x", "translate-y", "scale", "rotate", "min-scale", "max-scale", "offset-top", "offset-right", "offset-bottom", "offset-left", "clamp-bounds", "rotation"]);
371
+ customElements.get("zoom-pinch") || customElements.define("zoom-pinch", M);
@@ -1,4 +1,4 @@
1
- (function(m){typeof define=="function"&&define.amd?define(m):m()})((function(){"use strict";var W=Object.defineProperty;var L=(m,v,g)=>v in m?W(m,v,{enumerable:!0,configurable:!0,writable:!0,value:g}):m[v]=g;var X=(m,v,g)=>L(m,typeof v!="symbol"?v+"":v,g);var m=Object.defineProperty,v=(h,t,e)=>t in h?m(h,t,{enumerable:!0,configurable:!0,writable:!0,value:e}):h[t]=e,g=(h,t,e)=>v(h,typeof t!="symbol"?t+"":t,e);function R(h){return h*Math.PI/180}function T(h,t,e){return Math.min(Math.max(h,t),e)}function w(h,t,e){const[s,n]=h,[a,r]=t,o=Math.cos(e)*(s-a)-Math.sin(e)*(n-r)+a,c=Math.sin(e)*(s-a)+Math.cos(e)*(n-r)+r;return[o,c]}function S(h,t){const e=Math.pow(10,t);return Math.round(h*e)/e}function y(h){var t=!1;return h.wheelDeltaY?h.wheelDeltaY===h.deltaY*-3&&(t=!0):h.deltaMode===0&&(t=!0),t}function C(h,t){const e=t.find(s=>h%s===0);return e?h/e:1}function E(h,t,e,s,n){let a=h.left-t,r=h.top-e;const o=Math.cos(-n),c=Math.sin(-n);let l=a*o-r*c,u=a*c+r*o;const d=h.width/s,i=h.height/s;return l/=s,u/=s,{x:S(l,4),y:S(u,4),width:S(d,4),height:S(i,4)}}class x extends EventTarget{constructor(t,e,s,n,a,r,o=.1,c=10){super(),g(this,"wrapperBounds"),g(this,"canvasBounds"),g(this,"gestureStartRotate",0),g(this,"dragStart",null),g(this,"dragStartFrozenX",null),g(this,"dragStartFrozenY",null),g(this,"touchStarts",null),g(this,"touchStartTranslateX",0),g(this,"touchStartTranslateY",0),this.element=t,this.offset=e,this.translateX=s,this.translateY=n,this.scale=a,this.rotate=r,this.minScale=o,this.maxScale=c;const l=new ResizeObserver(()=>{const{x:d,y:i,width:f,height:p}=this.element.getBoundingClientRect();this.wrapperBounds={x:d,y:i,width:f,height:p},this.update()}),u=new ResizeObserver(()=>{const{x:d,y:i,width:f,height:p}=E(this.canvasElement.getBoundingClientRect(),this.renderingTranslateX,this.renderingTranslateY,this.renderinScale,this.renderingRotate);this.canvasBounds={x:d,y:i,width:f,height:p},this.update()});requestAnimationFrame(()=>{this.wrapperBounds=this.element.getBoundingClientRect(),this.canvasBounds=this.canvasElement.getBoundingClientRect(),this.update(),this.dispatchEvent(new Event("init"))}),u.observe(this.canvasElement),l.observe(this.element),console.log("INIT!")}get canvasElement(){return this.element.querySelector(".canvas")}get wrapperInnerX(){return this.wrapperBounds.x+this.offset.left}get wrapperInnerY(){return this.wrapperBounds.y+this.offset.top}get wrapperInnerWidth(){return this.wrapperBounds.width-this.offset.left-this.offset.right}get wrapperInnerHeight(){return this.wrapperBounds.height-this.offset.top-this.offset.bottom}get wrapperInnerRatio(){return this.wrapperInnerWidth/this.wrapperInnerHeight}get canvasNaturalRatio(){return this.canvasBounds.width/this.canvasBounds.height}get naturalScale(){return this.canvasNaturalRatio>=this.wrapperInnerRatio?this.wrapperInnerWidth/this.canvasBounds.width:this.wrapperInnerHeight/this.canvasBounds.height}handleGesturestart(t){this.gestureStartRotate=this.rotate}handleGesturechange(t){const{clientX:e,clientY:s}=t,n=t.rotation;if(n===0)return;const a=this.normalizeMatrixCoordinates(e,s);this.rotateCanvas(a[0],a[1],this.gestureStartRotate+R(n))}handleGestureend(t){}handleMousedown(t){t.preventDefault(),this.dragStart=[t.clientX,t.clientY],this.dragStartFrozenX=this.translateX,this.dragStartFrozenY=this.translateY}handleMouseup(t){t.preventDefault(),this.dragStart=null,this.dragStartFrozenX=null,this.dragStartFrozenY=null}handleMousemove(t){if(t.preventDefault(),this.dragStart&&this.dragStartFrozenX!==null&&this.dragStartFrozenY!==null){const e=t.clientX-this.dragStart[0],s=t.clientY-this.dragStart[1],n=this.dragStartFrozenX- -e,a=this.dragStartFrozenY- -s;this.translateX=n,this.translateY=a,this.update()}}handleWheel(t){let{deltaX:e,deltaY:s,ctrlKey:n}=t;const a=[120,100],r=2;y(t)||((Math.abs(e)===120||Math.abs(e)===200)&&(e=e/(100/r*C(e,a))*Math.sign(e)),(Math.abs(s)===120||Math.abs(s)===200)&&(s=s/(100/r*C(s,a))*Math.sign(s)));const o=this.scale;if(n){const c=-s/100*o,l=T(o+c,this.minScale,this.maxScale),u=this.relativeWrapperCoordinatesFromClientCoords(t.clientX,t.clientY),[d,i]=this.calcProjectionTranslate(l,u,this.normalizeMatrixCoordinates(t.clientX,t.clientY));this.translateX=d,this.translateY=i,this.scale=l}else this.translateX=this.translateX-e,this.translateY=this.translateY-s;this.update(),t.preventDefault()}freezeTouches(t){return Array.from(t).map(e=>{const s=this.clientCoordsToWrapperCoords(e.clientX,e.clientY);return{client:[e.clientX,e.clientY],canvasRel:this.getCanvasCoordsRel(s[0],s[1])}})}handleTouchstart(t){this.touchStarts=this.freezeTouches(t.touches),this.touchStartTranslateX=this.translateX,this.touchStartTranslateY=this.translateY,t.preventDefault()}handleTouchmove(t){t.preventDefault();const e=Array.from(t.touches).map(s=>this.clientCoordsToWrapperCoords(s.clientX,s.clientY));if(this.touchStarts){if(e.length>=2&&this.touchStarts.length>=2){const s=[this.touchStarts[0].canvasRel[0]*this.canvasBounds.width,this.touchStarts[0].canvasRel[1]*this.canvasBounds.height],n=[this.touchStarts[1].canvasRel[0]*this.canvasBounds.width,this.touchStarts[1].canvasRel[1]*this.canvasBounds.height],a=Math.sqrt(Math.pow(s[0]-n[0],2)+Math.pow(s[1]-n[1],2)),r=Math.sqrt(Math.pow(e[0][0]-e[1][0],2)+Math.pow(e[0][1]-e[1][1],2))/this.naturalScale,o=T(r/a,this.minScale,this.maxScale),c=[e[0][0]/this.wrapperInnerWidth,e[0][1]/this.wrapperInnerHeight],l=this.touchStarts[0].canvasRel,[u,d]=this.calcProjectionTranslate(o,c,l,0);let i=0,f=0,p=0;const b=Math.atan2(n[1]-s[1],n[0]-s[0]);p=Math.atan2(e[1][1]-e[0][1],e[1][0]-e[0][0])-b;const M=(z,I)=>[this.offset.left+this.canvasBounds.width*z*this.naturalScale*o+u,this.offset.top+this.canvasBounds.height*I*this.naturalScale*o+d],Y=M(0,0),A=M(this.touchStarts[0].canvasRel[0],this.touchStarts[0].canvasRel[1]),N=w(Y,A,p);i=N[0]-Y[0],f=N[1]-Y[1],this.scale=o,this.rotate=p,this.translateX=u+i,this.translateY=d+f}else{const s=t.touches[0].clientX-this.touchStarts[0].client[0],n=t.touches[0].clientY-this.touchStarts[0].client[1],a=this.touchStartTranslateX+s,r=this.touchStartTranslateY+n;this.translateX=a,this.translateY=r}this.update()}}handleTouchend(t){t.touches.length===0?this.touchStarts=null:(this.touchStarts=this.freezeTouches(t.touches),this.touchStartTranslateX=this.translateX,this.touchStartTranslateY=this.translateY)}calcProjectionTranslate(t,e,s,n){const a=this.canvasBounds.width*this.naturalScale,r=this.canvasBounds.height*this.naturalScale,o=s[0]*a*t,c=s[1]*r*t,l=w([o,c],[0,0],n??this.rotate),u=e[0]*this.wrapperInnerWidth,d=e[1]*this.wrapperInnerHeight,i=u-l[0],f=d-l[1];return[i,f]}applyTransform(t,e,s){console.log("....apply transform");const n=this.calcProjectionTranslate(t,e,s,0);this.scale=t,this.translateX=n[0],this.translateY=n[1],this.update()}composeRelPoint(t,e,s,n,a,r){s=s??this.scale,n=n??this.translateX,a=a??this.translateY,r=r??this.rotate;const o=[this.offset.left,this.offset.top],c=[this.offset.left+this.canvasBounds.width*(s*this.naturalScale)*t,this.offset.top+this.canvasBounds.height*(s*this.naturalScale)*e],l=w(c,o,r);return[l[0]+n,l[1]+a]}composePoint(t,e){const s=t/this.canvasBounds.width,n=e/this.canvasBounds.height;return this.composeRelPoint(s,n)}getAnchorOffset(t,e,s,n,a=[.5,.5]){const r=this.calcProjectionTranslate(t,a,a,0),o=[this.offset.left+r[0]+this.canvasBounds.width*(t*this.naturalScale)*a[0],this.offset.top+r[1]+this.canvasBounds.height*(t*this.naturalScale)*a[1]],c=this.composeRelPoint(a[0],a[1],t,e,s,n),l=c[0]-o[0],u=c[1]-o[1];return[l,u]}getCanvasCoordsRel(t,e){const s=[0,0],n=[t-this.translateX,e-this.translateY],a=w(n,s,-this.rotate),r=[a[0]/this.renderinScale,a[1]/this.renderinScale];return[r[0]/this.canvasBounds.width,r[1]/this.canvasBounds.height]}clientCoordsToWrapperCoords(t,e){return[t-this.wrapperInnerX,e-this.wrapperInnerY]}relativeWrapperCoordinatesFromClientCoords(t,e){const[s,n]=this.clientCoordsToWrapperCoords(t,e);return[s/this.wrapperInnerWidth,n/this.wrapperInnerHeight]}normalizeMatrixCoordinates(t,e){const s=this.clientCoordsToWrapperCoords(t,e);return this.getCanvasCoordsRel(s[0],s[1])}normalizeClientCoords(t,e){const[s,n]=this.normalizeMatrixCoordinates(t,e);return[s*this.canvasBounds.width,n*this.canvasBounds.height]}rotateCanvas(t,e,s){const n=this.composeRelPoint(t,e,this.scale,0,0,s),a=this.composeRelPoint(t,e);this.translateX=a[0]-n[0],this.translateY=a[1]-n[1],this.rotate=s,this.update()}get renderinScale(){return this.naturalScale*this.scale}get renderingTranslateX(){return this.offset.left+this.translateX}get renderingTranslateY(){return this.offset.top+this.translateY}get renderingRotate(){return this.rotate}update(){this.canvasElement.style.transformOrigin="top left",this.canvasElement.style.transform=`translateX(${this.renderingTranslateX}px) translateY(${this.renderingTranslateY}px) scale(${this.renderinScale}) rotate(${this.renderingRotate}rad)`,this.dispatchEvent(new Event("update"))}destroy(){}}class B extends HTMLElement{constructor(){super();X(this,"engine");this.attachShadow({mode:"open"})}get contentEl(){return this.shadowRoot.querySelector(".content")}get canvasElement(){return this.shadowRoot.querySelector(".canvas")}connectedCallback(){this.shadowRoot.innerHTML=`
1
+ (function(w){typeof define=="function"&&define.amd?define(w):w()})((function(){"use strict";var I=Object.defineProperty;var W=(w,S,p)=>S in w?I(w,S,{enumerable:!0,configurable:!0,writable:!0,value:p}):w[S]=p;var Y=(w,S,p)=>W(w,typeof S!="symbol"?S+"":S,p);var w=Object.defineProperty,S=(o,t,e)=>t in o?w(o,t,{enumerable:!0,configurable:!0,writable:!0,value:e}):o[t]=e,p=(o,t,e)=>S(o,typeof t!="symbol"?t+"":t,e);function E(o){return o*Math.PI/180}function X(o,t,e){return Math.min(Math.max(o,t),e)}function b(o,t,e){const[s,n]=o,[a,i]=t,r=Math.cos(e)*(s-a)-Math.sin(e)*(n-i)+a,c=Math.sin(e)*(s-a)+Math.cos(e)*(n-i)+i;return[r,c]}function T(o,t){const e=Math.pow(10,t);return Math.round(o*e)/e}function N(o){var t=!1;return o.wheelDeltaY?o.wheelDeltaY===o.deltaY*-3&&(t=!0):o.deltaMode===0&&(t=!0),t}function M(o,t){const e=t.find(s=>o%s===0);return e?o/e:1}function x(o,t,e,s,n){let a=o.left-t,i=o.top-e;const r=Math.cos(-n),c=Math.sin(-n);let l=a*r-i*c,u=a*c+i*r;const d=o.width/s,g=o.height/s;return l/=s,u/=s,{x:T(l,4),y:T(u,4),width:T(d,4),height:T(g,4)}}class y extends EventTarget{constructor(t,e,s,n,a,i,r=.1,c=10,l=!1,u=!0){super(),p(this,"wrapperBounds"),p(this,"canvasBounds"),p(this,"gestureStartRotate",0),p(this,"dragStart",null),p(this,"dragStartFrozenX",null),p(this,"dragStartFrozenY",null),p(this,"touchStarts",null),p(this,"touchStartTranslateX",0),p(this,"touchStartTranslateY",0),this.element=t,this.offset=e,this.translateX=s,this.translateY=n,this.scale=a,this.rotate=i,this.minScale=r,this.maxScale=c,this.clampBounds=l,this.rotation=u;const d=new ResizeObserver(()=>{const{x:h,y:f,width:v,height:m}=this.element.getBoundingClientRect();this.wrapperBounds={x:h,y:f,width:v,height:m},this.update()}),g=new ResizeObserver(()=>{const{x:h,y:f,width:v,height:m}=x(this.canvasElement.getBoundingClientRect(),this.renderingTranslateX,this.renderingTranslateY,this.renderinScale,this.renderingRotate);this.canvasBounds={x:h,y:f,width:v,height:m},this.update()});requestAnimationFrame(()=>{this.wrapperBounds=this.element.getBoundingClientRect(),this.canvasBounds=this.canvasElement.getBoundingClientRect(),this.update(),this.dispatchEvent(new Event("init"))}),g.observe(this.canvasElement),d.observe(this.element)}get canvasElement(){return this.element.querySelector(".canvas")}get wrapperInnerX(){return this.wrapperBounds.x+this.offset.left}get wrapperInnerY(){return this.wrapperBounds.y+this.offset.top}get wrapperInnerWidth(){return this.wrapperBounds.width-this.offset.left-this.offset.right}get wrapperInnerHeight(){return this.wrapperBounds.height-this.offset.top-this.offset.bottom}get wrapperInnerRatio(){return this.wrapperInnerWidth/this.wrapperInnerHeight}get canvasNaturalRatio(){return this.canvasBounds.width/this.canvasBounds.height}get naturalScale(){return this.canvasNaturalRatio>=this.wrapperInnerRatio?this.wrapperInnerWidth/this.canvasBounds.width:this.wrapperInnerHeight/this.canvasBounds.height}setTranslateFromUserGesture(t,e){if(this.clampBounds){const s=this.clampTranslate({translateX:t,translateY:e,scale:this.scale,rotate:this.rotate});this.translateX=s.translateX,this.translateY=s.translateY,this.rotate=0}else this.translateX=t,this.translateY=e}handleGesturestart(t){this.gestureStartRotate=this.rotate}handleGesturechange(t){const{clientX:e,clientY:s}=t,n=t.rotation;if(n===0||!this.rotation)return;const a=this.normalizeClientCoords(e,s);this.rotateCanvas(a[0],a[1],this.gestureStartRotate+E(n))}handleGestureend(t){}handleMousedown(t){t.preventDefault(),this.dragStart=[t.clientX,t.clientY],this.dragStartFrozenX=this.translateX,this.dragStartFrozenY=this.translateY}handleMouseup(t){t.preventDefault(),this.dragStart=null,this.dragStartFrozenX=null,this.dragStartFrozenY=null}handleMousemove(t){if(t.preventDefault(),this.dragStart&&this.dragStartFrozenX!==null&&this.dragStartFrozenY!==null){const e=t.clientX-this.dragStart[0],s=t.clientY-this.dragStart[1],n=this.dragStartFrozenX- -e,a=this.dragStartFrozenY- -s;this.setTranslateFromUserGesture(n,a),this.update()}}handleWheel(t){let{deltaX:e,deltaY:s,ctrlKey:n}=t;const a=[120,100],i=2;N(t)||((Math.abs(e)===120||Math.abs(e)===200)&&(e=e/(100/i*M(e,a))*Math.sign(e)),(Math.abs(s)===120||Math.abs(s)===200)&&(s=s/(100/i*M(s,a))*Math.sign(s)));const r=this.scale;if(n){const c=-s/100*r,l=X(r+c,this.minScale,this.maxScale),u=this.relativeWrapperCoordinatesFromClientCoords(t.clientX,t.clientY),[d,g]=this.calcProjectionTranslate(l,u,this.normalizeMatrixCoordinates(t.clientX,t.clientY));this.setTranslateFromUserGesture(d,g),this.scale=l}else this.setTranslateFromUserGesture(this.translateX-e,this.translateY-s);this.update(),t.preventDefault()}freezeTouches(t){return Array.from(t).map(e=>{const s=this.clientCoordsToWrapperCoords(e.clientX,e.clientY);return{client:[e.clientX,e.clientY],canvasRel:this.getCanvasCoordsRel(s[0],s[1])}})}handleTouchstart(t){this.touchStarts=this.freezeTouches(t.touches),this.touchStartTranslateX=this.translateX,this.touchStartTranslateY=this.translateY,t.preventDefault()}handleTouchmove(t){t.preventDefault();const e=Array.from(t.touches).map(s=>this.clientCoordsToWrapperCoords(s.clientX,s.clientY));if(this.touchStarts){if(e.length>=2&&this.touchStarts.length>=2){const s=[this.touchStarts[0].canvasRel[0]*this.canvasBounds.width,this.touchStarts[0].canvasRel[1]*this.canvasBounds.height],n=[this.touchStarts[1].canvasRel[0]*this.canvasBounds.width,this.touchStarts[1].canvasRel[1]*this.canvasBounds.height],a=Math.sqrt(Math.pow(s[0]-n[0],2)+Math.pow(s[1]-n[1],2)),i=Math.sqrt(Math.pow(e[0][0]-e[1][0],2)+Math.pow(e[0][1]-e[1][1],2))/this.naturalScale,r=X(i/a,this.minScale,this.maxScale),c=[e[0][0]/this.wrapperInnerWidth,e[0][1]/this.wrapperInnerHeight],l=this.touchStarts[0].canvasRel,[u,d]=this.calcProjectionTranslate(r,c,l,0);if(this.rotation){let g=0,h=0,f=0;const v=Math.atan2(n[1]-s[1],n[0]-s[0]);f=Math.atan2(e[1][1]-e[0][1],e[1][0]-e[0][0])-v;const m=(z,F)=>[this.offset.left+this.canvasBounds.width*z*this.naturalScale*r+u,this.offset.top+this.canvasBounds.height*F*this.naturalScale*r+d],B=m(0,0),A=m(this.touchStarts[0].canvasRel[0],this.touchStarts[0].canvasRel[1]),R=b(B,A,f);g=R[0]-B[0],h=R[1]-B[1],this.scale=r,this.rotate=f,this.setTranslateFromUserGesture(u+g,d+h)}else this.scale=r,this.setTranslateFromUserGesture(u,d)}else{const s=t.touches[0].clientX-this.touchStarts[0].client[0],n=t.touches[0].clientY-this.touchStarts[0].client[1],a=this.touchStartTranslateX+s,i=this.touchStartTranslateY+n;this.setTranslateFromUserGesture(a,i)}this.update()}}handleTouchend(t){t.touches.length===0?this.touchStarts=null:(this.touchStarts=this.freezeTouches(t.touches),this.touchStartTranslateX=this.translateX,this.touchStartTranslateY=this.translateY)}calcProjectionTranslate(t,e,s,n){const a=this.canvasBounds.width*this.naturalScale,i=this.canvasBounds.height*this.naturalScale,r=s[0]*a*t,c=s[1]*i*t,l=b([r,c],[0,0],n??this.rotate),u=e[0]*this.wrapperInnerWidth,d=e[1]*this.wrapperInnerHeight,g=u-l[0],h=d-l[1];return[g,h]}applyTransform(t,e,s){const n=this.calcProjectionTranslate(t,e,s,0);this.scale=t,this.setTranslateFromUserGesture(n[0],n[1]),this.update()}composeRelPoint(t,e,s,n,a,i){s=s??this.scale,n=n??this.translateX,a=a??this.translateY,i=i??this.rotate;const r=[this.offset.left,this.offset.top],c=[this.offset.left+this.canvasBounds.width*(s*this.naturalScale)*t,this.offset.top+this.canvasBounds.height*(s*this.naturalScale)*e],l=b(c,r,i);return[l[0]+n,l[1]+a]}composePoint(t,e){const s=t/this.canvasBounds.width,n=e/this.canvasBounds.height;return this.composeRelPoint(s,n)}getAnchorOffset(t,e,s,n,a=[.5,.5]){const i=this.calcProjectionTranslate(t,a,a,0),r=[this.offset.left+i[0]+this.canvasBounds.width*(t*this.naturalScale)*a[0],this.offset.top+i[1]+this.canvasBounds.height*(t*this.naturalScale)*a[1]],c=this.composeRelPoint(a[0],a[1],t,e,s,n),l=c[0]-r[0],u=c[1]-r[1];return[l,u]}getCanvasCoordsRel(t,e){const s=[0,0],n=[t-this.translateX,e-this.translateY],a=b(n,s,-this.rotate),i=[a[0]/this.renderinScale,a[1]/this.renderinScale];return[i[0]/this.canvasBounds.width,i[1]/this.canvasBounds.height]}clientCoordsToWrapperCoords(t,e){return[t-this.wrapperInnerX,e-this.wrapperInnerY]}relativeWrapperCoordinatesFromClientCoords(t,e){const[s,n]=this.clientCoordsToWrapperCoords(t,e);return[s/this.wrapperInnerWidth,n/this.wrapperInnerHeight]}normalizeMatrixCoordinates(t,e){const s=this.clientCoordsToWrapperCoords(t,e);return this.getCanvasCoordsRel(s[0],s[1])}normalizeClientCoords(t,e){const[s,n]=this.normalizeMatrixCoordinates(t,e);return[s*this.canvasBounds.width,n*this.canvasBounds.height]}rotateCanvas(t,e,s){const n=t/this.canvasBounds.width,a=e/this.canvasBounds.height,i=this.composeRelPoint(n,a,this.scale,0,0,s),r=this.composeRelPoint(n,a);this.setTranslateFromUserGesture(r[0]-i[0],r[1]-i[1]),this.rotate=s,this.update()}get renderinScale(){return this.naturalScale*this.scale}get renderingTranslateX(){return this.offset.left+this.translateX}get renderingTranslateY(){return this.offset.top+this.translateY}get renderingRotate(){return this.rotate}clampTranslate(t,e=[.5,.5]){const s=this.canvasBounds.width*this.naturalScale*t.scale,n=this.canvasBounds.height*this.naturalScale*t.scale,a=s-this.wrapperInnerWidth,i=n-this.wrapperInnerHeight,r=a>0?-a:0,c=Math.min(0,Math.max(t.translateX,r)),l=i>0?-i:0,u=Math.min(0,Math.max(t.translateY,l)),d=-Math.min(0,a)*e[0],g=-Math.min(0,i)*e[1];return{translateX:c+d,translateY:u+g}}update(){this.canvasElement.style.transformOrigin="top left",this.canvasElement.style.transform=`translateX(${this.renderingTranslateX}px) translateY(${this.renderingTranslateY}px) scale(${this.renderinScale}) rotate(${this.renderingRotate}rad)`,this.dispatchEvent(new Event("update"))}destroy(){}}class C extends HTMLElement{constructor(){super();Y(this,"engine");this.attachShadow({mode:"open"})}get contentEl(){return this.shadowRoot.querySelector(".content")}get canvasElement(){return this.shadowRoot.querySelector(".canvas")}connectedCallback(){this.shadowRoot.innerHTML=`
2
2
  <style>
3
3
  :host {
4
4
  display: block;
@@ -32,4 +32,4 @@
32
32
  <slot name="matrix"></slot>
33
33
  </div>
34
34
  </div>
35
- `;const e=Number(this.getAttribute("translate-x")||"0"),s=Number(this.getAttribute("translate-y")||"0"),n=Number(this.getAttribute("scale")||"1"),a=Number(this.getAttribute("rotate")||"0"),r=Number(this.getAttribute("min-scale")),o=Number(this.getAttribute("max-scale")),c=Number(this.getAttribute("offset-top")),l=Number(this.getAttribute("offset-right")),u=Number(this.getAttribute("offset-bottom")),d=Number(this.getAttribute("offset-left"));this.engine=new x(this.contentEl,{top:isNaN(c)?100:c,left:isNaN(d)?0:d,right:isNaN(l)?0:l,bottom:isNaN(u)?0:u},e,s,n,a,isNaN(r)?void 0:r,isNaN(o)?void 0:o),this.contentEl.addEventListener("wheel",i=>this.engine.handleWheel(i)),this.contentEl.addEventListener("gesturestart",i=>this.engine.handleGesturestart(i)),window.addEventListener("gesturechange",i=>this.engine.handleGesturechange(i)),window.addEventListener("gestureend",i=>this.engine.handleGestureend(i)),this.contentEl.addEventListener("mousedown",i=>this.engine.handleMousedown(i)),window.addEventListener("mousemove",i=>this.engine.handleMousemove(i)),window.addEventListener("mouseup",i=>this.engine.handleMouseup(i)),this.contentEl.addEventListener("touchstart",i=>this.engine.handleTouchstart(i)),window.addEventListener("touchmove",i=>this.engine.handleTouchmove(i)),window.addEventListener("touchend",i=>this.engine.handleTouchend(i)),this.engine.addEventListener("update",()=>{const i=this.engine.translateX.toString(),f=this.engine.translateY.toString(),p=this.engine.scale.toString(),b=this.engine.rotate.toString();this.getAttribute("translate-x")!==i&&this.setAttribute("translate-x",i),this.getAttribute("translate-y")!==f&&this.setAttribute("translate-y",f),this.getAttribute("scale")!==p&&this.setAttribute("scale",p),this.getAttribute("rotate")!==b&&this.setAttribute("rotate",b),this.dispatchEvent(new Event("update"))})}disconnectedCallback(){this.engine.destroy()}attributeChangedCallback(e,s,n){if(this.engine)switch(e){case"translate-x":const a=Number(n);this.engine.translateX!==a&&(this.engine.translateX=a,this.engine.update());break;case"translate-y":const r=Number(n);this.engine.translateY!==r&&(this.engine.translateY=r,this.engine.update());break;case"scale":const o=Number(n);this.engine.scale!==o&&(this.engine.scale=o,this.engine.update());break;case"rotate":const c=Number(n);this.engine.rotate!==c&&(this.engine.rotate=c,this.engine.update());break;case"min-scale":const l=Number(n);!isNaN(l)&&this.engine.minScale!==l&&(this.engine.minScale=l,this.engine.update());break;case"max-scale":const u=Number(n);!isNaN(u)&&this.engine.maxScale!==u&&(this.engine.maxScale=u,this.engine.update());break;case"offset-top":case"offset-right":case"offset-bottom":case"offset-left":const d=Number(this.getAttribute("offset-top")||"0"),i=Number(this.getAttribute("offset-right")||"0"),f=Number(this.getAttribute("offset-bottom")||"0"),p=Number(this.getAttribute("offset-left")||"0");this.engine.offset={top:d,right:i,bottom:f,left:p},this.engine.update();break}}get canvasWidth(){return this.engine.canvasBounds.width}get canvasHeight(){return this.engine.canvasBounds.height}applyTransform(e,s,n){this.engine.applyTransform(e,s,n)}normalizeClientCoords(e,s){return this.engine.normalizeClientCoords(e,s)}composePoint(e,s){return this.engine.composePoint(e,s)}}X(B,"observedAttributes",["translate-x","translate-y","scale","rotate","min-scale","max-scale","offset-top","offset-right","offset-bottom","offset-left"]),customElements.get("zoom-pinch")||customElements.define("zoom-pinch",B)}));
35
+ `;const e=Number(this.getAttribute("translate-x")||"0"),s=Number(this.getAttribute("translate-y")||"0"),n=Number(this.getAttribute("scale")||"1"),a=Number(this.getAttribute("rotate")||"0"),i=Number(this.getAttribute("min-scale")),r=Number(this.getAttribute("max-scale")),c=Number(this.getAttribute("offset-top")),l=Number(this.getAttribute("offset-right")),u=Number(this.getAttribute("offset-bottom")),d=Number(this.getAttribute("offset-left")),g=this.getAttribute("clamp-bounds")==="true";this.getAttribute("rotation"),this.engine=new y(this.contentEl,{top:isNaN(c)?100:c,left:isNaN(d)?0:d,right:isNaN(l)?0:l,bottom:isNaN(u)?0:u},e,s,n,a,isNaN(i)?void 0:i,isNaN(r)?void 0:r,g),this.contentEl.addEventListener("wheel",h=>this.engine.handleWheel(h)),this.contentEl.addEventListener("gesturestart",h=>this.engine.handleGesturestart(h)),window.addEventListener("gesturechange",h=>this.engine.handleGesturechange(h)),window.addEventListener("gestureend",h=>this.engine.handleGestureend(h)),this.contentEl.addEventListener("mousedown",h=>this.engine.handleMousedown(h)),window.addEventListener("mousemove",h=>this.engine.handleMousemove(h)),window.addEventListener("mouseup",h=>this.engine.handleMouseup(h)),this.contentEl.addEventListener("touchstart",h=>this.engine.handleTouchstart(h)),window.addEventListener("touchmove",h=>this.engine.handleTouchmove(h)),window.addEventListener("touchend",h=>this.engine.handleTouchend(h)),this.engine.addEventListener("update",()=>{const h=this.engine.translateX.toString(),f=this.engine.translateY.toString(),v=this.engine.scale.toString(),m=this.engine.rotate.toString();this.getAttribute("translate-x")!==h&&this.setAttribute("translate-x",h),this.getAttribute("translate-y")!==f&&this.setAttribute("translate-y",f),this.getAttribute("scale")!==v&&this.setAttribute("scale",v),this.getAttribute("rotate")!==m&&this.setAttribute("rotate",m),this.dispatchEvent(new Event("update"))}),this.engine.addEventListener("init",()=>{this.dispatchEvent(new Event("init"))})}disconnectedCallback(){this.engine.destroy()}attributeChangedCallback(e,s,n){if(this.engine)switch(e){case"translate-x":const a=Number(n);this.engine.translateX!==a&&(this.engine.translateX=a,this.engine.update());break;case"translate-y":const i=Number(n);this.engine.translateY!==i&&(this.engine.translateY=i,this.engine.update());break;case"scale":const r=Number(n);this.engine.scale!==r&&(this.engine.scale=r,this.engine.update());break;case"rotate":const c=Number(n);this.engine.rotate!==c&&(this.engine.rotate=c,this.engine.update());break;case"min-scale":const l=Number(n);!isNaN(l)&&this.engine.minScale!==l&&(this.engine.minScale=l,this.engine.update());break;case"max-scale":const u=Number(n);!isNaN(u)&&this.engine.maxScale!==u&&(this.engine.maxScale=u,this.engine.update());break;case"offset-top":case"offset-right":case"offset-bottom":case"offset-left":const d=Number(this.getAttribute("offset-top")||"0"),g=Number(this.getAttribute("offset-right")||"0"),h=Number(this.getAttribute("offset-bottom")||"0"),f=Number(this.getAttribute("offset-left")||"0");this.engine.offset={top:d,right:g,bottom:h,left:f},this.engine.update();break;case"clamp-bounds":const v=n==="true";this.engine.clampBounds!==v&&(this.engine.clampBounds=v,this.engine.setTranslateFromUserGesture(this.engine.translateX,this.engine.translateY),this.engine.update());break;case"rotation":const m=n==="true";this.engine.rotation!==m&&(this.engine.rotation=m,this.engine.update())}}get canvasWidth(){return this.engine.canvasBounds.width}get canvasHeight(){return this.engine.canvasBounds.height}applyTransform(e,s,n){this.engine.applyTransform(e,s,n)}normalizeClientCoords(e,s){return this.engine.normalizeClientCoords(e,s)}composePoint(e,s){return this.engine.composePoint(e,s)}}Y(C,"observedAttributes",["translate-x","translate-y","scale","rotate","min-scale","max-scale","offset-top","offset-right","offset-bottom","offset-left","clamp-bounds","rotation"]),customElements.get("zoom-pinch")||customElements.define("zoom-pinch",C)}));
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@zoompinch/elements",
3
3
  "description": "Custom elements wrapper ZoomPinch - reactive pinch & zoom component",
4
- "version": "0.0.15",
4
+ "version": "0.0.18",
5
5
  "private": false,
6
6
  "type": "module",
7
7
  "main": "./dist/zoompinch-elements.umd.js",
@@ -26,7 +26,7 @@
26
26
  "vite": "^6.4.1"
27
27
  },
28
28
  "dependencies": {
29
- "@zoompinch/core": "^0.0.15"
29
+ "@zoompinch/core": "^0.0.18"
30
30
  },
31
31
  "publishConfig": {
32
32
  "access": "public"