From 92491285a0b394f433a018810606bc6a543e7e93 Mon Sep 17 00:00:00 2001
From: Stanley Yip <stanley_yip@brown.edu>
Date: Sat, 23 Nov 2019 16:17:28 -0500
Subject: a lot of fixes!

---
 src/client/views/Touchable.tsx | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

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

diff --git a/src/client/views/Touchable.tsx b/src/client/views/Touchable.tsx
index ba87025c4..326e8e578 100644
--- a/src/client/views/Touchable.tsx
+++ b/src/client/views/Touchable.tsx
@@ -41,7 +41,7 @@ export abstract class Touchable<T = {}> extends React.Component<T> {
     @action
     protected onTouch = (e: TouchEvent): void => {
         // if we're not actually moving a lot, don't consider it as dragging yet
-        if (!InteractionUtils.IsDragging(this.prevPoints, e.targetTouches, 5) && !this._touchDrag) return;
+        // if (!InteractionUtils.IsDragging(this.prevPoints, e.targetTouches, 5) && !this._touchDrag) return;
         this._touchDrag = true;
         switch (e.targetTouches.length) {
             case 1:
-- 
cgit v1.2.3-70-g09d2


From 22472e278c5616ba86c75ed29cd5846d0cf35ff5 Mon Sep 17 00:00:00 2001
From: Stanley Yip <stanley_yip@brown.edu>
Date: Sat, 23 Nov 2019 17:29:18 -0500
Subject: auto pen !

---
 src/client/util/InteractionUtils.ts                | 153 ++++++++++++---------
 src/client/views/Touchable.tsx                     |  34 +++--
 .../collectionFreeForm/CollectionFreeFormView.tsx  |  52 +++++--
 src/client/views/nodes/DocumentView.tsx            |  10 +-
 4 files changed, 150 insertions(+), 99 deletions(-)

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

diff --git a/src/client/util/InteractionUtils.ts b/src/client/util/InteractionUtils.ts
index e58635a6f..d5799c21f 100644
--- a/src/client/util/InteractionUtils.ts
+++ b/src/client/util/InteractionUtils.ts
@@ -1,9 +1,23 @@
 export namespace InteractionUtils {
-    export const MOUSE = "mouse";
-    export const TOUCH = "touch";
+    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 {
-        return e.pointerType === type;
+        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 {
@@ -42,70 +56,75 @@ export namespace InteractionUtils {
         return 0;
     }
 
-    /**
-     * 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 };
-    //     }
-    // }
+    // These might not be very useful anymore, but I'll leave them here for now -syip2
+    {
 
-    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;
+
+        /**
+         * 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;
+        // }
     }
 }
\ No newline at end of file
diff --git a/src/client/views/Touchable.tsx b/src/client/views/Touchable.tsx
index 326e8e578..dbadc27ea 100644
--- a/src/client/views/Touchable.tsx
+++ b/src/client/views/Touchable.tsx
@@ -17,22 +17,28 @@ export abstract class Touchable<T = {}> extends React.Component<T> {
     @action
     protected onTouchStart = (e: React.TouchEvent): void => {
         for (let i = 0; i < e.targetTouches.length; i++) {
-            let pt = e.targetTouches.item(i);
-            this.prevPoints.set(pt.identifier, pt);
+            let pt: any = e.targetTouches.item(i);
+            // pen is also a touch, but with a radius of 0.5 (at least with the surface pens). i doubt anyone's fingers are 2 pixels wide,
+            // and this seems to be the only way of differentiating pen and touch on touch events
+            if (pt.radiusX > 2 && pt.radiusY > 2) {
+                this.prevPoints.set(pt.identifier, pt);
+            }
         }
 
-        switch (e.targetTouches.length) {
-            case 1:
-                this.handle1PointerDown(e);
-                break;
-            case 2:
-                this.handle2PointersDown(e);
-        }
+        if (this.prevPoints.size) {
+            switch (e.targetTouches.length) {
+                case 1:
+                    this.handle1PointerDown(e);
+                    break;
+                case 2:
+                    this.handle2PointersDown(e);
+            }
 
-        document.removeEventListener("touchmove", this.onTouch);
-        document.addEventListener("touchmove", this.onTouch);
-        document.removeEventListener("touchend", this.onTouchEnd);
-        document.addEventListener("touchend", this.onTouchEnd);
+            document.removeEventListener("touchmove", this.onTouch);
+            document.addEventListener("touchmove", this.onTouch);
+            document.removeEventListener("touchend", this.onTouchEnd);
+            document.addEventListener("touchend", this.onTouchEnd);
+        }
     }
 
     /**
@@ -45,7 +51,7 @@ export abstract class Touchable<T = {}> extends React.Component<T> {
         this._touchDrag = true;
         switch (e.targetTouches.length) {
             case 1:
-                this.handle1PointerMove(e)
+                this.handle1PointerMove(e);
                 break;
             case 2:
                 this.handle2PointersMove(e);
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 3dd655b96..03f860b32 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -26,7 +26,7 @@ import { COLLECTION_BORDER_WIDTH } from "../../../views/globalCssVariables.scss"
 import { ContextMenu } from "../../ContextMenu";
 import { ContextMenuProps } from "../../ContextMenuItem";
 import { InkingControl } from "../../InkingControl";
-import { CreatePolyline } from "../../InkingStroke";
+import { CreatePolyline, InkingStroke } from "../../InkingStroke";
 import { CollectionFreeFormDocumentView } from "../../nodes/CollectionFreeFormDocumentView";
 import { DocumentViewProps } from "../../nodes/DocumentView";
 import { FormattedTextBox } from "../../nodes/FormattedTextBox";
@@ -282,20 +282,43 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
             document.removeEventListener("pointerup", this.onPointerUp);
             document.addEventListener("pointermove", this.onPointerMove);
             document.addEventListener("pointerup", this.onPointerUp);
-            if (InkingControl.Instance.selectedTool === InkTool.None) {
+            // if physically using a pen or we're in pen or highlighter mode
+            if (InteractionUtils.IsType(e, InteractionUtils.PENTYPE) || (InkingControl.Instance.selectedTool === InkTool.Highlighter || InkingControl.Instance.selectedTool === InkTool.Pen)) {
+                e.stopPropagation();
+                e.preventDefault();
+                let point = this.getTransform().transformPoint(e.pageX, e.pageY);
+                this._points.push({ x: point[0], y: point[1] });
+            }
+            // if not using a pen and in no ink mode
+            else if (InkingControl.Instance.selectedTool === InkTool.None) {
                 this._lastX = e.pageX;
                 this._lastY = e.pageY;
             }
+            // eraser or scrubber plus anything else mode
             else {
                 e.stopPropagation();
                 e.preventDefault();
-
-                if (InkingControl.Instance.selectedTool !== InkTool.Eraser && InkingControl.Instance.selectedTool !== InkTool.Scrubber) {
-                    let point = this.getTransform().transformPoint(e.pageX, e.pageY);
-                    this._points.push({ x: point[0], y: point[1] });
-                }
             }
         }
+        // if (e.button === 0 && !e.shiftKey && !e.altKey && !e.ctrlKey && this.props.active(true)) {
+        //     document.removeEventListener("pointermove", this.onPointerMove);
+        //     document.removeEventListener("pointerup", this.onPointerUp);
+        //     document.addEventListener("pointermove", this.onPointerMove);
+        //     document.addEventListener("pointerup", this.onPointerUp);
+        //     if (InkingControl.Instance.selectedTool === InkTool.None) {
+        //         this._lastX = e.pageX;
+        //         this._lastY = e.pageY;
+        //     }
+        //     else {
+        //         e.stopPropagation();
+        //         e.preventDefault();
+
+        //         if (InkingControl.Instance.selectedTool !== InkTool.Eraser && InkingControl.Instance.selectedTool !== InkTool.Scrubber) {
+        //             let point = this.getTransform().transformPoint(e.pageX, e.pageY);
+        //             this._points.push({ x: point[0], y: point[1] });
+        //         }
+        //     }
+        // }
     }
 
     @action
@@ -308,7 +331,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
 
     @action
     onPointerUp = (e: PointerEvent): void => {
-        if (InteractionUtils.IsType(e, InteractionUtils.TOUCH) && this._points.length <= 1) return;
+        if (InteractionUtils.IsType(e, InteractionUtils.TOUCHTYPE) && this._points.length <= 1) return;
 
         if (this._points.length > 1) {
             let B = this.svgBounds;
@@ -364,14 +387,19 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
 
     @action
     onPointerMove = (e: PointerEvent): void => {
-        if (InteractionUtils.IsType(e, InteractionUtils.TOUCH)) {
+        if (InteractionUtils.IsType(e, InteractionUtils.TOUCHTYPE)) {
             if (this.props.active(true)) {
                 e.stopPropagation();
             }
             return;
         }
         if (!e.cancelBubble) {
-            if (InkingControl.Instance.selectedTool === InkTool.None) {
+            const selectedTool = InkingControl.Instance.selectedTool;
+            if (selectedTool === InkTool.Highlighter || selectedTool === InkTool.Pen || InteractionUtils.IsType(e, InteractionUtils.PENTYPE)) {
+                let point = this.getTransform().transformPoint(e.clientX, e.clientY);
+                this._points.push({ x: point[0], y: point[1] });
+            }
+            else if (selectedTool === InkTool.None) {
                 if (this._hitCluster && this.tryDragCluster(e)) {
                     e.stopPropagation(); // doesn't actually stop propagation since all our listeners are listening to events on 'document'  however it does mark the event as cancelBubble=true which we test for in the move event handlers
                     e.preventDefault();
@@ -381,10 +409,6 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
                 }
                 this.pan(e);
             }
-            else if (InkingControl.Instance.selectedTool !== InkTool.Eraser && InkingControl.Instance.selectedTool !== InkTool.Scrubber) {
-                let point = this.getTransform().transformPoint(e.clientX, e.clientY);
-                this._points.push({ x: point[0], y: point[1] });
-            }
             e.stopPropagation(); // doesn't actually stop propagation since all our listeners are listening to events on 'document'  however it does mark the event as cancelBubble=true which we test for in the move event handlers
             e.preventDefault();
         }
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 3a600e0fd..687106a9e 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -193,9 +193,11 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
     }
 
     onPointerDown = (e: React.PointerEvent): void => {
-        if ((e.nativeEvent.cancelBubble && (e.button === 0 || InteractionUtils.IsType(e, InteractionUtils.TOUCH)))
+        if ((e.nativeEvent.cancelBubble && (e.button === 0 || InteractionUtils.IsType(e, InteractionUtils.TOUCHTYPE)))
             // return if we're inking, and not selecting a button document
-            || (InkingControl.Instance.selectedTool !== InkTool.None && !this.Document.onClick)) return;
+            || (InkingControl.Instance.selectedTool !== InkTool.None && !this.Document.onClick)
+            // return if using pen or eraser
+            || InteractionUtils.IsType(e, InteractionUtils.PENTYPE) || InteractionUtils.IsType(e, InteractionUtils.ERASERTYPE)) return;
         this._downX = e.clientX;
         this._downY = e.clientY;
         this._hitTemplateDrag = false;
@@ -206,7 +208,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
                 this._hitTemplateDrag = true;
             }
         }
-        if ((this.active || this.Document.onDragStart || this.Document.onClick) && !e.ctrlKey && (e.button === 0 || InteractionUtils.IsType(e, InteractionUtils.TOUCH)) && !this.Document.lockedPosition && !this.Document.inOverlay) e.stopPropagation(); // events stop at the lowest document that is active.  if right dragging, we let it go through though to allow for context menu clicks. PointerMove callbacks should remove themselves if the move event gets stopPropagated by a lower-level handler (e.g, marquee drag);
+        if ((this.active || this.Document.onDragStart || this.Document.onClick) && !e.ctrlKey && (e.button === 0 || InteractionUtils.IsType(e, InteractionUtils.TOUCHTYPE)) && !this.Document.lockedPosition && !this.Document.inOverlay) e.stopPropagation(); // events stop at the lowest document that is active.  if right dragging, we let it go through though to allow for context menu clicks. PointerMove callbacks should remove themselves if the move event gets stopPropagated by a lower-level handler (e.g, marquee drag);
         document.removeEventListener("pointermove", this.onPointerMove);
         document.removeEventListener("pointerup", this.onPointerUp);
         document.addEventListener("pointermove", this.onPointerMove);
@@ -221,7 +223,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
         }
         else if (!e.cancelBubble && (SelectionManager.IsSelected(this, true) || this.props.parentActive(true) || this.Document.onDragStart || this.Document.onClick) && !this.Document.lockedPosition && !this.Document.inOverlay) {
             if (Math.abs(this._downX - e.clientX) > 3 || Math.abs(this._downY - e.clientY) > 3) {
-                if (!e.altKey && (!this.topMost || this.Document.onDragStart || this.Document.onClick) && (e.buttons === 1 || InteractionUtils.IsType(e, InteractionUtils.TOUCH))) {
+                if (!e.altKey && (!this.topMost || this.Document.onDragStart || this.Document.onClick) && (e.buttons === 1 || InteractionUtils.IsType(e, InteractionUtils.TOUCHTYPE))) {
                     document.removeEventListener("pointermove", this.onPointerMove);
                     document.removeEventListener("pointerup", this.onPointerUp);
                     this.startDragging(this._downX, this._downY, this.Document.dropAction ? this.Document.dropAction as any : e.ctrlKey || e.altKey ? "alias" : undefined, this._hitTemplateDrag);
-- 
cgit v1.2.3-70-g09d2


From 80ecf02d19efb4cc2de63b77f4aa821bd74c67b2 Mon Sep 17 00:00:00 2001
From: Stanley Yip <stanley_yip@brown.edu>
Date: Sat, 23 Nov 2019 17:56:43 -0500
Subject: tool bar works better with touch, started doing resizing interaction
 but not done

---
 src/client/util/InteractionUtils.ts     | 23 +++++++++++++++++++++++
 src/client/views/Touchable.tsx          | 12 ++++++++++++
 src/client/views/nodes/DocumentView.tsx | 17 ++++++++++++++++-
 src/client/views/nodes/FontIconBox.scss |  8 +++++---
 4 files changed, 56 insertions(+), 4 deletions(-)

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

diff --git a/src/client/util/InteractionUtils.ts b/src/client/util/InteractionUtils.ts
index d5799c21f..b7738e862 100644
--- a/src/client/util/InteractionUtils.ts
+++ b/src/client/util/InteractionUtils.ts
@@ -56,6 +56,29 @@ export namespace InteractionUtils {
         return 0;
     }
 
+    /**
+     * Returns -1 if pinning and pinching out, 0 if not pinning, 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 Pinning(pt1: React.Touch, pt2: React.Touch, oldPoint1: React.Touch, oldPoint2: React.Touch): number {
+        let threshold = 4;
+
+        let pt1Dist = TwoPointEuclidist(oldPoint1, pt1);
+        let pt2Dist = TwoPointEuclidist(oldPoint2, pt2);
+
+        let pinching = Pinching(pt1, pt2, oldPoint1, oldPoint2);
+
+        if (pinching !== 0) {
+            if ((pt1Dist < threshold && pt2Dist > threshold) || (pt1Dist > threshold && pt2Dist < threshold)) {
+                return pinching;
+            }
+        }
+        return 0;
+    }
+
     // These might not be very useful anymore, but I'll leave them here for now -syip2
     {
 
diff --git a/src/client/views/Touchable.tsx b/src/client/views/Touchable.tsx
index dbadc27ea..0056a1d96 100644
--- a/src/client/views/Touchable.tsx
+++ b/src/client/views/Touchable.tsx
@@ -57,6 +57,18 @@ export abstract class Touchable<T = {}> extends React.Component<T> {
                 this.handle2PointersMove(e);
                 break;
         }
+
+        for (let i = 0; i < e.targetTouches.length; i++) {
+            let pt = e.targetTouches.item(i);
+            if (pt) {
+                if (this.prevPoints.has(pt.identifier)) {
+                    this.prevPoints.set(pt.identifier, pt);
+                }
+                else {
+                    this.prevPoints.set(pt.identifier, pt);
+                }
+            }
+        }
     }
 
     @action
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 687106a9e..f8c592f07 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -648,6 +648,21 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
         return this.Document.isBackground && !this.isSelected();
     }
 
+    @action
+    handle2PointersMove = (e: TouchEvent) => {
+        let pt1 = e.targetTouches.item(0);
+        let pt2 = e.targetTouches.item(1);
+        if (pt1 && pt2 && this.prevPoints.has(pt1.identifier) && this.prevPoints.has(pt2.identifier)) {
+            let oldPoint1 = this.prevPoints.get(pt1.identifier);
+            let oldPoint2 = this.prevPoints.get(pt2.identifier);
+            let pinching = InteractionUtils.Pinning(pt1, pt2, oldPoint1!, oldPoint2!);
+            if (pinching !== 0) {
+                let newWidth = Math.max(Math.abs(oldPoint1!.clientX - oldPoint2!.clientX), Math.abs(pt1.clientX - pt2.clientX))
+                this.props.Document.width = newWidth;
+            }
+        }
+    }
+
     render() {
         if (!this.props.Document) return (null);
         const ruleColor = this.props.ruleProvider ? StrCast(this.props.ruleProvider["ruleColor_" + this.Document.heading]) : undefined;
@@ -682,7 +697,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
                 width: animwidth,
                 height: animheight,
                 opacity: this.Document.opacity
-            }} >
+            }} onTouchStart={this.onTouchStart}>
             {this.innards}
         </div>;
     }
diff --git a/src/client/views/nodes/FontIconBox.scss b/src/client/views/nodes/FontIconBox.scss
index 905601ce3..f0fe7a54e 100644
--- a/src/client/views/nodes/FontIconBox.scss
+++ b/src/client/views/nodes/FontIconBox.scss
@@ -2,12 +2,14 @@
     width: 100%;
     height: 100%;
     pointer-events: all;
+    touch-action: none;
     border-radius: inherit;
     background: black;
     border-radius: 100%;
     transform-origin: top left;
+
     svg {
-        width:95% !important;
-        height:95%;
+        width: 95% !important;
+        height: 95%;
     }
-}
+}
\ No newline at end of file
-- 
cgit v1.2.3-70-g09d2

