aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/client/views/InkingCanvas.tsx25
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx1
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss1
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx199
-rw-r--r--src/client/views/collections/collectionFreeForm/MarqueeView.scss6
-rw-r--r--src/client/views/collections/collectionFreeForm/MarqueeView.tsx169
-rw-r--r--src/client/views/collections/collectionFreeForm/PreviewCursor.scss7
-rw-r--r--src/client/views/collections/collectionFreeForm/PreviewCursor.tsx71
8 files changed, 245 insertions, 234 deletions
diff --git a/src/client/views/InkingCanvas.tsx b/src/client/views/InkingCanvas.tsx
index 36a8834a0..8fb74ec48 100644
--- a/src/client/views/InkingCanvas.tsx
+++ b/src/client/views/InkingCanvas.tsx
@@ -1,16 +1,15 @@
-import { observer } from "mobx-react";
-import { observable } from "mobx";
import { action, computed } from "mobx";
-import { InkingControl } from "./InkingControl";
-import React = require("react");
-import { Transform } from "../util/Transform";
+import { observer } from "mobx-react";
import { Document } from "../../fields/Document";
-import { KeyStore } from "../../fields/KeyStore";
+import { FieldWaiting } from "../../fields/Field";
import { InkField, InkTool, StrokeData, StrokeMap } from "../../fields/InkField";
-import { InkingStroke } from "./InkingStroke";
-import "./InkingCanvas.scss"
+import { KeyStore } from "../../fields/KeyStore";
import { Utils } from "../../Utils";
-import { FieldWaiting } from "../../fields/Field";
+import { Transform } from "../util/Transform";
+import "./InkingCanvas.scss";
+import { InkingControl } from "./InkingControl";
+import { InkingStroke } from "./InkingStroke";
+import React = require("react");
interface InkCanvasProps {
getScreenTransform: () => Transform;
@@ -71,8 +70,7 @@ export class InkingCanvas extends React.Component<InkCanvasProps> {
// start the new line, saves a uuid to represent the field of the stroke
this._idGenerator = Utils.GenerateGuid();
- let data = this.inkData;
- data.set(this._idGenerator,
+ this.inkData.set(this._idGenerator,
{
pathData: [point],
color: InkingControl.Instance.selectedColor,
@@ -80,7 +78,6 @@ export class InkingCanvas extends React.Component<InkCanvasProps> {
tool: InkingControl.Instance.selectedTool,
page: this.props.Document.GetNumber(KeyStore.CurPage, -1)
});
- this.inkData = data;
this._isDrawing = true;
}
@@ -163,9 +160,7 @@ export class InkingCanvas extends React.Component<InkCanvasProps> {
})
return (
-
- <div className="inking-canvas" style={canvasStyle}
- onPointerDown={this.handleMouseDown} onPointerMove={this.handleMouseMove} >
+ <div className="inking-canvas" style={canvasStyle} onPointerDown={this.handleMouseDown} onPointerMove={this.handleMouseMove} >
<svg>
{paths}
</svg>
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx
index f793b3a49..ea392eaea 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx
@@ -96,6 +96,7 @@ export class CollectionFreeFormLinksView extends React.Component<CollectionViewP
return (
<svg className="collectionfreeformlinksview-svgCanvas">
{this.uniqueConnections.map(c => <CollectionFreeFormLinkView key={Utils.GenerateGuid()} A={c.a} B={c.b} LinkDocs={c.l} />)}
+ {this.props.children}
</svg>);
}
} \ No newline at end of file
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss
index 215a75243..c979b27a9 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss
@@ -6,6 +6,7 @@
left: 0;
width: 100%;
height: 100%;
+ transform-origin: left top;
.inking-canvas {
transform-origin: 50000px 50000px;
}
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 1f90b0d46..cdc5bdfb0 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -3,7 +3,6 @@ import { observer } from "mobx-react";
import { Document } from "../../../../fields/Document";
import { FieldWaiting } from "../../../../fields/Field";
import { KeyStore } from "../../../../fields/KeyStore";
-import { ListField } from "../../../../fields/ListField";
import { TextField } from "../../../../fields/TextField";
import { DragManager } from "../../../util/DragManager";
import { Transform } from "../../../util/Transform";
@@ -14,10 +13,9 @@ import { DocumentContentsView } from "../../nodes/DocumentContentsView";
import { DocumentViewProps } from "../../nodes/DocumentView";
import { COLLECTION_BORDER_WIDTH } from "../CollectionView";
import { CollectionViewBase } from "../CollectionViewBase";
-import { MarqueeView } from "./MarqueeView";
-import { PreviewCursor } from "./PreviewCursor";
import { CollectionFreeFormLinksView } from "./CollectionFreeFormLinksView";
import "./CollectionFreeFormView.scss";
+import { MarqueeView } from "./MarqueeView";
import React = require("react");
import v5 = require("uuid/v5");
@@ -27,12 +25,15 @@ export class CollectionFreeFormView extends CollectionViewBase {
private _selectOnLoaded: string = ""; // id of document that should be selected once it's loaded (used for click-to-type)
public addLiveTextBox = (newBox: Document) => {
- // mark this collection so that when the text box is created we can send it the SelectOnLoad prop to focus itself
+ // mark this collection so that when the text box is created we can send it the SelectOnLoad prop to focus itself and receive text input
this._selectOnLoaded = newBox.Id;
- //set text to be the typed key and get focus on text box
- this.props.addDocument(newBox, false);
- //remove cursor from screen
- this.PreviewCursorVisible = false;
+ this.addDocument(newBox, false);
+ }
+
+ public addDocument = (newBox: Document, allowDuplicates: boolean) => {
+ let added = this.props.addDocument(newBox, false);
+ this.bringToFront(newBox);
+ return added;
}
public selectDocuments = (docs: Document[]) => {
@@ -42,23 +43,15 @@ export class CollectionFreeFormView extends CollectionViewBase {
public getActiveDocuments = () => {
var curPage = this.props.Document.GetNumber(KeyStore.CurPage, -1);
- const lvalue = this.props.Document.GetT<ListField<Document>>(this.props.fieldKey, ListField);
- let active: Document[] = [];
- if (lvalue && lvalue != FieldWaiting) {
- lvalue.Data.map(doc => {
- var page = doc.GetNumber(KeyStore.Page, -1);
- if (page == curPage || page == -1) {
- active.push(doc);
- }
- })
- }
-
- return active;
+ return this.props.Document.GetList(this.props.fieldKey, [] as Document[]).reduce((active, doc) => {
+ var page = doc.GetNumber(KeyStore.Page, -1);
+ if (page == curPage || page == -1) {
+ active.push(doc);
+ }
+ return active;
+ }, [] as Document[]);
}
- //determines whether the blinking cursor for indicating whether a text will be made on key down is visible
- @observable public PreviewCursorVisible: boolean = false;
- @observable public MarqueeVisible = false;
@observable public DownX: number = 0;
@observable public DownY: number = 0;
@observable private _lastX: number = 0;
@@ -100,12 +93,10 @@ export class CollectionFreeFormView extends CollectionViewBase {
cleanupInteractions = () => {
document.removeEventListener("pointermove", this.onPointerMove);
document.removeEventListener("pointerup", this.onPointerUp);
- this.MarqueeVisible = false;
}
@action
onPointerDown = (e: React.PointerEvent): void => {
- this.PreviewCursorVisible = false;
if ((e.button === 2 && this.props.active() && (!this.isAnnotationOverlay || this.zoomScaling != 1)) || e.button == 0) {
document.removeEventListener("pointermove", this.onPointerMove);
document.addEventListener("pointermove", this.onPointerMove);
@@ -120,28 +111,13 @@ export class CollectionFreeFormView extends CollectionViewBase {
onPointerUp = (e: PointerEvent): void => {
e.stopPropagation();
- if (Math.abs(this.DownX - e.clientX) < 4 && Math.abs(this.DownY - e.clientY) < 4) {
- //show preview text cursor on tap
- this.PreviewCursorVisible = true;
- //select is not already selected
- if (!this.props.isSelected()) {
- this.props.select(false);
- }
- }
this.cleanupInteractions();
}
@action
onPointerMove = (e: PointerEvent): void => {
if (!e.cancelBubble && this.props.active()) {
- if (e.buttons == 1 && !e.altKey && !e.metaKey) {
- this.MarqueeVisible = true;
- }
- if (this.MarqueeVisible) {
- e.stopPropagation();
- e.preventDefault();
- }
- else if ((!this.isAnnotationOverlay || this.zoomScaling != 1) && !e.shiftKey) {
+ if ((!this.isAnnotationOverlay || this.zoomScaling != 1) && !e.shiftKey) {
let x = this.props.Document.GetNumber(KeyStore.PanX, 0);
let y = this.props.Document.GetNumber(KeyStore.PanY, 0);
let [dx, dy] = this.getTransform().transformDirection(e.clientX - this._lastX, e.clientY - this._lastY);
@@ -264,16 +240,12 @@ export class CollectionFreeFormView extends CollectionViewBase {
@computed
get views() {
var curPage = this.props.Document.GetNumber(KeyStore.CurPage, -1);
- const lvalue = this.props.Document.GetT<ListField<Document>>(this.props.fieldKey, ListField);
- if (lvalue && lvalue != FieldWaiting) {
- return lvalue.Data.map(doc => {
- if (!doc) return null;
- var page = doc.GetNumber(KeyStore.Page, 0);
- return (page != curPage && page != 0) ? (null) :
- (<CollectionFreeFormDocumentView key={doc.Id} {...this.getDocumentViewProps(doc)} />);
- })
- }
- return null;
+ return this.props.Document.GetList(this.props.fieldKey, [] as Document[]).filter(doc => doc).reduce((prev, doc) => {
+ var page = doc.GetNumber(KeyStore.Page, -1);
+ if (page == curPage || page == -1)
+ prev.push(<CollectionFreeFormDocumentView key={doc.Id} {...this.getDocumentViewProps(doc)} />);
+ return prev;
+ }, [] as JSX.Element[])
}
@computed
@@ -290,15 +262,10 @@ export class CollectionFreeFormView extends CollectionViewBase {
}
getTransform = (): Transform => this.props.ScreenToLocalTransform().translate(-COLLECTION_BORDER_WIDTH, -COLLECTION_BORDER_WIDTH).translate(-this.centeringShiftX, -this.centeringShiftY).transform(this.getLocalTransform())
- getMarqueeTransform = (): Transform => this.props.ScreenToLocalTransform().translate(-COLLECTION_BORDER_WIDTH, -COLLECTION_BORDER_WIDTH)
+ getContainerTransform = (): Transform => this.props.ScreenToLocalTransform().translate(-COLLECTION_BORDER_WIDTH, -COLLECTION_BORDER_WIDTH)
getLocalTransform = (): Transform => Transform.Identity.scale(1 / this.scale).translate(this.panX, this.panY);
noScaling = () => 1;
- //when focus is lost, this will remove the preview cursor
- @action
- onBlur = (): void => {
- this.PreviewCursorVisible = false;
- }
private crosshairs?: HTMLCanvasElement;
drawCrosshairs = (backgroundColor: string) => {
@@ -345,71 +312,63 @@ export class CollectionFreeFormView extends CollectionViewBase {
return (
<div className={`collectionfreeformview${this.isAnnotationOverlay ? "-overlay" : "-container"}`}
- onPointerDown={this.onPointerDown}
- onPointerMove={(e) => super.setCursorPosition(this.getTransform().transformPoint(e.clientX, e.clientY))}
- onWheel={this.onPointerWheel}
- onDrop={this.onDrop.bind(this)}
- onDragOver={this.onDragOver}
- onBlur={this.onBlur}
- style={{ borderWidth: `${COLLECTION_BORDER_WIDTH}px` }}// , zIndex: !this.props.isTopMost ? -1 : undefined }}
- tabIndex={0}
- ref={this.createDropTarget}>
- <div className="collectionfreeformview"
- style={{ transformOrigin: "left top", transform: `translate(${dx}px, ${dy}px) scale(${this.zoomScaling}, ${this.zoomScaling}) translate(${panx}px, ${pany}px)` }}
- ref={this._canvasRef}>
- {this.backgroundView}
- <InkingCanvas getScreenTransform={this.getTransform} Document={this.props.Document} />
- <PreviewCursor container={this} addLiveTextDocument={this.addLiveTextBox} getTransform={this.getTransform} />
- {this.views}
- <CollectionFreeFormLinksView {...this.props} />
- {super.getCursors().map(entry => {
- if (entry.Data.length > 0) {
- let id = entry.Data[0][0];
- let email = entry.Data[0][1];
- let point = entry.Data[1];
- this.drawCrosshairs("#" + v5(id, v5.URL).substring(0, 6).toUpperCase() + "22")
- return (
- <div
- key={id}
- style={{
- position: "absolute",
- transform: `translate(${point[0] - 10}px, ${point[1] - 10}px)`,
- zIndex: 10000,
- transformOrigin: 'center center',
- }}
- >
- <canvas
- ref={(el) => { if (el) this.crosshairs = el }}
- width={20}
- height={20}
- style={{
- position: 'absolute',
- width: "20px",
- height: "20px",
- opacity: 0.5,
- borderRadius: "50%",
- border: "2px solid black"
- }}
- />
- <p
+ onPointerDown={this.onPointerDown} onPointerMove={(e) => super.setCursorPosition(this.getTransform().transformPoint(e.clientX, e.clientY))}
+ onDrop={this.onDrop.bind(this)} onDragOver={this.onDragOver} onWheel={this.onPointerWheel}
+ style={{ borderWidth: `${COLLECTION_BORDER_WIDTH}px` }} tabIndex={0} ref={this.createDropTarget}>
+ <MarqueeView container={this} activeDocuments={this.getActiveDocuments} selectDocuments={this.selectDocuments}
+ addDocument={this.addDocument} removeDocument={this.props.removeDocument} addLiveTextDocument={this.addLiveTextBox}
+ getContainerTransform={this.getContainerTransform} getTransform={this.getTransform}>
+ <div className="collectionfreeformview" ref={this._canvasRef}
+ style={{ transform: `translate(${dx}px, ${dy}px) scale(${this.zoomScaling}, ${this.zoomScaling}) translate(${panx}px, ${pany}px)` }}>
+ {this.backgroundView}
+ <CollectionFreeFormLinksView {...this.props} />
+ {this.views}
+ <InkingCanvas getScreenTransform={this.getTransform} Document={this.props.Document} />
+ {super.getCursors().map(entry => {
+ if (entry.Data.length > 0) {
+ let id = entry.Data[0][0];
+ let email = entry.Data[0][1];
+ let point = entry.Data[1];
+ this.drawCrosshairs("#" + v5(id, v5.URL).substring(0, 6).toUpperCase() + "22")
+ return (
+ <div
+ key={id}
style={{
- fontSize: 14,
- color: "black",
- // fontStyle: "italic",
- marginLeft: -12,
- marginTop: 4
+ position: "absolute",
+ transform: `translate(${point[0] - 10}px, ${point[1] - 10}px)`,
+ zIndex: 10000,
+ transformOrigin: 'center center',
}}
- >{email[0].toUpperCase()}</p>
- </div>
- );
- }
- })}
- </div>
- <MarqueeView container={this} activeDocuments={this.getActiveDocuments} selectDocuments={this.selectDocuments}
- addDocument={this.props.addDocument} removeDocument={this.props.removeDocument}
- getMarqueeTransform={this.getMarqueeTransform} getTransform={this.getTransform} />
- {this.overlayView}
-
+ >
+ <canvas
+ ref={(el) => { if (el) this.crosshairs = el }}
+ width={20}
+ height={20}
+ style={{
+ position: 'absolute',
+ width: "20px",
+ height: "20px",
+ opacity: 0.5,
+ borderRadius: "50%",
+ border: "2px solid black"
+ }}
+ />
+ <p
+ style={{
+ fontSize: 14,
+ color: "black",
+ // fontStyle: "italic",
+ marginLeft: -12,
+ marginTop: 4
+ }}
+ >{email[0].toUpperCase()}</p>
+ </div>
+ );
+ }
+ })}
+ </div>
+ {this.overlayView}
+ </MarqueeView>
</div>
);
}
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.scss b/src/client/views/collections/collectionFreeForm/MarqueeView.scss
index 6d9a79344..1ee3b244b 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.scss
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.scss
@@ -1,8 +1,14 @@
.marqueeView {
+ position: absolute;
+ width:100%;
+ height:100%;
+}
+.marquee {
border-style: dashed;
box-sizing: border-box;
position: absolute;
border-width: 1px;
border-color: black;
+ pointer-events: none;
} \ No newline at end of file
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index 2692690dd..2b0e7d228 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -1,62 +1,58 @@
-import { action, IReactionDisposer, observable, reaction } from "mobx";
+import { action, computed, observable } from "mobx";
import { observer } from "mobx-react";
import { Document } from "../../../../fields/Document";
-import { FieldWaiting, Opt } from "../../../../fields/Field";
+import { FieldWaiting } from "../../../../fields/Field";
+import { InkField, StrokeData } from "../../../../fields/InkField";
import { KeyStore } from "../../../../fields/KeyStore";
import { Documents } from "../../../documents/Documents";
import { SelectionManager } from "../../../util/SelectionManager";
import { Transform } from "../../../util/Transform";
+import { InkingCanvas } from "../../InkingCanvas";
import { CollectionFreeFormView } from "./CollectionFreeFormView";
import "./MarqueeView.scss";
+import { PreviewCursor } from "./PreviewCursor";
import React = require("react");
-import { InkField, StrokeData } from "../../../../fields/InkField";
-import { Utils } from "../../../../Utils";
-import { InkingCanvas } from "../../InkingCanvas";
interface MarqueeViewProps {
- getMarqueeTransform: () => Transform;
+ getContainerTransform: () => Transform;
getTransform: () => Transform;
container: CollectionFreeFormView;
addDocument: (doc: Document, allowDuplicates: false) => boolean;
activeDocuments: () => Document[];
selectDocuments: (docs: Document[]) => void;
removeDocument: (doc: Document) => boolean;
+ addLiveTextDocument: (doc: Document) => void;
}
@observer
export class MarqueeView extends React.Component<MarqueeViewProps>
{
- private _reactionDisposer: Opt<IReactionDisposer>;
-
@observable _lastX: number = 0;
@observable _lastY: number = 0;
@observable _downX: number = 0;
@observable _downY: number = 0;
-
- componentDidMount() {
- this._reactionDisposer = reaction(
- () => this.props.container.MarqueeVisible,
- (visible: boolean) => this.onPointerDown(visible, this.props.container.DownX, this.props.container.DownY))
- }
- componentWillUnmount() {
- if (this._reactionDisposer) {
- this._reactionDisposer();
- }
- this.cleanupInteractions();
- }
+ @observable _used: boolean = false;
+ @observable _visible: boolean = false;
+ static DRAG_THRESHOLD = 4;
@action
- cleanupInteractions = () => {
- document.removeEventListener("pointermove", this.onPointerMove, true)
- document.removeEventListener("pointerup", this.onPointerUp, true);
+ cleanupInteractions = (all: boolean = false) => {
+ if (all) {
+ document.removeEventListener("pointermove", this.onPointerMove, true)
+ document.removeEventListener("pointerup", this.onPointerUp, true);
+ } else {
+ this._used = true;
+ }
document.removeEventListener("keydown", this.marqueeCommand, true);
+ this._visible = false;
}
@action
- onPointerDown = (visible: boolean, downX: number, downY: number): void => {
- if (visible) {
- this._downX = this._lastX = downX;
- this._downY = this._lastY = downY;
+ onPointerDown = (e: React.PointerEvent): void => {
+ if (e.buttons == 1 && !e.altKey && !e.metaKey && this.props.container.props.active()) {
+ this._downX = this._lastX = e.pageX;
+ this._downY = this._lastY = e.pageY;
+ this._used = false;
document.addEventListener("pointermove", this.onPointerMove, true)
document.addEventListener("pointerup", this.onPointerUp, true);
document.addEventListener("keydown", this.marqueeCommand, true);
@@ -67,11 +63,20 @@ export class MarqueeView extends React.Component<MarqueeViewProps>
onPointerMove = (e: PointerEvent): void => {
this._lastX = e.pageX;
this._lastY = e.pageY;
+ if (!e.cancelBubble) {
+ if (!this._used && e.buttons == 1 && !e.altKey && !e.metaKey &&
+ (Math.abs(this._lastX - this._downX) > MarqueeView.DRAG_THRESHOLD || Math.abs(this._lastY - this._downY) > MarqueeView.DRAG_THRESHOLD)) {
+ this._visible = true;
+ }
+ e.stopPropagation();
+ e.preventDefault();
+ }
}
@action
onPointerUp = (e: PointerEvent): void => {
- this.cleanupInteractions();
+ this.cleanupInteractions(true);
+ this._visible = false;
if (!e.shiftKey) {
SelectionManager.DeselectAll();
}
@@ -83,6 +88,7 @@ export class MarqueeView extends React.Component<MarqueeViewProps>
return !(r2.left > r1.left + r1.width || r2.left + r2.width < r1.left || r2.top > r1.top + r1.height || r2.top + r2.height < r1.top);
}
+ @computed
get Bounds() {
let left = this._downX < this._lastX ? this._downX : this._lastX;
let top = this._downY < this._lastY ? this._downY : this._lastY;
@@ -95,7 +101,10 @@ export class MarqueeView extends React.Component<MarqueeViewProps>
marqueeCommand = (e: KeyboardEvent) => {
if (e.key == "Backspace" || e.key == "Delete") {
this.marqueeSelect().map(d => this.props.removeDocument(d));
- this.props.container.props.Document.SetData(KeyStore.Ink, this.marqueeInkSelect(false), InkField);
+ let ink = this.props.container.props.Document.GetT(KeyStore.Ink, InkField);
+ if (ink && ink != FieldWaiting && ink.Data) {
+ this.marqueeInkDelete(ink.Data);
+ }
this.cleanupInteractions();
}
if (e.key == "c") {
@@ -104,53 +113,61 @@ export class MarqueeView extends React.Component<MarqueeViewProps>
this.props.removeDocument(d);
d.SetNumber(KeyStore.X, d.GetNumber(KeyStore.X, 0) - bounds.left - bounds.width / 2);
d.SetNumber(KeyStore.Y, d.GetNumber(KeyStore.Y, 0) - bounds.top - bounds.height / 2);
- d.SetNumber(KeyStore.Page, 0);
+ d.SetNumber(KeyStore.Page, -1);
d.SetText(KeyStore.Title, "" + d.GetNumber(KeyStore.Width, 0) + " " + d.GetNumber(KeyStore.Height, 0));
return d;
});
- let liftedInk = this.marqueeInkSelect(true);
- this.props.container.props.Document.SetData(KeyStore.Ink, this.marqueeInkSelect(false), InkField);
- //setTimeout(() => {
- let newCollection = Documents.FreeformDocument(selected, {
- x: bounds.left,
- y: bounds.top,
- panx: 0,
- pany: 0,
- width: bounds.width,
- height: bounds.height,
- backgroundColor: "Transparent",
- ink: liftedInk,
- title: "a nested collection"
- });
- this.props.addDocument(newCollection, false);
+ let ink = this.props.container.props.Document.GetT(KeyStore.Ink, InkField);
+ if (ink && ink != FieldWaiting && ink.Data) {
+ //setTimeout(() => {
+ let newCollection = Documents.FreeformDocument(selected, {
+ x: bounds.left,
+ y: bounds.top,
+ panx: 0,
+ pany: 0,
+ width: bounds.width,
+ height: bounds.height,
+ backgroundColor: "Transparent",
+ ink: this.marqueeInkSelect(ink.Data),
+ title: "a nested collection"
+ });
+ this.props.addDocument(newCollection, false);
+ this.marqueeInkDelete(ink.Data);
+ }
// }, 100);
this.cleanupInteractions();
}
}
- marqueeInkSelect(select: boolean) {
- let selRect = this.Bounds;
- let centerShiftX = 0 - (selRect.left + selRect.width / 2); // moves each point by the offset that shifts the selection's center to the origin.
- let centerShiftY = 0 - (selRect.top + selRect.height / 2);
- let ink = this.props.container.props.Document.GetT(KeyStore.Ink, InkField);
- if (ink && ink != FieldWaiting && ink.Data) {
- let idata = new Map();
- ink.Data.forEach((value: StrokeData, key: string, map: any) => {
- let inside = InkingCanvas.IntersectStrokeRect(value, selRect);
- if (inside && select) {
- idata.set(key,
- {
- pathData: value.pathData.map(val => { return { x: val.x + centerShiftX, y: val.y + centerShiftY } }),
- color: value.color,
- width: value.width,
- tool: value.tool,
- page: -1
- });
- } else if (!inside && !select) {
- idata.set(key, value);
- }
- })
- return idata;
- }
+ @action
+ marqueeInkSelect(ink: Map<any, any>) {
+ let idata = new Map();
+ let centerShiftX = 0 - (this.Bounds.left + this.Bounds.width / 2); // moves each point by the offset that shifts the selection's center to the origin.
+ let centerShiftY = 0 - (this.Bounds.top + this.Bounds.height / 2);
+ ink.forEach((value: StrokeData, key: string, map: any) => {
+ if (InkingCanvas.IntersectStrokeRect(value, this.Bounds)) {
+ idata.set(key,
+ {
+ pathData: value.pathData.map(val => { return { x: val.x + centerShiftX, y: val.y + centerShiftY } }),
+ color: value.color,
+ width: value.width,
+ tool: value.tool,
+ page: -1
+ });
+ }
+ });
+ return idata;
+ }
+
+ @action
+ marqueeInkDelete(ink: Map<any, any>, ) {
+ // bcz: this appears to work but when you restart all the deleted strokes come back -- InkField isn't observing its changes so they aren't written to the DB.
+ // ink.forEach((value: StrokeData, key: string, map: any) =>
+ // InkingCanvas.IntersectStrokeRect(value, this.Bounds) && ink.delete(key));
+
+ let idata = new Map();
+ ink.forEach((value: StrokeData, key: string, map: any) =>
+ !InkingCanvas.IntersectStrokeRect(value, this.Bounds) && idata.set(key, value));
+ this.props.container.props.Document.SetDataOnPrototype(KeyStore.Ink, idata, InkField);
}
marqueeSelect() {
@@ -168,8 +185,16 @@ export class MarqueeView extends React.Component<MarqueeViewProps>
}
render() {
- let p = this.props.getMarqueeTransform().transformPoint(this._downX < this._lastX ? this._downX : this._lastX, this._downY < this._lastY ? this._downY : this._lastY);
- let v = this.props.getMarqueeTransform().transformDirection(this._lastX - this._downX, this._lastY - this._downY);
- return (!this.props.container.MarqueeVisible ? (null) : <div className="marqueeView" style={{ transform: `translate(${p[0]}px, ${p[1]}px)`, width: `${Math.abs(v[0])}`, height: `${Math.abs(v[1])}` }} />);
+ let p = this.props.getContainerTransform().transformPoint(this._downX < this._lastX ? this._downX : this._lastX, this._downY < this._lastY ? this._downY : this._lastY);
+ let v = this.props.getContainerTransform().transformDirection(this._lastX - this._downX, this._lastY - this._downY);
+ return <div className="marqueeView" onPointerDown={this.onPointerDown}>
+ <PreviewCursor container={this.props.container} addLiveTextDocument={this.props.addLiveTextDocument}
+ getContainerTransform={this.props.getContainerTransform} getTransform={this.props.getTransform} >
+ {this.props.children}
+ {!this._visible ? (null) :
+ <div className="marquee" style={{ transform: `translate(${p[0]}px, ${p[1]}px)`, width: `${Math.abs(v[0])}`, height: `${Math.abs(v[1])}` }} />}
+
+ </PreviewCursor>
+ </div>;
}
} \ No newline at end of file
diff --git a/src/client/views/collections/collectionFreeForm/PreviewCursor.scss b/src/client/views/collections/collectionFreeForm/PreviewCursor.scss
index a797411f6..7d6d5aaab 100644
--- a/src/client/views/collections/collectionFreeForm/PreviewCursor.scss
+++ b/src/client/views/collections/collectionFreeForm/PreviewCursor.scss
@@ -5,6 +5,11 @@
transform-origin: left top;
pointer-events: none;
}
+.previewCursorView {
+ position: absolute;
+ width:100%;
+ height:100%;
+}
//this is an animation for the blinking cursor!
@keyframes blink {
@@ -14,5 +19,5 @@
}
#previewCursor {
- animation: blink 1s infinite;
+ animation: blink 1s infinite;
} \ No newline at end of file
diff --git a/src/client/views/collections/collectionFreeForm/PreviewCursor.tsx b/src/client/views/collections/collectionFreeForm/PreviewCursor.tsx
index 95364f04b..339e056a8 100644
--- a/src/client/views/collections/collectionFreeForm/PreviewCursor.tsx
+++ b/src/client/views/collections/collectionFreeForm/PreviewCursor.tsx
@@ -1,7 +1,6 @@
-import { action, IReactionDisposer, observable, reaction } from "mobx";
+import { action, observable } from "mobx";
import { observer } from "mobx-react";
import { Document } from "../../../../fields/Document";
-import { Opt } from "../../../../fields/Field";
import { Documents } from "../../../documents/Documents";
import { Transform } from "../../../util/Transform";
import { CollectionFreeFormView } from "./CollectionFreeFormView";
@@ -11,43 +10,50 @@ import React = require("react");
export interface PreviewCursorProps {
getTransform: () => Transform;
+ getContainerTransform: () => Transform;
container: CollectionFreeFormView;
addLiveTextDocument: (doc: Document) => void;
}
@observer
export class PreviewCursor extends React.Component<PreviewCursorProps> {
- private _reactionDisposer: Opt<IReactionDisposer>;
-
@observable _lastX: number = 0;
@observable _lastY: number = 0;
+ @observable public _visible: boolean = false;
+ @observable public DownX: number = 0;
+ @observable public DownY: number = 0;
+ _showOnUp: boolean = false;
+ public _previewDivRef = React.createRef<HTMLDivElement>();
- componentDidMount() {
- this._reactionDisposer = reaction(
- () => this.props.container.PreviewCursorVisible,
- (visible: boolean) => this.onCursorPlaced(visible, this.props.container.DownX, this.props.container.DownY))
- }
- componentWillUnmount() {
- if (this._reactionDisposer) {
- this._reactionDisposer();
- }
- this.cleanupInteractions();
+ @action
+ cleanupInteractions = () => {
+ document.removeEventListener("pointerup", this.onPointerUp, true);
}
-
@action
- cleanupInteractions = () => {
+ onPointerDown = (e: React.PointerEvent) => {
+ this._visible = false;
document.removeEventListener("keypress", this.onKeyPress, false);
+ this._showOnUp = true;
+ this._lastX = this.DownX = e.pageX;
+ this._lastY = this.DownY = e.pageY;
+ document.addEventListener("pointerup", this.onPointerUp, true);
+ document.addEventListener("pointermove", this.onPointerMove, true);
+ }
+ @action
+ onPointerMove = (e: PointerEvent): void => {
+ if (Math.abs(this.DownX - e.clientX) > 4 || Math.abs(this.DownY - e.clientY) > 4) {
+ this._showOnUp = false;
+ }
}
@action
- onCursorPlaced = (visible: boolean, downX: number, downY: number): void => {
- if (visible) {
+ onPointerUp = (e: PointerEvent): void => {
+ if (this._showOnUp) {
document.addEventListener("keypress", this.onKeyPress, false);
- this._lastX = downX;
- this._lastY = downY;
- } else
- this.cleanupInteractions();
+ this._visible = true;
+ }
+ this.cleanupInteractions();
}
@action
@@ -61,16 +67,29 @@ export class PreviewCursor extends React.Component<PreviewCursorProps> {
let [x, y] = this.props.getTransform().transformPoint(this._lastX, this._lastY);
let newBox = Documents.TextDocument({ width: 200, height: 100, x: x, y: y, title: "typed text" });
this.props.addLiveTextDocument(newBox);
+ document.removeEventListener("keypress", this.onKeyPress, false);
+ this._visible = false;
e.stopPropagation();
}
}
+ //when focus is lost, this will remove the preview cursor
+ @action
+ onBlur = (): void => {
+ this._visible = false;
+ document.removeEventListener("keypress", this.onKeyPress, false);
+ }
render() {
//get local position and place cursor there!
- let [x, y] = this.props.getTransform().transformPoint(this._lastX, this._lastY);
+ let p = this.props.getContainerTransform().transformPoint(this._lastX, this._lastY);
+ if (this._visible && this._previewDivRef.current)
+ this._previewDivRef.current!.focus();
return (
- !this.props.container.PreviewCursorVisible ? (null) :
- <div className="previewCursor" id="previewCursor" style={{ transform: `translate(${x}px, ${y}px)` }}>I</div>)
-
+ <div className="previewCursorView" tabIndex={0} ref={this._previewDivRef} onBlur={this.onBlur} onPointerDown={this.onPointerDown}>
+ {this.props.children}
+ {!this._visible ? (null) :
+ <div className="previewCursor" id="previewCursor" style={{ transform: `translate(${p[0]}px, ${p[1]}px)` }}>I</div>}
+ </div>
+ )
}
} \ No newline at end of file