@readium/navigator 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/LICENSE +28 -0
  2. package/README.MD +11 -0
  3. package/dist/assets/AccessibleDfA.otf +0 -0
  4. package/dist/assets/iAWriterDuospace-Regular.ttf +0 -0
  5. package/dist/index.js +6263 -0
  6. package/dist/index.umd.cjs +107 -0
  7. package/package.json +65 -0
  8. package/src/Navigator.ts +66 -0
  9. package/src/audio/engine/AudioEngine.ts +136 -0
  10. package/src/audio/engine/WebAudioEngine.ts +286 -0
  11. package/src/audio/engine/index.ts +2 -0
  12. package/src/audio/index.ts +1 -0
  13. package/src/epub/EpubNavigator.ts +507 -0
  14. package/src/epub/frame/FrameBlobBuilder.ts +211 -0
  15. package/src/epub/frame/FrameComms.ts +142 -0
  16. package/src/epub/frame/FrameManager.ts +134 -0
  17. package/src/epub/frame/FramePoolManager.ts +179 -0
  18. package/src/epub/frame/index.ts +3 -0
  19. package/src/epub/fxl/FXLCoordinator.ts +152 -0
  20. package/src/epub/fxl/FXLFrameManager.ts +286 -0
  21. package/src/epub/fxl/FXLFramePoolManager.ts +632 -0
  22. package/src/epub/fxl/FXLPeripherals.ts +587 -0
  23. package/src/epub/fxl/FXLPeripheralsDebug.ts +46 -0
  24. package/src/epub/fxl/FXLSpreader.ts +95 -0
  25. package/src/epub/fxl/index.ts +5 -0
  26. package/src/epub/index.ts +3 -0
  27. package/src/helpers/sML.ts +120 -0
  28. package/src/index.ts +3 -0
  29. package/types/src/Navigator.d.ts +41 -0
  30. package/types/src/audio/engine/AudioEngine.d.ts +114 -0
  31. package/types/src/audio/engine/WebAudioEngine.d.ts +107 -0
  32. package/types/src/audio/engine/index.d.ts +2 -0
  33. package/types/src/audio/index.d.ts +1 -0
  34. package/types/src/epub/EpubNavigator.d.ts +66 -0
  35. package/types/src/epub/frame/FrameBlobBuilder.d.ts +13 -0
  36. package/types/src/epub/frame/FrameComms.d.ts +26 -0
  37. package/types/src/epub/frame/FrameManager.d.ts +21 -0
  38. package/types/src/epub/frame/FramePoolManager.d.ts +17 -0
  39. package/types/src/epub/frame/index.d.ts +3 -0
  40. package/types/src/epub/fxl/FXLCoordinator.d.ts +37 -0
  41. package/types/src/epub/fxl/FXLFrameManager.d.ts +41 -0
  42. package/types/src/epub/fxl/FXLFramePoolManager.d.ts +93 -0
  43. package/types/src/epub/fxl/FXLPeripherals.d.ts +97 -0
  44. package/types/src/epub/fxl/FXLPeripheralsDebug.d.ts +13 -0
  45. package/types/src/epub/fxl/FXLSpreader.d.ts +12 -0
  46. package/types/src/epub/fxl/index.d.ts +5 -0
  47. package/types/src/epub/index.d.ts +3 -0
  48. package/types/src/helpers/sML.d.ts +51 -0
  49. package/types/src/index.d.ts +3 -0
