@dtducas/wh-forge-viewer 1.0.7 → 1.0.9-beta0
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 +364 -58
- package/dist/index.d.ts +1062 -4
- package/dist/index.esm.js +49638 -1473
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +49695 -1474
- package/dist/index.js.map +1 -1
- package/package.json +6 -2
package/dist/index.d.ts
CHANGED
|
@@ -3,11 +3,27 @@
|
|
|
3
3
|
// Definitions by: Duong Tran Quang <https://github.com/DTDucas>
|
|
4
4
|
/// <reference types="react" />
|
|
5
5
|
declare module '@dtducas/wh-forge-viewer' {
|
|
6
|
-
import {
|
|
6
|
+
import type { ReactElement, ReactNode } from 'react';
|
|
7
7
|
/**
|
|
8
8
|
* Supported file extensions for the Forge Viewer
|
|
9
9
|
*/
|
|
10
|
-
export type TSupportedFileExtension = 'pdf' | 'dwf' | 'dwfx';
|
|
10
|
+
export type TSupportedFileExtension = 'pdf' | 'dwf' | 'dwfx' | 'gltf' | 'glb';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Toolbar visibility options
|
|
14
|
+
*/
|
|
15
|
+
export interface IToolbarOptions {
|
|
16
|
+
/** Show Pan button (default: true) */
|
|
17
|
+
showPan?: boolean;
|
|
18
|
+
/** Show Document Browser button (default: true) */
|
|
19
|
+
showDocBrowser?: boolean;
|
|
20
|
+
/** Show Download button (default: true) */
|
|
21
|
+
showDownload?: boolean;
|
|
22
|
+
/** Show Pagination controls (default: true) */
|
|
23
|
+
showPagination?: boolean;
|
|
24
|
+
/** Master switch - show entire custom toolbar (default: true) */
|
|
25
|
+
showToolbar?: boolean;
|
|
26
|
+
}
|
|
11
27
|
/**
|
|
12
28
|
* Autodesk Forge Viewer namespace
|
|
13
29
|
* For full type definitions, see Autodesk Forge Viewer documentation
|
|
@@ -27,6 +43,10 @@ declare module '@dtducas/wh-forge-viewer' {
|
|
|
27
43
|
setTool(toolName: string): void;
|
|
28
44
|
toolbar: any;
|
|
29
45
|
model: any;
|
|
46
|
+
/** The WebGL canvas element used for rendering */
|
|
47
|
+
canvas: HTMLCanvasElement;
|
|
48
|
+
/** The viewer's DOM container element */
|
|
49
|
+
container: HTMLElement;
|
|
30
50
|
}
|
|
31
51
|
export interface Extension {
|
|
32
52
|
load(): boolean;
|
|
@@ -38,6 +58,382 @@ declare module '@dtducas/wh-forge-viewer' {
|
|
|
38
58
|
export const TOOLBAR_CREATED_EVENT: string;
|
|
39
59
|
}
|
|
40
60
|
}
|
|
61
|
+
// ========================================
|
|
62
|
+
// Drawing Types
|
|
63
|
+
// ========================================
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Supported markup tool types
|
|
67
|
+
*/
|
|
68
|
+
export type TMarkupToolType =
|
|
69
|
+
| 'arrow'
|
|
70
|
+
| 'rectangle'
|
|
71
|
+
| 'ellipse' // Circle tool
|
|
72
|
+
| 'cloud'
|
|
73
|
+
| 'label' // Text tool
|
|
74
|
+
| 'freehand' // Pen tool
|
|
75
|
+
| 'line'
|
|
76
|
+
| 'polyline'
|
|
77
|
+
| 'polycloud'
|
|
78
|
+
| 'callout'
|
|
79
|
+
| 'image'; // Image/Stamp tool
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Markup style configuration
|
|
83
|
+
*/
|
|
84
|
+
export interface IMarkupStyle {
|
|
85
|
+
strokeColor: string;
|
|
86
|
+
strokeWidth: number;
|
|
87
|
+
strokeOpacity: number;
|
|
88
|
+
fillColor: string;
|
|
89
|
+
fillOpacity: number;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Markup data structure
|
|
94
|
+
*/
|
|
95
|
+
export interface IMarkupData {
|
|
96
|
+
version: string;
|
|
97
|
+
markups: any[];
|
|
98
|
+
metadata?: {
|
|
99
|
+
createdAt: string;
|
|
100
|
+
modifiedAt: string;
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* DrawingManager configuration
|
|
106
|
+
*/
|
|
107
|
+
export interface IDrawingManagerConfig {
|
|
108
|
+
autoEnterEditMode?: boolean;
|
|
109
|
+
defaultTool?: TMarkupToolType;
|
|
110
|
+
defaultStyles?: Partial<IMarkupStyle>;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* MarkupToolbar component props
|
|
115
|
+
*/
|
|
116
|
+
export interface IMarkupToolbarProps {
|
|
117
|
+
drawingManager: DrawingManager;
|
|
118
|
+
onClose?: () => void;
|
|
119
|
+
position?: 'top' | 'bottom';
|
|
120
|
+
theme?: 'light' | 'dark';
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// ========================================
|
|
124
|
+
// Property Panel Types
|
|
125
|
+
// ========================================
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Property control types
|
|
129
|
+
*/
|
|
130
|
+
export type TPropertyControlType =
|
|
131
|
+
| 'color'
|
|
132
|
+
| 'slider'
|
|
133
|
+
| 'select'
|
|
134
|
+
| 'button-group'
|
|
135
|
+
| 'toggle'
|
|
136
|
+
| 'action-button';
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Property value types
|
|
140
|
+
*/
|
|
141
|
+
export type TPropertyValue = string | number | boolean;
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Property option for select/button-group controls
|
|
145
|
+
*/
|
|
146
|
+
export interface IPropertyOption {
|
|
147
|
+
value: string | number;
|
|
148
|
+
label: string;
|
|
149
|
+
icon?: ReactNode;
|
|
150
|
+
tooltip?: string;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Base property definition
|
|
155
|
+
*/
|
|
156
|
+
export interface IPropertyDefinition {
|
|
157
|
+
key: string;
|
|
158
|
+
label: string;
|
|
159
|
+
controlType: TPropertyControlType;
|
|
160
|
+
defaultValue: TPropertyValue;
|
|
161
|
+
category: 'stroke' | 'fill' | 'style' | 'text' | 'layer' | 'action';
|
|
162
|
+
tooltip?: string;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Color property
|
|
167
|
+
*/
|
|
168
|
+
export interface IColorProperty extends IPropertyDefinition {
|
|
169
|
+
controlType: 'color';
|
|
170
|
+
defaultValue: string;
|
|
171
|
+
presetColors?: string[];
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Slider property
|
|
176
|
+
*/
|
|
177
|
+
export interface ISliderProperty extends IPropertyDefinition {
|
|
178
|
+
controlType: 'slider';
|
|
179
|
+
defaultValue: number;
|
|
180
|
+
min: number;
|
|
181
|
+
max: number;
|
|
182
|
+
step: number;
|
|
183
|
+
marks?: Record<number, string>;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Select property
|
|
188
|
+
*/
|
|
189
|
+
export interface ISelectProperty extends IPropertyDefinition {
|
|
190
|
+
controlType: 'select';
|
|
191
|
+
defaultValue: string | number;
|
|
192
|
+
options: IPropertyOption[];
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Button group property
|
|
197
|
+
*/
|
|
198
|
+
export interface IButtonGroupProperty extends IPropertyDefinition {
|
|
199
|
+
controlType: 'button-group';
|
|
200
|
+
defaultValue: string | number;
|
|
201
|
+
options: IPropertyOption[];
|
|
202
|
+
exclusive?: boolean;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Toggle property
|
|
207
|
+
*/
|
|
208
|
+
export interface IToggleProperty extends IPropertyDefinition {
|
|
209
|
+
controlType: 'toggle';
|
|
210
|
+
defaultValue: boolean;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Action button property
|
|
215
|
+
*/
|
|
216
|
+
export interface IActionButtonProperty extends IPropertyDefinition {
|
|
217
|
+
controlType: 'action-button';
|
|
218
|
+
defaultValue: never;
|
|
219
|
+
action: string;
|
|
220
|
+
icon?: ReactNode;
|
|
221
|
+
variant?: 'default' | 'danger' | 'primary';
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* Union type of all property types
|
|
226
|
+
*/
|
|
227
|
+
export type TProperty =
|
|
228
|
+
| IColorProperty
|
|
229
|
+
| ISliderProperty
|
|
230
|
+
| ISelectProperty
|
|
231
|
+
| IButtonGroupProperty
|
|
232
|
+
| IToggleProperty
|
|
233
|
+
| IActionButtonProperty;
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* Tool property configuration
|
|
237
|
+
*/
|
|
238
|
+
export interface IToolPropertyConfig {
|
|
239
|
+
toolType: TMarkupToolType;
|
|
240
|
+
displayName: string;
|
|
241
|
+
properties: TProperty[];
|
|
242
|
+
onPropertyChange?: (key: string, value: TPropertyValue) => void;
|
|
243
|
+
onAction?: (action: string) => void;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* PropertyPanel component props
|
|
248
|
+
*/
|
|
249
|
+
export interface IPropertyPanelProps {
|
|
250
|
+
config: IToolPropertyConfig | null;
|
|
251
|
+
values: Record<string, TPropertyValue>;
|
|
252
|
+
onPropertyChange: (key: string, value: TPropertyValue) => void;
|
|
253
|
+
onAction: (action: string) => void;
|
|
254
|
+
visible?: boolean;
|
|
255
|
+
position?: 'left' | 'right';
|
|
256
|
+
theme?: 'light' | 'dark';
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* DrawingManager class
|
|
261
|
+
* Manages Forge Viewer markup functionality
|
|
262
|
+
*/
|
|
263
|
+
export class DrawingManager {
|
|
264
|
+
constructor(
|
|
265
|
+
viewer: Autodesk.Viewing.GuiViewer3D,
|
|
266
|
+
eventBus: any,
|
|
267
|
+
config?: IDrawingManagerConfig
|
|
268
|
+
);
|
|
269
|
+
enterEditMode(): Promise<void>;
|
|
270
|
+
leaveEditMode(): void;
|
|
271
|
+
isEditMode(): boolean;
|
|
272
|
+
setActiveTool(toolType: TMarkupToolType): void;
|
|
273
|
+
getActiveTool(): TMarkupToolType | null;
|
|
274
|
+
setStrokeStyle(color: string, width: number, opacity: number): void;
|
|
275
|
+
setFillStyle(color: string, opacity: number): void;
|
|
276
|
+
saveMarkups(): IMarkupData;
|
|
277
|
+
loadMarkups(data: IMarkupData): void;
|
|
278
|
+
clearMarkups(): void;
|
|
279
|
+
exportToSVG(): string;
|
|
280
|
+
undo(): void;
|
|
281
|
+
redo(): void;
|
|
282
|
+
getCurrentStyles(): IMarkupStyle;
|
|
283
|
+
getCurrentToolPropertyConfig(): IToolPropertyConfig | null;
|
|
284
|
+
handlePropertyChange(key: string, value: any): void;
|
|
285
|
+
handleAction(action: string): void;
|
|
286
|
+
destroy(): void;
|
|
287
|
+
|
|
288
|
+
// Collaborative Markup API
|
|
289
|
+
getMarkupData(viewableGUID: string): IMarkupDataExport;
|
|
290
|
+
loadMarkupData(data: IMarkupDataExport, options?: ILoadMarkupDataOptions): Promise<void>;
|
|
291
|
+
onMarkupChange(callback: OnMarkupChangeCallback): () => void;
|
|
292
|
+
applyDelta(delta: IMarkupDelta & { compactElement?: IMarkupElementCompact }): boolean;
|
|
293
|
+
applyBatch(elements: IMarkupElementCompact[], clearExisting?: boolean): number;
|
|
294
|
+
getMarkupSVG(): string;
|
|
295
|
+
|
|
296
|
+
// Real-time Collaboration Rendering APIs
|
|
297
|
+
renderFromSVG(svgString: string, options?: { clearExisting?: boolean; layerId?: string }): number;
|
|
298
|
+
mergeFromSVG(svgString: string, layerId?: string): number;
|
|
299
|
+
clearForPageChange(viewableGUID: string): IMarkupDataExport;
|
|
300
|
+
restoreAfterPageChange(data: IMarkupDataExport, options?: ILoadMarkupDataOptions): Promise<void>;
|
|
301
|
+
|
|
302
|
+
// SVG/JSON Conversion APIs
|
|
303
|
+
getMarkupDataAsJson(viewableGUID: string): IJsonMarkupData;
|
|
304
|
+
loadMarkupDataFromJson(jsonData: IJsonMarkupData, options?: ILoadMarkupDataOptions): Promise<void>;
|
|
305
|
+
|
|
306
|
+
// PDF Export API
|
|
307
|
+
exportPDFWithMarkup(pdfSource: Blob | string, markupsByPage: IPageMarkupData[], options?: IExportPdfOptions): Promise<IExportResult>;
|
|
308
|
+
exportAndDownloadPDF(pdfSource: Blob | string, markupsByPage: IPageMarkupData[], options?: IExportPdfOptions): Promise<boolean>;
|
|
309
|
+
exportCurrentPagePDF(pdfSource: Blob | string, pageIndex?: number, options?: IExportPdfOptions): Promise<IExportResult>;
|
|
310
|
+
|
|
311
|
+
// User Presence API
|
|
312
|
+
updateUserCursor(cursor: IUserCursor): void;
|
|
313
|
+
removeUserCursor(userId: string): void;
|
|
314
|
+
getRemoteCursors(): Map<string, IUserCursor>;
|
|
315
|
+
onLocalCursorMove(callback: OnLocalCursorMoveCallback): () => void;
|
|
316
|
+
clearAllCursors(): void;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
/**
|
|
320
|
+
* MarkupToolbar component
|
|
321
|
+
*/
|
|
322
|
+
export function MarkupToolbar(props: IMarkupToolbarProps): JSX.Element;
|
|
323
|
+
|
|
324
|
+
/**
|
|
325
|
+
* PropertyPanel component
|
|
326
|
+
*/
|
|
327
|
+
export function PropertyPanel(props: IPropertyPanelProps): JSX.Element;
|
|
328
|
+
|
|
329
|
+
/**
|
|
330
|
+
* Markup tool constants
|
|
331
|
+
*/
|
|
332
|
+
export const MARKUP_TOOLS: {
|
|
333
|
+
ARROW: 'arrow';
|
|
334
|
+
RECTANGLE: 'rectangle';
|
|
335
|
+
CIRCLE: 'ellipse';
|
|
336
|
+
CLOUD: 'cloud';
|
|
337
|
+
TEXT: 'label';
|
|
338
|
+
PEN: 'freehand';
|
|
339
|
+
/** @deprecated Use PEN instead */
|
|
340
|
+
FREEHAND: 'freehand';
|
|
341
|
+
LINE: 'line';
|
|
342
|
+
POLYLINE: 'polyline';
|
|
343
|
+
POLYCLOUD: 'polycloud';
|
|
344
|
+
CALLOUT: 'callout';
|
|
345
|
+
IMAGE: 'image';
|
|
346
|
+
};
|
|
347
|
+
|
|
348
|
+
/**
|
|
349
|
+
* Default markup styles
|
|
350
|
+
*/
|
|
351
|
+
export const DEFAULT_MARKUP_STYLES: IMarkupStyle;
|
|
352
|
+
|
|
353
|
+
/**
|
|
354
|
+
* Preset colors
|
|
355
|
+
*/
|
|
356
|
+
export const PRESET_COLORS: readonly string[];
|
|
357
|
+
|
|
358
|
+
// ========================================
|
|
359
|
+
// Markup Tools (OOP Architecture)
|
|
360
|
+
// ========================================
|
|
361
|
+
|
|
362
|
+
/**
|
|
363
|
+
* Abstract base class for all markup tools
|
|
364
|
+
*/
|
|
365
|
+
export abstract class MarkupTool {
|
|
366
|
+
constructor(markupsCore: any);
|
|
367
|
+
getToolId(): string;
|
|
368
|
+
getEditModeClassName(): string;
|
|
369
|
+
getDisplayName(): string;
|
|
370
|
+
activate(styles?: IMarkupStyle): void;
|
|
371
|
+
deactivate(): void;
|
|
372
|
+
supportsFillColor(): boolean;
|
|
373
|
+
getMetadata(): Record<string, any>;
|
|
374
|
+
getPropertyConfig(): IToolPropertyConfig | null;
|
|
375
|
+
onPropertyChange(key: string, value: any): void;
|
|
376
|
+
onAction(action: string): void;
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
/**
|
|
380
|
+
* Concrete tool implementations
|
|
381
|
+
*/
|
|
382
|
+
export class ArrowTool extends MarkupTool {}
|
|
383
|
+
export class RectangleTool extends MarkupTool {}
|
|
384
|
+
export class CircleTool extends MarkupTool {}
|
|
385
|
+
export class CloudTool extends MarkupTool {}
|
|
386
|
+
export class TextTool extends MarkupTool {}
|
|
387
|
+
export class FreehandTool extends MarkupTool {}
|
|
388
|
+
/** Alias for FreehandTool */
|
|
389
|
+
export class PenTool extends MarkupTool {}
|
|
390
|
+
export class LineTool extends MarkupTool {}
|
|
391
|
+
export class PolylineTool extends MarkupTool {}
|
|
392
|
+
export class PolycloudTool extends MarkupTool {}
|
|
393
|
+
export class CalloutTool extends MarkupTool {}
|
|
394
|
+
export class ImageTool extends MarkupTool {
|
|
395
|
+
setImage(imageData: string, width: number, height: number, type?: 'base64' | 'svg'): void;
|
|
396
|
+
getPendingImage(): { data: string; width: number; height: number; type: 'base64' | 'svg'; storageId?: string } | null;
|
|
397
|
+
clearPendingImage(): void;
|
|
398
|
+
loadImageFile(file: File, options?: { storeInIndexedDB?: boolean }): Promise<string | void>;
|
|
399
|
+
loadSVGFile(file: File): Promise<void>;
|
|
400
|
+
// IndexedDB Storage Methods
|
|
401
|
+
initializeStorage(): Promise<void>;
|
|
402
|
+
getStorageService(): ImageStorageService | null;
|
|
403
|
+
storeImage(imageData: string, metadata?: { fileName?: string; mimeType?: string; width?: number; height?: number }): Promise<string>;
|
|
404
|
+
getStoredImage(storageId: string): Promise<string | null>;
|
|
405
|
+
hasStoredImage(storageId: string): Promise<boolean>;
|
|
406
|
+
deleteStoredImage(storageId: string): Promise<boolean>;
|
|
407
|
+
getCurrentStorageId(): string;
|
|
408
|
+
loadFromStorage(storageId: string): Promise<void>;
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
/**
|
|
412
|
+
* Tool Factory for creating tool instances
|
|
413
|
+
*/
|
|
414
|
+
export class ToolFactory {
|
|
415
|
+
constructor(markupsCore: any);
|
|
416
|
+
createTool(toolType: TMarkupToolType): MarkupTool | null;
|
|
417
|
+
getAvailableTools(): TMarkupToolType[];
|
|
418
|
+
static registerCustomTool(toolType: TMarkupToolType, toolClass: any): void;
|
|
419
|
+
clearInstances(): void;
|
|
420
|
+
getToolInstance(toolType: TMarkupToolType): MarkupTool | undefined;
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
/**
|
|
424
|
+
* Tool Registry for managing tool types
|
|
425
|
+
*/
|
|
426
|
+
export class ToolRegistry {
|
|
427
|
+
static registerTool(toolType: TMarkupToolType, toolClass: any): void;
|
|
428
|
+
static getToolConstructor(toolType: TMarkupToolType): any;
|
|
429
|
+
static getAllToolTypes(): TMarkupToolType[];
|
|
430
|
+
static hasToolType(toolType: TMarkupToolType): boolean;
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
// ========================================
|
|
434
|
+
// Viewer Component Props
|
|
435
|
+
// ========================================
|
|
436
|
+
|
|
41
437
|
/**
|
|
42
438
|
* Props for ViewerForgePDF component
|
|
43
439
|
*/
|
|
@@ -47,13 +443,27 @@ declare module '@dtducas/wh-forge-viewer' {
|
|
|
47
443
|
*/
|
|
48
444
|
filePath: string;
|
|
49
445
|
/**
|
|
50
|
-
* File extension (pdf, dwf, dwfx)
|
|
446
|
+
* File extension (pdf, dwf, dwfx, gltf, glb)
|
|
51
447
|
*/
|
|
52
448
|
fileExt: TSupportedFileExtension;
|
|
449
|
+
/**
|
|
450
|
+
* Toolbar visibility options
|
|
451
|
+
* Controls which toolbar buttons and controls are displayed
|
|
452
|
+
*/
|
|
453
|
+
toolbarOptions?: IToolbarOptions;
|
|
53
454
|
/**
|
|
54
455
|
* Callback to receive viewer instance when initialized
|
|
55
456
|
*/
|
|
56
457
|
setViewer?: (viewer: Autodesk.Viewing.GuiViewer3D | null) => void;
|
|
458
|
+
/**
|
|
459
|
+
* Enable custom markup toolbar
|
|
460
|
+
* @default false
|
|
461
|
+
*/
|
|
462
|
+
enableCustomMarkups?: boolean;
|
|
463
|
+
/**
|
|
464
|
+
* Configuration for DrawingManager
|
|
465
|
+
*/
|
|
466
|
+
markupConfig?: IDrawingManagerConfig;
|
|
57
467
|
}
|
|
58
468
|
/**
|
|
59
469
|
* ViewerForgePDF - React component for displaying PDF and CAD files using Autodesk Forge Viewer
|
|
@@ -69,11 +479,659 @@ declare module '@dtducas/wh-forge-viewer' {
|
|
|
69
479
|
* <ViewerForgePDF
|
|
70
480
|
* filePath="https://example.com/document.pdf"
|
|
71
481
|
* fileExt="pdf"
|
|
482
|
+
* toolbarOptions={{ showDownload: true, showDocBrowser: true }}
|
|
72
483
|
* setViewer={setViewer}
|
|
73
484
|
* />
|
|
74
485
|
* );
|
|
75
486
|
* }
|
|
76
487
|
* ```
|
|
77
488
|
*/
|
|
78
|
-
export
|
|
489
|
+
export function ViewerForgePDF(props: IViewerForgePDFProps): JSX.Element;
|
|
490
|
+
|
|
491
|
+
// ========================================
|
|
492
|
+
// EventBus for page change events
|
|
493
|
+
// ========================================
|
|
494
|
+
|
|
495
|
+
/**
|
|
496
|
+
* Event names for EventBus subscriptions
|
|
497
|
+
*/
|
|
498
|
+
export const EVENT_NAMES: {
|
|
499
|
+
PAGE_CHANGING: 'page:changing';
|
|
500
|
+
PAGE_CHANGED: 'page:changed';
|
|
501
|
+
VIEWABLES_SET: 'viewables:set';
|
|
502
|
+
DOC_BROWSER_OPENED: 'docBrowser:opened';
|
|
503
|
+
DOC_BROWSER_CLOSED: 'docBrowser:closed';
|
|
504
|
+
MARKUP_CHANGED: 'markup:changed';
|
|
505
|
+
};
|
|
506
|
+
|
|
507
|
+
/**
|
|
508
|
+
* EventBus singleton for cross-component communication
|
|
509
|
+
*/
|
|
510
|
+
export class EventBus {
|
|
511
|
+
static getInstance(): EventBus;
|
|
512
|
+
on(event: string, callback: (...args: any[]) => void): void;
|
|
513
|
+
off(event: string, callback: (...args: any[]) => void): void;
|
|
514
|
+
emit(event: string, ...args: any[]): void;
|
|
515
|
+
once(event: string, callback: (...args: any[]) => void): void;
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
// ========================================
|
|
519
|
+
// Collaborative Markup API Types
|
|
520
|
+
// ========================================
|
|
521
|
+
|
|
522
|
+
/**
|
|
523
|
+
* Individual markup item
|
|
524
|
+
*/
|
|
525
|
+
export interface IMarkupItem {
|
|
526
|
+
id: string;
|
|
527
|
+
type: string;
|
|
528
|
+
position: { x: number; y: number };
|
|
529
|
+
size: { x: number; y: number };
|
|
530
|
+
rotation: number;
|
|
531
|
+
style: Record<string, any>;
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
/**
|
|
535
|
+
* Markup data export format for persistence
|
|
536
|
+
*/
|
|
537
|
+
export interface IMarkupDataExport {
|
|
538
|
+
version: string;
|
|
539
|
+
/** Viewable identifier - provided by the consuming app (any string format) */
|
|
540
|
+
viewableGUID: string;
|
|
541
|
+
svgString: string;
|
|
542
|
+
markups: IMarkupItem[];
|
|
543
|
+
timestamp: number;
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
/**
|
|
547
|
+
* Markup change delta for real-time sync
|
|
548
|
+
*/
|
|
549
|
+
export interface IMarkupDelta {
|
|
550
|
+
type: 'create' | 'update' | 'delete';
|
|
551
|
+
markupId: string;
|
|
552
|
+
data?: Partial<IMarkupItem>;
|
|
553
|
+
timestamp: number;
|
|
554
|
+
/** Compact element for JSON-based sync (attached when using serializer) */
|
|
555
|
+
compactElement?: IMarkupElementCompact;
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
// ========================================
|
|
559
|
+
// JSON-based Sync Types (Compact Format)
|
|
560
|
+
// ========================================
|
|
561
|
+
|
|
562
|
+
/**
|
|
563
|
+
* Compact markup element format for real-time sync
|
|
564
|
+
* ~80 bytes vs ~500 bytes for SVG strings
|
|
565
|
+
*/
|
|
566
|
+
export interface IMarkupElementCompact {
|
|
567
|
+
/** Unique markup ID */
|
|
568
|
+
id: string;
|
|
569
|
+
/** Markup type */
|
|
570
|
+
type: string;
|
|
571
|
+
/** Position in markup coordinates [x, y] */
|
|
572
|
+
pos: [number, number];
|
|
573
|
+
/** Size in markup coordinates [width, height] */
|
|
574
|
+
size: [number, number];
|
|
575
|
+
/** Rotation in radians */
|
|
576
|
+
rot: number;
|
|
577
|
+
/** Style properties (compact keys) */
|
|
578
|
+
style: ICompactStyle;
|
|
579
|
+
/** Shape-specific data */
|
|
580
|
+
shape?: IShapeData;
|
|
581
|
+
/** Version number for CRDT conflict resolution */
|
|
582
|
+
version: number;
|
|
583
|
+
/** Tombstone flag for deletion */
|
|
584
|
+
deleted?: boolean;
|
|
585
|
+
/** Timestamp (Unix epoch ms) */
|
|
586
|
+
ts: number;
|
|
587
|
+
/** Created by user ID */
|
|
588
|
+
createdBy?: string;
|
|
589
|
+
/** Modified by user ID */
|
|
590
|
+
modifiedBy?: string;
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
/**
|
|
594
|
+
* Compact style properties (short keys for minimal payload)
|
|
595
|
+
*/
|
|
596
|
+
export interface ICompactStyle {
|
|
597
|
+
/** Stroke color (hex) */
|
|
598
|
+
sc?: string;
|
|
599
|
+
/** Stroke width */
|
|
600
|
+
sw?: number;
|
|
601
|
+
/** Stroke opacity (0-1) */
|
|
602
|
+
so?: number;
|
|
603
|
+
/** Stroke dash array */
|
|
604
|
+
sd?: string;
|
|
605
|
+
/** Fill color (hex) */
|
|
606
|
+
fc?: string;
|
|
607
|
+
/** Fill opacity (0-1) */
|
|
608
|
+
fo?: number;
|
|
609
|
+
/** Font size */
|
|
610
|
+
fs?: number;
|
|
611
|
+
/** Font family */
|
|
612
|
+
ff?: string;
|
|
613
|
+
/** Font weight */
|
|
614
|
+
fw?: string;
|
|
615
|
+
/** Font style */
|
|
616
|
+
fi?: string;
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
/**
|
|
620
|
+
* Shape-specific data for different markup types
|
|
621
|
+
*/
|
|
622
|
+
export interface IShapeData {
|
|
623
|
+
/** Points array (flat: [x1,y1,x2,y2,...]) */
|
|
624
|
+
points?: number[];
|
|
625
|
+
/** Text content */
|
|
626
|
+
text?: string;
|
|
627
|
+
/** Image data URI */
|
|
628
|
+
imageData?: string;
|
|
629
|
+
/** Cloud arc count */
|
|
630
|
+
arcCount?: number;
|
|
631
|
+
/** Path data string */
|
|
632
|
+
pathData?: string;
|
|
633
|
+
/** Arrow head configuration */
|
|
634
|
+
head?: { type: string; size: number };
|
|
635
|
+
/** Arrow tail configuration */
|
|
636
|
+
tail?: { type: string; size: number };
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
/**
|
|
640
|
+
* Serialize a Forge Markup object to compact JSON format
|
|
641
|
+
*/
|
|
642
|
+
export function serializeMarkup(
|
|
643
|
+
markup: any,
|
|
644
|
+
userId?: string
|
|
645
|
+
): IMarkupElementCompact | null;
|
|
646
|
+
|
|
647
|
+
/**
|
|
648
|
+
* Deserialize compact style to Forge-compatible style object
|
|
649
|
+
*/
|
|
650
|
+
export function deserializeStyle(compact: ICompactStyle): Record<string, any>;
|
|
651
|
+
|
|
652
|
+
/**
|
|
653
|
+
* Expand flat points array to {x, y} objects
|
|
654
|
+
*/
|
|
655
|
+
export function expandPoints(flatPoints: number[]): Array<{ x: number; y: number }>;
|
|
656
|
+
|
|
657
|
+
/**
|
|
658
|
+
* Calculate byte size of serialized markup
|
|
659
|
+
*/
|
|
660
|
+
export function getSerializedSize(compact: IMarkupElementCompact): number;
|
|
661
|
+
|
|
662
|
+
/**
|
|
663
|
+
* Render a compact markup element to the Forge Viewer canvas
|
|
664
|
+
*/
|
|
665
|
+
export function renderMarkupElement(
|
|
666
|
+
element: IMarkupElementCompact,
|
|
667
|
+
markupsCore: any,
|
|
668
|
+
mode?: 'create' | 'update'
|
|
669
|
+
): boolean;
|
|
670
|
+
|
|
671
|
+
/**
|
|
672
|
+
* Delete a markup element from the canvas
|
|
673
|
+
*/
|
|
674
|
+
export function deleteMarkupElement(
|
|
675
|
+
elementId: string,
|
|
676
|
+
markupsCore: any
|
|
677
|
+
): boolean;
|
|
678
|
+
|
|
679
|
+
/**
|
|
680
|
+
* Render multiple markup elements as a batch
|
|
681
|
+
*/
|
|
682
|
+
export function renderMarkupBatch(
|
|
683
|
+
elements: IMarkupElementCompact[],
|
|
684
|
+
markupsCore: any,
|
|
685
|
+
clearExisting?: boolean
|
|
686
|
+
): number;
|
|
687
|
+
|
|
688
|
+
/**
|
|
689
|
+
* Clear all markups from the canvas
|
|
690
|
+
*/
|
|
691
|
+
export function clearAllMarkups(markupsCore: any): void;
|
|
692
|
+
|
|
693
|
+
/**
|
|
694
|
+
* Options for loadMarkupData method
|
|
695
|
+
*/
|
|
696
|
+
export interface ILoadMarkupDataOptions {
|
|
697
|
+
mode?: 'replace' | 'merge';
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
/**
|
|
701
|
+
* Callback type for markup change subscription
|
|
702
|
+
*/
|
|
703
|
+
export type OnMarkupChangeCallback = (delta: IMarkupDelta) => void;
|
|
704
|
+
|
|
705
|
+
// ========================================
|
|
706
|
+
// User Presence API Types
|
|
707
|
+
// ========================================
|
|
708
|
+
|
|
709
|
+
/**
|
|
710
|
+
* User cursor data for collaborative presence
|
|
711
|
+
*/
|
|
712
|
+
export interface IUserCursor {
|
|
713
|
+
userId: string;
|
|
714
|
+
userName: string;
|
|
715
|
+
color: string;
|
|
716
|
+
position: { x: number; y: number };
|
|
717
|
+
timestamp: number;
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
/**
|
|
721
|
+
* Callback for local cursor movement
|
|
722
|
+
*/
|
|
723
|
+
export type OnLocalCursorMoveCallback = (payload: {
|
|
724
|
+
position: { x: number; y: number };
|
|
725
|
+
screenPosition: { x: number; y: number };
|
|
726
|
+
timestamp: number;
|
|
727
|
+
}) => void;
|
|
728
|
+
|
|
729
|
+
/**
|
|
730
|
+
* CursorOverlay component props
|
|
731
|
+
*/
|
|
732
|
+
export interface ICursorOverlayProps {
|
|
733
|
+
cursors: Map<string, IUserCursor>;
|
|
734
|
+
containerRef?: React.RefObject<HTMLElement>;
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
/**
|
|
738
|
+
* CursorOverlay component for displaying remote user cursors
|
|
739
|
+
*/
|
|
740
|
+
export function CursorOverlay(props: ICursorOverlayProps): JSX.Element;
|
|
741
|
+
|
|
742
|
+
// ========================================
|
|
743
|
+
// PDF Export Services
|
|
744
|
+
// ========================================
|
|
745
|
+
|
|
746
|
+
/**
|
|
747
|
+
* Export options for PDF with markup
|
|
748
|
+
*/
|
|
749
|
+
export interface IExportPdfOptions {
|
|
750
|
+
/** Output filename without extension @default 'document-with-markup' */
|
|
751
|
+
filename?: string;
|
|
752
|
+
/** Preserve original PDF metadata @default true */
|
|
753
|
+
preserveMetadata?: boolean;
|
|
754
|
+
/** Flatten markups (cannot be edited later) @default true */
|
|
755
|
+
flattenMarkups?: boolean;
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
/**
|
|
759
|
+
* Markup data for a single page
|
|
760
|
+
*/
|
|
761
|
+
export interface IPageMarkupData {
|
|
762
|
+
/** Page index (0-based) */
|
|
763
|
+
pageIndex: number;
|
|
764
|
+
/** SVG string of markups for this page */
|
|
765
|
+
svgString: string;
|
|
766
|
+
/** SVG viewBox dimensions (extracted from SVG if not provided) */
|
|
767
|
+
viewBox?: { x: number; y: number; width: number; height: number };
|
|
768
|
+
/** Model bounding box from Forge Viewer (PDF page extent in viewer coords) */
|
|
769
|
+
modelBounds?: { minX: number; minY: number; maxX: number; maxY: number };
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
/**
|
|
773
|
+
* Export result
|
|
774
|
+
*/
|
|
775
|
+
export interface IExportResult {
|
|
776
|
+
/** Whether export was successful */
|
|
777
|
+
success: boolean;
|
|
778
|
+
/** Error message if failed */
|
|
779
|
+
error?: string;
|
|
780
|
+
/** Resulting PDF blob */
|
|
781
|
+
blob?: Blob;
|
|
782
|
+
/** Number of pages processed */
|
|
783
|
+
pagesProcessed: number;
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
/**
|
|
787
|
+
* Conversion options for SVG to PDF
|
|
788
|
+
*/
|
|
789
|
+
export interface ISvgToPdfOptions {
|
|
790
|
+
/** PDF page width in points */
|
|
791
|
+
pageWidth: number;
|
|
792
|
+
/** PDF page height in points */
|
|
793
|
+
pageHeight: number;
|
|
794
|
+
/** SVG viewBox dimensions */
|
|
795
|
+
svgViewBox: { x: number; y: number; width: number; height: number };
|
|
796
|
+
/** Model bounding box (PDF page extent in viewer coords) - used instead of viewBox for mapping */
|
|
797
|
+
modelBounds?: { minX: number; minY: number; maxX: number; maxY: number };
|
|
798
|
+
/** Scale factor @default 1 */
|
|
799
|
+
scale?: number;
|
|
800
|
+
/** Offset for positioning */
|
|
801
|
+
offset?: { x: number; y: number };
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
/**
|
|
805
|
+
* Service for exporting PDF with markup overlaid as vector graphics
|
|
806
|
+
* Uses pdf-lib and SvgToPdfConverter for client-side PDF manipulation
|
|
807
|
+
*
|
|
808
|
+
* @example
|
|
809
|
+
* ```typescript
|
|
810
|
+
* const exportService = new MarkupExportService();
|
|
811
|
+
* const result = await exportService.exportPDFWithMarkup(
|
|
812
|
+
* pdfBlob,
|
|
813
|
+
* [{ pageIndex: 0, svgString: svgMarkup }],
|
|
814
|
+
* { filename: 'annotated-document' }
|
|
815
|
+
* );
|
|
816
|
+
* ```
|
|
817
|
+
*/
|
|
818
|
+
export class MarkupExportService {
|
|
819
|
+
constructor();
|
|
820
|
+
exportPDFWithMarkup(originalPdfBlob: Blob, markupsByPage: IPageMarkupData[], options?: IExportPdfOptions): Promise<IExportResult>;
|
|
821
|
+
exportPDFWithMarkupMap(originalPdfBlob: Blob, markupsByPage: Map<number, string>, options?: IExportPdfOptions): Promise<IExportResult>;
|
|
822
|
+
exportAndDownload(originalPdfBlob: Blob, markupsByPage: IPageMarkupData[], options?: IExportPdfOptions): Promise<boolean>;
|
|
823
|
+
downloadPdf(blob: Blob, filename?: string): void;
|
|
824
|
+
static fetchPdfBlob(pdfSource: Blob | string): Promise<Blob>;
|
|
825
|
+
}
|
|
826
|
+
|
|
827
|
+
/**
|
|
828
|
+
* SVG to PDF Converter
|
|
829
|
+
* Converts SVG markup elements to PDF drawing operations using pdf-lib
|
|
830
|
+
*
|
|
831
|
+
* @example
|
|
832
|
+
* ```typescript
|
|
833
|
+
* const converter = new SvgToPdfConverter();
|
|
834
|
+
* await converter.drawSvgOnPdfPage(svgString, pdfPage, {
|
|
835
|
+
* pageWidth: 612, pageHeight: 792,
|
|
836
|
+
* svgViewBox: { x: 0, y: 0, width: 1000, height: 1000 }
|
|
837
|
+
* });
|
|
838
|
+
* ```
|
|
839
|
+
*/
|
|
840
|
+
export class SvgToPdfConverter {
|
|
841
|
+
drawSvgOnPdfPage(svgString: string, pdfPage: any, options: ISvgToPdfOptions): Promise<void>;
|
|
842
|
+
}
|
|
843
|
+
|
|
844
|
+
// ========================================
|
|
845
|
+
// Toolbar Visibility API Types
|
|
846
|
+
// ========================================
|
|
847
|
+
|
|
848
|
+
/**
|
|
849
|
+
* Toolbar button identifiers
|
|
850
|
+
*/
|
|
851
|
+
export type TToolbarButtonId = 'pan' | 'docBrowser' | 'download' | 'markup' | 'pagination';
|
|
852
|
+
|
|
853
|
+
/**
|
|
854
|
+
* Toolbar button visibility configuration
|
|
855
|
+
*/
|
|
856
|
+
export interface IToolbarVisibilityConfig {
|
|
857
|
+
pan?: boolean;
|
|
858
|
+
docBrowser?: boolean;
|
|
859
|
+
download?: boolean;
|
|
860
|
+
markup?: boolean;
|
|
861
|
+
pagination?: boolean;
|
|
862
|
+
}
|
|
863
|
+
|
|
864
|
+
/**
|
|
865
|
+
* Toolbar visibility API interface
|
|
866
|
+
*/
|
|
867
|
+
export interface IToolbarVisibilityAPI {
|
|
868
|
+
getVisibilityConfig(): IToolbarVisibilityConfig;
|
|
869
|
+
setVisibilityConfig(config: IToolbarVisibilityConfig): void;
|
|
870
|
+
showButton(buttonId: TToolbarButtonId): void;
|
|
871
|
+
hideButton(buttonId: TToolbarButtonId): void;
|
|
872
|
+
showAllButtons(): void;
|
|
873
|
+
hideAllButtons(): void;
|
|
874
|
+
isButtonVisible(buttonId: TToolbarButtonId): boolean;
|
|
875
|
+
}
|
|
876
|
+
|
|
877
|
+
/**
|
|
878
|
+
* Default toolbar visibility configuration (all visible)
|
|
879
|
+
*/
|
|
880
|
+
export const DEFAULT_TOOLBAR_VISIBILITY: Required<IToolbarVisibilityConfig>;
|
|
881
|
+
|
|
882
|
+
// ========================================
|
|
883
|
+
// Image Storage Service (IndexedDB)
|
|
884
|
+
// ========================================
|
|
885
|
+
|
|
886
|
+
/**
|
|
887
|
+
* Stored image data structure
|
|
888
|
+
*/
|
|
889
|
+
export interface IStoredImage {
|
|
890
|
+
id: string;
|
|
891
|
+
data: string;
|
|
892
|
+
mimeType: string;
|
|
893
|
+
fileName?: string;
|
|
894
|
+
width: number;
|
|
895
|
+
height: number;
|
|
896
|
+
sizeBytes: number;
|
|
897
|
+
createdAt: number;
|
|
898
|
+
lastAccessedAt: number;
|
|
899
|
+
expiresAt?: number;
|
|
900
|
+
}
|
|
901
|
+
|
|
902
|
+
/**
|
|
903
|
+
* Image storage configuration
|
|
904
|
+
*/
|
|
905
|
+
export interface IImageStorageConfig {
|
|
906
|
+
dbName?: string;
|
|
907
|
+
maxStorageSize?: number;
|
|
908
|
+
defaultExpiryMs?: number;
|
|
909
|
+
enableAutoCleanup?: boolean;
|
|
910
|
+
cleanupIntervalMs?: number;
|
|
911
|
+
}
|
|
912
|
+
|
|
913
|
+
/**
|
|
914
|
+
* Storage statistics
|
|
915
|
+
*/
|
|
916
|
+
export interface IStorageStats {
|
|
917
|
+
totalImages: number;
|
|
918
|
+
totalSizeBytes: number;
|
|
919
|
+
oldestImage?: number;
|
|
920
|
+
newestImage?: number;
|
|
921
|
+
expiredCount: number;
|
|
922
|
+
}
|
|
923
|
+
|
|
924
|
+
/**
|
|
925
|
+
* Image storage service using IndexedDB
|
|
926
|
+
*/
|
|
927
|
+
export class ImageStorageService {
|
|
928
|
+
static getInstance(config?: IImageStorageConfig): ImageStorageService;
|
|
929
|
+
initialize(): Promise<void>;
|
|
930
|
+
storeImage(imageData: string, metadata?: Partial<IStoredImage>): Promise<string>;
|
|
931
|
+
getImage(id: string): Promise<IStoredImage | null>;
|
|
932
|
+
hasImage(id: string): Promise<boolean>;
|
|
933
|
+
deleteImage(id: string): Promise<boolean>;
|
|
934
|
+
cleanupExpiredImages(): Promise<number>;
|
|
935
|
+
clearAll(): Promise<void>;
|
|
936
|
+
getStorageStats(): Promise<IStorageStats>;
|
|
937
|
+
destroy(): void;
|
|
938
|
+
}
|
|
939
|
+
|
|
940
|
+
// ========================================
|
|
941
|
+
// Markup Converter Service (SVG ↔ JSON)
|
|
942
|
+
// ========================================
|
|
943
|
+
|
|
944
|
+
/**
|
|
945
|
+
* JSON markup data format for database storage
|
|
946
|
+
* Coordinates are stored as-is (no scaling)
|
|
947
|
+
*/
|
|
948
|
+
export interface IJsonMarkupData {
|
|
949
|
+
/** Format version for JSON schema compatibility */
|
|
950
|
+
version: string;
|
|
951
|
+
/** Viewable identifier - provided by the consuming app (any string format) */
|
|
952
|
+
viewableGUID: string;
|
|
953
|
+
/** Array of compact markup elements */
|
|
954
|
+
elements: IMarkupElementCompact[];
|
|
955
|
+
/** Optional metadata for custom data */
|
|
956
|
+
metadata?: Record<string, any>;
|
|
957
|
+
/** Timestamp when data was created (Unix epoch ms) */
|
|
958
|
+
timestamp: number;
|
|
959
|
+
}
|
|
960
|
+
|
|
961
|
+
/**
|
|
962
|
+
* SVG validation result
|
|
963
|
+
*/
|
|
964
|
+
export interface ISvgValidationResult {
|
|
965
|
+
valid: boolean;
|
|
966
|
+
errors: string[];
|
|
967
|
+
markupCount: number;
|
|
968
|
+
}
|
|
969
|
+
|
|
970
|
+
/**
|
|
971
|
+
* JSON validation result
|
|
972
|
+
*/
|
|
973
|
+
export interface IJsonValidationResult {
|
|
974
|
+
valid: boolean;
|
|
975
|
+
errors: string[];
|
|
976
|
+
}
|
|
977
|
+
|
|
978
|
+
/**
|
|
979
|
+
* Service for converting between SVG and JSON markup formats
|
|
980
|
+
*
|
|
981
|
+
* ID FORMAT:
|
|
982
|
+
* Element IDs use compact format: {toolCode}-{timestamp}-{random4}
|
|
983
|
+
* Example: "1-1770285843573-a7f3" (freehand=1)
|
|
984
|
+
*
|
|
985
|
+
* @example
|
|
986
|
+
* ```typescript
|
|
987
|
+
* // SVG to JSON
|
|
988
|
+
* const svg = markupsCore.generateData();
|
|
989
|
+
* const json = MarkupConverterService.svgToJson(svg, 'my-page-id');
|
|
990
|
+
*
|
|
991
|
+
* // JSON to SVG (for restoring)
|
|
992
|
+
* const svg = MarkupConverterService.jsonToSvg(json);
|
|
993
|
+
* markupsCore.loadMarkups(svg, 'restored-layer');
|
|
994
|
+
* ```
|
|
995
|
+
*/
|
|
996
|
+
export class MarkupConverterService {
|
|
997
|
+
static svgToJson(svgString: string, viewableGUID: string): IJsonMarkupData;
|
|
998
|
+
static jsonToSvg(jsonData: IJsonMarkupData, layerId?: string): string;
|
|
999
|
+
static validateJsonData(data: unknown): IJsonValidationResult;
|
|
1000
|
+
static validateSvgString(svgString: string): ISvgValidationResult;
|
|
1001
|
+
static isValidJsonData(data: unknown): data is IJsonMarkupData;
|
|
1002
|
+
static getCurrentVersion(): string;
|
|
1003
|
+
static isVersionCompatible(version: string): boolean;
|
|
1004
|
+
static mergeJsonData(dataSets: IJsonMarkupData[]): IJsonMarkupData;
|
|
1005
|
+
}
|
|
1006
|
+
|
|
1007
|
+
/**
|
|
1008
|
+
* Generate UUIDv7 - time-ordered UUID
|
|
1009
|
+
* Utility function, can be used if you need a UUID identifier
|
|
1010
|
+
* Note: viewableGUID can be any string, UUIDv7 is not required
|
|
1011
|
+
*
|
|
1012
|
+
* @example
|
|
1013
|
+
* ```typescript
|
|
1014
|
+
* const id = generateUUIDv7();
|
|
1015
|
+
* // "0192d4e5-7f8a-7b3c-9d1e-2f4a6b8c0d2e"
|
|
1016
|
+
* ```
|
|
1017
|
+
*/
|
|
1018
|
+
export function generateUUIDv7(): string;
|
|
1019
|
+
|
|
1020
|
+
/**
|
|
1021
|
+
* Validate if a string is a valid UUID format (v4 or v7)
|
|
1022
|
+
* Format: xxxxxxxx-xxxx-Vxxx-yxxx-xxxxxxxxxxxx
|
|
1023
|
+
*
|
|
1024
|
+
* @param uuid - String to validate
|
|
1025
|
+
* @returns True if valid UUID format
|
|
1026
|
+
*
|
|
1027
|
+
* @example
|
|
1028
|
+
* ```typescript
|
|
1029
|
+
* isValidUUID('0192d4e5-7f8a-7b3c-9d1e-2f4a6b8c0d2e'); // true
|
|
1030
|
+
* isValidUUID('test-viewable-guid'); // false
|
|
1031
|
+
* ```
|
|
1032
|
+
*/
|
|
1033
|
+
export function isValidUUID(uuid: string): boolean;
|
|
1034
|
+
|
|
1035
|
+
/**
|
|
1036
|
+
* Validate if a string is a valid UUIDv7 format
|
|
1037
|
+
* Format: xxxxxxxx-xxxx-7xxx-yxxx-xxxxxxxxxxxx
|
|
1038
|
+
* Version 7 indicated by '7' at position 14
|
|
1039
|
+
*
|
|
1040
|
+
* @param uuid - String to validate
|
|
1041
|
+
* @returns True if valid UUIDv7 format
|
|
1042
|
+
*
|
|
1043
|
+
* @example
|
|
1044
|
+
* ```typescript
|
|
1045
|
+
* isValidUUIDv7('0192d4e5-7f8a-7b3c-9d1e-2f4a6b8c0d2e'); // true (if version is 7)
|
|
1046
|
+
* isValidUUIDv7('550e8400-e29b-41d4-a716-446655440000'); // false (version 4)
|
|
1047
|
+
* ```
|
|
1048
|
+
*/
|
|
1049
|
+
export function isValidUUIDv7(uuid: string): boolean;
|
|
1050
|
+
|
|
1051
|
+
/**
|
|
1052
|
+
* Coordinate scale factor for precision calculations (1e7)
|
|
1053
|
+
* Use this constant when performing math operations that need precision
|
|
1054
|
+
* Note: Coordinates are NOT scaled in storage
|
|
1055
|
+
*/
|
|
1056
|
+
export const MARKUP_COORDINATE_SCALE: number;
|
|
1057
|
+
|
|
1058
|
+
/**
|
|
1059
|
+
* Tool type to numeric code mapping for compact ID generation
|
|
1060
|
+
* Used in element ID format: {toolCode}-{timestamp}-{random4}
|
|
1061
|
+
*/
|
|
1062
|
+
export const MARKUP_TOOL_CODES: Record<string, number>;
|
|
1063
|
+
|
|
1064
|
+
// ========================================
|
|
1065
|
+
// Coordinate System Utilities
|
|
1066
|
+
// ========================================
|
|
1067
|
+
|
|
1068
|
+
/**
|
|
1069
|
+
* Coordinate space types
|
|
1070
|
+
*/
|
|
1071
|
+
export type TCoordinateSpace = 'screen' | 'markup' | 'page';
|
|
1072
|
+
|
|
1073
|
+
/**
|
|
1074
|
+
* 2D point interface
|
|
1075
|
+
*/
|
|
1076
|
+
export interface IPoint2D {
|
|
1077
|
+
x: number;
|
|
1078
|
+
y: number;
|
|
1079
|
+
}
|
|
1080
|
+
|
|
1081
|
+
/**
|
|
1082
|
+
* 2D bounds interface
|
|
1083
|
+
*/
|
|
1084
|
+
export interface IBounds2D {
|
|
1085
|
+
min: IPoint2D;
|
|
1086
|
+
max: IPoint2D;
|
|
1087
|
+
}
|
|
1088
|
+
|
|
1089
|
+
/**
|
|
1090
|
+
* Coordinate validation result
|
|
1091
|
+
*/
|
|
1092
|
+
export interface ICoordinateValidationResult {
|
|
1093
|
+
valid: boolean;
|
|
1094
|
+
space: TCoordinateSpace;
|
|
1095
|
+
message?: string;
|
|
1096
|
+
normalized?: IPoint2D;
|
|
1097
|
+
}
|
|
1098
|
+
|
|
1099
|
+
/**
|
|
1100
|
+
* Coordinate space information for debugging
|
|
1101
|
+
*/
|
|
1102
|
+
export interface ICoordinateSpaceInfo {
|
|
1103
|
+
viewBox: { x: number; y: number; width: number; height: number };
|
|
1104
|
+
bounds: IBounds2D | null;
|
|
1105
|
+
currentZoom: number;
|
|
1106
|
+
currentPan: IPoint2D;
|
|
1107
|
+
ctmMatrix: DOMMatrix | null;
|
|
1108
|
+
}
|
|
1109
|
+
|
|
1110
|
+
/**
|
|
1111
|
+
* Validate coordinates in markup space
|
|
1112
|
+
*/
|
|
1113
|
+
export function validateMarkupCoordinates(
|
|
1114
|
+
point: IPoint2D,
|
|
1115
|
+
markupsCore: any
|
|
1116
|
+
): ICoordinateValidationResult;
|
|
1117
|
+
|
|
1118
|
+
/**
|
|
1119
|
+
* Get coordinate space metadata for debugging
|
|
1120
|
+
*/
|
|
1121
|
+
export function getCoordinateSpaceInfo(markupsCore: any): ICoordinateSpaceInfo;
|
|
1122
|
+
|
|
1123
|
+
/**
|
|
1124
|
+
* Convert coordinates between different coordinate spaces
|
|
1125
|
+
*/
|
|
1126
|
+
export function convertCoordinates(
|
|
1127
|
+
point: IPoint2D,
|
|
1128
|
+
from: TCoordinateSpace,
|
|
1129
|
+
to: TCoordinateSpace,
|
|
1130
|
+
markupsCore: any
|
|
1131
|
+
): IPoint2D;
|
|
1132
|
+
|
|
1133
|
+
/**
|
|
1134
|
+
* Check if the coordinate system is normalized (zoom/pan independent)
|
|
1135
|
+
*/
|
|
1136
|
+
export function isCoordinateSystemNormalized(markupsCore: any): boolean;
|
|
79
1137
|
}
|