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 |
+ }; |
+ } |
+}; |