/**
|
* Only implements needed gestures for mobile.
|
*/
|
|
import * as eventUtil from './event';
|
import { ZRRawTouchEvent, ZRPinchEvent, Dictionary } from './types';
|
import Displayable from '../graphic/Displayable';
|
|
interface TrackItem {
|
points: number[][]
|
touches: Touch[]
|
target: Displayable,
|
event: ZRRawTouchEvent
|
}
|
|
export class GestureMgr {
|
|
private _track: TrackItem[] = []
|
|
constructor() {}
|
|
recognize(event: ZRRawTouchEvent, target: Displayable, root: HTMLElement) {
|
this._doTrack(event, target, root);
|
return this._recognize(event);
|
}
|
|
clear() {
|
this._track.length = 0;
|
return this;
|
}
|
|
_doTrack(event: ZRRawTouchEvent, target: Displayable, root: HTMLElement) {
|
const touches = event.touches;
|
|
if (!touches) {
|
return;
|
}
|
|
const trackItem: TrackItem = {
|
points: [],
|
touches: [],
|
target: target,
|
event: event
|
};
|
|
for (let i = 0, len = touches.length; i < len; i++) {
|
const touch = touches[i];
|
const pos = eventUtil.clientToLocal(root, touch, {});
|
trackItem.points.push([pos.zrX, pos.zrY]);
|
trackItem.touches.push(touch);
|
}
|
|
this._track.push(trackItem);
|
}
|
|
_recognize(event: ZRRawTouchEvent) {
|
for (let eventName in recognizers) {
|
if (recognizers.hasOwnProperty(eventName)) {
|
const gestureInfo = recognizers[eventName](this._track, event);
|
if (gestureInfo) {
|
return gestureInfo;
|
}
|
}
|
}
|
}
|
}
|
|
function dist(pointPair: number[][]): number {
|
const dx = pointPair[1][0] - pointPair[0][0];
|
const dy = pointPair[1][1] - pointPair[0][1];
|
|
return Math.sqrt(dx * dx + dy * dy);
|
}
|
|
function center(pointPair: number[][]): number[] {
|
return [
|
(pointPair[0][0] + pointPair[1][0]) / 2,
|
(pointPair[0][1] + pointPair[1][1]) / 2
|
];
|
}
|
|
type Recognizer = (tracks: TrackItem[], event: ZRRawTouchEvent) => {
|
type: string
|
target: Displayable
|
event: ZRRawTouchEvent
|
}
|
|
const recognizers: Dictionary<Recognizer> = {
|
|
pinch: function (tracks: TrackItem[], event: ZRRawTouchEvent) {
|
const trackLen = tracks.length;
|
|
if (!trackLen) {
|
return;
|
}
|
|
const pinchEnd = (tracks[trackLen - 1] || {}).points;
|
const pinchPre = (tracks[trackLen - 2] || {}).points || pinchEnd;
|
|
if (pinchPre
|
&& pinchPre.length > 1
|
&& pinchEnd
|
&& pinchEnd.length > 1
|
) {
|
let pinchScale = dist(pinchEnd) / dist(pinchPre);
|
!isFinite(pinchScale) && (pinchScale = 1);
|
|
(event as ZRPinchEvent).pinchScale = pinchScale;
|
|
const pinchCenter = center(pinchEnd);
|
(event as ZRPinchEvent).pinchX = pinchCenter[0];
|
(event as ZRPinchEvent).pinchY = pinchCenter[1];
|
|
return {
|
type: 'pinch',
|
target: tracks[0].target,
|
event: event
|
};
|
}
|
}
|
|
// Only pinch currently.
|
};
|