web-annotation-renderer 0.3.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +49 -42
- package/dist/index.js.map +1 -1
- package/dist/index10.cjs +1 -1
- package/dist/index10.cjs.map +1 -1
- package/dist/index10.js +172 -17
- package/dist/index10.js.map +1 -1
- package/dist/index11.cjs +1 -1
- package/dist/index11.cjs.map +1 -1
- package/dist/index11.js +13 -20
- package/dist/index11.js.map +1 -1
- package/dist/index12.cjs +1 -1
- package/dist/index12.cjs.map +1 -1
- package/dist/index12.js +167 -124
- package/dist/index12.js.map +1 -1
- package/dist/index13.cjs +1 -1
- package/dist/index13.cjs.map +1 -1
- package/dist/index13.js +29 -198
- package/dist/index13.js.map +1 -1
- package/dist/index14.cjs +1 -1
- package/dist/index14.cjs.map +1 -1
- package/dist/index14.js +78 -15
- package/dist/index14.js.map +1 -1
- package/dist/index15.cjs +1 -1
- package/dist/index15.cjs.map +1 -1
- package/dist/index15.js +115 -120
- package/dist/index15.js.map +1 -1
- package/dist/index16.cjs +1 -1
- package/dist/index16.cjs.map +1 -1
- package/dist/index16.js +100 -212
- package/dist/index16.js.map +1 -1
- package/dist/index17.cjs +1 -1
- package/dist/index17.cjs.map +1 -1
- package/dist/index17.js +55 -37
- package/dist/index17.js.map +1 -1
- package/dist/index18.cjs +1 -1
- package/dist/index18.cjs.map +1 -1
- package/dist/index18.js +139 -35
- package/dist/index18.js.map +1 -1
- package/dist/index19.cjs +1 -1
- package/dist/index19.cjs.map +1 -1
- package/dist/index19.js +37 -37
- package/dist/index19.js.map +1 -1
- package/dist/index2.cjs +1 -1
- package/dist/index2.cjs.map +1 -1
- package/dist/index2.js +95 -73
- package/dist/index2.js.map +1 -1
- package/dist/index20.cjs +1 -1
- package/dist/index20.cjs.map +1 -1
- package/dist/index20.js +29 -39
- package/dist/index20.js.map +1 -1
- package/dist/index21.cjs +1 -1
- package/dist/index21.cjs.map +1 -1
- package/dist/index21.js +38 -32
- package/dist/index21.js.map +1 -1
- package/dist/index22.cjs +1 -1
- package/dist/index22.cjs.map +1 -1
- package/dist/index22.js +22 -5
- package/dist/index22.js.map +1 -1
- package/dist/index23.cjs +2 -0
- package/dist/index23.cjs.map +1 -0
- package/dist/index23.js +8 -0
- package/dist/index23.js.map +1 -0
- package/dist/index24.cjs +2 -0
- package/dist/index24.cjs.map +1 -0
- package/dist/index24.js +8 -0
- package/dist/index24.js.map +1 -0
- package/dist/index3.cjs +1 -1
- package/dist/index3.cjs.map +1 -1
- package/dist/index3.js +1 -1
- package/dist/index4.cjs +1 -1
- package/dist/index4.cjs.map +1 -1
- package/dist/index4.js +72 -71
- package/dist/index4.js.map +1 -1
- package/dist/index5.cjs +1 -1
- package/dist/index5.cjs.map +1 -1
- package/dist/index5.js +217 -65
- package/dist/index5.js.map +1 -1
- package/dist/index6.cjs +1 -1
- package/dist/index6.cjs.map +1 -1
- package/dist/index6.js +60 -114
- package/dist/index6.js.map +1 -1
- package/dist/index7.cjs +1 -1
- package/dist/index7.cjs.map +1 -1
- package/dist/index7.js +19 -91
- package/dist/index7.js.map +1 -1
- package/dist/index8.cjs +1 -1
- package/dist/index8.cjs.map +1 -1
- package/dist/index8.js +19 -105
- package/dist/index8.js.map +1 -1
- package/dist/index9.cjs +1 -1
- package/dist/index9.cjs.map +1 -1
- package/dist/index9.js +123 -98
- package/dist/index9.js.map +1 -1
- package/package.json +4 -3
package/dist/index2.js
CHANGED
|
@@ -1,17 +1,19 @@
|
|
|
1
|
-
import { PDFRenderer as
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
|
|
1
|
+
import { PDFRenderer as n } from "./index3.js";
|
|
2
|
+
import { TimelineSync as s } from "./index4.js";
|
|
3
|
+
import { StrokeRenderer as i } from "./index5.js";
|
|
4
|
+
import { deepMerge as o } from "./index6.js";
|
|
5
|
+
class d {
|
|
5
6
|
/**
|
|
6
7
|
* Create AnnotationRenderer instance
|
|
7
8
|
*
|
|
8
9
|
* @param {Object} config - Configuration object
|
|
9
|
-
* @param {HTMLElement} config.container - DOM element for
|
|
10
|
+
* @param {HTMLElement} config.container - DOM element for annotation canvas
|
|
10
11
|
* @param {HTMLCanvasElement} config.canvasElement - Canvas element for PDF rendering
|
|
11
12
|
* @param {string} [config.pdfUrl] - PDF URL to load immediately
|
|
12
13
|
* @param {number} [config.initialPage=1] - Initial page number
|
|
13
14
|
* @param {number} [config.initialScale=1.0] - Initial scale factor
|
|
14
15
|
* @param {Array} [config.annotations=[]] - Initial annotation data
|
|
16
|
+
* @param {Object} [config.strokeConfig] - StrokeRenderer configuration
|
|
15
17
|
* @throws {Error} If config is invalid or required elements are missing
|
|
16
18
|
*/
|
|
17
19
|
constructor(e) {
|
|
@@ -21,42 +23,36 @@ class c {
|
|
|
21
23
|
throw new Error("AnnotationRenderer: config.container must be a valid DOM element");
|
|
22
24
|
if (!e.canvasElement || !(e.canvasElement instanceof HTMLCanvasElement))
|
|
23
25
|
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
|
|
25
|
-
|
|
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);
|
|
26
|
+
this.config = e, this.canvasElement = e.canvasElement, this.container = e.container, this.pdfRenderer = new n(), this.strokeCanvas = this._createStrokeCanvas(), this.strokeRenderer = new i(this.strokeCanvas, e.strokeConfig || {}), 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) => {
|
|
27
|
+
this.strokeRenderer.render(t);
|
|
30
28
|
}), e.pdfUrl && this.loadPDF(e.pdfUrl).catch((t) => {
|
|
31
29
|
console.error("AnnotationRenderer: Failed to auto-load PDF:", t);
|
|
32
30
|
});
|
|
33
31
|
}
|
|
32
|
+
/**
|
|
33
|
+
* Create stroke canvas overlay
|
|
34
|
+
*
|
|
35
|
+
* @private
|
|
36
|
+
* @returns {HTMLCanvasElement} Stroke canvas element
|
|
37
|
+
*/
|
|
38
|
+
_createStrokeCanvas() {
|
|
39
|
+
const e = document.createElement("canvas");
|
|
40
|
+
return e.className = "stroke-canvas", e.style.position = "absolute", e.style.top = "0", e.style.left = "0", e.style.pointerEvents = "none", e.style.zIndex = "10", this.container.appendChild(e), e;
|
|
41
|
+
}
|
|
34
42
|
/**
|
|
35
43
|
* Load PDF document from URL
|
|
36
44
|
*
|
|
37
45
|
* @param {string} url - URL or path to PDF file
|
|
38
46
|
* @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
47
|
*/
|
|
43
48
|
async loadPDF(e) {
|
|
44
49
|
try {
|
|
45
50
|
if (!e || typeof e != "string")
|
|
46
|
-
return {
|
|
47
|
-
success: !1,
|
|
48
|
-
error: "Invalid PDF URL provided"
|
|
49
|
-
};
|
|
51
|
+
return { success: !1, error: "Invalid PDF URL provided" };
|
|
50
52
|
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;
|
|
53
|
+
return t.success ? (this.pdfUrl = e, this.pageCount = t.pageCount, { success: !0, pageCount: t.pageCount }) : t;
|
|
55
54
|
} catch (t) {
|
|
56
|
-
return console.error("AnnotationRenderer.loadPDF: Error loading PDF:", t), {
|
|
57
|
-
success: !1,
|
|
58
|
-
error: `Failed to load PDF: ${t.message}`
|
|
59
|
-
};
|
|
55
|
+
return console.error("AnnotationRenderer.loadPDF: Error loading PDF:", t), { success: !1, error: `Failed to load PDF: ${t.message}` };
|
|
60
56
|
}
|
|
61
57
|
}
|
|
62
58
|
/**
|
|
@@ -64,37 +60,27 @@ class c {
|
|
|
64
60
|
*
|
|
65
61
|
* @param {number} pageNum - Page number (1-indexed)
|
|
66
62
|
* @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
63
|
*/
|
|
71
64
|
async setPage(e) {
|
|
72
65
|
try {
|
|
73
66
|
if (typeof e != "number" || e < 1)
|
|
74
|
-
return {
|
|
75
|
-
success: !1,
|
|
76
|
-
error: "Invalid page number"
|
|
77
|
-
};
|
|
67
|
+
return { success: !1, error: "Invalid page number" };
|
|
78
68
|
if (this.pageCount > 0 && e > this.pageCount)
|
|
79
|
-
return {
|
|
80
|
-
success: !1,
|
|
81
|
-
error: `Page ${e} exceeds document page count (${this.pageCount})`
|
|
82
|
-
};
|
|
69
|
+
return { success: !1, error: `Page ${e} exceeds document page count (${this.pageCount})` };
|
|
83
70
|
this.pdfRenderer.cancelRender();
|
|
84
71
|
const t = await this.pdfRenderer.renderPage(
|
|
85
72
|
e,
|
|
86
73
|
this.canvasElement,
|
|
87
74
|
this.currentScale
|
|
88
75
|
);
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
76
|
+
if (t.success) {
|
|
77
|
+
this.currentPage = e, this.currentViewport = t.viewport, this.strokeRenderer.setViewport(t.viewport.width, t.viewport.height), this.strokeRenderer.setAnnotations(this.annotations, e);
|
|
78
|
+
const r = this.timelineSync.getCurrentTime();
|
|
79
|
+
return this.strokeRenderer.render(r), { success: !0, viewport: t.viewport };
|
|
80
|
+
}
|
|
81
|
+
return t;
|
|
93
82
|
} catch (t) {
|
|
94
|
-
return console.error("AnnotationRenderer.setPage: Error rendering page:", t), {
|
|
95
|
-
success: !1,
|
|
96
|
-
error: `Failed to render page: ${t.message}`
|
|
97
|
-
};
|
|
83
|
+
return console.error("AnnotationRenderer.setPage: Error rendering page:", t), { success: !1, error: `Failed to render page: ${t.message}` };
|
|
98
84
|
}
|
|
99
85
|
}
|
|
100
86
|
/**
|
|
@@ -102,37 +88,40 @@ class c {
|
|
|
102
88
|
*
|
|
103
89
|
* @param {number} scale - Scale factor (e.g., 1.0, 1.5, 2.0)
|
|
104
90
|
* @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
91
|
*/
|
|
109
92
|
async setScale(e) {
|
|
110
93
|
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));
|
|
94
|
+
return typeof e != "number" || e <= 0 ? { success: !1, error: "Invalid scale value (must be positive number)" } : (this.currentScale = e, await this.setPage(this.currentPage));
|
|
115
95
|
} catch (t) {
|
|
116
|
-
return console.error("AnnotationRenderer.setScale: Error changing scale:", t), {
|
|
117
|
-
success: !1,
|
|
118
|
-
error: `Failed to change scale: ${t.message}`
|
|
119
|
-
};
|
|
96
|
+
return console.error("AnnotationRenderer.setScale: Error changing scale:", t), { success: !1, error: `Failed to change scale: ${t.message}` };
|
|
120
97
|
}
|
|
121
98
|
}
|
|
122
99
|
/**
|
|
123
100
|
* Update annotation data for rendering
|
|
124
101
|
*
|
|
125
102
|
* @param {Array} annotations - Complete annotation array (all pages, all types)
|
|
126
|
-
* @returns {void}
|
|
127
103
|
*/
|
|
128
104
|
setAnnotations(e) {
|
|
129
|
-
Array.isArray(e) || (console.warn("AnnotationRenderer.setAnnotations: annotations must be an array"), e = []), this.annotations = e, this.
|
|
105
|
+
Array.isArray(e) || (console.warn("AnnotationRenderer.setAnnotations: annotations must be an array"), e = []), this.annotations = e, this.strokeRenderer.setAnnotations(e, this.currentPage);
|
|
106
|
+
const t = this.timelineSync.getCurrentTime();
|
|
107
|
+
this.strokeRenderer.render(t);
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Set pre-converted strokes directly
|
|
111
|
+
*
|
|
112
|
+
* Bypasses annotation conversion, useful for stroke commands from backend.
|
|
113
|
+
*
|
|
114
|
+
* @param {Array} strokes - Array of stroke command objects
|
|
115
|
+
*/
|
|
116
|
+
setStrokes(e) {
|
|
117
|
+
this.strokeRenderer.setStrokes(e);
|
|
118
|
+
const t = this.timelineSync.getCurrentTime();
|
|
119
|
+
this.strokeRenderer.render(t);
|
|
130
120
|
}
|
|
131
121
|
/**
|
|
132
122
|
* Update timeline position for animation
|
|
133
123
|
*
|
|
134
124
|
* @param {number} timestamp - Current timeline position in seconds
|
|
135
|
-
* @returns {void}
|
|
136
125
|
*/
|
|
137
126
|
setTime(e) {
|
|
138
127
|
if (typeof e != "number") {
|
|
@@ -141,17 +130,55 @@ class c {
|
|
|
141
130
|
}
|
|
142
131
|
this.timelineSync.setTime(e);
|
|
143
132
|
}
|
|
133
|
+
/**
|
|
134
|
+
* Start continuous timeline synchronization using requestAnimationFrame
|
|
135
|
+
*
|
|
136
|
+
* Polls the provided function at ~60fps for smooth animation.
|
|
137
|
+
* Use this for audio/video synchronization instead of setTime().
|
|
138
|
+
*
|
|
139
|
+
* @param {Function} getTimeFunction - Function that returns current time in seconds
|
|
140
|
+
* @example
|
|
141
|
+
* const audio = document.getElementById('audio');
|
|
142
|
+
* renderer.startContinuousSync(() => audio.currentTime);
|
|
143
|
+
*/
|
|
144
|
+
startContinuousSync(e) {
|
|
145
|
+
this.timelineSync.startContinuousSync(e);
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Stop continuous timeline synchronization
|
|
149
|
+
*
|
|
150
|
+
* Call this when audio/video stops or component unmounts.
|
|
151
|
+
*/
|
|
152
|
+
stopContinuousSync() {
|
|
153
|
+
this.timelineSync.stopContinuousSync();
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Check if continuous sync is currently active
|
|
157
|
+
*
|
|
158
|
+
* @returns {boolean} True if continuous sync is running
|
|
159
|
+
*/
|
|
160
|
+
isContinuousSyncActive() {
|
|
161
|
+
return this.timelineSync.isRunning;
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Update stroke rendering configuration at runtime
|
|
165
|
+
*
|
|
166
|
+
* Merges new config with existing and re-renders annotations.
|
|
167
|
+
* Used for live preview of pen style changes.
|
|
168
|
+
*
|
|
169
|
+
* @param {Object} newConfig - New stroke configuration to merge
|
|
170
|
+
*/
|
|
171
|
+
updateStrokeConfig(e) {
|
|
172
|
+
if (!e || typeof e != "object")
|
|
173
|
+
return;
|
|
174
|
+
this.strokeRenderer.config = o(this.strokeRenderer.config, e), this.strokeRenderer.setAnnotations(this.annotations, this.currentPage);
|
|
175
|
+
const t = this.timelineSync.getCurrentTime();
|
|
176
|
+
this.strokeRenderer.render(t);
|
|
177
|
+
}
|
|
144
178
|
/**
|
|
145
179
|
* Get current engine state snapshot
|
|
146
180
|
*
|
|
147
181
|
* @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
182
|
*/
|
|
156
183
|
getState() {
|
|
157
184
|
return {
|
|
@@ -166,17 +193,12 @@ class c {
|
|
|
166
193
|
}
|
|
167
194
|
/**
|
|
168
195
|
* 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
196
|
*/
|
|
175
197
|
destroy() {
|
|
176
|
-
this.pdfRenderer && this.pdfRenderer.destroy(), this.
|
|
198
|
+
this.pdfRenderer && this.pdfRenderer.destroy(), this.strokeRenderer && this.strokeRenderer.destroy(), this.timelineSync && this.timelineSync.destroy(), this.strokeCanvas && this.strokeCanvas.parentNode && this.strokeCanvas.parentNode.removeChild(this.strokeCanvas), this.pdfRenderer = null, this.strokeRenderer = null, this.timelineSync = null, this.strokeCanvas = 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
199
|
}
|
|
178
200
|
}
|
|
179
201
|
export {
|
|
180
|
-
|
|
202
|
+
d as AnnotationRenderer
|
|
181
203
|
};
|
|
182
204
|
//# sourceMappingURL=index2.js.map
|
package/dist/index2.js.map
CHANGED
|
@@ -1 +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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"}
|
|
1
|
+
{"version":3,"file":"index2.js","sources":["../src/core/AnnotationRenderer.js"],"sourcesContent":["/**\n * AnnotationRenderer - Main facade for PDF annotation rendering engine\n *\n * Orchestrates PDFRenderer, StrokeRenderer, and TimelineSync subsystems.\n * 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 { TimelineSync } from './TimelineSync.js';\nimport { StrokeRenderer } from '../renderer/StrokeRenderer.js';\nimport { deepMerge } from '../pen/effects.js';\n\n/**\n * AnnotationRenderer class\n *\n * Main engine that coordinates PDF rendering, stroke-based annotation rendering,\n * and timeline synchronization. Provides simple imperative API for consumers.\n *\n * @class\n * @example\n * const renderer = new AnnotationRenderer({\n * container: document.getElementById('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.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 annotation canvas\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 * @param {Object} [config.strokeConfig] - StrokeRenderer configuration\n * @throws {Error} If config is invalid or required elements are missing\n */\n constructor(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 this.config = config;\n this.canvasElement = config.canvasElement;\n this.container = config.container;\n\n // Initialize PDFRenderer\n this.pdfRenderer = new PDFRenderer();\n\n // Create stroke canvas and StrokeRenderer\n this.strokeCanvas = this._createStrokeCanvas();\n this.strokeRenderer = new StrokeRenderer(this.strokeCanvas, config.strokeConfig || {});\n\n // Initialize TimelineSync\n this.timelineSync = new TimelineSync();\n\n // State\n this.currentPage = config.initialPage || 1;\n this.currentScale = config.initialScale || 1.0;\n this.annotations = config.annotations || [];\n this.pageCount = 0;\n this.currentViewport = null;\n this.pdfUrl = null;\n\n // Wire up timeline to render\n this.timelineSync.subscribe((time) => {\n this.strokeRenderer.render(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 * Create stroke canvas overlay\n *\n * @private\n * @returns {HTMLCanvasElement} Stroke canvas element\n */\n _createStrokeCanvas() {\n const canvas = document.createElement('canvas');\n canvas.className = 'stroke-canvas';\n canvas.style.position = 'absolute';\n canvas.style.top = '0';\n canvas.style.left = '0';\n canvas.style.pointerEvents = 'none';\n canvas.style.zIndex = '10';\n this.container.appendChild(canvas);\n return canvas;\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 */\n async loadPDF(url) {\n try {\n if (!url || typeof url !== 'string') {\n return { success: false, error: 'Invalid PDF URL provided' };\n }\n\n const result = await this.pdfRenderer.loadDocument(url);\n\n if (result.success) {\n this.pdfUrl = url;\n this.pageCount = result.pageCount;\n return { success: true, pageCount: result.pageCount };\n }\n\n return result;\n } catch (err) {\n console.error('AnnotationRenderer.loadPDF: Error loading PDF:', err);\n return { success: false, error: `Failed to load PDF: ${err.message}` };\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 */\n async setPage(pageNum) {\n try {\n if (typeof pageNum !== 'number' || pageNum < 1) {\n return { success: false, error: 'Invalid page number' };\n }\n\n if (this.pageCount > 0 && pageNum > this.pageCount) {\n return { success: false, error: `Page ${pageNum} exceeds document page count (${this.pageCount})` };\n }\n\n this.pdfRenderer.cancelRender();\n\n const result = await this.pdfRenderer.renderPage(\n pageNum,\n this.canvasElement,\n this.currentScale\n );\n\n if (result.success) {\n this.currentPage = pageNum;\n this.currentViewport = result.viewport;\n\n // Update StrokeRenderer viewport\n this.strokeRenderer.setViewport(result.viewport.width, result.viewport.height);\n\n // Re-set annotations for new page\n this.strokeRenderer.setAnnotations(this.annotations, pageNum);\n\n // Render at current time\n const currentTime = this.timelineSync.getCurrentTime();\n this.strokeRenderer.render(currentTime);\n\n return { success: true, viewport: result.viewport };\n }\n\n return result;\n } catch (err) {\n console.error('AnnotationRenderer.setPage: Error rendering page:', err);\n return { success: false, error: `Failed to render page: ${err.message}` };\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 */\n async setScale(scale) {\n try {\n if (typeof scale !== 'number' || scale <= 0) {\n return { success: false, error: 'Invalid scale value (must be positive number)' };\n }\n\n this.currentScale = scale;\n return await this.setPage(this.currentPage);\n } catch (err) {\n console.error('AnnotationRenderer.setScale: Error changing scale:', err);\n return { success: false, error: `Failed to change scale: ${err.message}` };\n }\n }\n\n /**\n * Update annotation data for rendering\n *\n * @param {Array} annotations - Complete annotation array (all pages, all types)\n */\n setAnnotations(annotations) {\n if (!Array.isArray(annotations)) {\n console.warn('AnnotationRenderer.setAnnotations: annotations must be an array');\n annotations = [];\n }\n\n this.annotations = annotations;\n this.strokeRenderer.setAnnotations(annotations, this.currentPage);\n\n // Render at current time\n const currentTime = this.timelineSync.getCurrentTime();\n this.strokeRenderer.render(currentTime);\n }\n\n /**\n * Set pre-converted strokes directly\n *\n * Bypasses annotation conversion, useful for stroke commands from backend.\n *\n * @param {Array} strokes - Array of stroke command objects\n */\n setStrokes(strokes) {\n this.strokeRenderer.setStrokes(strokes);\n\n const currentTime = this.timelineSync.getCurrentTime();\n this.strokeRenderer.render(currentTime);\n }\n\n /**\n * Update timeline position for animation\n *\n * @param {number} timestamp - Current timeline position in seconds\n */\n setTime(timestamp) {\n if (typeof timestamp !== 'number') {\n console.warn('AnnotationRenderer.setTime: timestamp must be a number');\n return;\n }\n\n this.timelineSync.setTime(timestamp);\n }\n\n /**\n * Start continuous timeline synchronization using requestAnimationFrame\n *\n * Polls the provided function at ~60fps for smooth animation.\n * Use this for audio/video synchronization instead of setTime().\n *\n * @param {Function} getTimeFunction - Function that returns current time in seconds\n * @example\n * const audio = document.getElementById('audio');\n * renderer.startContinuousSync(() => audio.currentTime);\n */\n startContinuousSync(getTimeFunction) {\n this.timelineSync.startContinuousSync(getTimeFunction);\n }\n\n /**\n * Stop continuous timeline synchronization\n *\n * Call this when audio/video stops or component unmounts.\n */\n stopContinuousSync() {\n this.timelineSync.stopContinuousSync();\n }\n\n /**\n * Check if continuous sync is currently active\n *\n * @returns {boolean} True if continuous sync is running\n */\n isContinuousSyncActive() {\n return this.timelineSync.isRunning;\n }\n\n /**\n * Update stroke rendering configuration at runtime\n *\n * Merges new config with existing and re-renders annotations.\n * Used for live preview of pen style changes.\n *\n * @param {Object} newConfig - New stroke configuration to merge\n */\n updateStrokeConfig(newConfig) {\n if (!newConfig || typeof newConfig !== 'object') {\n return;\n }\n\n // Merge new config into existing\n this.strokeRenderer.config = deepMerge(this.strokeRenderer.config, newConfig);\n\n // Re-convert annotations with new style and render\n this.strokeRenderer.setAnnotations(this.annotations, this.currentPage);\n const currentTime = this.timelineSync.getCurrentTime();\n this.strokeRenderer.render(currentTime);\n }\n\n /**\n * Get current engine state snapshot\n *\n * @returns {Object} Current state\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 destroy() {\n if (this.pdfRenderer) {\n this.pdfRenderer.destroy();\n }\n\n if (this.strokeRenderer) {\n this.strokeRenderer.destroy();\n }\n\n if (this.timelineSync) {\n this.timelineSync.destroy();\n }\n\n if (this.strokeCanvas && this.strokeCanvas.parentNode) {\n this.strokeCanvas.parentNode.removeChild(this.strokeCanvas);\n }\n\n this.pdfRenderer = null;\n this.strokeRenderer = null;\n this.timelineSync = null;\n this.strokeCanvas = 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","StrokeRenderer","TimelineSync","time","err","canvas","url","result","pageNum","currentTime","scale","annotations","strokes","timestamp","getTimeFunction","newConfig","deepMerge"],"mappings":"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"}
|
package/dist/index20.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const a=require("./index24.cjs");function h(e){if(!e.quads||!Array.isArray(e.quads)||e.quads.length===0)throw new Error("Highlight annotation requires at least one quad");if(!e.page||typeof e.page!="number"||e.page<1)throw new Error("Highlight annotation requires a valid page number (>= 1)");if(!e.sentence_ref||typeof e.sentence_ref!="string")throw new Error("Highlight annotation requires a sentence_ref for timing");e.quads.forEach((r,o)=>{if(typeof r!="object"||r===null||Array.isArray(r))throw new Error(`Quad at index ${o} must be an object with {x, y, w, h} properties`);const i=["x","y","w","h"];for(const t of i){if(typeof r[t]!="number")throw new Error(`Quad at index ${o} is missing required property '${t}' or it's not a number`);if(r[t]<0||r[t]>1)throw new Error(`Quad property '${t}' at index ${o} must be between 0 and 1 (got ${r[t]})`)}});const n=e.color||"rgba(255, 255, 0, 0.3)";return{id:a.generateId("highlight"),type:"highlight",mode:"quads",page:e.page,quads:e.quads,style:{color:n},sentence_ref:e.sentence_ref}}exports.createHighlight=h;
|
|
2
2
|
//# sourceMappingURL=index20.cjs.map
|
package/dist/index20.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index20.cjs","sources":["../src/ai-tools/creators/
|
|
1
|
+
{"version":3,"file":"index20.cjs","sources":["../src/ai-tools/creators/createHighlight.js"],"sourcesContent":["/**\n * Highlight Annotation Creator\n *\n * Converts AI-generated tool call arguments into valid highlight annotation objects\n * compatible with web-annotation-renderer library format.\n *\n * @module ai-tools/creators/createHighlight\n */\n\nimport { generateId } from '../../utils/idGenerator.js';\n\n/**\n * Create a highlight annotation from tool call arguments\n *\n * @param {Object} args - Tool call arguments from AI\n * @param {Array<Object>} args.quads - Rectangle objects with {x, y, w, h} (normalized 0-1)\n * @param {string} [args.color='rgba(255, 255, 0, 0.3)'] - Highlight color in rgba format\n * @param {number} args.page - Page number (1-indexed)\n * @param {string} args.sentence_ref - Sentence reference for timing (e.g., 'S1')\n * @returns {Object} Valid highlight annotation object\n * @example\n * ```javascript\n * const highlight = createHighlight({\n * quads: [{x: 0.1, y: 0.2, w: 0.8, h: 0.05}],\n * color: 'rgba(255, 255, 0, 0.3)',\n * page: 1,\n * sentence_ref: 'S2'\n * });\n * ```\n */\nexport function createHighlight(args) {\n // Validate required fields\n if (!args.quads || !Array.isArray(args.quads) || args.quads.length === 0) {\n throw new Error('Highlight annotation requires at least one quad');\n }\n\n if (!args.page || typeof args.page !== 'number' || args.page < 1) {\n throw new Error('Highlight annotation requires a valid page number (>= 1)');\n }\n\n if (!args.sentence_ref || typeof args.sentence_ref !== 'string') {\n throw new Error('Highlight annotation requires a sentence_ref for timing');\n }\n\n // Validate quad format - each quad must be an object with {x, y, w, h}\n args.quads.forEach((quad, index) => {\n if (typeof quad !== 'object' || quad === null || Array.isArray(quad)) {\n throw new Error(`Quad at index ${index} must be an object with {x, y, w, h} properties`);\n }\n\n const requiredProps = ['x', 'y', 'w', 'h'];\n for (const prop of requiredProps) {\n if (typeof quad[prop] !== 'number') {\n throw new Error(`Quad at index ${index} is missing required property '${prop}' or it's not a number`);\n }\n if (quad[prop] < 0 || quad[prop] > 1) {\n throw new Error(`Quad property '${prop}' at index ${index} must be between 0 and 1 (got ${quad[prop]})`);\n }\n }\n });\n\n // Validate color format (should be rgba)\n const color = args.color || 'rgba(255, 255, 0, 0.3)';\n\n // Create annotation object matching library format\n return {\n id: generateId('highlight'),\n type: 'highlight',\n mode: 'quads', // Required by HighlightLayer\n page: args.page,\n quads: args.quads, // Array of {x, y, w, h} objects\n style: {\n color: color // Color wrapped in style object\n },\n sentence_ref: args.sentence_ref,\n // Note: start/end will be added during timing sync phase\n };\n}\n"],"names":["createHighlight","args","quad","index","requiredProps","prop","color","generateId"],"mappings":"iHA8BO,SAASA,EAAgBC,EAAM,CAEpC,GAAI,CAACA,EAAK,OAAS,CAAC,MAAM,QAAQA,EAAK,KAAK,GAAKA,EAAK,MAAM,SAAW,EACrE,MAAM,IAAI,MAAM,iDAAiD,EAGnE,GAAI,CAACA,EAAK,MAAQ,OAAOA,EAAK,MAAS,UAAYA,EAAK,KAAO,EAC7D,MAAM,IAAI,MAAM,0DAA0D,EAG5E,GAAI,CAACA,EAAK,cAAgB,OAAOA,EAAK,cAAiB,SACrD,MAAM,IAAI,MAAM,yDAAyD,EAI3EA,EAAK,MAAM,QAAQ,CAACC,EAAMC,IAAU,CAClC,GAAI,OAAOD,GAAS,UAAYA,IAAS,MAAQ,MAAM,QAAQA,CAAI,EACjE,MAAM,IAAI,MAAM,iBAAiBC,CAAK,iDAAiD,EAGzF,MAAMC,EAAgB,CAAC,IAAK,IAAK,IAAK,GAAG,EACzC,UAAWC,KAAQD,EAAe,CAChC,GAAI,OAAOF,EAAKG,CAAI,GAAM,SACxB,MAAM,IAAI,MAAM,iBAAiBF,CAAK,kCAAkCE,CAAI,wBAAwB,EAEtG,GAAIH,EAAKG,CAAI,EAAI,GAAKH,EAAKG,CAAI,EAAI,EACjC,MAAM,IAAI,MAAM,kBAAkBA,CAAI,cAAcF,CAAK,iCAAiCD,EAAKG,CAAI,CAAC,GAAG,CAE3G,CACF,CAAC,EAGD,MAAMC,EAAQL,EAAK,OAAS,yBAG5B,MAAO,CACL,GAAIM,EAAAA,WAAW,WAAW,EAC1B,KAAM,YACN,KAAM,QACN,KAAMN,EAAK,KACX,MAAOA,EAAK,MACZ,MAAO,CACL,MAAOK,CACb,EACI,aAAcL,EAAK,YAEvB,CACA"}
|
package/dist/index20.js
CHANGED
|
@@ -1,50 +1,40 @@
|
|
|
1
|
-
import { generateId as
|
|
2
|
-
function
|
|
3
|
-
if (!e.
|
|
4
|
-
throw new Error("
|
|
1
|
+
import { generateId as h } from "./index24.js";
|
|
2
|
+
function p(e) {
|
|
3
|
+
if (!e.quads || !Array.isArray(e.quads) || e.quads.length === 0)
|
|
4
|
+
throw new Error("Highlight annotation requires at least one quad");
|
|
5
5
|
if (!e.page || typeof e.page != "number" || e.page < 1)
|
|
6
|
-
throw new Error("
|
|
6
|
+
throw new Error("Highlight annotation requires a valid page number (>= 1)");
|
|
7
7
|
if (!e.sentence_ref || typeof e.sentence_ref != "string")
|
|
8
|
-
throw new Error("
|
|
9
|
-
|
|
8
|
+
throw new Error("Highlight annotation requires a sentence_ref for timing");
|
|
9
|
+
e.quads.forEach((r, o) => {
|
|
10
10
|
if (typeof r != "object" || r === null || Array.isArray(r))
|
|
11
|
-
throw new Error(`
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
throw new Error(`Point y coordinate at stroke[${o}][${n}] must be between 0 and 1 (got ${t.y})`);
|
|
27
|
-
});
|
|
28
|
-
const s = r.size || 3;
|
|
29
|
-
if (s < 1 || s > 10)
|
|
30
|
-
throw new Error(`Stroke size at index ${o} must be between 1 and 10 pixels (got ${s})`);
|
|
31
|
-
}), {
|
|
32
|
-
id: f("ink"),
|
|
33
|
-
type: "ink",
|
|
11
|
+
throw new Error(`Quad at index ${o} must be an object with {x, y, w, h} properties`);
|
|
12
|
+
const i = ["x", "y", "w", "h"];
|
|
13
|
+
for (const t of i) {
|
|
14
|
+
if (typeof r[t] != "number")
|
|
15
|
+
throw new Error(`Quad at index ${o} is missing required property '${t}' or it's not a number`);
|
|
16
|
+
if (r[t] < 0 || r[t] > 1)
|
|
17
|
+
throw new Error(`Quad property '${t}' at index ${o} must be between 0 and 1 (got ${r[t]})`);
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
const n = e.color || "rgba(255, 255, 0, 0.3)";
|
|
21
|
+
return {
|
|
22
|
+
id: h("highlight"),
|
|
23
|
+
type: "highlight",
|
|
24
|
+
mode: "quads",
|
|
25
|
+
// Required by HighlightLayer
|
|
34
26
|
page: e.page,
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
//
|
|
40
|
-
|
|
41
|
-
// Array of {t, x, y} objects
|
|
42
|
-
})),
|
|
27
|
+
quads: e.quads,
|
|
28
|
+
// Array of {x, y, w, h} objects
|
|
29
|
+
style: {
|
|
30
|
+
color: n
|
|
31
|
+
// Color wrapped in style object
|
|
32
|
+
},
|
|
43
33
|
sentence_ref: e.sentence_ref
|
|
44
34
|
// Note: start/end will be added during timing sync phase
|
|
45
35
|
};
|
|
46
36
|
}
|
|
47
37
|
export {
|
|
48
|
-
|
|
38
|
+
p as createHighlight
|
|
49
39
|
};
|
|
50
40
|
//# sourceMappingURL=index20.js.map
|
package/dist/index20.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index20.js","sources":["../src/ai-tools/creators/
|
|
1
|
+
{"version":3,"file":"index20.js","sources":["../src/ai-tools/creators/createHighlight.js"],"sourcesContent":["/**\n * Highlight Annotation Creator\n *\n * Converts AI-generated tool call arguments into valid highlight annotation objects\n * compatible with web-annotation-renderer library format.\n *\n * @module ai-tools/creators/createHighlight\n */\n\nimport { generateId } from '../../utils/idGenerator.js';\n\n/**\n * Create a highlight annotation from tool call arguments\n *\n * @param {Object} args - Tool call arguments from AI\n * @param {Array<Object>} args.quads - Rectangle objects with {x, y, w, h} (normalized 0-1)\n * @param {string} [args.color='rgba(255, 255, 0, 0.3)'] - Highlight color in rgba format\n * @param {number} args.page - Page number (1-indexed)\n * @param {string} args.sentence_ref - Sentence reference for timing (e.g., 'S1')\n * @returns {Object} Valid highlight annotation object\n * @example\n * ```javascript\n * const highlight = createHighlight({\n * quads: [{x: 0.1, y: 0.2, w: 0.8, h: 0.05}],\n * color: 'rgba(255, 255, 0, 0.3)',\n * page: 1,\n * sentence_ref: 'S2'\n * });\n * ```\n */\nexport function createHighlight(args) {\n // Validate required fields\n if (!args.quads || !Array.isArray(args.quads) || args.quads.length === 0) {\n throw new Error('Highlight annotation requires at least one quad');\n }\n\n if (!args.page || typeof args.page !== 'number' || args.page < 1) {\n throw new Error('Highlight annotation requires a valid page number (>= 1)');\n }\n\n if (!args.sentence_ref || typeof args.sentence_ref !== 'string') {\n throw new Error('Highlight annotation requires a sentence_ref for timing');\n }\n\n // Validate quad format - each quad must be an object with {x, y, w, h}\n args.quads.forEach((quad, index) => {\n if (typeof quad !== 'object' || quad === null || Array.isArray(quad)) {\n throw new Error(`Quad at index ${index} must be an object with {x, y, w, h} properties`);\n }\n\n const requiredProps = ['x', 'y', 'w', 'h'];\n for (const prop of requiredProps) {\n if (typeof quad[prop] !== 'number') {\n throw new Error(`Quad at index ${index} is missing required property '${prop}' or it's not a number`);\n }\n if (quad[prop] < 0 || quad[prop] > 1) {\n throw new Error(`Quad property '${prop}' at index ${index} must be between 0 and 1 (got ${quad[prop]})`);\n }\n }\n });\n\n // Validate color format (should be rgba)\n const color = args.color || 'rgba(255, 255, 0, 0.3)';\n\n // Create annotation object matching library format\n return {\n id: generateId('highlight'),\n type: 'highlight',\n mode: 'quads', // Required by HighlightLayer\n page: args.page,\n quads: args.quads, // Array of {x, y, w, h} objects\n style: {\n color: color // Color wrapped in style object\n },\n sentence_ref: args.sentence_ref,\n // Note: start/end will be added during timing sync phase\n };\n}\n"],"names":["createHighlight","args","quad","index","requiredProps","prop","color","generateId"],"mappings":";AA8BO,SAASA,EAAgBC,GAAM;AAEpC,MAAI,CAACA,EAAK,SAAS,CAAC,MAAM,QAAQA,EAAK,KAAK,KAAKA,EAAK,MAAM,WAAW;AACrE,UAAM,IAAI,MAAM,iDAAiD;AAGnE,MAAI,CAACA,EAAK,QAAQ,OAAOA,EAAK,QAAS,YAAYA,EAAK,OAAO;AAC7D,UAAM,IAAI,MAAM,0DAA0D;AAG5E,MAAI,CAACA,EAAK,gBAAgB,OAAOA,EAAK,gBAAiB;AACrD,UAAM,IAAI,MAAM,yDAAyD;AAI3E,EAAAA,EAAK,MAAM,QAAQ,CAACC,GAAMC,MAAU;AAClC,QAAI,OAAOD,KAAS,YAAYA,MAAS,QAAQ,MAAM,QAAQA,CAAI;AACjE,YAAM,IAAI,MAAM,iBAAiBC,CAAK,iDAAiD;AAGzF,UAAMC,IAAgB,CAAC,KAAK,KAAK,KAAK,GAAG;AACzC,eAAWC,KAAQD,GAAe;AAChC,UAAI,OAAOF,EAAKG,CAAI,KAAM;AACxB,cAAM,IAAI,MAAM,iBAAiBF,CAAK,kCAAkCE,CAAI,wBAAwB;AAEtG,UAAIH,EAAKG,CAAI,IAAI,KAAKH,EAAKG,CAAI,IAAI;AACjC,cAAM,IAAI,MAAM,kBAAkBA,CAAI,cAAcF,CAAK,iCAAiCD,EAAKG,CAAI,CAAC,GAAG;AAAA,IAE3G;AAAA,EACF,CAAC;AAGD,QAAMC,IAAQL,EAAK,SAAS;AAG5B,SAAO;AAAA,IACL,IAAIM,EAAW,WAAW;AAAA,IAC1B,MAAM;AAAA,IACN,MAAM;AAAA;AAAA,IACN,MAAMN,EAAK;AAAA,IACX,OAAOA,EAAK;AAAA;AAAA,IACZ,OAAO;AAAA,MACL,OAAOK;AAAA;AAAA,IACb;AAAA,IACI,cAAcL,EAAK;AAAA;AAAA,EAEvB;AACA;"}
|
package/dist/index21.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const o=require("./index24.cjs");function r(e){if(!e.content||typeof e.content!="string"||e.content.trim().length===0)throw new Error("Text annotation requires non-empty content");if(typeof e.x!="number"||e.x<0||e.x>1)throw new Error("Text annotation x position must be between 0 and 1");if(typeof e.y!="number"||e.y<0||e.y>1)throw new Error("Text annotation y position must be between 0 and 1");if(typeof e.w!="number"||e.w<0||e.w>1)throw new Error("Text annotation width (w) must be between 0 and 1");if(typeof e.h!="number"||e.h<0||e.h>1)throw new Error("Text annotation height (h) must be between 0 and 1");if(!e.page||typeof e.page!="number"||e.page<1)throw new Error("Text annotation requires a valid page number (>= 1)");if(!e.sentence_ref||typeof e.sentence_ref!="string")throw new Error("Text annotation requires a sentence_ref for timing");const t=e.textColor||"#1f2937",n=e.bgColor||"transparent";return{id:o.generateId("text"),type:"text",page:e.page,content:e.content.trim(),x:e.x,y:e.y,w:e.w,h:e.h,style:{bg:n,color:t},sentence_ref:e.sentence_ref}}exports.createText=r;
|
|
2
2
|
//# sourceMappingURL=index21.cjs.map
|
package/dist/index21.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index21.cjs","sources":["../src/
|
|
1
|
+
{"version":3,"file":"index21.cjs","sources":["../src/ai-tools/creators/createText.js"],"sourcesContent":["/**\n * Text Annotation Creator\n *\n * Converts AI-generated tool call arguments into valid text annotation objects\n * compatible with web-annotation-renderer library format.\n *\n * @module ai-tools/creators/createText\n */\n\nimport { generateId } from '../../utils/idGenerator.js';\n\n/**\n * Create a text annotation from tool call arguments\n *\n * @param {Object} args - Tool call arguments from AI\n * @param {string} args.content - Text content\n * @param {number} args.x - Horizontal position (0-1)\n * @param {number} args.y - Vertical position (0-1)\n * @param {number} args.w - Width (0-1)\n * @param {number} args.h - Height (0-1)\n * @param {number} args.page - Page number (1-indexed)\n * @param {string} [args.textColor='#1f2937'] - Text color in hex format\n * @param {string} [args.bgColor='transparent'] - Background color (transparent by default, or rgba format)\n * @param {string} args.sentence_ref - Sentence reference for timing (e.g., 'S1')\n * @returns {Object} Valid text annotation object\n * @example\n * ```javascript\n * const textNote = createText({\n * content: 'This is important',\n * x: 0.1,\n * y: 0.5,\n * w: 0.3,\n * h: 0.1,\n * page: 1,\n * textColor: '#000000',\n * bgColor: 'transparent', // or use rgba format like 'rgba(255, 255, 255, 0.9)'\n * sentence_ref: 'S3'\n * });\n * ```\n */\nexport function createText(args) {\n // Validate required fields\n if (!args.content || typeof args.content !== 'string' || args.content.trim().length === 0) {\n throw new Error('Text annotation requires non-empty content');\n }\n\n if (typeof args.x !== 'number' || args.x < 0 || args.x > 1) {\n throw new Error('Text annotation x position must be between 0 and 1');\n }\n\n if (typeof args.y !== 'number' || args.y < 0 || args.y > 1) {\n throw new Error('Text annotation y position must be between 0 and 1');\n }\n\n if (typeof args.w !== 'number' || args.w < 0 || args.w > 1) {\n throw new Error('Text annotation width (w) must be between 0 and 1');\n }\n\n if (typeof args.h !== 'number' || args.h < 0 || args.h > 1) {\n throw new Error('Text annotation height (h) must be between 0 and 1');\n }\n\n if (!args.page || typeof args.page !== 'number' || args.page < 1) {\n throw new Error('Text annotation requires a valid page number (>= 1)');\n }\n\n if (!args.sentence_ref || typeof args.sentence_ref !== 'string') {\n throw new Error('Text annotation requires a sentence_ref for timing');\n }\n\n // Get colors with defaults (transparent background for better visibility)\n const textColor = args.textColor || '#1f2937';\n const bgColor = args.bgColor || 'transparent';\n\n // Create annotation object matching library format\n return {\n id: generateId('text'),\n type: 'text', // Type name is 'text', not 'text_annotation'\n page: args.page,\n content: args.content.trim(),\n x: args.x, // Direct properties, not in position object\n y: args.y,\n w: args.w,\n h: args.h,\n style: { // Colors wrapped in style object\n bg: bgColor,\n color: textColor\n },\n sentence_ref: args.sentence_ref,\n // Note: start/end will be added during timing sync phase\n };\n}\n"],"names":["createText","args","textColor","bgColor","generateId"],"mappings":"iHAwCO,SAASA,EAAWC,EAAM,CAE/B,GAAI,CAACA,EAAK,SAAW,OAAOA,EAAK,SAAY,UAAYA,EAAK,QAAQ,OAAO,SAAW,EACtF,MAAM,IAAI,MAAM,4CAA4C,EAG9D,GAAI,OAAOA,EAAK,GAAM,UAAYA,EAAK,EAAI,GAAKA,EAAK,EAAI,EACvD,MAAM,IAAI,MAAM,oDAAoD,EAGtE,GAAI,OAAOA,EAAK,GAAM,UAAYA,EAAK,EAAI,GAAKA,EAAK,EAAI,EACvD,MAAM,IAAI,MAAM,oDAAoD,EAGtE,GAAI,OAAOA,EAAK,GAAM,UAAYA,EAAK,EAAI,GAAKA,EAAK,EAAI,EACvD,MAAM,IAAI,MAAM,mDAAmD,EAGrE,GAAI,OAAOA,EAAK,GAAM,UAAYA,EAAK,EAAI,GAAKA,EAAK,EAAI,EACvD,MAAM,IAAI,MAAM,oDAAoD,EAGtE,GAAI,CAACA,EAAK,MAAQ,OAAOA,EAAK,MAAS,UAAYA,EAAK,KAAO,EAC7D,MAAM,IAAI,MAAM,qDAAqD,EAGvE,GAAI,CAACA,EAAK,cAAgB,OAAOA,EAAK,cAAiB,SACrD,MAAM,IAAI,MAAM,oDAAoD,EAItE,MAAMC,EAAYD,EAAK,WAAa,UAC9BE,EAAUF,EAAK,SAAW,cAGhC,MAAO,CACL,GAAIG,EAAAA,WAAW,MAAM,EACrB,KAAM,OACN,KAAMH,EAAK,KACX,QAASA,EAAK,QAAQ,KAAI,EAC1B,EAAGA,EAAK,EACR,EAAGA,EAAK,EACR,EAAGA,EAAK,EACR,EAAGA,EAAK,EACR,MAAO,CACL,GAAIE,EACJ,MAAOD,CACb,EACI,aAAcD,EAAK,YAEvB,CACA"}
|