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.
Files changed (64) hide show
  1. package/CHANGELOG.md +34 -0
  2. package/LICENSE +21 -0
  3. package/README.md +156 -0
  4. package/dist/index.cjs +2 -0
  5. package/dist/index.cjs.map +1 -0
  6. package/dist/index.js +32 -0
  7. package/dist/index.js.map +1 -0
  8. package/dist/index10.cjs +2 -0
  9. package/dist/index10.cjs.map +1 -0
  10. package/dist/index10.js +23 -0
  11. package/dist/index10.js.map +1 -0
  12. package/dist/index11.cjs +2 -0
  13. package/dist/index11.cjs.map +1 -0
  14. package/dist/index11.js +23 -0
  15. package/dist/index11.js.map +1 -0
  16. package/dist/index12.cjs +2 -0
  17. package/dist/index12.cjs.map +1 -0
  18. package/dist/index12.js +203 -0
  19. package/dist/index12.js.map +1 -0
  20. package/dist/index13.cjs +2 -0
  21. package/dist/index13.cjs.map +1 -0
  22. package/dist/index13.js +18 -0
  23. package/dist/index13.js.map +1 -0
  24. package/dist/index14.cjs +2 -0
  25. package/dist/index14.cjs.map +1 -0
  26. package/dist/index14.js +116 -0
  27. package/dist/index14.js.map +1 -0
  28. package/dist/index15.cjs +2 -0
  29. package/dist/index15.cjs.map +1 -0
  30. package/dist/index15.js +35 -0
  31. package/dist/index15.js.map +1 -0
  32. package/dist/index2.cjs +2 -0
  33. package/dist/index2.cjs.map +1 -0
  34. package/dist/index2.js +182 -0
  35. package/dist/index2.js.map +1 -0
  36. package/dist/index3.cjs +2 -0
  37. package/dist/index3.cjs.map +1 -0
  38. package/dist/index3.js +121 -0
  39. package/dist/index3.js.map +1 -0
  40. package/dist/index4.cjs +2 -0
  41. package/dist/index4.cjs.map +1 -0
  42. package/dist/index4.js +104 -0
  43. package/dist/index4.js.map +1 -0
  44. package/dist/index5.cjs +2 -0
  45. package/dist/index5.cjs.map +1 -0
  46. package/dist/index5.js +105 -0
  47. package/dist/index5.js.map +1 -0
  48. package/dist/index6.cjs +2 -0
  49. package/dist/index6.cjs.map +1 -0
  50. package/dist/index6.js +119 -0
  51. package/dist/index6.js.map +1 -0
  52. package/dist/index7.cjs +2 -0
  53. package/dist/index7.cjs.map +1 -0
  54. package/dist/index7.js +100 -0
  55. package/dist/index7.js.map +1 -0
  56. package/dist/index8.cjs +2 -0
  57. package/dist/index8.cjs.map +1 -0
  58. package/dist/index8.js +109 -0
  59. package/dist/index8.js.map +1 -0
  60. package/dist/index9.cjs +2 -0
  61. package/dist/index9.cjs.map +1 -0
  62. package/dist/index9.js +112 -0
  63. package/dist/index9.js.map +1 -0
  64. package/package.json +84 -0
