@editframe/create 0.44.0 → 0.45.0
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/dist/index.js +16 -28
- package/dist/index.js.map +1 -1
- package/dist/skills/editframe-brand-video-generator/README.md +155 -0
- package/dist/skills/editframe-brand-video-generator/SKILL.md +207 -0
- package/dist/skills/editframe-brand-video-generator/references/brand-examples.md +178 -0
- package/dist/skills/editframe-brand-video-generator/references/color-psychology.md +227 -0
- package/dist/skills/editframe-brand-video-generator/references/composition-patterns.md +383 -0
- package/dist/skills/editframe-brand-video-generator/references/editing.md +66 -0
- package/dist/skills/editframe-brand-video-generator/references/emotional-arcs.md +496 -0
- package/dist/skills/editframe-brand-video-generator/references/genre-selection.md +135 -0
- package/dist/skills/editframe-brand-video-generator/references/transition-styles.md +611 -0
- package/dist/skills/editframe-brand-video-generator/references/typography-personalities.md +326 -0
- package/dist/skills/editframe-brand-video-generator/references/video-archetypes.md +86 -0
- package/dist/skills/editframe-brand-video-generator/references/video-fundamentals.md +169 -0
- package/dist/skills/editframe-brand-video-generator/references/visual-metaphors.md +50 -0
- package/dist/skills/editframe-composition/SKILL.md +169 -0
- package/dist/skills/editframe-composition/references/audio.md +483 -0
- package/dist/skills/editframe-composition/references/captions.md +844 -0
- package/dist/skills/editframe-composition/references/composition-model.md +73 -0
- package/dist/skills/editframe-composition/references/configuration.md +403 -0
- package/dist/skills/editframe-composition/references/css-parts.md +105 -0
- package/dist/skills/editframe-composition/references/css-variables.md +640 -0
- package/dist/skills/editframe-composition/references/entry-points.md +810 -0
- package/dist/skills/editframe-composition/references/events.md +499 -0
- package/dist/skills/editframe-composition/references/getting-started.md +259 -0
- package/dist/skills/editframe-composition/references/hooks.md +234 -0
- package/dist/skills/editframe-composition/references/image.md +241 -0
- package/dist/skills/editframe-composition/references/r3f.md +580 -0
- package/dist/skills/editframe-composition/references/render-api.md +484 -0
- package/dist/skills/editframe-composition/references/render-strategies.md +119 -0
- package/dist/skills/editframe-composition/references/render-to-video.md +1101 -0
- package/dist/skills/editframe-composition/references/scripting.md +606 -0
- package/dist/skills/editframe-composition/references/sequencing.md +116 -0
- package/dist/skills/editframe-composition/references/server-rendering.md +753 -0
- package/dist/skills/editframe-composition/references/surface.md +329 -0
- package/dist/skills/editframe-composition/references/text.md +627 -0
- package/dist/skills/editframe-composition/references/time-model.md +99 -0
- package/dist/skills/editframe-composition/references/timegroup-modes.md +102 -0
- package/dist/skills/editframe-composition/references/timegroup.md +457 -0
- package/dist/skills/editframe-composition/references/timeline-root.md +398 -0
- package/dist/skills/editframe-composition/references/transcription.md +47 -0
- package/dist/skills/editframe-composition/references/transitions.md +608 -0
- package/dist/skills/editframe-composition/references/use-media-info.md +357 -0
- package/dist/skills/editframe-composition/references/video.md +506 -0
- package/dist/skills/editframe-composition/references/waveform.md +327 -0
- package/dist/skills/editframe-editor-gui/SKILL.md +152 -0
- package/dist/skills/editframe-editor-gui/references/active-root-temporal.md +657 -0
- package/dist/skills/editframe-editor-gui/references/canvas.md +947 -0
- package/dist/skills/editframe-editor-gui/references/controls.md +366 -0
- package/dist/skills/editframe-editor-gui/references/dial.md +756 -0
- package/dist/skills/editframe-editor-gui/references/editor-toolkit.md +587 -0
- package/dist/skills/editframe-editor-gui/references/filmstrip.md +460 -0
- package/dist/skills/editframe-editor-gui/references/fit-scale.md +772 -0
- package/dist/skills/editframe-editor-gui/references/focus-overlay.md +561 -0
- package/dist/skills/editframe-editor-gui/references/hierarchy.md +544 -0
- package/dist/skills/editframe-editor-gui/references/overlay-item.md +634 -0
- package/dist/skills/editframe-editor-gui/references/overlay-layer.md +429 -0
- package/dist/skills/editframe-editor-gui/references/pan-zoom.md +568 -0
- package/dist/skills/editframe-editor-gui/references/pause.md +397 -0
- package/dist/skills/editframe-editor-gui/references/play.md +370 -0
- package/dist/skills/editframe-editor-gui/references/preview.md +391 -0
- package/dist/skills/editframe-editor-gui/references/resizable-box.md +749 -0
- package/dist/skills/editframe-editor-gui/references/scrubber.md +588 -0
- package/dist/skills/editframe-editor-gui/references/thumbnail-strip.md +566 -0
- package/dist/skills/editframe-editor-gui/references/time-display.md +492 -0
- package/dist/skills/editframe-editor-gui/references/timeline-ruler.md +489 -0
- package/dist/skills/editframe-editor-gui/references/timeline.md +604 -0
- package/dist/skills/editframe-editor-gui/references/toggle-loop.md +618 -0
- package/dist/skills/editframe-editor-gui/references/toggle-play.md +526 -0
- package/dist/skills/editframe-editor-gui/references/transform-handles.md +924 -0
- package/dist/skills/editframe-editor-gui/references/trim-handles.md +725 -0
- package/dist/skills/editframe-editor-gui/references/workbench.md +453 -0
- package/dist/skills/editframe-motion-design/SKILL.md +101 -0
- package/dist/skills/editframe-motion-design/references/0-editframe.md +299 -0
- package/dist/skills/editframe-motion-design/references/1-intent.md +201 -0
- package/dist/skills/editframe-motion-design/references/2-physics-model.md +405 -0
- package/dist/skills/editframe-motion-design/references/3-attention.md +350 -0
- package/dist/skills/editframe-motion-design/references/4-process.md +418 -0
- package/dist/skills/editframe-vite-plugin/SKILL.md +75 -0
- package/dist/skills/editframe-vite-plugin/references/file-api.md +111 -0
- package/dist/skills/editframe-vite-plugin/references/getting-started.md +96 -0
- package/dist/skills/editframe-vite-plugin/references/jit-transcoding.md +91 -0
- package/dist/skills/editframe-vite-plugin/references/local-assets.md +75 -0
- package/dist/skills/editframe-vite-plugin/references/visual-testing.md +136 -0
- package/dist/skills/editframe-webhooks/SKILL.md +126 -0
- package/dist/skills/editframe-webhooks/references/events.md +382 -0
- package/dist/skills/editframe-webhooks/references/getting-started.md +232 -0
- package/dist/skills/editframe-webhooks/references/security.md +418 -0
- package/dist/skills/editframe-webhooks/references/testing.md +409 -0
- package/dist/skills/editframe-webhooks/references/troubleshooting.md +457 -0
- package/dist/templates/html/AGENTS.md +13 -0
- package/dist/templates/react/AGENTS.md +13 -0
- package/dist/utils.js +15 -16
- package/dist/utils.js.map +1 -1
- package/package.json +1 -1
- package/tsdown.config.ts +4 -0
- package/dist/detectAgent.js +0 -89
- package/dist/detectAgent.js.map +0 -1
|
@@ -0,0 +1,568 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Pan-Zoom Element
|
|
3
|
+
description: Interactive container providing pan and zoom navigation with touch gesture support, mouse wheel zoom, and programmatic control.
|
|
4
|
+
type: reference
|
|
5
|
+
nav:
|
|
6
|
+
parent: "Preview & Canvas"
|
|
7
|
+
priority: 12
|
|
8
|
+
api:
|
|
9
|
+
attributes:
|
|
10
|
+
- name: x
|
|
11
|
+
type: number
|
|
12
|
+
default: 0
|
|
13
|
+
description: Horizontal pan offset in pixels
|
|
14
|
+
- name: y
|
|
15
|
+
type: number
|
|
16
|
+
default: 0
|
|
17
|
+
description: Vertical pan offset in pixels
|
|
18
|
+
- name: scale
|
|
19
|
+
type: number
|
|
20
|
+
default: 1
|
|
21
|
+
description: Zoom scale factor (0.1 to 5)
|
|
22
|
+
- name: auto-fit
|
|
23
|
+
type: boolean
|
|
24
|
+
default: false
|
|
25
|
+
description: Auto-fit content on first render
|
|
26
|
+
methods:
|
|
27
|
+
- name: screenToCanvas(screenX, screenY)
|
|
28
|
+
signature: "screenToCanvas(screenX: number, screenY: number): { x: number, y: number }"
|
|
29
|
+
description: Convert screen coordinates to canvas coordinates
|
|
30
|
+
returns: Object with x, y in canvas space
|
|
31
|
+
- name: canvasToScreen(canvasX, canvasY)
|
|
32
|
+
signature: "canvasToScreen(canvasX: number, canvasY: number): { x: number, y: number }"
|
|
33
|
+
description: Convert canvas coordinates to screen coordinates
|
|
34
|
+
returns: Object with x, y in screen space
|
|
35
|
+
- name: reset()
|
|
36
|
+
signature: "reset(): void"
|
|
37
|
+
description: Reset to default transform (x=0, y=0, scale=1)
|
|
38
|
+
returns: void
|
|
39
|
+
- name: fitToContent(padding)
|
|
40
|
+
signature: "fitToContent(padding?: number): void"
|
|
41
|
+
description: Fit content to container with optional padding (0-1)
|
|
42
|
+
returns: void
|
|
43
|
+
events:
|
|
44
|
+
- name: transform-changed
|
|
45
|
+
type: CustomEvent<PanZoomTransform>
|
|
46
|
+
description: Fired when pan or zoom changes
|
|
47
|
+
detail: "{ x: number, y: number, scale: number }"
|
|
48
|
+
react:
|
|
49
|
+
generate: true
|
|
50
|
+
componentName: PanZoom
|
|
51
|
+
importPath: "@editframe/react"
|
|
52
|
+
propMapping:
|
|
53
|
+
auto-fit: autoFit
|
|
54
|
+
additionalProps:
|
|
55
|
+
- name: onTransformChanged
|
|
56
|
+
type: "(event: CustomEvent<PanZoomTransform>) => void"
|
|
57
|
+
description: Callback fired when pan or zoom changes
|
|
58
|
+
- name: className
|
|
59
|
+
type: string
|
|
60
|
+
description: CSS classes for styling
|
|
61
|
+
- name: children
|
|
62
|
+
type: ReactNode
|
|
63
|
+
description: Content to make pannable and zoomable
|
|
64
|
+
- name: ref
|
|
65
|
+
type: "Ref<EFPanZoom>"
|
|
66
|
+
description: Ref to access underlying element methods
|
|
67
|
+
nav:
|
|
68
|
+
parent: "Components / Interaction"
|
|
69
|
+
priority: 15
|
|
70
|
+
related: ["preview", "workbench"]
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
<!-- html-only -->
|
|
74
|
+
# ef-pan-zoom
|
|
75
|
+
<!-- /html-only -->
|
|
76
|
+
<!-- react-only -->
|
|
77
|
+
# PanZoom
|
|
78
|
+
<!-- /react-only -->
|
|
79
|
+
|
|
80
|
+
Interactive pan and zoom container with mouse/trackpad gesture support.
|
|
81
|
+
|
|
82
|
+
<!-- react-only -->
|
|
83
|
+
## Import
|
|
84
|
+
|
|
85
|
+
```tsx
|
|
86
|
+
import { PanZoom } from "@editframe/react";
|
|
87
|
+
```
|
|
88
|
+
<!-- /react-only -->
|
|
89
|
+
|
|
90
|
+
## Basic Usage
|
|
91
|
+
|
|
92
|
+
Wrap any content to make it pannable and zoomable:
|
|
93
|
+
|
|
94
|
+
<!-- html-only -->
|
|
95
|
+
```html live
|
|
96
|
+
<ef-pan-zoom class="w-[720px] h-[480px] border border-gray-300 rounded">
|
|
97
|
+
<ef-timegroup mode="contain" class="w-[1280px] h-[720px] bg-black">
|
|
98
|
+
<ef-video src="https://assets.editframe.com/bars-n-tone.mp4" class="size-full object-contain"></ef-video>
|
|
99
|
+
</ef-timegroup>
|
|
100
|
+
</ef-pan-zoom>
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
> **Interaction:** Click and drag to pan. Hold Cmd/Ctrl and scroll to zoom. Scroll to pan horizontally/vertically.
|
|
104
|
+
<!-- /html-only -->
|
|
105
|
+
<!-- react-only -->
|
|
106
|
+
```tsx
|
|
107
|
+
import { PanZoom, Timegroup, Video } from "@editframe/react";
|
|
108
|
+
|
|
109
|
+
<PanZoom className="w-[720px] h-[480px] border border-gray-300 rounded">
|
|
110
|
+
<Timegroup mode="contain" className="w-[1280px] h-[720px] bg-black">
|
|
111
|
+
<Video src="/assets/video.mp4" className="size-full object-contain" />
|
|
112
|
+
</Timegroup>
|
|
113
|
+
</PanZoom>
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
**Interaction:**
|
|
117
|
+
- Click and drag to pan
|
|
118
|
+
- Cmd/Ctrl + scroll to zoom
|
|
119
|
+
- Two-finger trackpad gestures for pan/zoom
|
|
120
|
+
<!-- /react-only -->
|
|
121
|
+
|
|
122
|
+
## Auto-Fit Content
|
|
123
|
+
|
|
124
|
+
Automatically fit content to the container on load:
|
|
125
|
+
|
|
126
|
+
<!-- html-only -->
|
|
127
|
+
```html live
|
|
128
|
+
<ef-pan-zoom auto-fit class="w-[600px] h-[400px] border border-gray-300 rounded bg-gray-50">
|
|
129
|
+
<ef-timegroup mode="contain" class="w-[1280px] h-[720px] bg-black">
|
|
130
|
+
<ef-video src="https://assets.editframe.com/bars-n-tone.mp4" class="size-full object-contain"></ef-video>
|
|
131
|
+
</ef-timegroup>
|
|
132
|
+
</ef-pan-zoom>
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
The `auto-fit` attribute centers and scales content to fit with 5% padding.
|
|
136
|
+
<!-- /html-only -->
|
|
137
|
+
<!-- react-only -->
|
|
138
|
+
```tsx
|
|
139
|
+
<PanZoom
|
|
140
|
+
autoFit
|
|
141
|
+
className="w-[600px] h-[400px] border border-gray-300 rounded bg-gray-50"
|
|
142
|
+
>
|
|
143
|
+
<Timegroup mode="contain" className="w-[1280px] h-[720px] bg-black">
|
|
144
|
+
<Video src="/assets/video.mp4" className="size-full object-contain" />
|
|
145
|
+
</Timegroup>
|
|
146
|
+
</PanZoom>
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
The `autoFit` prop centers and scales content to fit with 5% padding.
|
|
150
|
+
<!-- /react-only -->
|
|
151
|
+
|
|
152
|
+
## Gesture Controls
|
|
153
|
+
|
|
154
|
+
### Panning
|
|
155
|
+
|
|
156
|
+
<!-- html-only -->
|
|
157
|
+
Click and drag anywhere to pan the view:
|
|
158
|
+
|
|
159
|
+
```html live
|
|
160
|
+
<ef-pan-zoom class="w-[500px] h-[300px] border border-gray-300 rounded">
|
|
161
|
+
<div class="w-[1000px] h-[600px] bg-gradient-to-br from-blue-500 to-purple-600 flex items-center justify-center">
|
|
162
|
+
<p class="text-white text-2xl font-bold">Drag to pan</p>
|
|
163
|
+
</div>
|
|
164
|
+
</ef-pan-zoom>
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
### Zooming
|
|
168
|
+
|
|
169
|
+
Hold Cmd (Mac) or Ctrl (Windows/Linux) and scroll to zoom:
|
|
170
|
+
|
|
171
|
+
```html live
|
|
172
|
+
<ef-pan-zoom class="w-[500px] h-[300px] border border-gray-300 rounded">
|
|
173
|
+
<div class="w-[800px] h-[600px] bg-gradient-to-br from-green-500 to-teal-600 flex items-center justify-center">
|
|
174
|
+
<p class="text-white text-2xl font-bold">Cmd/Ctrl + Scroll to zoom</p>
|
|
175
|
+
</div>
|
|
176
|
+
</ef-pan-zoom>
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
Zoom is centered on the cursor position — the point under the cursor remains fixed while zooming.
|
|
180
|
+
|
|
181
|
+
### Trackpad Gestures
|
|
182
|
+
|
|
183
|
+
- **Two-finger drag:** Pan horizontally and vertically
|
|
184
|
+
- **Pinch:** Zoom in/out (with Cmd/Ctrl)
|
|
185
|
+
- **Scroll:** Pan without modifier keys
|
|
186
|
+
<!-- /html-only -->
|
|
187
|
+
<!-- react-only -->
|
|
188
|
+
- **Click and drag:** Pan in any direction
|
|
189
|
+
- **Two-finger drag (trackpad):** Pan horizontally and vertically
|
|
190
|
+
- **Scroll:** Pan without modifier keys
|
|
191
|
+
|
|
192
|
+
### Zooming
|
|
193
|
+
- **Cmd/Ctrl + scroll:** Zoom in/out
|
|
194
|
+
- **Pinch (trackpad):** Zoom with Cmd/Ctrl modifier
|
|
195
|
+
|
|
196
|
+
Zoom is centered on the cursor position — the point under the cursor remains fixed while zooming.
|
|
197
|
+
<!-- /react-only -->
|
|
198
|
+
|
|
199
|
+
## Programmatic Control
|
|
200
|
+
|
|
201
|
+
<!-- html-only -->
|
|
202
|
+
Set transform properties directly:
|
|
203
|
+
|
|
204
|
+
```html live
|
|
205
|
+
<div>
|
|
206
|
+
<ef-pan-zoom id="demo-panzoom" x="100" y="50" scale="1.5" class="w-[500px] h-[300px] border border-gray-300 rounded">
|
|
207
|
+
<div class="w-[800px] h-[600px] bg-gradient-to-br from-red-500 to-pink-600 flex items-center justify-center">
|
|
208
|
+
<p class="text-white text-2xl font-bold">Programmatic Transform</p>
|
|
209
|
+
</div>
|
|
210
|
+
</ef-pan-zoom>
|
|
211
|
+
<div class="mt-4 flex gap-2">
|
|
212
|
+
<button onclick="document.getElementById('demo-panzoom').reset()" class="px-3 py-1 bg-blue-500 text-white rounded hover:bg-blue-600">Reset</button>
|
|
213
|
+
<button onclick="document.getElementById('demo-panzoom').fitToContent()" class="px-3 py-1 bg-green-500 text-white rounded hover:bg-green-600">Fit Content</button>
|
|
214
|
+
<button onclick="document.getElementById('demo-panzoom').scale = 2" class="px-3 py-1 bg-purple-500 text-white rounded hover:bg-purple-600">Zoom 2x</button>
|
|
215
|
+
</div>
|
|
216
|
+
</div>
|
|
217
|
+
```
|
|
218
|
+
<!-- /html-only -->
|
|
219
|
+
<!-- react-only -->
|
|
220
|
+
Control transform with props:
|
|
221
|
+
|
|
222
|
+
```tsx
|
|
223
|
+
import { useState } from "react";
|
|
224
|
+
import { PanZoom, Timegroup, Video } from "@editframe/react";
|
|
225
|
+
|
|
226
|
+
const ZoomablePreview = () => {
|
|
227
|
+
const [x, setX] = useState(0);
|
|
228
|
+
const [y, setY] = useState(0);
|
|
229
|
+
const [scale, setScale] = useState(1);
|
|
230
|
+
|
|
231
|
+
return (
|
|
232
|
+
<div>
|
|
233
|
+
<PanZoom
|
|
234
|
+
x={x}
|
|
235
|
+
y={y}
|
|
236
|
+
scale={scale}
|
|
237
|
+
className="w-[500px] h-[300px] border border-gray-300 rounded"
|
|
238
|
+
>
|
|
239
|
+
<Timegroup mode="contain" className="w-[800px] h-[600px] bg-black">
|
|
240
|
+
<Video src="/assets/video.mp4" className="size-full" />
|
|
241
|
+
</Timegroup>
|
|
242
|
+
</PanZoom>
|
|
243
|
+
|
|
244
|
+
<div className="mt-4 flex gap-2">
|
|
245
|
+
<button
|
|
246
|
+
onClick={() => { setX(0); setY(0); setScale(1); }}
|
|
247
|
+
className="px-3 py-1 bg-blue-500 text-white rounded"
|
|
248
|
+
>
|
|
249
|
+
Reset
|
|
250
|
+
</button>
|
|
251
|
+
<button
|
|
252
|
+
onClick={() => setScale(2)}
|
|
253
|
+
className="px-3 py-1 bg-purple-500 text-white rounded"
|
|
254
|
+
>
|
|
255
|
+
Zoom 2x
|
|
256
|
+
</button>
|
|
257
|
+
<button
|
|
258
|
+
onClick={() => setScale(0.5)}
|
|
259
|
+
className="px-3 py-1 bg-green-500 text-white rounded"
|
|
260
|
+
>
|
|
261
|
+
Zoom Out
|
|
262
|
+
</button>
|
|
263
|
+
</div>
|
|
264
|
+
</div>
|
|
265
|
+
);
|
|
266
|
+
};
|
|
267
|
+
```
|
|
268
|
+
<!-- /react-only -->
|
|
269
|
+
|
|
270
|
+
## Methods
|
|
271
|
+
|
|
272
|
+
### reset()
|
|
273
|
+
|
|
274
|
+
Reset the view to default values:
|
|
275
|
+
|
|
276
|
+
<!-- html-only -->
|
|
277
|
+
```javascript
|
|
278
|
+
const panZoom = document.querySelector('ef-pan-zoom');
|
|
279
|
+
panZoom.reset(); // x=0, y=0, scale=1
|
|
280
|
+
```
|
|
281
|
+
<!-- /html-only -->
|
|
282
|
+
<!-- react-only -->
|
|
283
|
+
```tsx
|
|
284
|
+
import { useRef } from "react";
|
|
285
|
+
import { PanZoom } from "@editframe/react";
|
|
286
|
+
import type { EFPanZoom } from "@editframe/elements";
|
|
287
|
+
|
|
288
|
+
const panZoomRef = useRef<EFPanZoom>(null);
|
|
289
|
+
panZoomRef.current?.reset();
|
|
290
|
+
```
|
|
291
|
+
<!-- /react-only -->
|
|
292
|
+
|
|
293
|
+
### fitToContent(padding)
|
|
294
|
+
|
|
295
|
+
Fit content to the container:
|
|
296
|
+
|
|
297
|
+
<!-- html-only -->
|
|
298
|
+
```javascript
|
|
299
|
+
const panZoom = document.querySelector('ef-pan-zoom');
|
|
300
|
+
panZoom.fitToContent(0.1); // 10% padding on each side
|
|
301
|
+
```
|
|
302
|
+
<!-- /html-only -->
|
|
303
|
+
<!-- react-only -->
|
|
304
|
+
```tsx
|
|
305
|
+
panZoomRef.current?.fitToContent(0.1); // 10% padding
|
|
306
|
+
```
|
|
307
|
+
<!-- /react-only -->
|
|
308
|
+
|
|
309
|
+
Padding is a factor from 0 to 1, where 0.1 = 10% padding.
|
|
310
|
+
|
|
311
|
+
### screenToCanvas(screenX, screenY)
|
|
312
|
+
|
|
313
|
+
Convert screen coordinates (e.g., mouse event) to canvas coordinates:
|
|
314
|
+
|
|
315
|
+
<!-- html-only -->
|
|
316
|
+
```javascript
|
|
317
|
+
panZoom.addEventListener('click', (e) => {
|
|
318
|
+
const canvasPos = panZoom.screenToCanvas(e.clientX, e.clientY);
|
|
319
|
+
console.log(`Clicked at canvas position: ${canvasPos.x}, ${canvasPos.y}`);
|
|
320
|
+
});
|
|
321
|
+
```
|
|
322
|
+
<!-- /html-only -->
|
|
323
|
+
<!-- react-only -->
|
|
324
|
+
```tsx
|
|
325
|
+
const canvasPos = panZoomRef.current?.screenToCanvas(e.clientX, e.clientY);
|
|
326
|
+
```
|
|
327
|
+
<!-- /react-only -->
|
|
328
|
+
|
|
329
|
+
Useful for hit detection and positioning elements in canvas space.
|
|
330
|
+
|
|
331
|
+
### canvasToScreen(canvasX, canvasY)
|
|
332
|
+
|
|
333
|
+
Convert canvas coordinates to screen coordinates:
|
|
334
|
+
|
|
335
|
+
<!-- html-only -->
|
|
336
|
+
```javascript
|
|
337
|
+
const screenPos = panZoom.canvasToScreen(element.x, element.y);
|
|
338
|
+
tooltip.style.left = `${screenPos.x}px`;
|
|
339
|
+
tooltip.style.top = `${screenPos.y}px`;
|
|
340
|
+
```
|
|
341
|
+
<!-- /html-only -->
|
|
342
|
+
<!-- react-only -->
|
|
343
|
+
```tsx
|
|
344
|
+
const screenPos = panZoomRef.current?.canvasToScreen(canvasX, canvasY);
|
|
345
|
+
```
|
|
346
|
+
<!-- /react-only -->
|
|
347
|
+
|
|
348
|
+
Useful for positioning overlays and tooltips relative to canvas elements.
|
|
349
|
+
|
|
350
|
+
## Events
|
|
351
|
+
|
|
352
|
+
### transform-changed
|
|
353
|
+
|
|
354
|
+
Fired when pan or zoom changes:
|
|
355
|
+
|
|
356
|
+
<!-- html-only -->
|
|
357
|
+
```javascript
|
|
358
|
+
panZoom.addEventListener('transform-changed', (e) => {
|
|
359
|
+
console.log('Transform:', e.detail); // { x, y, scale }
|
|
360
|
+
});
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
Use this to sync UI controls or persist view state.
|
|
364
|
+
<!-- /html-only -->
|
|
365
|
+
<!-- react-only -->
|
|
366
|
+
```tsx
|
|
367
|
+
<PanZoom
|
|
368
|
+
onTransformChanged={(e) => {
|
|
369
|
+
console.log('Transform:', e.detail); // { x, y, scale }
|
|
370
|
+
}}
|
|
371
|
+
className="w-[500px] h-[300px]"
|
|
372
|
+
>
|
|
373
|
+
<div className="w-[1000px] h-[600px] bg-gradient-to-br from-blue-500 to-purple-600">
|
|
374
|
+
<p className="text-white text-2xl">Pan and zoom me</p>
|
|
375
|
+
</div>
|
|
376
|
+
</PanZoom>
|
|
377
|
+
```
|
|
378
|
+
<!-- /react-only -->
|
|
379
|
+
|
|
380
|
+
<!-- html-only -->
|
|
381
|
+
## Context Provision
|
|
382
|
+
|
|
383
|
+
`ef-pan-zoom` provides transform data via Lit context. Child components can consume this to render overlays that match the transform:
|
|
384
|
+
|
|
385
|
+
```javascript
|
|
386
|
+
import { consume } from '@lit/context';
|
|
387
|
+
import { panZoomTransformContext } from '@editframe/elements';
|
|
388
|
+
|
|
389
|
+
@consume({ context: panZoomTransformContext })
|
|
390
|
+
panZoomTransform?: PanZoomTransform;
|
|
391
|
+
```
|
|
392
|
+
|
|
393
|
+
Overlay components (like selection handles) use this to align with the panned/zoomed content.
|
|
394
|
+
<!-- /html-only -->
|
|
395
|
+
|
|
396
|
+
<!-- react-only -->
|
|
397
|
+
## With Ref for Methods
|
|
398
|
+
|
|
399
|
+
Access underlying element methods using ref:
|
|
400
|
+
|
|
401
|
+
```tsx
|
|
402
|
+
import { useRef } from "react";
|
|
403
|
+
import { PanZoom } from "@editframe/react";
|
|
404
|
+
import type { EFPanZoom } from "@editframe/elements";
|
|
405
|
+
|
|
406
|
+
const PanZoomWithControls = () => {
|
|
407
|
+
const panZoomRef = useRef<EFPanZoom>(null);
|
|
408
|
+
|
|
409
|
+
const handleReset = () => {
|
|
410
|
+
panZoomRef.current?.reset();
|
|
411
|
+
};
|
|
412
|
+
|
|
413
|
+
const handleFitContent = () => {
|
|
414
|
+
panZoomRef.current?.fitToContent(0.1); // 10% padding
|
|
415
|
+
};
|
|
416
|
+
|
|
417
|
+
return (
|
|
418
|
+
<div>
|
|
419
|
+
<PanZoom ref={panZoomRef} className="w-[500px] h-[300px] border">
|
|
420
|
+
{/* Content */}
|
|
421
|
+
</PanZoom>
|
|
422
|
+
|
|
423
|
+
<div className="flex gap-2 mt-2">
|
|
424
|
+
<button onClick={handleReset}>Reset</button>
|
|
425
|
+
<button onClick={handleFitContent}>Fit Content</button>
|
|
426
|
+
</div>
|
|
427
|
+
</div>
|
|
428
|
+
);
|
|
429
|
+
};
|
|
430
|
+
```
|
|
431
|
+
|
|
432
|
+
### Available Methods
|
|
433
|
+
|
|
434
|
+
- `reset()` - Reset to default transform (x=0, y=0, scale=1)
|
|
435
|
+
- `fitToContent(padding?: number)` - Fit content to container with optional padding (0-1)
|
|
436
|
+
- `screenToCanvas(screenX: number, screenY: number)` - Convert screen coordinates to canvas coordinates
|
|
437
|
+
- `canvasToScreen(canvasX: number, canvasY: number)` - Convert canvas coordinates to screen coordinates
|
|
438
|
+
|
|
439
|
+
## With usePanZoomTransform Hook
|
|
440
|
+
|
|
441
|
+
Use the `usePanZoomTransform` hook to access transform data in child components:
|
|
442
|
+
|
|
443
|
+
```tsx
|
|
444
|
+
import { PanZoom, usePanZoomTransform } from "@editframe/react";
|
|
445
|
+
|
|
446
|
+
const TransformDisplay = () => {
|
|
447
|
+
const transform = usePanZoomTransform();
|
|
448
|
+
|
|
449
|
+
return (
|
|
450
|
+
<div className="absolute top-4 right-4 bg-white/90 px-3 py-2 rounded text-sm">
|
|
451
|
+
<div>X: {transform?.x.toFixed(0)}</div>
|
|
452
|
+
<div>Y: {transform?.y.toFixed(0)}</div>
|
|
453
|
+
<div>Scale: {transform?.scale.toFixed(2)}</div>
|
|
454
|
+
</div>
|
|
455
|
+
);
|
|
456
|
+
};
|
|
457
|
+
|
|
458
|
+
export const PanZoomWithDisplay = () => {
|
|
459
|
+
return (
|
|
460
|
+
<PanZoom className="w-[500px] h-[300px] border rounded">
|
|
461
|
+
<div className="w-[1000px] h-[600px] bg-blue-500">
|
|
462
|
+
<TransformDisplay />
|
|
463
|
+
</div>
|
|
464
|
+
</PanZoom>
|
|
465
|
+
);
|
|
466
|
+
};
|
|
467
|
+
```
|
|
468
|
+
<!-- /react-only -->
|
|
469
|
+
|
|
470
|
+
## Video Preview with Pan-Zoom
|
|
471
|
+
|
|
472
|
+
Create a zoomable video preview:
|
|
473
|
+
|
|
474
|
+
<!-- html-only -->
|
|
475
|
+
```html live
|
|
476
|
+
<ef-pan-zoom auto-fit class="w-[720px] h-[480px] border border-gray-300 rounded bg-gray-900">
|
|
477
|
+
<ef-timegroup mode="contain" class="w-[1920px] h-[1080px] bg-black">
|
|
478
|
+
<ef-video src="https://assets.editframe.com/bars-n-tone.mp4" class="size-full object-contain"></ef-video>
|
|
479
|
+
<div class="absolute top-8 left-8 bg-white/90 backdrop-blur px-4 py-2 rounded">
|
|
480
|
+
<p class="text-sm font-semibold">Zoomable Preview</p>
|
|
481
|
+
<p class="text-xs text-gray-600">Cmd/Ctrl + Scroll to zoom</p>
|
|
482
|
+
</div>
|
|
483
|
+
</ef-timegroup>
|
|
484
|
+
</ef-pan-zoom>
|
|
485
|
+
```
|
|
486
|
+
<!-- /html-only -->
|
|
487
|
+
<!-- react-only -->
|
|
488
|
+
```tsx
|
|
489
|
+
import { PanZoom, Timegroup, Video, Text } from "@editframe/react";
|
|
490
|
+
|
|
491
|
+
export const VideoEditorPreview = () => {
|
|
492
|
+
return (
|
|
493
|
+
<div className="flex flex-col gap-4">
|
|
494
|
+
<PanZoom
|
|
495
|
+
autoFit
|
|
496
|
+
className="w-full h-[600px] border border-gray-300 rounded bg-gray-900"
|
|
497
|
+
>
|
|
498
|
+
<Timegroup mode="contain" className="w-[1920px] h-[1080px] bg-black">
|
|
499
|
+
<Video
|
|
500
|
+
src="/assets/project.mp4"
|
|
501
|
+
className="size-full object-contain"
|
|
502
|
+
/>
|
|
503
|
+
<Text className="absolute top-8 left-8 text-white text-4xl">
|
|
504
|
+
Zoomable Preview
|
|
505
|
+
</Text>
|
|
506
|
+
</Timegroup>
|
|
507
|
+
</PanZoom>
|
|
508
|
+
|
|
509
|
+
<div className="text-sm text-gray-600">
|
|
510
|
+
Cmd/Ctrl + Scroll to zoom • Click and drag to pan
|
|
511
|
+
</div>
|
|
512
|
+
</div>
|
|
513
|
+
);
|
|
514
|
+
};
|
|
515
|
+
```
|
|
516
|
+
<!-- /react-only -->
|
|
517
|
+
|
|
518
|
+
## Styling
|
|
519
|
+
|
|
520
|
+
<!-- html-only -->
|
|
521
|
+
The element has `overflow: hidden` and `position: relative` by default. Style the container as needed:
|
|
522
|
+
|
|
523
|
+
```html
|
|
524
|
+
<ef-pan-zoom class="w-full h-screen border-2 border-blue-500 rounded-lg shadow-xl">
|
|
525
|
+
<!-- Content -->
|
|
526
|
+
</ef-pan-zoom>
|
|
527
|
+
```
|
|
528
|
+
<!-- /html-only -->
|
|
529
|
+
<!-- react-only -->
|
|
530
|
+
The component has `overflow: hidden` and `position: relative` by default. Add custom styles via `className`:
|
|
531
|
+
|
|
532
|
+
```tsx
|
|
533
|
+
<PanZoom className="w-full h-screen border-2 border-blue-500 rounded-lg shadow-xl">
|
|
534
|
+
{/* Content */}
|
|
535
|
+
</PanZoom>
|
|
536
|
+
```
|
|
537
|
+
<!-- /react-only -->
|
|
538
|
+
|
|
539
|
+
## Scale Limits
|
|
540
|
+
|
|
541
|
+
Scale is clamped between 0.1 and 5:
|
|
542
|
+
- Minimum: 0.1 (10% of original size)
|
|
543
|
+
- Maximum: 5 (500% of original size)
|
|
544
|
+
|
|
545
|
+
These limits prevent unusable zoom levels while allowing meaningful magnification.
|
|
546
|
+
|
|
547
|
+
<!-- html-only -->
|
|
548
|
+
## Browser Navigation Prevention
|
|
549
|
+
|
|
550
|
+
`ef-pan-zoom` prevents browser back/forward navigation triggered by trackpad swipes. This ensures pan gestures don't accidentally navigate away from the page.
|
|
551
|
+
|
|
552
|
+
The element uses passive event listeners in capture phase to intercept and prevent default navigation behavior while still allowing normal pan/zoom interactions.
|
|
553
|
+
<!-- /html-only -->
|
|
554
|
+
|
|
555
|
+
<!-- react-only -->
|
|
556
|
+
## TypeScript Types
|
|
557
|
+
|
|
558
|
+
```tsx
|
|
559
|
+
import type { PanZoomTransform } from "@editframe/elements";
|
|
560
|
+
|
|
561
|
+
// Transform structure
|
|
562
|
+
interface PanZoomTransform {
|
|
563
|
+
x: number;
|
|
564
|
+
y: number;
|
|
565
|
+
scale: number;
|
|
566
|
+
}
|
|
567
|
+
```
|
|
568
|
+
<!-- /react-only -->
|