@@ -0,0 +1,587 @@
1
+ import { FXLCoordinator, Point } from "./FXLCoordinator";
2
+ import { FXLFramePoolManager } from "./FXLFramePoolManager";
3
+ import { FXLPeripheralsDebug } from "./FXLPeripheralsDebug";
4
+
5
+ const MAX_SCALE = 6; // 6x zoom
6
+ const MIN_SCALE = 1.02;
7
+ const ZOOM_OVERSCROLL_THRESHOLD = 50;
8
+
9
+ export interface PanTracker {
10
+ startX: number;
11
+ endX: number;
12
+ overscrollX: number;
13
+ overscrollY: number;
14
+ startY: number;
15
+ letItGo: boolean;
16
+ preventClick: boolean;
17
+ translateX: number;
18
+ translateY: number;
19
+ touchID: number;
20
+ }
21
+
22
+ export interface PinchTracker {
23
+ startDistance: number;
24
+ startScale: number;
25
+ target: Point;
26
+ startTranslate: Point;
27
+ touchN: number;
28
+ }
29
+
30
+ export interface Zoomer {
31
+ scale: number;
32
+ translate: {
33
+ X: number;
34
+ Y: number;
35
+ };
36
+ }
37
+
38
+ export class FXLPeripherals {
39
+
40
+ private readonly manager: FXLFramePoolManager;
41
+ private readonly coordinator: FXLCoordinator;
42
+
43
+ public dragState = 0;
44
+ private minimumMoved = false;
45
+ public pan: PanTracker = {
46
+ startX: 0,
47
+ endX: 0,
48
+ startY: 0,
49
+ overscrollX: 0,
50
+ overscrollY: 0,
51
+ letItGo: false,
52
+ preventClick: false,
53
+ translateX: 0,
54
+ translateY: 0,
55
+ touchID: 0
56
+ };
57
+ private pinch: PinchTracker = {
58
+ startDistance: 0,
59
+ startScale: 0,
60
+ target: {X: 0, Y: 0},
61
+ touchN: 0,
62
+ startTranslate: {X: 0, Y: 0}
63
+ };
64
+
65
+ // Scale
66
+ private _scale = 1;
67
+ public get scale() {
68
+ return this._scale;
69
+ }
70
+ private scaleDebouncer = 0;
71
+ public set scale(value: number) {
72
+ if(isNaN(value)) value = 1;
73
+ window.clearTimeout(this.scaleDebouncer);
74
+ this.scaleDebouncer = window.setTimeout(() => {
75
+ if(this.dragState === 0) {
76
+ if(this.scale < MIN_SCALE) {
77
+ this.pan.translateX = 0;
78
+ this.pan.translateY = 0;
79
+ this.clearPan();
80
+ this.manager.updateBookStyle();
81
+ }
82
+ }
83
+ this.manager.listener("zoom", value);
84
+ }, 100);
85
+ this._scale = value;
86
+ }
87
+
88
+ private frameBounds: DOMRect | null = null;
89
+ private debugger: FXLPeripheralsDebug | null = null;
90
+
91
+ constructor(manager: FXLFramePoolManager, debug=false) {
92
+ this.manager = manager;
93
+ this.coordinator = new FXLCoordinator();
94
+ this.attachEvents();
95
+
96
+ if(debug) {
97
+ this.debugger = new FXLPeripheralsDebug();
98
+ }
99
+ }
100
+
101
+ private readonly btouchstartHandler = this.touchstartHandler.bind(this);
102
+ private readonly btouchendHandler = this.touchendHandler.bind(this);
103
+ private readonly btouchmoveHandler = this.touchmoveHandler.bind(this);
104
+ private readonly bdblclickHandler = this.dblclickHandler.bind(this);
105
+ // private readonly bclickHandler = this.clickHandler.bind(this);
106
+ private readonly bmousedownHandler = this.mousedownHandler.bind(this);
107
+ private readonly bmouseupHandler = this.mouseupHandler.bind(this);
108
+ private readonly bmousemoveHandler = this.mousemoveHandler.bind(this);
109
+
110
+ /**
111
+ * Attaches listeners to required events.
112
+ */
113
+ attachEvents() {
114
+ this.observe(this.manager.spineElement);
115
+
116
+ // Keep track pointer hold and dragging distance
117
+ this.pan = {
118
+ startX: 0,
119
+ startY: 0,
120
+ endX: 0,
121
+ overscrollX: 0,
122
+ overscrollY: 0,
123
+ letItGo: false,
124
+ preventClick: false,
125
+ translateX: 0,
126
+ translateY: 0,
127
+ touchID: 0,
128
+ };
129
+
130
+ this.pinch = {
131
+ startDistance: 0,
132
+ startScale: 0,
133
+ target: {X: 0, Y: 0},
134
+ startTranslate: {X: 0, Y: 0},
135
+ touchN: 0
136
+ };
137
+ }
138
+
139
+ /**
140
+ * Clear drag after touchend and mouseup event
141
+ */
142
+ private clearPan() {
143
+ this.pan.letItGo = false;
144
+ this.pan.touchID = 0;
145
+ this.pan.endX = 0;
146
+ this.pan.overscrollX = 0;
147
+ this.pan.overscrollY = 0;
148
+ }
149
+
150
+ public clearPinch() {
151
+ this.pinch = {
152
+ startDistance: 0,
153
+ startScale: this.pinch.startScale,
154
+ target: {X: 0, Y: 0},
155
+ touchN: 0,
156
+ startTranslate: {X: 0, Y: 0}
157
+ };
158
+ }
159
+
160
+ observe(item: EventTarget) {
161
+ item.addEventListener("touchstart", this.btouchstartHandler as EventListener);
162
+ item.addEventListener("touchend", this.btouchendHandler as EventListener);
163
+ item.addEventListener("touchmove", this.btouchmoveHandler as EventListener, {
164
+ passive: true
165
+ });
166
+ item.addEventListener("dblclick", this.bdblclickHandler as EventListener, {
167
+ passive: true
168
+ });
169
+ item.addEventListener("mousedown", this.bmousedownHandler as EventListener);
170
+ item.addEventListener("mouseup", this.bmouseupHandler as EventListener);
171
+ item.addEventListener("mousemove", this.bmousemoveHandler as EventListener);
172
+ // item.addEventListener("click", this.bclickHandler as EventListener);
173
+ }
174
+
175
+ clickHandler(_: MouseEvent) {
176
+ // e.preventDefault();
177
+ }
178
+
179
+ /**
180
+ * touchstart event handler
181
+ */
182
+ touchstartHandler(e: TouchEvent) {
183
+ // Prevent dragging / swiping on inputs, selects and textareas
184
+ const ignoreSlider = ["TEXTAREA", "OPTION", "INPUT", "SELECT"].indexOf((e.target as Element).nodeName) !== -1;
185
+ if (ignoreSlider)
186
+ return;
187
+
188
+ e.stopPropagation();
189
+ this.frameBounds = this.manager.currentBounds;
190
+ this.coordinator.refreshOuterPixels(this.frameBounds);
191
+
192
+ switch (e.touches.length) {
193
+ case 3:
194
+ // this.ui.toggle();
195
+ return;
196
+ case 2: {
197
+ // Pinch
198
+ e.preventDefault();
199
+ this.pinch.startDistance = this.coordinator.getTouchDistance(e);
200
+
201
+ // Reverse translate
202
+ // Z = TX + (CX - SX) * 1 / ZS
203
+ // CX = ZS * Z - ZS * TX + SX
204
+ /*const cx = this.scale * this.pan.translateX - this.scale * this.pan.translateX + this.pan.startX;
205
+ const cy = this.scale * this.pan.translateY - this.scale * this.pan.translateY + this.pan.startY;
206
+ this.pan.startX += center!.X - cx;
207
+ this.pan.startY += center!.Y - cy;
208
+ this.pan.startX = center!.X;
209
+ this.pan.startY = center!.Y;*/
210
+ //this.pan.translateX = -1* (center!.X - this.manager.width / 2);
211
+ //this.pan.translateY = -1* (center!.Y - this.manager.height / 2);
212
+ const st = this.startTouch(e);
213
+ this.pan.startX = st.X;
214
+ this.pan.startY = st.Y;
215
+
216
+ this.dragState = 2;
217
+ this.manager.updateBookStyle(true);
218
+ if(!this.isScaled) {
219
+ this.pinch.target = {X: 0, Y: 0};
220
+ this.pinch.startScale = this.scale;
221
+ } else {
222
+ this.pinch.target.X -= this.pan.translateX * (this.pinch.startScale / this.scale);
223
+ this.pinch.target.Y -= this.pan.translateY * (this.pinch.startScale / this.scale);
224
+ this.pinch.target = {X: 0, Y: 0};
225
+ this.pinch.startScale = 1 / this.scale;
226
+ }
227
+ /*this.pinch.target = this.startTouch(e);
228
+ this.pinch.target.X -= this.manager.width / 2;
229
+ this.pinch.target.Y -= this.manager.height / 2;*/
230
+ this.pinch.startTranslate = {X: this.pan.translateX, Y: this.pan.translateY};
231
+
232
+ if(this.debugger?.show) {
233
+ this.debugger.DOM.touch2.style.display = "";
234
+ this.debugger.DOM.center.style.display = "";
235
+ this.debugger.DOM.pinchTarget.style.display = "";
236
+ //this.debugger.DOM.pinchTarget.style.top = `${this.pinch.target.Y-5}px`;
237
+ //this.debugger.DOM.pinchTarget.style.left = `${this.pinch.target.X-5}px`;
238
+ //this.debugger.DOM.pinchTarget.innerText = `${this.pinch.target.X},${this.pinch.target.Y}`;
239
+ }
240
+ return;
241
+ }
242
+ // @ts-ignore
243
+ case 1:
244
+ this.pan.touchID = e.touches[0].identifier;
245
+ if(this.debugger?.show) this.debugger.DOM.touch1.style.display = "";
246
+ // Fallthrough on purpose
247
+ default:
248
+ if(this.dragState < 1) this.dragState = 1;
249
+ this.manager.updateBookStyle(true);
250
+ }
251
+ this.manager.updateSpineStyle(false);
252
+ const st = this.startTouch(e);
253
+ this.pan.startX = st.X;
254
+ this.pan.startY = st.Y;
255
+ }
256
+
257
+ private startTouch(e: TouchEvent): Point {
258
+ const center = this.coordinator.getTouchCenter(e) || this.coordinator.getBibiEventCoord(e);
259
+ return {
260
+ // SX = CX - Z * SC + MW / 2
261
+ X: (center.X - this.manager.width / 2) - this.pan.translateX * this.scale + this.manager.width / 2,
262
+ Y: (center.Y - this.manager.height / 2) - this.pan.translateY * this.scale + this.manager.height / 2
263
+ };
264
+ }
265
+
266
+ /**
267
+ * touchend event handler
268
+ */
269
+ touchendHandler(e: TouchEvent) {
270
+ e.stopPropagation();
271
+
272
+ if(!e.touches || e.touches.length === 0) {
273
+ if ((this.pan.endX && !this.isScaled)) {
274
+ if(this.pinch.touchN) {
275
+ this.pan.endX = this.pan.startX;
276
+ }
277
+ // Only possibly go to another page if:
278
+ // - Moved horizontally sufficiently
279
+ // - Not currently scale
280
+ // - Not ending a pinch gesture
281
+ this.updateAfterDrag();
282
+ } else if(!this.pinch.touchN && Math.abs(this.pan.overscrollX) > ZOOM_OVERSCROLL_THRESHOLD && Math.abs(this.pan.overscrollY) < ZOOM_OVERSCROLL_THRESHOLD / 2) {
283
+ // Panned past the limits on the horizontal axis while zoomed in.
284
+ // This simulates dragging while not scaled.
285
+ this.pan.startX = 0;
286
+ this.pan.endX = -this.pan.overscrollX;
287
+ this.updateAfterDrag();
288
+ }
289
+ this.dragState = 0;
290
+ this.minimumMoved = false;
291
+ this.clearPinch();
292
+ if(this.debugger?.show) {
293
+ this.debugger.DOM.center.style.display = "none";
294
+ this.debugger.DOM.touch1.style.display = "none";
295
+ this.debugger.DOM.touch2.style.display = "none";
296
+ }
297
+ } else if(e.touches.length === 1) {
298
+ // Back to only one touch from 2+
299
+ this.dragState = 1;
300
+ if(e.touches[0].identifier !== this.pan.touchID) {
301
+ this.pan.touchID = e.touches[0].identifier;
302
+ }
303
+
304
+ if(this.debugger?.show) {
305
+ this.debugger.DOM.center.style.display = "none";
306
+ this.debugger.DOM.touch2.style.display = "none";
307
+ this.debugger.DOM.pinchTarget.style.display = "none";
308
+ }
309
+
310
+ // Reverse translate
311
+ // Z = TX + (CX - SX) * 1 / ZS
312
+ // CX = ZS * Z - ZS * TX + SX
313
+ /*const cx = this.scale * this.pan.translateX - this.scale * this.pan.translateX + this.pan.startX;
314
+ const cy = this.scale * this.pan.translateY - this.scale * this.pan.translateY + this.pan.startY;
315
+ this.pan.startX += coords.X - cx;
316
+ this.pan.startY += coords.Y - cy;*/
317
+ const st = this.startTouch(e);
318
+ this.pan.startX = st.X;
319
+ this.pan.startY = st.Y;
320
+ }
321
+ window.setTimeout(() => {
322
+ // TODO
323
+ this.manager.updateBookStyle(true);
324
+ if(this.dragState === 0) {
325
+ if(this.scale < MIN_SCALE) {
326
+ this.pan.translateX = 0;
327
+ this.pan.translateY = 0;
328
+ } else {
329
+ /*const maxEdgeX = this.frameBounds!.width / 2 - this.manager!.width / 2 * 1 / this.scale;
330
+ const maxEdgeY = this.frameBounds!.height / 2 - this.manager!.height / 2 * 1 / this.scale;
331
+ if(this.frameBounds!.width * this.scale > this.manager!.width) this.pan.translateX = Math.max(-maxEdgeX, Math.min(maxEdgeX, this.pan.translateX));
332
+ if(this.frameBounds!.height * this.scale > this.manager!.height) this.pan.translateY = Math.max(-maxEdgeY, Math.min(maxEdgeY, this.pan.translateY));*/
333
+ }
334
+ this.clearPan();
335
+ }
336
+ this.manager.updateBookStyle(true);
337
+ }, 50);
338
+ }
339
+
340
+ private moveFrame = 0;
341
+
342
+ /**
343
+ * touchmove event handler
344
+ */
345
+ touchmoveHandler(e: TouchEvent) {
346
+ e.stopPropagation();
347
+ const coords = this.coordinator.getBibiEventCoord(e);
348
+
349
+ if ((Math.abs(this.pan.startY - coords.Y) + Math.abs(this.pan.startX - coords.X)) > 5) {
350
+ if(!this.minimumMoved) {
351
+ this.manager.deselect();
352
+ this.minimumMoved = true;
353
+ }
354
+ if(this.dragState < 1) this.dragState = 1;
355
+ }
356
+
357
+ const currentDistance = this.coordinator?.getTouchDistance(e);
358
+
359
+ let updateBook = false;
360
+
361
+ const oldScale = this.scale;
362
+ // const oldDistance = this.pinch.startDistance;
363
+ if(this.dragState === 2 && currentDistance) {
364
+ this.pinch.touchN++;
365
+ if(this.pinch.touchN < 4) return;
366
+ let newScale = currentDistance / this.pinch.startDistance * this.scale;
367
+ if(newScale >= MAX_SCALE)
368
+ newScale = MAX_SCALE;
369
+ if(newScale <= MIN_SCALE)
370
+ newScale = 1;
371
+ this.scale = newScale;
372
+ this.pinch.startDistance = currentDistance;
373
+ updateBook = true;
374
+ }
375
+
376
+ if (this.pan.letItGo === false) {
377
+ this.pan.letItGo = Math.abs(this.pan.startY - coords.Y) < Math.abs(this.pan.startX - coords.X);
378
+ }
379
+
380
+ if(this.debugger?.show) {
381
+ this.debugger.DOM.touch1.style.top = `${coords.Y-10}px`;
382
+ this.debugger.DOM.touch1.style.left = `${coords.X-10}px`;
383
+ this.debugger.DOM.touch1.innerText = `${coords.X.toFixed(2)},${coords.Y.toFixed(2)}`;
384
+ }
385
+
386
+ if ((this.dragState > 0 && this.isScaled) || this.dragState > 1) {
387
+ if(this.dragState === 1) {
388
+ const center = {
389
+ X: coords.X - this.manager.width / 2,
390
+ Y: coords.Y - this.manager.height / 2
391
+ };
392
+ // Z = (CX - (SX - MW / 2)) * 1 / SC
393
+ this.pan.translateX = (center.X - (this.pan.startX - this.manager.width / 2)) * 1 / this.scale;
394
+ this.pan.translateY = (center.Y - (this.pan.startY - this.manager.height / 2)) * 1 / this.scale;
395
+ //console.log("#1", this.pan.translateY, "<- (", center.Y, "-", this.pan.startY, ") * 1 /", this.scale);
396
+ } else if(this.dragState === 2) {
397
+ const center = this.coordinator.getTouchCenter(e)!;
398
+ if(this.debugger?.show) {
399
+ this.debugger.DOM.center.style.top = `${center.Y-5}px`;
400
+ this.debugger.DOM.center.style.left = `${center.X-5}px`;
401
+ this.debugger.DOM.center.innerText = `${center.X.toFixed(2)},${center.Y.toFixed(2)}`;
402
+
403
+ const coords = this.coordinator.getBibiEventCoord(e, 1);
404
+ this.debugger.DOM.touch2.style.top = `${coords.Y-10}px`;
405
+ this.debugger.DOM.touch2.style.left = `${coords.X-10}px`;
406
+ this.debugger.DOM.touch2.innerText = `${coords.X.toFixed(2)},${coords.Y.toFixed(2)}`;
407
+ }
408
+
409
+ center.X -= this.manager.width / 2;
410
+ center.Y -= this.manager.height / 2;
411
+
412
+ /*
413
+ const pinchMultiplier = this.scale / this.pinch.startScale;
414
+ center.X /= pinchMultiplier;
415
+ center.Y /= pinchMultiplier;
416
+ */
417
+ //const pinchMultiplier = this.scale / this.pinch.startScale;
418
+
419
+ let ptx = -center.X / oldScale;
420
+ ptx += center.X / this.scale;
421
+ //ptx += (this.pan.translateX - this.pinch.startTranslate.X) * pinchMultiplier; // Pan align
422
+ this.pinch.target.X += ptx;
423
+ center.X += this.pinch.target.X * this.scale / this.pinch.startScale;
424
+
425
+ let pty = -center.Y / oldScale;
426
+ pty += center.Y / this.scale;
427
+ //pty += (this.pan.translateY - this.pinch.startTranslate.Y) * pinchMultiplier; // Pan align
428
+ this.pinch.target.Y += pty;
429
+ center.Y += this.pinch.target.Y * this.scale / this.pinch.startScale;
430
+
431
+ // Z = (CX - (SX - MW / 2)) * 1 / SC
432
+ let translateX = (center.X - (this.pan.startX - this.manager.width / 2)) * 1 / this.scale;
433
+ let translateY = (center.Y - (this.pan.startY - this.manager.height / 2)) * 1 / this.scale;
434
+
435
+ //
436
+
437
+ this.pan.translateX = translateX;
438
+ this.pan.translateY = translateY;
439
+ // console.log("#2", this.pan.translateY, "<- (", center.Y, "-", this.pan.startY, ") * 1 /", this.scale);
440
+
441
+ //(this.pinch.target.X - this.manager.width / 2) - this.pan.translateX * this.scale + this.manager.width / 2
442
+ ///(center.Y - this.manager.height / 2) - this.pan.translateY * this.scale + this.manager.height / 2
443
+
444
+ if(this.debugger?.show) {
445
+ this.debugger.DOM.pinchTarget.style.left = `${this.pinch.target.X * this.scale / this.pinch.startScale-5+this.manager.width / 2}px`;
446
+ this.debugger.DOM.pinchTarget.style.top = `${this.pinch.target.Y * this.scale / this.pinch.startScale-5+this.manager.height / 2}px`;
447
+ this.debugger.DOM.pinchTarget.innerText = `${(this.pinch.target.X * this.scale / this.pinch.startScale).toFixed(2)},${(this.pinch.target.Y * this.scale / this.pinch.startScale).toFixed(2)}`;
448
+ }
449
+ }
450
+
451
+ const maxEdgeX = this.frameBounds!.width / 6;
452
+ const maxEdgeY = this.frameBounds!.height / 6;
453
+
454
+ if (this.pan.translateX < -maxEdgeX) {
455
+ this.pan.overscrollX = -(maxEdgeX + this.pan.translateX);
456
+ this.pan.translateX = -maxEdgeX;
457
+ }
458
+ if (this.pan.translateY < -maxEdgeY) {
459
+ this.pan.overscrollY = -(maxEdgeY + this.pan.translateY);
460
+ this.pan.translateY = -maxEdgeY;
461
+ }
462
+
463
+ if (this.pan.translateX > maxEdgeX) {
464
+ this.pan.overscrollX = maxEdgeX - this.pan.translateX;
465
+ this.pan.translateX = maxEdgeX;
466
+ }
467
+ if (this.pan.translateY > maxEdgeY) {
468
+ this.pan.overscrollY = maxEdgeY - this.pan.translateY;
469
+ this.pan.translateY = maxEdgeY;
470
+ }
471
+
472
+ updateBook = true;
473
+
474
+ if(this.debugger?.show)
475
+ this.debugger.DOM.stats.innerText =
476
+ `TX: ${this.pan.translateX.toFixed(2)}\nTY: ${this.pan.translateY.toFixed(2)}\nZoom: ${this.scale.toFixed(2)}\nOverscroll: ${this.pan.overscrollX.toFixed(2)},${this.pan.overscrollY.toFixed(2)}`;
477
+ }
478
+
479
+ if(updateBook) {
480
+ this.manager.updateBookStyle();
481
+ return;
482
+ }
483
+
484
+ /*if(this.slider.ttb) {
485
+ this.ui.mousing = false;
486
+ return;
487
+ }*/
488
+
489
+ if (this.dragState > 0 && this.pan.letItGo) {
490
+ this.pan.endX = coords.X;
491
+ // this.manager.updateSpineStyle(false);
492
+
493
+ const currentSlide = this.manager.currentSlide;
494
+ const currentOffset = currentSlide * (this.manager.width / this.manager.perPage);
495
+ const dragOffset = (this.pan.endX - this.pan.startX);
496
+ const offset = this.manager.rtl ? currentOffset + dragOffset : currentOffset - dragOffset;
497
+
498
+ cancelAnimationFrame(this.moveFrame);
499
+ this.moveFrame = requestAnimationFrame(() => {
500
+ requestAnimationFrame(() => {
501
+ this.manager.spineElement.style.transform = `translate3d(${(this.manager.rtl ? 1 : -1) * offset}px, 0, 0)`;
502
+ })
503
+ });
504
+ }
505
+ }
506
+
507
+ private dtimer!: number;
508
+ // @ts-ignore
509
+ private pdblclick!: boolean;
510
+ private disableDblClick!: boolean;
511
+ dblclickHandler(_: MouseEvent) {
512
+ clearTimeout(this.dtimer);
513
+ this.pdblclick = true;
514
+ this.dtimer = window.setTimeout(() => this.pdblclick = false, 200);
515
+
516
+ if(this.disableDblClick) return;
517
+
518
+ if(this.isScaled) this.scale = 1;
519
+
520
+ // TODO smarter
521
+ /*const ev = this.coordinator.getBibiEvent(e);
522
+ this.scale = this.isScaled ? 1 : 2;
523
+ if (this.isScaled)
524
+ this.pan.translate = {
525
+ X: ev.Coord.X / 2,
526
+ Y: ev.Coord.Y / 2
527
+ };
528
+ this.manager.updateBookStyle();*/
529
+ }
530
+
531
+ public get isScaled() {
532
+ return this.scale > 1;
533
+ }
534
+
535
+ private addTouch(e: any) {
536
+ e.touches = [{
537
+ pageX: e.pageX,
538
+ pageY: e.pageY
539
+ }];
540
+ }
541
+
542
+ /**
543
+ * mousedown event handler
544
+ */
545
+ mousedownHandler(e: MouseEvent) {
546
+ if (this.isScaled) {
547
+ this.addTouch(e as any);
548
+ this.touchstartHandler(e as any);
549
+ }
550
+ }
551
+
552
+ /**
553
+ * mouseup event handler
554
+ */
555
+ mouseupHandler(e: MouseEvent) {
556
+ if (this.isScaled) {
557
+ this.touchendHandler(e as any);
558
+ }
559
+ }
560
+
561
+ /**
562
+ * mousemove event handler
563
+ */
564
+ mousemoveHandler(e: MouseEvent) {
565
+ if (this.isScaled && e.buttons > 0) {
566
+ e.preventDefault();
567
+ this.addTouch(e as any);
568
+ this.touchmoveHandler(e as any);
569
+ }
570
+ }
571
+
572
+ /**
573
+ * Recalculate drag/swipe event and reposition the frame of a slider
574
+ */
575
+ private updateAfterDrag() {
576
+ const movement = (this.manager.rtl ? -1 : 1) * (this.pan.endX - this.pan.startX);
577
+ const movementDistance = Math.abs(movement);
578
+
579
+ if (movement > 0 && movementDistance > this.manager.threshold && this.manager.slength > this.manager.perPage) {
580
+ this.manager.listener("no_less", undefined);
581
+ } else if (movement < 0 && movementDistance > this.manager.threshold && this.manager.slength > this.manager.perPage) {
582
+ this.manager.listener("no_more", undefined);
583
+ }
584
+ // this.ui.toggle(false);
585
+ this.manager.slideToCurrent(true, true); // slideToNegativeClone || slideToPositiveClone
586
+ }
587
+ }
@@ -0,0 +1,46 @@
1
+ export class FXLPeripheralsDebug {
2
+ private readonly _DOM = {
3
+ show: false,
4
+ pinchTarget: document.createElement("div"),
5
+ touch1: document.createElement("div"),
6
+ touch2: document.createElement("div"),
7
+ center: document.createElement("div"),
8
+ stats: document.createElement("div"),
9
+ };
10
+
11
+ get show() {
12
+ return this.DOM.show;
13
+ }
14
+
15
+ get DOM() {
16
+ return this._DOM;
17
+ }
18
+
19
+ constructor() {
20
+ this._DOM.show = true;
21
+ this._DOM.pinchTarget.style.zIndex =this._DOM.stats.style.zIndex = this._DOM.center.style.zIndex = this._DOM.touch1.style.zIndex = this._DOM.touch2.style.zIndex = "100000";
22
+ this._DOM.pinchTarget.style.position = this._DOM.stats.style.position = this._DOM.center.style.position = this._DOM.touch1.style.position = this._DOM.touch2.style.position = "absolute";
23
+ this._DOM.pinchTarget.style.borderRadius = this._DOM.center.style.borderRadius = this._DOM.touch1.style.borderRadius = this._DOM.touch2.style.borderRadius = "50%";
24
+ this._DOM.pinchTarget.style.pointerEvents = this._DOM.stats.style.pointerEvents = this._DOM.center.style.pointerEvents = this._DOM.touch1.style.pointerEvents = this._DOM.touch2.style.pointerEvents = "none";
25
+ this._DOM.pinchTarget.style.display = this._DOM.center.style.display = this._DOM.touch1.style.display = this._DOM.touch2.style.display = "none";
26
+ this._DOM.pinchTarget.style.paddingTop = this._DOM.center.style.paddingTop = "10px";
27
+ this._DOM.pinchTarget.style.width = this._DOM.pinchTarget.style.height = this._DOM.center.style.width = this._DOM.center.style.height = "10px";
28
+ this._DOM.pinchTarget.style.backgroundColor = "green";
29
+ this._DOM.center.style.backgroundColor = "red";
30
+ this._DOM.touch1.style.backgroundColor = this._DOM.touch2.style.backgroundColor = "blue";
31
+ this._DOM.touch1.style.height = this._DOM.touch2.style.height = "20px";
32
+ this._DOM.touch1.style.width = this._DOM.touch2.style.width = "20px";
33
+ this._DOM.touch1.style.paddingTop = this._DOM.touch2.style.paddingTop = "20px";
34
+ this._DOM.touch1.textContent = "1";
35
+ this._DOM.touch2.textContent = "2";
36
+ this._DOM.stats.style.padding = "20px";
37
+ this._DOM.stats.style.backgroundColor = "rgba(0,0,0,0.5)";
38
+ this._DOM.stats.style.color = "white";
39
+ this._DOM.stats.textContent = "[stats]";
40
+ document.body.appendChild(this._DOM.stats);
41
+ document.body.appendChild(this._DOM.center);
42
+ document.body.appendChild(this._DOM.touch1);
43
+ document.body.appendChild(this._DOM.touch2);
44
+ document.body.appendChild(this._DOM.pinchTarget);
45
+ }
46
+ }