@edgepdf/viewer-react 0.0.31 → 0.0.33
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 +571 -12
- package/dist/index.css +940 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +12336 -12399
- package/dist/lib/pdf-viewer.d.ts +3 -4
- package/dist/lib/pdf-viewer.d.ts.map +1 -1
- package/dist/lib/use-markers.d.ts +8 -2
- package/dist/lib/use-markers.d.ts.map +1 -1
- package/dist/lib/use-viewer.d.ts +1 -3
- package/dist/lib/use-viewer.d.ts.map +1 -1
- package/package.json +2 -3
- package/dist/lib/pdf-viewer-client.d.ts +0 -65
- package/dist/lib/pdf-viewer-client.d.ts.map +0 -1
package/README.md
CHANGED
|
@@ -12,7 +12,7 @@ pnpm add @edgepdf/viewer-react @edgepdf/viewer-js
|
|
|
12
12
|
yarn add @edgepdf/viewer-react @edgepdf/viewer-js
|
|
13
13
|
```
|
|
14
14
|
|
|
15
|
-
##
|
|
15
|
+
## Quick Start
|
|
16
16
|
|
|
17
17
|
### Next.js
|
|
18
18
|
|
|
@@ -98,6 +98,7 @@ import {
|
|
|
98
98
|
EdgePDFViewer,
|
|
99
99
|
useMarkers,
|
|
100
100
|
useViewer,
|
|
101
|
+
useZoom,
|
|
101
102
|
} from '@edgepdf/viewer-react';
|
|
102
103
|
import type { ViewerConfig } from '@edgepdf/types';
|
|
103
104
|
|
|
@@ -113,16 +114,17 @@ const config: ViewerConfig = {
|
|
|
113
114
|
};
|
|
114
115
|
|
|
115
116
|
function MarkerPanel() {
|
|
116
|
-
const { markers } = useMarkers();
|
|
117
|
+
const { markers, addMarker, removeMarker } = useMarkers();
|
|
117
118
|
const { viewer, isInitialized } = useViewer();
|
|
118
|
-
|
|
119
|
-
// You can interact with viewer + markers here,
|
|
120
|
-
// independent of where <EdgePDFViewer /> is rendered.
|
|
119
|
+
const { zoomIn, zoomOut, currentZoom } = useZoom();
|
|
121
120
|
|
|
122
121
|
return (
|
|
123
122
|
<div>
|
|
124
123
|
<div>Initialized: {isInitialized ? 'yes' : 'no'}</div>
|
|
125
124
|
<div>Total markers: {markers.length}</div>
|
|
125
|
+
<div>Current zoom: {currentZoom}</div>
|
|
126
|
+
<button onClick={zoomIn}>Zoom In</button>
|
|
127
|
+
<button onClick={zoomOut}>Zoom Out</button>
|
|
126
128
|
</div>
|
|
127
129
|
);
|
|
128
130
|
}
|
|
@@ -130,20 +132,577 @@ function MarkerPanel() {
|
|
|
130
132
|
function App() {
|
|
131
133
|
return (
|
|
132
134
|
<ViewerProvider>
|
|
133
|
-
{/* This can be on one route/screen */}
|
|
134
135
|
<MarkerPanel />
|
|
135
|
-
|
|
136
|
-
{/* And EdgePDFViewer can be on another */}
|
|
137
136
|
<EdgePDFViewer config={config} />
|
|
138
137
|
</ViewerProvider>
|
|
139
138
|
);
|
|
140
139
|
}
|
|
141
140
|
```
|
|
142
141
|
|
|
143
|
-
##
|
|
142
|
+
## API Reference
|
|
143
|
+
|
|
144
|
+
### Components
|
|
145
|
+
|
|
146
|
+
#### `<ViewerProvider>`
|
|
147
|
+
|
|
148
|
+
Provides viewer context to child components. Must wrap all components that use viewer hooks.
|
|
149
|
+
|
|
150
|
+
**Props:**
|
|
151
|
+
|
|
152
|
+
```typescript
|
|
153
|
+
interface ViewerProviderProps {
|
|
154
|
+
children: ReactNode;
|
|
155
|
+
}
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
**Example:**
|
|
159
|
+
|
|
160
|
+
```tsx
|
|
161
|
+
<ViewerProvider>
|
|
162
|
+
<App />
|
|
163
|
+
</ViewerProvider>
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
---
|
|
167
|
+
|
|
168
|
+
#### `<EdgePDFViewer>`
|
|
169
|
+
|
|
170
|
+
Main React component for the EdgePDF viewer. Must be used within a `ViewerProvider`.
|
|
171
|
+
|
|
172
|
+
**Props:**
|
|
173
|
+
|
|
174
|
+
```typescript
|
|
175
|
+
interface EdgePDFViewerProps {
|
|
176
|
+
/** Viewer configuration */
|
|
177
|
+
config: ViewerConfig;
|
|
178
|
+
/** Optional map options */
|
|
179
|
+
mapOptions?: MapOptions;
|
|
180
|
+
/** Optional className for the container */
|
|
181
|
+
className?: string;
|
|
182
|
+
/** Optional style for the container */
|
|
183
|
+
style?: React.CSSProperties;
|
|
184
|
+
/** Show zoom controls (default: true) */
|
|
185
|
+
showZoomControls?: boolean;
|
|
186
|
+
/** Zoom controls position (only used if showZoomControls is true) */
|
|
187
|
+
zoomControlsPosition?:
|
|
188
|
+
| 'top-left'
|
|
189
|
+
| 'top-right'
|
|
190
|
+
| 'bottom-left'
|
|
191
|
+
| 'bottom-right';
|
|
192
|
+
/** Show zoom level in zoom controls (only used if showZoomControls is true) */
|
|
193
|
+
showZoomLevel?: boolean;
|
|
194
|
+
/** Enable annotation functionality (default: true) */
|
|
195
|
+
enableAnnotation?: boolean;
|
|
196
|
+
/** Show edit button in marker action controls (default: true) */
|
|
197
|
+
showEditButton?: boolean;
|
|
198
|
+
/** Show delete button in marker action controls (default: true) */
|
|
199
|
+
showDeleteButton?: boolean;
|
|
200
|
+
/** Default zoom level for initial view */
|
|
201
|
+
defaultZoomLevel?: number;
|
|
202
|
+
/** Callback when markers/pins are updated */
|
|
203
|
+
onPinsUpdate?: (pins: Marker[]) => void;
|
|
204
|
+
/** Callback when a marker is clicked */
|
|
205
|
+
onMarkerClick?: (marker: Marker) => void;
|
|
206
|
+
/** Callback when a marker is updated */
|
|
207
|
+
onMarkerUpdate?: (marker: Marker) => void;
|
|
208
|
+
/** Callback when a marker is deleted */
|
|
209
|
+
onMarkerDelete?: (marker: Marker) => void;
|
|
210
|
+
/** Callback when a marker is added (created by user tap/click) */
|
|
211
|
+
onMarkerAdd?: (marker: Marker) => void;
|
|
212
|
+
/** Default pins to preload (uses internal import) */
|
|
213
|
+
defaultPins?: Marker[] | MarkerData;
|
|
214
|
+
/** Children components */
|
|
215
|
+
children?: ReactNode;
|
|
216
|
+
}
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
**Example:**
|
|
220
|
+
|
|
221
|
+
```tsx
|
|
222
|
+
<EdgePDFViewer
|
|
223
|
+
config={config}
|
|
224
|
+
showZoomControls={true}
|
|
225
|
+
zoomControlsPosition="top-right"
|
|
226
|
+
enableAnnotation={true}
|
|
227
|
+
onMarkerClick={(marker) => console.log('Marker clicked:', marker)}
|
|
228
|
+
onPinsUpdate={(pins) => console.log('Pins updated:', pins)}
|
|
229
|
+
/>
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
---
|
|
233
|
+
|
|
234
|
+
#### `<ZoomControls>`
|
|
235
|
+
|
|
236
|
+
React component for zoom controls. Uses the JS library's zoom controls internally.
|
|
237
|
+
|
|
238
|
+
**Props:**
|
|
239
|
+
|
|
240
|
+
```typescript
|
|
241
|
+
interface ZoomControlsProps {
|
|
242
|
+
/** Optional className for the container */
|
|
243
|
+
className?: string;
|
|
244
|
+
/** Optional style for the container */
|
|
245
|
+
style?: React.CSSProperties;
|
|
246
|
+
/** Position of the controls */
|
|
247
|
+
position?: 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';
|
|
248
|
+
/** Show zoom level display */
|
|
249
|
+
showZoomLevel?: boolean;
|
|
250
|
+
}
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
**Example:**
|
|
254
|
+
|
|
255
|
+
```tsx
|
|
256
|
+
<EdgePDFViewer config={config}>
|
|
257
|
+
<ZoomControls position="top-right" showZoomLevel={true} />
|
|
258
|
+
</EdgePDFViewer>
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
---
|
|
262
|
+
|
|
263
|
+
### Hooks
|
|
264
|
+
|
|
265
|
+
#### `useViewer()`
|
|
266
|
+
|
|
267
|
+
Hook to access and interact with the viewer instance.
|
|
268
|
+
|
|
269
|
+
**Returns:**
|
|
270
|
+
|
|
271
|
+
```typescript
|
|
272
|
+
interface UseViewerReturn {
|
|
273
|
+
/** Viewer instance */
|
|
274
|
+
viewer: EdgePdfViewer | null;
|
|
275
|
+
/** Whether viewer is initialized */
|
|
276
|
+
isInitialized: boolean;
|
|
277
|
+
/** Get the Leaflet map instance */
|
|
278
|
+
getMap: () => L.Map | null;
|
|
279
|
+
/** Check if viewer is initialized */
|
|
280
|
+
checkInitialized: () => boolean;
|
|
281
|
+
}
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
**Example:**
|
|
285
|
+
|
|
286
|
+
```tsx
|
|
287
|
+
function MyComponent() {
|
|
288
|
+
const { viewer, isInitialized, getMap } = useViewer();
|
|
289
|
+
|
|
290
|
+
useEffect(() => {
|
|
291
|
+
if (isInitialized && viewer) {
|
|
292
|
+
const map = getMap();
|
|
293
|
+
// Use map...
|
|
294
|
+
}
|
|
295
|
+
}, [isInitialized, viewer, getMap]);
|
|
296
|
+
|
|
297
|
+
return <div>Viewer is {isInitialized ? 'ready' : 'loading'}</div>;
|
|
298
|
+
}
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
---
|
|
302
|
+
|
|
303
|
+
#### `useMarkers()`
|
|
304
|
+
|
|
305
|
+
Hook to manage markers in the viewer.
|
|
306
|
+
|
|
307
|
+
**Returns:**
|
|
308
|
+
|
|
309
|
+
```typescript
|
|
310
|
+
interface UseMarkersReturn {
|
|
311
|
+
/** Current markers */
|
|
312
|
+
markers: Marker[];
|
|
313
|
+
/** Add a new marker */
|
|
314
|
+
addMarker: (options: CreateMarkerOptions) => Marker | null;
|
|
315
|
+
/** Remove a marker by ID */
|
|
316
|
+
removeMarker: (id: string) => boolean;
|
|
317
|
+
/** Update a marker */
|
|
318
|
+
updateMarker: (id: string, updates: Partial<Marker>) => boolean;
|
|
319
|
+
/** Get a marker by ID */
|
|
320
|
+
getMarker: (id: string) => Marker | null;
|
|
321
|
+
/** Get all markers */
|
|
322
|
+
getAllMarkers: () => Marker[];
|
|
323
|
+
/** Export markers as JSON */
|
|
324
|
+
exportMarkers: () => MarkerData;
|
|
325
|
+
/** Import markers from JSON */
|
|
326
|
+
importMarkers: (data: MarkerData) => boolean;
|
|
327
|
+
/** Clear all markers */
|
|
328
|
+
clearMarkers: () => void;
|
|
329
|
+
/** Focus on a marker by panning and zooming to its position */
|
|
330
|
+
focusMarker: (
|
|
331
|
+
markerOrId: string | Marker,
|
|
332
|
+
options?: {
|
|
333
|
+
zoom?: number;
|
|
334
|
+
animate?: boolean;
|
|
335
|
+
duration?: number;
|
|
336
|
+
}
|
|
337
|
+
) => boolean;
|
|
338
|
+
}
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
**Example:**
|
|
342
|
+
|
|
343
|
+
```tsx
|
|
344
|
+
function MarkerControls() {
|
|
345
|
+
const {
|
|
346
|
+
markers,
|
|
347
|
+
addMarker,
|
|
348
|
+
removeMarker,
|
|
349
|
+
updateMarker,
|
|
350
|
+
exportMarkers,
|
|
351
|
+
importMarkers,
|
|
352
|
+
clearMarkers,
|
|
353
|
+
focusMarker,
|
|
354
|
+
} = useMarkers();
|
|
355
|
+
|
|
356
|
+
const handleAddMarker = () => {
|
|
357
|
+
addMarker({
|
|
358
|
+
position: [100, 200],
|
|
359
|
+
x: 100,
|
|
360
|
+
y: 200,
|
|
361
|
+
zoom: 1,
|
|
362
|
+
label: 'New Marker',
|
|
363
|
+
});
|
|
364
|
+
};
|
|
365
|
+
|
|
366
|
+
const handleExport = () => {
|
|
367
|
+
const data = exportMarkers();
|
|
368
|
+
console.log(JSON.stringify(data, null, 2));
|
|
369
|
+
};
|
|
370
|
+
|
|
371
|
+
const handleFocus = (markerId: string) => {
|
|
372
|
+
focusMarker(markerId, { zoom: 3, animate: true });
|
|
373
|
+
};
|
|
374
|
+
|
|
375
|
+
return (
|
|
376
|
+
<div>
|
|
377
|
+
<button onClick={handleAddMarker}>Add Marker</button>
|
|
378
|
+
<button onClick={handleExport}>Export Markers</button>
|
|
379
|
+
<button onClick={clearMarkers}>Clear All</button>
|
|
380
|
+
{markers.map((marker) => (
|
|
381
|
+
<div key={marker.id}>
|
|
382
|
+
{marker.label}
|
|
383
|
+
<button onClick={() => removeMarker(marker.id)}>Remove</button>
|
|
384
|
+
<button onClick={() => handleFocus(marker.id)}>Focus</button>
|
|
385
|
+
</div>
|
|
386
|
+
))}
|
|
387
|
+
</div>
|
|
388
|
+
);
|
|
389
|
+
}
|
|
390
|
+
```
|
|
391
|
+
|
|
392
|
+
**Methods:**
|
|
393
|
+
|
|
394
|
+
- **`addMarker(options: CreateMarkerOptions): Marker | null`** - Creates a new marker. Returns the created marker or `null` if viewer is not initialized.
|
|
395
|
+
|
|
396
|
+
- **`removeMarker(id: string): boolean`** - Removes a marker by ID. Returns `true` if successful, `false` otherwise.
|
|
397
|
+
|
|
398
|
+
- **`updateMarker(id: string, updates: Partial<Marker>): boolean`** - Updates a marker's properties. Returns `true` if successful, `false` otherwise.
|
|
399
|
+
|
|
400
|
+
- **`getMarker(id: string): Marker | null`** - Gets a marker by ID. Returns the marker or `null` if not found.
|
|
401
|
+
|
|
402
|
+
- **`getAllMarkers(): Marker[]`** - Gets all markers. Returns an array of all markers.
|
|
403
|
+
|
|
404
|
+
- **`exportMarkers(): MarkerData`** - Exports all markers as JSON data. Returns a `MarkerData` object.
|
|
405
|
+
|
|
406
|
+
- **`importMarkers(data: MarkerData): boolean`** - Imports markers from JSON data. Returns `true` if successful, `false` otherwise.
|
|
407
|
+
|
|
408
|
+
- **`clearMarkers(): void`** - Removes all markers.
|
|
409
|
+
|
|
410
|
+
- **`focusMarker(markerOrId: string | Marker, options?: FocusOptions): boolean`** - Focuses on a marker by panning and zooming. Returns `true` if successful, `false` otherwise.
|
|
411
|
+
|
|
412
|
+
---
|
|
413
|
+
|
|
414
|
+
#### `useZoom()`
|
|
415
|
+
|
|
416
|
+
Hook to manage zoom in the viewer.
|
|
417
|
+
|
|
418
|
+
**Returns:**
|
|
419
|
+
|
|
420
|
+
```typescript
|
|
421
|
+
interface UseZoomReturn {
|
|
422
|
+
/** Current zoom state */
|
|
423
|
+
zoomState: ZoomState | null;
|
|
424
|
+
/** Current zoom level */
|
|
425
|
+
currentZoom: number;
|
|
426
|
+
/** Minimum zoom level */
|
|
427
|
+
minZoom: number;
|
|
428
|
+
/** Maximum zoom level */
|
|
429
|
+
maxZoom: number;
|
|
430
|
+
/** Zoom in */
|
|
431
|
+
zoomIn: () => void;
|
|
432
|
+
/** Zoom out */
|
|
433
|
+
zoomOut: () => void;
|
|
434
|
+
/** Set zoom level */
|
|
435
|
+
setZoom: (zoom: number) => void;
|
|
436
|
+
/** Check if can zoom in */
|
|
437
|
+
canZoomIn: () => boolean;
|
|
438
|
+
/** Check if can zoom out */
|
|
439
|
+
canZoomOut: () => boolean;
|
|
440
|
+
}
|
|
441
|
+
```
|
|
442
|
+
|
|
443
|
+
**Example:**
|
|
444
|
+
|
|
445
|
+
```tsx
|
|
446
|
+
function ZoomControls() {
|
|
447
|
+
const {
|
|
448
|
+
zoomIn,
|
|
449
|
+
zoomOut,
|
|
450
|
+
setZoom,
|
|
451
|
+
currentZoom,
|
|
452
|
+
minZoom,
|
|
453
|
+
maxZoom,
|
|
454
|
+
canZoomIn,
|
|
455
|
+
canZoomOut,
|
|
456
|
+
} = useZoom();
|
|
457
|
+
|
|
458
|
+
return (
|
|
459
|
+
<div>
|
|
460
|
+
<button onClick={zoomOut} disabled={!canZoomOut()}>
|
|
461
|
+
Zoom Out
|
|
462
|
+
</button>
|
|
463
|
+
<span>
|
|
464
|
+
Zoom: {currentZoom} ({minZoom}-{maxZoom})
|
|
465
|
+
</span>
|
|
466
|
+
<button onClick={zoomIn} disabled={!canZoomIn()}>
|
|
467
|
+
Zoom In
|
|
468
|
+
</button>
|
|
469
|
+
<button onClick={() => setZoom(2)}>Set Zoom to 2</button>
|
|
470
|
+
</div>
|
|
471
|
+
);
|
|
472
|
+
}
|
|
473
|
+
```
|
|
474
|
+
|
|
475
|
+
**Methods:**
|
|
476
|
+
|
|
477
|
+
- **`zoomIn(): void`** - Zooms in by one level.
|
|
478
|
+
|
|
479
|
+
- **`zoomOut(): void`** - Zooms out by one level.
|
|
480
|
+
|
|
481
|
+
- **`setZoom(zoom: number): void`** - Sets a specific zoom level.
|
|
482
|
+
|
|
483
|
+
- **`canZoomIn(): boolean`** - Checks if can zoom in. Returns `true` if current zoom is less than max zoom.
|
|
484
|
+
|
|
485
|
+
- **`canZoomOut(): boolean`** - Checks if can zoom out. Returns `true` if current zoom is greater than min zoom.
|
|
486
|
+
|
|
487
|
+
---
|
|
488
|
+
|
|
489
|
+
#### `useViewerContext()`
|
|
490
|
+
|
|
491
|
+
Hook to access viewer context directly. Usually you should use `useViewer()`, `useMarkers()`, or `useZoom()` instead.
|
|
492
|
+
|
|
493
|
+
**Returns:**
|
|
494
|
+
|
|
495
|
+
```typescript
|
|
496
|
+
interface ViewerContextValue {
|
|
497
|
+
/** Viewer instance */
|
|
498
|
+
viewer: EdgePdfViewer | null;
|
|
499
|
+
/** Whether viewer is initialized */
|
|
500
|
+
isInitialized: boolean;
|
|
501
|
+
/** Current markers */
|
|
502
|
+
markers: Marker[];
|
|
503
|
+
/** Current zoom state */
|
|
504
|
+
zoomState: ZoomState | null;
|
|
505
|
+
/** Internal: Function to update context value */
|
|
506
|
+
setContextValue: (
|
|
507
|
+
updates: Partial<Omit<ViewerContextValue, 'setContextValue'>>
|
|
508
|
+
) => void;
|
|
509
|
+
}
|
|
510
|
+
```
|
|
511
|
+
|
|
512
|
+
**Throws:**
|
|
513
|
+
|
|
514
|
+
- `Error` if used outside `ViewerProvider`
|
|
515
|
+
|
|
516
|
+
**Example:**
|
|
517
|
+
|
|
518
|
+
```tsx
|
|
519
|
+
function MyComponent() {
|
|
520
|
+
const { viewer, isInitialized, markers, zoomState } = useViewerContext();
|
|
521
|
+
// Use context values...
|
|
522
|
+
}
|
|
523
|
+
```
|
|
524
|
+
|
|
525
|
+
---
|
|
526
|
+
|
|
527
|
+
## Type Exports
|
|
528
|
+
|
|
529
|
+
The library also exports TypeScript types for convenience:
|
|
530
|
+
|
|
531
|
+
```typescript
|
|
532
|
+
import type {
|
|
533
|
+
EdgePDFViewerProps,
|
|
534
|
+
ZoomControlsProps,
|
|
535
|
+
ViewerContextValue,
|
|
536
|
+
ViewerProviderProps,
|
|
537
|
+
UseViewerReturn,
|
|
538
|
+
UseMarkersReturn,
|
|
539
|
+
UseZoomReturn,
|
|
540
|
+
} from '@edgepdf/viewer-react';
|
|
541
|
+
```
|
|
542
|
+
|
|
543
|
+
## Examples
|
|
544
|
+
|
|
545
|
+
### Basic Usage with Markers
|
|
546
|
+
|
|
547
|
+
```tsx
|
|
548
|
+
import {
|
|
549
|
+
ViewerProvider,
|
|
550
|
+
EdgePDFViewer,
|
|
551
|
+
useMarkers,
|
|
552
|
+
} from '@edgepdf/viewer-react';
|
|
553
|
+
|
|
554
|
+
function MarkerList() {
|
|
555
|
+
const { markers, addMarker, removeMarker } = useMarkers();
|
|
556
|
+
|
|
557
|
+
return (
|
|
558
|
+
<div>
|
|
559
|
+
<h3>Markers ({markers.length})</h3>
|
|
560
|
+
{markers.map((marker) => (
|
|
561
|
+
<div key={marker.id}>
|
|
562
|
+
<strong>{marker.label}</strong>
|
|
563
|
+
<button onClick={() => removeMarker(marker.id)}>Remove</button>
|
|
564
|
+
</div>
|
|
565
|
+
))}
|
|
566
|
+
</div>
|
|
567
|
+
);
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
function App() {
|
|
571
|
+
const config = {
|
|
572
|
+
tileUrl: 'https://example.com/tiles/{z}/{x}/{y}.png',
|
|
573
|
+
imageInfo: {
|
|
574
|
+
width: 2000,
|
|
575
|
+
height: 3000,
|
|
576
|
+
tileSize: 256,
|
|
577
|
+
maxZoom: 5,
|
|
578
|
+
minZoom: 0,
|
|
579
|
+
},
|
|
580
|
+
};
|
|
581
|
+
|
|
582
|
+
return (
|
|
583
|
+
<ViewerProvider>
|
|
584
|
+
<div style={{ display: 'flex' }}>
|
|
585
|
+
<div style={{ width: '300px' }}>
|
|
586
|
+
<MarkerList />
|
|
587
|
+
</div>
|
|
588
|
+
<div style={{ flex: 1, height: '100vh' }}>
|
|
589
|
+
<EdgePDFViewer config={config} />
|
|
590
|
+
</div>
|
|
591
|
+
</div>
|
|
592
|
+
</ViewerProvider>
|
|
593
|
+
);
|
|
594
|
+
}
|
|
595
|
+
```
|
|
596
|
+
|
|
597
|
+
### With Callbacks
|
|
598
|
+
|
|
599
|
+
```tsx
|
|
600
|
+
function App() {
|
|
601
|
+
const config = {
|
|
602
|
+
tileUrl: 'https://example.com/tiles/{z}/{x}/{y}.png',
|
|
603
|
+
imageInfo: {
|
|
604
|
+
width: 2000,
|
|
605
|
+
height: 3000,
|
|
606
|
+
tileSize: 256,
|
|
607
|
+
maxZoom: 5,
|
|
608
|
+
minZoom: 0,
|
|
609
|
+
},
|
|
610
|
+
};
|
|
611
|
+
|
|
612
|
+
const handleMarkerClick = (marker: Marker) => {
|
|
613
|
+
console.log('Marker clicked:', marker);
|
|
614
|
+
};
|
|
144
615
|
|
|
145
|
-
|
|
616
|
+
const handlePinsUpdate = (pins: Marker[]) => {
|
|
617
|
+
console.log('Pins updated:', pins);
|
|
618
|
+
// Save to backend, localStorage, etc.
|
|
619
|
+
};
|
|
146
620
|
|
|
147
|
-
|
|
621
|
+
return (
|
|
622
|
+
<ViewerProvider>
|
|
623
|
+
<EdgePDFViewer
|
|
624
|
+
config={config}
|
|
625
|
+
onMarkerClick={handleMarkerClick}
|
|
626
|
+
onPinsUpdate={handlePinsUpdate}
|
|
627
|
+
enableAnnotation={true}
|
|
628
|
+
/>
|
|
629
|
+
</ViewerProvider>
|
|
630
|
+
);
|
|
631
|
+
}
|
|
632
|
+
```
|
|
148
633
|
|
|
149
|
-
|
|
634
|
+
### Custom Zoom Controls
|
|
635
|
+
|
|
636
|
+
```tsx
|
|
637
|
+
function CustomZoomControls() {
|
|
638
|
+
const { zoomIn, zoomOut, currentZoom, canZoomIn, canZoomOut } = useZoom();
|
|
639
|
+
|
|
640
|
+
return (
|
|
641
|
+
<div style={{ position: 'absolute', top: 10, right: 10, zIndex: 1000 }}>
|
|
642
|
+
<button onClick={zoomOut} disabled={!canZoomOut()}>
|
|
643
|
+
−
|
|
644
|
+
</button>
|
|
645
|
+
<span>{currentZoom}</span>
|
|
646
|
+
<button onClick={zoomIn} disabled={!canZoomIn()}>
|
|
647
|
+
+
|
|
648
|
+
</button>
|
|
649
|
+
</div>
|
|
650
|
+
);
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
function App() {
|
|
654
|
+
return (
|
|
655
|
+
<ViewerProvider>
|
|
656
|
+
<EdgePDFViewer config={config} showZoomControls={false}>
|
|
657
|
+
<CustomZoomControls />
|
|
658
|
+
</EdgePDFViewer>
|
|
659
|
+
</ViewerProvider>
|
|
660
|
+
);
|
|
661
|
+
}
|
|
662
|
+
```
|
|
663
|
+
|
|
664
|
+
### Import/Export Markers
|
|
665
|
+
|
|
666
|
+
```tsx
|
|
667
|
+
function MarkerManager() {
|
|
668
|
+
const { markers, exportMarkers, importMarkers, clearMarkers } = useMarkers();
|
|
669
|
+
|
|
670
|
+
const handleExport = () => {
|
|
671
|
+
const data = exportMarkers();
|
|
672
|
+
const blob = new Blob([JSON.stringify(data, null, 2)], {
|
|
673
|
+
type: 'application/json',
|
|
674
|
+
});
|
|
675
|
+
const url = URL.createObjectURL(blob);
|
|
676
|
+
const a = document.createElement('a');
|
|
677
|
+
a.href = url;
|
|
678
|
+
a.download = 'markers.json';
|
|
679
|
+
a.click();
|
|
680
|
+
URL.revokeObjectURL(url);
|
|
681
|
+
};
|
|
682
|
+
|
|
683
|
+
const handleImport = (event: React.ChangeEvent<HTMLInputElement>) => {
|
|
684
|
+
const file = event.target.files?.[0];
|
|
685
|
+
if (!file) return;
|
|
686
|
+
|
|
687
|
+
const reader = new FileReader();
|
|
688
|
+
reader.onload = (e) => {
|
|
689
|
+
try {
|
|
690
|
+
const data = JSON.parse(e.target?.result as string);
|
|
691
|
+
importMarkers(data);
|
|
692
|
+
} catch (error) {
|
|
693
|
+
console.error('Failed to import markers:', error);
|
|
694
|
+
}
|
|
695
|
+
};
|
|
696
|
+
reader.readAsText(file);
|
|
697
|
+
};
|
|
698
|
+
|
|
699
|
+
return (
|
|
700
|
+
<div>
|
|
701
|
+
<button onClick={handleExport}>Export Markers</button>
|
|
702
|
+
<input type="file" accept=".json" onChange={handleImport} />
|
|
703
|
+
<button onClick={clearMarkers}>Clear All</button>
|
|
704
|
+
<div>Total markers: {markers.length}</div>
|
|
705
|
+
</div>
|
|
706
|
+
);
|
|
707
|
+
}
|
|
708
|
+
```
|