/** 
 | 
 * 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. 
 | 
}; 
 |