@epam/pdf-highlighter-kit 0.0.1

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 (77) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +219 -0
  3. package/dist/PDFHighlightViewer.d.ts +219 -0
  4. package/dist/PDFHighlightViewer.d.ts.map +1 -0
  5. package/dist/PDFHighlightViewer.js +1551 -0
  6. package/dist/PDFHighlightViewer.js.map +1 -0
  7. package/dist/api.d.ts +59 -0
  8. package/dist/api.d.ts.map +1 -0
  9. package/dist/api.js +2 -0
  10. package/dist/api.js.map +1 -0
  11. package/dist/config.d.ts +12 -0
  12. package/dist/config.d.ts.map +1 -0
  13. package/dist/config.js +32 -0
  14. package/dist/config.js.map +1 -0
  15. package/dist/core/interaction-handler.d.ts +63 -0
  16. package/dist/core/interaction-handler.d.ts.map +1 -0
  17. package/dist/core/interaction-handler.js +430 -0
  18. package/dist/core/interaction-handler.js.map +1 -0
  19. package/dist/core/pdf-engine.d.ts +37 -0
  20. package/dist/core/pdf-engine.d.ts.map +1 -0
  21. package/dist/core/pdf-engine.js +281 -0
  22. package/dist/core/pdf-engine.js.map +1 -0
  23. package/dist/core/performance-optimizer.d.ts +91 -0
  24. package/dist/core/performance-optimizer.d.ts.map +1 -0
  25. package/dist/core/performance-optimizer.js +473 -0
  26. package/dist/core/performance-optimizer.js.map +1 -0
  27. package/dist/core/style-manager.d.ts +88 -0
  28. package/dist/core/style-manager.d.ts.map +1 -0
  29. package/dist/core/style-manager.js +413 -0
  30. package/dist/core/style-manager.js.map +1 -0
  31. package/dist/core/text-segmentation.d.ts +41 -0
  32. package/dist/core/text-segmentation.d.ts.map +1 -0
  33. package/dist/core/text-segmentation.js +338 -0
  34. package/dist/core/text-segmentation.js.map +1 -0
  35. package/dist/core/unified-layer-builder.d.ts +27 -0
  36. package/dist/core/unified-layer-builder.d.ts.map +1 -0
  37. package/dist/core/unified-layer-builder.js +331 -0
  38. package/dist/core/unified-layer-builder.js.map +1 -0
  39. package/dist/core/viewport-manager.d.ts +103 -0
  40. package/dist/core/viewport-manager.d.ts.map +1 -0
  41. package/dist/core/viewport-manager.js +222 -0
  42. package/dist/core/viewport-manager.js.map +1 -0
  43. package/dist/index.d.ts +27 -0
  44. package/dist/index.d.ts.map +1 -0
  45. package/dist/index.js +57 -0
  46. package/dist/index.js.map +1 -0
  47. package/dist/pdf-highlight-viewer.css +488 -0
  48. package/dist/types.d.ts +279 -0
  49. package/dist/types.d.ts.map +1 -0
  50. package/dist/types.js +2 -0
  51. package/dist/types.js.map +1 -0
  52. package/dist/utils/highlight-adapter.d.ts +31 -0
  53. package/dist/utils/highlight-adapter.d.ts.map +1 -0
  54. package/dist/utils/highlight-adapter.js +202 -0
  55. package/dist/utils/highlight-adapter.js.map +1 -0
  56. package/dist/utils/pdf-utils.d.ts +14 -0
  57. package/dist/utils/pdf-utils.d.ts.map +1 -0
  58. package/dist/utils/pdf-utils.js +120 -0
  59. package/dist/utils/pdf-utils.js.map +1 -0
  60. package/dist/utils/worker-loader-simple.d.ts +8 -0
  61. package/dist/utils/worker-loader-simple.d.ts.map +1 -0
  62. package/dist/utils/worker-loader-simple.js +65 -0
  63. package/dist/utils/worker-loader-simple.js.map +1 -0
  64. package/dist/vite.config.d.ts +3 -0
  65. package/dist/vite.config.d.ts.map +1 -0
  66. package/dist/vite.config.js +20 -0
  67. package/dist/vite.config.js.map +1 -0
  68. package/dist/vitest.config.d.ts +3 -0
  69. package/dist/vitest.config.d.ts.map +1 -0
  70. package/dist/vitest.config.js +24 -0
  71. package/dist/vitest.config.js.map +1 -0
  72. package/dist/vitest.setup.d.ts +2 -0
  73. package/dist/vitest.setup.d.ts.map +1 -0
  74. package/dist/vitest.setup.js +8 -0
  75. package/dist/vitest.setup.js.map +1 -0
  76. package/package.json +74 -0
  77. package/styles/pdf-highlight-viewer.css +488 -0