package/dist/index5.js ADDED
@@ -0,0 +1,105 @@
1
+ class e {
2
+ constructor() {
3
+ this.currentTime = 0, this.subscribers = /* @__PURE__ */ new Set(), this.animationFrameId = null, this.isRunning = !1;
4
+ }
5
+ /**
6
+ * Set timeline position and notify subscribers if changed
7
+ *
8
+ * @param {number} timestamp - Timeline position in seconds
9
+ * @returns {void}
10
+ */
11
+ setTime(n) {
12
+ n !== this.currentTime && (this.currentTime = n, this.notifySubscribers());
13
+ }
14
+ /**
15
+ * Get current timeline position
16
+ *
17
+ * @returns {number} Current timeline position in seconds
18
+ */
19
+ getCurrentTime() {
20
+ return this.currentTime;
21
+ }
22
+ /**
23
+ * Subscribe to timeline updates
24
+ *
25
+ * @param {Function} callback - Function to call on timeline updates
26
+ * @returns {Function} Unsubscribe function
27
+ * @throws {Error} If callback is not a function
28
+ */
29
+ subscribe(n) {
30
+ if (typeof n != "function")
31
+ throw new Error("TimelineSync.subscribe: callback must be a function");
32
+ return this.subscribers.add(n), () => this.unsubscribe(n);
33
+ }
34
+ /**
35
+ * Unsubscribe from timeline updates
36
+ *
37
+ * @param {Function} callback - Callback function to remove
38
+ * @returns {void}
39
+ */
40
+ unsubscribe(n) {
41
+ this.subscribers.delete(n);
42
+ }
43
+ /**
44
+ * Start continuous timeline synchronization
45
+ *
46
+ * @param {Function} getTimeFunction - Function that returns current time
47
+ * @returns {void}
48
+ * @throws {Error} If getTimeFunction is not a function
49
+ */
50
+ startContinuousSync(n) {
51
+ if (typeof n != "function")
52
+ throw new Error("TimelineSync.startContinuousSync: getTimeFunction must be a function");
53
+ if (this.isRunning) {
54
+ console.warn("TimelineSync: Continuous sync already running");
55
+ return;
56
+ }
57
+ this.isRunning = !0;
58
+ const i = () => {
59
+ if (this.isRunning) {
60
+ try {
61
+ const r = n();
62
+ this.setTime(r);
63
+ } catch (r) {
64
+ console.error("TimelineSync: Error in continuous sync:", r);
65
+ }
66
+ this.animationFrameId = requestAnimationFrame(i);
67
+ }
68
+ };
69
+ i();
70
+ }
71
+ /**
72
+ * Stop continuous timeline synchronization
73
+ *
74
+ * @returns {void}
75
+ */
76
+ stopContinuousSync() {
77
+ this.isRunning = !1, this.animationFrameId !== null && (cancelAnimationFrame(this.animationFrameId), this.animationFrameId = null);
78
+ }
79
+ /**
80
+ * Clean up resources and release references
81
+ *
82
+ * @returns {void}
83
+ */
84
+ destroy() {
85
+ this.stopContinuousSync(), this.subscribers.clear(), this.currentTime = 0;
86
+ }
87
+ /**
88
+ * Notify all subscribers of current time
89
+ *
90
+ * @private
91
+ * @returns {void}
92
+ */
93
+ notifySubscribers() {
94
+ for (const n of this.subscribers)
95
+ try {
96
+ n(this.currentTime);
97
+ } catch (i) {
98
+ console.error("TimelineSync: Subscriber callback error:", i);
99
+ }
100
+ }
101
+ }
102
+ export {
103
+ e as TimelineSync
104
+ };
105
+ //# sourceMappingURL=index5.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index5.js","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":"AA4BO,MAAMA,EAAa;AAAA,EACxB,cAAc;AAKZ,SAAK,cAAc,GAMnB,KAAK,cAAc,oBAAI,IAAG,GAM1B,KAAK,mBAAmB,MAMxB,KAAK,YAAY;AAAA,EACnB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,QAAQC,GAAW;AACjB,IAAIA,MAAc,KAAK,gBAIvB,KAAK,cAAcA,GACnB,KAAK,kBAAiB;AAAA,EACxB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,iBAAiB;AACf,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,UAAUC,GAAU;AAClB,QAAI,OAAOA,KAAa;AACtB,YAAM,IAAI,MAAM,qDAAqD;AAGvE,gBAAK,YAAY,IAAIA,CAAQ,GAEtB,MAAM,KAAK,YAAYA,CAAQ;AAAA,EACxC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,YAAYA,GAAU;AACpB,SAAK,YAAY,OAAOA,CAAQ;AAAA,EAClC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,oBAAoBC,GAAiB;AACnC,QAAI,OAAOA,KAAoB;AAC7B,YAAM,IAAI,MAAM,sEAAsE;AAGxF,QAAI,KAAK,WAAW;AAClB,cAAQ,KAAK,+CAA+C;AAC5D;AAAA,IACF;AAEA,SAAK,YAAY;AAEjB,UAAMC,IAAW,MAAM;AACrB,UAAK,KAAK,WAIV;AAAA,YAAI;AACF,gBAAMC,IAAUF,EAAe;AAC/B,eAAK,QAAQE,CAAO;AAAA,QACtB,SAASC,GAAK;AACZ,kBAAQ,MAAM,2CAA2CA,CAAG;AAAA,QAC9D;AAEA,aAAK,mBAAmB,sBAAsBF,CAAQ;AAAA;AAAA,IACxD;AAEA,IAAAA,EAAQ;AAAA,EACV;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,qBAAqB;AACnB,SAAK,YAAY,IAEb,KAAK,qBAAqB,SAC5B,qBAAqB,KAAK,gBAAgB,GAC1C,KAAK,mBAAmB;AAAA,EAE5B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,UAAU;AACR,SAAK,mBAAkB,GACvB,KAAK,YAAY,MAAK,GACtB,KAAK,cAAc;AAAA,EACrB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,oBAAoB;AAClB,eAAWF,KAAY,KAAK;AAC1B,UAAI;AACF,QAAAA,EAAS,KAAK,WAAW;AAAA,MAC3B,SAASI,GAAK;AACZ,gBAAQ,MAAM,4CAA4CA,CAAG;AAAA,MAC/D;AAAA,EAEJ;AACF;"}
@@ -0,0 +1,2 @@
1
+ "use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});class t{constructor(e,r){if(this._validateContainer(e),this._validateViewport(r),this.container=e,this.viewport={...r},this.annotations=[],this.currentTime=0,this.isDestroyed=!1,new.target===t)throw new Error("BaseLayer is an abstract class and cannot be instantiated directly. Extend it with a concrete implementation.")}setAnnotations(e){this._checkDestroyed("setAnnotations"),this.annotations=e||[]}setViewport(e){this._checkDestroyed("setViewport"),this._validateViewport(e),this.viewport={...e}}updateTime(e){this._checkDestroyed("updateTime"),this.currentTime=e}destroy(){this.isDestroyed||(this.annotations=null,this.viewport=null,this.container=null,this.isDestroyed=!0)}render(){throw new Error("render() must be implemented by subclass")}update(){throw new Error("update() must be implemented by subclass")}_validateContainer(e){if(!e||!(e instanceof HTMLElement))throw new Error("BaseLayer: container must be a valid HTMLElement")}_validateViewport(e){if(!e||typeof e!="object")throw new Error("BaseLayer: viewport must be an object");if(typeof e.width!="number"||e.width<=0)throw new Error("BaseLayer: viewport.width must be a positive number");if(typeof e.height!="number"||e.height<=0)throw new Error("BaseLayer: viewport.height must be a positive number");if(typeof e.scale!="number"||e.scale<=0)throw new Error("BaseLayer: viewport.scale must be a positive number")}_checkDestroyed(e){if(this.isDestroyed)throw new Error(`BaseLayer: Cannot call ${e}() on destroyed layer`)}}exports.default=t;
2
+ //# sourceMappingURL=index6.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index6.cjs","sources":["../src/layers/BaseLayer.js"],"sourcesContent":["/**\n * BaseLayer - Abstract base class for annotation layers\n *\n * Provides common interface and lifecycle management for all annotation layer types.\n * Subclasses must implement render() and update() abstract methods.\n *\n * @abstract\n */\nclass BaseLayer {\n /**\n * Creates a new BaseLayer instance\n *\n * @param {HTMLElement} container - Parent DOM element for layer content\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 - PDF scale/zoom level\n * @throws {Error} If container is not a valid HTMLElement\n * @throws {Error} If viewport is missing required properties\n * @throws {Error} If instantiated directly (abstract class)\n */\n constructor(container, viewport) {\n // Validate parameters\n this._validateContainer(container);\n this._validateViewport(viewport);\n\n // Initialize core properties\n this.container = container;\n this.viewport = { ...viewport };\n this.annotations = [];\n this.currentTime = 0;\n this.isDestroyed = false;\n\n // Prevent direct instantiation\n if (new.target === BaseLayer) {\n throw new Error('BaseLayer is an abstract class and cannot be instantiated directly. Extend it with a concrete implementation.');\n }\n }\n\n /**\n * Sets the annotation data for this layer\n *\n * @param {Array} annotations - Array of annotation objects\n * @throws {Error} If called after layer is destroyed\n */\n setAnnotations(annotations) {\n this._checkDestroyed('setAnnotations');\n this.annotations = annotations || [];\n }\n\n /**\n * Updates the viewport dimensions\n *\n * @param {Object} viewport - New 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 - PDF scale/zoom level\n * @throws {Error} If viewport is missing required properties\n * @throws {Error} If called after layer is destroyed\n */\n setViewport(viewport) {\n this._checkDestroyed('setViewport');\n this._validateViewport(viewport);\n this.viewport = { ...viewport };\n }\n\n /**\n * Updates the current timeline position\n *\n * @param {number} nowSec - Current timeline position in seconds\n * @throws {Error} If called after layer is destroyed\n */\n updateTime(nowSec) {\n this._checkDestroyed('updateTime');\n this.currentTime = nowSec;\n }\n\n /**\n * Destroys the layer and releases resources\n *\n * Safe to call multiple times (idempotent).\n * Subclasses must call super.destroy() after their own cleanup.\n */\n destroy() {\n if (this.isDestroyed) {\n return;\n }\n\n this.annotations = null;\n this.viewport = null;\n this.container = null;\n this.isDestroyed = true;\n }\n\n /**\n * Renders the layer content\n *\n * @abstract\n * @throws {Error} If not implemented by subclass\n */\n render() {\n throw new Error('render() must be implemented by subclass');\n }\n\n /**\n * Updates the visual state of the layer\n *\n * @abstract\n * @throws {Error} If not implemented by subclass\n */\n update() {\n throw new Error('update() must be implemented by subclass');\n }\n\n /**\n * Validates that container is a valid HTMLElement\n *\n * @private\n * @param {*} container - Value to validate\n * @throws {Error} If container is not a valid HTMLElement\n */\n _validateContainer(container) {\n if (!container || !(container instanceof HTMLElement)) {\n throw new Error('BaseLayer: container must be a valid HTMLElement');\n }\n }\n\n /**\n * Validates that viewport has required properties\n *\n * @private\n * @param {*} viewport - Value to validate\n * @throws {Error} If viewport is missing required properties\n */\n _validateViewport(viewport) {\n if (!viewport || typeof viewport !== 'object') {\n throw new Error('BaseLayer: viewport must be an object');\n }\n\n if (typeof viewport.width !== 'number' || viewport.width <= 0) {\n throw new Error('BaseLayer: viewport.width must be a positive number');\n }\n\n if (typeof viewport.height !== 'number' || viewport.height <= 0) {\n throw new Error('BaseLayer: viewport.height must be a positive number');\n }\n\n if (typeof viewport.scale !== 'number' || viewport.scale <= 0) {\n throw new Error('BaseLayer: viewport.scale must be a positive number');\n }\n }\n\n /**\n * Checks if layer is destroyed and throws error if so\n *\n * @private\n * @param {string} methodName - Name of method being called\n * @throws {Error} If layer is destroyed\n */\n _checkDestroyed(methodName) {\n if (this.isDestroyed) {\n throw new Error(`BaseLayer: Cannot call ${methodName}() on destroyed layer`);\n }\n }\n}\n\nexport default BaseLayer;\n"],"names":["BaseLayer","container","viewport","annotations","nowSec","methodName"],"mappings":"4GAQA,MAAMA,CAAU,CAad,YAAYC,EAAWC,EAAU,CAa/B,GAXA,KAAK,mBAAmBD,CAAS,EACjC,KAAK,kBAAkBC,CAAQ,EAG/B,KAAK,UAAYD,EACjB,KAAK,SAAW,CAAE,GAAGC,CAAQ,EAC7B,KAAK,YAAc,CAAA,EACnB,KAAK,YAAc,EACnB,KAAK,YAAc,GAGf,aAAeF,EACjB,MAAM,IAAI,MAAM,+GAA+G,CAEnI,CAQA,eAAeG,EAAa,CAC1B,KAAK,gBAAgB,gBAAgB,EACrC,KAAK,YAAcA,GAAe,CAAA,CACpC,CAYA,YAAYD,EAAU,CACpB,KAAK,gBAAgB,aAAa,EAClC,KAAK,kBAAkBA,CAAQ,EAC/B,KAAK,SAAW,CAAE,GAAGA,CAAQ,CAC/B,CAQA,WAAWE,EAAQ,CACjB,KAAK,gBAAgB,YAAY,EACjC,KAAK,YAAcA,CACrB,CAQA,SAAU,CACJ,KAAK,cAIT,KAAK,YAAc,KACnB,KAAK,SAAW,KAChB,KAAK,UAAY,KACjB,KAAK,YAAc,GACrB,CAQA,QAAS,CACP,MAAM,IAAI,MAAM,0CAA0C,CAC5D,CAQA,QAAS,CACP,MAAM,IAAI,MAAM,0CAA0C,CAC5D,CASA,mBAAmBH,EAAW,CAC5B,GAAI,CAACA,GAAa,EAAEA,aAAqB,aACvC,MAAM,IAAI,MAAM,kDAAkD,CAEtE,CASA,kBAAkBC,EAAU,CAC1B,GAAI,CAACA,GAAY,OAAOA,GAAa,SACnC,MAAM,IAAI,MAAM,uCAAuC,EAGzD,GAAI,OAAOA,EAAS,OAAU,UAAYA,EAAS,OAAS,EAC1D,MAAM,IAAI,MAAM,qDAAqD,EAGvE,GAAI,OAAOA,EAAS,QAAW,UAAYA,EAAS,QAAU,EAC5D,MAAM,IAAI,MAAM,sDAAsD,EAGxE,GAAI,OAAOA,EAAS,OAAU,UAAYA,EAAS,OAAS,EAC1D,MAAM,IAAI,MAAM,qDAAqD,CAEzE,CASA,gBAAgBG,EAAY,CAC1B,GAAI,KAAK,YACP,MAAM,IAAI,MAAM,0BAA0BA,CAAU,uBAAuB,CAE/E,CACF"}
package/dist/index6.js ADDED
@@ -0,0 +1,119 @@
1
+ class r {
2
+ /**
3
+ * Creates a new BaseLayer instance
4
+ *
5
+ * @param {HTMLElement} container - Parent DOM element for layer content
6
+ * @param {Object} viewport - Initial viewport dimensions
7
+ * @param {number} viewport.width - Viewport width in pixels
8
+ * @param {number} viewport.height - Viewport height in pixels
9
+ * @param {number} viewport.scale - PDF scale/zoom level
10
+ * @throws {Error} If container is not a valid HTMLElement
11
+ * @throws {Error} If viewport is missing required properties
12
+ * @throws {Error} If instantiated directly (abstract class)
13
+ */
14
+ constructor(e, t) {
15
+ if (this._validateContainer(e), this._validateViewport(t), this.container = e, this.viewport = { ...t }, this.annotations = [], this.currentTime = 0, this.isDestroyed = !1, new.target === r)
16
+ throw new Error("BaseLayer is an abstract class and cannot be instantiated directly. Extend it with a concrete implementation.");
17
+ }
18
+ /**
19
+ * Sets the annotation data for this layer
20
+ *
21
+ * @param {Array} annotations - Array of annotation objects
22
+ * @throws {Error} If called after layer is destroyed
23
+ */
24
+ setAnnotations(e) {
25
+ this._checkDestroyed("setAnnotations"), this.annotations = e || [];
26
+ }
27
+ /**
28
+ * Updates the viewport dimensions
29
+ *
30
+ * @param {Object} viewport - New viewport dimensions
31
+ * @param {number} viewport.width - Viewport width in pixels
32
+ * @param {number} viewport.height - Viewport height in pixels
33
+ * @param {number} viewport.scale - PDF scale/zoom level
34
+ * @throws {Error} If viewport is missing required properties
35
+ * @throws {Error} If called after layer is destroyed
36
+ */
37
+ setViewport(e) {
38
+ this._checkDestroyed("setViewport"), this._validateViewport(e), this.viewport = { ...e };
39
+ }
40
+ /**
41
+ * Updates the current timeline position
42
+ *
43
+ * @param {number} nowSec - Current timeline position in seconds
44
+ * @throws {Error} If called after layer is destroyed
45
+ */
46
+ updateTime(e) {
47
+ this._checkDestroyed("updateTime"), this.currentTime = e;
48
+ }
49
+ /**
50
+ * Destroys the layer and releases resources
51
+ *
52
+ * Safe to call multiple times (idempotent).
53
+ * Subclasses must call super.destroy() after their own cleanup.
54
+ */
55
+ destroy() {
56
+ this.isDestroyed || (this.annotations = null, this.viewport = null, this.container = null, this.isDestroyed = !0);
57
+ }
58
+ /**
59
+ * Renders the layer content
60
+ *
61
+ * @abstract
62
+ * @throws {Error} If not implemented by subclass
63
+ */
64
+ render() {
65
+ throw new Error("render() must be implemented by subclass");
66
+ }
67
+ /**
68
+ * Updates the visual state of the layer
69
+ *
70
+ * @abstract
71
+ * @throws {Error} If not implemented by subclass
72
+ */
73
+ update() {
74
+ throw new Error("update() must be implemented by subclass");
75
+ }
76
+ /**
77
+ * Validates that container is a valid HTMLElement
78
+ *
79
+ * @private
80
+ * @param {*} container - Value to validate
81
+ * @throws {Error} If container is not a valid HTMLElement
82
+ */
83
+ _validateContainer(e) {
84
+ if (!e || !(e instanceof HTMLElement))
85
+ throw new Error("BaseLayer: container must be a valid HTMLElement");
86
+ }
87
+ /**
88
+ * Validates that viewport has required properties
89
+ *
90
+ * @private
91
+ * @param {*} viewport - Value to validate
92
+ * @throws {Error} If viewport is missing required properties
93
+ */
94
+ _validateViewport(e) {
95
+ if (!e || typeof e != "object")
96
+ throw new Error("BaseLayer: viewport must be an object");
97
+ if (typeof e.width != "number" || e.width <= 0)
98
+ throw new Error("BaseLayer: viewport.width must be a positive number");
99
+ if (typeof e.height != "number" || e.height <= 0)
100
+ throw new Error("BaseLayer: viewport.height must be a positive number");
101
+ if (typeof e.scale != "number" || e.scale <= 0)
102
+ throw new Error("BaseLayer: viewport.scale must be a positive number");
103
+ }
104
+ /**
105
+ * Checks if layer is destroyed and throws error if so
106
+ *
107
+ * @private
108
+ * @param {string} methodName - Name of method being called
109
+ * @throws {Error} If layer is destroyed
110
+ */
111
+ _checkDestroyed(e) {
112
+ if (this.isDestroyed)
113
+ throw new Error(`BaseLayer: Cannot call ${e}() on destroyed layer`);
114
+ }
115
+ }
116
+ export {
117
+ r as default
118
+ };
119
+ //# sourceMappingURL=index6.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index6.js","sources":["../src/layers/BaseLayer.js"],"sourcesContent":["/**\n * BaseLayer - Abstract base class for annotation layers\n *\n * Provides common interface and lifecycle management for all annotation layer types.\n * Subclasses must implement render() and update() abstract methods.\n *\n * @abstract\n */\nclass BaseLayer {\n /**\n * Creates a new BaseLayer instance\n *\n * @param {HTMLElement} container - Parent DOM element for layer content\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 - PDF scale/zoom level\n * @throws {Error} If container is not a valid HTMLElement\n * @throws {Error} If viewport is missing required properties\n * @throws {Error} If instantiated directly (abstract class)\n */\n constructor(container, viewport) {\n // Validate parameters\n this._validateContainer(container);\n this._validateViewport(viewport);\n\n // Initialize core properties\n this.container = container;\n this.viewport = { ...viewport };\n this.annotations = [];\n this.currentTime = 0;\n this.isDestroyed = false;\n\n // Prevent direct instantiation\n if (new.target === BaseLayer) {\n throw new Error('BaseLayer is an abstract class and cannot be instantiated directly. Extend it with a concrete implementation.');\n }\n }\n\n /**\n * Sets the annotation data for this layer\n *\n * @param {Array} annotations - Array of annotation objects\n * @throws {Error} If called after layer is destroyed\n */\n setAnnotations(annotations) {\n this._checkDestroyed('setAnnotations');\n this.annotations = annotations || [];\n }\n\n /**\n * Updates the viewport dimensions\n *\n * @param {Object} viewport - New 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 - PDF scale/zoom level\n * @throws {Error} If viewport is missing required properties\n * @throws {Error} If called after layer is destroyed\n */\n setViewport(viewport) {\n this._checkDestroyed('setViewport');\n this._validateViewport(viewport);\n this.viewport = { ...viewport };\n }\n\n /**\n * Updates the current timeline position\n *\n * @param {number} nowSec - Current timeline position in seconds\n * @throws {Error} If called after layer is destroyed\n */\n updateTime(nowSec) {\n this._checkDestroyed('updateTime');\n this.currentTime = nowSec;\n }\n\n /**\n * Destroys the layer and releases resources\n *\n * Safe to call multiple times (idempotent).\n * Subclasses must call super.destroy() after their own cleanup.\n */\n destroy() {\n if (this.isDestroyed) {\n return;\n }\n\n this.annotations = null;\n this.viewport = null;\n this.container = null;\n this.isDestroyed = true;\n }\n\n /**\n * Renders the layer content\n *\n * @abstract\n * @throws {Error} If not implemented by subclass\n */\n render() {\n throw new Error('render() must be implemented by subclass');\n }\n\n /**\n * Updates the visual state of the layer\n *\n * @abstract\n * @throws {Error} If not implemented by subclass\n */\n update() {\n throw new Error('update() must be implemented by subclass');\n }\n\n /**\n * Validates that container is a valid HTMLElement\n *\n * @private\n * @param {*} container - Value to validate\n * @throws {Error} If container is not a valid HTMLElement\n */\n _validateContainer(container) {\n if (!container || !(container instanceof HTMLElement)) {\n throw new Error('BaseLayer: container must be a valid HTMLElement');\n }\n }\n\n /**\n * Validates that viewport has required properties\n *\n * @private\n * @param {*} viewport - Value to validate\n * @throws {Error} If viewport is missing required properties\n */\n _validateViewport(viewport) {\n if (!viewport || typeof viewport !== 'object') {\n throw new Error('BaseLayer: viewport must be an object');\n }\n\n if (typeof viewport.width !== 'number' || viewport.width <= 0) {\n throw new Error('BaseLayer: viewport.width must be a positive number');\n }\n\n if (typeof viewport.height !== 'number' || viewport.height <= 0) {\n throw new Error('BaseLayer: viewport.height must be a positive number');\n }\n\n if (typeof viewport.scale !== 'number' || viewport.scale <= 0) {\n throw new Error('BaseLayer: viewport.scale must be a positive number');\n }\n }\n\n /**\n * Checks if layer is destroyed and throws error if so\n *\n * @private\n * @param {string} methodName - Name of method being called\n * @throws {Error} If layer is destroyed\n */\n _checkDestroyed(methodName) {\n if (this.isDestroyed) {\n throw new Error(`BaseLayer: Cannot call ${methodName}() on destroyed layer`);\n }\n }\n}\n\nexport default BaseLayer;\n"],"names":["BaseLayer","container","viewport","annotations","nowSec","methodName"],"mappings":"AAQA,MAAMA,EAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAad,YAAYC,GAAWC,GAAU;AAa/B,QAXA,KAAK,mBAAmBD,CAAS,GACjC,KAAK,kBAAkBC,CAAQ,GAG/B,KAAK,YAAYD,GACjB,KAAK,WAAW,EAAE,GAAGC,EAAQ,GAC7B,KAAK,cAAc,CAAA,GACnB,KAAK,cAAc,GACnB,KAAK,cAAc,IAGf,eAAeF;AACjB,YAAM,IAAI,MAAM,+GAA+G;AAAA,EAEnI;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,eAAeG,GAAa;AAC1B,SAAK,gBAAgB,gBAAgB,GACrC,KAAK,cAAcA,KAAe,CAAA;AAAA,EACpC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,YAAYD,GAAU;AACpB,SAAK,gBAAgB,aAAa,GAClC,KAAK,kBAAkBA,CAAQ,GAC/B,KAAK,WAAW,EAAE,GAAGA,EAAQ;AAAA,EAC/B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,WAAWE,GAAQ;AACjB,SAAK,gBAAgB,YAAY,GACjC,KAAK,cAAcA;AAAA,EACrB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,UAAU;AACR,IAAI,KAAK,gBAIT,KAAK,cAAc,MACnB,KAAK,WAAW,MAChB,KAAK,YAAY,MACjB,KAAK,cAAc;AAAA,EACrB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,SAAS;AACP,UAAM,IAAI,MAAM,0CAA0C;AAAA,EAC5D;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,SAAS;AACP,UAAM,IAAI,MAAM,0CAA0C;AAAA,EAC5D;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,mBAAmBH,GAAW;AAC5B,QAAI,CAACA,KAAa,EAAEA,aAAqB;AACvC,YAAM,IAAI,MAAM,kDAAkD;AAAA,EAEtE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,kBAAkBC,GAAU;AAC1B,QAAI,CAACA,KAAY,OAAOA,KAAa;AACnC,YAAM,IAAI,MAAM,uCAAuC;AAGzD,QAAI,OAAOA,EAAS,SAAU,YAAYA,EAAS,SAAS;AAC1D,YAAM,IAAI,MAAM,qDAAqD;AAGvE,QAAI,OAAOA,EAAS,UAAW,YAAYA,EAAS,UAAU;AAC5D,YAAM,IAAI,MAAM,sDAAsD;AAGxE,QAAI,OAAOA,EAAS,SAAU,YAAYA,EAAS,SAAS;AAC1D,YAAM,IAAI,MAAM,qDAAqD;AAAA,EAEzE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,gBAAgBG,GAAY;AAC1B,QAAI,KAAK;AACP,YAAM,IAAI,MAAM,0BAA0BA,CAAU,uBAAuB;AAAA,EAE/E;AACF;"}
@@ -0,0 +1,2 @@
1
+ "use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const y=require("./index6.cjs"),u=require("./index10.cjs");class p extends y.default{constructor(e,r){super(e,r),this.layerElement=document.createElement("div"),this.layerElement.style.position="absolute",this.layerElement.style.inset="0",this.layerElement.style.pointerEvents="none",this.layerElement.style.zIndex="25",this.container.appendChild(this.layerElement),this.elements=new Map,this.rafId=null}render(){this.layerElement.innerHTML="",this.elements.clear(),this.annotations.forEach(e=>{if(e.mode!=="quads"||!e.quads?.length)return;const r=e.quads.reduce((a,i)=>a+i.w,0);e.quads.forEach((a,i)=>{const s=u.rectNormToAbs(a,this.viewport),n=e.quads.slice(0,i).reduce((m,c)=>m+c.w,0),h=n/r,d=(n+a.w)/r,t=document.createElement("div");t.style.position="absolute",t.style.left=`${s.left}px`,t.style.top=`${s.top}px`,t.style.width=`${s.width}px`,t.style.height=`${s.height}px`,t.style.overflow="hidden",t.style.borderRadius="2px";const l=document.createElement("div");l.style.width="100%",l.style.height="100%",l.style.background=e?.style?.color??"rgba(255,230,100,0.35)",l.style.outline="1px solid rgba(255,200,0,0.6)",l.style.transformOrigin="left center",l.style.transform="scaleX(0)",l.style.willChange="transform",t.appendChild(l),this.layerElement.appendChild(t);const o=`${e.id}-${i}`;this.elements.set(o,{element:l,wrapper:t,annotation:e,segStart:h,segEnd:d})})})}updateTime(e){super.updateTime(e),this.rafId&&(cancelAnimationFrame(this.rafId),this.rafId=null);const r=()=>{this.isDestroyed||(this.elements.forEach(({element:a,wrapper:i,annotation:s,segStart:n,segEnd:h})=>{if(e<s.start)i.style.display="none";else{i.style.display="block";const d=Math.max(0,Math.min(1,(e-s.start)/Math.max(1e-6,s.end-s.start))),t=Math.max(0,Math.min(1,(d-n)/Math.max(1e-6,h-n)));a.style.transform=`scaleX(${t})`}}),this.rafId=requestAnimationFrame(r))};r()}update(){}destroy(){this.rafId&&(cancelAnimationFrame(this.rafId),this.rafId=null),this.elements.clear(),this.elements=null,this.layerElement&&this.layerElement.parentNode&&this.layerElement.parentNode.removeChild(this.layerElement),this.layerElement=null,super.destroy()}}exports.default=p;
2
+ //# sourceMappingURL=index7.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index7.cjs","sources":["../src/layers/HighlightLayer.js"],"sourcesContent":["import BaseLayer from './BaseLayer.js';\nimport { rectNormToAbs } from '../utils/coordinateUtils.js';\n\n/**\n * HighlightLayer - Renders highlight annotations with progressive reveal\n *\n * Extends BaseLayer to render rectangular highlight regions (quads) with\n * progressive left-to-right scaleX animation based on timeline position.\n * Supports multi-line highlights with per-quad timing segments.\n *\n * @extends BaseLayer\n */\nclass HighlightLayer extends BaseLayer {\n /**\n * Creates a new HighlightLayer instance\n *\n * @param {HTMLElement} container - Parent DOM element for layer content\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 - PDF scale/zoom level\n */\n constructor(container, viewport) {\n super(container, viewport);\n\n // Create layer container element\n this.layerElement = document.createElement('div');\n this.layerElement.style.position = 'absolute';\n this.layerElement.style.inset = '0';\n this.layerElement.style.pointerEvents = 'none';\n this.layerElement.style.zIndex = '25';\n\n this.container.appendChild(this.layerElement);\n\n // Initialize element storage\n this.elements = new Map();\n\n // Initialize RAF ID\n this.rafId = null;\n }\n\n /**\n * Renders highlight elements for all annotations\n *\n * Creates DOM structure for each quad in each annotation. Calculates\n * timing segments for progressive animation. Clears and recreates all\n * elements when called.\n */\n render() {\n // Clear existing elements\n this.layerElement.innerHTML = '';\n this.elements.clear();\n\n // Process each annotation\n this.annotations.forEach((annotation) => {\n // Skip if not quad mode or no quads\n if (annotation.mode !== 'quads' || !annotation.quads?.length) {\n return;\n }\n\n // Calculate total width across all quads\n const totalW = annotation.quads.reduce((sum, quad) => sum + quad.w, 0);\n\n // Process each quad\n annotation.quads.forEach((quad, idx) => {\n // Convert normalized coordinates to absolute pixels\n const abs = rectNormToAbs(quad, this.viewport);\n\n // Calculate timing segment for this quad\n const prevW = annotation.quads.slice(0, idx).reduce((sum, q) => sum + q.w, 0);\n const segStart = prevW / totalW;\n const segEnd = (prevW + quad.w) / totalW;\n\n // Create wrapper div\n const wrapper = document.createElement('div');\n wrapper.style.position = 'absolute';\n wrapper.style.left = `${abs.left}px`;\n wrapper.style.top = `${abs.top}px`;\n wrapper.style.width = `${abs.width}px`;\n wrapper.style.height = `${abs.height}px`;\n wrapper.style.overflow = 'hidden';\n wrapper.style.borderRadius = '2px';\n\n // Create highlight div\n const highlight = document.createElement('div');\n highlight.style.width = '100%';\n highlight.style.height = '100%';\n highlight.style.background = annotation?.style?.color ?? 'rgba(255,230,100,0.35)';\n highlight.style.outline = '1px solid rgba(255,200,0,0.6)';\n highlight.style.transformOrigin = 'left center';\n highlight.style.transform = 'scaleX(0)';\n highlight.style.willChange = 'transform';\n\n // Assemble DOM structure\n wrapper.appendChild(highlight);\n this.layerElement.appendChild(wrapper);\n\n // Store reference for animation\n const key = `${annotation.id}-${idx}`;\n this.elements.set(key, {\n element: highlight,\n wrapper: wrapper,\n annotation: annotation,\n segStart: segStart,\n segEnd: segEnd\n });\n });\n });\n }\n\n /**\n * Updates highlight animations based on current timeline position\n *\n * Starts requestAnimationFrame loop to animate scaleX transform for\n * each highlight element. Calculates progress for each quad segment\n * and updates visibility.\n *\n * @param {number} nowSec - Current timeline position in seconds\n */\n updateTime(nowSec) {\n super.updateTime(nowSec);\n\n // Cancel existing RAF if running\n if (this.rafId) {\n cancelAnimationFrame(this.rafId);\n this.rafId = null;\n }\n\n // Start animation loop\n const animate = () => {\n if (this.isDestroyed) {\n return;\n }\n\n // Update each highlight element\n this.elements.forEach(({ element, wrapper, annotation, segStart, segEnd }) => {\n // Hide wrapper if time hasn't reached annotation start\n if (nowSec < annotation.start) {\n wrapper.style.display = 'none';\n } else {\n // Show wrapper\n wrapper.style.display = 'block';\n\n // Calculate global progress (0 to 1)\n const globalProgress = Math.max(\n 0,\n Math.min(\n 1,\n (nowSec - annotation.start) / Math.max(1e-6, annotation.end - annotation.start)\n )\n );\n\n // Calculate local progress for this quad segment (0 to 1)\n const localProgress = Math.max(\n 0,\n Math.min(\n 1,\n (globalProgress - segStart) / Math.max(1e-6, segEnd - segStart)\n )\n );\n\n // Apply scaleX transform\n element.style.transform = `scaleX(${localProgress})`;\n }\n });\n\n // Schedule next frame\n this.rafId = requestAnimationFrame(animate);\n };\n\n animate();\n }\n\n /**\n * Updates the visual state of the layer\n *\n * Not used by HighlightLayer - animation handled in updateTime()\n */\n update() {\n // Not used - updateTime handles animation directly\n }\n\n /**\n * Destroys the layer and releases all resources\n *\n * Cancels animation loop, clears element storage, removes DOM elements,\n * and calls parent cleanup.\n */\n destroy() {\n // Cancel RAF if running\n if (this.rafId) {\n cancelAnimationFrame(this.rafId);\n this.rafId = null;\n }\n\n // Clear element storage\n this.elements.clear();\n this.elements = null;\n\n // Remove layer element from DOM\n if (this.layerElement && this.layerElement.parentNode) {\n this.layerElement.parentNode.removeChild(this.layerElement);\n }\n this.layerElement = null;\n\n // Call parent destroy\n super.destroy();\n }\n}\n\nexport default HighlightLayer;\n"],"names":["HighlightLayer","BaseLayer","container","viewport","annotation","totalW","sum","quad","idx","abs","rectNormToAbs","prevW","q","segStart","segEnd","wrapper","highlight","key","nowSec","animate","element","globalProgress","localProgress"],"mappings":"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"}
package/dist/index7.js ADDED
@@ -0,0 +1,100 @@
1
+ import c from "./index6.js";
2
+ import { rectNormToAbs as p } from "./index10.js";
3
+ class g extends c {
4
+ /**
5
+ * Creates a new HighlightLayer instance
6
+ *
7
+ * @param {HTMLElement} container - Parent DOM element for layer content
8
+ * @param {Object} viewport - Initial viewport dimensions
9
+ * @param {number} viewport.width - Viewport width in pixels
10
+ * @param {number} viewport.height - Viewport height in pixels
11
+ * @param {number} viewport.scale - PDF scale/zoom level
12
+ */
13
+ constructor(e, r) {
14
+ super(e, r), this.layerElement = document.createElement("div"), this.layerElement.style.position = "absolute", this.layerElement.style.inset = "0", this.layerElement.style.pointerEvents = "none", this.layerElement.style.zIndex = "25", this.container.appendChild(this.layerElement), this.elements = /* @__PURE__ */ new Map(), this.rafId = null;
15
+ }
16
+ /**
17
+ * Renders highlight elements for all annotations
18
+ *
19
+ * Creates DOM structure for each quad in each annotation. Calculates
20
+ * timing segments for progressive animation. Clears and recreates all
21
+ * elements when called.
22
+ */
23
+ render() {
24
+ this.layerElement.innerHTML = "", this.elements.clear(), this.annotations.forEach((e) => {
25
+ if (e.mode !== "quads" || !e.quads?.length)
26
+ return;
27
+ const r = e.quads.reduce((a, i) => a + i.w, 0);
28
+ e.quads.forEach((a, i) => {
29
+ const s = p(a, this.viewport), n = e.quads.slice(0, i).reduce((o, y) => o + y.w, 0), h = n / r, d = (n + a.w) / r, t = document.createElement("div");
30
+ t.style.position = "absolute", t.style.left = `${s.left}px`, t.style.top = `${s.top}px`, t.style.width = `${s.width}px`, t.style.height = `${s.height}px`, t.style.overflow = "hidden", t.style.borderRadius = "2px";
31
+ const l = document.createElement("div");
32
+ l.style.width = "100%", l.style.height = "100%", l.style.background = e?.style?.color ?? "rgba(255,230,100,0.35)", l.style.outline = "1px solid rgba(255,200,0,0.6)", l.style.transformOrigin = "left center", l.style.transform = "scaleX(0)", l.style.willChange = "transform", t.appendChild(l), this.layerElement.appendChild(t);
33
+ const m = `${e.id}-${i}`;
34
+ this.elements.set(m, {
35
+ element: l,
36
+ wrapper: t,
37
+ annotation: e,
38
+ segStart: h,
39
+ segEnd: d
40
+ });
41
+ });
42
+ });
43
+ }
44
+ /**
45
+ * Updates highlight animations based on current timeline position
46
+ *
47
+ * Starts requestAnimationFrame loop to animate scaleX transform for
48
+ * each highlight element. Calculates progress for each quad segment
49
+ * and updates visibility.
50
+ *
51
+ * @param {number} nowSec - Current timeline position in seconds
52
+ */
53
+ updateTime(e) {
54
+ super.updateTime(e), this.rafId && (cancelAnimationFrame(this.rafId), this.rafId = null);
55
+ const r = () => {
56
+ this.isDestroyed || (this.elements.forEach(({ element: a, wrapper: i, annotation: s, segStart: n, segEnd: h }) => {
57
+ if (e < s.start)
58
+ i.style.display = "none";
59
+ else {
60
+ i.style.display = "block";
61
+ const d = Math.max(
62
+ 0,
63
+ Math.min(
64
+ 1,
65
+ (e - s.start) / Math.max(1e-6, s.end - s.start)
66
+ )
67
+ ), t = Math.max(
68
+ 0,
69
+ Math.min(
70
+ 1,
71
+ (d - n) / Math.max(1e-6, h - n)
72
+ )
73
+ );
74
+ a.style.transform = `scaleX(${t})`;
75
+ }
76
+ }), this.rafId = requestAnimationFrame(r));
77
+ };
78
+ r();
79
+ }
80
+ /**
81
+ * Updates the visual state of the layer
82
+ *
83
+ * Not used by HighlightLayer - animation handled in updateTime()
84
+ */
85
+ update() {
86
+ }
87
+ /**
88
+ * Destroys the layer and releases all resources
89
+ *
90
+ * Cancels animation loop, clears element storage, removes DOM elements,
91
+ * and calls parent cleanup.
92
+ */
93
+ destroy() {
94
+ this.rafId && (cancelAnimationFrame(this.rafId), this.rafId = null), this.elements.clear(), this.elements = null, this.layerElement && this.layerElement.parentNode && this.layerElement.parentNode.removeChild(this.layerElement), this.layerElement = null, super.destroy();
95
+ }
96
+ }
97
+ export {
98
+ g as default
99
+ };
100
+ //# sourceMappingURL=index7.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index7.js","sources":["../src/layers/HighlightLayer.js"],"sourcesContent":["import BaseLayer from './BaseLayer.js';\nimport { rectNormToAbs } from '../utils/coordinateUtils.js';\n\n/**\n * HighlightLayer - Renders highlight annotations with progressive reveal\n *\n * Extends BaseLayer to render rectangular highlight regions (quads) with\n * progressive left-to-right scaleX animation based on timeline position.\n * Supports multi-line highlights with per-quad timing segments.\n *\n * @extends BaseLayer\n */\nclass HighlightLayer extends BaseLayer {\n /**\n * Creates a new HighlightLayer instance\n *\n * @param {HTMLElement} container - Parent DOM element for layer content\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 - PDF scale/zoom level\n */\n constructor(container, viewport) {\n super(container, viewport);\n\n // Create layer container element\n this.layerElement = document.createElement('div');\n this.layerElement.style.position = 'absolute';\n this.layerElement.style.inset = '0';\n this.layerElement.style.pointerEvents = 'none';\n this.layerElement.style.zIndex = '25';\n\n this.container.appendChild(this.layerElement);\n\n // Initialize element storage\n this.elements = new Map();\n\n // Initialize RAF ID\n this.rafId = null;\n }\n\n /**\n * Renders highlight elements for all annotations\n *\n * Creates DOM structure for each quad in each annotation. Calculates\n * timing segments for progressive animation. Clears and recreates all\n * elements when called.\n */\n render() {\n // Clear existing elements\n this.layerElement.innerHTML = '';\n this.elements.clear();\n\n // Process each annotation\n this.annotations.forEach((annotation) => {\n // Skip if not quad mode or no quads\n if (annotation.mode !== 'quads' || !annotation.quads?.length) {\n return;\n }\n\n // Calculate total width across all quads\n const totalW = annotation.quads.reduce((sum, quad) => sum + quad.w, 0);\n\n // Process each quad\n annotation.quads.forEach((quad, idx) => {\n // Convert normalized coordinates to absolute pixels\n const abs = rectNormToAbs(quad, this.viewport);\n\n // Calculate timing segment for this quad\n const prevW = annotation.quads.slice(0, idx).reduce((sum, q) => sum + q.w, 0);\n const segStart = prevW / totalW;\n const segEnd = (prevW + quad.w) / totalW;\n\n // Create wrapper div\n const wrapper = document.createElement('div');\n wrapper.style.position = 'absolute';\n wrapper.style.left = `${abs.left}px`;\n wrapper.style.top = `${abs.top}px`;\n wrapper.style.width = `${abs.width}px`;\n wrapper.style.height = `${abs.height}px`;\n wrapper.style.overflow = 'hidden';\n wrapper.style.borderRadius = '2px';\n\n // Create highlight div\n const highlight = document.createElement('div');\n highlight.style.width = '100%';\n highlight.style.height = '100%';\n highlight.style.background = annotation?.style?.color ?? 'rgba(255,230,100,0.35)';\n highlight.style.outline = '1px solid rgba(255,200,0,0.6)';\n highlight.style.transformOrigin = 'left center';\n highlight.style.transform = 'scaleX(0)';\n highlight.style.willChange = 'transform';\n\n // Assemble DOM structure\n wrapper.appendChild(highlight);\n this.layerElement.appendChild(wrapper);\n\n // Store reference for animation\n const key = `${annotation.id}-${idx}`;\n this.elements.set(key, {\n element: highlight,\n wrapper: wrapper,\n annotation: annotation,\n segStart: segStart,\n segEnd: segEnd\n });\n });\n });\n }\n\n /**\n * Updates highlight animations based on current timeline position\n *\n * Starts requestAnimationFrame loop to animate scaleX transform for\n * each highlight element. Calculates progress for each quad segment\n * and updates visibility.\n *\n * @param {number} nowSec - Current timeline position in seconds\n */\n updateTime(nowSec) {\n super.updateTime(nowSec);\n\n // Cancel existing RAF if running\n if (this.rafId) {\n cancelAnimationFrame(this.rafId);\n this.rafId = null;\n }\n\n // Start animation loop\n const animate = () => {\n if (this.isDestroyed) {\n return;\n }\n\n // Update each highlight element\n this.elements.forEach(({ element, wrapper, annotation, segStart, segEnd }) => {\n // Hide wrapper if time hasn't reached annotation start\n if (nowSec < annotation.start) {\n wrapper.style.display = 'none';\n } else {\n // Show wrapper\n wrapper.style.display = 'block';\n\n // Calculate global progress (0 to 1)\n const globalProgress = Math.max(\n 0,\n Math.min(\n 1,\n (nowSec - annotation.start) / Math.max(1e-6, annotation.end - annotation.start)\n )\n );\n\n // Calculate local progress for this quad segment (0 to 1)\n const localProgress = Math.max(\n 0,\n Math.min(\n 1,\n (globalProgress - segStart) / Math.max(1e-6, segEnd - segStart)\n )\n );\n\n // Apply scaleX transform\n element.style.transform = `scaleX(${localProgress})`;\n }\n });\n\n // Schedule next frame\n this.rafId = requestAnimationFrame(animate);\n };\n\n animate();\n }\n\n /**\n * Updates the visual state of the layer\n *\n * Not used by HighlightLayer - animation handled in updateTime()\n */\n update() {\n // Not used - updateTime handles animation directly\n }\n\n /**\n * Destroys the layer and releases all resources\n *\n * Cancels animation loop, clears element storage, removes DOM elements,\n * and calls parent cleanup.\n */\n destroy() {\n // Cancel RAF if running\n if (this.rafId) {\n cancelAnimationFrame(this.rafId);\n this.rafId = null;\n }\n\n // Clear element storage\n this.elements.clear();\n this.elements = null;\n\n // Remove layer element from DOM\n if (this.layerElement && this.layerElement.parentNode) {\n this.layerElement.parentNode.removeChild(this.layerElement);\n }\n this.layerElement = null;\n\n // Call parent destroy\n super.destroy();\n }\n}\n\nexport default HighlightLayer;\n"],"names":["HighlightLayer","BaseLayer","container","viewport","annotation","totalW","sum","quad","idx","abs","rectNormToAbs","prevW","q","segStart","segEnd","wrapper","highlight","key","nowSec","animate","element","globalProgress","localProgress"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ "use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const h=require("./index6.cjs"),p=require("./index10.cjs");class u extends h.default{constructor(t,s){super(t,s),this.layerElement=document.createElement("div"),this.layerElement.style.position="absolute",this.layerElement.style.inset="0",this.layerElement.style.pointerEvents="none",this.layerElement.style.zIndex="30",this.container.appendChild(this.layerElement),this.textElements=new Map}render(){this.layerElement.innerHTML="",this.textElements.clear(),this.annotations.forEach(t=>{const s=p.rectNormToAbs(t,this.viewport),e=document.createElement("div");e.style.position="absolute",e.style.left=`${s.left}px`,e.style.top=`${s.top}px`,e.style.width=`${s.width}px`,e.style.height=`${s.height}px`,e.style.backgroundColor=t.style?.bg||"rgba(255,255,255,0.9)",e.style.borderRadius="4px",e.style.padding="8px",e.style.fontSize="14px",e.style.lineHeight="1.4",e.style.color=t.style?.color||"#1f2937",e.style.fontFamily="system-ui, -apple-system, sans-serif",e.style.display="flex",e.style.alignItems="center",e.style.justifyContent="flex-start",e.style.overflow="hidden",e.style.wordWrap="break-word",e.style.display="none",this.layerElement.appendChild(e),this.textElements.set(t.id,{element:e,annotation:t})})}updateTime(t){super.updateTime(t),this.textElements.forEach(({element:s,annotation:e})=>{if(t<e.start)s.style.display="none";else{s.style.display="flex";const l=this._getVisibleText(e.content,e.start,e.end,t);s.textContent=l}})}_getVisibleText(t,s,e,l){if(l<s)return"";if(l>=e)return t;const n=(l-s)/(e-s),r=t.split(" "),i=Math.floor(n*r.length);if(i===0)return"";const o=r.slice(0,i);if(i<r.length){const d=n*r.length-i,y=r[i],a=Math.floor(d*y.length);a>0&&o.push(y.slice(0,a))}return o.join(" ")}update(){}destroy(){this.textElements.clear(),this.textElements=null,this.layerElement&&this.layerElement.parentNode&&this.layerElement.parentNode.removeChild(this.layerElement),this.layerElement=null,super.destroy()}}exports.default=u;
2
+ //# sourceMappingURL=index8.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index8.cjs","sources":["../src/layers/TextLayer.js"],"sourcesContent":["import BaseLayer from \"./BaseLayer.js\";\nimport { rectNormToAbs } from \"../utils/coordinateUtils.js\";\n\n/**\n * TextLayer - Renders text annotations with progressive reveal\n *\n * Extends BaseLayer to render text box annotations with progressive\n * word-by-word text reveal animation (typing effect). Text appears\n * immediately and types in character by character, simulating real-time typing.\n *\n * @extends BaseLayer\n */\nclass TextLayer extends BaseLayer {\n /**\n * Creates a new TextLayer instance\n *\n * @param {HTMLElement} container - Parent DOM element for layer content\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 - PDF scale/zoom level\n */\n constructor(container, viewport) {\n // Call parent constructor first\n super(container, viewport);\n\n // Create layer container element\n this.layerElement = document.createElement(\"div\");\n this.layerElement.style.position = \"absolute\";\n this.layerElement.style.inset = \"0\";\n this.layerElement.style.pointerEvents = \"none\";\n this.layerElement.style.zIndex = \"30\";\n\n // Append to parent container\n this.container.appendChild(this.layerElement);\n\n // Initialize element storage (Map of id -> element)\n this.textElements = new Map();\n }\n\n /**\n * Renders text box elements for all annotations\n *\n * Creates DOM structure for each text annotation. Creates text box divs\n * with proper positioning and styling. Initially hidden (visibility\n * controlled by updateTime).\n *\n * This method is idempotent - safe to call multiple times.\n */\n render() {\n // Clear existing elements\n this.layerElement.innerHTML = \"\";\n this.textElements.clear();\n\n // Process each annotation\n this.annotations.forEach((annotation) => {\n // Convert normalized coordinates to absolute pixels\n const abs = rectNormToAbs(annotation, this.viewport);\n\n // Create text box div\n const textBox = document.createElement(\"div\");\n\n // Set positioning\n textBox.style.position = \"absolute\";\n textBox.style.left = `${abs.left}px`;\n textBox.style.top = `${abs.top}px`;\n textBox.style.width = `${abs.width}px`;\n textBox.style.height = `${abs.height}px`;\n\n // Set background and border\n textBox.style.backgroundColor =\n annotation.style?.bg || \"rgba(255,255,255,0.9)\";\n textBox.style.borderRadius = \"4px\";\n textBox.style.padding = \"8px\";\n\n // Set text styling\n textBox.style.fontSize = \"14px\";\n textBox.style.lineHeight = \"1.4\";\n textBox.style.color = annotation.style?.color || \"#1f2937\";\n textBox.style.fontFamily = \"system-ui, -apple-system, sans-serif\";\n\n // Set layout\n textBox.style.display = \"flex\";\n textBox.style.alignItems = \"center\";\n textBox.style.justifyContent = \"flex-start\";\n textBox.style.overflow = \"hidden\";\n textBox.style.wordWrap = \"break-word\";\n\n // Initially hidden (will be shown/updated in updateTime)\n textBox.style.display = \"none\";\n\n // Append to layer\n this.layerElement.appendChild(textBox);\n\n // Store reference\n this.textElements.set(annotation.id, {\n element: textBox,\n annotation: annotation,\n });\n });\n }\n\n /**\n * Updates text box visibility and content based on timeline position\n *\n * Shows/hides text boxes based on start time. Calculates visible text\n * for progressive reveal (typing effect). Text appears immediately when\n * start time is reached and types in progressively.\n *\n * @param {number} nowSec - Current timeline position in seconds\n */\n updateTime(nowSec) {\n // Call parent implementation\n super.updateTime(nowSec);\n\n // Update each text element\n this.textElements.forEach(({ element, annotation }) => {\n // Check if annotation should be visible\n if (nowSec < annotation.start) {\n // Before start time - hide\n element.style.display = \"none\";\n } else {\n // After start time - show\n element.style.display = \"flex\";\n\n // Calculate visible text\n const visibleText = this._getVisibleText(\n annotation.content,\n annotation.start,\n annotation.end,\n nowSec\n );\n\n // Update text content (typing effect)\n element.textContent = visibleText;\n }\n });\n }\n\n /**\n * Calculates visible text based on progress between start and end times\n *\n * Implements word-by-word reveal with partial character reveal for\n * the current word being typed.\n *\n * @private\n * @param {string} content - Full text content\n * @param {number} start - Start time in seconds\n * @param {number} end - End time in seconds\n * @param {number} currentTime - Current timeline position in seconds\n * @returns {string} Visible portion of text\n */\n _getVisibleText(content, start, end, currentTime) {\n // Before start - no text visible\n if (currentTime < start) {\n return \"\";\n }\n\n // After end - full text visible\n if (currentTime >= end) {\n return content;\n }\n\n // During animation - calculate progress\n const progress = (currentTime - start) / (end - start);\n\n // Split into words\n const words = content.split(\" \");\n\n // Calculate visible word count\n const visibleWordCount = Math.floor(progress * words.length);\n\n // No words visible yet\n if (visibleWordCount === 0) {\n return \"\";\n }\n\n // Get complete visible words\n const visibleWords = words.slice(0, visibleWordCount);\n\n // Add partial of the next word if not at the end\n if (visibleWordCount < words.length) {\n // Calculate progress within current word\n const currentWordProgress = progress * words.length - visibleWordCount;\n\n // Get current word being typed\n const currentWord = words[visibleWordCount];\n\n // Calculate visible character count\n const visibleCharCount = Math.floor(\n currentWordProgress * currentWord.length\n );\n\n // Add partial word if any characters are visible\n if (visibleCharCount > 0) {\n visibleWords.push(currentWord.slice(0, visibleCharCount));\n }\n }\n\n // Join words with spaces\n return visibleWords.join(\" \");\n }\n\n /**\n * Updates the visual state of the layer\n *\n * Not used by TextLayer - updateTime handles all updates directly.\n * Implemented to satisfy BaseLayer contract.\n */\n update() {\n // Not used - updateTime handles updates directly\n }\n\n /**\n * Destroys the layer and releases all resources\n *\n * Clears element storage, removes DOM elements, and calls parent cleanup.\n */\n destroy() {\n // Clear element storage\n this.textElements.clear();\n this.textElements = null;\n\n // Remove layer element from DOM\n if (this.layerElement && this.layerElement.parentNode) {\n this.layerElement.parentNode.removeChild(this.layerElement);\n }\n this.layerElement = null;\n\n // Call parent destroy\n super.destroy();\n }\n}\n\nexport default TextLayer;\n"],"names":["TextLayer","BaseLayer","container","viewport","annotation","abs","rectNormToAbs","textBox","nowSec","element","visibleText","content","start","end","currentTime","progress","words","visibleWordCount","visibleWords","currentWordProgress","currentWord","visibleCharCount"],"mappings":"uKAYA,MAAMA,UAAkBC,EAAAA,OAAU,CAUhC,YAAYC,EAAWC,EAAU,CAE/B,MAAMD,EAAWC,CAAQ,EAGzB,KAAK,aAAe,SAAS,cAAc,KAAK,EAChD,KAAK,aAAa,MAAM,SAAW,WACnC,KAAK,aAAa,MAAM,MAAQ,IAChC,KAAK,aAAa,MAAM,cAAgB,OACxC,KAAK,aAAa,MAAM,OAAS,KAGjC,KAAK,UAAU,YAAY,KAAK,YAAY,EAG5C,KAAK,aAAe,IAAI,GAC1B,CAWA,QAAS,CAEP,KAAK,aAAa,UAAY,GAC9B,KAAK,aAAa,MAAK,EAGvB,KAAK,YAAY,QAASC,GAAe,CAEvC,MAAMC,EAAMC,EAAAA,cAAcF,EAAY,KAAK,QAAQ,EAG7CG,EAAU,SAAS,cAAc,KAAK,EAG5CA,EAAQ,MAAM,SAAW,WACzBA,EAAQ,MAAM,KAAO,GAAGF,EAAI,IAAI,KAChCE,EAAQ,MAAM,IAAM,GAAGF,EAAI,GAAG,KAC9BE,EAAQ,MAAM,MAAQ,GAAGF,EAAI,KAAK,KAClCE,EAAQ,MAAM,OAAS,GAAGF,EAAI,MAAM,KAGpCE,EAAQ,MAAM,gBACZH,EAAW,OAAO,IAAM,wBAC1BG,EAAQ,MAAM,aAAe,MAC7BA,EAAQ,MAAM,QAAU,MAGxBA,EAAQ,MAAM,SAAW,OACzBA,EAAQ,MAAM,WAAa,MAC3BA,EAAQ,MAAM,MAAQH,EAAW,OAAO,OAAS,UACjDG,EAAQ,MAAM,WAAa,uCAG3BA,EAAQ,MAAM,QAAU,OACxBA,EAAQ,MAAM,WAAa,SAC3BA,EAAQ,MAAM,eAAiB,aAC/BA,EAAQ,MAAM,SAAW,SACzBA,EAAQ,MAAM,SAAW,aAGzBA,EAAQ,MAAM,QAAU,OAGxB,KAAK,aAAa,YAAYA,CAAO,EAGrC,KAAK,aAAa,IAAIH,EAAW,GAAI,CACnC,QAASG,EACT,WAAYH,CACpB,CAAO,CACH,CAAC,CACH,CAWA,WAAWI,EAAQ,CAEjB,MAAM,WAAWA,CAAM,EAGvB,KAAK,aAAa,QAAQ,CAAC,CAAE,QAAAC,EAAS,WAAAL,CAAU,IAAO,CAErD,GAAII,EAASJ,EAAW,MAEtBK,EAAQ,MAAM,QAAU,WACnB,CAELA,EAAQ,MAAM,QAAU,OAGxB,MAAMC,EAAc,KAAK,gBACvBN,EAAW,QACXA,EAAW,MACXA,EAAW,IACXI,CACV,EAGQC,EAAQ,YAAcC,CACxB,CACF,CAAC,CACH,CAeA,gBAAgBC,EAASC,EAAOC,EAAKC,EAAa,CAEhD,GAAIA,EAAcF,EAChB,MAAO,GAIT,GAAIE,GAAeD,EACjB,OAAOF,EAIT,MAAMI,GAAYD,EAAcF,IAAUC,EAAMD,GAG1CI,EAAQL,EAAQ,MAAM,GAAG,EAGzBM,EAAmB,KAAK,MAAMF,EAAWC,EAAM,MAAM,EAG3D,GAAIC,IAAqB,EACvB,MAAO,GAIT,MAAMC,EAAeF,EAAM,MAAM,EAAGC,CAAgB,EAGpD,GAAIA,EAAmBD,EAAM,OAAQ,CAEnC,MAAMG,EAAsBJ,EAAWC,EAAM,OAASC,EAGhDG,EAAcJ,EAAMC,CAAgB,EAGpCI,EAAmB,KAAK,MAC5BF,EAAsBC,EAAY,MAC1C,EAGUC,EAAmB,GACrBH,EAAa,KAAKE,EAAY,MAAM,EAAGC,CAAgB,CAAC,CAE5D,CAGA,OAAOH,EAAa,KAAK,GAAG,CAC9B,CAQA,QAAS,CAET,CAOA,SAAU,CAER,KAAK,aAAa,MAAK,EACvB,KAAK,aAAe,KAGhB,KAAK,cAAgB,KAAK,aAAa,YACzC,KAAK,aAAa,WAAW,YAAY,KAAK,YAAY,EAE5D,KAAK,aAAe,KAGpB,MAAM,QAAO,CACf,CACF"}
package/dist/index8.js ADDED
@@ -0,0 +1,109 @@
1
+ import d from "./index6.js";
2
+ import { rectNormToAbs as p } from "./index10.js";
3
+ class f extends d {
4
+ /**
5
+ * Creates a new TextLayer instance
6
+ *
7
+ * @param {HTMLElement} container - Parent DOM element for layer content
8
+ * @param {Object} viewport - Initial viewport dimensions
9
+ * @param {number} viewport.width - Viewport width in pixels
10
+ * @param {number} viewport.height - Viewport height in pixels
11
+ * @param {number} viewport.scale - PDF scale/zoom level
12
+ */
13
+ constructor(t, s) {
14
+ super(t, s), this.layerElement = document.createElement("div"), this.layerElement.style.position = "absolute", this.layerElement.style.inset = "0", this.layerElement.style.pointerEvents = "none", this.layerElement.style.zIndex = "30", this.container.appendChild(this.layerElement), this.textElements = /* @__PURE__ */ new Map();
15
+ }
16
+ /**
17
+ * Renders text box elements for all annotations
18
+ *
19
+ * Creates DOM structure for each text annotation. Creates text box divs
20
+ * with proper positioning and styling. Initially hidden (visibility
21
+ * controlled by updateTime).
22
+ *
23
+ * This method is idempotent - safe to call multiple times.
24
+ */
25
+ render() {
26
+ this.layerElement.innerHTML = "", this.textElements.clear(), this.annotations.forEach((t) => {
27
+ const s = p(t, this.viewport), e = document.createElement("div");
28
+ e.style.position = "absolute", e.style.left = `${s.left}px`, e.style.top = `${s.top}px`, e.style.width = `${s.width}px`, e.style.height = `${s.height}px`, e.style.backgroundColor = t.style?.bg || "rgba(255,255,255,0.9)", e.style.borderRadius = "4px", e.style.padding = "8px", e.style.fontSize = "14px", e.style.lineHeight = "1.4", e.style.color = t.style?.color || "#1f2937", e.style.fontFamily = "system-ui, -apple-system, sans-serif", e.style.display = "flex", e.style.alignItems = "center", e.style.justifyContent = "flex-start", e.style.overflow = "hidden", e.style.wordWrap = "break-word", e.style.display = "none", this.layerElement.appendChild(e), this.textElements.set(t.id, {
29
+ element: e,
30
+ annotation: t
31
+ });
32
+ });
33
+ }
34
+ /**
35
+ * Updates text box visibility and content based on timeline position
36
+ *
37
+ * Shows/hides text boxes based on start time. Calculates visible text
38
+ * for progressive reveal (typing effect). Text appears immediately when
39
+ * start time is reached and types in progressively.
40
+ *
41
+ * @param {number} nowSec - Current timeline position in seconds
42
+ */
43
+ updateTime(t) {
44
+ super.updateTime(t), this.textElements.forEach(({ element: s, annotation: e }) => {
45
+ if (t < e.start)
46
+ s.style.display = "none";
47
+ else {
48
+ s.style.display = "flex";
49
+ const l = this._getVisibleText(
50
+ e.content,
51
+ e.start,
52
+ e.end,
53
+ t
54
+ );
55
+ s.textContent = l;
56
+ }
57
+ });
58
+ }
59
+ /**
60
+ * Calculates visible text based on progress between start and end times
61
+ *
62
+ * Implements word-by-word reveal with partial character reveal for
63
+ * the current word being typed.
64
+ *
65
+ * @private
66
+ * @param {string} content - Full text content
67
+ * @param {number} start - Start time in seconds
68
+ * @param {number} end - End time in seconds
69
+ * @param {number} currentTime - Current timeline position in seconds
70
+ * @returns {string} Visible portion of text
71
+ */
72
+ _getVisibleText(t, s, e, l) {
73
+ if (l < s)
74
+ return "";
75
+ if (l >= e)
76
+ return t;
77
+ const n = (l - s) / (e - s), r = t.split(" "), i = Math.floor(n * r.length);
78
+ if (i === 0)
79
+ return "";
80
+ const o = r.slice(0, i);
81
+ if (i < r.length) {
82
+ const h = n * r.length - i, y = r[i], a = Math.floor(
83
+ h * y.length
84
+ );
85
+ a > 0 && o.push(y.slice(0, a));
86
+ }
87
+ return o.join(" ");
88
+ }
89
+ /**
90
+ * Updates the visual state of the layer
91
+ *
92
+ * Not used by TextLayer - updateTime handles all updates directly.
93
+ * Implemented to satisfy BaseLayer contract.
94
+ */
95
+ update() {
96
+ }
97
+ /**
98
+ * Destroys the layer and releases all resources
99
+ *
100
+ * Clears element storage, removes DOM elements, and calls parent cleanup.
101
+ */
102
+ destroy() {
103
+ this.textElements.clear(), this.textElements = null, this.layerElement && this.layerElement.parentNode && this.layerElement.parentNode.removeChild(this.layerElement), this.layerElement = null, super.destroy();
104
+ }
105
+ }
106
+ export {
107
+ f as default
108
+ };
109
+ //# sourceMappingURL=index8.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index8.js","sources":["../src/layers/TextLayer.js"],"sourcesContent":["import BaseLayer from \"./BaseLayer.js\";\nimport { rectNormToAbs } from \"../utils/coordinateUtils.js\";\n\n/**\n * TextLayer - Renders text annotations with progressive reveal\n *\n * Extends BaseLayer to render text box annotations with progressive\n * word-by-word text reveal animation (typing effect). Text appears\n * immediately and types in character by character, simulating real-time typing.\n *\n * @extends BaseLayer\n */\nclass TextLayer extends BaseLayer {\n /**\n * Creates a new TextLayer instance\n *\n * @param {HTMLElement} container - Parent DOM element for layer content\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 - PDF scale/zoom level\n */\n constructor(container, viewport) {\n // Call parent constructor first\n super(container, viewport);\n\n // Create layer container element\n this.layerElement = document.createElement(\"div\");\n this.layerElement.style.position = \"absolute\";\n this.layerElement.style.inset = \"0\";\n this.layerElement.style.pointerEvents = \"none\";\n this.layerElement.style.zIndex = \"30\";\n\n // Append to parent container\n this.container.appendChild(this.layerElement);\n\n // Initialize element storage (Map of id -> element)\n this.textElements = new Map();\n }\n\n /**\n * Renders text box elements for all annotations\n *\n * Creates DOM structure for each text annotation. Creates text box divs\n * with proper positioning and styling. Initially hidden (visibility\n * controlled by updateTime).\n *\n * This method is idempotent - safe to call multiple times.\n */\n render() {\n // Clear existing elements\n this.layerElement.innerHTML = \"\";\n this.textElements.clear();\n\n // Process each annotation\n this.annotations.forEach((annotation) => {\n // Convert normalized coordinates to absolute pixels\n const abs = rectNormToAbs(annotation, this.viewport);\n\n // Create text box div\n const textBox = document.createElement(\"div\");\n\n // Set positioning\n textBox.style.position = \"absolute\";\n textBox.style.left = `${abs.left}px`;\n textBox.style.top = `${abs.top}px`;\n textBox.style.width = `${abs.width}px`;\n textBox.style.height = `${abs.height}px`;\n\n // Set background and border\n textBox.style.backgroundColor =\n annotation.style?.bg || \"rgba(255,255,255,0.9)\";\n textBox.style.borderRadius = \"4px\";\n textBox.style.padding = \"8px\";\n\n // Set text styling\n textBox.style.fontSize = \"14px\";\n textBox.style.lineHeight = \"1.4\";\n textBox.style.color = annotation.style?.color || \"#1f2937\";\n textBox.style.fontFamily = \"system-ui, -apple-system, sans-serif\";\n\n // Set layout\n textBox.style.display = \"flex\";\n textBox.style.alignItems = \"center\";\n textBox.style.justifyContent = \"flex-start\";\n textBox.style.overflow = \"hidden\";\n textBox.style.wordWrap = \"break-word\";\n\n // Initially hidden (will be shown/updated in updateTime)\n textBox.style.display = \"none\";\n\n // Append to layer\n this.layerElement.appendChild(textBox);\n\n // Store reference\n this.textElements.set(annotation.id, {\n element: textBox,\n annotation: annotation,\n });\n });\n }\n\n /**\n * Updates text box visibility and content based on timeline position\n *\n * Shows/hides text boxes based on start time. Calculates visible text\n * for progressive reveal (typing effect). Text appears immediately when\n * start time is reached and types in progressively.\n *\n * @param {number} nowSec - Current timeline position in seconds\n */\n updateTime(nowSec) {\n // Call parent implementation\n super.updateTime(nowSec);\n\n // Update each text element\n this.textElements.forEach(({ element, annotation }) => {\n // Check if annotation should be visible\n if (nowSec < annotation.start) {\n // Before start time - hide\n element.style.display = \"none\";\n } else {\n // After start time - show\n element.style.display = \"flex\";\n\n // Calculate visible text\n const visibleText = this._getVisibleText(\n annotation.content,\n annotation.start,\n annotation.end,\n nowSec\n );\n\n // Update text content (typing effect)\n element.textContent = visibleText;\n }\n });\n }\n\n /**\n * Calculates visible text based on progress between start and end times\n *\n * Implements word-by-word reveal with partial character reveal for\n * the current word being typed.\n *\n * @private\n * @param {string} content - Full text content\n * @param {number} start - Start time in seconds\n * @param {number} end - End time in seconds\n * @param {number} currentTime - Current timeline position in seconds\n * @returns {string} Visible portion of text\n */\n _getVisibleText(content, start, end, currentTime) {\n // Before start - no text visible\n if (currentTime < start) {\n return \"\";\n }\n\n // After end - full text visible\n if (currentTime >= end) {\n return content;\n }\n\n // During animation - calculate progress\n const progress = (currentTime - start) / (end - start);\n\n // Split into words\n const words = content.split(\" \");\n\n // Calculate visible word count\n const visibleWordCount = Math.floor(progress * words.length);\n\n // No words visible yet\n if (visibleWordCount === 0) {\n return \"\";\n }\n\n // Get complete visible words\n const visibleWords = words.slice(0, visibleWordCount);\n\n // Add partial of the next word if not at the end\n if (visibleWordCount < words.length) {\n // Calculate progress within current word\n const currentWordProgress = progress * words.length - visibleWordCount;\n\n // Get current word being typed\n const currentWord = words[visibleWordCount];\n\n // Calculate visible character count\n const visibleCharCount = Math.floor(\n currentWordProgress * currentWord.length\n );\n\n // Add partial word if any characters are visible\n if (visibleCharCount > 0) {\n visibleWords.push(currentWord.slice(0, visibleCharCount));\n }\n }\n\n // Join words with spaces\n return visibleWords.join(\" \");\n }\n\n /**\n * Updates the visual state of the layer\n *\n * Not used by TextLayer - updateTime handles all updates directly.\n * Implemented to satisfy BaseLayer contract.\n */\n update() {\n // Not used - updateTime handles updates directly\n }\n\n /**\n * Destroys the layer and releases all resources\n *\n * Clears element storage, removes DOM elements, and calls parent cleanup.\n */\n destroy() {\n // Clear element storage\n this.textElements.clear();\n this.textElements = null;\n\n // Remove layer element from DOM\n if (this.layerElement && this.layerElement.parentNode) {\n this.layerElement.parentNode.removeChild(this.layerElement);\n }\n this.layerElement = null;\n\n // Call parent destroy\n super.destroy();\n }\n}\n\nexport default TextLayer;\n"],"names":["TextLayer","BaseLayer","container","viewport","annotation","abs","rectNormToAbs","textBox","nowSec","element","visibleText","content","start","end","currentTime","progress","words","visibleWordCount","visibleWords","currentWordProgress","currentWord","visibleCharCount"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ "use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const c=require("./index6.cjs");class d extends c.default{constructor(t,s){super(t,s),this.canvasElement=document.createElement("canvas"),this.canvasElement.style.position="absolute",this.canvasElement.style.inset="0",this.canvasElement.style.pointerEvents="none",this.canvasElement.style.zIndex="40",this.container.appendChild(this.canvasElement),this.ctx=this.canvasElement.getContext("2d"),this.rafId=null,this._setupCanvas()}_setupCanvas(){const t=window.devicePixelRatio||1;this.canvasElement.width=Math.round(this.viewport.width*t),this.canvasElement.height=Math.round(this.viewport.height*t),this.canvasElement.style.width=`${this.viewport.width}px`,this.canvasElement.style.height=`${this.viewport.height}px`,this.ctx.setTransform(t,0,0,t,0,0)}setViewport(t){super.setViewport(t),this._setupCanvas()}updateTime(t){super.updateTime(t),this.rafId&&cancelAnimationFrame(this.rafId);const s=()=>{if(!this.isDestroyed){this.ctx.clearRect(0,0,this.canvasElement.width,this.canvasElement.height);for(const e of this.annotations){if(t<e.start)continue;const o=e.end-e.start,l=Math.min(t-e.start,o);for(const i of e.strokes||[]){this.ctx.lineCap="round",this.ctx.lineJoin="round",this.ctx.strokeStyle=i.color||"#1f2937",this.ctx.lineWidth=i.size||3,this.ctx.beginPath();let n=!1;for(const a of i.points){if(a.t>l)break;const h=a.x*this.viewport.width,r=a.y*this.viewport.height;n?this.ctx.lineTo(h,r):(this.ctx.moveTo(h,r),n=!0)}n&&this.ctx.stroke()}}this.rafId=requestAnimationFrame(s)}};s()}render(){}update(){}destroy(){this.rafId&&(cancelAnimationFrame(this.rafId),this.rafId=null),this.ctx=null,this.canvasElement&&this.canvasElement.parentNode&&this.canvasElement.parentNode.removeChild(this.canvasElement),this.canvasElement=null,super.destroy()}}exports.default=d;
2
+ //# sourceMappingURL=index9.cjs.map