Skip to content

Commit b4be1e9

Browse files
authored
Merge pull request mozilla#7653 from staktrace/touch_swipe_presentation_mode
Add support for touch-swiping between pages in presentation mode (bug…
2 parents a9a3396 + ba9e8cb commit b4be1e9

File tree

1 file changed

+106
-15
lines changed

1 file changed

+106
-15
lines changed

web/pdf_presentation_mode.js

Lines changed: 106 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ var PDFPresentationMode = (function PDFPresentationModeClosure() {
6262
this.contextMenuOpen = false;
6363
this.mouseScrollTimeStamp = 0;
6464
this.mouseScrollDelta = 0;
65+
this.touchSwipeState = null;
6566

6667
if (contextMenuItems) {
6768
contextMenuItems.contextFirstPage.addEventListener('click',
@@ -135,10 +136,6 @@ var PDFPresentationMode = (function PDFPresentationModeClosure() {
135136

136137
var MOUSE_SCROLL_COOLDOWN_TIME = 50;
137138
var PAGE_SWITCH_THRESHOLD = 0.1;
138-
var PageSwitchDirection = {
139-
UP: -1,
140-
DOWN: 1
141-
};
142139

143140
var currentTime = (new Date()).getTime();
144141
var storedTime = this.mouseScrollTimeStamp;
@@ -156,19 +153,13 @@ var PDFPresentationMode = (function PDFPresentationModeClosure() {
156153
this.mouseScrollDelta += delta;
157154

158155
if (Math.abs(this.mouseScrollDelta) >= PAGE_SWITCH_THRESHOLD) {
159-
var pageSwitchDirection = (this.mouseScrollDelta > 0) ?
160-
PageSwitchDirection.UP : PageSwitchDirection.DOWN;
161-
var page = this.pdfViewer.currentPageNumber;
156+
var totalDelta = this.mouseScrollDelta;
162157
this._resetMouseScrollState();
163-
164-
// If we're at the first/last page, we don't need to do anything.
165-
if ((page === 1 && pageSwitchDirection === PageSwitchDirection.UP) ||
166-
(page === this.pdfViewer.pagesCount &&
167-
pageSwitchDirection === PageSwitchDirection.DOWN)) {
168-
return;
158+
var success = totalDelta > 0 ? this._goToPreviousPage()
159+
: this._goToNextPage();
160+
if (success) {
161+
this.mouseScrollTimeStamp = currentTime;
169162
}
170-
this.pdfViewer.currentPageNumber = (page + pageSwitchDirection);
171-
this.mouseScrollTimeStamp = currentTime;
172163
}
173164
},
174165

@@ -179,6 +170,32 @@ var PDFPresentationMode = (function PDFPresentationModeClosure() {
179170
document.msFullscreenElement);
180171
},
181172

173+
/**
174+
* @private
175+
*/
176+
_goToPreviousPage: function PDFPresentationMode_goToPreviousPage() {
177+
var page = this.pdfViewer.currentPageNumber;
178+
// If we're at the first page, we don't need to do anything.
179+
if (page <= 1) {
180+
return false;
181+
}
182+
this.pdfViewer.currentPageNumber = (page - 1);
183+
return true;
184+
},
185+
186+
/**
187+
* @private
188+
*/
189+
_goToNextPage: function PDFPresentationMode_goToNextPage() {
190+
var page = this.pdfViewer.currentPageNumber;
191+
// If we're at the last page, we don't need to do anything.
192+
if (page >= this.pdfViewer.pagesCount) {
193+
return false;
194+
}
195+
this.pdfViewer.currentPageNumber = (page + 1);
196+
return true;
197+
},
198+
182199
/**
183200
* @private
184201
*/
@@ -339,6 +356,72 @@ var PDFPresentationMode = (function PDFPresentationModeClosure() {
339356
this.mouseScrollDelta = 0;
340357
},
341358

359+
/**
360+
* @private
361+
*/
362+
_touchSwipe: function PDFPresentationMode_touchSwipe(evt) {
363+
if (!this.active) {
364+
return;
365+
}
366+
367+
// Must move at least these many CSS pixels for it to count as a swipe
368+
var SWIPE_MIN_DISTANCE_THRESHOLD = 50;
369+
// The swipe angle is allowed to deviate from the x or y axis by this much
370+
// before it is not considered a swipe in that direction any more.
371+
var SWIPE_ANGLE_THRESHOLD = Math.PI / 6;
372+
373+
if (evt.touches.length > 1) {
374+
// Multiple touch points detected, cancel the swipe.
375+
this.touchSwipeState = null;
376+
return;
377+
}
378+
switch (evt.type) {
379+
case 'touchstart':
380+
this.touchSwipeState = {
381+
startX: evt.touches[0].pageX,
382+
startY: evt.touches[0].pageY,
383+
endX: evt.touches[0].pageX,
384+
endY: evt.touches[0].pageY
385+
};
386+
break;
387+
case 'touchmove':
388+
if (this.touchSwipeState === null) {
389+
return;
390+
}
391+
this.touchSwipeState.endX = evt.touches[0].pageX;
392+
this.touchSwipeState.endY = evt.touches[0].pageY;
393+
// Do a preventDefault to avoid the swipe from triggering browser
394+
// gestures (Chrome in particular has some sort of swipe gesture in
395+
// fullscreen mode).
396+
evt.preventDefault();
397+
break;
398+
case 'touchend':
399+
if (this.touchSwipeState === null) {
400+
return;
401+
}
402+
var delta = 0;
403+
var dx = this.touchSwipeState.endX - this.touchSwipeState.startX;
404+
var dy = this.touchSwipeState.endY - this.touchSwipeState.startY;
405+
var absAngle = Math.abs(Math.atan2(dy, dx));
406+
if (Math.abs(dx) > SWIPE_MIN_DISTANCE_THRESHOLD &&
407+
(absAngle <= SWIPE_ANGLE_THRESHOLD ||
408+
absAngle >= (Math.PI - SWIPE_ANGLE_THRESHOLD))) {
409+
// horizontal swipe
410+
delta = dx;
411+
} else if (Math.abs(dy) > SWIPE_MIN_DISTANCE_THRESHOLD &&
412+
Math.abs(absAngle - (Math.PI / 2)) <= SWIPE_ANGLE_THRESHOLD) {
413+
// vertical swipe
414+
delta = dy;
415+
}
416+
if (delta > 0) {
417+
this._goToPreviousPage();
418+
} else if (delta < 0) {
419+
this._goToNextPage();
420+
}
421+
break;
422+
}
423+
},
424+
342425
/**
343426
* @private
344427
*/
@@ -348,12 +431,16 @@ var PDFPresentationMode = (function PDFPresentationModeClosure() {
348431
this.mouseWheelBind = this._mouseWheel.bind(this);
349432
this.resetMouseScrollStateBind = this._resetMouseScrollState.bind(this);
350433
this.contextMenuBind = this._contextMenu.bind(this);
434+
this.touchSwipeBind = this._touchSwipe.bind(this);
351435

352436
window.addEventListener('mousemove', this.showControlsBind);
353437
window.addEventListener('mousedown', this.mouseDownBind);
354438
window.addEventListener('wheel', this.mouseWheelBind);
355439
window.addEventListener('keydown', this.resetMouseScrollStateBind);
356440
window.addEventListener('contextmenu', this.contextMenuBind);
441+
window.addEventListener('touchstart', this.touchSwipeBind);
442+
window.addEventListener('touchmove', this.touchSwipeBind);
443+
window.addEventListener('touchend', this.touchSwipeBind);
357444
},
358445

359446
/**
@@ -366,12 +453,16 @@ var PDFPresentationMode = (function PDFPresentationModeClosure() {
366453
window.removeEventListener('wheel', this.mouseWheelBind);
367454
window.removeEventListener('keydown', this.resetMouseScrollStateBind);
368455
window.removeEventListener('contextmenu', this.contextMenuBind);
456+
window.removeEventListener('touchstart', this.touchSwipeBind);
457+
window.removeEventListener('touchmove', this.touchSwipeBind);
458+
window.removeEventListener('touchend', this.touchSwipeBind);
369459

370460
delete this.showControlsBind;
371461
delete this.mouseDownBind;
372462
delete this.mouseWheelBind;
373463
delete this.resetMouseScrollStateBind;
374464
delete this.contextMenuBind;
465+
delete this.touchSwipeBind;
375466
},
376467

377468
/**

0 commit comments

Comments
 (0)