@zoompinch/vue 0.0.14 → 0.0.16

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,379 @@
1
+ # @zoompinch/vue
2
+
3
+ Vue 3 bindings 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/vue
21
+ ```
22
+
23
+ ## Complete Example
24
+
25
+ ```vue
26
+ <template>
27
+ <zoompinch
28
+ ref="zoompinchRef"
29
+ v-model:transform="transform"
30
+ :offset="{ top: 0, right: 0, bottom: 0, left: 0 }"
31
+ :min-scale="0.5"
32
+ :max-scale="4"
33
+ :clamp-bounds="false"
34
+ :rotation="true"
35
+ :mouse="false"
36
+ :wheel="true"
37
+ :touch="true"
38
+ :gesture="true"
39
+ @init="handleInit"
40
+ @click="handleClick"
41
+ class="viewer"
42
+ >
43
+ <img width="1536" height="2048" src="https://imagedelivery.net/mudX-CmAqIANL8bxoNCToA/489df5b2-38ce-46e7-32e0-d50170e8d800/public" />
44
+ <template #matrix="{ composePoint, normalizeClientCoords, canvasWidth, canvasHeight }">
45
+ <svg width="100%" height="100%">
46
+ <!-- Center marker -->
47
+ <circle :cx="composePoint(canvasWidth / 2, canvasHeight / 2)[0]" :cy="composePoint(canvasWidth / 2, canvasHeight / 2)[1]" r="8" fill="red" />
48
+ </svg>
49
+ </template>
50
+ </zoompinch>
51
+ </template>
52
+
53
+ <script setup lang="ts">
54
+ import { ref } from 'vue';
55
+ import { Zoompinch } from '@zoompinch/vue';
56
+
57
+ const zoompinchRef = ref<InstanceType<typeof Zoompinch>>();
58
+ const transform = ref({
59
+ translateX: 0,
60
+ translateY: 0,
61
+ scale: 1,
62
+ rotate: 0
63
+ });
64
+ const clickPoint = ref<[number, number] | null>(null);
65
+
66
+ function handleInit() {
67
+ // Center canvas on initialization
68
+ zoompinchRef.value?.applyTransform(1, [0.5, 0.5], [0.5, 0.5], 0);
69
+ }
70
+
71
+ function handleTransformUpdate(newTransform) {
72
+ console.log('Transform updated:', newTransform);
73
+ }
74
+
75
+ function handleClick(event: MouseEvent) {
76
+ if (!zoompinchRef.value) return;
77
+ const [x, y] = zoompinchRef.value.normalizeClientCoords(event.clientX, event.clientY);
78
+ clickPoint.value = [x, y];
79
+ }
80
+ </script>
81
+
82
+ <style scoped>
83
+ .zoompinch {
84
+ width: 800px;
85
+ height: 600px;
86
+ border: 1px solid #f00;
87
+ }
88
+ </style>
89
+ ```
90
+
91
+ ---
92
+
93
+ ## API Reference
94
+
95
+ ### Props
96
+
97
+ | Prop | Type | Default | Description |
98
+ |------|------|---------|-------------|
99
+ | `transform` | `Transform` | `{ translateX: 0, translateY: 0, scale: 1, rotate: 0 }` | Current transform state (v-model) |
100
+ | `offset` | `Offset` | `{ top: 0, right: 0, bottom: 0, left: 0 }` | Inner padding/offset within container |
101
+ | `min-scale` | `number` | `0.5` | Minimum scale (user gestures only) |
102
+ | `max-scale` | `number` | `10` | Maximum scale (user gestures only) |
103
+ | `clamp-bounds` | `boolean` | `false` | Clamp panning within bounds (user gestures only) |
104
+ | `rotation` | `boolean` | `true` | Enable rotation gestures |
105
+ | `mouse` | `boolean` | `true` | Enable mouse drag |
106
+ | `wheel` | `boolean` | `true` | Enable wheel/trackpad |
107
+ | `touch` | `boolean` | `true` | Enable touch gestures |
108
+ | `gesture` | `boolean` | `true` | Enable Safari gesture events |
109
+
110
+ **Note:** `min-scale`, `max-scale`, `rotation`, and `clamp-bounds` only apply during user interaction. Programmatic changes via ref methods are unrestricted.
111
+
112
+ ### Events
113
+
114
+ | Event | Payload | Description |
115
+ |-------|---------|-------------|
116
+ | `@init` | `void` | Fired when canvas dimensions are available |
117
+ | `@update:transform` | `Transform` | Fired when transform changes (v-model) |
118
+
119
+ ```vue
120
+ <zoompinch
121
+ @init="handleInit"
122
+ @update:transform="handleTransformUpdate"
123
+ >
124
+ <!-- content -->
125
+ </zoompinch>
126
+ ```
127
+
128
+ ### Template Ref Methods
129
+
130
+ Access methods via template ref:
131
+
132
+ ```typescript
133
+ const zoompinchRef = ref<InstanceType<typeof Zoompinch>>();
134
+
135
+ // Call methods
136
+ zoompinchRef.value?.applyTransform(scale, wrapperCoords, canvasCoords, rotate?);
137
+ zoompinchRef.value?.normalizeClientCoords(clientX, clientY);
138
+ zoompinchRef.value?.composePoint(x, y);
139
+ zoompinchRef.value?.rotateCanvas(x, y, radians);
140
+
141
+ // Access properties
142
+ zoompinchRef.value?.canvasWidth;
143
+ zoompinchRef.value?.canvasHeight;
144
+ ```
145
+
146
+ #### `applyTransform(scale, wrapperCoords, canvasCoords, rotate?)`
147
+
148
+ Apply transform by anchoring a canvas point to a wrapper point.
149
+
150
+ **Parameters:**
151
+ - `scale: number` - Target scale
152
+ - `wrapperCoords: [number, number]` - Wrapper position (0-1, 0.5 = center)
153
+ - `canvasCoords: [number, number]` - Canvas position (0-1, 0.5 = center)
154
+ - `rotate?: number` - Optional rotation in radians
155
+
156
+ **Examples:**
157
+
158
+ ```typescript
159
+ // Center canvas at scale 1
160
+ zoompinchRef.value?.applyTransform(1, [0.5, 0.5], [0.5, 0.5]);
161
+
162
+ // Zoom to 2x, keep centered
163
+ zoompinchRef.value?.applyTransform(2, [0.5, 0.5], [0.5, 0.5]);
164
+
165
+ // Anchor canvas top-left to wrapper center
166
+ zoompinchRef.value?.applyTransform(1.5, [0.5, 0.5], [0, 0]);
167
+
168
+ // Set rotation
169
+ zoompinchRef.value?.applyTransform(1, [0.5, 0.5], [0.5, 0.5], Math.PI / 4);
170
+ ```
171
+
172
+ #### `normalizeClientCoords(clientX, clientY)`
173
+
174
+ Convert global client coordinates to canvas coordinates.
175
+
176
+ **Parameters:**
177
+ - `clientX: number` - Global X from event
178
+ - `clientY: number` - Global Y from event
179
+
180
+ **Returns:** `[number, number]` - Canvas coordinates in pixels
181
+
182
+ **Example:**
183
+
184
+ ```typescript
185
+ function handleClick(event: MouseEvent) {
186
+ const [x, y] = zoompinchRef.value!.normalizeClientCoords(
187
+ event.clientX,
188
+ event.clientY
189
+ );
190
+ console.log('Canvas position:', x, y);
191
+ }
192
+ ```
193
+
194
+ #### `composePoint(x, y)`
195
+
196
+ Convert canvas coordinates to wrapper coordinates (accounts for transform).
197
+
198
+ **Parameters:**
199
+ - `x: number` - Canvas X in pixels
200
+ - `y: number` - Canvas Y in pixels
201
+
202
+ **Returns:** `[number, number]` - Wrapper coordinates in pixels
203
+
204
+ **Example:**
205
+
206
+ ```typescript
207
+ // Get wrapper position for canvas center
208
+ const [wrapperX, wrapperY] = zoompinchRef.value!.composePoint(
209
+ canvasWidth / 2,
210
+ canvasHeight / 2
211
+ );
212
+ ```
213
+
214
+ #### `rotateCanvas(x, y, radians)`
215
+
216
+ Rotate canvas around a specific canvas point.
217
+
218
+ **Parameters:**
219
+ - `x: number` - Canvas X (rotation center)
220
+ - `y: number` - Canvas Y (rotation center)
221
+ - `radians: number` - Rotation angle
222
+
223
+ **Example:**
224
+
225
+ ```typescript
226
+ // Rotate 90° around canvas center
227
+ const centerX = zoompinchRef.value!.canvasWidth / 2;
228
+ const centerY = zoompinchRef.value!.canvasHeight / 2;
229
+ zoompinchRef.value?.rotateCanvas(centerX, centerY, Math.PI / 2);
230
+ ```
231
+
232
+ ### Reactive Properties
233
+
234
+ Access current canvas dimensions:
235
+
236
+ ```typescript
237
+ const width = zoompinchRef.value?.canvasWidth; // number
238
+ const height = zoompinchRef.value?.canvasHeight; // number
239
+ ```
240
+
241
+ ### Matrix Slot
242
+
243
+ Scoped slot for rendering overlay elements that follow the canvas transform.
244
+
245
+ **Scoped Props:**
246
+
247
+ | Prop | Type | Description |
248
+ |------|------|-------------|
249
+ | `composePoint` | `(x: number, y: number) => [number, number]` | Canvas → Wrapper coords |
250
+ | `normalizeClientCoords` | `(clientX: number, clientY: number) => [number, number]` | Client → Canvas coords |
251
+ | `canvasWidth` | `number` | Current canvas width |
252
+ | `canvasHeight` | `number` | Current canvas height |
253
+
254
+ **Note:** `applyTransform` and `rotateCanvas` are NOT available in the slot. Use component ref instead.
255
+
256
+ **Example:**
257
+
258
+ ```vue
259
+ <zoompinch>
260
+ <img width="1920" height="1080" src="image.jpg" />
261
+
262
+ <template #matrix="{ composePoint, normalizeClientCoords, canvasWidth, canvasHeight }">
263
+ <svg width="100%" height="100%">
264
+ <circle
265
+ :cx="composePoint(canvasWidth / 2, canvasHeight / 2)[0]"
266
+ :cy="composePoint(canvasWidth / 2, canvasHeight / 2)[1]"
267
+ r="8"
268
+ fill="red"
269
+ />
270
+ </svg>
271
+ </template>
272
+ </zoompinch>
273
+ ```
274
+
275
+ ## Coordinate Systems
276
+
277
+ ### 1. Canvas Coordinates (Absolute)
278
+
279
+ Absolute pixels within canvas content.
280
+ - Origin: `(0, 0)` at top-left
281
+ - Range: `0` to `canvasWidth`, `0` to `canvasHeight`
282
+
283
+ ```typescript
284
+ const [canvasX, canvasY] = normalizeClientCoords(event.clientX, event.clientY);
285
+ ```
286
+
287
+ ### 2. Wrapper Coordinates (Absolute)
288
+
289
+ Absolute pixels within viewport/wrapper.
290
+ - Origin: `(0, 0)` at top-left (accounting for offset)
291
+ - Range: `0` to `wrapperWidth`, `0` to `wrapperHeight`
292
+
293
+ ```typescript
294
+ const [wrapperX, wrapperY] = composePoint(canvasX, canvasY);
295
+ ```
296
+
297
+ ### 3. Relative Coordinates (0-1)
298
+
299
+ Normalized coordinates for `applyTransform`.
300
+ - Range: `0.0` to `1.0`
301
+ - `0.5` = center, `1.0` = bottom-right
302
+
303
+ ```typescript
304
+ [0, 0] // top-left
305
+ [0.5, 0.5] // center
306
+ [1, 1] // bottom-right
307
+ ```
308
+
309
+ **Conversion Flow:**
310
+
311
+ ```
312
+ Client Coords → normalizeClientCoords() → Canvas Coords → composePoint() → Wrapper Coords
313
+ ```
314
+
315
+ ## Best Practices
316
+
317
+ 1. **Always specify image dimensions** to avoid layout shifts:
318
+ ```vue
319
+ <img width="1920" height="1080" src="image.jpg" />
320
+ ```
321
+
322
+ 2. **Center content on init:**
323
+ ```typescript
324
+ function handleInit() {
325
+ zoompinchRef.value?.applyTransform(1, [0.5, 0.5], [0.5, 0.5]);
326
+ }
327
+ ```
328
+
329
+ 3. **Prevent image drag:**
330
+ ```vue
331
+ <img src="image.jpg" draggable="false" style="user-select: none;" />
332
+ ```
333
+
334
+ 4. **Use clamp bounds for image viewers:**
335
+ ```vue
336
+ <zoompinch :clamp-bounds="true" :min-scale="0.5" :max-scale="4">
337
+ ```
338
+ ## Styling
339
+
340
+ Minimal base styles are applied. Customize via class or style:
341
+
342
+ ```vue
343
+ <zoompinch
344
+ class="my-viewer"
345
+ style="width: 100%; height: 600px; border: 1px solid #ccc;"
346
+ >
347
+ <!-- content -->
348
+ </zoompinch>
349
+ ```
350
+
351
+ **Internal CSS classes:**
352
+
353
+ ```css
354
+ .zoompinch /* Container */
355
+ .zoompinch > .canvas /* Canvas wrapper */
356
+ .zoompinch > .matrix /* Matrix overlay */
357
+ ```
358
+
359
+ ## Browser Support
360
+
361
+ - ✅ Chrome/Edge (latest)
362
+ - ✅ Firefox (latest)
363
+ - ✅ Safari (latest, including iOS)
364
+ - ✅ Mobile browsers (iOS Safari, Chrome Mobile)
365
+
366
+ ## License
367
+
368
+ MIT
369
+
370
+ ---
371
+
372
+ ## Related
373
+
374
+ - [@zoompinch/core](https://www.npmjs.com/package/@zoompinch/core) - Core engine
375
+ - [@zoompinch/elements](https://www.npmjs.com/package/@zoompinch/elements) - Web Components
376
+
377
+ ---
378
+
379
+ Built with ❤️ by Elya Maurice Conrad
@@ -1,4 +1,5 @@
1
1
  import { Transform, Zoompinch } from '@zoompinch/core';
2
+ import { VNode } from 'vue';
2
3
  type __VLS_Props = {
3
4
  transform?: Transform;
4
5
  offset?: {
@@ -9,7 +10,7 @@ type __VLS_Props = {
9
10
  };
10
11
  maxScale?: number;
11
12
  minScale?: number;
12
- bounds?: boolean;
13
+ clampBounds?: boolean;
13
14
  rotation?: boolean;
14
15
  mouse?: boolean;
15
16
  wheel?: boolean;
@@ -18,11 +19,22 @@ type __VLS_Props = {
18
19
  };
19
20
  declare function __VLS_template(): {
20
21
  attrs: Partial<{}>;
21
- slots: {
22
- default?(_: {}): any;
23
- matrix?(_: {
22
+ slots: Readonly<{
23
+ default: () => VNode | VNode[];
24
+ matrix: (args: {
24
25
  composePoint: (x: number, y: number) => [number, number];
25
- }): any;
26
+ normalizeClientCoords: (clientX: number, clientY: number) => [number, number];
27
+ canvasWidth: number;
28
+ canvasHeight: number;
29
+ }) => VNode | VNode[];
30
+ }> & {
31
+ default: () => VNode | VNode[];
32
+ matrix: (args: {
33
+ composePoint: (x: number, y: number) => [number, number];
34
+ normalizeClientCoords: (clientX: number, clientY: number) => [number, number];
35
+ canvasWidth: number;
36
+ canvasHeight: number;
37
+ }) => VNode | VNode[];
26
38
  };
27
39
  refs: {
28
40
  zoompinchRef: HTMLDivElement;
@@ -35,12 +47,17 @@ declare const __VLS_component: import('vue').DefineComponent<__VLS_Props, {
35
47
  composePoint: import('vue').Ref<(x: number, y: number) => [number, number], (x: number, y: number) => [number, number]>;
36
48
  normalizeClientCoords: (clientX: number, clientY: number) => [number, number];
37
49
  zoompinchEngine: import('vue').Ref<Zoompinch | undefined, Zoompinch | undefined>;
50
+ canvasWidth: import('vue').Ref<number, number>;
51
+ canvasHeight: import('vue').Ref<number, number>;
52
+ rotateCanvas: (x: number, y: number, radians: number) => void;
38
53
  }, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {
39
54
  "update:transform": (transform: Transform) => any;
55
+ init: () => any;
40
56
  dragGestureStart: (event: MouseEvent | TouchEvent | WheelEvent) => any;
41
57
  dragGestureEnd: (event: MouseEvent | TouchEvent | WheelEvent) => any;
42
58
  }, string, import('vue').PublicProps, Readonly<__VLS_Props> & Readonly<{
43
59
  "onUpdate:transform"?: ((transform: Transform) => any) | undefined;
60
+ onInit?: (() => any) | undefined;
44
61
  onDragGestureStart?: ((event: MouseEvent | TouchEvent | WheelEvent) => any) | undefined;
45
62
  onDragGestureEnd?: ((event: MouseEvent | TouchEvent | WheelEvent) => any) | undefined;
46
63
  }>, {
@@ -53,7 +70,7 @@ declare const __VLS_component: import('vue').DefineComponent<__VLS_Props, {
53
70
  };
54
71
  maxScale: number;
55
72
  minScale: number;
56
- bounds: boolean;
73
+ clampBounds: boolean;
57
74
  rotation: boolean;
58
75
  mouse: boolean;
59
76
  wheel: boolean;
package/dist/style.css CHANGED
@@ -1 +1 @@
1
- .zoompinch[data-v-681ec398]{touch-action:none;overflow:hidden;width:100%;height:100%;position:relative}.zoompinch>.canvas[data-v-681ec398]{position:absolute}.zoompinch>.matrix[data-v-681ec398]{pointer-events:none;width:100%;height:100%;position:absolute;top:0;left:0}
1
+ .zoompinch[data-v-13174681]{touch-action:none;overflow:hidden;width:100%;height:100%;position:relative}.zoompinch>.canvas[data-v-13174681]{position:absolute}.zoompinch>.matrix[data-v-13174681]{pointer-events:none;width:100%;height:100%;position:absolute;top:0;left:0}
@@ -1,28 +1,30 @@
1
- import { defineComponent as G, ref as u, onMounted as x, watch as l, onUnmounted as B, createElementBlock as C, openBlock as M, createElementVNode as L, renderSlot as y, createCommentVNode as k } from "vue";
2
- import { Zoompinch as Z } from "@zoompinch/core";
3
- const N = { class: "canvas" }, P = { class: "matrix" }, W = /* @__PURE__ */ G({
1
+ import { defineComponent as M, ref as o, onMounted as k, watch as r, onUnmounted as W, useSlots as Z, createElementBlock as N, openBlock as P, createElementVNode as S, renderSlot as T, createCommentVNode as $ } from "vue";
2
+ import { Zoompinch as H } from "@zoompinch/core";
3
+ const R = { class: "canvas" }, U = { class: "matrix" }, V = /* @__PURE__ */ M({
4
4
  __name: "Zoompinch",
5
5
  props: {
6
6
  transform: { default: () => ({ translateX: 0, translateY: 0, scale: 1, rotate: 0 }) },
7
7
  offset: { default: () => ({ left: 0, top: 0, right: 0, bottom: 0 }) },
8
8
  maxScale: { default: 10 },
9
9
  minScale: { default: 0.5 },
10
- bounds: { type: Boolean, default: !1 },
10
+ clampBounds: { type: Boolean, default: !1 },
11
11
  rotation: { type: Boolean, default: !0 },
12
12
  mouse: { type: Boolean, default: !0 },
13
13
  wheel: { type: Boolean, default: !0 },
14
14
  touch: { type: Boolean, default: !0 },
15
15
  gesture: { type: Boolean, default: !0 }
16
16
  },
17
- emits: ["update:transform", "dragGestureStart", "dragGestureEnd"],
18
- setup(o, { expose: i, emit: r }) {
19
- const a = o, d = r, v = u(), e = u(), f = u(!1);
17
+ emits: ["update:transform", "init", "dragGestureStart", "dragGestureEnd"],
18
+ setup(s, { expose: d, emit: l }) {
19
+ const a = s, i = l, c = o(), e = o(), h = o(!1);
20
20
  window.zoompinchEngine = e;
21
- const s = u(() => {
21
+ const v = o(() => {
22
22
  throw new Error("Not initialized yet");
23
- });
24
- x(() => {
25
- v.value && (e.value = new Z(v.value, a.offset, a.transform.translateX, a.transform.translateY, a.transform.scale, a.transform.rotate, a.minScale, a.maxScale), e.value.addEventListener("update", () => {
23
+ }), m = o(0), f = o(0);
24
+ k(() => {
25
+ c.value && (e.value = new H(c.value, a.offset, a.transform.translateX, a.transform.translateY, a.transform.scale, a.transform.rotate, a.minScale, a.maxScale, a.clampBounds, a.rotation), e.value.addEventListener("init", () => {
26
+ i("init");
27
+ }), e.value.addEventListener("update", () => {
26
28
  if (!e.value) return;
27
29
  const t = {
28
30
  translateX: e.value.translateX,
@@ -30,93 +32,107 @@ const N = { class: "canvas" }, P = { class: "matrix" }, W = /* @__PURE__ */ G({
30
32
  scale: e.value.scale,
31
33
  rotate: e.value.rotate
32
34
  };
33
- (t.translateX !== a.transform.translateX || t.translateY !== a.transform.translateY || t.scale !== a.transform.scale || t.rotate !== a.transform.rotate) && d("update:transform", t), s.value = (n, c) => e.value.composePoint(n, c);
35
+ (t.translateX !== a.transform.translateX || t.translateY !== a.transform.translateY || t.scale !== a.transform.scale || t.rotate !== a.transform.rotate) && i("update:transform", t), v.value = (n, u) => e.value.composePoint(n, u), m.value = e.value.canvasBounds.width, f.value = e.value.canvasBounds.height;
34
36
  }), e.value.addEventListener("init", () => {
35
- f.value = !0;
37
+ h.value = !0;
36
38
  }));
37
- }), l(
39
+ }), r(
38
40
  () => a.transform,
39
41
  () => {
40
42
  e.value && (e.value.translateX !== a.transform.translateX || e.value.translateY !== a.transform.translateY || e.value.scale !== a.transform.scale || e.value.rotate !== a.transform.rotate) && (e.value.translateX = a.transform.translateX, e.value.translateY = a.transform.translateY, e.value.scale = a.transform.scale, e.value.rotate = a.transform.rotate, e.value.update());
41
43
  },
42
44
  { deep: !0 }
43
- ), l(
45
+ ), r(
44
46
  () => a.offset,
45
47
  (t) => {
46
48
  e.value && (e.value.offset = t, e.value.update());
47
49
  },
48
50
  { deep: !0 }
49
- ), l(
51
+ ), r(
50
52
  () => a.minScale,
51
53
  (t) => {
52
54
  e.value && (e.value.minScale = t, e.value.update());
53
55
  }
54
- ), l(
56
+ ), r(
55
57
  () => a.maxScale,
56
58
  (t) => {
57
59
  e.value && (e.value.maxScale = t, e.value.update());
58
60
  }
59
- );
60
- const z = (t, n, c, _) => {
61
- e.value && (_ !== void 0 && (e.value.rotate = _), e.value.applyTransform(t, n, c));
62
- }, S = (t) => {
61
+ ), r(() => a.clampBounds, (t) => {
62
+ e.value && (e.value.clampBounds = t, e.value.setTranslateFromUserGesture(e.value.translateX, e.value.translateY), e.value.update());
63
+ }), r(() => a.rotation, (t) => {
64
+ e.value && (e.value.rotation = t, e.value.update());
65
+ });
66
+ const X = (t, n, u, y) => {
67
+ e.value && (y !== void 0 && (e.value.rotate = y), e.value.applyTransform(t, n, u));
68
+ }, Y = (t) => {
63
69
  e.value && a.wheel && e.value.handleWheel(t);
64
- }, T = (t) => {
70
+ }, G = (t) => {
65
71
  e.value && a.gesture && e.value.handleGesturestart(t);
66
- }, m = (t) => {
72
+ }, p = (t) => {
67
73
  e.value && a.gesture && e.value.handleGesturechange(t);
68
- }, h = (t) => {
74
+ }, w = (t) => {
69
75
  e.value && a.gesture && e.value.handleGestureend(t);
70
- }, X = (t) => {
76
+ }, z = (t) => {
71
77
  e.value && a.mouse && e.value.handleMousedown(t);
72
- }, p = (t) => {
78
+ }, g = (t) => {
73
79
  e.value && a.mouse && e.value.handleMousemove(t);
74
- }, w = (t) => {
80
+ }, E = (t) => {
75
81
  e.value && a.mouse && e.value.handleMouseup(t);
76
- }, Y = (t) => {
82
+ }, x = (t) => {
77
83
  e.value && a.touch && e.value.handleTouchstart(t);
78
- }, E = (t) => {
84
+ }, L = (t) => {
79
85
  e.value && a.touch && e.value.handleTouchmove(t);
80
- }, g = (t) => {
86
+ }, _ = (t) => {
81
87
  e.value && a.touch && e.value.handleTouchend(t);
82
88
  };
83
- return window.addEventListener("gesturechange", m), window.addEventListener("gestureend", h), window.addEventListener("mousemove", p), window.addEventListener("mouseup", w), window.addEventListener("touchmove", E), window.addEventListener("touchend", g), B(() => {
84
- window.removeEventListener("gesturechange", m), window.removeEventListener("gestureend", h), window.removeEventListener("mousemove", p), window.removeEventListener("mouseup", w), window.removeEventListener("touchmove", E), window.removeEventListener("touchend", g);
85
- }), i({
86
- applyTransform: z,
87
- composePoint: s,
88
- normalizeClientCoords: (t, n) => {
89
- if (!e.value)
90
- throw new Error("Zoompinch engine not initialized");
91
- return e.value.normalizeClientCoords(t, n);
92
- },
93
- zoompinchEngine: e
94
- }), (t, n) => (M(), C("div", {
89
+ window.addEventListener("gesturechange", p), window.addEventListener("gestureend", w), window.addEventListener("mousemove", g), window.addEventListener("mouseup", E), window.addEventListener("touchmove", L), window.addEventListener("touchend", _), W(() => {
90
+ window.removeEventListener("gesturechange", p), window.removeEventListener("gestureend", w), window.removeEventListener("mousemove", g), window.removeEventListener("mouseup", E), window.removeEventListener("touchmove", L), window.removeEventListener("touchend", _);
91
+ });
92
+ const B = (t, n) => {
93
+ if (!e.value)
94
+ throw new Error("Zoompinch engine not initialized");
95
+ return e.value.normalizeClientCoords(t, n);
96
+ }, C = (t, n, u) => {
97
+ e.value && e.value.rotateCanvas(t, n, u);
98
+ };
99
+ return Z(), d({
100
+ applyTransform: X,
101
+ composePoint: v,
102
+ normalizeClientCoords: B,
103
+ zoompinchEngine: e,
104
+ canvasWidth: m,
105
+ canvasHeight: f,
106
+ rotateCanvas: C
107
+ }), (t, n) => (P(), N("div", {
95
108
  ref_key: "zoompinchRef",
96
- ref: v,
109
+ ref: c,
97
110
  class: "zoompinch",
98
- onWheel: S,
99
- onGesturestart: T,
100
- onMousedown: X,
101
- onTouchstart: Y
111
+ onWheel: Y,
112
+ onGesturestart: G,
113
+ onMousedown: z,
114
+ onTouchstart: x
102
115
  }, [
103
- L("div", N, [
104
- y(t.$slots, "default", {}, void 0, !0)
116
+ S("div", R, [
117
+ T(t.$slots, "default", {}, void 0, !0)
105
118
  ]),
106
- L("div", P, [
107
- f.value && s.value ? y(t.$slots, "matrix", {
119
+ S("div", U, [
120
+ h.value && v.value ? T(t.$slots, "matrix", {
108
121
  key: 0,
109
- composePoint: s.value
110
- }, void 0, !0) : k("", !0)
122
+ composePoint: v.value,
123
+ normalizeClientCoords: B,
124
+ canvasWidth: m.value,
125
+ canvasHeight: f.value
126
+ }, void 0, !0) : $("", !0)
111
127
  ])
112
128
  ], 544));
113
129
  }
114
- }), $ = (o, i) => {
115
- const r = o.__vccOpts || o;
116
- for (const [a, d] of i)
117
- r[a] = d;
118
- return r;
119
- }, I = /* @__PURE__ */ $(W, [["__scopeId", "data-v-681ec398"]]);
130
+ }), b = (s, d) => {
131
+ const l = s.__vccOpts || s;
132
+ for (const [a, i] of d)
133
+ l[a] = i;
134
+ return l;
135
+ }, O = /* @__PURE__ */ b(V, [["__scopeId", "data-v-13174681"]]);
120
136
  export {
121
- I as Zoompinch
137
+ O as Zoompinch
122
138
  };
@@ -1 +1 @@
1
- (function(o,a){typeof exports=="object"&&typeof module<"u"?a(exports,require("vue"),require("@zoompinch/core")):typeof define=="function"&&define.amd?define(["exports","vue","@zoompinch/core"],a):(o=typeof globalThis<"u"?globalThis:o||self,a(o.ZoompinchVue={},o.Vue,o.ZoompinchCore))})(this,(function(o,a,y){"use strict";const L={class:"canvas"},S={class:"matrix"},T=((s,i)=>{const l=s.__vccOpts||s;for(const[n,d]of i)l[n]=d;return l})(a.defineComponent({__name:"Zoompinch",props:{transform:{default:()=>({translateX:0,translateY:0,scale:1,rotate:0})},offset:{default:()=>({left:0,top:0,right:0,bottom:0})},maxScale:{default:10},minScale:{default:.5},bounds:{type:Boolean,default:!1},rotation:{type:Boolean,default:!0},mouse:{type:Boolean,default:!0},wheel:{type:Boolean,default:!0},touch:{type:Boolean,default:!0},gesture:{type:Boolean,default:!0}},emits:["update:transform","dragGestureStart","dragGestureEnd"],setup(s,{expose:i,emit:l}){const n=s,d=l,c=a.ref(),e=a.ref(),m=a.ref(!1);window.zoompinchEngine=e;const u=a.ref(()=>{throw new Error("Not initialized yet")});a.onMounted(()=>{c.value&&(e.value=new y.Zoompinch(c.value,n.offset,n.transform.translateX,n.transform.translateY,n.transform.scale,n.transform.rotate,n.minScale,n.maxScale),e.value.addEventListener("update",()=>{if(!e.value)return;const t={translateX:e.value.translateX,translateY:e.value.translateY,scale:e.value.scale,rotate:e.value.rotate};(t.translateX!==n.transform.translateX||t.translateY!==n.transform.translateY||t.scale!==n.transform.scale||t.rotate!==n.transform.rotate)&&d("update:transform",t),u.value=(r,f)=>e.value.composePoint(r,f)}),e.value.addEventListener("init",()=>{m.value=!0}))}),a.watch(()=>n.transform,()=>{e.value&&(e.value.translateX!==n.transform.translateX||e.value.translateY!==n.transform.translateY||e.value.scale!==n.transform.scale||e.value.rotate!==n.transform.rotate)&&(e.value.translateX=n.transform.translateX,e.value.translateY=n.transform.translateY,e.value.scale=n.transform.scale,e.value.rotate=n.transform.rotate,e.value.update())},{deep:!0}),a.watch(()=>n.offset,t=>{e.value&&(e.value.offset=t,e.value.update())},{deep:!0}),a.watch(()=>n.minScale,t=>{e.value&&(e.value.minScale=t,e.value.update())}),a.watch(()=>n.maxScale,t=>{e.value&&(e.value.maxScale=t,e.value.update())});const z=(t,r,f,_)=>{e.value&&(_!==void 0&&(e.value.rotate=_),e.value.applyTransform(t,r,f))},x=t=>{e.value&&n.wheel&&e.value.handleWheel(t)},X=t=>{e.value&&n.gesture&&e.value.handleGesturestart(t)},v=t=>{e.value&&n.gesture&&e.value.handleGesturechange(t)},h=t=>{e.value&&n.gesture&&e.value.handleGestureend(t)},Y=t=>{e.value&&n.mouse&&e.value.handleMousedown(t)},p=t=>{e.value&&n.mouse&&e.value.handleMousemove(t)},w=t=>{e.value&&n.mouse&&e.value.handleMouseup(t)},C=t=>{e.value&&n.touch&&e.value.handleTouchstart(t)},E=t=>{e.value&&n.touch&&e.value.handleTouchmove(t)},g=t=>{e.value&&n.touch&&e.value.handleTouchend(t)};return window.addEventListener("gesturechange",v),window.addEventListener("gestureend",h),window.addEventListener("mousemove",p),window.addEventListener("mouseup",w),window.addEventListener("touchmove",E),window.addEventListener("touchend",g),a.onUnmounted(()=>{window.removeEventListener("gesturechange",v),window.removeEventListener("gestureend",h),window.removeEventListener("mousemove",p),window.removeEventListener("mouseup",w),window.removeEventListener("touchmove",E),window.removeEventListener("touchend",g)}),i({applyTransform:z,composePoint:u,normalizeClientCoords:(t,r)=>{if(!e.value)throw new Error("Zoompinch engine not initialized");return e.value.normalizeClientCoords(t,r)},zoompinchEngine:e}),(t,r)=>(a.openBlock(),a.createElementBlock("div",{ref_key:"zoompinchRef",ref:c,class:"zoompinch",onWheel:x,onGesturestart:X,onMousedown:Y,onTouchstart:C},[a.createElementVNode("div",L,[a.renderSlot(t.$slots,"default",{},void 0,!0)]),a.createElementVNode("div",S,[m.value&&u.value?a.renderSlot(t.$slots,"matrix",{key:0,composePoint:u.value},void 0,!0):a.createCommentVNode("",!0)])],544))}}),[["__scopeId","data-v-681ec398"]]);o.Zoompinch=T,Object.defineProperty(o,Symbol.toStringTag,{value:"Module"})}));
1
+ (function(o,n){typeof exports=="object"&&typeof module<"u"?n(exports,require("vue"),require("@zoompinch/core")):typeof define=="function"&&define.amd?define(["exports","vue","@zoompinch/core"],n):(o=typeof globalThis<"u"?globalThis:o||self,n(o.ZoompinchVue={},o.Vue,o.ZoompinchCore))})(this,(function(o,n,S){"use strict";const T={class:"canvas"},z={class:"matrix"},X=((l,c)=>{const u=l.__vccOpts||l;for(const[a,i]of c)u[a]=i;return u})(n.defineComponent({__name:"Zoompinch",props:{transform:{default:()=>({translateX:0,translateY:0,scale:1,rotate:0})},offset:{default:()=>({left:0,top:0,right:0,bottom:0})},maxScale:{default:10},minScale:{default:.5},clampBounds:{type:Boolean,default:!1},rotation:{type:Boolean,default:!0},mouse:{type:Boolean,default:!0},wheel:{type:Boolean,default:!0},touch:{type:Boolean,default:!0},gesture:{type:Boolean,default:!0}},emits:["update:transform","init","dragGestureStart","dragGestureEnd"],setup(l,{expose:c,emit:u}){const a=l,i=u,f=n.ref(),e=n.ref(),h=n.ref(!1);window.zoompinchEngine=e;const d=n.ref(()=>{throw new Error("Not initialized yet")}),v=n.ref(0),m=n.ref(0);n.onMounted(()=>{f.value&&(e.value=new S.Zoompinch(f.value,a.offset,a.transform.translateX,a.transform.translateY,a.transform.scale,a.transform.rotate,a.minScale,a.maxScale,a.clampBounds,a.rotation),e.value.addEventListener("init",()=>{i("init")}),e.value.addEventListener("update",()=>{if(!e.value)return;const t={translateX:e.value.translateX,translateY:e.value.translateY,scale:e.value.scale,rotate:e.value.rotate};(t.translateX!==a.transform.translateX||t.translateY!==a.transform.translateY||t.scale!==a.transform.scale||t.rotate!==a.transform.rotate)&&i("update:transform",t),d.value=(r,s)=>e.value.composePoint(r,s),v.value=e.value.canvasBounds.width,m.value=e.value.canvasBounds.height}),e.value.addEventListener("init",()=>{h.value=!0}))}),n.watch(()=>a.transform,()=>{e.value&&(e.value.translateX!==a.transform.translateX||e.value.translateY!==a.transform.translateY||e.value.scale!==a.transform.scale||e.value.rotate!==a.transform.rotate)&&(e.value.translateX=a.transform.translateX,e.value.translateY=a.transform.translateY,e.value.scale=a.transform.scale,e.value.rotate=a.transform.rotate,e.value.update())},{deep:!0}),n.watch(()=>a.offset,t=>{e.value&&(e.value.offset=t,e.value.update())},{deep:!0}),n.watch(()=>a.minScale,t=>{e.value&&(e.value.minScale=t,e.value.update())}),n.watch(()=>a.maxScale,t=>{e.value&&(e.value.maxScale=t,e.value.update())}),n.watch(()=>a.clampBounds,t=>{e.value&&(e.value.clampBounds=t,e.value.setTranslateFromUserGesture(e.value.translateX,e.value.translateY),e.value.update())}),n.watch(()=>a.rotation,t=>{e.value&&(e.value.rotation=t,e.value.update())});const Y=(t,r,s,B)=>{e.value&&(B!==void 0&&(e.value.rotate=B),e.value.applyTransform(t,r,s))},x=t=>{e.value&&a.wheel&&e.value.handleWheel(t)},G=t=>{e.value&&a.gesture&&e.value.handleGesturestart(t)},p=t=>{e.value&&a.gesture&&e.value.handleGesturechange(t)},w=t=>{e.value&&a.gesture&&e.value.handleGestureend(t)},C=t=>{e.value&&a.mouse&&e.value.handleMousedown(t)},E=t=>{e.value&&a.mouse&&e.value.handleMousemove(t)},g=t=>{e.value&&a.mouse&&e.value.handleMouseup(t)},M=t=>{e.value&&a.touch&&e.value.handleTouchstart(t)},_=t=>{e.value&&a.touch&&e.value.handleTouchmove(t)},y=t=>{e.value&&a.touch&&e.value.handleTouchend(t)};window.addEventListener("gesturechange",p),window.addEventListener("gestureend",w),window.addEventListener("mousemove",E),window.addEventListener("mouseup",g),window.addEventListener("touchmove",_),window.addEventListener("touchend",y),n.onUnmounted(()=>{window.removeEventListener("gesturechange",p),window.removeEventListener("gestureend",w),window.removeEventListener("mousemove",E),window.removeEventListener("mouseup",g),window.removeEventListener("touchmove",_),window.removeEventListener("touchend",y)});const L=(t,r)=>{if(!e.value)throw new Error("Zoompinch engine not initialized");return e.value.normalizeClientCoords(t,r)},Z=(t,r,s)=>{e.value&&e.value.rotateCanvas(t,r,s)};return n.useSlots(),c({applyTransform:Y,composePoint:d,normalizeClientCoords:L,zoompinchEngine:e,canvasWidth:v,canvasHeight:m,rotateCanvas:Z}),(t,r)=>(n.openBlock(),n.createElementBlock("div",{ref_key:"zoompinchRef",ref:f,class:"zoompinch",onWheel:x,onGesturestart:G,onMousedown:C,onTouchstart:M},[n.createElementVNode("div",T,[n.renderSlot(t.$slots,"default",{},void 0,!0)]),n.createElementVNode("div",z,[h.value&&d.value?n.renderSlot(t.$slots,"matrix",{key:0,composePoint:d.value,normalizeClientCoords:L,canvasWidth:v.value,canvasHeight:m.value},void 0,!0):n.createCommentVNode("",!0)])],544))}}),[["__scopeId","data-v-13174681"]]);o.Zoompinch=X,Object.defineProperty(o,Symbol.toStringTag,{value:"Module"})}));
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@zoompinch/vue",
3
3
  "description": "Vue wrapper for ZoomPinch - reactive pinch & zoom component",
4
- "version": "0.0.14",
4
+ "version": "0.0.16",
5
5
  "private": false,
6
6
  "type": "module",
7
7
  "main": "./dist/zoompinch-vue.umd.js",
@@ -30,7 +30,7 @@
30
30
  "vue-tsc": "^3.2.0"
31
31
  },
32
32
  "dependencies": {
33
- "@zoompinch/core": "^0.0.14"
33
+ "@zoompinch/core": "^0.0.16"
34
34
  },
35
35
  "peerDependencies": {
36
36
  "vue": "^3.5.26"