constructor()

in src/viewer/TouchService.ts [58:289]


    constructor(canvasContainer: HTMLElement, domContainer: HTMLElement) {
        const subs = this._subscriptions;

        this._activeSubject$ = new BehaviorSubject<boolean>(false);

        this._active$ = this._activeSubject$.pipe(
            distinctUntilChanged(),
            publishReplay(1),
            refCount());

        subs.push(observableFromEvent<TouchEvent>(domContainer, "touchmove")
            .subscribe(
                (event: TouchEvent): void => {
                    event.preventDefault();
                }));

        this._touchStart$ = observableFromEvent<TouchEvent>(canvasContainer, "touchstart");
        this._touchMove$ = observableFromEvent<TouchEvent>(canvasContainer, "touchmove");
        this._touchEnd$ = observableFromEvent<TouchEvent>(canvasContainer, "touchend");
        this._touchCancel$ = observableFromEvent<TouchEvent>(canvasContainer, "touchcancel");

        const tapStart$: Observable<TouchEvent> = this._touchStart$.pipe(
            filter(
                (te: TouchEvent): boolean => {
                    return te.touches.length === 1 && te.targetTouches.length === 1;
                }),
            share());

        this._doubleTap$ = tapStart$.pipe(
            bufferWhen(
                (): Observable<number | TouchEvent> => {
                    return tapStart$.pipe(
                        first(),
                        switchMap(
                            (): Observable<number | TouchEvent> => {
                                return observableMerge(
                                    observableTimer(300),
                                    tapStart$).pipe(
                                        take(1));
                            }));
                }),
            filter(
                (events: TouchEvent[]): boolean => {
                    return events.length === 2;
                }),
            map(
                (events: TouchEvent[]): TouchEvent => {
                    return events[events.length - 1];
                }),
            share());

        subs.push(this._doubleTap$
            .subscribe(
                (event: TouchEvent): void => {
                    event.preventDefault();
                }));

        this._singleTouchMove$ = this._touchMove$.pipe(
            filter(
                (te: TouchEvent): boolean => {
                    return te.touches.length === 1 && te.targetTouches.length === 1;
                }),
            share());

        let singleTouchStart$: Observable<TouchEvent> = observableMerge(
            this._touchStart$,
            this._touchEnd$,
            this._touchCancel$).pipe(
                filter(
                    (te: TouchEvent): boolean => {
                        return te.touches.length === 1 && te.targetTouches.length === 1;
                    }));

        let multipleTouchStart$: Observable<TouchEvent> = observableMerge(
            this._touchStart$,
            this._touchEnd$,
            this._touchCancel$).pipe(
                filter(
                    (te: TouchEvent): boolean => {
                        return te.touches.length >= 1;
                    }));

        let touchStop$: Observable<TouchEvent> = observableMerge(
            this._touchEnd$,
            this._touchCancel$).pipe(
                filter(
                    (te: TouchEvent): boolean => {
                        return te.touches.length === 0;
                    }));

        this._singleTouchDragStart$ = singleTouchStart$.pipe(
            mergeMap(
                (): Observable<TouchEvent> => {
                    return this._singleTouchMove$.pipe(
                        takeUntil(
                            observableMerge(
                                touchStop$,
                                multipleTouchStart$)),
                        take(1));
                }));

        this._singleTouchDragEnd$ = singleTouchStart$.pipe(
            mergeMap(
                (): Observable<TouchEvent> => {
                    return observableMerge(
                        touchStop$,
                        multipleTouchStart$).pipe(
                            first());
                }));

        this._singleTouchDrag$ = singleTouchStart$.pipe(
            switchMap(
                (): Observable<TouchEvent> => {
                    return this._singleTouchMove$.pipe(
                        skip(1),
                        takeUntil(
                            observableMerge(
                                multipleTouchStart$,
                                touchStop$)));
                }));

        let touchesChanged$: Observable<TouchEvent> = observableMerge(
            this._touchStart$,
            this._touchEnd$,
            this._touchCancel$);

        this._pinchStart$ = touchesChanged$.pipe(
            filter(
                (te: TouchEvent): boolean => {
                    return te.touches.length === 2 && te.targetTouches.length === 2;
                }));

        this._pinchEnd$ = touchesChanged$.pipe(
            filter(
                (te: TouchEvent): boolean => {
                    return te.touches.length !== 2 || te.targetTouches.length !== 2;
                }));

        this._pinchOperation$ = new Subject<PinchOperation>();

        this._pinch$ = this._pinchOperation$.pipe(
            scan(
                (pinch: TouchPinch, operation: PinchOperation): TouchPinch => {
                    return operation(pinch);
                },
                {
                    changeX: 0,
                    changeY: 0,
                    clientX: 0,
                    clientY: 0,
                    distance: 0,
                    distanceChange: 0,
                    distanceX: 0,
                    distanceY: 0,
                    originalEvent: null,
                    pageX: 0,
                    pageY: 0,
                    screenX: 0,
                    screenY: 0,
                    touch1: null,
                    touch2: null,
                }));

        const pinchSubscription = this._touchMove$.pipe(
            filter(
                (te: TouchEvent): boolean => {
                    return te.touches.length === 2 && te.targetTouches.length === 2;
                }),
            map(
                (te: TouchEvent): PinchOperation => {
                    return (previous: TouchPinch): TouchPinch => {
                        let touch1: Touch = te.touches[0];
                        let touch2: Touch = te.touches[1];

                        let minX: number = Math.min(touch1.clientX, touch2.clientX);
                        let maxX: number = Math.max(touch1.clientX, touch2.clientX);

                        let minY: number = Math.min(touch1.clientY, touch2.clientY);
                        let maxY: number = Math.max(touch1.clientY, touch2.clientY);

                        let centerClientX: number = minX + (maxX - minX) / 2;
                        let centerClientY: number = minY + (maxY - minY) / 2;

                        let centerPageX: number = centerClientX + touch1.pageX - touch1.clientX;
                        let centerPageY: number = centerClientY + touch1.pageY - touch1.clientY;

                        let centerScreenX: number = centerClientX + touch1.screenX - touch1.clientX;
                        let centerScreenY: number = centerClientY + touch1.screenY - touch1.clientY;

                        let distanceX: number = Math.abs(touch1.clientX - touch2.clientX);
                        let distanceY: number = Math.abs(touch1.clientY - touch2.clientY);

                        let distance: number = Math.sqrt(distanceX * distanceX + distanceY * distanceY);

                        let distanceChange: number = distance - previous.distance;

                        let changeX: number = distanceX - previous.distanceX;
                        let changeY: number = distanceY - previous.distanceY;

                        let current: TouchPinch = {
                            changeX: changeX,
                            changeY: changeY,
                            clientX: centerClientX,
                            clientY: centerClientY,
                            distance: distance,
                            distanceChange: distanceChange,
                            distanceX: distanceX,
                            distanceY: distanceY,
                            originalEvent: te,
                            pageX: centerPageX,
                            pageY: centerPageY,
                            screenX: centerScreenX,
                            screenY: centerScreenY,
                            touch1: touch1,
                            touch2: touch2,
                        };

                        return current;
                    };
                }))
            .subscribe(this._pinchOperation$);

        subs.push(pinchSubscription);

        this._pinchChange$ = this._pinchStart$.pipe(
            switchMap(
                (): Observable<TouchPinch> => {
                    return this._pinch$.pipe(
                        skip(1),
                        takeUntil(this._pinchEnd$));
                }));
    }