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.
Files changed (96) hide show
  1. package/dist/index.cjs +1 -1
  2. package/dist/index.cjs.map +1 -1
  3. package/dist/index.js +49 -42
  4. package/dist/index.js.map +1 -1
  5. package/dist/index10.cjs +1 -1
  6. package/dist/index10.cjs.map +1 -1
  7. package/dist/index10.js +172 -17
  8. package/dist/index10.js.map +1 -1
  9. package/dist/index11.cjs +1 -1
  10. package/dist/index11.cjs.map +1 -1
  11. package/dist/index11.js +13 -20
  12. package/dist/index11.js.map +1 -1
  13. package/dist/index12.cjs +1 -1
  14. package/dist/index12.cjs.map +1 -1
  15. package/dist/index12.js +167 -124
  16. package/dist/index12.js.map +1 -1
  17. package/dist/index13.cjs +1 -1
  18. package/dist/index13.cjs.map +1 -1
  19. package/dist/index13.js +29 -198
  20. package/dist/index13.js.map +1 -1
  21. package/dist/index14.cjs +1 -1
  22. package/dist/index14.cjs.map +1 -1
  23. package/dist/index14.js +78 -15
  24. package/dist/index14.js.map +1 -1
  25. package/dist/index15.cjs +1 -1
  26. package/dist/index15.cjs.map +1 -1
  27. package/dist/index15.js +115 -120
  28. package/dist/index15.js.map +1 -1
  29. package/dist/index16.cjs +1 -1
  30. package/dist/index16.cjs.map +1 -1
  31. package/dist/index16.js +100 -212
  32. package/dist/index16.js.map +1 -1
  33. package/dist/index17.cjs +1 -1
  34. package/dist/index17.cjs.map +1 -1
  35. package/dist/index17.js +55 -37
  36. package/dist/index17.js.map +1 -1
  37. package/dist/index18.cjs +1 -1
  38. package/dist/index18.cjs.map +1 -1
  39. package/dist/index18.js +139 -35
  40. package/dist/index18.js.map +1 -1
  41. package/dist/index19.cjs +1 -1
  42. package/dist/index19.cjs.map +1 -1
  43. package/dist/index19.js +37 -37
  44. package/dist/index19.js.map +1 -1
  45. package/dist/index2.cjs +1 -1
  46. package/dist/index2.cjs.map +1 -1
  47. package/dist/index2.js +95 -73
  48. package/dist/index2.js.map +1 -1
  49. package/dist/index20.cjs +1 -1
  50. package/dist/index20.cjs.map +1 -1
  51. package/dist/index20.js +29 -39
  52. package/dist/index20.js.map +1 -1
  53. package/dist/index21.cjs +1 -1
  54. package/dist/index21.cjs.map +1 -1
  55. package/dist/index21.js +38 -32
  56. package/dist/index21.js.map +1 -1
  57. package/dist/index22.cjs +1 -1
  58. package/dist/index22.cjs.map +1 -1
  59. package/dist/index22.js +22 -5
  60. package/dist/index22.js.map +1 -1
  61. package/dist/index23.cjs +2 -0
  62. package/dist/index23.cjs.map +1 -0
  63. package/dist/index23.js +8 -0
  64. package/dist/index23.js.map +1 -0
  65. package/dist/index24.cjs +2 -0
  66. package/dist/index24.cjs.map +1 -0
  67. package/dist/index24.js +8 -0
  68. package/dist/index24.js.map +1 -0
  69. package/dist/index3.cjs +1 -1
  70. package/dist/index3.cjs.map +1 -1
  71. package/dist/index3.js +1 -1
  72. package/dist/index4.cjs +1 -1
  73. package/dist/index4.cjs.map +1 -1
  74. package/dist/index4.js +72 -71
  75. package/dist/index4.js.map +1 -1
  76. package/dist/index5.cjs +1 -1
  77. package/dist/index5.cjs.map +1 -1
  78. package/dist/index5.js +217 -65
  79. package/dist/index5.js.map +1 -1
  80. package/dist/index6.cjs +1 -1
  81. package/dist/index6.cjs.map +1 -1
  82. package/dist/index6.js +60 -114
  83. package/dist/index6.js.map +1 -1
  84. package/dist/index7.cjs +1 -1
  85. package/dist/index7.cjs.map +1 -1
  86. package/dist/index7.js +19 -91
  87. package/dist/index7.js.map +1 -1
  88. package/dist/index8.cjs +1 -1
  89. package/dist/index8.cjs.map +1 -1
  90. package/dist/index8.js +19 -105
  91. package/dist/index8.js.map +1 -1
  92. package/dist/index9.cjs +1 -1
  93. package/dist/index9.cjs.map +1 -1
  94. package/dist/index9.js +123 -98
  95. package/dist/index9.js.map +1 -1
  96. package/package.json +4 -3
