@embedpdf/plugin-scroll 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/dist/index.cjs +737 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +188 -0
- package/dist/index.d.ts +188 -0
- package/dist/index.js +714 -0
- package/dist/index.js.map +1 -0
- package/dist/preact/index.cjs +156 -0
- package/dist/preact/index.cjs.map +1 -0
- package/dist/preact/index.d.cts +30 -0
- package/dist/preact/index.d.ts +30 -0
- package/dist/preact/index.js +127 -0
- package/dist/preact/index.js.map +1 -0
- package/dist/react/index.cjs +156 -0
- package/dist/react/index.cjs.map +1 -0
- package/dist/react/index.d.cts +29 -0
- package/dist/react/index.d.ts +29 -0
- package/dist/react/index.js +127 -0
- package/dist/react/index.js.map +1 -0
- package/package.json +64 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,737 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
SCROLL_PLUGIN_ID: () => SCROLL_PLUGIN_ID,
|
|
24
|
+
ScrollPlugin: () => ScrollPlugin,
|
|
25
|
+
ScrollPluginPackage: () => ScrollPluginPackage,
|
|
26
|
+
ScrollStrategy: () => ScrollStrategy,
|
|
27
|
+
manifest: () => manifest
|
|
28
|
+
});
|
|
29
|
+
module.exports = __toCommonJS(index_exports);
|
|
30
|
+
|
|
31
|
+
// src/lib/scroll-plugin.ts
|
|
32
|
+
var import_core = require("@embedpdf/core");
|
|
33
|
+
|
|
34
|
+
// ../models/dist/index.js
|
|
35
|
+
var Rotation = /* @__PURE__ */ ((Rotation22) => {
|
|
36
|
+
Rotation22[Rotation22["Degree0"] = 0] = "Degree0";
|
|
37
|
+
Rotation22[Rotation22["Degree90"] = 1] = "Degree90";
|
|
38
|
+
Rotation22[Rotation22["Degree180"] = 2] = "Degree180";
|
|
39
|
+
Rotation22[Rotation22["Degree270"] = 3] = "Degree270";
|
|
40
|
+
return Rotation22;
|
|
41
|
+
})(Rotation || {});
|
|
42
|
+
function swap(size) {
|
|
43
|
+
const { width, height } = size;
|
|
44
|
+
return {
|
|
45
|
+
width: height,
|
|
46
|
+
height: width
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
function rotatePosition(containerSize, position, rotation) {
|
|
50
|
+
let x = position.x;
|
|
51
|
+
let y = position.y;
|
|
52
|
+
switch (rotation) {
|
|
53
|
+
case 0:
|
|
54
|
+
x = position.x;
|
|
55
|
+
y = position.y;
|
|
56
|
+
break;
|
|
57
|
+
case 1:
|
|
58
|
+
x = containerSize.height - position.y;
|
|
59
|
+
y = position.x;
|
|
60
|
+
break;
|
|
61
|
+
case 2:
|
|
62
|
+
x = containerSize.width - position.x;
|
|
63
|
+
y = containerSize.height - position.y;
|
|
64
|
+
break;
|
|
65
|
+
case 3:
|
|
66
|
+
x = position.y;
|
|
67
|
+
y = containerSize.width - position.x;
|
|
68
|
+
break;
|
|
69
|
+
}
|
|
70
|
+
return {
|
|
71
|
+
x,
|
|
72
|
+
y
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
function scalePosition(position, scaleFactor) {
|
|
76
|
+
return {
|
|
77
|
+
x: position.x * scaleFactor,
|
|
78
|
+
y: position.y * scaleFactor
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
function transformPosition(containerSize, position, rotation, scaleFactor) {
|
|
82
|
+
return scalePosition(rotatePosition(containerSize, position, rotation), scaleFactor);
|
|
83
|
+
}
|
|
84
|
+
function rotateRect(containerSize, rect, rotation) {
|
|
85
|
+
let x = rect.origin.x;
|
|
86
|
+
let y = rect.origin.y;
|
|
87
|
+
let size = rect.size;
|
|
88
|
+
switch (rotation) {
|
|
89
|
+
case 0:
|
|
90
|
+
break;
|
|
91
|
+
case 1:
|
|
92
|
+
x = containerSize.height - rect.origin.y - rect.size.height;
|
|
93
|
+
y = rect.origin.x;
|
|
94
|
+
size = swap(rect.size);
|
|
95
|
+
break;
|
|
96
|
+
case 2:
|
|
97
|
+
x = containerSize.width - rect.origin.x - rect.size.width;
|
|
98
|
+
y = containerSize.height - rect.origin.y - rect.size.height;
|
|
99
|
+
break;
|
|
100
|
+
case 3:
|
|
101
|
+
x = rect.origin.y;
|
|
102
|
+
y = containerSize.width - rect.origin.x - rect.size.width;
|
|
103
|
+
size = swap(rect.size);
|
|
104
|
+
break;
|
|
105
|
+
}
|
|
106
|
+
return {
|
|
107
|
+
origin: {
|
|
108
|
+
x,
|
|
109
|
+
y
|
|
110
|
+
},
|
|
111
|
+
size: {
|
|
112
|
+
width: size.width,
|
|
113
|
+
height: size.height
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
function scaleRect(rect, scaleFactor) {
|
|
118
|
+
return {
|
|
119
|
+
origin: {
|
|
120
|
+
x: rect.origin.x * scaleFactor,
|
|
121
|
+
y: rect.origin.y * scaleFactor
|
|
122
|
+
},
|
|
123
|
+
size: {
|
|
124
|
+
width: rect.size.width * scaleFactor,
|
|
125
|
+
height: rect.size.height * scaleFactor
|
|
126
|
+
}
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
function transformRect(containerSize, rect, rotation, scaleFactor) {
|
|
130
|
+
return scaleRect(rotateRect(containerSize, rect, rotation), scaleFactor);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// src/lib/types.ts
|
|
134
|
+
var ScrollStrategy = /* @__PURE__ */ ((ScrollStrategy2) => {
|
|
135
|
+
ScrollStrategy2["Vertical"] = "vertical";
|
|
136
|
+
ScrollStrategy2["Horizontal"] = "horizontal";
|
|
137
|
+
return ScrollStrategy2;
|
|
138
|
+
})(ScrollStrategy || {});
|
|
139
|
+
|
|
140
|
+
// src/lib/strategies/base-strategy.ts
|
|
141
|
+
var BaseScrollStrategy = class {
|
|
142
|
+
constructor(config) {
|
|
143
|
+
this.pageGap = config.pageGap ?? 20;
|
|
144
|
+
this.viewportGap = config.viewportGap ?? 20;
|
|
145
|
+
this.bufferSize = config.bufferSize ?? 2;
|
|
146
|
+
}
|
|
147
|
+
getVisibleRange(viewport, virtualItems, scale) {
|
|
148
|
+
const scrollOffset = this.getScrollOffset(viewport);
|
|
149
|
+
const clientSize = this.getClientSize(viewport);
|
|
150
|
+
const viewportStart = scrollOffset;
|
|
151
|
+
const viewportEnd = scrollOffset + clientSize;
|
|
152
|
+
let startIndex = 0;
|
|
153
|
+
while (startIndex < virtualItems.length && (virtualItems[startIndex].offset + virtualItems[startIndex].height) * scale <= viewportStart) {
|
|
154
|
+
startIndex++;
|
|
155
|
+
}
|
|
156
|
+
let endIndex = startIndex;
|
|
157
|
+
while (endIndex < virtualItems.length && virtualItems[endIndex].offset * scale <= viewportEnd) {
|
|
158
|
+
endIndex++;
|
|
159
|
+
}
|
|
160
|
+
return {
|
|
161
|
+
start: Math.max(0, startIndex - this.bufferSize),
|
|
162
|
+
end: Math.min(virtualItems.length - 1, endIndex + this.bufferSize - 1)
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
handleScroll(viewport, virtualItems, scale) {
|
|
166
|
+
const range = this.getVisibleRange(viewport, virtualItems, scale);
|
|
167
|
+
const visibleItems = virtualItems.slice(range.start, range.end + 1);
|
|
168
|
+
const pageVisibilityMetrics = this.calculatePageVisibility(visibleItems, viewport, scale);
|
|
169
|
+
const visiblePages = pageVisibilityMetrics.map((m) => m.pageNumber);
|
|
170
|
+
const renderedPageIndexes = virtualItems.slice(range.start, range.end + 1).flatMap((item) => item.index);
|
|
171
|
+
const currentPage = this.determineCurrentPage(pageVisibilityMetrics);
|
|
172
|
+
const first = virtualItems[range.start];
|
|
173
|
+
const last = virtualItems[range.end];
|
|
174
|
+
const startSpacing = first ? first.offset * scale : 0;
|
|
175
|
+
const endSpacing = last ? (virtualItems[virtualItems.length - 1].offset + // end of content
|
|
176
|
+
virtualItems[virtualItems.length - 1].height) * scale - // minus
|
|
177
|
+
(last.offset + last.height) * scale : 0;
|
|
178
|
+
return {
|
|
179
|
+
currentPage,
|
|
180
|
+
visiblePages,
|
|
181
|
+
pageVisibilityMetrics,
|
|
182
|
+
renderedPageIndexes,
|
|
183
|
+
scrollOffset: { x: viewport.scrollLeft, y: viewport.scrollTop },
|
|
184
|
+
startSpacing,
|
|
185
|
+
endSpacing
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
calculatePageVisibility(virtualItems, viewport, scale) {
|
|
189
|
+
const visibilityMetrics = [];
|
|
190
|
+
virtualItems.forEach((item) => {
|
|
191
|
+
item.pageLayouts.forEach((page) => {
|
|
192
|
+
const itemX = item.x * scale;
|
|
193
|
+
const itemY = item.y * scale;
|
|
194
|
+
const pageX = itemX + page.x * scale;
|
|
195
|
+
const pageY = itemY + page.y * scale;
|
|
196
|
+
const pageWidth = page.rotatedWidth * scale;
|
|
197
|
+
const pageHeight = page.rotatedHeight * scale;
|
|
198
|
+
const viewportLeft = viewport.scrollLeft;
|
|
199
|
+
const viewportTop = viewport.scrollTop;
|
|
200
|
+
const viewportRight = viewportLeft + viewport.clientWidth;
|
|
201
|
+
const viewportBottom = viewportTop + viewport.clientHeight;
|
|
202
|
+
const intersectionLeft = Math.max(pageX, viewportLeft);
|
|
203
|
+
const intersectionTop = Math.max(pageY, viewportTop);
|
|
204
|
+
const intersectionRight = Math.min(pageX + pageWidth, viewportRight);
|
|
205
|
+
const intersectionBottom = Math.min(pageY + pageHeight, viewportBottom);
|
|
206
|
+
if (intersectionLeft < intersectionRight && intersectionTop < intersectionBottom) {
|
|
207
|
+
const visibleWidth = intersectionRight - intersectionLeft;
|
|
208
|
+
const visibleHeight = intersectionBottom - intersectionTop;
|
|
209
|
+
const totalArea = pageWidth * pageHeight;
|
|
210
|
+
const visibleArea = visibleWidth * visibleHeight;
|
|
211
|
+
visibilityMetrics.push({
|
|
212
|
+
pageNumber: page.pageNumber,
|
|
213
|
+
viewportX: intersectionLeft - viewportLeft,
|
|
214
|
+
viewportY: intersectionTop - viewportTop,
|
|
215
|
+
visiblePercentage: visibleArea / totalArea * 100,
|
|
216
|
+
original: {
|
|
217
|
+
pageX: (intersectionLeft - pageX) / scale,
|
|
218
|
+
pageY: (intersectionTop - pageY) / scale,
|
|
219
|
+
visibleWidth: visibleWidth / scale,
|
|
220
|
+
visibleHeight: visibleHeight / scale,
|
|
221
|
+
scale: 1
|
|
222
|
+
},
|
|
223
|
+
scaled: {
|
|
224
|
+
pageX: intersectionLeft - pageX,
|
|
225
|
+
pageY: intersectionTop - pageY,
|
|
226
|
+
visibleWidth,
|
|
227
|
+
visibleHeight,
|
|
228
|
+
scale
|
|
229
|
+
}
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
});
|
|
233
|
+
});
|
|
234
|
+
return visibilityMetrics;
|
|
235
|
+
}
|
|
236
|
+
determineCurrentPage(visibilityMetrics) {
|
|
237
|
+
if (visibilityMetrics.length === 0) return 1;
|
|
238
|
+
const maxVisibility = Math.max(...visibilityMetrics.map((m) => m.visiblePercentage));
|
|
239
|
+
const mostVisiblePages = visibilityMetrics.filter((m) => m.visiblePercentage === maxVisibility);
|
|
240
|
+
return mostVisiblePages.length === 1 ? mostVisiblePages[0].pageNumber : mostVisiblePages.sort((a, b) => a.pageNumber - b.pageNumber)[0].pageNumber;
|
|
241
|
+
}
|
|
242
|
+
getRectLocationForPage(pageNumber, virtualItems) {
|
|
243
|
+
const item = virtualItems.find((item2) => item2.pageNumbers.includes(pageNumber));
|
|
244
|
+
if (!item) return null;
|
|
245
|
+
const pageLayout = item.pageLayouts.find((layout) => layout.pageNumber === pageNumber);
|
|
246
|
+
if (!pageLayout) return null;
|
|
247
|
+
return {
|
|
248
|
+
origin: {
|
|
249
|
+
x: item.x + pageLayout.x,
|
|
250
|
+
y: item.y + pageLayout.y
|
|
251
|
+
},
|
|
252
|
+
size: {
|
|
253
|
+
width: pageLayout.width,
|
|
254
|
+
height: pageLayout.height
|
|
255
|
+
}
|
|
256
|
+
};
|
|
257
|
+
}
|
|
258
|
+
getScrollPositionForPage(pageNumber, virtualItems, scale, rotation, pageCoordinates) {
|
|
259
|
+
const pageRect = this.getRectLocationForPage(pageNumber, virtualItems);
|
|
260
|
+
if (!pageRect) return null;
|
|
261
|
+
const scaledBasePosition = scalePosition(pageRect.origin, scale);
|
|
262
|
+
if (pageCoordinates) {
|
|
263
|
+
const rotatedSize = transformPosition(
|
|
264
|
+
{
|
|
265
|
+
width: pageRect.size.width,
|
|
266
|
+
height: pageRect.size.height
|
|
267
|
+
},
|
|
268
|
+
{
|
|
269
|
+
x: pageCoordinates.x,
|
|
270
|
+
y: pageCoordinates.y
|
|
271
|
+
},
|
|
272
|
+
rotation,
|
|
273
|
+
scale
|
|
274
|
+
);
|
|
275
|
+
return {
|
|
276
|
+
x: scaledBasePosition.x + rotatedSize.x + this.viewportGap,
|
|
277
|
+
y: scaledBasePosition.y + rotatedSize.y + this.viewportGap
|
|
278
|
+
};
|
|
279
|
+
}
|
|
280
|
+
return {
|
|
281
|
+
x: scaledBasePosition.x + this.viewportGap,
|
|
282
|
+
y: scaledBasePosition.y + this.viewportGap
|
|
283
|
+
};
|
|
284
|
+
}
|
|
285
|
+
getRectPositionForPage(pageNumber, virtualItems, scale, rotation, rect) {
|
|
286
|
+
const pageRect = this.getRectLocationForPage(pageNumber, virtualItems);
|
|
287
|
+
if (!pageRect) return null;
|
|
288
|
+
const scaledBasePosition = scalePosition(pageRect.origin, scale);
|
|
289
|
+
const rotatedSize = transformRect(
|
|
290
|
+
{
|
|
291
|
+
width: pageRect.size.width,
|
|
292
|
+
height: pageRect.size.height
|
|
293
|
+
},
|
|
294
|
+
rect,
|
|
295
|
+
rotation,
|
|
296
|
+
scale
|
|
297
|
+
);
|
|
298
|
+
return {
|
|
299
|
+
origin: {
|
|
300
|
+
x: scaledBasePosition.x + rotatedSize.origin.x,
|
|
301
|
+
y: scaledBasePosition.y + rotatedSize.origin.y
|
|
302
|
+
},
|
|
303
|
+
size: rotatedSize.size
|
|
304
|
+
};
|
|
305
|
+
}
|
|
306
|
+
};
|
|
307
|
+
|
|
308
|
+
// src/lib/strategies/vertical-strategy.ts
|
|
309
|
+
var VerticalScrollStrategy = class extends BaseScrollStrategy {
|
|
310
|
+
constructor(config) {
|
|
311
|
+
super(config);
|
|
312
|
+
}
|
|
313
|
+
createVirtualItems(pdfPageObject) {
|
|
314
|
+
let yOffset = 0;
|
|
315
|
+
return pdfPageObject.map((pagesInSpread, index) => {
|
|
316
|
+
let pageX = 0;
|
|
317
|
+
const pageLayouts = pagesInSpread.map((page) => {
|
|
318
|
+
const layout = {
|
|
319
|
+
pageNumber: page.index + 1,
|
|
320
|
+
pageIndex: page.index,
|
|
321
|
+
x: pageX,
|
|
322
|
+
y: 0,
|
|
323
|
+
width: page.size.width,
|
|
324
|
+
height: page.size.height,
|
|
325
|
+
rotatedWidth: page.rotatedSize.width,
|
|
326
|
+
rotatedHeight: page.rotatedSize.height
|
|
327
|
+
};
|
|
328
|
+
pageX += page.rotatedSize.width + this.pageGap;
|
|
329
|
+
return layout;
|
|
330
|
+
});
|
|
331
|
+
const width = pagesInSpread.reduce(
|
|
332
|
+
(sum, page, i) => sum + page.rotatedSize.width + (i < pagesInSpread.length - 1 ? this.pageGap : 0),
|
|
333
|
+
0
|
|
334
|
+
);
|
|
335
|
+
const height = Math.max(...pagesInSpread.map((p) => p.rotatedSize.height));
|
|
336
|
+
const item = {
|
|
337
|
+
id: `item-${index}`,
|
|
338
|
+
x: 0,
|
|
339
|
+
y: yOffset,
|
|
340
|
+
offset: yOffset,
|
|
341
|
+
width,
|
|
342
|
+
height,
|
|
343
|
+
pageLayouts,
|
|
344
|
+
pageNumbers: pagesInSpread.map((p) => p.index + 1),
|
|
345
|
+
index
|
|
346
|
+
};
|
|
347
|
+
yOffset += height + this.pageGap;
|
|
348
|
+
return item;
|
|
349
|
+
});
|
|
350
|
+
}
|
|
351
|
+
getTotalContentSize(virtualItems) {
|
|
352
|
+
if (virtualItems.length === 0) return { width: 0, height: 0 };
|
|
353
|
+
const maxWidth = Math.max(...virtualItems.map((item) => item.width));
|
|
354
|
+
const totalHeight = virtualItems[virtualItems.length - 1].y + virtualItems[virtualItems.length - 1].height;
|
|
355
|
+
return {
|
|
356
|
+
width: maxWidth,
|
|
357
|
+
height: totalHeight
|
|
358
|
+
};
|
|
359
|
+
}
|
|
360
|
+
getScrollOffset(viewport) {
|
|
361
|
+
return viewport.scrollTop;
|
|
362
|
+
}
|
|
363
|
+
getClientSize(viewport) {
|
|
364
|
+
return viewport.clientHeight;
|
|
365
|
+
}
|
|
366
|
+
};
|
|
367
|
+
|
|
368
|
+
// src/lib/strategies/horizontal-strategy.ts
|
|
369
|
+
var HorizontalScrollStrategy = class extends BaseScrollStrategy {
|
|
370
|
+
constructor(config) {
|
|
371
|
+
super(config);
|
|
372
|
+
}
|
|
373
|
+
createVirtualItems(pdfPageObject) {
|
|
374
|
+
let xOffset = 0;
|
|
375
|
+
return pdfPageObject.map((pagesInSpread, index) => {
|
|
376
|
+
let pageX = 0;
|
|
377
|
+
const pageLayouts = pagesInSpread.map((page) => {
|
|
378
|
+
const layout = {
|
|
379
|
+
pageNumber: page.index + 1,
|
|
380
|
+
pageIndex: page.index,
|
|
381
|
+
x: pageX,
|
|
382
|
+
y: 0,
|
|
383
|
+
width: page.size.width,
|
|
384
|
+
height: page.size.height,
|
|
385
|
+
rotatedWidth: page.rotatedSize.width,
|
|
386
|
+
rotatedHeight: page.rotatedSize.height
|
|
387
|
+
};
|
|
388
|
+
pageX += page.rotatedSize.width + this.pageGap;
|
|
389
|
+
return layout;
|
|
390
|
+
});
|
|
391
|
+
const width = pagesInSpread.reduce(
|
|
392
|
+
(sum, page, i) => sum + page.rotatedSize.width + (i < pagesInSpread.length - 1 ? this.pageGap : 0),
|
|
393
|
+
0
|
|
394
|
+
);
|
|
395
|
+
const height = Math.max(...pagesInSpread.map((p) => p.rotatedSize.height));
|
|
396
|
+
const item = {
|
|
397
|
+
id: `item-${index}`,
|
|
398
|
+
x: xOffset,
|
|
399
|
+
y: 0,
|
|
400
|
+
offset: xOffset,
|
|
401
|
+
width,
|
|
402
|
+
height,
|
|
403
|
+
pageLayouts,
|
|
404
|
+
pageNumbers: pagesInSpread.map((p) => p.index + 1),
|
|
405
|
+
index
|
|
406
|
+
};
|
|
407
|
+
xOffset += width + this.pageGap;
|
|
408
|
+
return item;
|
|
409
|
+
});
|
|
410
|
+
}
|
|
411
|
+
getTotalContentSize(virtualItems) {
|
|
412
|
+
if (virtualItems.length === 0) return { width: 0, height: 0 };
|
|
413
|
+
const totalWidth = virtualItems[virtualItems.length - 1].x + virtualItems[virtualItems.length - 1].width;
|
|
414
|
+
const maxHeight = Math.max(...virtualItems.map((item) => item.height));
|
|
415
|
+
return {
|
|
416
|
+
width: totalWidth,
|
|
417
|
+
height: maxHeight
|
|
418
|
+
};
|
|
419
|
+
}
|
|
420
|
+
getScrollOffset(viewport) {
|
|
421
|
+
return viewport.scrollLeft;
|
|
422
|
+
}
|
|
423
|
+
getClientSize(viewport) {
|
|
424
|
+
return viewport.clientWidth;
|
|
425
|
+
}
|
|
426
|
+
};
|
|
427
|
+
|
|
428
|
+
// src/lib/actions.ts
|
|
429
|
+
var UPDATE_SCROLL_STATE = "UPDATE_SCROLL_STATE";
|
|
430
|
+
var SET_DESIRED_SCROLL_POSITION = "SET_DESIRED_SCROLL_POSITION";
|
|
431
|
+
function updateScrollState(payload) {
|
|
432
|
+
return { type: UPDATE_SCROLL_STATE, payload };
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
// src/lib/selectors.ts
|
|
436
|
+
var getScrollerLayout = (state, scale) => {
|
|
437
|
+
return {
|
|
438
|
+
startSpacing: state.startSpacing,
|
|
439
|
+
endSpacing: state.endSpacing,
|
|
440
|
+
totalWidth: state.totalContentSize.width * scale,
|
|
441
|
+
totalHeight: state.totalContentSize.height * scale,
|
|
442
|
+
pageGap: state.pageGap * scale,
|
|
443
|
+
strategy: state.strategy,
|
|
444
|
+
items: state.renderedPageIndexes.map((idx) => {
|
|
445
|
+
return {
|
|
446
|
+
...state.virtualItems[idx],
|
|
447
|
+
pageLayouts: state.virtualItems[idx].pageLayouts.map((layout) => {
|
|
448
|
+
return {
|
|
449
|
+
...layout,
|
|
450
|
+
rotatedWidth: layout.rotatedWidth * scale,
|
|
451
|
+
rotatedHeight: layout.rotatedHeight * scale,
|
|
452
|
+
width: layout.width * scale,
|
|
453
|
+
height: layout.height * scale
|
|
454
|
+
};
|
|
455
|
+
})
|
|
456
|
+
};
|
|
457
|
+
})
|
|
458
|
+
};
|
|
459
|
+
};
|
|
460
|
+
|
|
461
|
+
// src/lib/scroll-plugin.ts
|
|
462
|
+
var ScrollPlugin = class extends import_core.BasePlugin {
|
|
463
|
+
constructor(id, registry, config) {
|
|
464
|
+
super(id, registry);
|
|
465
|
+
this.id = id;
|
|
466
|
+
this.config = config;
|
|
467
|
+
this.currentScale = 1;
|
|
468
|
+
this.currentRotation = Rotation.Degree0;
|
|
469
|
+
this.currentPage = 1;
|
|
470
|
+
this.layout$ = (0, import_core.createBehaviorEmitter)();
|
|
471
|
+
this.scroll$ = (0, import_core.createBehaviorEmitter)();
|
|
472
|
+
this.state$ = (0, import_core.createBehaviorEmitter)();
|
|
473
|
+
this.scrollerLayout$ = (0, import_core.createBehaviorEmitter)();
|
|
474
|
+
this.pageChange$ = (0, import_core.createEmitter)();
|
|
475
|
+
this.viewport = this.registry.getPlugin("viewport").provides();
|
|
476
|
+
this.strategyConfig = {
|
|
477
|
+
pageGap: this.config?.pageGap ?? 10,
|
|
478
|
+
viewportGap: this.viewport.getViewportGap(),
|
|
479
|
+
bufferSize: this.config?.bufferSize ?? 2
|
|
480
|
+
};
|
|
481
|
+
this.strategy = this.config?.strategy === "horizontal" /* Horizontal */ ? new HorizontalScrollStrategy(this.strategyConfig) : new VerticalScrollStrategy(this.strategyConfig);
|
|
482
|
+
this.initialPage = this.config?.initialPage;
|
|
483
|
+
this.currentScale = this.coreState.core.scale;
|
|
484
|
+
this.currentRotation = this.coreState.core.rotation;
|
|
485
|
+
this.viewport.onViewportChange((vp) => this.commitMetrics(this.computeMetrics(vp)), {
|
|
486
|
+
mode: "throttle",
|
|
487
|
+
wait: 250
|
|
488
|
+
});
|
|
489
|
+
this.coreStore.onAction(
|
|
490
|
+
import_core.SET_DOCUMENT,
|
|
491
|
+
(_action, state) => this.refreshAll((0, import_core.getPagesWithRotatedSize)(state.core), this.viewport.getMetrics())
|
|
492
|
+
);
|
|
493
|
+
this.coreStore.onAction(
|
|
494
|
+
import_core.SET_ROTATION,
|
|
495
|
+
(_action, state) => this.refreshAll((0, import_core.getPagesWithRotatedSize)(state.core), this.viewport.getMetrics())
|
|
496
|
+
);
|
|
497
|
+
this.coreStore.onAction(
|
|
498
|
+
import_core.SET_PAGES,
|
|
499
|
+
(_action, state) => this.refreshAll((0, import_core.getPagesWithRotatedSize)(state.core), this.viewport.getMetrics())
|
|
500
|
+
);
|
|
501
|
+
}
|
|
502
|
+
/* ------------------------------------------------------------------ */
|
|
503
|
+
/* ᴄᴏᴍᴘᴜᴛᴇʀs */
|
|
504
|
+
/* ------------------------------------------------------------------ */
|
|
505
|
+
computeLayout(pages) {
|
|
506
|
+
const virtualItems = this.strategy.createVirtualItems(pages);
|
|
507
|
+
const totalContentSize = this.strategy.getTotalContentSize(virtualItems);
|
|
508
|
+
return { virtualItems, totalContentSize };
|
|
509
|
+
}
|
|
510
|
+
computeMetrics(vp, items = this.state.virtualItems) {
|
|
511
|
+
return this.strategy.handleScroll(vp, items, this.currentScale);
|
|
512
|
+
}
|
|
513
|
+
/* ------------------------------------------------------------------ */
|
|
514
|
+
/* ᴄᴏᴍᴍɪᴛ (single source of truth) */
|
|
515
|
+
/* ------------------------------------------------------------------ */
|
|
516
|
+
commit(stateDelta, emit) {
|
|
517
|
+
this.dispatch(updateScrollState(stateDelta));
|
|
518
|
+
if (emit?.layout) this.layout$.emit(emit.layout);
|
|
519
|
+
if (emit?.metrics) {
|
|
520
|
+
this.scroll$.emit(emit.metrics);
|
|
521
|
+
if (emit.metrics.currentPage !== this.currentPage) {
|
|
522
|
+
this.currentPage = emit.metrics.currentPage;
|
|
523
|
+
this.pageChange$.emit(this.currentPage);
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
this.scrollerLayout$.emit(this.getScrollerLayoutFromState());
|
|
527
|
+
}
|
|
528
|
+
/* convenience wrappers */
|
|
529
|
+
commitMetrics(metrics) {
|
|
530
|
+
this.commit(metrics, { metrics });
|
|
531
|
+
}
|
|
532
|
+
/* full re-compute after page-spread or initialisation */
|
|
533
|
+
refreshAll(pages, vp) {
|
|
534
|
+
const layout = this.computeLayout(pages);
|
|
535
|
+
const metrics = this.computeMetrics(vp, layout.virtualItems);
|
|
536
|
+
this.commit({ ...layout, ...metrics }, { layout, metrics });
|
|
537
|
+
}
|
|
538
|
+
getVirtualItemsFromState() {
|
|
539
|
+
return this.state.virtualItems || [];
|
|
540
|
+
}
|
|
541
|
+
getScrollerLayoutFromState() {
|
|
542
|
+
const scale = this.coreState.core.scale;
|
|
543
|
+
return getScrollerLayout(this.state, scale);
|
|
544
|
+
}
|
|
545
|
+
pushScrollLayout() {
|
|
546
|
+
this.scrollerLayout$.emit(this.getScrollerLayoutFromState());
|
|
547
|
+
}
|
|
548
|
+
onStoreUpdated(_prevState, _newState) {
|
|
549
|
+
this.pushScrollLayout();
|
|
550
|
+
}
|
|
551
|
+
onCoreStoreUpdated(prevState, newState) {
|
|
552
|
+
if (prevState.core.scale !== newState.core.scale) {
|
|
553
|
+
this.currentScale = newState.core.scale;
|
|
554
|
+
this.commitMetrics(this.computeMetrics(this.viewport.getMetrics()));
|
|
555
|
+
}
|
|
556
|
+
if (prevState.core.rotation !== newState.core.rotation) {
|
|
557
|
+
this.currentRotation = newState.core.rotation;
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
/**
|
|
561
|
+
* Change the scroll strategy at runtime (e.g., vertical <-> horizontal)
|
|
562
|
+
* @param newStrategy ScrollStrategy.Horizontal or ScrollStrategy.Vertical
|
|
563
|
+
*/
|
|
564
|
+
setScrollStrategy(newStrategy) {
|
|
565
|
+
if (newStrategy === "horizontal" /* Horizontal */ && this.strategy instanceof HorizontalScrollStrategy || newStrategy === "vertical" /* Vertical */ && this.strategy instanceof VerticalScrollStrategy) {
|
|
566
|
+
return;
|
|
567
|
+
}
|
|
568
|
+
this.strategy = newStrategy === "horizontal" /* Horizontal */ ? new HorizontalScrollStrategy(this.strategyConfig) : new VerticalScrollStrategy(this.strategyConfig);
|
|
569
|
+
this.dispatch(
|
|
570
|
+
updateScrollState({
|
|
571
|
+
strategy: newStrategy
|
|
572
|
+
})
|
|
573
|
+
);
|
|
574
|
+
const pages = (0, import_core.getPagesWithRotatedSize)(this.coreState.core);
|
|
575
|
+
this.refreshAll(pages, this.viewport.getMetrics());
|
|
576
|
+
}
|
|
577
|
+
buildCapability() {
|
|
578
|
+
return {
|
|
579
|
+
onStateChange: this.state$.on,
|
|
580
|
+
onLayoutChange: this.layout$.on,
|
|
581
|
+
onScroll: this.scroll$.on,
|
|
582
|
+
onPageChange: this.pageChange$.on,
|
|
583
|
+
onScrollerData: this.scrollerLayout$.on,
|
|
584
|
+
scrollToPage: (options) => {
|
|
585
|
+
const { pageNumber, behavior = "smooth", pageCoordinates, center = false } = options;
|
|
586
|
+
const virtualItems = this.getVirtualItemsFromState();
|
|
587
|
+
const position = this.strategy.getScrollPositionForPage(
|
|
588
|
+
pageNumber,
|
|
589
|
+
virtualItems,
|
|
590
|
+
this.currentScale,
|
|
591
|
+
this.currentRotation,
|
|
592
|
+
pageCoordinates
|
|
593
|
+
);
|
|
594
|
+
if (position) {
|
|
595
|
+
this.viewport.scrollTo({ ...position, behavior, center });
|
|
596
|
+
}
|
|
597
|
+
},
|
|
598
|
+
scrollToNextPage: (behavior = "smooth") => {
|
|
599
|
+
const virtualItems = this.getVirtualItemsFromState();
|
|
600
|
+
const currentItemIndex = virtualItems.findIndex(
|
|
601
|
+
(item) => item.pageNumbers.includes(this.currentPage)
|
|
602
|
+
);
|
|
603
|
+
if (currentItemIndex >= 0 && currentItemIndex < virtualItems.length - 1) {
|
|
604
|
+
const nextItem = virtualItems[currentItemIndex + 1];
|
|
605
|
+
const position = this.strategy.getScrollPositionForPage(
|
|
606
|
+
nextItem.pageNumbers[0],
|
|
607
|
+
virtualItems,
|
|
608
|
+
this.currentScale,
|
|
609
|
+
this.currentRotation
|
|
610
|
+
);
|
|
611
|
+
if (position) {
|
|
612
|
+
this.viewport.scrollTo({ ...position, behavior });
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
},
|
|
616
|
+
scrollToPreviousPage: (behavior = "smooth") => {
|
|
617
|
+
const virtualItems = this.getVirtualItemsFromState();
|
|
618
|
+
const currentItemIndex = virtualItems.findIndex(
|
|
619
|
+
(item) => item.pageNumbers.includes(this.currentPage)
|
|
620
|
+
);
|
|
621
|
+
if (currentItemIndex > 0) {
|
|
622
|
+
const prevItem = virtualItems[currentItemIndex - 1];
|
|
623
|
+
const position = this.strategy.getScrollPositionForPage(
|
|
624
|
+
prevItem.pageNumbers[0],
|
|
625
|
+
virtualItems,
|
|
626
|
+
this.currentScale,
|
|
627
|
+
this.currentRotation
|
|
628
|
+
);
|
|
629
|
+
if (position) {
|
|
630
|
+
this.viewport.scrollTo({ ...position, behavior });
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
},
|
|
634
|
+
getMetrics: this.getMetrics.bind(this),
|
|
635
|
+
getLayout: this.getLayout.bind(this),
|
|
636
|
+
getRectPositionForPage: this.getRectPositionForPage.bind(this),
|
|
637
|
+
getPageGap: () => this.state.pageGap,
|
|
638
|
+
getScrollerLayout: () => this.getScrollerLayoutFromState(),
|
|
639
|
+
setScrollStrategy: (strategy) => this.setScrollStrategy(strategy)
|
|
640
|
+
};
|
|
641
|
+
}
|
|
642
|
+
getMetrics(viewport) {
|
|
643
|
+
const metrics = viewport || this.viewport.getMetrics();
|
|
644
|
+
const virtualItems = this.getVirtualItemsFromState();
|
|
645
|
+
return this.strategy.handleScroll(metrics, virtualItems, this.currentScale);
|
|
646
|
+
}
|
|
647
|
+
getLayout() {
|
|
648
|
+
return {
|
|
649
|
+
virtualItems: this.state.virtualItems,
|
|
650
|
+
totalContentSize: this.state.totalContentSize
|
|
651
|
+
};
|
|
652
|
+
}
|
|
653
|
+
getRectPositionForPage(pageIndex, rect, scale, rotation) {
|
|
654
|
+
return this.strategy.getRectPositionForPage(
|
|
655
|
+
pageIndex + 1,
|
|
656
|
+
this.state.virtualItems,
|
|
657
|
+
scale ?? this.currentScale,
|
|
658
|
+
rotation ?? this.currentRotation,
|
|
659
|
+
rect
|
|
660
|
+
);
|
|
661
|
+
}
|
|
662
|
+
async initialize() {
|
|
663
|
+
}
|
|
664
|
+
async destroy() {
|
|
665
|
+
this.layout$.clear();
|
|
666
|
+
this.scroll$.clear();
|
|
667
|
+
this.pageChange$.clear();
|
|
668
|
+
this.state$.clear();
|
|
669
|
+
super.destroy();
|
|
670
|
+
}
|
|
671
|
+
};
|
|
672
|
+
ScrollPlugin.id = "scroll";
|
|
673
|
+
|
|
674
|
+
// src/lib/manifest.ts
|
|
675
|
+
var SCROLL_PLUGIN_ID = "scroll";
|
|
676
|
+
var manifest = {
|
|
677
|
+
id: SCROLL_PLUGIN_ID,
|
|
678
|
+
name: "Scroll Plugin",
|
|
679
|
+
version: "1.0.0",
|
|
680
|
+
provides: ["scroll"],
|
|
681
|
+
requires: ["viewport"],
|
|
682
|
+
optional: [],
|
|
683
|
+
defaultConfig: {
|
|
684
|
+
enabled: true,
|
|
685
|
+
pageGap: 10
|
|
686
|
+
}
|
|
687
|
+
};
|
|
688
|
+
|
|
689
|
+
// src/lib/reducer.ts
|
|
690
|
+
var import_core2 = require("@embedpdf/core");
|
|
691
|
+
var defaultScrollMetrics = {
|
|
692
|
+
currentPage: 1,
|
|
693
|
+
visiblePages: [],
|
|
694
|
+
pageVisibilityMetrics: [],
|
|
695
|
+
renderedPageIndexes: [],
|
|
696
|
+
scrollOffset: { x: 0, y: 0 },
|
|
697
|
+
startSpacing: 0,
|
|
698
|
+
endSpacing: 0
|
|
699
|
+
};
|
|
700
|
+
var initialState = (coreState, config) => ({
|
|
701
|
+
virtualItems: [],
|
|
702
|
+
totalContentSize: { width: 0, height: 0 },
|
|
703
|
+
desiredScrollPosition: { x: 0, y: 0 },
|
|
704
|
+
strategy: config.strategy ?? "vertical" /* Vertical */,
|
|
705
|
+
pageGap: config.pageGap ?? 10,
|
|
706
|
+
scale: coreState.scale,
|
|
707
|
+
...defaultScrollMetrics
|
|
708
|
+
});
|
|
709
|
+
var scrollReducer = (state, action) => {
|
|
710
|
+
switch (action.type) {
|
|
711
|
+
case import_core2.SET_SCALE:
|
|
712
|
+
return { ...state, scale: action.payload };
|
|
713
|
+
case UPDATE_SCROLL_STATE:
|
|
714
|
+
return { ...state, ...action.payload };
|
|
715
|
+
case SET_DESIRED_SCROLL_POSITION:
|
|
716
|
+
return { ...state, desiredScrollPosition: action.payload };
|
|
717
|
+
default:
|
|
718
|
+
return state;
|
|
719
|
+
}
|
|
720
|
+
};
|
|
721
|
+
|
|
722
|
+
// src/lib/index.ts
|
|
723
|
+
var ScrollPluginPackage = {
|
|
724
|
+
manifest,
|
|
725
|
+
create: (registry, _engine, config) => new ScrollPlugin(SCROLL_PLUGIN_ID, registry, config),
|
|
726
|
+
reducer: scrollReducer,
|
|
727
|
+
initialState: (coreState, config) => initialState(coreState, config)
|
|
728
|
+
};
|
|
729
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
730
|
+
0 && (module.exports = {
|
|
731
|
+
SCROLL_PLUGIN_ID,
|
|
732
|
+
ScrollPlugin,
|
|
733
|
+
ScrollPluginPackage,
|
|
734
|
+
ScrollStrategy,
|
|
735
|
+
manifest
|
|
736
|
+
});
|
|
737
|
+
//# sourceMappingURL=index.cjs.map
|