From de0c00ff0bb1f58a0736da24acc984f5a090d009 Mon Sep 17 00:00:00 2001
From: Stanley Yip <stanley_yip@brown.edu>
Date: Tue, 14 Jan 2020 18:35:28 -0500
Subject: ok we now use custom events for touch. im struggling with figuring
 out how to ignore a hand lol

---
 src/client/views/Touchable.tsx | 114 ++++++++++++++++++++++++++++-------------
 1 file changed, 78 insertions(+), 36 deletions(-)

(limited to 'src/client/views/Touchable.tsx')

diff --git a/src/client/views/Touchable.tsx b/src/client/views/Touchable.tsx
index 2a7599fbf..a71015b05 100644
--- a/src/client/views/Touchable.tsx
+++ b/src/client/views/Touchable.tsx
@@ -8,8 +8,11 @@ const HOLD_DURATION = 1000;
 
 export abstract class Touchable<T = {}> extends React.Component<T> {
     //private holdTimer: NodeJS.Timeout | undefined;
-    holdTimer: NodeJS.Timeout | undefined;
+    private holdTimer: NodeJS.Timeout | undefined;
+    private moveDisposer?: InteractionUtils.MultiTouchEventDisposer;
+    private endDisposer?: InteractionUtils.MultiTouchEventDisposer;
 
+    protected abstract multiTouchDisposer?: InteractionUtils.MultiTouchEventDisposer;
     protected _touchDrag: boolean = false;
     protected prevPoints: Map<number, React.Touch> = new Map<number, React.Touch>();
 
@@ -22,16 +25,27 @@ export abstract class Touchable<T = {}> extends React.Component<T> {
      * When a touch even starts, we keep track of each touch that is associated with that event
      */
     @action
-    protected onTouchStart = (e: React.TouchEvent): void => {
+    protected onTouchStart = (e: Event, me: InteractionUtils.MultiTouchEvent<React.TouchEvent>): void => {
         const actualPts: React.Touch[] = [];
-        for (let i = 0; i < e.targetTouches.length; i++) {
-            const pt: any = e.targetTouches.item(i);
+        const te = me.touchEvent;
+        // loop through all touches on screen
+        for (let i = 0; i < te.touches.length; i++) {
+            const pt: any = te.touches.item(i);
             actualPts.push(pt);
-            // pen is also a touch, but with a radius of 0.5 (at least with the surface pens)
-            // and this seems to be the only way of differentiating pen and touch on touch events
-            if (pt.radiusX > 1 && pt.radiusY > 1) {
+            if (this.prevPoints.has(pt.identifier)) {
                 this.prevPoints.set(pt.identifier, pt);
             }
+            // only add the ones that are targeted on "this" element, but with the identifier that the screen touch gives
+            for (let j = 0; j < te.changedTouches.length; j++) {
+                const tPt = te.changedTouches.item(j);
+                if (pt.clientX === tPt.clientX && pt.clientY === tPt.clientY) {
+                    // pen is also a touch, but with a radius of 0.5 (at least with the surface pens)
+                    // and this seems to be the only way of differentiating pen and touch on touch events
+                    if (pt.radiusX > 1 && pt.radiusY > 1) {
+                        this.prevPoints.set(pt.identifier, pt);
+                    }
+                }
+            }
         }
 
         const ptsToDelete: number[] = [];
@@ -41,26 +55,30 @@ export abstract class Touchable<T = {}> extends React.Component<T> {
             }
         });
 
+        // console.log(ptsToDelete.length);
         ptsToDelete.forEach(pt => this.prevPoints.delete(pt));
 
+        // console.log(this.prevPoints.size);
         if (this.prevPoints.size) {
             switch (this.prevPoints.size) {
                 case 1:
-                    this.handle1PointerDown(e);
-                    e.persist();
+                    this.handle1PointerDown(te);
+                    te.persist();
                     // if (this.holdTimer) {
                     //     clearTimeout(this.holdTimer)
                     //     this.holdTimer = undefined;
                     // }
-                    this.holdTimer = setTimeout(() => this.handle1PointerHoldStart(e), HOLD_DURATION);
+                    this.holdTimer = setTimeout(() => this.handle1PointerHoldStart(te), HOLD_DURATION);
+                    // e.stopPropagation();
                     // console.log(this.holdTimer);
                     break;
                 case 2:
-                    this.handle2PointersDown(e);
-                    break;
-                case 5:
-                    this.handleHandDown(e);
+                    this.handle2PointersDown(te);
+                    // e.stopPropagation();
                     break;
+                // case 5:
+                //     this.handleHandDown(te);
+                //     break;
             }
         }
     }
@@ -69,28 +87,30 @@ export abstract class Touchable<T = {}> extends React.Component<T> {
     * Handle touch move event
     */
     @action
-    protected onTouch = (e: TouchEvent): void => {
-        const myTouches = InteractionUtils.GetMyTargetTouches(e, this.prevPoints, true);
+    protected onTouch = (e: Event, me: InteractionUtils.MultiTouchEvent<TouchEvent>): void => {
+        const te = me.touchEvent;
+        const myTouches = InteractionUtils.GetMyTargetTouches(te, this.prevPoints, true);
 
         // if we're not actually moving a lot, don't consider it as dragging yet
         if (!InteractionUtils.IsDragging(this.prevPoints, myTouches, 5) && !this._touchDrag) return;
         this._touchDrag = true;
         if (this.holdTimer) {
-            console.log("CLEAR")
+            console.log("CLEAR");
             clearTimeout(this.holdTimer);
             // this.holdTimer = undefined;
         }
+        // console.log(myTouches.length);
         switch (myTouches.length) {
             case 1:
-                this.handle1PointerMove(e);
+                this.handle1PointerMove(te);
                 break;
             case 2:
-                this.handle2PointersMove(e);
+                this.handle2PointersMove(te);
                 break;
         }
 
-        for (let i = 0; i < e.targetTouches.length; i++) {
-            const pt = e.targetTouches.item(i);
+        for (let i = 0; i < te.touches.length; i++) {
+            const pt = te.touches.item(i);
             if (pt) {
                 if (this.prevPoints.has(pt.identifier)) {
                     this.prevPoints.set(pt.identifier, pt);
@@ -100,11 +120,12 @@ export abstract class Touchable<T = {}> extends React.Component<T> {
     }
 
     @action
-    protected onTouchEnd = (e: TouchEvent): void => {
+    protected onTouchEnd = (e: Event, me: InteractionUtils.MultiTouchEvent<TouchEvent>): void => {
         // console.log(InteractionUtils.GetMyTargetTouches(e, this.prevPoints).length + " up");
         // remove all the touches associated with the event
-        for (let i = 0; i < e.changedTouches.length; i++) {
-            const pt = e.changedTouches.item(i);
+        const te = me.touchEvent;
+        for (let i = 0; i < te.changedTouches.length; i++) {
+            const pt = te.changedTouches.item(i);
             if (pt) {
                 if (this.prevPoints.has(pt.identifier)) {
                     this.prevPoints.delete(pt.identifier);
@@ -116,7 +137,7 @@ export abstract class Touchable<T = {}> extends React.Component<T> {
             console.log("clear");
         }
         this._touchDrag = false;
-        e.stopPropagation();
+        te.stopPropagation();
 
 
         // if (e.targetTouches.length === 0) {
@@ -126,11 +147,12 @@ export abstract class Touchable<T = {}> extends React.Component<T> {
         if (this.prevPoints.size === 0) {
             this.cleanUpInteractions();
         }
+        e.stopPropagation();
     }
 
     cleanUpInteractions = (): void => {
-        document.removeEventListener("touchmove", this.onTouch);
-        document.removeEventListener("touchend", this.onTouchEnd);
+        this.removeMoveListeners();
+        this.removeEndListeners();
     }
 
     handle1PointerMove = (e: TouchEvent): any => {
@@ -144,23 +166,43 @@ export abstract class Touchable<T = {}> extends React.Component<T> {
     }
 
     handle1PointerDown = (e: React.TouchEvent): any => {
-        document.removeEventListener("touchmove", this.onTouch);
-        document.addEventListener("touchmove", this.onTouch);
-        document.removeEventListener("touchend", this.onTouchEnd);
-        document.addEventListener("touchend", this.onTouchEnd);
+        this.removeMoveListeners();
+        this.addMoveListeners();
+        this.removeEndListeners();
+        this.addEndListeners();
     }
 
     handle2PointersDown = (e: React.TouchEvent): any => {
-        document.removeEventListener("touchmove", this.onTouch);
-        document.addEventListener("touchmove", this.onTouch);
-        document.removeEventListener("touchend", this.onTouchEnd);
-        document.addEventListener("touchend", this.onTouchEnd);
+        this.removeMoveListeners();
+        this.addMoveListeners();
+        this.removeEndListeners();
+        this.addEndListeners();
     }
 
     handle1PointerHoldStart = (e: React.TouchEvent): any => {
         e.stopPropagation();
         e.preventDefault();
-        document.removeEventListener("touchmove", this.onTouch);
+        this.removeMoveListeners();
+    }
+
+    addMoveListeners = () => {
+        const handler = (e: Event) => this.onTouch(e, (e as CustomEvent<InteractionUtils.MultiTouchEvent<TouchEvent>>).detail);
+        document.addEventListener("dashOnTouchMove", handler);
+        this.moveDisposer = () => document.removeEventListener("dashOnTouchMove", handler);
+    }
+
+    removeMoveListeners = () => {
+        this.moveDisposer && this.moveDisposer();
+    }
+
+    addEndListeners = () => {
+        const handler = (e: Event) => this.onTouchEnd(e, (e as CustomEvent<InteractionUtils.MultiTouchEvent<TouchEvent>>).detail);
+        document.addEventListener("dashOnTouchEnd", handler);
+        this.endDisposer = () => document.removeEventListener("dashOnTouchEnd", handler);
+    }
+
+    removeEndListeners = () => {
+        this.endDisposer && this.endDisposer();
     }
 
     handleHandDown = (e: React.TouchEvent) => {
-- 
cgit v1.2.3-70-g09d2

