| 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..a64729e58adbc116946f24b7f8069848b459217c
|
| --- /dev/null
|
| +++ b/chrome/browser/resources/pdf/gesture_detector.js
|
| @@ -0,0 +1,160 @@
|
| +// 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_ = new Map([
|
| + ['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_.has(type)) {
|
| + this.listeners_.get(type).push(listener);
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * Call the relevant listeners with the given |pinchEvent|.
|
| + * @private
|
| + * @param {!Object} pinchEvent The event to notify the listeners of.
|
| + */
|
| + notify_(pinchEvent) {
|
| + let listeners = this.listeners_.get(pinchEvent.type);
|
| +
|
| + for (let l of listeners)
|
| + l(pinchEvent);
|
| + }
|
| +
|
| + /**
|
| + * The callback for touchstart events on the element.
|
| + * @private
|
| + * @param {!TouchEvent} event Touch event on the element.
|
| + */
|
| + onTouchStart_(event) {
|
| + // 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 (event.touches.length == 2) {
|
| + event.preventDefault();
|
| + this.pinchStartEvent_ = event;
|
| + this.lastEvent_ = event;
|
| + this.notify_({
|
| + type: 'pinchstart',
|
| + center: GestureDetector.center_(event)
|
| + });
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * The callback for touch move, end, and cancel events on the element.
|
| + * @private
|
| + * @param {!TouchEvent} event Touch event on the element.
|
| + */
|
| + onTouch_(event) {
|
| + if (!this.pinchStartEvent_)
|
| + return;
|
| +
|
| + // Check if the pinch ends with the current event.
|
| + if (event.touches.length < 2 ||
|
| + this.lastEvent_.touches.length !== event.touches.length) {
|
| + let startScaleRatio = GestureDetector.pinchScaleRatio_(
|
| + this.lastEvent_, this.pinchStartEvent_);
|
| + let center = GestureDetector.center_(this.lastEvent_);
|
| + let endEvent = {
|
| + type: 'pinchend',
|
| + startScaleRatio: startScaleRatio,
|
| + center: center
|
| + };
|
| + this.pinchStartEvent_ = null;
|
| + this.lastEvent_ = null;
|
| + this.notify_(endEvent);
|
| + return;
|
| + }
|
| +
|
| + let scaleRatio = GestureDetector.pinchScaleRatio_(event, this.lastEvent_);
|
| + let startScaleRatio = GestureDetector.pinchScaleRatio_(
|
| + event, this.pinchStartEvent_);
|
| + let center = GestureDetector.center_(event);
|
| + this.notify_({
|
| + type: 'pinchupdate',
|
| + scaleRatio: scaleRatio,
|
| + direction: scaleRatio > 1.0 ? 'in' : 'out',
|
| + startScaleRatio: startScaleRatio,
|
| + center: center
|
| + });
|
| +
|
| + this.lastEvent_ = event;
|
| + }
|
| +
|
| + /**
|
| + * Computes the change in scale between this touch event
|
| + * and a previous one.
|
| + * @private
|
| + * @param {!TouchEvent} event Latest touch event on the element.
|
| + * @param {!TouchEvent} prevEvent A previous touch event on the element.
|
| + * @return {?number} The ratio of the scale of this event and the
|
| + * scale of the previous one.
|
| + */
|
| + static pinchScaleRatio_(event, prevEvent) {
|
| + let distance1 = GestureDetector.distance_(prevEvent);
|
| + let distance2 = GestureDetector.distance_(event);
|
| + return distance1 === 0 ? null : distance2 / distance1;
|
| + }
|
| +
|
| + /**
|
| + * Computes the distance between fingers.
|
| + * @private
|
| + * @param {!TouchEvent} event Touch event with at least 2 touch points.
|
| + * @return {number} Distance between touch[0] and touch[1].
|
| + */
|
| + static distance_(event) {
|
| + let touch1 = event.touches[0];
|
| + let touch2 = event.touches[1];
|
| + let dx = touch1.clientX - touch2.clientX;
|
| + let dy = touch1.clientY - touch2.clientY;
|
| + return Math.sqrt(dx * dx + dy * dy);
|
| + }
|
| +
|
| + /**
|
| + * Computes the midpoint between fingers.
|
| + * @private
|
| + * @param {!TouchEvent} event Touch event with at least 2 touch points.
|
| + * @return {!Object} Midpoint between touch[0] and touch[1].
|
| + */
|
| + static center_(event) {
|
| + let touch1 = event.touches[0];
|
| + let touch2 = event.touches[1];
|
| + return {
|
| + x: (touch1.clientX + touch2.clientX) / 2,
|
| + y: (touch1.clientY + touch2.clientY) / 2
|
| + };
|
| + }
|
| +};
|
|
|