From d16636a8246dadb486476fe98da63fc0db4d36dc Mon Sep 17 00:00:00 2001 From: Stanley Yip Date: Tue, 7 Jan 2020 14:49:27 -0500 Subject: resizing works, the math is just wrong looool --- src/client/util/InteractionUtils.ts | 2 +- src/client/views/Touchable.tsx | 21 ++- .../collectionFreeForm/CollectionFreeFormView.tsx | 44 ++++- src/client/views/nodes/DocumentView.tsx | 191 +++++++++++++++++---- src/client/views/nodes/FormattedTextBox.scss | 20 ++- 5 files changed, 220 insertions(+), 58 deletions(-) (limited to 'src') diff --git a/src/client/util/InteractionUtils.ts b/src/client/util/InteractionUtils.ts index 7c386abc2..2d3671041 100644 --- a/src/client/util/InteractionUtils.ts +++ b/src/client/util/InteractionUtils.ts @@ -8,7 +8,7 @@ export namespace InteractionUtils { const REACT_POINTER_PEN_BUTTON = 0; const ERASER_BUTTON = 5; - export function GetMyTargetTouches(e: TouchEvent, prevPoints: Map): React.Touch[] { + export function GetMyTargetTouches(e: TouchEvent | React.TouchEvent, prevPoints: Map): React.Touch[] { let myTouches = new Array(); for (let i = 0; i < e.targetTouches.length; i++) { let pt = e.targetTouches.item(i); diff --git a/src/client/views/Touchable.tsx b/src/client/views/Touchable.tsx index a647dec04..7b0581376 100644 --- a/src/client/views/Touchable.tsx +++ b/src/client/views/Touchable.tsx @@ -26,7 +26,6 @@ export abstract class Touchable extends React.Component { } if (this.prevPoints.size) { - console.log(e.targetTouches.length); switch (this.prevPoints.size) { case 1: this.handle1PointerDown(e); @@ -35,11 +34,6 @@ export abstract class Touchable extends React.Component { this.handle2PointersDown(e); break; } - - document.removeEventListener("touchmove", this.onTouch); - document.addEventListener("touchmove", this.onTouch); - document.removeEventListener("touchend", this.onTouchEnd); - document.addEventListener("touchend", this.onTouchEnd); } } @@ -110,6 +104,17 @@ export abstract class Touchable extends React.Component { e.preventDefault(); } - handle1PointerDown = (e: React.TouchEvent): any => { }; - handle2PointersDown = (e: React.TouchEvent): any => { }; + 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); + } + + 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); + } } \ No newline at end of file diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 7b507f739..75690ab2c 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -326,9 +326,30 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { @action handle1PointerDown = (e: React.TouchEvent) => { + if (e.nativeEvent.cancelBubble) return; let pt = e.targetTouches.item(0); if (pt) { this._hitCluster = this.props.Document.useCluster ? this.pickCluster(this.getTransform().transformPoint(pt.clientX, pt.clientY)) !== -1 : false; + if (!e.shiftKey && !e.altKey && !e.ctrlKey && this.props.active(true)) { + document.removeEventListener("touchmove", this.onTouch); + document.addEventListener("touchmove", this.onTouch); + document.removeEventListener("touchend", this.onTouchEnd); + document.addEventListener("touchend", this.onTouchEnd); + if (InkingControl.Instance.selectedTool === InkTool.Highlighter || InkingControl.Instance.selectedTool === InkTool.Pen) { + e.stopPropagation(); + e.preventDefault(); + let point = this.getTransform().transformPoint(pt.pageX, pt.pageY); + this._points.push({ X: point[0], Y: point[1] }); + } + else if (InkingControl.Instance.selectedTool === InkTool.None) { + this._lastX = pt.pageX; + this._lastY = pt.pageY; + } + else { + e.stopPropagation(); + e.preventDefault(); + } + } } } @@ -544,14 +565,21 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { } handle2PointersDown = (e: React.TouchEvent) => { - let pt1: React.Touch | null = e.targetTouches.item(0); - let pt2: React.Touch | null = e.targetTouches.item(1); - if (!pt1 || !pt2) return; - - let centerX = Math.min(pt1.clientX, pt2.clientX) + Math.abs(pt2.clientX - pt1.clientX) / 2; - let centerY = Math.min(pt1.clientY, pt2.clientY) + Math.abs(pt2.clientY - pt1.clientY) / 2; - this._lastX = centerX; - this._lastY = centerY; + if (!e.nativeEvent.cancelBubble && this.props.active(true)) { + let pt1: React.Touch | null = e.targetTouches.item(0); + let pt2: React.Touch | null = e.targetTouches.item(1); + if (!pt1 || !pt2) return; + + let centerX = Math.min(pt1.clientX, pt2.clientX) + Math.abs(pt2.clientX - pt1.clientX) / 2; + let centerY = Math.min(pt1.clientY, pt2.clientY) + Math.abs(pt2.clientY - pt1.clientY) / 2; + this._lastX = centerX; + this._lastY = centerY; + document.removeEventListener("touchmove", this.onTouch); + document.addEventListener("touchmove", this.onTouch); + document.removeEventListener("touchend", this.onTouchEnd); + document.addEventListener("touchend", this.onTouchEnd); + e.stopPropagation(); + } } cleanUpInteractions = () => { diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index dfeadb8c0..1780d9789 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -4,7 +4,7 @@ import { action, computed, runInAction, trace } from "mobx"; import { observer } from "mobx-react"; import * as rp from "request-promise"; import { Doc, DocListCast, DocListCastAsync, Opt } from "../../../new_fields/Doc"; -import { Document } from '../../../new_fields/documentSchemas'; +import { Document, PositionDocument } from '../../../new_fields/documentSchemas'; import { Id } from '../../../new_fields/FieldSymbols'; import { listSpec } from "../../../new_fields/Schema"; import { ScriptField } from '../../../new_fields/ScriptField'; @@ -193,28 +193,165 @@ export class DocumentView extends DocComponent(Docu } } + handle1PointerDown = (e: React.TouchEvent) => { + if (!e.nativeEvent.cancelBubble) { + let touch = InteractionUtils.GetMyTargetTouches(e, this.prevPoints)[0]; + this._downX = touch.clientX; + this._downY = touch.clientY; + this._hitTemplateDrag = false; + for (let element = (e.target as any); element && !this._hitTemplateDrag; element = element.parentElement) { + if (element.className && element.className.toString() === "collectionViewBaseChrome-collapse") { + this._hitTemplateDrag = true; + } + } + if ((this.active || this.Document.onDragStart || this.Document.onClick) && !e.ctrlKey && !this.Document.lockedPosition && !this.Document.inOverlay) e.stopPropagation(); + document.removeEventListener("touchmove", this.onTouch); + document.addEventListener("touchmove", this.onTouch); + document.removeEventListener("touchend", this.onTouchEnd); + document.addEventListener("touchend", this.onTouchEnd); + if ((e.nativeEvent as any).formattedHandled) e.stopPropagation(); + console.log("down") + } + } + + handle1PointerMove = (e: TouchEvent) => { + if ((e as any).formattedHandled) { e.stopPropagation; return; } + if (e.cancelBubble && this.active) { + document.removeEventListener("touchmove", this.onTouch); + } + else if (!e.cancelBubble && (SelectionManager.IsSelected(this, true) || this.props.parentActive(true) || this.Document.onDragStart || this.Document.onClick) && !this.Document.lockedPosition && !this.Document.inOverlay) { + let touch = InteractionUtils.GetMyTargetTouches(e, this.prevPoints)[0]; + if (Math.abs(this._downX - touch.clientX) > 3 || Math.abs(this._downY - touch.clientY) > 3) { + if (!e.altKey && (!this.topMost || this.Document.onDragStart || this.Document.onClick)) { + document.removeEventListener("touchmove", this.onTouch); + document.removeEventListener("touchend", this.onTouchEnd); + this.startDragging(this._downX, this._downY, this.Document.dropAction ? this.Document.dropAction as any : e.ctrlKey || e.altKey ? "alias" : undefined, this._hitTemplateDrag); + } + } + 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(); + + } + } + + handle2PointersDown = (e: React.TouchEvent) => { + if (!e.nativeEvent.cancelBubble && !this.isSelected()) { + e.stopPropagation(); + e.preventDefault(); + + document.removeEventListener("touchmove", this.onTouch); + document.addEventListener("touchmove", this.onTouch); + document.removeEventListener("touchend", this.onTouchEnd); + document.addEventListener("touchend", this.onTouchEnd); + } + } + + @action + handle2PointersMove = (e: TouchEvent) => { + let myTouches = InteractionUtils.GetMyTargetTouches(e, this.prevPoints); + let pt1 = myTouches[0]; + let pt2 = myTouches[1]; + 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 && oldPoint1 && oldPoint2) { + // let dX = (Math.min(pt1.clientX, pt2.clientX) - Math.min(oldPoint1.clientX, oldPoint2.clientX)); + // let dY = (Math.min(pt1.clientY, pt2.clientY) - Math.min(oldPoint1.clientY, oldPoint2.clientY)); + // let dX = Math.sign(Math.abs(pt1.clientX - oldPoint1.clientX) - Math.abs(pt2.clientX - oldPoint2.clientX)); + // let dY = Math.sign(Math.abs(pt1.clientY - oldPoint1.clientY) - Math.abs(pt2.clientY - oldPoint2.clientY)); + // let dW = -dX; + // let dH = -dY; + let dW = (Math.abs(pt1.clientX - pt2.clientX) - Math.abs(oldPoint1.clientX - oldPoint2.clientX)); + let dH = (Math.abs(pt1.clientY - pt2.clientY) - Math.abs(oldPoint1.clientY - oldPoint2.clientY)); + let dX = -1 * Math.sign(dW); + let dY = -1 * Math.sign(dH); + + if (dX !== 0 || dY !== 0 || dW !== 0 || dH !== 0) { + let doc = PositionDocument(this.props.Document); + let layoutDoc = PositionDocument(Doc.Layout(this.props.Document)); + let nwidth = layoutDoc.nativeWidth || 0; + let nheight = layoutDoc.nativeHeight || 0; + let width = (layoutDoc.width || 0); + let height = (layoutDoc.height || (nheight / nwidth * width)); + let scale = this.props.ScreenToLocalTransform().Scale * this.props.ContentScaling(); + let actualdW = Math.max(width + (dW * scale), 20); + let actualdH = Math.max(height + (dH * scale), 20); + doc.x = (doc.x || 0) + dX * (actualdW - width); + doc.y = (doc.y || 0) + dY * (actualdH - height); + let fixedAspect = e.ctrlKey || (!layoutDoc.ignoreAspect && nwidth && nheight); + if (fixedAspect && e.ctrlKey && layoutDoc.ignoreAspect) { + layoutDoc.ignoreAspect = false; + layoutDoc.nativeWidth = nwidth = layoutDoc.width || 0; + layoutDoc.nativeHeight = nheight = layoutDoc.height || 0; + } + if (fixedAspect && (!nwidth || !nheight)) { + layoutDoc.nativeWidth = nwidth = layoutDoc.width || 0; + layoutDoc.nativeHeight = nheight = layoutDoc.height || 0; + } + if (nwidth > 0 && nheight > 0 && !layoutDoc.ignoreAspect) { + if (Math.abs(dW) > Math.abs(dH)) { + if (!fixedAspect) { + layoutDoc.nativeWidth = actualdW / (layoutDoc.width || 1) * (layoutDoc.nativeWidth || 0); + } + layoutDoc.width = actualdW; + if (fixedAspect && !layoutDoc.fitWidth) layoutDoc.height = nheight / nwidth * layoutDoc.width; + else layoutDoc.height = actualdH; + } + else { + if (!fixedAspect) { + layoutDoc.nativeHeight = actualdH / (layoutDoc.height || 1) * (doc.nativeHeight || 0); + } + layoutDoc.height = actualdH; + if (fixedAspect && !layoutDoc.fitWidth) layoutDoc.width = nwidth / nheight * layoutDoc.height; + else layoutDoc.width = actualdW; + } + } else { + dW && (layoutDoc.width = actualdW); + dH && (layoutDoc.height = actualdH); + dH && layoutDoc.autoHeight && (layoutDoc.autoHeight = false); + } + } + // let newWidth = Math.max(Math.abs(oldPoint1!.clientX - oldPoint2!.clientX), Math.abs(pt1.clientX - pt2.clientX)) + // this.props.Document.width = newWidth; + e.stopPropagation(); + e.preventDefault(); + } + } + onPointerDown = (e: React.PointerEvent): void => { - 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 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; - // this whole section needs to move somewhere else. We're trying to initiate a special "template" drag where - // this document is the template and we apply it to whatever we drop it on. - for (let element = (e.target as any); element && !this._hitTemplateDrag; element = element.parentElement) { - if (element.className && element.className.toString() === "collectionViewBaseChrome-collapse") { - this._hitTemplateDrag = true; + // console.log(e.button) + // console.log(e.nativeEvent) + // continue if the event hasn't been canceled AND we are using a moues or this is has an onClick or onDragStart function (meaning it is a button document) + if (!InteractionUtils.IsType(e, InteractionUtils.MOUSETYPE)) { + e.stopPropagation(); + return; + } + if ((!e.nativeEvent.cancelBubble || this.Document.onClick || this.Document.onDragStart)) { + // 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 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; + // this whole section needs to move somewhere else. We're trying to initiate a special "template" drag where + // this document is the template and we apply it to whatever we drop it on. + for (let element = (e.target as any); element && !this._hitTemplateDrag; element = element.parentElement) { + if (element.className && element.className.toString() === "collectionViewBaseChrome-collapse") { + this._hitTemplateDrag = true; + } } + 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); + document.addEventListener("pointerup", this.onPointerUp); + if ((e.nativeEvent as any).formattedHandled) { e.stopPropagation(); } } - 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); - document.addEventListener("pointerup", this.onPointerUp); - if ((e.nativeEvent as any).formattedHandled) { e.stopPropagation(); } } onPointerMove = (e: PointerEvent): void => { @@ -649,20 +786,6 @@ export class DocumentView extends DocComponent(Docu return (this.Document.isBackground && !this.isSelected()) || (this.Document.type === DocumentType.INK && InkingControl.Instance.selectedTool !== InkTool.None); } - @action - handle2PointersMove = (e: TouchEvent) => { - let myTouches = InteractionUtils.GetMyTargetTouches(e, this.prevPoints); - let pt1 = myTouches[0]; - let pt2 = myTouches[1]; - 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; diff --git a/src/client/views/nodes/FormattedTextBox.scss b/src/client/views/nodes/FormattedTextBox.scss index 77cdd3d42..2e5848db4 100644 --- a/src/client/views/nodes/FormattedTextBox.scss +++ b/src/client/views/nodes/FormattedTextBox.scss @@ -11,6 +11,7 @@ } .formattedTextBox-cont { + touch-action: none; cursor: text; background: inherit; padding: 0; @@ -50,6 +51,7 @@ width: 100%; height: 100%; } + .formattedTextBox-sidebar-handle { position: absolute; top: calc(50% - 17.5px); @@ -58,19 +60,23 @@ background: lightgray; border-radius: 20px; } -.formattedTextBox-cont > .formattedTextBox-sidebar-handle { + +.formattedTextBox-cont>.formattedTextBox-sidebar-handle { right: 0; left: unset; } -.formattedTextBox-sidebar, .formattedTextBox-sidebar-inking { - border-left: dashed 1px black; - height: 100%; + +.formattedTextBox-sidebar, +.formattedTextBox-sidebar-inking { + border-left: dashed 1px black; + height: 100%; display: inline-block; position: absolute; right: 0; - > .formattedTextBox-sidebar-handle { - right:unset; - left:-5; + + >.formattedTextBox-sidebar-handle { + right: unset; + left: -5; } } -- cgit v1.2.3-70-g09d2