@@ -0,0 +1,331 @@
1
+ export class UnifiedLayerBuilder {
2
+ // eslint-disable-next-line @typescript-eslint/no-empty-function
3
+ constructor() {
4
+ this.pageContainer = null;
5
+ this.unifiedLayer = null;
6
+ }
7
+ async buildUnifiedLayer(pageContainer, textContent, highlights, pageNumber, scale = 1.5) {
8
+ this.pageContainer = pageContainer;
9
+ const analysis = this.analyzeContent(textContent, highlights, pageNumber);
10
+ const segments = this.segmentTextWithHighlights(textContent, highlights, pageNumber);
11
+ const unifiedLayer = this.buildDOM(segments, scale);
12
+ this.positionLayer(unifiedLayer, pageContainer);
13
+ this.unifiedLayer = unifiedLayer;
14
+ return unifiedLayer;
15
+ }
16
+ analyzeContent(textContent, highlights, pageNumber) {
17
+ const highlightRanges = [];
18
+ Object.entries(highlights).forEach(([category, categoryData]) => {
19
+ const pageHighlights = categoryData.pages[pageNumber.toString()];
20
+ if (pageHighlights) {
21
+ pageHighlights.forEach((occurrence) => {
22
+ occurrence.coordinates.forEach((coord) => {
23
+ const intersectingItems = this.findIntersectingTextItems(textContent.items, coord);
24
+ intersectingItems.forEach(({ item, startIndex, endIndex }) => {
25
+ highlightRanges.push({
26
+ start: startIndex,
27
+ end: endIndex,
28
+ termId: occurrence.termId,
29
+ category,
30
+ coordinates: coord,
31
+ });
32
+ });
33
+ });
34
+ });
35
+ }
36
+ });
37
+ highlightRanges.sort((a, b) => a.start - b.start);
38
+ return {
39
+ segments: [],
40
+ highlightRanges,
41
+ };
42
+ }
43
+ findIntersectingTextItems(textItems, coordinates) {
44
+ const intersecting = [];
45
+ let globalIndex = 0;
46
+ textItems.forEach((item, itemIndex) => {
47
+ const itemBounds = this.getTextItemBounds(item);
48
+ if (this.boundsIntersect(itemBounds, coordinates)) {
49
+ intersecting.push({
50
+ item,
51
+ startIndex: globalIndex,
52
+ endIndex: globalIndex + item.str.length,
53
+ itemIndex,
54
+ });
55
+ }
56
+ globalIndex += item.str.length;
57
+ });
58
+ return intersecting;
59
+ }
60
+ getTextItemBounds(item) {
61
+ const transform = item.transform;
62
+ const x = transform[4];
63
+ const y = transform[5];
64
+ return {
65
+ x1: x,
66
+ y1: y - item.height,
67
+ x2: x + item.width,
68
+ y2: y,
69
+ };
70
+ }
71
+ boundsIntersect(bounds1, bounds2) {
72
+ return !(bounds1.x2 < bounds2.x1 ||
73
+ bounds1.x1 > bounds2.x2 ||
74
+ bounds1.y2 < bounds2.y1 ||
75
+ bounds1.y1 > bounds2.y2);
76
+ }
77
+ segmentTextWithHighlights(textContent, highlights, pageNumber) {
78
+ const segments = [];
79
+ const analysis = this.analyzeContent(textContent, highlights, pageNumber);
80
+ textContent.items.forEach((textItem, itemIndex) => {
81
+ const itemBounds = this.getTextItemBounds(textItem);
82
+ const itemHighlights = this.getHighlightsForTextItem(textItem, itemBounds, highlights, pageNumber);
83
+ if (itemHighlights.length === 0) {
84
+ segments.push({
85
+ text: textItem.str,
86
+ bounds: itemBounds,
87
+ hasHighlight: false,
88
+ transform: textItem.transform,
89
+ fontName: textItem.fontName,
90
+ });
91
+ }
92
+ else {
93
+ const highlightedSegments = this.createHighlightedSegments(textItem, itemHighlights);
94
+ segments.push(...highlightedSegments);
95
+ }
96
+ });
97
+ return this.mergeAdjacentSegments(segments);
98
+ }
99
+ getHighlightsForTextItem(textItem, itemBounds, highlights, pageNumber) {
100
+ const itemHighlights = [];
101
+ Object.entries(highlights).forEach(([category, categoryData]) => {
102
+ const pageHighlights = categoryData.pages[pageNumber.toString()];
103
+ if (pageHighlights) {
104
+ pageHighlights.forEach((occurrence) => {
105
+ occurrence.coordinates.forEach((coord) => {
106
+ if (this.boundsIntersect(itemBounds, coord)) {
107
+ itemHighlights.push({
108
+ termId: occurrence.termId,
109
+ category,
110
+ coordinates: coord,
111
+ });
112
+ }
113
+ });
114
+ });
115
+ }
116
+ });
117
+ return itemHighlights;
118
+ }
119
+ createHighlightedSegments(textItem, itemHighlights) {
120
+ const segments = [];
121
+ const itemBounds = this.getTextItemBounds(textItem);
122
+ const primaryHighlight = itemHighlights[0];
123
+ segments.push({
124
+ text: textItem.str,
125
+ bounds: itemBounds,
126
+ hasHighlight: true,
127
+ highlightInfo: {
128
+ termId: primaryHighlight.termId,
129
+ category: primaryHighlight.category,
130
+ },
131
+ transform: textItem.transform,
132
+ fontName: textItem.fontName,
133
+ });
134
+ return segments;
135
+ }
136
+ mergeAdjacentSegments(segments) {
137
+ if (segments.length <= 1)
138
+ return segments;
139
+ const merged = [];
140
+ let current = segments[0];
141
+ for (let i = 1; i < segments.length; i++) {
142
+ const next = segments[i];
143
+ if (this.canMergeSegments(current, next)) {
144
+ current = this.mergeSegments(current, next);
145
+ }
146
+ else {
147
+ merged.push(current);
148
+ current = next;
149
+ }
150
+ }
151
+ merged.push(current);
152
+ return merged;
153
+ }
154
+ canMergeSegments(segment1, segment2) {
155
+ if (segment1.hasHighlight !== segment2.hasHighlight) {
156
+ return false;
157
+ }
158
+ if (segment1.hasHighlight && segment2.hasHighlight) {
159
+ return (segment1.highlightInfo?.category === segment2.highlightInfo?.category &&
160
+ segment1.highlightInfo?.termId === segment2.highlightInfo?.termId);
161
+ }
162
+ return segment1.fontName === segment2.fontName;
163
+ }
164
+ mergeSegments(segment1, segment2) {
165
+ return {
166
+ text: segment1.text + segment2.text,
167
+ bounds: {
168
+ x1: Math.min(segment1.bounds.x1, segment2.bounds.x1),
169
+ y1: Math.min(segment1.bounds.y1, segment2.bounds.y1),
170
+ x2: Math.max(segment1.bounds.x2, segment2.bounds.x2),
171
+ y2: Math.max(segment1.bounds.y2, segment2.bounds.y2),
172
+ },
173
+ hasHighlight: segment1.hasHighlight,
174
+ highlightInfo: segment1.highlightInfo,
175
+ transform: segment1.transform,
176
+ fontName: segment1.fontName,
177
+ };
178
+ }
179
+ buildDOM(segments, scale) {
180
+ const unifiedLayer = document.createElement('div');
181
+ unifiedLayer.className = 'unified-layer';
182
+ const fragment = document.createDocumentFragment();
183
+ const batch = [];
184
+ segments.forEach((segment, index) => {
185
+ const element = segment.hasHighlight
186
+ ? this.createHighlightElement(segment, scale)
187
+ : this.createTextElement(segment, scale);
188
+ batch.push(element);
189
+ if (batch.length >= 100) {
190
+ batch.forEach((el) => fragment.appendChild(el));
191
+ batch.length = 0;
192
+ }
193
+ });
194
+ batch.forEach((el) => fragment.appendChild(el));
195
+ unifiedLayer.appendChild(fragment);
196
+ return unifiedLayer;
197
+ }
198
+ createTextElement(segment, scale) {
199
+ const span = document.createElement('span');
200
+ span.className = 'text-segment';
201
+ span.textContent = segment.text;
202
+ this.applyTextPositioning(span, segment, scale);
203
+ return span;
204
+ }
205
+ createHighlightElement(segment, scale) {
206
+ const wrapper = document.createElement('span');
207
+ wrapper.className = `highlight-wrapper ${segment.highlightInfo?.category}-highlight`;
208
+ wrapper.setAttribute('data-term-id', segment.highlightInfo?.termId || '');
209
+ const textSpan = document.createElement('span');
210
+ textSpan.className = 'text-segment selectable';
211
+ textSpan.textContent = segment.text;
212
+ const background = document.createElement('span');
213
+ background.className = 'highlight-background';
214
+ wrapper.appendChild(textSpan);
215
+ wrapper.appendChild(background);
216
+ this.applyTextPositioning(wrapper, segment, scale);
217
+ return wrapper;
218
+ }
219
+ applyTextPositioning(element, segment, scale) {
220
+ const transform = segment.transform;
221
+ const x = transform[4] * scale;
222
+ const y = transform[5] * scale;
223
+ const scaleX = transform[0] * scale;
224
+ const scaleY = transform[3] * scale;
225
+ element.style.position = 'absolute';
226
+ element.style.left = `${x}px`;
227
+ element.style.top = `${y}px`;
228
+ element.style.transform = `scale(${scaleX}, ${scaleY})`;
229
+ element.style.transformOrigin = '0% 0%';
230
+ element.style.whiteSpace = 'pre';
231
+ element.style.userSelect = 'text';
232
+ element.style.color = 'transparent';
233
+ element.style.fontFamily = segment.fontName;
234
+ element.style.cursor = segment.hasHighlight ? 'pointer' : 'text';
235
+ }
236
+ positionLayer(unifiedLayer, pageContainer) {
237
+ unifiedLayer.style.position = 'absolute';
238
+ unifiedLayer.style.top = '0';
239
+ unifiedLayer.style.left = '0';
240
+ unifiedLayer.style.width = '100%';
241
+ unifiedLayer.style.height = '100%';
242
+ unifiedLayer.style.zIndex = '2';
243
+ unifiedLayer.style.pointerEvents = 'auto';
244
+ unifiedLayer.style.opacity = '1';
245
+ const style = document.createElement('style');
246
+ style.textContent = `
247
+ .unified-layer .text-segment,
248
+ .unified-layer .highlight-wrapper {
249
+ pointer-events: auto;
250
+ cursor: pointer;
251
+ }
252
+ .unified-layer .highlight-wrapper {
253
+ background-color: rgba(102, 126, 234, 0.15);
254
+ }
255
+ .unified-layer .highlight-wrapper:hover {
256
+ background-color: rgba(102, 126, 234, 0.25);
257
+ }
258
+ .highlight.selected-term,
259
+ .unified-layer .highlight-wrapper.selected-term,
260
+ div.highlight.selected-term,
261
+ div.highlight-wrapper.selected-term {
262
+ opacity: 1 !important;
263
+ filter: brightness(2) contrast(1.5) saturate(2) !important;
264
+ box-shadow: 0 0 0 3px rgba(255, 255, 255, 1), 0 0 10px rgba(255, 255, 0, 0.8), 0 0 20px rgba(255, 255, 0, 0.4) !important;
265
+ z-index: 15 !important;
266
+ transform: scale(1.1) !important;
267
+ transition: all 0.3s ease !important;
268
+ border-width: 3px !important;
269
+ outline: 2px solid rgba(255, 255, 255, 0.9) !important;
270
+ outline-offset: 1px !important;
271
+ }
272
+ .highlight.dimmed-highlight,
273
+ .unified-layer .highlight-wrapper.dimmed-highlight,
274
+ div.highlight.dimmed-highlight,
275
+ div.highlight-wrapper.dimmed-highlight {
276
+ opacity: 0.15 !important;
277
+ filter: brightness(0.4) contrast(0.6) saturate(0.3) grayscale(0.3) !important;
278
+ transition: all 0.3s ease !important;
279
+ }
280
+ .highlight,
281
+ .unified-layer .highlight-wrapper,
282
+ div.highlight,
283
+ div.highlight-wrapper {
284
+ transition: all 0.3s ease;
285
+ }
286
+ `;
287
+ document.head.appendChild(style);
288
+ pageContainer.appendChild(unifiedLayer);
289
+ }
290
+ updateHighlights(highlights, pageNumber, textContent) {
291
+ if (!this.unifiedLayer || !this.pageContainer) {
292
+ throw new Error('Unified layer not initialized');
293
+ }
294
+ if (textContent) {
295
+ this.buildUnifiedLayer(this.pageContainer, textContent, highlights, pageNumber);
296
+ }
297
+ else {
298
+ this.updateExistingHighlights(highlights, pageNumber);
299
+ }
300
+ }
301
+ updateExistingHighlights(highlights, pageNumber) {
302
+ if (!this.unifiedLayer)
303
+ return;
304
+ const existingHighlights = this.unifiedLayer.querySelectorAll('.highlight-wrapper');
305
+ existingHighlights.forEach((highlight) => {
306
+ highlight.classList.remove(...Array.from(highlight.classList).filter((cls) => cls.endsWith('-highlight')));
307
+ });
308
+ Object.entries(highlights).forEach(([category, categoryData]) => {
309
+ const pageHighlights = categoryData.pages[pageNumber.toString()];
310
+ if (pageHighlights) {
311
+ pageHighlights.forEach((occurrence) => {
312
+ const elements = this.unifiedLayer.querySelectorAll(`[data-term-id="${occurrence.termId}"]`);
313
+ elements.forEach((element) => {
314
+ element.classList.add(`${category}-highlight`);
315
+ });
316
+ });
317
+ }
318
+ });
319
+ }
320
+ clear() {
321
+ if (this.unifiedLayer && this.unifiedLayer.parentNode) {
322
+ this.unifiedLayer.parentNode.removeChild(this.unifiedLayer);
323
+ }
324
+ this.unifiedLayer = null;
325
+ this.pageContainer = null;
326
+ }
327
+ getUnifiedLayer() {
328
+ return this.unifiedLayer;
329
+ }
330
+ }
331
+ //# sourceMappingURL=unified-layer-builder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"unified-layer-builder.js","sourceRoot":"","sources":["../../core/unified-layer-builder.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,103 @@
1
+ import { ViewportManager as IViewportManager, Priority, BoundingBox } from '../types';
2
+ export declare class ViewportManager implements IViewportManager {
3
+ private containerHeight;
4
+ private pageHeight;
5
+ private pageGap;
6
+ private bufferSize;
7
+ private maxCachedPages;
8
+ private totalPages;
9
+ constructor(bufferSize?: number, // Restored to 2 to prevent white boxes
10
+ maxCachedPages?: number);
11
+ /**
12
+ * Update container dimensions
13
+ */
14
+ updateDimensions(containerHeight: number, pageHeight?: number): void;
15
+ /**
16
+ * Set total pages
17
+ */
18
+ setTotalPages(totalPages: number): void;
19
+ /**
20
+ * Calculate visible pages based on scroll position
21
+ */
22
+ getVisiblePages(scrollTop: number, containerHeight: number): number[];
23
+ /**
24
+ * Get buffer pages around visible pages
25
+ */
26
+ getBufferPages(visiblePages: number[], bufferSize?: number): number[];
27
+ /**
28
+ * Queue pages for rendering with appropriate priority
29
+ */
30
+ queuePagesForRendering(pages: number[], priority: Priority): void;
31
+ /**
32
+ * Determine which pages to unload based on distance from current view
33
+ */
34
+ unloadDistantPages(currentPage: number, threshold?: number): void;
35
+ /**
36
+ * Get rendering strategy for current viewport
37
+ */
38
+ getRenderingStrategy(scrollTop: number, containerHeight: number): {
39
+ highPriority: number[];
40
+ mediumPriority: number[];
41
+ lowPriority: number[];
42
+ unloadPages: number[];
43
+ };
44
+ /**
45
+ * Calculate page position in viewport
46
+ */
47
+ getPagePosition(pageNumber: number): {
48
+ top: number;
49
+ bottom: number;
50
+ };
51
+ /**
52
+ * Calculate which page contains a specific Y coordinate
53
+ */
54
+ getPageAtPosition(y: number): number;
55
+ /**
56
+ * Check if a page is visible in current viewport
57
+ */
58
+ isPageVisible(pageNumber: number, scrollTop: number, containerHeight: number): boolean;
59
+ /**
60
+ * Get optimal scroll position to center a page
61
+ */
62
+ getScrollPositionForPage(pageNumber: number): number;
63
+ /**
64
+ * Calculate viewport bounds for spatial indexing
65
+ */
66
+ getViewportBounds(scrollTop: number, containerHeight: number, scale?: number): BoundingBox;
67
+ /**
68
+ * Performance optimization: predict next viewport based on scroll direction
69
+ */
70
+ predictNextViewport(currentScrollTop: number, scrollVelocity: number, deltaTime: number): {
71
+ scrollTop: number;
72
+ visiblePages: number[];
73
+ };
74
+ /**
75
+ * Get memory usage estimation for current strategy
76
+ */
77
+ estimateMemoryUsage(strategy: ReturnType<typeof this.getRenderingStrategy>): {
78
+ highPriorityMB: number;
79
+ mediumPriorityMB: number;
80
+ lowPriorityMB: number;
81
+ totalMB: number;
82
+ };
83
+ /**
84
+ * Update configuration
85
+ */
86
+ updateConfig(config: {
87
+ bufferSize?: number;
88
+ maxCachedPages?: number;
89
+ pageHeight?: number;
90
+ pageGap?: number;
91
+ }): void;
92
+ /**
93
+ * Get current configuration
94
+ */
95
+ getConfig(): {
96
+ bufferSize: number;
97
+ maxCachedPages: number;
98
+ pageHeight: number;
99
+ pageGap: number;
100
+ containerHeight: number;
101
+ };
102
+ }
103
+ //# sourceMappingURL=viewport-manager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"viewport-manager.d.ts","sourceRoot":"","sources":["../../core/viewport-manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,IAAI,gBAAgB,EAAE,QAAQ,EAAY,WAAW,EAAE,MAAM,UAAU,CAAC;AAEhG,qBAAa,eAAgB,YAAW,gBAAgB;IACtD,OAAO,CAAC,eAAe,CAAa;IACpC,OAAO,CAAC,UAAU,CAAe;IACjC,OAAO,CAAC,OAAO,CAAc;IAC7B,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,cAAc,CAAS;IAC/B,OAAO,CAAC,UAAU,CAAa;gBAG7B,UAAU,GAAE,MAAU,EAAE,uCAAuC;IAC/D,cAAc,GAAE,MAAU;IAM5B;;OAEG;IACH,gBAAgB,CAAC,eAAe,EAAE,MAAM,EAAE,UAAU,GAAE,MAAY,GAAG,IAAI;IAKzE;;OAEG;IACH,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI;IAIvC;;OAEG;IACH,eAAe,CAAC,SAAS,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,GAAG,MAAM,EAAE;IAoBrE;;OAEG;IACH,cAAc,CAAC,YAAY,EAAE,MAAM,EAAE,EAAE,UAAU,GAAE,MAAwB,GAAG,MAAM,EAAE;IAqBtF;;OAEG;IACH,sBAAsB,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,QAAQ,EAAE,QAAQ,GAAG,IAAI;IAKjE;;OAEG;IACH,kBAAkB,CAAC,WAAW,EAAE,MAAM,EAAE,SAAS,GAAE,MAAU,GAAG,IAAI;IAKpE;;OAEG;IACH,oBAAoB,CAClB,SAAS,EAAE,MAAM,EACjB,eAAe,EAAE,MAAM,GACtB;QACD,YAAY,EAAE,MAAM,EAAE,CAAC;QACvB,cAAc,EAAE,MAAM,EAAE,CAAC;QACzB,WAAW,EAAE,MAAM,EAAE,CAAC;QACtB,WAAW,EAAE,MAAM,EAAE,CAAC;KACvB;IA4DD;;OAEG;IACH,eAAe,CAAC,UAAU,EAAE,MAAM,GAAG;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE;IAOpE;;OAEG;IACH,iBAAiB,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM;IAIpC;;OAEG;IACH,aAAa,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,GAAG,OAAO;IAStF;;OAEG;IACH,wBAAwB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM;IAQpD;;OAEG;IACH,iBAAiB,CAAC,SAAS,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,EAAE,KAAK,GAAE,MAAU,GAAG,WAAW;IAS7F;;OAEG;IACH,mBAAmB,CACjB,gBAAgB,EAAE,MAAM,EACxB,cAAc,EAAE,MAAM,EACtB,SAAS,EAAE,MAAM,GAChB;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,EAAE,CAAA;KAAE;IAUhD;;OAEG;IACH,mBAAmB,CAAC,QAAQ,EAAE,UAAU,CAAC,OAAO,IAAI,CAAC,oBAAoB,CAAC,GAAG;QAC3E,cAAc,EAAE,MAAM,CAAC;QACvB,gBAAgB,EAAE,MAAM,CAAC;QACzB,aAAa,EAAE,MAAM,CAAC;QACtB,OAAO,EAAE,MAAM,CAAC;KACjB;IAeD;;OAEG;IACH,YAAY,CAAC,MAAM,EAAE;QACnB,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,cAAc,CAAC,EAAE,MAAM,CAAC;QACxB,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,OAAO,CAAC,EAAE,MAAM,CAAC;KAClB,GAAG,IAAI;IAeR;;OAEG;IACH,SAAS;;;;;;;CASV"}
@@ -0,0 +1,222 @@
1
+ export class ViewportManager {
2
+ constructor(bufferSize = 2, // Restored to 2 to prevent white boxes
3
+ maxCachedPages = 8 // Increased to 8 for better user experience
4
+ ) {
5
+ this.containerHeight = 0;
6
+ this.pageHeight = 800; // Default page height
7
+ this.pageGap = 20; // Gap between pages
8
+ this.totalPages = 0;
9
+ this.bufferSize = bufferSize;
10
+ this.maxCachedPages = maxCachedPages;
11
+ }
12
+ /**
13
+ * Update container dimensions
14
+ */
15
+ updateDimensions(containerHeight, pageHeight = 800) {
16
+ this.containerHeight = containerHeight;
17
+ this.pageHeight = pageHeight;
18
+ }
19
+ /**
20
+ * Set total pages
21
+ */
22
+ setTotalPages(totalPages) {
23
+ this.totalPages = totalPages;
24
+ }
25
+ /**
26
+ * Calculate visible pages based on scroll position
27
+ */
28
+ getVisiblePages(scrollTop, containerHeight) {
29
+ const visiblePages = [];
30
+ // Calculate which pages are in viewport
31
+ const startY = scrollTop;
32
+ const endY = scrollTop + containerHeight;
33
+ // Find first page that intersects viewport
34
+ const firstPage = Math.max(1, Math.floor(startY / (this.pageHeight + this.pageGap)) + 1);
35
+ // Find last page that intersects viewport
36
+ const lastPage = Math.min(this.totalPages, Math.ceil(endY / (this.pageHeight + this.pageGap)));
37
+ for (let page = firstPage; page <= lastPage; page++) {
38
+ visiblePages.push(page);
39
+ }
40
+ return visiblePages;
41
+ }
42
+ /**
43
+ * Get buffer pages around visible pages
44
+ */
45
+ getBufferPages(visiblePages, bufferSize = this.bufferSize) {
46
+ if (visiblePages.length === 0)
47
+ return [];
48
+ const minPage = Math.min(...visiblePages);
49
+ const maxPage = Math.max(...visiblePages);
50
+ const bufferPages = [];
51
+ // Add buffer pages before visible range
52
+ for (let i = Math.max(1, minPage - bufferSize); i < minPage; i++) {
53
+ bufferPages.push(i);
54
+ }
55
+ // Add buffer pages after visible range
56
+ for (let i = maxPage + 1; i <= maxPage + bufferSize; i++) {
57
+ bufferPages.push(i);
58
+ }
59
+ return bufferPages;
60
+ }
61
+ /**
62
+ * Queue pages for rendering with appropriate priority
63
+ */
64
+ queuePagesForRendering(pages, priority) {
65
+ // This will be called by the consumer (PDFEngine)
66
+ // Implementation is handled by the engine that uses this manager
67
+ }
68
+ /**
69
+ * Determine which pages to unload based on distance from current view
70
+ */
71
+ unloadDistantPages(currentPage, threshold = 5) {
72
+ // This will be called by the consumer (PDFEngine)
73
+ // Implementation is handled by the engine that uses this manager
74
+ }
75
+ /**
76
+ * Get rendering strategy for current viewport
77
+ */
78
+ getRenderingStrategy(scrollTop, containerHeight) {
79
+ const visiblePages = this.getVisiblePages(scrollTop, containerHeight);
80
+ const bufferPages = this.getBufferPages(visiblePages);
81
+ // High priority: visible pages
82
+ const highPriority = visiblePages;
83
+ // Medium priority: buffer pages
84
+ const mediumPriority = bufferPages;
85
+ // Low priority: reasonable preload pages to prevent white boxes
86
+ const lowPriority = [];
87
+ if (visiblePages.length > 0) {
88
+ const minVisible = Math.min(...visiblePages);
89
+ const maxVisible = Math.max(...visiblePages);
90
+ const preloadSize = 2; // Increased back to 2
91
+ // Preload pages before buffer
92
+ for (let i = Math.max(1, minVisible - this.bufferSize - preloadSize); i < minVisible - this.bufferSize; i++) {
93
+ if (i >= 1)
94
+ lowPriority.push(i);
95
+ }
96
+ // Preload pages after buffer
97
+ for (let i = maxVisible + this.bufferSize + 1; i <= Math.min(this.totalPages, maxVisible + this.bufferSize + preloadSize); i++) {
98
+ if (i <= this.totalPages)
99
+ lowPriority.push(i);
100
+ }
101
+ }
102
+ // Pages to unload (far from current view) - more aggressive unloading
103
+ const unloadPages = [];
104
+ const currentCenter = visiblePages.length > 0
105
+ ? Math.floor((Math.min(...visiblePages) + Math.max(...visiblePages)) / 2)
106
+ : 1;
107
+ // Mark pages for unloading if they're beyond threshold (more conservative)
108
+ const unloadThreshold = this.bufferSize + 7; // Increased to be less aggressive
109
+ for (let page = 1; page <= this.totalPages; page++) {
110
+ const distance = Math.abs(page - currentCenter);
111
+ if (distance > unloadThreshold) {
112
+ unloadPages.push(page);
113
+ }
114
+ }
115
+ return {
116
+ highPriority,
117
+ mediumPriority,
118
+ lowPriority,
119
+ unloadPages,
120
+ };
121
+ }
122
+ /**
123
+ * Calculate page position in viewport
124
+ */
125
+ getPagePosition(pageNumber) {
126
+ const top = (pageNumber - 1) * (this.pageHeight + this.pageGap);
127
+ const bottom = top + this.pageHeight;
128
+ return { top, bottom };
129
+ }
130
+ /**
131
+ * Calculate which page contains a specific Y coordinate
132
+ */
133
+ getPageAtPosition(y) {
134
+ return Math.max(1, Math.floor(y / (this.pageHeight + this.pageGap)) + 1);
135
+ }
136
+ /**
137
+ * Check if a page is visible in current viewport
138
+ */
139
+ isPageVisible(pageNumber, scrollTop, containerHeight) {
140
+ const pagePos = this.getPagePosition(pageNumber);
141
+ const viewportTop = scrollTop;
142
+ const viewportBottom = scrollTop + containerHeight;
143
+ // Check if page intersects with viewport
144
+ return !(pagePos.bottom < viewportTop || pagePos.top > viewportBottom);
145
+ }
146
+ /**
147
+ * Get optimal scroll position to center a page
148
+ */
149
+ getScrollPositionForPage(pageNumber) {
150
+ const pagePos = this.getPagePosition(pageNumber);
151
+ const pageCenter = pagePos.top + this.pageHeight / 2;
152
+ const viewportCenter = this.containerHeight / 2;
153
+ return Math.max(0, pageCenter - viewportCenter);
154
+ }
155
+ /**
156
+ * Calculate viewport bounds for spatial indexing
157
+ */
158
+ getViewportBounds(scrollTop, containerHeight, scale = 1) {
159
+ return {
160
+ x1: 0,
161
+ y1: scrollTop / scale,
162
+ x2: Number.MAX_SAFE_INTEGER, // Full width
163
+ y2: (scrollTop + containerHeight) / scale,
164
+ };
165
+ }
166
+ /**
167
+ * Performance optimization: predict next viewport based on scroll direction
168
+ */
169
+ predictNextViewport(currentScrollTop, scrollVelocity, deltaTime) {
170
+ const predictedScrollTop = currentScrollTop + scrollVelocity * deltaTime;
171
+ const predictedVisiblePages = this.getVisiblePages(predictedScrollTop, this.containerHeight);
172
+ return {
173
+ scrollTop: predictedScrollTop,
174
+ visiblePages: predictedVisiblePages,
175
+ };
176
+ }
177
+ /**
178
+ * Get memory usage estimation for current strategy
179
+ */
180
+ estimateMemoryUsage(strategy) {
181
+ const estimatedPageSizeMB = 2; // Rough estimate per rendered page
182
+ const highPriorityMB = strategy.highPriority.length * estimatedPageSizeMB;
183
+ const mediumPriorityMB = strategy.mediumPriority.length * estimatedPageSizeMB;
184
+ const lowPriorityMB = strategy.lowPriority.length * estimatedPageSizeMB;
185
+ return {
186
+ highPriorityMB,
187
+ mediumPriorityMB,
188
+ lowPriorityMB,
189
+ totalMB: highPriorityMB + mediumPriorityMB + lowPriorityMB,
190
+ };
191
+ }
192
+ /**
193
+ * Update configuration
194
+ */
195
+ updateConfig(config) {
196
+ if (config.bufferSize !== undefined) {
197
+ this.bufferSize = config.bufferSize;
198
+ }
199
+ if (config.maxCachedPages !== undefined) {
200
+ this.maxCachedPages = config.maxCachedPages;
201
+ }
202
+ if (config.pageHeight !== undefined) {
203
+ this.pageHeight = config.pageHeight;
204
+ }
205
+ if (config.pageGap !== undefined) {
206
+ this.pageGap = config.pageGap;
207
+ }
208
+ }
209
+ /**
210
+ * Get current configuration
211
+ */
212
+ getConfig() {
213
+ return {
214
+ bufferSize: this.bufferSize,
215
+ maxCachedPages: this.maxCachedPages,
216
+ pageHeight: this.pageHeight,
217
+ pageGap: this.pageGap,
218
+ containerHeight: this.containerHeight,
219
+ };
220
+ }
221
+ }
222
+ //# sourceMappingURL=viewport-manager.js.map