package/dist/index6.js CHANGED
@@ -1,119 +1,65 @@
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`);
1
+ function s(t) {
2
+ if (t == null)
3
+ return Math.random;
4
+ let n = typeof t == "string" ? t.split("").reduce((e, r) => e + r.charCodeAt(0), 0) : t;
5
+ return function() {
6
+ n |= 0, n = n + 1831565813 | 0;
7
+ let e = Math.imul(n ^ n >>> 15, 1 | n);
8
+ return e = e + Math.imul(e ^ e >>> 7, 61 | e) ^ e, ((e ^ e >>> 14) >>> 0) / 4294967296;
9
+ };
10
+ }
11
+ function M(t, n, e = null) {
12
+ const { amplitude: r = 0 } = n || {};
13
+ if (r === 0 || !t || t.length === 0)
14
+ return t;
15
+ const u = s(e);
16
+ return t.map(([l, f]) => [
17
+ l + (u() - 0.5) * r,
18
+ f + (u() - 0.5) * r
19
+ ]);
20
+ }
21
+ function b(t, n) {
22
+ const { taperIn: e = 0, taperOut: r = 0 } = n || {};
23
+ if (!t || t.length === 0)
24
+ return [];
25
+ if (e === 0 && r === 0)
26
+ return t.map(() => 1);
27
+ const u = t.length;
28
+ return t.map((l, f) => {
29
+ const c = u > 1 ? f / (u - 1) : 0;
30
+ return e > 0 && c < e ? c / e : r > 0 && c > 1 - r ? (1 - c) / r : 1;
31
+ });
32
+ }
33
+ function A(t, n) {
34
+ const { amplitude: e = 0, frequency: r = 0.05 } = n || {};
35
+ return e === 0 || !t || t.length < 2 ? t : t.map(([u, l], f) => {
36
+ const c = f / (t.length - 1), h = Math.sin(c * Math.PI * 2 * r * t.length) * e;
37
+ let y = 0, d = 1;
38
+ if (f < t.length - 1) {
39
+ const [m, p] = t[f + 1], a = m - u, o = p - l, i = Math.sqrt(a * a + o * o);
40
+ i > 1e-4 && (y = -o / i, d = a / i);
41
+ }
42
+ return [
43
+ u + y * h,
44
+ l + d * h
45
+ ];
46
+ });
47
+ }
48
+ function g(t, n) {
49
+ if (!n) return { ...t };
50
+ if (!t) return { ...n };
51
+ const e = { ...t };
52
+ for (const r of Object.keys(n)) {
53
+ const u = n[r], l = t[r];
54
+ u !== null && typeof u == "object" && !Array.isArray(u) && l !== null && typeof l == "object" && !Array.isArray(l) ? e[r] = g(l, u) : u !== void 0 && (e[r] = u);
114
55
  }
56
+ return e;
115
57
  }
116
58
  export {
117
- r as default
59
+ M as applyJitter,
60
+ b as applyPressure,
61
+ A as applyWobble,
62
+ g as deepMerge,
63
+ s as seededRandom
118
64
  };
119
65
  //# sourceMappingURL=index6.js.map
@@ -1 +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;"}
1
+ {"version":3,"file":"index6.js","sources":["../src/pen/effects.js"],"sourcesContent":["/**\n * Pen Effects - Utility functions for hand-drawn feel\n *\n * Provides jitter, pressure, and wobble effects for stroke paths.\n * Pure functions that transform point arrays without side effects.\n *\n * @module pen/effects\n */\n\n/**\n * Creates a seeded random number generator\n *\n * Uses mulberry32 algorithm for deterministic randomness.\n * Same seed produces same sequence of random numbers.\n *\n * @param {string|number|null} seed - Seed value (null uses Math.random)\n * @returns {Function} Function that returns random numbers 0-1\n */\nexport function seededRandom(seed) {\n if (seed === null || seed === undefined) {\n return Math.random;\n }\n\n // Convert string seed to number\n let numSeed = typeof seed === 'string'\n ? seed.split('').reduce((acc, char) => acc + char.charCodeAt(0), 0)\n : seed;\n\n // Mulberry32 algorithm\n return function() {\n numSeed |= 0;\n numSeed = (numSeed + 0x6D2B79F5) | 0;\n let t = Math.imul(numSeed ^ (numSeed >>> 15), 1 | numSeed);\n t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t;\n return ((t ^ (t >>> 14)) >>> 0) / 4294967296;\n };\n}\n\n/**\n * Applies random jitter offset to points\n *\n * Adds small random displacement to each point for hand-drawn imperfection.\n * Returns new array, does not mutate input.\n *\n * @param {Array<[number, number]>} points - Array of [x, y] coordinates\n * @param {Object} config - Jitter configuration\n * @param {number} config.amplitude - Max offset in normalized units (0 = disabled)\n * @param {number} [config.frequency=1] - Not currently used, reserved for future\n * @param {string|number|null} [seed=null] - Seed for reproducible randomness\n * @returns {Array<[number, number]>} New array with jittered points\n */\nexport function applyJitter(points, config, seed = null) {\n const { amplitude = 0 } = config || {};\n\n if (amplitude === 0 || !points || points.length === 0) {\n return points;\n }\n\n const rng = seededRandom(seed);\n\n return points.map(([x, y]) => [\n x + (rng() - 0.5) * amplitude,\n y + (rng() - 0.5) * amplitude\n ]);\n}\n\n/**\n * Calculates pressure values for variable stroke width\n *\n * Simulates pen pressure with taper at start and end of stroke.\n * Returns pressure multipliers (0-1) for each point.\n *\n * @param {Array<[number, number]>} points - Array of [x, y] coordinates\n * @param {Object} config - Pressure configuration\n * @param {number} [config.taperIn=0] - Start taper length (0-1, fraction of stroke)\n * @param {number} [config.taperOut=0] - End taper length (0-1, fraction of stroke)\n * @returns {Array<number>} Pressure values (0-1) per point\n */\nexport function applyPressure(points, config) {\n const { taperIn = 0, taperOut = 0 } = config || {};\n\n if (!points || points.length === 0) {\n return [];\n }\n\n if (taperIn === 0 && taperOut === 0) {\n return points.map(() => 1.0);\n }\n\n const len = points.length;\n\n return points.map((_, i) => {\n const t = len > 1 ? i / (len - 1) : 0;\n\n // Taper in at start\n if (taperIn > 0 && t < taperIn) {\n return t / taperIn;\n }\n\n // Taper out at end\n if (taperOut > 0 && t > 1 - taperOut) {\n return (1 - t) / taperOut;\n }\n\n // Full pressure in middle\n return 1.0;\n });\n}\n\n/**\n * Applies low-frequency wobble perpendicular to stroke direction\n *\n * Adds gentle wave effect to simulate natural hand movement.\n * Returns new array, does not mutate input.\n *\n * @param {Array<[number, number]>} points - Array of [x, y] coordinates\n * @param {Object} config - Wobble configuration\n * @param {number} config.amplitude - Wave height in normalized units (0 = disabled)\n * @param {number} [config.frequency=0.05] - Wave frequency\n * @returns {Array<[number, number]>} New array with wobbled points\n */\nexport function applyWobble(points, config) {\n const { amplitude = 0, frequency = 0.05 } = config || {};\n\n if (amplitude === 0 || !points || points.length < 2) {\n return points;\n }\n\n return points.map(([x, y], i) => {\n // Calculate perpendicular direction based on position in stroke\n // Use simple sine wave for now\n const t = i / (points.length - 1);\n const offset = Math.sin(t * Math.PI * 2 * frequency * points.length) * amplitude;\n\n // Calculate perpendicular direction from neighbors\n let perpX = 0;\n let perpY = 1;\n\n if (i < points.length - 1) {\n const [nx, ny] = points[i + 1];\n const dx = nx - x;\n const dy = ny - y;\n const len = Math.sqrt(dx * dx + dy * dy);\n\n if (len > 0.0001) {\n // Perpendicular is (-dy, dx) normalized\n perpX = -dy / len;\n perpY = dx / len;\n }\n }\n\n return [\n x + perpX * offset,\n y + perpY * offset\n ];\n });\n}\n\n/**\n * Deep merges configuration objects\n *\n * Merges source into target, handling nested objects.\n * Returns new object, does not mutate inputs.\n *\n * @param {Object} target - Target object\n * @param {Object} source - Source object to merge\n * @returns {Object} Merged object\n */\nexport function deepMerge(target, source) {\n if (!source) return { ...target };\n if (!target) return { ...source };\n\n const result = { ...target };\n\n for (const key of Object.keys(source)) {\n const sourceVal = source[key];\n const targetVal = target[key];\n\n if (\n sourceVal !== null &&\n typeof sourceVal === 'object' &&\n !Array.isArray(sourceVal) &&\n targetVal !== null &&\n typeof targetVal === 'object' &&\n !Array.isArray(targetVal)\n ) {\n result[key] = deepMerge(targetVal, sourceVal);\n } else if (sourceVal !== undefined) {\n result[key] = sourceVal;\n }\n }\n\n return result;\n}\n"],"names":["seededRandom","seed","numSeed","acc","char","t","applyJitter","points","config","amplitude","rng","x","y","applyPressure","taperIn","taperOut","len","_","i","applyWobble","frequency","offset","perpX","perpY","nx","ny","dx","dy","deepMerge","target","source","result","key","sourceVal","targetVal"],"mappings":"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"}
package/dist/index7.cjs CHANGED
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const c=require("./index6.cjs"),u=require("./index10.cjs");class p extends c.default{constructor(e,a){super(e,a),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}render(){this.layerElement.innerHTML="",this.elements.clear(),this.annotations.forEach(e=>{if(e.mode!=="quads"||!e.quads?.length)return;const a=e.quads.reduce((r,s)=>r+s.w,0);e.quads.forEach((r,s)=>{const i=u.rectNormToAbs(r,this.viewport),n=e.quads.slice(0,s).reduce((y,m)=>y+m.w,0),h=n/a,d=(n+r.w)/a,t=document.createElement("div");t.style.position="absolute",t.style.left=`${i.left}px`,t.style.top=`${i.top}px`,t.style.width=`${i.width}px`,t.style.height=`${i.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}-${s}`;this.elements.set(o,{element:l,wrapper:t,annotation:e,segStart:h,segEnd:d})})})}updateTime(e){super.updateTime(e),!this.isDestroyed&&this.elements.forEach(({element:a,wrapper:r,annotation:s,segStart:i,segEnd:n})=>{if(e<s.start)r.style.display="none";else{r.style.display="block";const h=Math.max(0,Math.min(1,(e-s.start)/Math.max(1e-6,s.end-s.start))),d=Math.max(0,Math.min(1,(h-i)/Math.max(1e-6,n-i)));a.style.transform=`scaleX(${d})`}})}update(){}destroy(){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;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=(t,h)=>({left:t.x*h.width,top:t.y*h.height,width:(t.w??0)*h.width,height:(t.h??0)*h.height}),i=(t,h)=>({left:t.x*h.width,top:t.y*h.height,width:(t.w??0)*h.width,height:(t.h??0)*h.height});function o(t,h){return{x:t.x*h.width,y:t.y*h.height}}exports.NormSizeToPixel=i;exports.pointNormToAbs=o;exports.rectNormToAbs=e;
2
2
  //# sourceMappingURL=index7.cjs.map
@@ -1 +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\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 * Updates scaleX transform for each highlight element based on timeline.\n * Calculates progress for each quad segment and updates visibility.\n * Renders once per call - no continuous loop.\n *\n * @param {number} nowSec - Current timeline position in seconds\n */\n updateTime(nowSec) {\n super.updateTime(nowSec);\n\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\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 * Clears element storage, removes DOM elements, and calls parent cleanup.\n */\n destroy() {\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","element","globalProgress","localProgress"],"mappings":"uKAYA,MAAMA,UAAuBC,EAAAA,OAAU,CAUrC,YAAYC,EAAWC,EAAU,CAC/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,KAEjC,KAAK,UAAU,YAAY,KAAK,YAAY,EAG5C,KAAK,SAAW,IAAI,GACtB,CASA,QAAS,CAEP,KAAK,aAAa,UAAY,GAC9B,KAAK,SAAS,MAAK,EAGnB,KAAK,YAAY,QAASC,GAAe,CAEvC,GAAIA,EAAW,OAAS,SAAW,CAACA,EAAW,OAAO,OACpD,OAIF,MAAMC,EAASD,EAAW,MAAM,OAAO,CAACE,EAAKC,IAASD,EAAMC,EAAK,EAAG,CAAC,EAGrEH,EAAW,MAAM,QAAQ,CAACG,EAAMC,IAAQ,CAEtC,MAAMC,EAAMC,EAAAA,cAAcH,EAAM,KAAK,QAAQ,EAGvCI,EAAQP,EAAW,MAAM,MAAM,EAAGI,CAAG,EAAE,OAAO,CAACF,EAAKM,IAAMN,EAAMM,EAAE,EAAG,CAAC,EACtEC,EAAWF,EAAQN,EACnBS,GAAUH,EAAQJ,EAAK,GAAKF,EAG5BU,EAAU,SAAS,cAAc,KAAK,EAC5CA,EAAQ,MAAM,SAAW,WACzBA,EAAQ,MAAM,KAAO,GAAGN,EAAI,IAAI,KAChCM,EAAQ,MAAM,IAAM,GAAGN,EAAI,GAAG,KAC9BM,EAAQ,MAAM,MAAQ,GAAGN,EAAI,KAAK,KAClCM,EAAQ,MAAM,OAAS,GAAGN,EAAI,MAAM,KACpCM,EAAQ,MAAM,SAAW,SACzBA,EAAQ,MAAM,aAAe,MAG7B,MAAMC,EAAY,SAAS,cAAc,KAAK,EAC9CA,EAAU,MAAM,MAAQ,OACxBA,EAAU,MAAM,OAAS,OACzBA,EAAU,MAAM,WAAaZ,GAAY,OAAO,OAAS,yBACzDY,EAAU,MAAM,QAAU,gCAC1BA,EAAU,MAAM,gBAAkB,cAClCA,EAAU,MAAM,UAAY,YAC5BA,EAAU,MAAM,WAAa,YAG7BD,EAAQ,YAAYC,CAAS,EAC7B,KAAK,aAAa,YAAYD,CAAO,EAGrC,MAAME,EAAM,GAAGb,EAAW,EAAE,IAAII,CAAG,GACnC,KAAK,SAAS,IAAIS,EAAK,CACrB,QAASD,EACT,QAASD,EACT,WAAYX,EACZ,SAAUS,EACV,OAAQC,CAClB,CAAS,CACH,CAAC,CACH,CAAC,CACH,CAWA,WAAWI,EAAQ,CACjB,MAAM,WAAWA,CAAM,EAEnB,MAAK,aAKT,KAAK,SAAS,QAAQ,CAAC,CAAE,QAAAC,EAAS,QAAAJ,EAAS,WAAAX,EAAY,SAAAS,EAAU,OAAAC,KAAa,CAE5E,GAAII,EAASd,EAAW,MACtBW,EAAQ,MAAM,QAAU,WACnB,CAELA,EAAQ,MAAM,QAAU,QAGxB,MAAMK,EAAiB,KAAK,IAC1B,EACA,KAAK,IACH,GACCF,EAASd,EAAW,OAAS,KAAK,IAAI,KAAMA,EAAW,IAAMA,EAAW,KAAK,CAC1F,CACA,EAGciB,EAAgB,KAAK,IACzB,EACA,KAAK,IACH,GACCD,EAAiBP,GAAY,KAAK,IAAI,KAAMC,EAASD,CAAQ,CAC1E,CACA,EAGQM,EAAQ,MAAM,UAAY,UAAUE,CAAa,GACnD,CACF,CAAC,CACH,CAOA,QAAS,CAET,CAOA,SAAU,CAER,KAAK,SAAS,MAAK,EACnB,KAAK,SAAW,KAGZ,KAAK,cAAgB,KAAK,aAAa,YACzC,KAAK,aAAa,WAAW,YAAY,KAAK,YAAY,EAE5D,KAAK,aAAe,KAGpB,MAAM,QAAO,CACf,CACF"}
1
+ {"version":3,"file":"index7.cjs","sources":["../src/utils/coordinateUtils.js"],"sourcesContent":["/**\n * Coordinate Utility Functions\n *\n * This module provides utility functions for coordinate transformations\n * between normalized (0-1) coordinates and absolute pixel coordinates.\n * Used by annotation layers to position elements on the PDF canvas.\n */\n\n/**\n * Convert normalized rectangle to absolute pixel coordinates\n *\n * Transforms a rectangle with normalized coordinates (0-1 range) to\n * absolute pixel coordinates based on viewport dimensions.\n *\n * @param {{x: number, y: number, w: number, h: number}} rect - Normalized rectangle (0-1)\n * @param {{width: number, height: number}} viewport - Viewport dimensions in pixels\n * @returns {{left: number, top: number, width: number, height: number}} Absolute coordinates in pixels\n *\n * @example\n * const rect = { x: 0.1, y: 0.2, w: 0.5, h: 0.3 };\n * const viewport = { width: 1000, height: 1400 };\n * const absolute = rectNormToAbs(rect, viewport);\n * // Returns: { left: 100, top: 280, width: 500, height: 420 }\n */\nexport const rectNormToAbs = (r, vp) => ({\n left: r.x * vp.width,\n top: r.y * vp.height,\n width: (r.w ?? 0) * vp.width,\n height: (r.h ?? 0) * vp.height,\n});\n\n/**\n * Convert normalized size to pixel dimensions (Legacy)\n *\n * @deprecated Use rectNormToAbs instead. This function is kept for backward compatibility.\n *\n * Transforms normalized rectangle coordinates to absolute pixel coordinates.\n * This is an alias for rectNormToAbs maintained for backward compatibility.\n *\n * @param {{x: number, y: number, w: number, h: number}} r - Normalized rectangle (0-1)\n * @param {{width: number, height: number}} vp - Viewport dimensions in pixels\n * @returns {{left: number, top: number, width: number, height: number}} Absolute coordinates in pixels\n */\nexport const NormSizeToPixel = (r, vp) => ({\n left: r.x * vp.width,\n top: r.y * vp.height,\n width: (r.w ?? 0) * vp.width,\n height: (r.h ?? 0) * vp.height,\n});\n\n/**\n * Convert normalized point to absolute pixel coordinates\n *\n * Transforms a point with normalized coordinates (0-1 range) to\n * absolute pixel coordinates based on viewport dimensions.\n *\n * @param {{x: number, y: number}} point - Normalized point (0-1)\n * @param {{width: number, height: number}} viewport - Viewport dimensions in pixels\n * @returns {{x: number, y: number}} Absolute coordinates in pixels\n *\n * @example\n * const point = { x: 0.5, y: 0.5 };\n * const viewport = { width: 1000, height: 1400 };\n * const absolute = pointNormToAbs(point, viewport);\n * // Returns: { x: 500, y: 700 }\n */\nexport function pointNormToAbs(point, viewport) {\n return {\n x: point.x * viewport.width,\n y: point.y * viewport.height\n };\n}\n"],"names":["rectNormToAbs","r","vp","NormSizeToPixel","pointNormToAbs","point","viewport"],"mappings":"gFAwBY,MAACA,EAAgB,CAACC,EAAGC,KAAQ,CACvC,KAAMD,EAAE,EAAIC,EAAG,MACf,IAAKD,EAAE,EAAIC,EAAG,OACd,OAAQD,EAAE,GAAK,GAAKC,EAAG,MACvB,QAASD,EAAE,GAAK,GAAKC,EAAG,MAC1B,GAcaC,EAAkB,CAACF,EAAGC,KAAQ,CACzC,KAAMD,EAAE,EAAIC,EAAG,MACf,IAAKD,EAAE,EAAIC,EAAG,OACd,OAAQD,EAAE,GAAK,GAAKC,EAAG,MACvB,QAASD,EAAE,GAAK,GAAKC,EAAG,MAC1B,GAkBO,SAASE,EAAeC,EAAOC,EAAU,CAC9C,MAAO,CACL,EAAGD,EAAM,EAAIC,EAAS,MACtB,EAAGD,EAAM,EAAIC,EAAS,MAC1B,CACA"}
package/dist/index7.js CHANGED
@@ -1,95 +1,23 @@
1
- import p from "./index6.js";
2
- import { rectNormToAbs as c } from "./index10.js";
3
- class f extends p {
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, a) {
14
- super(e, a), 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();
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 a = e.quads.reduce((r, s) => r + s.w, 0);
28
- e.quads.forEach((r, s) => {
29
- const i = c(r, this.viewport), h = e.quads.slice(0, s).reduce((o, y) => o + y.w, 0), n = h / a, d = (h + r.w) / a, t = document.createElement("div");
30
- t.style.position = "absolute", t.style.left = `${i.left}px`, t.style.top = `${i.top}px`, t.style.width = `${i.width}px`, t.style.height = `${i.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}-${s}`;
34
- this.elements.set(m, {
35
- element: l,
36
- wrapper: t,
37
- annotation: e,
38
- segStart: n,
39
- segEnd: d
40
- });
41
- });
42
- });
43
- }
44
- /**
45
- * Updates highlight animations based on current timeline position
46
- *
47
- * Updates scaleX transform for each highlight element based on timeline.
48
- * Calculates progress for each quad segment and updates visibility.
49
- * Renders once per call - no continuous loop.
50
- *
51
- * @param {number} nowSec - Current timeline position in seconds
52
- */
53
- updateTime(e) {
54
- super.updateTime(e), !this.isDestroyed && this.elements.forEach(({ element: a, wrapper: r, annotation: s, segStart: i, segEnd: h }) => {
55
- if (e < s.start)
56
- r.style.display = "none";
57
- else {
58
- r.style.display = "block";
59
- const n = Math.max(
60
- 0,
61
- Math.min(
62
- 1,
63
- (e - s.start) / Math.max(1e-6, s.end - s.start)
64
- )
65
- ), d = Math.max(
66
- 0,
67
- Math.min(
68
- 1,
69
- (n - i) / Math.max(1e-6, h - i)
70
- )
71
- );
72
- a.style.transform = `scaleX(${d})`;
73
- }
74
- });
75
- }
76
- /**
77
- * Updates the visual state of the layer
78
- *
79
- * Not used by HighlightLayer - animation handled in updateTime()
80
- */
81
- update() {
82
- }
83
- /**
84
- * Destroys the layer and releases all resources
85
- *
86
- * Clears element storage, removes DOM elements, and calls parent cleanup.
87
- */
88
- destroy() {
89
- this.elements.clear(), this.elements = null, this.layerElement && this.layerElement.parentNode && this.layerElement.parentNode.removeChild(this.layerElement), this.layerElement = null, super.destroy();
90
- }
1
+ const i = (h, t) => ({
2
+ left: h.x * t.width,
3
+ top: h.y * t.height,
4
+ width: (h.w ?? 0) * t.width,
5
+ height: (h.h ?? 0) * t.height
6
+ }), e = (h, t) => ({
7
+ left: h.x * t.width,
8
+ top: h.y * t.height,
9
+ width: (h.w ?? 0) * t.width,
10
+ height: (h.h ?? 0) * t.height
11
+ });
12
+ function o(h, t) {
13
+ return {
14
+ x: h.x * t.width,
15
+ y: h.y * t.height
16
+ };
91
17
  }
92
18
  export {
93
- f as default
19
+ e as NormSizeToPixel,
20
+ o as pointNormToAbs,
21
+ i as rectNormToAbs
94
22
  };
95
23
  //# sourceMappingURL=index7.js.map
@@ -1 +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\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 * Updates scaleX transform for each highlight element based on timeline.\n * Calculates progress for each quad segment and updates visibility.\n * Renders once per call - no continuous loop.\n *\n * @param {number} nowSec - Current timeline position in seconds\n */\n updateTime(nowSec) {\n super.updateTime(nowSec);\n\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\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 * Clears element storage, removes DOM elements, and calls parent cleanup.\n */\n destroy() {\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","element","globalProgress","localProgress"],"mappings":"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"}
1
+ {"version":3,"file":"index7.js","sources":["../src/utils/coordinateUtils.js"],"sourcesContent":["/**\n * Coordinate Utility Functions\n *\n * This module provides utility functions for coordinate transformations\n * between normalized (0-1) coordinates and absolute pixel coordinates.\n * Used by annotation layers to position elements on the PDF canvas.\n */\n\n/**\n * Convert normalized rectangle to absolute pixel coordinates\n *\n * Transforms a rectangle with normalized coordinates (0-1 range) to\n * absolute pixel coordinates based on viewport dimensions.\n *\n * @param {{x: number, y: number, w: number, h: number}} rect - Normalized rectangle (0-1)\n * @param {{width: number, height: number}} viewport - Viewport dimensions in pixels\n * @returns {{left: number, top: number, width: number, height: number}} Absolute coordinates in pixels\n *\n * @example\n * const rect = { x: 0.1, y: 0.2, w: 0.5, h: 0.3 };\n * const viewport = { width: 1000, height: 1400 };\n * const absolute = rectNormToAbs(rect, viewport);\n * // Returns: { left: 100, top: 280, width: 500, height: 420 }\n */\nexport const rectNormToAbs = (r, vp) => ({\n left: r.x * vp.width,\n top: r.y * vp.height,\n width: (r.w ?? 0) * vp.width,\n height: (r.h ?? 0) * vp.height,\n});\n\n/**\n * Convert normalized size to pixel dimensions (Legacy)\n *\n * @deprecated Use rectNormToAbs instead. This function is kept for backward compatibility.\n *\n * Transforms normalized rectangle coordinates to absolute pixel coordinates.\n * This is an alias for rectNormToAbs maintained for backward compatibility.\n *\n * @param {{x: number, y: number, w: number, h: number}} r - Normalized rectangle (0-1)\n * @param {{width: number, height: number}} vp - Viewport dimensions in pixels\n * @returns {{left: number, top: number, width: number, height: number}} Absolute coordinates in pixels\n */\nexport const NormSizeToPixel = (r, vp) => ({\n left: r.x * vp.width,\n top: r.y * vp.height,\n width: (r.w ?? 0) * vp.width,\n height: (r.h ?? 0) * vp.height,\n});\n\n/**\n * Convert normalized point to absolute pixel coordinates\n *\n * Transforms a point with normalized coordinates (0-1 range) to\n * absolute pixel coordinates based on viewport dimensions.\n *\n * @param {{x: number, y: number}} point - Normalized point (0-1)\n * @param {{width: number, height: number}} viewport - Viewport dimensions in pixels\n * @returns {{x: number, y: number}} Absolute coordinates in pixels\n *\n * @example\n * const point = { x: 0.5, y: 0.5 };\n * const viewport = { width: 1000, height: 1400 };\n * const absolute = pointNormToAbs(point, viewport);\n * // Returns: { x: 500, y: 700 }\n */\nexport function pointNormToAbs(point, viewport) {\n return {\n x: point.x * viewport.width,\n y: point.y * viewport.height\n };\n}\n"],"names":["rectNormToAbs","r","vp","NormSizeToPixel","pointNormToAbs","point","viewport"],"mappings":"AAwBY,MAACA,IAAgB,CAACC,GAAGC,OAAQ;AAAA,EACvC,MAAMD,EAAE,IAAIC,EAAG;AAAA,EACf,KAAKD,EAAE,IAAIC,EAAG;AAAA,EACd,QAAQD,EAAE,KAAK,KAAKC,EAAG;AAAA,EACvB,SAASD,EAAE,KAAK,KAAKC,EAAG;AAC1B,IAcaC,IAAkB,CAACF,GAAGC,OAAQ;AAAA,EACzC,MAAMD,EAAE,IAAIC,EAAG;AAAA,EACf,KAAKD,EAAE,IAAIC,EAAG;AAAA,EACd,QAAQD,EAAE,KAAK,KAAKC,EAAG;AAAA,EACvB,SAASD,EAAE,KAAK,KAAKC,EAAG;AAC1B;AAkBO,SAASE,EAAeC,GAAOC,GAAU;AAC9C,SAAO;AAAA,IACL,GAAGD,EAAM,IAAIC,EAAS;AAAA,IACtB,GAAGD,EAAM,IAAIC,EAAS;AAAA,EAC1B;AACA;"}
package/dist/index8.cjs CHANGED
@@ -1,2 +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;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});function n(e,t){if(!e)throw new Error("Page object is required");return e.getViewport({scale:t})}function r(e){return e?{width:e.width,height:e.height}:{width:0,height:0}}function o(e,t,i){return{width:e*i,height:t*i}}exports.calculateScaledDimensions=o;exports.calculateViewport=n;exports.getViewportDimensions=r;
2
2
  //# sourceMappingURL=index8.cjs.map
@@ -1 +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"}
1
+ {"version":3,"file":"index8.cjs","sources":["../src/utils/viewportUtils.js"],"sourcesContent":["/**\n * Viewport Utility Functions\n *\n * This module provides utility functions for PDF viewport calculations\n * and transformations. These functions are used by the PDF viewer to\n * calculate viewport dimensions and manage scaling.\n */\n\n/**\n * Calculate viewport from PDF page\n *\n * Creates a viewport object from a PDF.js page with the specified scale.\n * The viewport contains dimensions and transformation matrix for rendering.\n *\n * @param {Object} page - PDF.js page object\n * @param {number} scale - Scale factor for rendering\n * @returns {Object} Viewport object with width, height, and transform matrix\n *\n * @example\n * const viewport = calculateViewport(pdfPage, 1.5);\n * // Returns: { width: 1200, height: 1600, scale: 1.5, ... }\n */\nexport function calculateViewport(page, scale) {\n if (!page) {\n throw new Error('Page object is required');\n }\n\n return page.getViewport({ scale });\n}\n\n/**\n * Get viewport dimensions\n *\n * Extracts width and height from a viewport object.\n * Useful for coordinate transformations and layout calculations.\n *\n * @param {Object} viewport - Viewport object from PDF.js\n * @returns {{width: number, height: number}} Dimensions object\n *\n * @example\n * const { width, height } = getViewportDimensions(viewport);\n * // Returns: { width: 1200, height: 1600 }\n */\nexport function getViewportDimensions(viewport) {\n if (!viewport) {\n return { width: 0, height: 0 };\n }\n\n return {\n width: viewport.width,\n height: viewport.height\n };\n}\n\n/**\n * Calculate scaled dimensions\n *\n * Calculates dimensions for a given scale factor.\n * Used when zoom level changes to determine new canvas size.\n *\n * @param {number} baseWidth - Original width\n * @param {number} baseHeight - Original height\n * @param {number} scale - Scale factor\n * @returns {{width: number, height: number}} Scaled dimensions\n *\n * @example\n * const scaled = calculateScaledDimensions(800, 1000, 1.5);\n * // Returns: { width: 1200, height: 1500 }\n */\nexport function calculateScaledDimensions(baseWidth, baseHeight, scale) {\n return {\n width: baseWidth * scale,\n height: baseHeight * scale\n };\n}\n"],"names":["calculateViewport","page","scale","getViewportDimensions","viewport","calculateScaledDimensions","baseWidth","baseHeight"],"mappings":"gFAsBO,SAASA,EAAkBC,EAAMC,EAAO,CAC7C,GAAI,CAACD,EACH,MAAM,IAAI,MAAM,yBAAyB,EAG3C,OAAOA,EAAK,YAAY,CAAE,MAAAC,EAAO,CACnC,CAeO,SAASC,EAAsBC,EAAU,CAC9C,OAAKA,EAIE,CACL,MAAOA,EAAS,MAChB,OAAQA,EAAS,MACrB,EANW,CAAE,MAAO,EAAG,OAAQ,CAAC,CAOhC,CAiBO,SAASC,EAA0BC,EAAWC,EAAYL,EAAO,CACtE,MAAO,CACL,MAAOI,EAAYJ,EACnB,OAAQK,EAAaL,CACzB,CACA"}