Chromium Code Reviews| 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 |
| + }; |
| + } |
| +}; |