aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
diff options
context:
space:
mode:
authorBob Zeleznik <zzzman@gmail.com>2019-03-31 17:58:11 -0400
committerBob Zeleznik <zzzman@gmail.com>2019-03-31 17:58:11 -0400
commiteb220da697e2383b1e368dee743613158994746e (patch)
tree32df869f251fa9d54eaca1be05358d7570150a25 /src/client/views/collections/collectionFreeForm/MarqueeView.tsx
parent0ae1eac2e2b26c0eee747c81ea1478118b4ec874 (diff)
restructured marquee and preview cursor to not need reactions. fixed some inking bugs.
Diffstat (limited to 'src/client/views/collections/collectionFreeForm/MarqueeView.tsx')
-rw-r--r--src/client/views/collections/collectionFreeForm/MarqueeView.tsx169
1 files changed, 97 insertions, 72 deletions
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