diff options
Diffstat (limited to 'src/client/views/Touchable.tsx')
-rw-r--r-- | src/client/views/Touchable.tsx | 139 |
1 files changed, 103 insertions, 36 deletions
diff --git a/src/client/views/Touchable.tsx b/src/client/views/Touchable.tsx index 251cd41e5..7800c4019 100644 --- a/src/client/views/Touchable.tsx +++ b/src/client/views/Touchable.tsx @@ -1,12 +1,18 @@ import * as React from 'react'; import { action } from 'mobx'; import { InteractionUtils } from '../util/InteractionUtils'; +import { SelectionManager } from '../util/SelectionManager'; +import { RadialMenu } from './nodes/RadialMenu'; const HOLD_DURATION = 1000; export abstract class Touchable<T = {}> extends React.Component<T> { + //private 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>(); @@ -19,26 +25,57 @@ 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 => { - for (let i = 0; i < e.targetTouches.length; i++) { - const pt: any = e.targetTouches.item(i); - // 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 > 0.5 && pt.radiusY > 0.5) { + protected onTouchStart = (e: Event, me: InteractionUtils.MultiTouchEvent<React.TouchEvent>): void => { + const actualPts: React.Touch[] = []; + const te = me.touchEvent; + // loop through all touches on screen + for (const pt of me.touches) { + actualPts.push(pt); + 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 (const tPt of me.changedTouches) { + 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[] = []; + this.prevPoints.forEach(pt => { + if (!actualPts.includes(pt)) { + ptsToDelete.push(pt.identifier); + } + }); + + // console.log(ptsToDelete.length); + ptsToDelete.forEach(pt => this.prevPoints.delete(pt)); + if (this.prevPoints.size) { switch (this.prevPoints.size) { case 1: - this.handle1PointerDown(e); - e.persist(); - this.holdTimer = setTimeout(() => this.handle1PointerHoldStart(e), HOLD_DURATION); + this.handle1PointerDown(te, me); + te.persist(); + // if (this.holdTimer) { + // clearTimeout(this.holdTimer) + // this.holdTimer = undefined; + // } + this.holdTimer = setTimeout(() => this.handle1PointerHoldStart(te, me), HOLD_DURATION); + // e.stopPropagation(); + // console.log(this.holdTimer); break; case 2: - this.handle2PointersDown(e); + this.handle2PointersDown(te, me); + // e.stopPropagation(); break; + // case 5: + // this.handleHandDown(te); + // break; } } } @@ -47,26 +84,29 @@ 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); + protected onTouch = (e: Event, me: InteractionUtils.MultiTouchEvent<TouchEvent>): void => { + const te = me.touchEvent; + const myTouches = InteractionUtils.GetMyTargetTouches(me, 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"); clearTimeout(this.holdTimer); + // this.holdTimer = undefined; } + // console.log(myTouches.length); switch (myTouches.length) { case 1: - this.handle1PointerMove(e); + this.handle1PointerMove(te, me); break; case 2: - this.handle2PointersMove(e); + this.handle2PointersMove(te, me); break; } - for (let i = 0; i < e.targetTouches.length; i++) { - const pt = e.targetTouches.item(i); + for (const pt of me.touches) { if (pt) { if (this.prevPoints.has(pt.identifier)) { this.prevPoints.set(pt.identifier, pt); @@ -76,11 +116,11 @@ 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 (const pt of me.changedTouches) { if (pt) { if (this.prevPoints.has(pt.identifier)) { this.prevPoints.delete(pt.identifier); @@ -89,9 +129,10 @@ export abstract class Touchable<T = {}> extends React.Component<T> { } if (this.holdTimer) { clearTimeout(this.holdTimer); + console.log("clear"); } this._touchDrag = false; - e.stopPropagation(); + te.stopPropagation(); // if (e.targetTouches.length === 0) { @@ -101,40 +142,66 @@ 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 => { + handle1PointerMove = (e: TouchEvent, me: InteractionUtils.MultiTouchEvent<TouchEvent>): any => { e.stopPropagation(); e.preventDefault(); } - handle2PointersMove = (e: TouchEvent): any => { + handle2PointersMove = (e: TouchEvent, me: InteractionUtils.MultiTouchEvent<TouchEvent>): any => { e.stopPropagation(); e.preventDefault(); } - 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); + handle1PointerDown = (e: React.TouchEvent, me: InteractionUtils.MultiTouchEvent<React.TouchEvent>): any => { + 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); + handle2PointersDown = (e: React.TouchEvent, me: InteractionUtils.MultiTouchEvent<React.TouchEvent>): any => { + this.removeMoveListeners(); + this.addMoveListeners(); + this.removeEndListeners(); + this.addEndListeners(); } - handle1PointerHoldStart = (e: React.TouchEvent): any => { - console.log("Hold"); + handle1PointerHoldStart = (e: React.TouchEvent, me: InteractionUtils.MultiTouchEvent<React.TouchEvent>): any => { e.stopPropagation(); e.preventDefault(); + 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) => { + // e.stopPropagation(); + // e.preventDefault(); } }
\ No newline at end of file |