aboutsummaryrefslogtreecommitdiff
path: root/src/client/util/InteractionUtils.ts
blob: d5799c21f70b8add6038d3f33f4bd5ccc0600bdd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
export namespace InteractionUtils {
    export const MOUSETYPE = "mouse";
    export const TOUCHTYPE = "touch";
    export const PENTYPE = "pen";
    export const ERASERTYPE = "eraser";

    const POINTER_PEN_BUTTON = -1;
    const REACT_POINTER_PEN_BUTTON = 0;
    const ERASER_BUTTON = 5;

    export function IsType(e: PointerEvent | React.PointerEvent, type: string): boolean {
        switch (type) {
            // pen and eraser are both pointer type 'pen', but pen is button 0 and eraser is button 5. -syip2
            case PENTYPE:
                return e.pointerType === PENTYPE && e.button === (e instanceof PointerEvent ? POINTER_PEN_BUTTON : REACT_POINTER_PEN_BUTTON);
            case ERASERTYPE:
                return e.pointerType === PENTYPE && e.button === (e instanceof PointerEvent ? ERASER_BUTTON : ERASER_BUTTON);
            default:
                return e.pointerType === type;
        }
    }

    export function TwoPointEuclidist(pt1: React.Touch, pt2: React.Touch): number {
        return Math.sqrt(Math.pow(pt1.clientX - pt2.clientX, 2) + Math.pow(pt1.clientY - pt2.clientY, 2));
    }

    /**
     * Returns the centroid of an n-arbitrary long list of points (takes the average the x and y components of each point)
     * @param pts - n-arbitrary long list of points
     */
    export function CenterPoint(pts: React.Touch[]): { X: number, Y: number } {
        let centerX = pts.map(pt => pt.clientX).reduce((a, b) => a + b, 0) / pts.length;
        let centerY = pts.map(pt => pt.clientY).reduce((a, b) => a + b, 0) / pts.length;
        return { X: centerX, Y: centerY };
    }

    /**
     * Returns -1 if pinching out, 0 if not pinching, and 1 if pinching in
     * @param pt1 - new point that corresponds to oldPoint1
     * @param pt2 - new point that corresponds to oldPoint2
     * @param oldPoint1 - previous point 1
     * @param oldPoint2 - previous point 2
     */
    export function Pinching(pt1: React.Touch, pt2: React.Touch, oldPoint1: React.Touch, oldPoint2: React.Touch): number {
        let threshold = 4;
        let oldDist = TwoPointEuclidist(oldPoint1, oldPoint2);
        let newDist = TwoPointEuclidist(pt1, pt2);

        /** if they have the same sign, then we are either pinching in or out.
          * threshold it by 10 (it has to be pinching by at least threshold to be a valid pinch)
          * so that it can still pan without freaking out
          */
        if (Math.sign(oldDist) === Math.sign(newDist) && Math.abs(oldDist - newDist) > threshold) {
            return Math.sign(oldDist - newDist);
        }
        return 0;
    }

    // These might not be very useful anymore, but I'll leave them here for now -syip2
    {


        /**
         * Returns the type of Touch Interaction from a list of points.
         * Also returns any data that is associated with a Touch Interaction
         * @param pts - List of points
         */
        // export function InterpretPointers(pts: React.Touch[]): { type: Opt<TouchInteraction>, data?: any } {
        //     const leniency = 200;
        //     switch (pts.length) {
        //         case 1:
        //             return { type: OneFinger };
        //         case 2:
        //             return { type: TwoSeperateFingers };
        //         case 3:
        //             let pt1 = pts[0];
        //             let pt2 = pts[1];
        //             let pt3 = pts[2];
        //             if (pt1 && pt2 && pt3) {
        //                 let dist12 = TwoPointEuclidist(pt1, pt2);
        //                 let dist23 = TwoPointEuclidist(pt2, pt3);
        //                 let dist13 = TwoPointEuclidist(pt1, pt3);
        //                 console.log(`distances: ${dist12}, ${dist23}, ${dist13}`);
        //                 let dist12close = dist12 < leniency;
        //                 let dist23close = dist23 < leniency;
        //                 let dist13close = dist13 < leniency;
        //                 let xor2313 = dist23close ? !dist13close : dist13close;
        //                 let xor = dist12close ? !xor2313 : xor2313;
        //                 // three input xor because javascript doesn't have logical xor's
        //                 if (xor) {
        //                     let points: number[] = [];
        //                     let min = Math.min(dist12, dist23, dist13);
        //                     switch (min) {
        //                         case dist12:
        //                             points = [0, 1, 2];
        //                             break;
        //                         case dist23:
        //                             points = [1, 2, 0];
        //                             break;
        //                         case dist13:
        //                             points = [0, 2, 1];
        //                             break;
        //                     }
        //                     return { type: TwoToOneFingers, data: points };
        //                 }
        //                 else {
        //                     return { type: ThreeSeperateFingers, data: null };
        //                 }
        //             }
        //         default:
        //             return { type: undefined };
        //     }
        // }

        // export function IsDragging(oldTouches: Map<number, React.Touch>, newTouches: TouchList, leniency: number): boolean {
        //     for (let i = 0; i < newTouches.length; i++) {
        //         let touch = newTouches.item(i);
        //         if (touch) {
        //             let oldTouch = oldTouches.get(touch.identifier);
        //             if (oldTouch) {
        //                 if (TwoPointEuclidist(touch, oldTouch) >= leniency) {
        //                     return true;
        //                 }
        //             }
        //         }
        //     }
        //     return false;
        // }
    }
}