@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 +379 -0
- package/dist/components/Zoompinch.vue.d.ts +23 -6
- package/dist/style.css +1 -1
- package/dist/zoompinch-vue.es.js +76 -60
- package/dist/zoompinch-vue.umd.js +1 -1
- package/package.json +2 -2
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
|
+

|
|
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
|
-
|
|
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
|
|
23
|
-
matrix
|
|
22
|
+
slots: Readonly<{
|
|
23
|
+
default: () => VNode | VNode[];
|
|
24
|
+
matrix: (args: {
|
|
24
25
|
composePoint: (x: number, y: number) => [number, number];
|
|
25
|
-
|
|
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
|
-
|
|
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-
|
|
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}
|
package/dist/zoompinch-vue.es.js
CHANGED
|
@@ -1,28 +1,30 @@
|
|
|
1
|
-
import { defineComponent as
|
|
2
|
-
import { Zoompinch as
|
|
3
|
-
const
|
|
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
|
-
|
|
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(
|
|
19
|
-
const a =
|
|
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
|
|
21
|
+
const v = o(() => {
|
|
22
22
|
throw new Error("Not initialized yet");
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
|
|
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) &&
|
|
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
|
-
|
|
37
|
+
h.value = !0;
|
|
36
38
|
}));
|
|
37
|
-
}),
|
|
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
|
-
),
|
|
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
|
-
),
|
|
51
|
+
), r(
|
|
50
52
|
() => a.minScale,
|
|
51
53
|
(t) => {
|
|
52
54
|
e.value && (e.value.minScale = t, e.value.update());
|
|
53
55
|
}
|
|
54
|
-
),
|
|
56
|
+
), r(
|
|
55
57
|
() => a.maxScale,
|
|
56
58
|
(t) => {
|
|
57
59
|
e.value && (e.value.maxScale = t, e.value.update());
|
|
58
60
|
}
|
|
59
|
-
)
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
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
|
-
},
|
|
70
|
+
}, G = (t) => {
|
|
65
71
|
e.value && a.gesture && e.value.handleGesturestart(t);
|
|
66
|
-
},
|
|
72
|
+
}, p = (t) => {
|
|
67
73
|
e.value && a.gesture && e.value.handleGesturechange(t);
|
|
68
|
-
},
|
|
74
|
+
}, w = (t) => {
|
|
69
75
|
e.value && a.gesture && e.value.handleGestureend(t);
|
|
70
|
-
},
|
|
76
|
+
}, z = (t) => {
|
|
71
77
|
e.value && a.mouse && e.value.handleMousedown(t);
|
|
72
|
-
},
|
|
78
|
+
}, g = (t) => {
|
|
73
79
|
e.value && a.mouse && e.value.handleMousemove(t);
|
|
74
|
-
},
|
|
80
|
+
}, E = (t) => {
|
|
75
81
|
e.value && a.mouse && e.value.handleMouseup(t);
|
|
76
|
-
},
|
|
82
|
+
}, x = (t) => {
|
|
77
83
|
e.value && a.touch && e.value.handleTouchstart(t);
|
|
78
|
-
},
|
|
84
|
+
}, L = (t) => {
|
|
79
85
|
e.value && a.touch && e.value.handleTouchmove(t);
|
|
80
|
-
},
|
|
86
|
+
}, _ = (t) => {
|
|
81
87
|
e.value && a.touch && e.value.handleTouchend(t);
|
|
82
88
|
};
|
|
83
|
-
|
|
84
|
-
window.removeEventListener("gesturechange",
|
|
85
|
-
})
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
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:
|
|
109
|
+
ref: c,
|
|
97
110
|
class: "zoompinch",
|
|
98
|
-
onWheel:
|
|
99
|
-
onGesturestart:
|
|
100
|
-
onMousedown:
|
|
101
|
-
onTouchstart:
|
|
111
|
+
onWheel: Y,
|
|
112
|
+
onGesturestart: G,
|
|
113
|
+
onMousedown: z,
|
|
114
|
+
onTouchstart: x
|
|
102
115
|
}, [
|
|
103
|
-
|
|
104
|
-
|
|
116
|
+
S("div", R, [
|
|
117
|
+
T(t.$slots, "default", {}, void 0, !0)
|
|
105
118
|
]),
|
|
106
|
-
|
|
107
|
-
|
|
119
|
+
S("div", U, [
|
|
120
|
+
h.value && v.value ? T(t.$slots, "matrix", {
|
|
108
121
|
key: 0,
|
|
109
|
-
composePoint:
|
|
110
|
-
|
|
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
|
-
}),
|
|
115
|
-
const
|
|
116
|
-
for (const [a,
|
|
117
|
-
|
|
118
|
-
return
|
|
119
|
-
},
|
|
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
|
-
|
|
137
|
+
O as Zoompinch
|
|
122
138
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
(function(o,
|
|
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.
|
|
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.
|
|
33
|
+
"@zoompinch/core": "^0.0.16"
|
|
34
34
|
},
|
|
35
35
|
"peerDependencies": {
|
|
36
36
|
"vue": "^3.5.26"
|