web-annotation-renderer 0.1.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/CHANGELOG.md +34 -0
- package/LICENSE +21 -0
- package/README.md +156 -0
- package/dist/index.cjs +2 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.js +32 -0
- package/dist/index.js.map +1 -0
- package/dist/index10.cjs +2 -0
- package/dist/index10.cjs.map +1 -0
- package/dist/index10.js +23 -0
- package/dist/index10.js.map +1 -0
- package/dist/index11.cjs +2 -0
- package/dist/index11.cjs.map +1 -0
- package/dist/index11.js +23 -0
- package/dist/index11.js.map +1 -0
- package/dist/index12.cjs +2 -0
- package/dist/index12.cjs.map +1 -0
- package/dist/index12.js +203 -0
- package/dist/index12.js.map +1 -0
- package/dist/index13.cjs +2 -0
- package/dist/index13.cjs.map +1 -0
- package/dist/index13.js +18 -0
- package/dist/index13.js.map +1 -0
- package/dist/index14.cjs +2 -0
- package/dist/index14.cjs.map +1 -0
- package/dist/index14.js +116 -0
- package/dist/index14.js.map +1 -0
- package/dist/index15.cjs +2 -0
- package/dist/index15.cjs.map +1 -0
- package/dist/index15.js +35 -0
- package/dist/index15.js.map +1 -0
- package/dist/index2.cjs +2 -0
- package/dist/index2.cjs.map +1 -0
- package/dist/index2.js +182 -0
- package/dist/index2.js.map +1 -0
- package/dist/index3.cjs +2 -0
- package/dist/index3.cjs.map +1 -0
- package/dist/index3.js +121 -0
- package/dist/index3.js.map +1 -0
- package/dist/index4.cjs +2 -0
- package/dist/index4.cjs.map +1 -0
- package/dist/index4.js +104 -0
- package/dist/index4.js.map +1 -0
- package/dist/index5.cjs +2 -0
- package/dist/index5.cjs.map +1 -0
- package/dist/index5.js +105 -0
- package/dist/index5.js.map +1 -0
- package/dist/index6.cjs +2 -0
- package/dist/index6.cjs.map +1 -0
- package/dist/index6.js +119 -0
- package/dist/index6.js.map +1 -0
- package/dist/index7.cjs +2 -0
- package/dist/index7.cjs.map +1 -0
- package/dist/index7.js +100 -0
- package/dist/index7.js.map +1 -0
- package/dist/index8.cjs +2 -0
- package/dist/index8.cjs.map +1 -0
- package/dist/index8.js +109 -0
- package/dist/index8.js.map +1 -0
- package/dist/index9.cjs +2 -0
- package/dist/index9.cjs.map +1 -0
- package/dist/index9.js +112 -0
- package/dist/index9.js.map +1 -0
- package/package.json +84 -0
package/dist/index2.js
ADDED
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
import { PDFRenderer as r } from "./index3.js";
|
|
2
|
+
import { LayerManager as n } from "./index4.js";
|
|
3
|
+
import { TimelineSync as s } from "./index5.js";
|
|
4
|
+
class c {
|
|
5
|
+
/**
|
|
6
|
+
* Create AnnotationRenderer instance
|
|
7
|
+
*
|
|
8
|
+
* @param {Object} config - Configuration object
|
|
9
|
+
* @param {HTMLElement} config.container - DOM element for layer rendering
|
|
10
|
+
* @param {HTMLCanvasElement} config.canvasElement - Canvas element for PDF rendering
|
|
11
|
+
* @param {string} [config.pdfUrl] - PDF URL to load immediately
|
|
12
|
+
* @param {number} [config.initialPage=1] - Initial page number
|
|
13
|
+
* @param {number} [config.initialScale=1.0] - Initial scale factor
|
|
14
|
+
* @param {Array} [config.annotations=[]] - Initial annotation data
|
|
15
|
+
* @throws {Error} If config is invalid or required elements are missing
|
|
16
|
+
*/
|
|
17
|
+
constructor(e) {
|
|
18
|
+
if (!e || typeof e != "object")
|
|
19
|
+
throw new Error("AnnotationRenderer: config object is required");
|
|
20
|
+
if (!e.container || !(e.container instanceof HTMLElement))
|
|
21
|
+
throw new Error("AnnotationRenderer: config.container must be a valid DOM element");
|
|
22
|
+
if (!e.canvasElement || !(e.canvasElement instanceof HTMLCanvasElement))
|
|
23
|
+
throw new Error("AnnotationRenderer: config.canvasElement must be a valid canvas element");
|
|
24
|
+
this.config = e, this.canvasElement = e.canvasElement, this.container = e.container, this.pdfRenderer = new r(), this.layerManager = new n(e.container, {
|
|
25
|
+
width: 1,
|
|
26
|
+
height: 1,
|
|
27
|
+
scale: 1
|
|
28
|
+
}), this.timelineSync = new s(), this.currentPage = e.initialPage || 1, this.currentScale = e.initialScale || 1, this.annotations = e.annotations || [], this.pageCount = 0, this.currentViewport = null, this.pdfUrl = null, this.timelineSync.subscribe((t) => {
|
|
29
|
+
this.layerManager.updateTimeline(t);
|
|
30
|
+
}), e.pdfUrl && this.loadPDF(e.pdfUrl).catch((t) => {
|
|
31
|
+
console.error("AnnotationRenderer: Failed to auto-load PDF:", t);
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Load PDF document from URL
|
|
36
|
+
*
|
|
37
|
+
* @param {string} url - URL or path to PDF file
|
|
38
|
+
* @returns {Promise<Object>} Load result with success status and page count
|
|
39
|
+
* @returns {boolean} return.success - Whether loading succeeded
|
|
40
|
+
* @returns {number} [return.pageCount] - Number of pages if successful
|
|
41
|
+
* @returns {string} [return.error] - Error message if failed
|
|
42
|
+
*/
|
|
43
|
+
async loadPDF(e) {
|
|
44
|
+
try {
|
|
45
|
+
if (!e || typeof e != "string")
|
|
46
|
+
return {
|
|
47
|
+
success: !1,
|
|
48
|
+
error: "Invalid PDF URL provided"
|
|
49
|
+
};
|
|
50
|
+
const t = await this.pdfRenderer.loadDocument(e);
|
|
51
|
+
return t.success ? (this.pdfUrl = e, this.pageCount = t.pageCount, {
|
|
52
|
+
success: !0,
|
|
53
|
+
pageCount: t.pageCount
|
|
54
|
+
}) : t;
|
|
55
|
+
} catch (t) {
|
|
56
|
+
return console.error("AnnotationRenderer.loadPDF: Error loading PDF:", t), {
|
|
57
|
+
success: !1,
|
|
58
|
+
error: `Failed to load PDF: ${t.message}`
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Navigate to specific page and render it
|
|
64
|
+
*
|
|
65
|
+
* @param {number} pageNum - Page number (1-indexed)
|
|
66
|
+
* @returns {Promise<Object>} Render result with viewport information
|
|
67
|
+
* @returns {boolean} return.success - Whether rendering succeeded
|
|
68
|
+
* @returns {Object} [return.viewport] - Viewport dimensions if successful
|
|
69
|
+
* @returns {string} [return.error] - Error message if failed
|
|
70
|
+
*/
|
|
71
|
+
async setPage(e) {
|
|
72
|
+
try {
|
|
73
|
+
if (typeof e != "number" || e < 1)
|
|
74
|
+
return {
|
|
75
|
+
success: !1,
|
|
76
|
+
error: "Invalid page number"
|
|
77
|
+
};
|
|
78
|
+
if (this.pageCount > 0 && e > this.pageCount)
|
|
79
|
+
return {
|
|
80
|
+
success: !1,
|
|
81
|
+
error: `Page ${e} exceeds document page count (${this.pageCount})`
|
|
82
|
+
};
|
|
83
|
+
this.pdfRenderer.cancelRender();
|
|
84
|
+
const t = await this.pdfRenderer.renderPage(
|
|
85
|
+
e,
|
|
86
|
+
this.canvasElement,
|
|
87
|
+
this.currentScale
|
|
88
|
+
);
|
|
89
|
+
return t.success ? (this.currentPage = e, this.currentViewport = t.viewport, this.layerManager.setAnnotations(this.annotations, e), this.layerManager.setViewport(t.viewport), {
|
|
90
|
+
success: !0,
|
|
91
|
+
viewport: t.viewport
|
|
92
|
+
}) : t;
|
|
93
|
+
} catch (t) {
|
|
94
|
+
return console.error("AnnotationRenderer.setPage: Error rendering page:", t), {
|
|
95
|
+
success: !1,
|
|
96
|
+
error: `Failed to render page: ${t.message}`
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Change zoom scale and re-render current page
|
|
102
|
+
*
|
|
103
|
+
* @param {number} scale - Scale factor (e.g., 1.0, 1.5, 2.0)
|
|
104
|
+
* @returns {Promise<Object>} Render result with viewport information
|
|
105
|
+
* @returns {boolean} return.success - Whether rendering succeeded
|
|
106
|
+
* @returns {Object} [return.viewport] - Viewport dimensions if successful
|
|
107
|
+
* @returns {string} [return.error] - Error message if failed
|
|
108
|
+
*/
|
|
109
|
+
async setScale(e) {
|
|
110
|
+
try {
|
|
111
|
+
return typeof e != "number" || e <= 0 ? {
|
|
112
|
+
success: !1,
|
|
113
|
+
error: "Invalid scale value (must be positive number)"
|
|
114
|
+
} : (this.currentScale = e, await this.setPage(this.currentPage));
|
|
115
|
+
} catch (t) {
|
|
116
|
+
return console.error("AnnotationRenderer.setScale: Error changing scale:", t), {
|
|
117
|
+
success: !1,
|
|
118
|
+
error: `Failed to change scale: ${t.message}`
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Update annotation data for rendering
|
|
124
|
+
*
|
|
125
|
+
* @param {Array} annotations - Complete annotation array (all pages, all types)
|
|
126
|
+
* @returns {void}
|
|
127
|
+
*/
|
|
128
|
+
setAnnotations(e) {
|
|
129
|
+
Array.isArray(e) || (console.warn("AnnotationRenderer.setAnnotations: annotations must be an array"), e = []), this.annotations = e, this.layerManager.setAnnotations(e, this.currentPage);
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Update timeline position for animation
|
|
133
|
+
*
|
|
134
|
+
* @param {number} timestamp - Current timeline position in seconds
|
|
135
|
+
* @returns {void}
|
|
136
|
+
*/
|
|
137
|
+
setTime(e) {
|
|
138
|
+
if (typeof e != "number") {
|
|
139
|
+
console.warn("AnnotationRenderer.setTime: timestamp must be a number");
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
this.timelineSync.setTime(e);
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Get current engine state snapshot
|
|
146
|
+
*
|
|
147
|
+
* @returns {Object} Current state
|
|
148
|
+
* @returns {number} return.page - Current page number
|
|
149
|
+
* @returns {number} return.scale - Current scale factor
|
|
150
|
+
* @returns {Array} return.annotations - Current annotation array
|
|
151
|
+
* @returns {number} return.pageCount - Total page count
|
|
152
|
+
* @returns {number} return.time - Current timeline position
|
|
153
|
+
* @returns {Object|null} return.viewport - Current viewport dimensions
|
|
154
|
+
* @returns {string|null} return.pdfUrl - Current PDF URL
|
|
155
|
+
*/
|
|
156
|
+
getState() {
|
|
157
|
+
return {
|
|
158
|
+
page: this.currentPage,
|
|
159
|
+
scale: this.currentScale,
|
|
160
|
+
annotations: this.annotations,
|
|
161
|
+
pageCount: this.pageCount,
|
|
162
|
+
time: this.timelineSync.getCurrentTime(),
|
|
163
|
+
viewport: this.currentViewport,
|
|
164
|
+
pdfUrl: this.pdfUrl
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Clean up all resources and subsystems
|
|
169
|
+
*
|
|
170
|
+
* Call before removing AnnotationRenderer instance.
|
|
171
|
+
* Destroys all subsystems and releases references.
|
|
172
|
+
*
|
|
173
|
+
* @returns {void}
|
|
174
|
+
*/
|
|
175
|
+
destroy() {
|
|
176
|
+
this.pdfRenderer && this.pdfRenderer.destroy(), this.layerManager && this.layerManager.destroy(), this.timelineSync && this.timelineSync.destroy(), this.pdfRenderer = null, this.layerManager = null, this.timelineSync = null, this.config = null, this.canvasElement = null, this.container = null, this.annotations = [], this.currentPage = 0, this.currentScale = 1, this.pageCount = 0, this.currentViewport = null, this.pdfUrl = null;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
export {
|
|
180
|
+
c as AnnotationRenderer
|
|
181
|
+
};
|
|
182
|
+
//# sourceMappingURL=index2.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index2.js","sources":["../src/core/AnnotationRenderer.js"],"sourcesContent":["/**\n * AnnotationRenderer - Main facade for PDF annotation rendering engine\n *\n * This module orchestrates all subsystems (PDFRenderer, LayerManager, TimelineSync)\n * and provides the primary public API for rendering PDFs with timeline-synchronized\n * annotations. Framework-agnostic core that can be wrapped by React/Vue adapters.\n *\n * @module core/AnnotationRenderer\n */\n\nimport { PDFRenderer } from './PDFRenderer.js';\nimport { LayerManager } from './LayerManager.js';\nimport { TimelineSync } from './TimelineSync.js';\n\n/**\n * AnnotationRenderer class\n *\n * Main engine that coordinates PDF rendering, annotation layers, and timeline\n * synchronization. Provides simple imperative API for consumers.\n *\n * @class\n * @example\n * const renderer = new AnnotationRenderer({\n * container: document.getElementById('layer-container'),\n * canvasElement: document.getElementById('pdf-canvas')\n * });\n *\n * await renderer.loadPDF('/path/to/doc.pdf');\n * await renderer.setPage(1);\n * renderer.setAnnotations(annotationData);\n * renderer.setScale(1.5);\n * renderer.setTime(3.5);\n */\nexport class AnnotationRenderer {\n /**\n * Create AnnotationRenderer instance\n *\n * @param {Object} config - Configuration object\n * @param {HTMLElement} config.container - DOM element for layer rendering\n * @param {HTMLCanvasElement} config.canvasElement - Canvas element for PDF rendering\n * @param {string} [config.pdfUrl] - PDF URL to load immediately\n * @param {number} [config.initialPage=1] - Initial page number\n * @param {number} [config.initialScale=1.0] - Initial scale factor\n * @param {Array} [config.annotations=[]] - Initial annotation data\n * @throws {Error} If config is invalid or required elements are missing\n */\n constructor(config) {\n // Validate config\n if (!config || typeof config !== 'object') {\n throw new Error('AnnotationRenderer: config object is required');\n }\n\n if (!config.container || !(config.container instanceof HTMLElement)) {\n throw new Error('AnnotationRenderer: config.container must be a valid DOM element');\n }\n\n if (!config.canvasElement || !(config.canvasElement instanceof HTMLCanvasElement)) {\n throw new Error('AnnotationRenderer: config.canvasElement must be a valid canvas element');\n }\n\n /**\n * @private\n * @type {Object}\n */\n this.config = config;\n\n /**\n * @private\n * @type {HTMLCanvasElement}\n */\n this.canvasElement = config.canvasElement;\n\n /**\n * @private\n * @type {HTMLElement}\n */\n this.container = config.container;\n\n /**\n * @private\n * @type {PDFRenderer}\n */\n this.pdfRenderer = new PDFRenderer();\n\n /**\n * @private\n * @type {LayerManager}\n */\n // Initialize LayerManager with a minimal default viewport that will be updated when PDF loads\n // BaseLayer requires positive width/height, so use 1x1 as placeholder\n this.layerManager = new LayerManager(config.container, {\n width: 1,\n height: 1,\n scale: 1.0\n });\n\n /**\n * @private\n * @type {TimelineSync}\n */\n this.timelineSync = new TimelineSync();\n\n /**\n * @private\n * @type {number}\n */\n this.currentPage = config.initialPage || 1;\n\n /**\n * @private\n * @type {number}\n */\n this.currentScale = config.initialScale || 1.0;\n\n /**\n * @private\n * @type {Array}\n */\n this.annotations = config.annotations || [];\n\n /**\n * @private\n * @type {number}\n */\n this.pageCount = 0;\n\n /**\n * @private\n * @type {Object|null}\n */\n this.currentViewport = null;\n\n /**\n * @private\n * @type {string|null}\n */\n this.pdfUrl = null;\n\n // Wire up subsystem communication\n // Timeline updates automatically propagate to LayerManager\n this.timelineSync.subscribe((time) => {\n this.layerManager.updateTimeline(time);\n });\n\n // Auto-load PDF if provided\n if (config.pdfUrl) {\n this.loadPDF(config.pdfUrl).catch(err => {\n console.error('AnnotationRenderer: Failed to auto-load PDF:', err);\n });\n }\n }\n\n /**\n * Load PDF document from URL\n *\n * @param {string} url - URL or path to PDF file\n * @returns {Promise<Object>} Load result with success status and page count\n * @returns {boolean} return.success - Whether loading succeeded\n * @returns {number} [return.pageCount] - Number of pages if successful\n * @returns {string} [return.error] - Error message if failed\n */\n async loadPDF(url) {\n try {\n // Validate URL\n if (!url || typeof url !== 'string') {\n return {\n success: false,\n error: 'Invalid PDF URL provided'\n };\n }\n\n // Load via PDFRenderer\n const result = await this.pdfRenderer.loadDocument(url);\n\n if (result.success) {\n // Store PDF metadata\n this.pdfUrl = url;\n this.pageCount = result.pageCount;\n\n return {\n success: true,\n pageCount: result.pageCount\n };\n } else {\n return result;\n }\n } catch (err) {\n console.error('AnnotationRenderer.loadPDF: Error loading PDF:', err);\n return {\n success: false,\n error: `Failed to load PDF: ${err.message}`\n };\n }\n }\n\n /**\n * Navigate to specific page and render it\n *\n * @param {number} pageNum - Page number (1-indexed)\n * @returns {Promise<Object>} Render result with viewport information\n * @returns {boolean} return.success - Whether rendering succeeded\n * @returns {Object} [return.viewport] - Viewport dimensions if successful\n * @returns {string} [return.error] - Error message if failed\n */\n async setPage(pageNum) {\n try {\n // Validate page number\n if (typeof pageNum !== 'number' || pageNum < 1) {\n return {\n success: false,\n error: 'Invalid page number'\n };\n }\n\n if (this.pageCount > 0 && pageNum > this.pageCount) {\n return {\n success: false,\n error: `Page ${pageNum} exceeds document page count (${this.pageCount})`\n };\n }\n\n // Cancel any in-progress rendering\n this.pdfRenderer.cancelRender();\n\n // Render page via PDFRenderer\n const result = await this.pdfRenderer.renderPage(\n pageNum,\n this.canvasElement,\n this.currentScale\n );\n\n if (result.success) {\n // Store current state\n this.currentPage = pageNum;\n this.currentViewport = result.viewport;\n\n // Update LayerManager with new page and viewport\n this.layerManager.setAnnotations(this.annotations, pageNum);\n this.layerManager.setViewport(result.viewport);\n\n return {\n success: true,\n viewport: result.viewport\n };\n } else {\n return result;\n }\n } catch (err) {\n console.error('AnnotationRenderer.setPage: Error rendering page:', err);\n return {\n success: false,\n error: `Failed to render page: ${err.message}`\n };\n }\n }\n\n /**\n * Change zoom scale and re-render current page\n *\n * @param {number} scale - Scale factor (e.g., 1.0, 1.5, 2.0)\n * @returns {Promise<Object>} Render result with viewport information\n * @returns {boolean} return.success - Whether rendering succeeded\n * @returns {Object} [return.viewport] - Viewport dimensions if successful\n * @returns {string} [return.error] - Error message if failed\n */\n async setScale(scale) {\n try {\n // Validate scale\n if (typeof scale !== 'number' || scale <= 0) {\n return {\n success: false,\n error: 'Invalid scale value (must be positive number)'\n };\n }\n\n // Store new scale\n this.currentScale = scale;\n\n // Re-render current page at new scale\n const result = await this.setPage(this.currentPage);\n\n return result;\n } catch (err) {\n console.error('AnnotationRenderer.setScale: Error changing scale:', err);\n return {\n success: false,\n error: `Failed to change scale: ${err.message}`\n };\n }\n }\n\n /**\n * Update annotation data for rendering\n *\n * @param {Array} annotations - Complete annotation array (all pages, all types)\n * @returns {void}\n */\n setAnnotations(annotations) {\n // Validate annotations\n if (!Array.isArray(annotations)) {\n console.warn('AnnotationRenderer.setAnnotations: annotations must be an array');\n annotations = [];\n }\n\n // Store annotations\n this.annotations = annotations;\n\n // Route to LayerManager for current page\n this.layerManager.setAnnotations(annotations, this.currentPage);\n }\n\n /**\n * Update timeline position for animation\n *\n * @param {number} timestamp - Current timeline position in seconds\n * @returns {void}\n */\n setTime(timestamp) {\n // Validate timestamp\n if (typeof timestamp !== 'number') {\n console.warn('AnnotationRenderer.setTime: timestamp must be a number');\n return;\n }\n\n // Forward to TimelineSync\n // TimelineSync will notify LayerManager automatically via subscription\n this.timelineSync.setTime(timestamp);\n }\n\n /**\n * Get current engine state snapshot\n *\n * @returns {Object} Current state\n * @returns {number} return.page - Current page number\n * @returns {number} return.scale - Current scale factor\n * @returns {Array} return.annotations - Current annotation array\n * @returns {number} return.pageCount - Total page count\n * @returns {number} return.time - Current timeline position\n * @returns {Object|null} return.viewport - Current viewport dimensions\n * @returns {string|null} return.pdfUrl - Current PDF URL\n */\n getState() {\n return {\n page: this.currentPage,\n scale: this.currentScale,\n annotations: this.annotations,\n pageCount: this.pageCount,\n time: this.timelineSync.getCurrentTime(),\n viewport: this.currentViewport,\n pdfUrl: this.pdfUrl\n };\n }\n\n /**\n * Clean up all resources and subsystems\n *\n * Call before removing AnnotationRenderer instance.\n * Destroys all subsystems and releases references.\n *\n * @returns {void}\n */\n destroy() {\n // Destroy all subsystems\n if (this.pdfRenderer) {\n this.pdfRenderer.destroy();\n }\n\n if (this.layerManager) {\n this.layerManager.destroy();\n }\n\n if (this.timelineSync) {\n this.timelineSync.destroy();\n }\n\n // Clear all references\n this.pdfRenderer = null;\n this.layerManager = null;\n this.timelineSync = null;\n this.config = null;\n this.canvasElement = null;\n this.container = null;\n this.annotations = [];\n this.currentPage = 0;\n this.currentScale = 1.0;\n this.pageCount = 0;\n this.currentViewport = null;\n this.pdfUrl = null;\n }\n}\n"],"names":["AnnotationRenderer","config","PDFRenderer","LayerManager","TimelineSync","time","err","url","result","pageNum","scale","annotations","timestamp"],"mappings":"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"}
|
package/dist/index3.cjs
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const i=require("pdfjs-dist"),l=require("./index11.cjs");function d(n){const e=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(n){for(const r in n)if(r!=="default"){const t=Object.getOwnPropertyDescriptor(n,r);Object.defineProperty(e,r,t.get?t:{enumerable:!0,get:()=>n[r]})}}return e.default=n,Object.freeze(e)}const u=d(i);class f{constructor(){this.pdfDoc=null,this.renderTask=null}async loadDocument(e){try{if(!e||typeof e!="string")return{success:!1,error:"Invalid PDF URL provided"};const t=await u.getDocument(e).promise;return this.pdfDoc=t,{success:!0,pageCount:t.numPages}}catch(r){return console.error("PDF loading error:",r),{success:!1,error:`Failed to load PDF: ${r.message}`}}}async renderPage(e,r,t){try{if(!this.pdfDoc)return{success:!1,error:"No PDF document loaded"};if(!r||!(r instanceof HTMLCanvasElement))return{success:!1,error:"Invalid canvas element provided"};if(e<1||e>this.pdfDoc.numPages)return{success:!1,error:`Invalid page number: ${e}. Document has ${this.pdfDoc.numPages} pages.`};this.renderTask&&(this.renderTask.cancel(),this.renderTask=null);const s=await this.pdfDoc.getPage(e),o=l.calculateViewport(s,t);r.width=o.width,r.height=o.height;const c=r.getContext("2d");if(!c)return{success:!1,error:"Failed to get canvas 2d context"};const a={canvasContext:c,viewport:o};return this.renderTask=s.render(a),await this.renderTask.promise,this.renderTask=null,{success:!0,viewport:o}}catch(s){return s.name==="RenderingCancelledException"?(console.log("Rendering cancelled"),{success:!1,error:"Rendering was cancelled"}):(console.error("Page rendering error:",s),{success:!1,error:`Failed to render page: ${s.message}`})}finally{this.renderTask=null}}getPageCount(){return this.pdfDoc?this.pdfDoc.numPages:0}cancelRender(){if(this.renderTask)try{this.renderTask.cancel()}catch(e){console.log("Render cancellation error (ignored):",e)}finally{this.renderTask=null}}destroy(){this.cancelRender(),this.pdfDoc&&(this.pdfDoc=null),this.renderTask=null}}exports.PDFRenderer=f;
|
|
2
|
+
//# sourceMappingURL=index3.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index3.cjs","sources":["../src/core/PDFRenderer.js"],"sourcesContent":["/**\n * PDFRenderer - Framework-agnostic PDF rendering subsystem\n *\n * This module encapsulates all pdf.js operations including document loading,\n * page rendering, viewport calculations, and rendering task management.\n *\n * @module core/PDFRenderer\n */\n\nimport * as pdfjsLib from \"pdfjs-dist\";\nimport { calculateViewport } from \"../utils/viewportUtils.js\";\n\n/**\n * PDFRenderer class\n *\n * Provides framework-agnostic PDF rendering capabilities.\n * Abstracts pdf.js complexity and provides clean interface for engine.\n *\n * @class\n * @example\n * const renderer = new PDFRenderer();\n * await renderer.loadDocument('/path/to/doc.pdf');\n * const result = await renderer.renderPage(1, canvasElement, 1.5);\n */\nexport class PDFRenderer {\n constructor() {\n /**\n * @private\n * @type {PDFDocumentProxy|null}\n */\n this.pdfDoc = null;\n\n /**\n * @private\n * @type {RenderTask|null}\n */\n this.renderTask = null;\n }\n\n /**\n * Load PDF document from URL\n *\n * @param {string} url - URL or path to PDF file\n * @returns {Promise<{success: boolean, pageCount?: number, error?: string}>}\n */\n async loadDocument(url) {\n try {\n if (!url || typeof url !== \"string\") {\n return {\n success: false,\n error: \"Invalid PDF URL provided\",\n };\n }\n\n const loadingTask = pdfjsLib.getDocument(url);\n const pdf = await loadingTask.promise;\n\n this.pdfDoc = pdf;\n\n return {\n success: true,\n pageCount: pdf.numPages,\n };\n } catch (err) {\n console.error(\"PDF loading error:\", err);\n return {\n success: false,\n error: `Failed to load PDF: ${err.message}`,\n };\n }\n }\n\n /**\n * Render PDF page to canvas element\n *\n * @param {number} pageNum - Page number (1-indexed)\n * @param {HTMLCanvasElement} canvas - Canvas element to render to\n * @param {number} scale - Scale factor for rendering\n * @returns {Promise<{success: boolean, viewport?: Object, error?: string}>}\n */\n async renderPage(pageNum, canvas, scale) {\n try {\n if (!this.pdfDoc) {\n return {\n success: false,\n error: \"No PDF document loaded\",\n };\n }\n\n if (!canvas || !(canvas instanceof HTMLCanvasElement)) {\n return {\n success: false,\n error: \"Invalid canvas element provided\",\n };\n }\n\n if (pageNum < 1 || pageNum > this.pdfDoc.numPages) {\n return {\n success: false,\n error: `Invalid page number: ${pageNum}. Document has ${this.pdfDoc.numPages} pages.`,\n };\n }\n\n // Cancel any in-progress rendering\n if (this.renderTask) {\n this.renderTask.cancel();\n this.renderTask = null;\n }\n\n const page = await this.pdfDoc.getPage(pageNum);\n const viewport = calculateViewport(page, scale);\n\n canvas.width = viewport.width;\n canvas.height = viewport.height;\n\n const context = canvas.getContext(\"2d\");\n if (!context) {\n return {\n success: false,\n error: \"Failed to get canvas 2d context\",\n };\n }\n\n const renderContext = {\n canvasContext: context,\n viewport: viewport,\n };\n\n this.renderTask = page.render(renderContext);\n await this.renderTask.promise;\n\n this.renderTask = null;\n\n return {\n success: true,\n viewport: viewport,\n };\n } catch (err) {\n if (err.name === \"RenderingCancelledException\") {\n console.log(\"Rendering cancelled\");\n return {\n success: false,\n error: \"Rendering was cancelled\",\n };\n }\n\n console.error(\"Page rendering error:\", err);\n return {\n success: false,\n error: `Failed to render page: ${err.message}`,\n };\n } finally {\n this.renderTask = null;\n }\n }\n\n /**\n * Get total number of pages in loaded PDF\n *\n * @returns {number} Page count, or 0 if no document loaded\n */\n getPageCount() {\n return this.pdfDoc ? this.pdfDoc.numPages : 0;\n }\n\n /**\n * Cancel current rendering task if active\n *\n * @returns {void}\n */\n cancelRender() {\n if (this.renderTask) {\n try {\n this.renderTask.cancel();\n } catch (err) {\n console.log(\"Render cancellation error (ignored):\", err);\n } finally {\n this.renderTask = null;\n }\n }\n }\n\n /**\n * Clean up resources and release references\n *\n * @returns {void}\n */\n destroy() {\n this.cancelRender();\n\n if (this.pdfDoc) {\n this.pdfDoc = null;\n }\n\n this.renderTask = null;\n }\n}\n"],"names":["PDFRenderer","url","pdf","pdfjsLib","err","pageNum","canvas","scale","page","viewport","calculateViewport","context","renderContext"],"mappings":"maAwBO,MAAMA,CAAY,CACvB,aAAc,CAKZ,KAAK,OAAS,KAMd,KAAK,WAAa,IACpB,CAQA,MAAM,aAAaC,EAAK,CACtB,GAAI,CACF,GAAI,CAACA,GAAO,OAAOA,GAAQ,SACzB,MAAO,CACL,QAAS,GACT,MAAO,0BACjB,EAIM,MAAMC,EAAM,MADQC,EAAS,YAAYF,CAAG,EACd,QAE9B,YAAK,OAASC,EAEP,CACL,QAAS,GACT,UAAWA,EAAI,QACvB,CACI,OAASE,EAAK,CACZ,eAAQ,MAAM,qBAAsBA,CAAG,EAChC,CACL,QAAS,GACT,MAAO,uBAAuBA,EAAI,OAAO,EACjD,CACI,CACF,CAUA,MAAM,WAAWC,EAASC,EAAQC,EAAO,CACvC,GAAI,CACF,GAAI,CAAC,KAAK,OACR,MAAO,CACL,QAAS,GACT,MAAO,wBACjB,EAGM,GAAI,CAACD,GAAU,EAAEA,aAAkB,mBACjC,MAAO,CACL,QAAS,GACT,MAAO,iCACjB,EAGM,GAAID,EAAU,GAAKA,EAAU,KAAK,OAAO,SACvC,MAAO,CACL,QAAS,GACT,MAAO,wBAAwBA,CAAO,kBAAkB,KAAK,OAAO,QAAQ,SACtF,EAIU,KAAK,aACP,KAAK,WAAW,OAAM,EACtB,KAAK,WAAa,MAGpB,MAAMG,EAAO,MAAM,KAAK,OAAO,QAAQH,CAAO,EACxCI,EAAWC,EAAAA,kBAAkBF,EAAMD,CAAK,EAE9CD,EAAO,MAAQG,EAAS,MACxBH,EAAO,OAASG,EAAS,OAEzB,MAAME,EAAUL,EAAO,WAAW,IAAI,EACtC,GAAI,CAACK,EACH,MAAO,CACL,QAAS,GACT,MAAO,iCACjB,EAGM,MAAMC,EAAgB,CACpB,cAAeD,EACf,SAAUF,CAClB,EAEM,YAAK,WAAaD,EAAK,OAAOI,CAAa,EAC3C,MAAM,KAAK,WAAW,QAEtB,KAAK,WAAa,KAEX,CACL,QAAS,GACT,SAAUH,CAClB,CACI,OAASL,EAAK,CACZ,OAAIA,EAAI,OAAS,+BACf,QAAQ,IAAI,qBAAqB,EAC1B,CACL,QAAS,GACT,MAAO,yBACjB,IAGM,QAAQ,MAAM,wBAAyBA,CAAG,EACnC,CACL,QAAS,GACT,MAAO,0BAA0BA,EAAI,OAAO,EACpD,EACI,QAAC,CACC,KAAK,WAAa,IACpB,CACF,CAOA,cAAe,CACb,OAAO,KAAK,OAAS,KAAK,OAAO,SAAW,CAC9C,CAOA,cAAe,CACb,GAAI,KAAK,WACP,GAAI,CACF,KAAK,WAAW,OAAM,CACxB,OAASA,EAAK,CACZ,QAAQ,IAAI,uCAAwCA,CAAG,CACzD,QAAC,CACC,KAAK,WAAa,IACpB,CAEJ,CAOA,SAAU,CACR,KAAK,aAAY,EAEb,KAAK,SACP,KAAK,OAAS,MAGhB,KAAK,WAAa,IACpB,CACF"}
|
package/dist/index3.js
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import * as c from "pdfjs-dist";
|
|
2
|
+
import { calculateViewport as i } from "./index11.js";
|
|
3
|
+
class u {
|
|
4
|
+
constructor() {
|
|
5
|
+
this.pdfDoc = null, this.renderTask = null;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Load PDF document from URL
|
|
9
|
+
*
|
|
10
|
+
* @param {string} url - URL or path to PDF file
|
|
11
|
+
* @returns {Promise<{success: boolean, pageCount?: number, error?: string}>}
|
|
12
|
+
*/
|
|
13
|
+
async loadDocument(e) {
|
|
14
|
+
try {
|
|
15
|
+
if (!e || typeof e != "string")
|
|
16
|
+
return {
|
|
17
|
+
success: !1,
|
|
18
|
+
error: "Invalid PDF URL provided"
|
|
19
|
+
};
|
|
20
|
+
const n = await c.getDocument(e).promise;
|
|
21
|
+
return this.pdfDoc = n, {
|
|
22
|
+
success: !0,
|
|
23
|
+
pageCount: n.numPages
|
|
24
|
+
};
|
|
25
|
+
} catch (r) {
|
|
26
|
+
return console.error("PDF loading error:", r), {
|
|
27
|
+
success: !1,
|
|
28
|
+
error: `Failed to load PDF: ${r.message}`
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Render PDF page to canvas element
|
|
34
|
+
*
|
|
35
|
+
* @param {number} pageNum - Page number (1-indexed)
|
|
36
|
+
* @param {HTMLCanvasElement} canvas - Canvas element to render to
|
|
37
|
+
* @param {number} scale - Scale factor for rendering
|
|
38
|
+
* @returns {Promise<{success: boolean, viewport?: Object, error?: string}>}
|
|
39
|
+
*/
|
|
40
|
+
async renderPage(e, r, n) {
|
|
41
|
+
try {
|
|
42
|
+
if (!this.pdfDoc)
|
|
43
|
+
return {
|
|
44
|
+
success: !1,
|
|
45
|
+
error: "No PDF document loaded"
|
|
46
|
+
};
|
|
47
|
+
if (!r || !(r instanceof HTMLCanvasElement))
|
|
48
|
+
return {
|
|
49
|
+
success: !1,
|
|
50
|
+
error: "Invalid canvas element provided"
|
|
51
|
+
};
|
|
52
|
+
if (e < 1 || e > this.pdfDoc.numPages)
|
|
53
|
+
return {
|
|
54
|
+
success: !1,
|
|
55
|
+
error: `Invalid page number: ${e}. Document has ${this.pdfDoc.numPages} pages.`
|
|
56
|
+
};
|
|
57
|
+
this.renderTask && (this.renderTask.cancel(), this.renderTask = null);
|
|
58
|
+
const s = await this.pdfDoc.getPage(e), t = i(s, n);
|
|
59
|
+
r.width = t.width, r.height = t.height;
|
|
60
|
+
const o = r.getContext("2d");
|
|
61
|
+
if (!o)
|
|
62
|
+
return {
|
|
63
|
+
success: !1,
|
|
64
|
+
error: "Failed to get canvas 2d context"
|
|
65
|
+
};
|
|
66
|
+
const a = {
|
|
67
|
+
canvasContext: o,
|
|
68
|
+
viewport: t
|
|
69
|
+
};
|
|
70
|
+
return this.renderTask = s.render(a), await this.renderTask.promise, this.renderTask = null, {
|
|
71
|
+
success: !0,
|
|
72
|
+
viewport: t
|
|
73
|
+
};
|
|
74
|
+
} catch (s) {
|
|
75
|
+
return s.name === "RenderingCancelledException" ? (console.log("Rendering cancelled"), {
|
|
76
|
+
success: !1,
|
|
77
|
+
error: "Rendering was cancelled"
|
|
78
|
+
}) : (console.error("Page rendering error:", s), {
|
|
79
|
+
success: !1,
|
|
80
|
+
error: `Failed to render page: ${s.message}`
|
|
81
|
+
});
|
|
82
|
+
} finally {
|
|
83
|
+
this.renderTask = null;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Get total number of pages in loaded PDF
|
|
88
|
+
*
|
|
89
|
+
* @returns {number} Page count, or 0 if no document loaded
|
|
90
|
+
*/
|
|
91
|
+
getPageCount() {
|
|
92
|
+
return this.pdfDoc ? this.pdfDoc.numPages : 0;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Cancel current rendering task if active
|
|
96
|
+
*
|
|
97
|
+
* @returns {void}
|
|
98
|
+
*/
|
|
99
|
+
cancelRender() {
|
|
100
|
+
if (this.renderTask)
|
|
101
|
+
try {
|
|
102
|
+
this.renderTask.cancel();
|
|
103
|
+
} catch (e) {
|
|
104
|
+
console.log("Render cancellation error (ignored):", e);
|
|
105
|
+
} finally {
|
|
106
|
+
this.renderTask = null;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Clean up resources and release references
|
|
111
|
+
*
|
|
112
|
+
* @returns {void}
|
|
113
|
+
*/
|
|
114
|
+
destroy() {
|
|
115
|
+
this.cancelRender(), this.pdfDoc && (this.pdfDoc = null), this.renderTask = null;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
export {
|
|
119
|
+
u as PDFRenderer
|
|
120
|
+
};
|
|
121
|
+
//# sourceMappingURL=index3.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index3.js","sources":["../src/core/PDFRenderer.js"],"sourcesContent":["/**\n * PDFRenderer - Framework-agnostic PDF rendering subsystem\n *\n * This module encapsulates all pdf.js operations including document loading,\n * page rendering, viewport calculations, and rendering task management.\n *\n * @module core/PDFRenderer\n */\n\nimport * as pdfjsLib from \"pdfjs-dist\";\nimport { calculateViewport } from \"../utils/viewportUtils.js\";\n\n/**\n * PDFRenderer class\n *\n * Provides framework-agnostic PDF rendering capabilities.\n * Abstracts pdf.js complexity and provides clean interface for engine.\n *\n * @class\n * @example\n * const renderer = new PDFRenderer();\n * await renderer.loadDocument('/path/to/doc.pdf');\n * const result = await renderer.renderPage(1, canvasElement, 1.5);\n */\nexport class PDFRenderer {\n constructor() {\n /**\n * @private\n * @type {PDFDocumentProxy|null}\n */\n this.pdfDoc = null;\n\n /**\n * @private\n * @type {RenderTask|null}\n */\n this.renderTask = null;\n }\n\n /**\n * Load PDF document from URL\n *\n * @param {string} url - URL or path to PDF file\n * @returns {Promise<{success: boolean, pageCount?: number, error?: string}>}\n */\n async loadDocument(url) {\n try {\n if (!url || typeof url !== \"string\") {\n return {\n success: false,\n error: \"Invalid PDF URL provided\",\n };\n }\n\n const loadingTask = pdfjsLib.getDocument(url);\n const pdf = await loadingTask.promise;\n\n this.pdfDoc = pdf;\n\n return {\n success: true,\n pageCount: pdf.numPages,\n };\n } catch (err) {\n console.error(\"PDF loading error:\", err);\n return {\n success: false,\n error: `Failed to load PDF: ${err.message}`,\n };\n }\n }\n\n /**\n * Render PDF page to canvas element\n *\n * @param {number} pageNum - Page number (1-indexed)\n * @param {HTMLCanvasElement} canvas - Canvas element to render to\n * @param {number} scale - Scale factor for rendering\n * @returns {Promise<{success: boolean, viewport?: Object, error?: string}>}\n */\n async renderPage(pageNum, canvas, scale) {\n try {\n if (!this.pdfDoc) {\n return {\n success: false,\n error: \"No PDF document loaded\",\n };\n }\n\n if (!canvas || !(canvas instanceof HTMLCanvasElement)) {\n return {\n success: false,\n error: \"Invalid canvas element provided\",\n };\n }\n\n if (pageNum < 1 || pageNum > this.pdfDoc.numPages) {\n return {\n success: false,\n error: `Invalid page number: ${pageNum}. Document has ${this.pdfDoc.numPages} pages.`,\n };\n }\n\n // Cancel any in-progress rendering\n if (this.renderTask) {\n this.renderTask.cancel();\n this.renderTask = null;\n }\n\n const page = await this.pdfDoc.getPage(pageNum);\n const viewport = calculateViewport(page, scale);\n\n canvas.width = viewport.width;\n canvas.height = viewport.height;\n\n const context = canvas.getContext(\"2d\");\n if (!context) {\n return {\n success: false,\n error: \"Failed to get canvas 2d context\",\n };\n }\n\n const renderContext = {\n canvasContext: context,\n viewport: viewport,\n };\n\n this.renderTask = page.render(renderContext);\n await this.renderTask.promise;\n\n this.renderTask = null;\n\n return {\n success: true,\n viewport: viewport,\n };\n } catch (err) {\n if (err.name === \"RenderingCancelledException\") {\n console.log(\"Rendering cancelled\");\n return {\n success: false,\n error: \"Rendering was cancelled\",\n };\n }\n\n console.error(\"Page rendering error:\", err);\n return {\n success: false,\n error: `Failed to render page: ${err.message}`,\n };\n } finally {\n this.renderTask = null;\n }\n }\n\n /**\n * Get total number of pages in loaded PDF\n *\n * @returns {number} Page count, or 0 if no document loaded\n */\n getPageCount() {\n return this.pdfDoc ? this.pdfDoc.numPages : 0;\n }\n\n /**\n * Cancel current rendering task if active\n *\n * @returns {void}\n */\n cancelRender() {\n if (this.renderTask) {\n try {\n this.renderTask.cancel();\n } catch (err) {\n console.log(\"Render cancellation error (ignored):\", err);\n } finally {\n this.renderTask = null;\n }\n }\n }\n\n /**\n * Clean up resources and release references\n *\n * @returns {void}\n */\n destroy() {\n this.cancelRender();\n\n if (this.pdfDoc) {\n this.pdfDoc = null;\n }\n\n this.renderTask = null;\n }\n}\n"],"names":["PDFRenderer","url","pdf","pdfjsLib","err","pageNum","canvas","scale","page","viewport","calculateViewport","context","renderContext"],"mappings":";;AAwBO,MAAMA,EAAY;AAAA,EACvB,cAAc;AAKZ,SAAK,SAAS,MAMd,KAAK,aAAa;AAAA,EACpB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,aAAaC,GAAK;AACtB,QAAI;AACF,UAAI,CAACA,KAAO,OAAOA,KAAQ;AACzB,eAAO;AAAA,UACL,SAAS;AAAA,UACT,OAAO;AAAA,QACjB;AAIM,YAAMC,IAAM,MADQC,EAAS,YAAYF,CAAG,EACd;AAE9B,kBAAK,SAASC,GAEP;AAAA,QACL,SAAS;AAAA,QACT,WAAWA,EAAI;AAAA,MACvB;AAAA,IACI,SAASE,GAAK;AACZ,qBAAQ,MAAM,sBAAsBA,CAAG,GAChC;AAAA,QACL,SAAS;AAAA,QACT,OAAO,uBAAuBA,EAAI,OAAO;AAAA,MACjD;AAAA,IACI;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,MAAM,WAAWC,GAASC,GAAQC,GAAO;AACvC,QAAI;AACF,UAAI,CAAC,KAAK;AACR,eAAO;AAAA,UACL,SAAS;AAAA,UACT,OAAO;AAAA,QACjB;AAGM,UAAI,CAACD,KAAU,EAAEA,aAAkB;AACjC,eAAO;AAAA,UACL,SAAS;AAAA,UACT,OAAO;AAAA,QACjB;AAGM,UAAID,IAAU,KAAKA,IAAU,KAAK,OAAO;AACvC,eAAO;AAAA,UACL,SAAS;AAAA,UACT,OAAO,wBAAwBA,CAAO,kBAAkB,KAAK,OAAO,QAAQ;AAAA,QACtF;AAIM,MAAI,KAAK,eACP,KAAK,WAAW,OAAM,GACtB,KAAK,aAAa;AAGpB,YAAMG,IAAO,MAAM,KAAK,OAAO,QAAQH,CAAO,GACxCI,IAAWC,EAAkBF,GAAMD,CAAK;AAE9C,MAAAD,EAAO,QAAQG,EAAS,OACxBH,EAAO,SAASG,EAAS;AAEzB,YAAME,IAAUL,EAAO,WAAW,IAAI;AACtC,UAAI,CAACK;AACH,eAAO;AAAA,UACL,SAAS;AAAA,UACT,OAAO;AAAA,QACjB;AAGM,YAAMC,IAAgB;AAAA,QACpB,eAAeD;AAAA,QACf,UAAUF;AAAA,MAClB;AAEM,kBAAK,aAAaD,EAAK,OAAOI,CAAa,GAC3C,MAAM,KAAK,WAAW,SAEtB,KAAK,aAAa,MAEX;AAAA,QACL,SAAS;AAAA,QACT,UAAUH;AAAA,MAClB;AAAA,IACI,SAASL,GAAK;AACZ,aAAIA,EAAI,SAAS,iCACf,QAAQ,IAAI,qBAAqB,GAC1B;AAAA,QACL,SAAS;AAAA,QACT,OAAO;AAAA,MACjB,MAGM,QAAQ,MAAM,yBAAyBA,CAAG,GACnC;AAAA,QACL,SAAS;AAAA,QACT,OAAO,0BAA0BA,EAAI,OAAO;AAAA,MACpD;AAAA,IACI,UAAC;AACC,WAAK,aAAa;AAAA,IACpB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,eAAe;AACb,WAAO,KAAK,SAAS,KAAK,OAAO,WAAW;AAAA,EAC9C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,eAAe;AACb,QAAI,KAAK;AACP,UAAI;AACF,aAAK,WAAW,OAAM;AAAA,MACxB,SAASA,GAAK;AACZ,gBAAQ,IAAI,wCAAwCA,CAAG;AAAA,MACzD,UAAC;AACC,aAAK,aAAa;AAAA,MACpB;AAAA,EAEJ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,UAAU;AACR,SAAK,aAAY,GAEb,KAAK,WACP,KAAK,SAAS,OAGhB,KAAK,aAAa;AAAA,EACpB;AACF;"}
|
package/dist/index4.cjs
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const h=require("./index7.cjs"),l=require("./index8.cjs"),o=require("./index9.cjs");class y{constructor(e,t){if(!e||!(e instanceof HTMLElement))throw new Error("LayerManager: containerElement must be a valid DOM element");if(!t||typeof t!="object")throw new Error("LayerManager: viewport must be a valid object");if(typeof t.width!="number"||typeof t.height!="number")throw new Error("LayerManager: viewport must have width and height properties");this.container=e,this.currentPage=null,this.currentViewport=t,this.allAnnotations=[],this.layers={highlight:new h.default(e,t),text:new l.default(e,t),drawing:new o.default(e,t)}}setAnnotations(e,t){if(Array.isArray(e)||(console.warn("LayerManager.setAnnotations: annotations must be an array"),e=[]),typeof t!="number"||t<1){console.warn("LayerManager.setAnnotations: invalid page number");return}this.allAnnotations=e,this.currentPage=t;const i=e.filter(r=>r.page===t),n=i.filter(r=>r.type==="highlight"),s=i.filter(r=>r.type==="text"),a=i.filter(r=>r.type==="ink");this.layers.highlight.setAnnotations(n),this.layers.text.setAnnotations(s),this.layers.drawing.setAnnotations(a),this.layers.highlight.render(),this.layers.text.render(),this.layers.drawing.render()}setViewport(e){if(!e||typeof e!="object"){console.warn("LayerManager.setViewport: invalid viewport object");return}this.currentViewport=e,this.layers.highlight.setViewport(e),this.layers.text.setViewport(e),this.layers.drawing.setViewport(e),this.layers.highlight.render(),this.layers.text.render(),this.layers.drawing.render()}updateTimeline(e){if(typeof e!="number"){console.warn("LayerManager.updateTimeline: timestamp must be a number");return}this.layers.highlight.updateTime(e),this.layers.text.updateTime(e),this.layers.drawing.updateTime(e)}destroy(){this.layers&&(this.layers.highlight.destroy(),this.layers.text.destroy(),this.layers.drawing.destroy(),this.layers=null),this.container=null,this.currentPage=null,this.currentViewport=null,this.allAnnotations=[]}}exports.LayerManager=y;
|
|
2
|
+
//# sourceMappingURL=index4.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index4.cjs","sources":["../src/core/LayerManager.js"],"sourcesContent":["/**\n * LayerManager - Framework-agnostic layer orchestration subsystem\n *\n * This module manages annotation layer instances, routes annotations by type,\n * and coordinates viewport and timeline state across all layers.\n * Instantiates layer classes directly and manages their lifecycle.\n *\n * @module core/LayerManager\n */\n\nimport HighlightLayer from '../layers/HighlightLayer.js';\nimport TextLayer from '../layers/TextLayer.js';\nimport DrawingLayer from '../layers/DrawingLayer.js';\n\n/**\n * LayerManager class\n *\n * Orchestrates annotation layers by instantiating and managing layer instances.\n * Routes annotations to appropriate layers by type, propagates viewport changes,\n * and coordinates timeline updates. Uses Direct Instantiation Pattern for\n * framework-agnostic layer management.\n *\n * @class\n * @example\n * const viewport = { width: 800, height: 600, scale: 1.0 };\n * const manager = new LayerManager(containerElement, viewport);\n * manager.setAnnotations(annotations, 1);\n * manager.setViewport(newViewport);\n * manager.updateTimeline(5.0);\n * // Layers render automatically\n * manager.destroy();\n */\nexport class LayerManager {\n /**\n * Create LayerManager instance\n *\n * Instantiates all layer classes and manages their lifecycle.\n * Layers are created immediately and appended to container.\n *\n * @param {HTMLElement} containerElement - DOM element for layer rendering\n * @param {Object} viewport - Initial viewport dimensions\n * @param {number} viewport.width - Viewport width in pixels\n * @param {number} viewport.height - Viewport height in pixels\n * @param {number} viewport.scale - Scale factor\n * @throws {Error} If containerElement is not a valid DOM element\n * @throws {Error} If viewport is invalid or missing required properties\n */\n constructor(containerElement, viewport) {\n // Validate container element\n if (!containerElement || !(containerElement instanceof HTMLElement)) {\n throw new Error('LayerManager: containerElement must be a valid DOM element');\n }\n\n // Validate viewport\n if (!viewport || typeof viewport !== 'object') {\n throw new Error('LayerManager: viewport must be a valid object');\n }\n if (typeof viewport.width !== 'number' || typeof viewport.height !== 'number') {\n throw new Error('LayerManager: viewport must have width and height properties');\n }\n\n /**\n * @private\n * @type {HTMLElement}\n */\n this.container = containerElement;\n\n /**\n * @private\n * @type {number|null}\n */\n this.currentPage = null;\n\n /**\n * @private\n * @type {Object}\n */\n this.currentViewport = viewport;\n\n /**\n * @private\n * @type {Array}\n */\n this.allAnnotations = [];\n\n /**\n * Layer instances\n * @private\n * @type {Object}\n */\n this.layers = {\n highlight: new HighlightLayer(containerElement, viewport),\n text: new TextLayer(containerElement, viewport),\n drawing: new DrawingLayer(containerElement, viewport)\n };\n }\n\n /**\n * Set annotations and route to appropriate layers\n *\n * Filters annotations for the specified page and groups by type.\n * Passes annotations to layer instances and triggers render.\n * Layers create/update their DOM elements during render.\n *\n * @param {Array} annotations - Complete annotation array (all pages, all types)\n * @param {number} pageNum - Current page number (1-indexed)\n * @returns {void}\n */\n setAnnotations(annotations, pageNum) {\n // Validate inputs\n if (!Array.isArray(annotations)) {\n console.warn('LayerManager.setAnnotations: annotations must be an array');\n annotations = [];\n }\n\n if (typeof pageNum !== 'number' || pageNum < 1) {\n console.warn('LayerManager.setAnnotations: invalid page number');\n return;\n }\n\n // Store for reference\n this.allAnnotations = annotations;\n this.currentPage = pageNum;\n\n // Filter annotations for current page only\n const pageAnnotations = annotations.filter(a => a.page === pageNum);\n\n // Group by type\n const highlights = pageAnnotations.filter(a => a.type === 'highlight');\n const textAnnotations = pageAnnotations.filter(a => a.type === 'text');\n const inkAnnotations = pageAnnotations.filter(a => a.type === 'ink');\n\n // Pass annotations to layer instances\n this.layers.highlight.setAnnotations(highlights);\n this.layers.text.setAnnotations(textAnnotations);\n this.layers.drawing.setAnnotations(inkAnnotations);\n\n // Trigger render on all layers\n this.layers.highlight.render();\n this.layers.text.render();\n this.layers.drawing.render();\n }\n\n /**\n * Update viewport dimensions for all layers\n *\n * Propagates viewport object to all layer instances.\n * Triggers render to recalculate element positions and dimensions.\n * Viewport contains width, height, scale from PDFRenderer.\n *\n * @param {Object} viewport - Viewport object from PDFRenderer\n * @param {number} viewport.width - Viewport width in pixels\n * @param {number} viewport.height - Viewport height in pixels\n * @param {number} viewport.scale - Scale factor\n * @returns {void}\n */\n setViewport(viewport) {\n // Validate viewport\n if (!viewport || typeof viewport !== 'object') {\n console.warn('LayerManager.setViewport: invalid viewport object');\n return;\n }\n\n // Store viewport reference\n this.currentViewport = viewport;\n\n // Propagate to all layer instances\n this.layers.highlight.setViewport(viewport);\n this.layers.text.setViewport(viewport);\n this.layers.drawing.setViewport(viewport);\n\n // Trigger render on all layers (viewport change requires re-layout)\n this.layers.highlight.render();\n this.layers.text.render();\n this.layers.drawing.render();\n }\n\n /**\n * Update timeline position for all layers\n *\n * Propagates timestamp to all layer instances.\n * Layers handle their own animation updates (RAF loops, transforms, etc).\n *\n * @param {number} timestamp - Current timeline position in seconds\n * @returns {void}\n */\n updateTimeline(timestamp) {\n // Validate timestamp\n if (typeof timestamp !== 'number') {\n console.warn('LayerManager.updateTimeline: timestamp must be a number');\n return;\n }\n\n // Propagate time update to all layer instances\n this.layers.highlight.updateTime(timestamp);\n this.layers.text.updateTime(timestamp);\n this.layers.drawing.updateTime(timestamp);\n }\n\n /**\n * Clean up resources and destroy layer instances\n *\n * Calls destroy() on all layer instances to clean up DOM elements,\n * cancel animations, and release references.\n * Call before removing LayerManager instance.\n *\n * @returns {void}\n */\n destroy() {\n // Destroy all layer instances\n if (this.layers) {\n this.layers.highlight.destroy();\n this.layers.text.destroy();\n this.layers.drawing.destroy();\n this.layers = null;\n }\n\n // Clear all references\n this.container = null;\n this.currentPage = null;\n this.currentViewport = null;\n this.allAnnotations = [];\n }\n}\n"],"names":["LayerManager","containerElement","viewport","HighlightLayer","TextLayer","DrawingLayer","annotations","pageNum","pageAnnotations","a","highlights","textAnnotations","inkAnnotations","timestamp"],"mappings":"oKAgCO,MAAMA,CAAa,CAexB,YAAYC,EAAkBC,EAAU,CAEtC,GAAI,CAACD,GAAoB,EAAEA,aAA4B,aACrD,MAAM,IAAI,MAAM,4DAA4D,EAI9E,GAAI,CAACC,GAAY,OAAOA,GAAa,SACnC,MAAM,IAAI,MAAM,+CAA+C,EAEjE,GAAI,OAAOA,EAAS,OAAU,UAAY,OAAOA,EAAS,QAAW,SACnE,MAAM,IAAI,MAAM,8DAA8D,EAOhF,KAAK,UAAYD,EAMjB,KAAK,YAAc,KAMnB,KAAK,gBAAkBC,EAMvB,KAAK,eAAiB,CAAA,EAOtB,KAAK,OAAS,CACZ,UAAW,IAAIC,EAAAA,QAAeF,EAAkBC,CAAQ,EACxD,KAAM,IAAIE,EAAAA,QAAUH,EAAkBC,CAAQ,EAC9C,QAAS,IAAIG,UAAaJ,EAAkBC,CAAQ,CAC1D,CACE,CAaA,eAAeI,EAAaC,EAAS,CAOnC,GALK,MAAM,QAAQD,CAAW,IAC5B,QAAQ,KAAK,2DAA2D,EACxEA,EAAc,CAAA,GAGZ,OAAOC,GAAY,UAAYA,EAAU,EAAG,CAC9C,QAAQ,KAAK,kDAAkD,EAC/D,MACF,CAGA,KAAK,eAAiBD,EACtB,KAAK,YAAcC,EAGnB,MAAMC,EAAkBF,EAAY,OAAOG,GAAKA,EAAE,OAASF,CAAO,EAG5DG,EAAaF,EAAgB,OAAOC,GAAKA,EAAE,OAAS,WAAW,EAC/DE,EAAkBH,EAAgB,OAAOC,GAAKA,EAAE,OAAS,MAAM,EAC/DG,EAAiBJ,EAAgB,OAAOC,GAAKA,EAAE,OAAS,KAAK,EAGnE,KAAK,OAAO,UAAU,eAAeC,CAAU,EAC/C,KAAK,OAAO,KAAK,eAAeC,CAAe,EAC/C,KAAK,OAAO,QAAQ,eAAeC,CAAc,EAGjD,KAAK,OAAO,UAAU,OAAM,EAC5B,KAAK,OAAO,KAAK,OAAM,EACvB,KAAK,OAAO,QAAQ,OAAM,CAC5B,CAeA,YAAYV,EAAU,CAEpB,GAAI,CAACA,GAAY,OAAOA,GAAa,SAAU,CAC7C,QAAQ,KAAK,mDAAmD,EAChE,MACF,CAGA,KAAK,gBAAkBA,EAGvB,KAAK,OAAO,UAAU,YAAYA,CAAQ,EAC1C,KAAK,OAAO,KAAK,YAAYA,CAAQ,EACrC,KAAK,OAAO,QAAQ,YAAYA,CAAQ,EAGxC,KAAK,OAAO,UAAU,OAAM,EAC5B,KAAK,OAAO,KAAK,OAAM,EACvB,KAAK,OAAO,QAAQ,OAAM,CAC5B,CAWA,eAAeW,EAAW,CAExB,GAAI,OAAOA,GAAc,SAAU,CACjC,QAAQ,KAAK,yDAAyD,EACtE,MACF,CAGA,KAAK,OAAO,UAAU,WAAWA,CAAS,EAC1C,KAAK,OAAO,KAAK,WAAWA,CAAS,EACrC,KAAK,OAAO,QAAQ,WAAWA,CAAS,CAC1C,CAWA,SAAU,CAEJ,KAAK,SACP,KAAK,OAAO,UAAU,QAAO,EAC7B,KAAK,OAAO,KAAK,QAAO,EACxB,KAAK,OAAO,QAAQ,QAAO,EAC3B,KAAK,OAAS,MAIhB,KAAK,UAAY,KACjB,KAAK,YAAc,KACnB,KAAK,gBAAkB,KACvB,KAAK,eAAiB,CAAA,CACxB,CACF"}
|
package/dist/index4.js
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import h from "./index7.js";
|
|
2
|
+
import l from "./index8.js";
|
|
3
|
+
import o from "./index9.js";
|
|
4
|
+
class f {
|
|
5
|
+
/**
|
|
6
|
+
* Create LayerManager instance
|
|
7
|
+
*
|
|
8
|
+
* Instantiates all layer classes and manages their lifecycle.
|
|
9
|
+
* Layers are created immediately and appended to container.
|
|
10
|
+
*
|
|
11
|
+
* @param {HTMLElement} containerElement - DOM element for layer rendering
|
|
12
|
+
* @param {Object} viewport - Initial viewport dimensions
|
|
13
|
+
* @param {number} viewport.width - Viewport width in pixels
|
|
14
|
+
* @param {number} viewport.height - Viewport height in pixels
|
|
15
|
+
* @param {number} viewport.scale - Scale factor
|
|
16
|
+
* @throws {Error} If containerElement is not a valid DOM element
|
|
17
|
+
* @throws {Error} If viewport is invalid or missing required properties
|
|
18
|
+
*/
|
|
19
|
+
constructor(t, e) {
|
|
20
|
+
if (!t || !(t instanceof HTMLElement))
|
|
21
|
+
throw new Error("LayerManager: containerElement must be a valid DOM element");
|
|
22
|
+
if (!e || typeof e != "object")
|
|
23
|
+
throw new Error("LayerManager: viewport must be a valid object");
|
|
24
|
+
if (typeof e.width != "number" || typeof e.height != "number")
|
|
25
|
+
throw new Error("LayerManager: viewport must have width and height properties");
|
|
26
|
+
this.container = t, this.currentPage = null, this.currentViewport = e, this.allAnnotations = [], this.layers = {
|
|
27
|
+
highlight: new h(t, e),
|
|
28
|
+
text: new l(t, e),
|
|
29
|
+
drawing: new o(t, e)
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Set annotations and route to appropriate layers
|
|
34
|
+
*
|
|
35
|
+
* Filters annotations for the specified page and groups by type.
|
|
36
|
+
* Passes annotations to layer instances and triggers render.
|
|
37
|
+
* Layers create/update their DOM elements during render.
|
|
38
|
+
*
|
|
39
|
+
* @param {Array} annotations - Complete annotation array (all pages, all types)
|
|
40
|
+
* @param {number} pageNum - Current page number (1-indexed)
|
|
41
|
+
* @returns {void}
|
|
42
|
+
*/
|
|
43
|
+
setAnnotations(t, e) {
|
|
44
|
+
if (Array.isArray(t) || (console.warn("LayerManager.setAnnotations: annotations must be an array"), t = []), typeof e != "number" || e < 1) {
|
|
45
|
+
console.warn("LayerManager.setAnnotations: invalid page number");
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
this.allAnnotations = t, this.currentPage = e;
|
|
49
|
+
const i = t.filter((r) => r.page === e), s = i.filter((r) => r.type === "highlight"), n = i.filter((r) => r.type === "text"), a = i.filter((r) => r.type === "ink");
|
|
50
|
+
this.layers.highlight.setAnnotations(s), this.layers.text.setAnnotations(n), this.layers.drawing.setAnnotations(a), this.layers.highlight.render(), this.layers.text.render(), this.layers.drawing.render();
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Update viewport dimensions for all layers
|
|
54
|
+
*
|
|
55
|
+
* Propagates viewport object to all layer instances.
|
|
56
|
+
* Triggers render to recalculate element positions and dimensions.
|
|
57
|
+
* Viewport contains width, height, scale from PDFRenderer.
|
|
58
|
+
*
|
|
59
|
+
* @param {Object} viewport - Viewport object from PDFRenderer
|
|
60
|
+
* @param {number} viewport.width - Viewport width in pixels
|
|
61
|
+
* @param {number} viewport.height - Viewport height in pixels
|
|
62
|
+
* @param {number} viewport.scale - Scale factor
|
|
63
|
+
* @returns {void}
|
|
64
|
+
*/
|
|
65
|
+
setViewport(t) {
|
|
66
|
+
if (!t || typeof t != "object") {
|
|
67
|
+
console.warn("LayerManager.setViewport: invalid viewport object");
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
this.currentViewport = t, this.layers.highlight.setViewport(t), this.layers.text.setViewport(t), this.layers.drawing.setViewport(t), this.layers.highlight.render(), this.layers.text.render(), this.layers.drawing.render();
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Update timeline position for all layers
|
|
74
|
+
*
|
|
75
|
+
* Propagates timestamp to all layer instances.
|
|
76
|
+
* Layers handle their own animation updates (RAF loops, transforms, etc).
|
|
77
|
+
*
|
|
78
|
+
* @param {number} timestamp - Current timeline position in seconds
|
|
79
|
+
* @returns {void}
|
|
80
|
+
*/
|
|
81
|
+
updateTimeline(t) {
|
|
82
|
+
if (typeof t != "number") {
|
|
83
|
+
console.warn("LayerManager.updateTimeline: timestamp must be a number");
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
this.layers.highlight.updateTime(t), this.layers.text.updateTime(t), this.layers.drawing.updateTime(t);
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Clean up resources and destroy layer instances
|
|
90
|
+
*
|
|
91
|
+
* Calls destroy() on all layer instances to clean up DOM elements,
|
|
92
|
+
* cancel animations, and release references.
|
|
93
|
+
* Call before removing LayerManager instance.
|
|
94
|
+
*
|
|
95
|
+
* @returns {void}
|
|
96
|
+
*/
|
|
97
|
+
destroy() {
|
|
98
|
+
this.layers && (this.layers.highlight.destroy(), this.layers.text.destroy(), this.layers.drawing.destroy(), this.layers = null), this.container = null, this.currentPage = null, this.currentViewport = null, this.allAnnotations = [];
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
export {
|
|
102
|
+
f as LayerManager
|
|
103
|
+
};
|
|
104
|
+
//# sourceMappingURL=index4.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index4.js","sources":["../src/core/LayerManager.js"],"sourcesContent":["/**\n * LayerManager - Framework-agnostic layer orchestration subsystem\n *\n * This module manages annotation layer instances, routes annotations by type,\n * and coordinates viewport and timeline state across all layers.\n * Instantiates layer classes directly and manages their lifecycle.\n *\n * @module core/LayerManager\n */\n\nimport HighlightLayer from '../layers/HighlightLayer.js';\nimport TextLayer from '../layers/TextLayer.js';\nimport DrawingLayer from '../layers/DrawingLayer.js';\n\n/**\n * LayerManager class\n *\n * Orchestrates annotation layers by instantiating and managing layer instances.\n * Routes annotations to appropriate layers by type, propagates viewport changes,\n * and coordinates timeline updates. Uses Direct Instantiation Pattern for\n * framework-agnostic layer management.\n *\n * @class\n * @example\n * const viewport = { width: 800, height: 600, scale: 1.0 };\n * const manager = new LayerManager(containerElement, viewport);\n * manager.setAnnotations(annotations, 1);\n * manager.setViewport(newViewport);\n * manager.updateTimeline(5.0);\n * // Layers render automatically\n * manager.destroy();\n */\nexport class LayerManager {\n /**\n * Create LayerManager instance\n *\n * Instantiates all layer classes and manages their lifecycle.\n * Layers are created immediately and appended to container.\n *\n * @param {HTMLElement} containerElement - DOM element for layer rendering\n * @param {Object} viewport - Initial viewport dimensions\n * @param {number} viewport.width - Viewport width in pixels\n * @param {number} viewport.height - Viewport height in pixels\n * @param {number} viewport.scale - Scale factor\n * @throws {Error} If containerElement is not a valid DOM element\n * @throws {Error} If viewport is invalid or missing required properties\n */\n constructor(containerElement, viewport) {\n // Validate container element\n if (!containerElement || !(containerElement instanceof HTMLElement)) {\n throw new Error('LayerManager: containerElement must be a valid DOM element');\n }\n\n // Validate viewport\n if (!viewport || typeof viewport !== 'object') {\n throw new Error('LayerManager: viewport must be a valid object');\n }\n if (typeof viewport.width !== 'number' || typeof viewport.height !== 'number') {\n throw new Error('LayerManager: viewport must have width and height properties');\n }\n\n /**\n * @private\n * @type {HTMLElement}\n */\n this.container = containerElement;\n\n /**\n * @private\n * @type {number|null}\n */\n this.currentPage = null;\n\n /**\n * @private\n * @type {Object}\n */\n this.currentViewport = viewport;\n\n /**\n * @private\n * @type {Array}\n */\n this.allAnnotations = [];\n\n /**\n * Layer instances\n * @private\n * @type {Object}\n */\n this.layers = {\n highlight: new HighlightLayer(containerElement, viewport),\n text: new TextLayer(containerElement, viewport),\n drawing: new DrawingLayer(containerElement, viewport)\n };\n }\n\n /**\n * Set annotations and route to appropriate layers\n *\n * Filters annotations for the specified page and groups by type.\n * Passes annotations to layer instances and triggers render.\n * Layers create/update their DOM elements during render.\n *\n * @param {Array} annotations - Complete annotation array (all pages, all types)\n * @param {number} pageNum - Current page number (1-indexed)\n * @returns {void}\n */\n setAnnotations(annotations, pageNum) {\n // Validate inputs\n if (!Array.isArray(annotations)) {\n console.warn('LayerManager.setAnnotations: annotations must be an array');\n annotations = [];\n }\n\n if (typeof pageNum !== 'number' || pageNum < 1) {\n console.warn('LayerManager.setAnnotations: invalid page number');\n return;\n }\n\n // Store for reference\n this.allAnnotations = annotations;\n this.currentPage = pageNum;\n\n // Filter annotations for current page only\n const pageAnnotations = annotations.filter(a => a.page === pageNum);\n\n // Group by type\n const highlights = pageAnnotations.filter(a => a.type === 'highlight');\n const textAnnotations = pageAnnotations.filter(a => a.type === 'text');\n const inkAnnotations = pageAnnotations.filter(a => a.type === 'ink');\n\n // Pass annotations to layer instances\n this.layers.highlight.setAnnotations(highlights);\n this.layers.text.setAnnotations(textAnnotations);\n this.layers.drawing.setAnnotations(inkAnnotations);\n\n // Trigger render on all layers\n this.layers.highlight.render();\n this.layers.text.render();\n this.layers.drawing.render();\n }\n\n /**\n * Update viewport dimensions for all layers\n *\n * Propagates viewport object to all layer instances.\n * Triggers render to recalculate element positions and dimensions.\n * Viewport contains width, height, scale from PDFRenderer.\n *\n * @param {Object} viewport - Viewport object from PDFRenderer\n * @param {number} viewport.width - Viewport width in pixels\n * @param {number} viewport.height - Viewport height in pixels\n * @param {number} viewport.scale - Scale factor\n * @returns {void}\n */\n setViewport(viewport) {\n // Validate viewport\n if (!viewport || typeof viewport !== 'object') {\n console.warn('LayerManager.setViewport: invalid viewport object');\n return;\n }\n\n // Store viewport reference\n this.currentViewport = viewport;\n\n // Propagate to all layer instances\n this.layers.highlight.setViewport(viewport);\n this.layers.text.setViewport(viewport);\n this.layers.drawing.setViewport(viewport);\n\n // Trigger render on all layers (viewport change requires re-layout)\n this.layers.highlight.render();\n this.layers.text.render();\n this.layers.drawing.render();\n }\n\n /**\n * Update timeline position for all layers\n *\n * Propagates timestamp to all layer instances.\n * Layers handle their own animation updates (RAF loops, transforms, etc).\n *\n * @param {number} timestamp - Current timeline position in seconds\n * @returns {void}\n */\n updateTimeline(timestamp) {\n // Validate timestamp\n if (typeof timestamp !== 'number') {\n console.warn('LayerManager.updateTimeline: timestamp must be a number');\n return;\n }\n\n // Propagate time update to all layer instances\n this.layers.highlight.updateTime(timestamp);\n this.layers.text.updateTime(timestamp);\n this.layers.drawing.updateTime(timestamp);\n }\n\n /**\n * Clean up resources and destroy layer instances\n *\n * Calls destroy() on all layer instances to clean up DOM elements,\n * cancel animations, and release references.\n * Call before removing LayerManager instance.\n *\n * @returns {void}\n */\n destroy() {\n // Destroy all layer instances\n if (this.layers) {\n this.layers.highlight.destroy();\n this.layers.text.destroy();\n this.layers.drawing.destroy();\n this.layers = null;\n }\n\n // Clear all references\n this.container = null;\n this.currentPage = null;\n this.currentViewport = null;\n this.allAnnotations = [];\n }\n}\n"],"names":["LayerManager","containerElement","viewport","HighlightLayer","TextLayer","DrawingLayer","annotations","pageNum","pageAnnotations","a","highlights","textAnnotations","inkAnnotations","timestamp"],"mappings":"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"}
|
package/dist/index5.cjs
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});class r{constructor(){this.currentTime=0,this.subscribers=new Set,this.animationFrameId=null,this.isRunning=!1}setTime(n){n!==this.currentTime&&(this.currentTime=n,this.notifySubscribers())}getCurrentTime(){return this.currentTime}subscribe(n){if(typeof n!="function")throw new Error("TimelineSync.subscribe: callback must be a function");return this.subscribers.add(n),()=>this.unsubscribe(n)}unsubscribe(n){this.subscribers.delete(n)}startContinuousSync(n){if(typeof n!="function")throw new Error("TimelineSync.startContinuousSync: getTimeFunction must be a function");if(this.isRunning){console.warn("TimelineSync: Continuous sync already running");return}this.isRunning=!0;const i=()=>{if(this.isRunning){try{const e=n();this.setTime(e)}catch(e){console.error("TimelineSync: Error in continuous sync:",e)}this.animationFrameId=requestAnimationFrame(i)}};i()}stopContinuousSync(){this.isRunning=!1,this.animationFrameId!==null&&(cancelAnimationFrame(this.animationFrameId),this.animationFrameId=null)}destroy(){this.stopContinuousSync(),this.subscribers.clear(),this.currentTime=0}notifySubscribers(){for(const n of this.subscribers)try{n(this.currentTime)}catch(i){console.error("TimelineSync: Subscriber callback error:",i)}}}exports.TimelineSync=r;
|
|
2
|
+
//# sourceMappingURL=index5.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index5.cjs","sources":["../src/core/TimelineSync.js"],"sourcesContent":["/**\n * TimelineSync - Framework-agnostic timeline synchronization subsystem\n *\n * This module manages timeline position and provides a subscriber notification\n * system for timeline updates. Supports both discrete updates (manual setTime)\n * and continuous synchronization via requestAnimationFrame for audio/video.\n *\n * @module core/TimelineSync\n */\n\n/**\n * TimelineSync class\n *\n * Provides timeline state management and pub-sub notification system.\n * Zero dependencies - pure JavaScript implementation.\n *\n * @class\n * @example\n * // Discrete mode\n * const sync = new TimelineSync();\n * sync.subscribe((time) => console.log('Time:', time));\n * sync.setTime(5.0);\n *\n * @example\n * // Continuous mode with audio\n * const audio = document.getElementById('audio');\n * sync.startContinuousSync(() => audio.currentTime);\n */\nexport class TimelineSync {\n constructor() {\n /**\n * @private\n * @type {number}\n */\n this.currentTime = 0;\n\n /**\n * @private\n * @type {Set<Function>}\n */\n this.subscribers = new Set();\n\n /**\n * @private\n * @type {number|null}\n */\n this.animationFrameId = null;\n\n /**\n * @private\n * @type {boolean}\n */\n this.isRunning = false;\n }\n\n /**\n * Set timeline position and notify subscribers if changed\n *\n * @param {number} timestamp - Timeline position in seconds\n * @returns {void}\n */\n setTime(timestamp) {\n if (timestamp === this.currentTime) {\n return;\n }\n\n this.currentTime = timestamp;\n this.notifySubscribers();\n }\n\n /**\n * Get current timeline position\n *\n * @returns {number} Current timeline position in seconds\n */\n getCurrentTime() {\n return this.currentTime;\n }\n\n /**\n * Subscribe to timeline updates\n *\n * @param {Function} callback - Function to call on timeline updates\n * @returns {Function} Unsubscribe function\n * @throws {Error} If callback is not a function\n */\n subscribe(callback) {\n if (typeof callback !== 'function') {\n throw new Error('TimelineSync.subscribe: callback must be a function');\n }\n\n this.subscribers.add(callback);\n\n return () => this.unsubscribe(callback);\n }\n\n /**\n * Unsubscribe from timeline updates\n *\n * @param {Function} callback - Callback function to remove\n * @returns {void}\n */\n unsubscribe(callback) {\n this.subscribers.delete(callback);\n }\n\n /**\n * Start continuous timeline synchronization\n *\n * @param {Function} getTimeFunction - Function that returns current time\n * @returns {void}\n * @throws {Error} If getTimeFunction is not a function\n */\n startContinuousSync(getTimeFunction) {\n if (typeof getTimeFunction !== 'function') {\n throw new Error('TimelineSync.startContinuousSync: getTimeFunction must be a function');\n }\n\n if (this.isRunning) {\n console.warn('TimelineSync: Continuous sync already running');\n return;\n }\n\n this.isRunning = true;\n\n const syncLoop = () => {\n if (!this.isRunning) {\n return;\n }\n\n try {\n const newTime = getTimeFunction();\n this.setTime(newTime);\n } catch (err) {\n console.error('TimelineSync: Error in continuous sync:', err);\n }\n\n this.animationFrameId = requestAnimationFrame(syncLoop);\n };\n\n syncLoop();\n }\n\n /**\n * Stop continuous timeline synchronization\n *\n * @returns {void}\n */\n stopContinuousSync() {\n this.isRunning = false;\n\n if (this.animationFrameId !== null) {\n cancelAnimationFrame(this.animationFrameId);\n this.animationFrameId = null;\n }\n }\n\n /**\n * Clean up resources and release references\n *\n * @returns {void}\n */\n destroy() {\n this.stopContinuousSync();\n this.subscribers.clear();\n this.currentTime = 0;\n }\n\n /**\n * Notify all subscribers of current time\n *\n * @private\n * @returns {void}\n */\n notifySubscribers() {\n for (const callback of this.subscribers) {\n try {\n callback(this.currentTime);\n } catch (err) {\n console.error('TimelineSync: Subscriber callback error:', err);\n }\n }\n }\n}\n"],"names":["TimelineSync","timestamp","callback","getTimeFunction","syncLoop","newTime","err"],"mappings":"gFA4BO,MAAMA,CAAa,CACxB,aAAc,CAKZ,KAAK,YAAc,EAMnB,KAAK,YAAc,IAAI,IAMvB,KAAK,iBAAmB,KAMxB,KAAK,UAAY,EACnB,CAQA,QAAQC,EAAW,CACbA,IAAc,KAAK,cAIvB,KAAK,YAAcA,EACnB,KAAK,kBAAiB,EACxB,CAOA,gBAAiB,CACf,OAAO,KAAK,WACd,CASA,UAAUC,EAAU,CAClB,GAAI,OAAOA,GAAa,WACtB,MAAM,IAAI,MAAM,qDAAqD,EAGvE,YAAK,YAAY,IAAIA,CAAQ,EAEtB,IAAM,KAAK,YAAYA,CAAQ,CACxC,CAQA,YAAYA,EAAU,CACpB,KAAK,YAAY,OAAOA,CAAQ,CAClC,CASA,oBAAoBC,EAAiB,CACnC,GAAI,OAAOA,GAAoB,WAC7B,MAAM,IAAI,MAAM,sEAAsE,EAGxF,GAAI,KAAK,UAAW,CAClB,QAAQ,KAAK,+CAA+C,EAC5D,MACF,CAEA,KAAK,UAAY,GAEjB,MAAMC,EAAW,IAAM,CACrB,GAAK,KAAK,UAIV,IAAI,CACF,MAAMC,EAAUF,EAAe,EAC/B,KAAK,QAAQE,CAAO,CACtB,OAASC,EAAK,CACZ,QAAQ,MAAM,0CAA2CA,CAAG,CAC9D,CAEA,KAAK,iBAAmB,sBAAsBF,CAAQ,EACxD,EAEAA,EAAQ,CACV,CAOA,oBAAqB,CACnB,KAAK,UAAY,GAEb,KAAK,mBAAqB,OAC5B,qBAAqB,KAAK,gBAAgB,EAC1C,KAAK,iBAAmB,KAE5B,CAOA,SAAU,CACR,KAAK,mBAAkB,EACvB,KAAK,YAAY,MAAK,EACtB,KAAK,YAAc,CACrB,CAQA,mBAAoB,CAClB,UAAWF,KAAY,KAAK,YAC1B,GAAI,CACFA,EAAS,KAAK,WAAW,CAC3B,OAASI,EAAK,CACZ,QAAQ,MAAM,2CAA4CA,CAAG,CAC/D,CAEJ,CACF"}
|