aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorbob <bcz@cs.brown.edu>2019-06-17 12:26:57 -0400
committerbob <bcz@cs.brown.edu>2019-06-17 12:26:57 -0400
commitf7a567b27b5c124e8c3bfe1e866162e2911607c5 (patch)
tree0c540ac3c7025f42bec34031fa56ae8c5aeec6e6 /src
parent4d3d9b4c33be1df26144aea16dde060b9263924e (diff)
cleaned up minimization code, added minimization for stacking
Diffstat (limited to 'src')
-rw-r--r--src/client/views/collections/CollectionSchemaView.tsx15
-rw-r--r--src/client/views/collections/CollectionStackingView.tsx21
-rw-r--r--src/client/views/nodes/CollectionFreeFormDocumentView.tsx147
-rw-r--r--src/client/views/nodes/DocumentView.tsx62
4 files changed, 89 insertions, 156 deletions
diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx
index b9e5a5b65..7cc00ce07 100644
--- a/src/client/views/collections/CollectionSchemaView.tsx
+++ b/src/client/views/collections/CollectionSchemaView.tsx
@@ -416,20 +416,6 @@ export class CollectionSchemaPreview extends React.Component<CollectionSchemaPre
onPreviewScriptChange = (e: React.ChangeEvent<HTMLInputElement>) => {
this.props.setPreviewScript(e.currentTarget.value);
}
- @undoBatch
- @action
- public collapseToPoint = (scrpt: number[], expandedDocs: Doc[] | undefined): void => {
- SelectionManager.DeselectAll();
- if (expandedDocs) {
- let isMinimized: boolean | undefined;
- expandedDocs.map(d => Doc.GetProto(d)).map(maximizedDoc => {
- if (isMinimized === undefined) {
- isMinimized = BoolCast(maximizedDoc.isMinimized, false);
- }
- maximizedDoc.isMinimized = !isMinimized;
- });
- }
- }
render() {
let input = this.props.previewScript === undefined ? (null) :
<input className="collectionSchemaView-input" value={this.props.previewScript} onChange={this.onPreviewScriptChange}
@@ -448,7 +434,6 @@ export class CollectionSchemaPreview extends React.Component<CollectionSchemaPre
whenActiveChanged={this.props.whenActiveChanged}
bringToFront={emptyFunction}
addDocTab={this.props.addDocTab}
- collapseToPoint={this.collapseToPoint}
/>
</div>)}
{input}
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index 236bfe136..ef12545b8 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -1,17 +1,15 @@
import React = require("react");
-import { action, computed, IReactionDisposer, reaction, trace } from "mobx";
+import { action, computed, IReactionDisposer, reaction } from "mobx";
import { observer } from "mobx-react";
import { Doc, HeightSym, WidthSym } from "../../../new_fields/Doc";
import { Id } from "../../../new_fields/FieldSymbols";
import { BoolCast, NumCast } from "../../../new_fields/Types";
import { emptyFunction, returnOne, Utils } from "../../../Utils";
-import { SelectionManager } from "../../util/SelectionManager";
-import { undoBatch } from "../../util/UndoManager";
+import { ContextMenu } from "../ContextMenu";
import { DocumentView } from "../nodes/DocumentView";
import { CollectionSchemaPreview } from "./CollectionSchemaView";
import "./CollectionStackingView.scss";
import { CollectionSubView } from "./CollectionSubView";
-import { ContextMenu } from "../ContextMenu";
@observer
export class CollectionStackingView extends CollectionSubView(doc => doc) {
@@ -62,20 +60,6 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
this._masonryGridRef = ele;
this.createDropTarget(ele!);
}
- @undoBatch
- @action
- public collapseToPoint = (scrpt: number[], expandedDocs: Doc[] | undefined): void => {
- SelectionManager.DeselectAll();
- if (expandedDocs) {
- let isMinimized: boolean | undefined;
- expandedDocs.map(d => Doc.GetProto(d)).map(maximizedDoc => {
- if (isMinimized === undefined) {
- isMinimized = BoolCast(maximizedDoc.isMinimized, false);
- }
- maximizedDoc.isMinimized = !isMinimized;
- });
- }
- }
@computed
get singleColumnChildren() {
@@ -144,7 +128,6 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
addDocTab={this.props.addDocTab}
bringToFront={emptyFunction}
whenActiveChanged={this.props.whenActiveChanged}
- collapseToPoint={this.collapseToPoint}
/>
</div>);
})
diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
index 499b83c0f..f6b1c62ee 100644
--- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
+++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
@@ -1,17 +1,12 @@
-import { computed, IReactionDisposer, reaction, action } from "mobx";
+import { computed } from "mobx";
import { observer } from "mobx-react";
-import { Doc } from "../../../new_fields/Doc";
-import { List } from "../../../new_fields/List";
-import { createSchema, listSpec, makeInterface } from "../../../new_fields/Schema";
-import { BoolCast, Cast, FieldValue, NumCast } from "../../../new_fields/Types";
-import { OmitKeys } from "../../../Utils";
+import { createSchema, makeInterface } from "../../../new_fields/Schema";
+import { BoolCast, FieldValue, NumCast } from "../../../new_fields/Types";
import { Transform } from "../../util/Transform";
import { DocComponent } from "../DocComponent";
import { DocumentView, DocumentViewProps, positionSchema } from "./DocumentView";
import "./DocumentView.scss";
import React = require("react");
-import { UndoManager } from "../../util/UndoManager";
-import { SelectionManager } from "../../util/SelectionManager";
export interface CollectionFreeFormDocumentViewProps extends DocumentViewProps {
}
@@ -27,13 +22,7 @@ const FreeformDocument = makeInterface(schema, positionSchema);
@observer
export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeFormDocumentViewProps, FreeformDocument>(FreeformDocument) {
- private _mainCont = React.createRef<HTMLDivElement>();
- _bringToFrontDisposer?: IReactionDisposer;
-
- @computed get transform() {
- return `scale(${this.props.ContentScaling()}, ${this.props.ContentScaling()}) translate(${this.X}px, ${this.Y}px) scale(${this.zoom}, ${this.zoom}) `;
- }
-
+ @computed get transform() { return `scale(${this.props.ContentScaling()}) translate(${this.X}px, ${this.Y}px) scale(${this.zoom}) `; }
@computed get X() { return FieldValue(this.Document.x, 0); }
@computed get Y() { return FieldValue(this.Document.y, 0); }
@computed get zoom(): number { return 1 / FieldValue(this.Document.zoomBasis, 1); }
@@ -59,91 +48,20 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
panelHeight = () => this.props.PanelHeight();
getTransform = (): Transform => this.props.ScreenToLocalTransform()
.translate(-this.X, -this.Y)
- .scale(1 / this.contentScaling()).scale(1 / this.zoom)
-
- @computed
- get docView() {
- return <DocumentView {...OmitKeys(this.props, ['zoomFade']).omit}
- ContentScaling={this.contentScaling}
- ScreenToLocalTransform={this.getTransform}
- PanelWidth={this.panelWidth}
- PanelHeight={this.panelHeight}
- collapseToPoint={this.collapseToPoint}
- />;
- }
-
- componentDidMount() {
- this._bringToFrontDisposer = reaction(() => this.props.Document.isIconAnimating, (values) => {
- this.props.bringToFront(this.props.Document);
- if (values instanceof List) {
- let scrpt = this.props.ScreenToLocalTransform().transformPoint(values[0], values[1]);
- this.animateBetweenIcon(true, scrpt, [this.Document.x || 0, this.Document.y || 0],
- this.Document.width || 0, this.Document.height || 0, values[2], values[3] ? true : false);
- }
- }, { fireImmediately: true });
- }
-
- componentWillUnmount() {
- if (this._bringToFrontDisposer) this._bringToFrontDisposer();
- }
-
- static _undoBatch?: UndoManager.Batch = undefined;
- @action
- public collapseToPoint = async (scrpt: number[], expandedDocs: Doc[] | undefined): Promise<void> => {
- SelectionManager.DeselectAll();
- if (expandedDocs) {
- if (!CollectionFreeFormDocumentView._undoBatch) {
- CollectionFreeFormDocumentView._undoBatch = UndoManager.StartBatch("iconAnimating");
- }
- let isMinimized: boolean | undefined;
- expandedDocs.map(d => Doc.GetProto(d)).map(maximizedDoc => {
- let iconAnimating = Cast(maximizedDoc.isIconAnimating, List);
- if (!iconAnimating || (Date.now() - iconAnimating[2] > 1000)) {
- if (isMinimized === undefined) {
- isMinimized = BoolCast(maximizedDoc.isMinimized, false);
- }
- maximizedDoc.willMaximize = isMinimized;
- maximizedDoc.isMinimized = false;
- maximizedDoc.isIconAnimating = new List<number>([scrpt[0], scrpt[1], Date.now(), isMinimized ? 1 : 0]);
- }
+ .scale(1 / this.contentScaling()).scale(1 / this.zoom);
+
+ animateBetweenIcon = (icon: number[], stime: number, maximizing: boolean) => {
+ this.props.bringToFront(this.props.Document);
+ let targetPos = [this.Document.x || 0, this.Document.y || 0];
+ let iconPos = this.props.ScreenToLocalTransform().transformPoint(icon[0], icon[1]);
+ DocumentView.animateBetweenIconFunc(this.props.Document,
+ this.Document.width || 0, this.Document.height || 0, stime, maximizing, (progress: number) => {
+ let pval = maximizing ?
+ [iconPos[0] + (targetPos[0] - iconPos[0]) * progress, iconPos[1] + (targetPos[1] - iconPos[1]) * progress] :
+ [targetPos[0] + (iconPos[0] - targetPos[0]) * progress, targetPos[1] + (iconPos[1] - targetPos[1]) * progress];
+ this.Document.x = progress === 1 ? targetPos[0] : pval[0];
+ this.Document.y = progress === 1 ? targetPos[1] : pval[1];
});
- setTimeout(() => {
- CollectionFreeFormDocumentView._undoBatch && CollectionFreeFormDocumentView._undoBatch.end();
- CollectionFreeFormDocumentView._undoBatch = undefined;
- }, 500);
- }
- }
-
- animateBetweenIcon(first: boolean, icon: number[], targ: number[], width: number, height: number, stime: number, maximizing: boolean) {
-
- setTimeout(() => {
- let now = Date.now();
- let progress = Math.min(1, (now - stime) / 200);
- let pval = maximizing ?
- [icon[0] + (targ[0] - icon[0]) * progress, icon[1] + (targ[1] - icon[1]) * progress] :
- [targ[0] + (icon[0] - targ[0]) * progress, targ[1] + (icon[1] - targ[1]) * progress];
- this.props.Document.width = maximizing ? 25 + (width - 25) * progress : width + (25 - width) * progress;
- this.props.Document.height = maximizing ? 25 + (height - 25) * progress : height + (25 - height) * progress;
- this.props.Document.x = pval[0];
- this.props.Document.y = pval[1];
- if (first) {
- this.props.Document.proto!.willMaximize = false;
- }
- if (now < stime + 200) {
- this.animateBetweenIcon(false, icon, targ, width, height, stime, maximizing);
- }
- else {
- if (!maximizing) {
- this.props.Document.proto!.isMinimized = true;
- this.props.Document.x = targ[0];
- this.props.Document.y = targ[1];
- this.props.Document.width = width;
- this.props.Document.height = height;
- }
- this.props.Document.proto!.isIconAnimating = undefined;
- }
- },
- 2);
}
borderRounding = () => {
@@ -155,34 +73,25 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
}
render() {
- let maximizedDoc = FieldValue(Cast(this.props.Document.maximizedDocs, listSpec(Doc)));
- let zoomFade = 1;
- //var zoom = doc.GetNumber(KeyStore.ZoomBasis, 1);
- // let transform = this.getTransform().scale(this.contentScaling()).inverse();
- // var [sptX, sptY] = transform.transformPoint(0, 0);
- // let [bptX, bptY] = transform.transformPoint(this.props.PanelWidth(), this.props.PanelHeight());
- // let w = bptX - sptX;
- //zoomFade = area < 100 || area > 800 ? Math.max(0, Math.min(1, 2 - 5 * (zoom < this.scale ? this.scale / zoom : zoom / this.scale))) : 1;
- const screenWidth = Math.min(50 * NumCast(this.props.Document.nativeWidth, 0), 1800);
- let fadeUp = .75 * screenWidth;
- let fadeDown = (maximizedDoc ? .0075 : .075) * screenWidth;
- // zoomFade = w < fadeDown /* || w > fadeUp */ ? Math.max(0.1, Math.min(1, 2 - (w < fadeDown ? Math.sqrt(Math.sqrt(fadeDown / w)) : w / fadeUp))) : 1;
-
return (
- <div className="collectionFreeFormDocumentView-container" ref={this._mainCont}
+ <div className="collectionFreeFormDocumentView-container"
style={{
- opacity: zoomFade,
- borderRadius: `${this.borderRounding()}px`,
transformOrigin: "left top",
+ position: "absolute",
+ backgroundColor: "transparent",
+ borderRadius: `${this.borderRounding()}px`,
transform: this.transform,
- pointerEvents: (zoomFade < 0.09 ? "none" : "all"),
width: this.width,
height: this.height,
- position: "absolute",
zIndex: this.Document.zIndex || 0,
- backgroundColor: "transparent"
}} >
- {this.docView}
+ <DocumentView {...this.props}
+ ContentScaling={this.contentScaling}
+ ScreenToLocalTransform={this.getTransform}
+ PanelWidth={this.panelWidth}
+ PanelHeight={this.panelHeight}
+ animateBetweenIcon={this.animateBetweenIcon}
+ />
</div>
);
}
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 6fe01963a..a8dc13d1e 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -75,7 +75,7 @@ export interface DocumentViewProps {
whenActiveChanged: (isActive: boolean) => void;
bringToFront: (doc: Doc) => void;
addDocTab: (doc: Doc, where: string) => void;
- collapseToPoint?: (scrpt: number[], expandedDocs: Doc[] | undefined) => void;
+ animateBetweenIcon?: (iconPos: number[], startTime: number, maximizing: boolean) => void;
}
const schema = createSchema({
@@ -127,6 +127,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
super(props);
}
+ _animateToIconDisposer?: IReactionDisposer;
_reactionDisposer?: IReactionDisposer;
@action
componentDidMount() {
@@ -148,8 +149,35 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
this.props.Document.proto!.title = "-" + sumDoc.title + ".expanded";
}
}, { fireImmediately: true });
+ this._animateToIconDisposer = reaction(() => this.props.Document.isIconAnimating, (values) =>
+ (values instanceof List) && this.animateBetweenIcon(values, values[2], values[3] ? true : false)
+ , { fireImmediately: true });
DocumentManager.Instance.DocumentViews.push(this);
}
+
+ animateBetweenIcon = (iconPos: number[], startTime: number, maximizing: boolean) => {
+ this.props.animateBetweenIcon ? this.props.animateBetweenIcon(iconPos, startTime, maximizing) :
+ DocumentView.animateBetweenIconFunc(this.props.Document, this.Document[WidthSym](), this.Document[HeightSym](), startTime, maximizing);
+ Doc.GetProto(this.props.Document).willMaximize = false;
+ }
+
+ public static animateBetweenIconFunc = (doc: Doc, width: number, height: number, stime: number, maximizing: boolean, cb?: (progress: number) => void) => {
+ setTimeout(() => {
+ let now = Date.now();
+ let progress = now < stime + 200 ? Math.min(1, (now - stime) / 200) : 1
+ doc.width = progress === 1 ? width : maximizing ? 25 + (width - 25) * progress : width + (25 - width) * progress
+ doc.height = progress === 1 ? height : maximizing ? 25 + (height - 25) * progress : height + (25 - height) * progress;
+ cb && cb(progress);
+ if (now < stime + 200) {
+ DocumentView.animateBetweenIconFunc(doc, width, height, stime, maximizing, cb);
+ }
+ else {
+ Doc.GetProto(doc).isMinimized = !maximizing;
+ Doc.GetProto(doc).isIconAnimating = undefined;
+ }
+ },
+ 2);
+ }
@action
componentDidUpdate() {
if (this._dropDisposer) {
@@ -164,6 +192,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
@action
componentWillUnmount() {
if (this._reactionDisposer) this._reactionDisposer();
+ if (this._animateToIconDisposer) this._animateToIconDisposer();
if (this._dropDisposer) this._dropDisposer();
DocumentManager.Instance.DocumentViews.splice(DocumentManager.Instance.DocumentViews.indexOf(this), 1);
}
@@ -195,7 +224,34 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
if (minimizedDoc) {
let scrpt = this.props.ScreenToLocalTransform().scale(this.props.ContentScaling()).inverse().transformPoint(
NumCast(minimizedDoc.x) - NumCast(this.Document.x), NumCast(minimizedDoc.y) - NumCast(this.Document.y));
- this.props.collapseToPoint && this.props.collapseToPoint(scrpt, await DocListCastAsync(minimizedDoc.maximizedDocs));
+ this.collapseTargetsToPoint(scrpt, await DocListCastAsync(minimizedDoc.maximizedDocs))
+ }
+ }
+
+ static _undoBatch?: UndoManager.Batch = undefined;
+ @action
+ public collapseTargetsToPoint = async (scrpt: number[], expandedDocs: Doc[] | undefined): Promise<void> => {
+ SelectionManager.DeselectAll();
+ if (expandedDocs) {
+ if (!DocumentView._undoBatch) {
+ DocumentView._undoBatch = UndoManager.StartBatch("iconAnimating");
+ }
+ let isMinimized: boolean | undefined;
+ expandedDocs.map(d => Doc.GetProto(d)).map(maximizedDoc => {
+ let iconAnimating = Cast(maximizedDoc.isIconAnimating, List);
+ if (!iconAnimating || (Date.now() - iconAnimating[2] > 1000)) {
+ if (isMinimized === undefined) {
+ isMinimized = BoolCast(maximizedDoc.isMinimized, false);
+ }
+ maximizedDoc.willMaximize = isMinimized;
+ maximizedDoc.isMinimized = false;
+ maximizedDoc.isIconAnimating = new List<number>([scrpt[0], scrpt[1], Date.now(), isMinimized ? 1 : 0]);
+ }
+ });
+ setTimeout(() => {
+ DocumentView._undoBatch && DocumentView._undoBatch.end();
+ DocumentView._undoBatch = undefined;
+ }, 500);
}
}
@@ -251,7 +307,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
}
} else {
let scrpt = this.props.ScreenToLocalTransform().scale(this.props.ContentScaling()).inverse().transformPoint(NumCast(this.Document.width) / 2, NumCast(this.Document.height) / 2);
- this.props.collapseToPoint && this.props.collapseToPoint(scrpt, expandedProtoDocs);
+ this.collapseTargetsToPoint(scrpt, expandedProtoDocs);
}
}
else if (linkedToDocs.length || linkedFromDocs.length) {