Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1563)

Unified Diff: chrome/browser/resources/pdf/gesture_detector.js

Issue 2400743002: Improved Pinch-Zoom for PDF. (Closed)
Patch Set: Use our own touch gesture detection. Created 4 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/browser/resources/pdf/gesture_detector.js
diff --git a/chrome/browser/resources/pdf/gesture_detector.js b/chrome/browser/resources/pdf/gesture_detector.js
new file mode 100644
index 0000000000000000000000000000000000000000..0e8e535ed350341f2b58816739e079f0baa27b3e
--- /dev/null
+++ b/chrome/browser/resources/pdf/gesture_detector.js
@@ -0,0 +1,161 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+'use strict';
+
+/**
+ * A class that listens for touch events and produces events when these
+ * touches form gestures (e.g. pinching).
+ */
+class GestureDetector {
+ /**
+ * Constructs a GestureDetector.
+ * @param {!Element} element The element to monitor for touch gestures.
+ */
+ constructor(element) {
+ this.element_ = element;
+
+ this.element_.addEventListener('touchstart', this.onTouchStart_.bind(this));
+ this.element_.addEventListener('touchmove', this.onTouch_.bind(this));
+ this.element_.addEventListener('touchend', this.onTouch_.bind(this));
+ this.element_.addEventListener('touchcancel', this.onTouch_.bind(this));
+
+ this.pinchStartEvent_ = null;
+ this.lastEvent_ = null;
+
+ this.listeners_ = {
+ 'pinchstart': [],
+ 'pinchupdate': [],
+ 'pinchend': []
+ };
+ }
+
+ /**
+ * Add a |listener| to be notified of |type| events.
+ * @param {string} type The event type to be notified for.
+ * @param {Function} listener The callback.
+ */
+ addEventListener(type, listener) {
+ if (this.listeners_[type]) {
dpapad 2016/10/31 23:02:23 Since you are already using ES6 in this file ("cla
Kevin McNee - google account 2016/11/07 23:08:27 Done.
+ this.listeners_[type].push(listener);
+ }
+ }
+
+ /**
+ * Call the relevant listeners with the given |pinchEvent|.
+ * @private
+ * @param {Object} pinchEvent The event to notify the listeners of.
+ */
+ notify_(pinchEvent) {
+ var listeners = this.listeners_[pinchEvent.type];
dpapad 2016/10/31 23:02:23 Nit(optional): s/var/let throughout this file?
Kevin McNee - google account 2016/11/07 23:08:27 Done.
+ var numListeners = listeners.length;
+ for (var i = 0; i < numListeners; i++) {
dpapad 2016/10/31 23:02:23 Nit for (let l of listeners) l(pinchEvent);
Kevin McNee - google account 2016/11/07 23:08:27 Done.
+ listeners[i](pinchEvent);
+ }
+ }
+
+ /**
+ * The callback for touchstart events on the element.
+ * @private
+ * @param {!TouchEvent} ev Touch event on the element.
+ */
+ onTouchStart_(ev) {
dpapad 2016/10/31 23:02:23 Let's be consistent within this file, s/ev/event (
Kevin McNee - google account 2016/11/07 23:08:27 Done.
+ // We must preventDefault if there is a two finger touch. By doing so
+ // native pinch-zoom does not interfere with our way of handling the event.
+ if (ev.touches.length == 2) {
+ ev.preventDefault();
+ this.pinchStartEvent_ = ev;
+ this.lastEvent_ = ev;
+ this.notify_({
+ type: 'pinchstart',
+ center: GestureDetector.center_(ev)
+ });
+ }
+ }
+
+ /**
+ * The callback for touch move, end, and cancel events on the element.
+ * @private
+ * @param {!TouchEvent} ev Touch event on the element.
+ */
+ onTouch_(ev) {
+ if (!this.pinchStartEvent_)
+ return;
+
+ // Check if the pinch ends with the current event.
+ if (ev.touches.length < 2 ||
+ this.lastEvent_.touches.length !== ev.touches.length) {
+ var startScaleRatio = GestureDetector.pinchScaleRatio_(
+ this.lastEvent_, this.pinchStartEvent_);
+ var center = GestureDetector.center_(this.lastEvent_);
+ var endEvent = {
+ type: 'pinchend',
+ startScaleRatio: startScaleRatio,
+ center: center
+ };
+ this.pinchStartEvent_ = null;
+ this.lastEvent_ = null;
+ this.notify_(endEvent);
+ return;
+ }
+
+ var scaleRatio = GestureDetector.pinchScaleRatio_(ev, this.lastEvent_);
+ var startScaleRatio = GestureDetector.pinchScaleRatio_(
+ ev, this.pinchStartEvent_);
+ var center = GestureDetector.center_(ev);
+ this.notify_({
+ type: 'pinchupdate',
+ scaleRatio: scaleRatio,
+ direction: scaleRatio > 1.0 ? 'in' : 'out',
+ startScaleRatio: startScaleRatio,
+ center: center
+ });
+
+ this.lastEvent_ = ev;
+ }
+
+ /**
+ * Computes the change in scale between this touch event
+ * and a previous one.
+ * @private
+ * @param {!TouchEvent} ev Latest touch event on the element.
+ * @param {!TouchEvent} prevEv A previous touch event on the element.
+ */
+ static pinchScaleRatio_(ev, prevEv) {
+ var distance1 = GestureDetector.distance_(prevEv);
+ var distance2 = GestureDetector.distance_(ev);
+ if (distance1 === 0)
dpapad 2016/10/31 23:02:23 return distance1 === 0 ? null : distance2 / distan
Kevin McNee - google account 2016/11/07 23:08:27 Done.
+ return null;
+ return distance2 / distance1;
+ }
+
+ /**
+ * Computes the distance between fingers.
+ * @private
+ * @param {!TouchEvent} ev Touch event with at least 2 touch points.
+ * @return {number} Distance between touch[0] and touch[1].
+ */
+ static distance_(ev) {
+ var touch1 = ev.touches[0];
+ var touch2 = ev.touches[1];
+ var dx = touch1.clientX - touch2.clientX;
+ var dy = touch1.clientY - touch2.clientY;
+ return Math.sqrt(dx * dx + dy * dy);
+ }
+
+ /**
+ * Computes the midpoint between fingers.
+ * @private
+ * @param {!TouchEvent} ev Touch event with at least 2 touch points.
+ * @return {Object} Midpoint between touch[0] and touch[1].
+ */
+ static center_(ev) {
+ var touch1 = ev.touches[0];
+ var touch2 = ev.touches[1];
+ return {
+ x: (touch1.clientX + touch2.clientX) / 2,
+ y: (touch1.clientY + touch2.clientY) / 2
+ };
+ }
+};

Powered by Google App Engine
This is Rietveld 408576698