@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.
- package/LICENSE +201 -0
- package/README.md +219 -0
- package/dist/PDFHighlightViewer.d.ts +219 -0
- package/dist/PDFHighlightViewer.d.ts.map +1 -0
- package/dist/PDFHighlightViewer.js +1551 -0
- package/dist/PDFHighlightViewer.js.map +1 -0
- package/dist/api.d.ts +59 -0
- package/dist/api.d.ts.map +1 -0
- package/dist/api.js +2 -0
- package/dist/api.js.map +1 -0
- package/dist/config.d.ts +12 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +32 -0
- package/dist/config.js.map +1 -0
- package/dist/core/interaction-handler.d.ts +63 -0
- package/dist/core/interaction-handler.d.ts.map +1 -0
- package/dist/core/interaction-handler.js +430 -0
- package/dist/core/interaction-handler.js.map +1 -0
- package/dist/core/pdf-engine.d.ts +37 -0
- package/dist/core/pdf-engine.d.ts.map +1 -0
- package/dist/core/pdf-engine.js +281 -0
- package/dist/core/pdf-engine.js.map +1 -0
- package/dist/core/performance-optimizer.d.ts +91 -0
- package/dist/core/performance-optimizer.d.ts.map +1 -0
- package/dist/core/performance-optimizer.js +473 -0
- package/dist/core/performance-optimizer.js.map +1 -0
- package/dist/core/style-manager.d.ts +88 -0
- package/dist/core/style-manager.d.ts.map +1 -0
- package/dist/core/style-manager.js +413 -0
- package/dist/core/style-manager.js.map +1 -0
- package/dist/core/text-segmentation.d.ts +41 -0
- package/dist/core/text-segmentation.d.ts.map +1 -0
- package/dist/core/text-segmentation.js +338 -0
- package/dist/core/text-segmentation.js.map +1 -0
- package/dist/core/unified-layer-builder.d.ts +27 -0
- package/dist/core/unified-layer-builder.d.ts.map +1 -0
- package/dist/core/unified-layer-builder.js +331 -0
- package/dist/core/unified-layer-builder.js.map +1 -0
- package/dist/core/viewport-manager.d.ts +103 -0
- package/dist/core/viewport-manager.d.ts.map +1 -0
- package/dist/core/viewport-manager.js +222 -0
- package/dist/core/viewport-manager.js.map +1 -0
- package/dist/index.d.ts +27 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +57 -0
- package/dist/index.js.map +1 -0
- package/dist/pdf-highlight-viewer.css +488 -0
- package/dist/types.d.ts +279 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/highlight-adapter.d.ts +31 -0
- package/dist/utils/highlight-adapter.d.ts.map +1 -0
- package/dist/utils/highlight-adapter.js +202 -0
- package/dist/utils/highlight-adapter.js.map +1 -0
- package/dist/utils/pdf-utils.d.ts +14 -0
- package/dist/utils/pdf-utils.d.ts.map +1 -0
- package/dist/utils/pdf-utils.js +120 -0
- package/dist/utils/pdf-utils.js.map +1 -0
- package/dist/utils/worker-loader-simple.d.ts +8 -0
- package/dist/utils/worker-loader-simple.d.ts.map +1 -0
- package/dist/utils/worker-loader-simple.js +65 -0
- package/dist/utils/worker-loader-simple.js.map +1 -0
- package/dist/vite.config.d.ts +3 -0
- package/dist/vite.config.d.ts.map +1 -0
- package/dist/vite.config.js +20 -0
- package/dist/vite.config.js.map +1 -0
- package/dist/vitest.config.d.ts +3 -0
- package/dist/vitest.config.d.ts.map +1 -0
- package/dist/vitest.config.js +24 -0
- package/dist/vitest.config.js.map +1 -0
- package/dist/vitest.setup.d.ts +2 -0
- package/dist/vitest.setup.d.ts.map +1 -0
- package/dist/vitest.setup.js +8 -0
- package/dist/vitest.setup.js.map +1 -0
- package/package.json +74 -0
- 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
|