aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/collections/collectionFreeForm
diff options
context:
space:
mode:
authoranika-ahluwalia <anika.ahluwalia@gmail.com>2020-04-14 17:41:51 -0500
committeranika-ahluwalia <anika.ahluwalia@gmail.com>2020-04-14 17:41:51 -0500
commite7469b5454acd59238dfeb5a7e023a591a23d852 (patch)
treefa30ffeaf57ee884445e5464ffd49fe03503d4c6 /src/client/views/collections/collectionFreeForm
parentc17e8ebf0454ad2067ab6556355c5bb69b7cf41e (diff)
parentad863eaee3af92c3bfec6dc72bc5d9ee5eec31d4 (diff)
Merge branch 'master' of https://github.com/browngraphicslab/Dash-Web into script_documents
Diffstat (limited to 'src/client/views/collections/collectionFreeForm')
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss2
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx174
-rw-r--r--src/client/views/collections/collectionFreeForm/MarqueeView.tsx22
3 files changed, 101 insertions, 97 deletions
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss
index 730392ab5..e1516b468 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss
@@ -12,7 +12,7 @@
}
.collectionfreeformview-ease {
- transition: transform 1s;
+ transition: transform 500ms;
}
.collectionfreeformview-none {
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 146ec9f7d..a77f09163 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -15,7 +15,7 @@ import { ScriptField } from "../../../../new_fields/ScriptField";
import { BoolCast, Cast, FieldValue, NumCast, ScriptCast, StrCast } from "../../../../new_fields/Types";
import { TraceMobx } from "../../../../new_fields/util";
import { GestureUtils } from "../../../../pen-gestures/GestureUtils";
-import { aggregateBounds, intersectRect, returnOne, Utils, returnZero } from "../../../../Utils";
+import { aggregateBounds, intersectRect, returnOne, Utils, returnZero, returnFalse } from "../../../../Utils";
import { CognitiveServices } from "../../../cognitive_services/CognitiveServices";
import { DocServer } from "../../../DocServer";
import { Docs } from "../../../documents/Documents";
@@ -43,6 +43,7 @@ import "./CollectionFreeFormView.scss";
import MarqueeOptionsMenu from "./MarqueeOptionsMenu";
import { MarqueeView } from "./MarqueeView";
import React = require("react");
+import { CollectionViewType } from "../CollectionView";
library.add(faEye as any, faTable, faPaintBrush, faExpandArrowsAlt, faCompressArrowsAlt, faCompass, faUpload, faBraille, faChalkboard, faFileUpload);
@@ -67,13 +68,15 @@ export const panZoomSchema = createSchema({
type PanZoomDocument = makeInterface<[typeof panZoomSchema, typeof documentSchema, typeof positionSchema, typeof pageSchema]>;
const PanZoomDocument = makeInterface(panZoomSchema, documentSchema, positionSchema, pageSchema);
export type collectionFreeformViewProps = {
- forceScaling?:boolean; // whether to force scaling of content (needed by ImageBox)
+ forceScaling?: boolean; // whether to force scaling of content (needed by ImageBox)
};
@observer
export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument, undefined as any as collectionFreeformViewProps) {
private _lastX: number = 0;
private _lastY: number = 0;
+ private _downX: number = 0;
+ private _downY: number = 0;
private _inkToTextStartX: number | undefined;
private _inkToTextStartY: number | undefined;
private _wordPalette: Map<string, string> = new Map<string, string>();
@@ -138,7 +141,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument, u
@undoBatch
@action
onInternalDrop = (e: Event, de: DragManager.DropEvent) => {
- if (this.props.Document.isBackground) return false;
+ // if (this.props.Document.isBackground) return false;
const xf = this.getTransform();
const xfo = this.getTransformOverlay();
const [xp, yp] = xf.transformPoint(de.x, de.y);
@@ -164,7 +167,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument, u
const nh = NumCast(layoutDoc._nativeHeight);
layoutDoc._height = nw && nh ? nh / nw * NumCast(layoutDoc._width) : 300;
}
- this.bringToFront(d);
+ d.isBackground === undefined && this.bringToFront(d);
}));
(de.complete.docDragData.droppedDocuments.length === 1 || de.shiftKey) && this.updateClusterDocs(de.complete.docDragData.droppedDocuments);
@@ -322,17 +325,10 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument, u
document.removeEventListener("pointerup", this.onPointerUp);
document.addEventListener("pointermove", this.onPointerMove);
document.addEventListener("pointerup", this.onPointerUp);
- // 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();
- // const 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
if (InkingControl.Instance.selectedTool === InkTool.None) {
- this._lastX = e.pageX;
- this._lastY = e.pageY;
+ this._downX = this._lastX = e.pageX;
+ this._downY = this._lastY = e.pageY;
}
// eraser plus anything else mode
else {
@@ -492,6 +488,8 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument, u
}
}
+ _lastTap = 0;
+
@action
onPointerUp = (e: PointerEvent): void => {
if (InteractionUtils.IsType(e, InteractionUtils.TOUCHTYPE)) return;
@@ -502,6 +500,18 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument, u
this.removeEndListeners();
}
+ onClick = (e: React.MouseEvent) => {
+ if (this.layoutDoc.targetScale && (Math.abs(e.pageX - this._downX) < 3 && Math.abs(e.pageY - this._downY) < 3)) {
+ if (Date.now() - this._lastTap < 300) {
+ const docpt = this.getTransform().transformPoint(e.clientX, e.clientY);
+ this.scaleAtPt(docpt, NumCast(this.layoutDoc.targetScale, NumCast(this.layoutDoc.scale)));
+ e.stopPropagation();
+ e.preventDefault();
+ }
+ this._lastTap = Date.now();
+ }
+ }
+
@action
pan = (e: PointerEvent | React.Touch | { clientX: number, clientY: number }): void => {
// bcz: theres should be a better way of doing these than referencing these static instances directly
@@ -509,31 +519,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument, u
PDFMenu.Instance.fadeOut(true);
const [dx, dy] = this.getTransform().transformDirection(e.clientX - this._lastX, e.clientY - this._lastY);
- let x = (this.Document._panX || 0) - dx;
- let y = (this.Document._panY || 0) - dy;
- if (!this.isAnnotationOverlay) {
- // this section wraps the pan position, horizontally and/or vertically whenever the content is panned out of the viewing bounds
- const docs = this.childLayoutPairs.filter(pair => pair.layout instanceof Doc).map(pair => pair.layout);
- const measuredDocs = docs.filter(doc => doc && this.childDataProvider(doc)).map(doc => this.childDataProvider(doc));
- if (measuredDocs.length) {
- const ranges = measuredDocs.reduce(({ xrange, yrange }, { x, y, width, height }) => // computes range of content
- ({
- xrange: { min: Math.min(xrange.min, x), max: Math.max(xrange.max, x + width) },
- yrange: { min: Math.min(yrange.min, y), max: Math.max(yrange.max, y + height) }
- })
- , {
- xrange: { min: Number.MAX_VALUE, max: -Number.MAX_VALUE },
- yrange: { min: Number.MAX_VALUE, max: -Number.MAX_VALUE }
- });
-
- const panelDim = [this.props.PanelWidth() / this.zoomScaling(), this.props.PanelHeight() / this.zoomScaling()];
- if (ranges.xrange.min > (this.panX() + panelDim[0] / 2)) x = ranges.xrange.max + panelDim[0] / 2; // snaps pan position of range of content goes out of bounds
- if (ranges.xrange.max < (this.panX() - panelDim[0] / 2)) x = ranges.xrange.min - panelDim[0] / 2;
- if (ranges.yrange.min > (this.panY() + panelDim[1] / 2)) y = ranges.yrange.max + panelDim[1] / 2;
- if (ranges.yrange.max < (this.panY() - panelDim[1] / 2)) y = ranges.yrange.min - panelDim[1] / 2;
- }
- }
- this.setPan(x, y);
+ this.setPan((this.Document._panX || 0) - dx, (this.Document._panY || 0) - dy, undefined, true);
this._lastX = e.clientX;
this._lastY = e.clientY;
}
@@ -730,10 +716,33 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument, u
e.stopPropagation();
this.zoom(e.clientX, e.clientY, e.deltaY);
}
+ this.props.Document.targetScale = NumCast(this.props.Document.scale);
}
@action
- setPan(panX: number, panY: number, panType: string = "None") {
+ setPan(panX: number, panY: number, panType: string = "None", clamp: boolean = false) {
+ if (!this.isAnnotationOverlay && clamp) {
+ // this section wraps the pan position, horizontally and/or vertically whenever the content is panned out of the viewing bounds
+ const docs = this.childLayoutPairs.filter(pair => pair.layout instanceof Doc).map(pair => pair.layout);
+ const measuredDocs = docs.filter(doc => doc && this.childDataProvider(doc)).map(doc => this.childDataProvider(doc));
+ if (measuredDocs.length) {
+ const ranges = measuredDocs.reduce(({ xrange, yrange }, { x, y, width, height }) => // computes range of content
+ ({
+ xrange: { min: Math.min(xrange.min, x), max: Math.max(xrange.max, x + width) },
+ yrange: { min: Math.min(yrange.min, y), max: Math.max(yrange.max, y + height) }
+ })
+ , {
+ xrange: { min: Number.MAX_VALUE, max: -Number.MAX_VALUE },
+ yrange: { min: Number.MAX_VALUE, max: -Number.MAX_VALUE }
+ });
+
+ const panelDim = [this.props.PanelWidth() / this.zoomScaling(), this.props.PanelHeight() / this.zoomScaling()];
+ if (ranges.xrange.min >= (panX + panelDim[0] / 2)) panX = ranges.xrange.max + panelDim[0] / 2; // snaps pan position of range of content goes out of bounds
+ else if (ranges.xrange.max <= (panX - panelDim[0] / 2)) panX = ranges.xrange.min - panelDim[0] / 2;
+ if (ranges.yrange.min >= (panY + panelDim[1] / 2)) panY = ranges.yrange.max + panelDim[1] / 2;
+ else if (ranges.yrange.max <= (panY - panelDim[1] / 2)) panY = ranges.yrange.min - panelDim[1] / 2;
+ }
+ }
if (!this.Document.lockedTransform || this.Document.inOverlay) {
this.Document.panTransformType = panType;
const scale = this.getLocalTransform().inverse().Scale;
@@ -759,6 +768,17 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument, u
}
}
+ scaleAtPt(docpt: number[], scale: number) {
+ const screenXY = this.getTransform().inverse().transformPoint(docpt[0], docpt[1]);
+ this.Document.panTransformType = "Ease";
+ this.layoutDoc.scale = scale;
+ const newScreenXY = this.getTransform().inverse().transformPoint(docpt[0], docpt[1]);
+ const scrDelta = { x: screenXY[0] - newScreenXY[0], y: screenXY[1] - newScreenXY[1] };
+ const newpan = this.getTransform().transformDirection(scrDelta.x, scrDelta.y);
+ this.layoutDoc._panX = NumCast(this.layoutDoc._panX) - newpan[0];
+ this.layoutDoc._panY = NumCast(this.layoutDoc._panY) - newpan[1];
+ }
+
focusDocument = (doc: Doc, willZoom: boolean, scale?: number, afterFocus?: () => boolean) => {
const state = HistoryUtil.getState();
@@ -797,12 +817,17 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument, u
const savedState = { px: this.Document._panX, py: this.Document._panY, s: this.Document.scale, pt: this.Document.panTransformType };
- if (DocListCast(this.dataDoc[this.props.fieldKey]).includes(doc)) {
- if (!doc.z) this.setPan(newPanX, newPanY, "Ease"); // docs that are floating in their collection can't be panned to from their collection -- need to propagate the pan to a parent freeform somehow
+ if (!willZoom) {
+ Doc.BrushDoc(this.props.Document);
+ !doc.z && this.scaleAtPt([NumCast(doc.x), NumCast(doc.y)], 1);
+ } else {
+ if (DocListCast(this.dataDoc[this.props.fieldKey]).includes(doc)) {
+ if (!doc.z) this.setPan(newPanX, newPanY, "Ease", true); // docs that are floating in their collection can't be panned to from their collection -- need to propagate the pan to a parent freeform somehow
+ }
+ Doc.BrushDoc(this.props.Document);
+ this.props.focus(this.props.Document);
+ willZoom && this.setScaleToZoom(layoutdoc, scale);
}
- Doc.BrushDoc(this.props.Document);
- this.props.focus(this.props.Document);
- willZoom && this.setScaleToZoom(layoutdoc, scale);
Doc.linkFollowHighlight(doc);
afterFocus && setTimeout(() => {
@@ -812,7 +837,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument, u
this.Document.scale = savedState.s;
this.Document.panTransformType = savedState.pt;
}
- }, 1000);
+ }, 500);
}
}
@@ -836,7 +861,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument, u
LibraryPath: this.libraryPath,
FreezeDimensions: this.props.freezeChildDimensions,
layoutKey: undefined,
- rootSelected: this.rootSelected,
+ rootSelected: childData ? this.rootSelected : returnFalse,
dropAction: StrCast(this.props.Document.childDropAction) as dropActionType,
//onClick: undefined, // this.props.onClick, // bcz: check this out -- I don't think we want to inherit click handlers, or we at least need a way to ignore them
onClick: this.onChildClickHandler,
@@ -1017,47 +1042,6 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument, u
private thumbIdentifier?: number;
- // @action
- // handleHandDown = (e: React.TouchEvent) => {
- // const fingers = InteractionUtils.GetMyTargetTouches(e, this.prevPoints, true);
- // const thumb = fingers.reduce((a, v) => a.clientY > v.clientY ? a : v, fingers[0]);
- // this.thumbIdentifier = thumb?.identifier;
- // const others = fingers.filter(f => f !== thumb);
- // const minX = Math.min(...others.map(f => f.clientX));
- // const minY = Math.min(...others.map(f => f.clientY));
- // const t = this.getTransform().transformPoint(minX, minY);
- // const th = this.getTransform().transformPoint(thumb.clientX, thumb.clientY);
-
- // const thumbDoc = FieldValue(Cast(CurrentUserUtils.setupThumbDoc(CurrentUserUtils.UserDocument), Doc));
- // if (thumbDoc) {
- // this._palette = <Palette x={t[0]} y={t[1]} thumb={th} thumbDoc={thumbDoc} />;
- // }
-
- // document.removeEventListener("touchmove", this.onTouch);
- // document.removeEventListener("touchmove", this.handleHandMove);
- // document.addEventListener("touchmove", this.handleHandMove);
- // document.removeEventListener("touchend", this.handleHandUp);
- // document.addEventListener("touchend", this.handleHandUp);
- // }
-
- // @action
- // handleHandMove = (e: TouchEvent) => {
- // for (let i = 0; i < e.changedTouches.length; i++) {
- // const pt = e.changedTouches.item(i);
- // if (pt?.identifier === this.thumbIdentifier) {
- // }
- // }
- // }
-
- // @action
- // handleHandUp = (e: TouchEvent) => {
- // this.onTouchEnd(e);
- // if (this.prevPoints.size < 3) {
- // this._palette = undefined;
- // document.removeEventListener("touchend", this.handleHandUp);
- // }
- // }
-
onContextMenu = (e: React.MouseEvent) => {
if (this.props.children && this.props.annotationsKey) return;
const layoutItems: ContextMenuProps[] = [];
@@ -1119,8 +1103,20 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument, u
<span className="collectionfreeformview-placeholderSpan">{this.props.Document.title?.toString()}</span>
</div>;
}
+
+ _nudgeTime = 0;
+ nudge = action((x: number, y: number) => {
+ if (this.props.ContainingCollectionDoc?._viewType !== CollectionViewType.Freeform) { // bcz: this isn't ideal, but want to try it out...
+ this.setPan(NumCast(this.layoutDoc._panX) + this.props.PanelWidth() / 2 * x / this.zoomScaling(),
+ NumCast(this.layoutDoc._panY) + this.props.PanelHeight() / 2 * (-y) / this.zoomScaling(), "Ease", true);
+ this._nudgeTime = Date.now();
+ setTimeout(() => (Date.now() - this._nudgeTime >= 500) && (this.Document.panTransformType = undefined), 500);
+ return true;
+ }
+ return false;
+ });
@computed get marqueeView() {
- return <MarqueeView {...this.props} activeDocuments={this.getActiveDocuments} selectDocuments={this.selectDocuments} addDocument={this.addDocument}
+ return <MarqueeView {...this.props} nudge={this.nudge} activeDocuments={this.getActiveDocuments} selectDocuments={this.selectDocuments} addDocument={this.addDocument}
addLiveTextDocument={this.addLiveTextBox} getContainerTransform={this.getContainerTransform} getTransform={this.getTransform} isAnnotationOverlay={this.isAnnotationOverlay}>
<CollectionFreeFormViewPannableContents centeringShiftX={this.centeringShiftX} centeringShiftY={this.centeringShiftY}
easing={this.easing} zoomScaling={this.zoomScaling} panX={this.panX} panY={this.panY}>
@@ -1149,7 +1145,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument, u
// otherwise, they are stored in fieldKey. All annotations to this document are stored in the extension document
return <div className={"collectionfreeformview-container"}
ref={this.createDashEventsTarget}
- onWheel={this.onPointerWheel}//pointerEvents: SelectionManager.GetIsDragging() ? "all" : undefined,
+ onWheel={this.onPointerWheel} onClick={this.onClick} //pointerEvents: SelectionManager.GetIsDragging() ? "all" : undefined,
onPointerDown={this.onPointerDown} onPointerMove={this.onCursorMove} onDrop={this.onExternalDrop.bind(this)} onContextMenu={this.onContextMenu}
style={{
pointerEvents: SelectionManager.GetIsDragging() ? "all" : undefined,
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index 503df10c2..454c3a5f2 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -31,6 +31,7 @@ interface MarqueeViewProps {
addLiveTextDocument: (doc: Doc) => void;
isSelected: () => boolean;
isAnnotationOverlay?: boolean;
+ nudge: (x: number, y: number) => boolean;
setPreviewCursor?: (func: (x: number, y: number, drag: boolean) => void) => void;
}
@@ -46,7 +47,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
_commandExecuted = false;
componentDidMount() {
- this.props.setPreviewCursor && this.props.setPreviewCursor(this.setPreviewCursor);
+ this.props.setPreviewCursor?.(this.setPreviewCursor);
}
@action
@@ -243,15 +244,16 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
} else {
this._downX = x;
this._downY = y;
- PreviewCursor.Show(x, y, this.onKeyPress, this.props.addLiveTextDocument, this.props.getTransform, this.props.addDocument);
+ PreviewCursor.Show(x, y, this.onKeyPress, this.props.addLiveTextDocument, this.props.getTransform, this.props.addDocument, this.props.nudge);
}
});
@action
onClick = (e: React.MouseEvent): void => {
- if (Math.abs(e.clientX - this._downX) < Utils.DRAG_THRESHOLD &&
+ if (
+ Math.abs(e.clientX - this._downX) < Utils.DRAG_THRESHOLD &&
Math.abs(e.clientY - this._downY) < Utils.DRAG_THRESHOLD) {
- this.setPreviewCursor(e.clientX, e.clientY, false);
+ !(e.nativeEvent as any).formattedHandled && this.setPreviewCursor(e.clientX, e.clientY, false);
// let the DocumentView stopPropagation of this event when it selects this document
} else { // why do we get a click event when the cursor have moved a big distance?
// let's cut it off here so no one else has to deal with it.
@@ -307,7 +309,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
this.hideMarquee();
}
- getCollection = (selected: Doc[], asTemplate: boolean, isBackground: boolean = false) => {
+ getCollection = (selected: Doc[], asTemplate: boolean, isBackground?: boolean) => {
const bounds = this.Bounds;
// const inkData = this.ink ? this.ink.inkData : undefined;
const creator = asTemplate ? Docs.Create.StackingDocument : Docs.Create.FreeformDocument;
@@ -585,13 +587,19 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
* This contains the "C for collection, ..." text on marquees.
* Commented out by syip2 when the marquee menu was added.
*/
- return <div className="marquee" style={{ transform: `translate(${p[0]}px, ${p[1]}px)`, width: `${Math.abs(v[0])}`, height: `${Math.abs(v[1])}`, zIndex: 2000 }} >
+ return <div className="marquee" style={{
+ transform: `translate(${p[0]}px, ${p[1]}px)`,
+ width: `${Math.abs(v[0])}`,
+ height: `${Math.abs(v[1])}`, zIndex: 2000
+ }} >
{/* <span className="marquee-legend" /> */}
</div>;
}
render() {
- return <div className="marqueeView" onScroll={(e) => e.currentTarget.scrollTop = e.currentTarget.scrollLeft = 0} onClick={this.onClick} onPointerDown={this.onPointerDown}>
+ return <div className="marqueeView"
+ style={{ overflow: StrCast(this.props.Document.overflow), }}
+ onScroll={(e) => e.currentTarget.scrollTop = e.currentTarget.scrollLeft = 0} onClick={this.onClick} onPointerDown={this.onPointerDown}>
{this._visible ? this.marqueeDiv : null}
{this.props.children}
</div>;