From 7e05ea0058766a3afa2ec82f6312f2df87178883 Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Sun, 14 Apr 2019 12:23:10 -0400
Subject: starting to add LOD

---
 src/client/views/nodes/CollectionFreeFormDocumentView.tsx | 13 ++++---------
 1 file changed, 4 insertions(+), 9 deletions(-)

(limited to 'src/client/views/nodes/CollectionFreeFormDocumentView.tsx')

diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
index 77f41105f..0aa152209 100644
--- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
+++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
@@ -6,7 +6,6 @@ import { Transform } from "../../util/Transform";
 import { DocumentView, DocumentViewProps } from "./DocumentView";
 import "./DocumentView.scss";
 import React = require("react");
-import { thisExpression } from "babel-types";
 
 
 @observer
@@ -16,18 +15,13 @@ export class CollectionFreeFormDocumentView extends React.Component<DocumentView
     constructor(props: DocumentViewProps) {
         super(props);
     }
-    get screenRect(): ClientRect | DOMRect {
-        if (this._mainCont.current) {
-            return this._mainCont.current.getBoundingClientRect();
-        }
-        return new DOMRect();
-    }
 
     @computed
     get transform(): string {
-        return `scale(${this.props.ContentScaling()}, ${this.props.ContentScaling()}) translate(${this.props.Document.GetNumber(KeyStore.X, 0)}px, ${this.props.Document.GetNumber(KeyStore.Y, 0)}px)`;
+        return `scale(${this.props.ContentScaling()}, ${this.props.ContentScaling()}) translate(${this.props.Document.GetNumber(KeyStore.X, 0)}px, ${this.props.Document.GetNumber(KeyStore.Y, 0)}px) scale(${this.zoom}, ${this.zoom}) `;
     }
 
+    @computed get zoom(): number { return 1 / this.props.Document.GetNumber(KeyStore.Zoom, 1); }
     @computed get zIndex(): number { return this.props.Document.GetNumber(KeyStore.ZIndex, 0); }
     @computed get width(): number { return this.props.Document.Width(); }
     @computed get height(): number { return this.props.Document.Height(); }
@@ -57,7 +51,7 @@ export class CollectionFreeFormDocumentView extends React.Component<DocumentView
     getTransform = (): Transform =>
         this.props.ScreenToLocalTransform()
             .translate(-this.props.Document.GetNumber(KeyStore.X, 0), -this.props.Document.GetNumber(KeyStore.Y, 0))
-            .scale(1 / this.contentScaling())
+            .scale(1 / this.contentScaling()).scale(1 / this.zoom)
 
     @computed
     get docView() {
@@ -74,6 +68,7 @@ export class CollectionFreeFormDocumentView extends React.Component<DocumentView
     render() {
         return (
             <div className="collectionFreeFormDocumentView-container" ref={this._mainCont} style={{
+                opacity: this.props.opacity,
                 transformOrigin: "left top",
                 transform: this.transform,
                 pointerEvents: "all",
-- 
cgit v1.2.3-70-g09d2


From 6c0b421db6aa3204bbc6e42139d240f503000b5d Mon Sep 17 00:00:00 2001
From: bob <bcz@cs.brown.edu>
Date: Mon, 15 Apr 2019 11:59:50 -0400
Subject: fixed zoom fading somewhat.

---
 src/Utils.ts                                       | 15 ++++++++++
 src/client/northstar/dash-fields/HistogramField.ts | 12 ++------
 src/client/views/Main.tsx                          |  3 +-
 src/client/views/MainOverlayTextBox.tsx            |  3 +-
 .../views/collections/CollectionDockingView.tsx    |  3 +-
 .../views/collections/CollectionSchemaView.tsx     |  3 +-
 .../collectionFreeForm/CollectionFreeFormView.tsx  | 19 ++++++-------
 .../views/nodes/CollectionFreeFormDocumentView.tsx | 18 ++++++++----
 src/client/views/nodes/DocumentContentsView.tsx    | 33 ++--------------------
 src/client/views/nodes/DocumentView.tsx            |  1 -
 src/client/views/nodes/FieldView.tsx               |  3 +-
 src/client/views/nodes/FormattedTextBox.tsx        |  4 ++-
 12 files changed, 51 insertions(+), 66 deletions(-)

(limited to 'src/client/views/nodes/CollectionFreeFormDocumentView.tsx')

diff --git a/src/Utils.ts b/src/Utils.ts
index e07d4e82d..dec6245ef 100644
--- a/src/Utils.ts
+++ b/src/Utils.ts
@@ -87,10 +87,25 @@ export class Utils {
     }
 }
 
+export function OmitKeys(obj: any, keys: any, addKeyFunc?: (dup: any) => void) {
+    var dup: any = {};
+    for (var key in obj) {
+        if (keys.indexOf(key) === -1) {
+            dup[key] = obj[key];
+        }
+    }
+    addKeyFunc && addKeyFunc(dup);
+    return dup;
+}
+
 export function returnTrue() { return true; }
 
 export function returnFalse() { return false; }
 
+export function returnOne() { return 1; }
+
+export function returnZero() { return 0; }
+
 export function emptyFunction() { }
 
 export function emptyDocFunction(doc: Document) { }
diff --git a/src/client/northstar/dash-fields/HistogramField.ts b/src/client/northstar/dash-fields/HistogramField.ts
index 82de51d56..c699691a4 100644
--- a/src/client/northstar/dash-fields/HistogramField.ts
+++ b/src/client/northstar/dash-fields/HistogramField.ts
@@ -6,6 +6,7 @@ import { BasicField } from "../../../fields/BasicField";
 import { Field, FieldId } from "../../../fields/Field";
 import { CurrentUserUtils } from "../../../server/authentication/models/current_user_utils";
 import { Types } from "../../../server/Message";
+import { OmitKeys } from "../../../Utils";
 
 
 export class HistogramField extends BasicField<HistogramOperation> {
@@ -13,17 +14,8 @@ export class HistogramField extends BasicField<HistogramOperation> {
         super(data ? data : HistogramOperation.Empty, save, id);
     }
 
-    omitKeys(obj: any, keys: any) {
-        var dup: any = {};
-        for (var key in obj) {
-            if (keys.indexOf(key) === -1) {
-                dup[key] = obj[key];
-            }
-        }
-        return dup;
-    }
     toString(): string {
-        return JSON.stringify(this.omitKeys(this.Data, ['Links', 'BrushLinks', 'Result', 'BrushColors', 'FilterModels', 'FilterOperand']));
+        return JSON.stringify(OmitKeys(this.Data, ['Links', 'BrushLinks', 'Result', 'BrushColors', 'FilterModels', 'FilterOperand']));
     }
 
     Copy(): Field {
diff --git a/src/client/views/Main.tsx b/src/client/views/Main.tsx
index d26586216..98ef329c7 100644
--- a/src/client/views/Main.tsx
+++ b/src/client/views/Main.tsx
@@ -17,7 +17,7 @@ import { CurrentUserUtils } from '../../server/authentication/models/current_use
 import { MessageStore } from '../../server/Message';
 import { RouteStore } from '../../server/RouteStore';
 import { ServerUtils } from '../../server/ServerUtil';
-import { emptyDocFunction, emptyFunction, returnTrue, Utils } from '../../Utils';
+import { emptyDocFunction, emptyFunction, returnTrue, Utils, returnOne } from '../../Utils';
 import { Documents } from '../documents/Documents';
 import { ColumnAttributeModel } from '../northstar/core/attribute/AttributeModel';
 import { AttributeTransformationModel } from '../northstar/core/attribute/AttributeTransformationModel';
@@ -178,7 +178,6 @@ export class Main extends React.Component {
                         <DocumentView Document={mainCont}
                             addDocument={undefined}
                             removeDocument={undefined}
-                            opacity={1}
                             ScreenToLocalTransform={Transform.Identity}
                             ContentScaling={noScaling}
                             PanelWidth={pwidthFunc}
diff --git a/src/client/views/MainOverlayTextBox.tsx b/src/client/views/MainOverlayTextBox.tsx
index df1addbc7..6d43d88f0 100644
--- a/src/client/views/MainOverlayTextBox.tsx
+++ b/src/client/views/MainOverlayTextBox.tsx
@@ -56,7 +56,8 @@ export class MainOverlayTextBox extends React.Component<MainOverlayTextBoxProps>
     @action
     textScroll = (e: React.UIEvent) => {
         if (this._textProxyDiv.current && this._textTargetDiv) {
-            this._textTargetDiv.scrollTop = this.TextScroll = this._textProxyDiv.current.children[0].scrollTop;
+            this.TextScroll = (e as any)._targetInst.stateNode.scrollTop;//  this._textProxyDiv.current.children[0].scrollTop;
+            this._textTargetDiv.scrollTop = this.TextScroll;
         }
     }
 
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index 4f7d4fc0d..2b96e7678 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -8,7 +8,7 @@ import { Document } from "../../../fields/Document";
 import { KeyStore } from "../../../fields/KeyStore";
 import Measure from "react-measure";
 import { FieldId, Opt, Field, FieldWaiting } from "../../../fields/Field";
-import { Utils, returnTrue, emptyFunction, emptyDocFunction } from "../../../Utils";
+import { Utils, returnTrue, emptyFunction, emptyDocFunction, returnOne } from "../../../Utils";
 import { Server } from "../../Server";
 import { undoBatch } from "../../util/UndoManager";
 import { DocumentView } from "../nodes/DocumentView";
@@ -343,7 +343,6 @@ export class DockedFrameRenderer extends React.Component<DockedFrameProps> {
                 <DocumentView key={this._document.Id} Document={this._document}
                     addDocument={undefined}
                     removeDocument={undefined}
-                    opacity={1}
                     ContentScaling={this._contentScaling}
                     PanelWidth={this._nativeWidth}
                     PanelHeight={this._nativeHeight}
diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx
index 2c99c9c67..4f4068e7a 100644
--- a/src/client/views/collections/CollectionSchemaView.tsx
+++ b/src/client/views/collections/CollectionSchemaView.tsx
@@ -12,7 +12,7 @@ import { Field, Opt } from "../../../fields/Field";
 import { Key } from "../../../fields/Key";
 import { KeyStore } from "../../../fields/KeyStore";
 import { ListField } from "../../../fields/ListField";
-import { emptyDocFunction, emptyFunction, returnFalse } from "../../../Utils";
+import { emptyDocFunction, emptyFunction, returnFalse, returnOne } from "../../../Utils";
 import { Server } from "../../Server";
 import { SetupDrag } from "../../util/DragManager";
 import { CompileScript, ToField } from "../../util/Scripting";
@@ -308,7 +308,6 @@ export class CollectionSchemaView extends CollectionSubView {
                             <DocumentView Document={doc}
                                 addDocument={this.props.addDocument} removeDocument={this.props.removeDocument}
                                 isTopMost={false}
-                                opacity={1}
                                 selectOnLoad={false}
                                 ScreenToLocalTransform={this.getPreviewTransform}
                                 ContentScaling={this.getContentScaling}
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index cb4e8fb2e..4db3bf81b 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -5,7 +5,7 @@ import { Document } from "../../../../fields/Document";
 import { FieldWaiting } from "../../../../fields/Field";
 import { KeyStore } from "../../../../fields/KeyStore";
 import { TextField } from "../../../../fields/TextField";
-import { emptyFunction, returnFalse } from "../../../../Utils";
+import { emptyFunction, returnFalse, returnOne } from "../../../../Utils";
 import { DocumentManager } from "../../../util/DocumentManager";
 import { DragManager } from "../../../util/DragManager";
 import { SelectionManager } from "../../../util/SelectionManager";
@@ -14,7 +14,7 @@ import { undoBatch } from "../../../util/UndoManager";
 import { COLLECTION_BORDER_WIDTH } from "../../../views/globalCssVariables.scss";
 import { InkingCanvas } from "../../InkingCanvas";
 import { Main } from "../../Main";
-import { CollectionFreeFormDocumentView } from "../../nodes/CollectionFreeFormDocumentView";
+import { CollectionFreeFormDocumentView, CollectionFreeFormDocumentViewProps } from "../../nodes/CollectionFreeFormDocumentView";
 import { DocumentContentsView } from "../../nodes/DocumentContentsView";
 import { DocumentViewProps } from "../../nodes/DocumentView";
 import { CollectionSubView, SubCollectionViewProps } from "../CollectionSubView";
@@ -200,7 +200,6 @@ export class CollectionFreeFormView extends CollectionSubView {
             this.props.Document.SetNumber(KeyStore.Scale, localTransform.Scale);
             this.SetPan(-localTransform.TranslateX / localTransform.Scale, -localTransform.TranslateY / localTransform.Scale);
             e.stopPropagation();
-            e.preventDefault();
         }
     }
 
@@ -261,10 +260,9 @@ export class CollectionFreeFormView extends CollectionSubView {
         this.props.focus(this.props.Document);
     }
 
-    getDocumentViewProps(document: Document, opacity: number): DocumentViewProps {
+    getDocumentViewProps(document: Document): DocumentViewProps {
         return {
             Document: document,
-            opacity: opacity,
             addDocument: this.props.addDocument,
             removeDocument: this.props.removeDocument,
             moveDocument: this.props.moveDocument,
@@ -288,9 +286,10 @@ export class CollectionFreeFormView extends CollectionSubView {
             var page = doc.GetNumber(KeyStore.Page, -1);
             var zoom = doc.GetNumber(KeyStore.Zoom, 1);
             var dv = DocumentManager.Instance.getDocumentView(doc);
-            let opacity = this.isAnnotationOverlay && (!dv || !SelectionManager.IsSelected(dv)) ? 1 - Math.abs(zoom - this.scale) : 1;
-            if ((page === curPage || page === -1)) {
-                prev.push(<CollectionFreeFormDocumentView key={doc.Id} {...this.getDocumentViewProps(doc, opacity)} />);
+            let zoomFade = !this.isAnnotationOverlay || (dv && SelectionManager.IsSelected(dv)) ? 1 :
+                Math.max(0, 2 - (zoom < this.scale ? this.scale / zoom : zoom / this.scale));
+            if (page === curPage || page === -1) {
+                prev.push(<CollectionFreeFormDocumentView key={doc.Id} {...this.getDocumentViewProps(doc)} zoomFade={zoomFade} />);
             }
             return prev;
         }, [] as JSX.Element[]);
@@ -305,13 +304,13 @@ export class CollectionFreeFormView extends CollectionSubView {
     @computed
     get backgroundView() {
         return !this.backgroundLayout ? (null) :
-            (<DocumentContentsView {...this.getDocumentViewProps(this.props.Document, 1)}
+            (<DocumentContentsView {...this.getDocumentViewProps(this.props.Document)}
                 layoutKey={KeyStore.BackgroundLayout} isTopMost={this.props.isTopMost} isSelected={returnFalse} select={emptyFunction} />);
     }
     @computed
     get overlayView() {
         return !this.overlayLayout ? (null) :
-            (<DocumentContentsView {...this.getDocumentViewProps(this.props.Document, 1)}
+            (<DocumentContentsView {...this.getDocumentViewProps(this.props.Document)}
                 layoutKey={KeyStore.OverlayLayout} isTopMost={this.props.isTopMost} isSelected={returnFalse} select={emptyFunction} />);
     }
 
diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
index 0aa152209..b00cefbf6 100644
--- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
+++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
@@ -1,4 +1,4 @@
-import { computed } from "mobx";
+import { computed, trace } from "mobx";
 import { observer } from "mobx-react";
 import { KeyStore } from "../../../fields/KeyStore";
 import { NumberField } from "../../../fields/NumberField";
@@ -6,13 +6,17 @@ import { Transform } from "../../util/Transform";
 import { DocumentView, DocumentViewProps } from "./DocumentView";
 import "./DocumentView.scss";
 import React = require("react");
+import { OmitKeys } from "../../../Utils";
 
+export interface CollectionFreeFormDocumentViewProps extends DocumentViewProps {
+    zoomFade: number;
+}
 
 @observer
-export class CollectionFreeFormDocumentView extends React.Component<DocumentViewProps> {
+export class CollectionFreeFormDocumentView extends React.Component<CollectionFreeFormDocumentViewProps> {
     private _mainCont = React.createRef<HTMLDivElement>();
 
-    constructor(props: DocumentViewProps) {
+    constructor(props: CollectionFreeFormDocumentViewProps) {
         super(props);
     }
 
@@ -55,20 +59,24 @@ export class CollectionFreeFormDocumentView extends React.Component<DocumentView
 
     @computed
     get docView() {
-        return <DocumentView {...this.props}
+        return <DocumentView {...this.docViewProps}
             ContentScaling={this.contentScaling}
             ScreenToLocalTransform={this.getTransform}
             PanelWidth={this.panelWidth}
             PanelHeight={this.panelHeight}
         />;
     }
+    @computed
+    get docViewProps(): DocumentViewProps {
+        return (OmitKeys(this.props, ['zoomFade']));
+    }
     panelWidth = () => this.props.Document.GetBoolean(KeyStore.Minimized, false) ? 10 : this.props.PanelWidth();
     panelHeight = () => this.props.Document.GetBoolean(KeyStore.Minimized, false) ? 10 : this.props.PanelHeight();
 
     render() {
         return (
             <div className="collectionFreeFormDocumentView-container" ref={this._mainCont} style={{
-                opacity: this.props.opacity,
+                opacity: this.props.zoomFade,
                 transformOrigin: "left top",
                 transform: this.transform,
                 pointerEvents: "all",
diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx
index 88900c4b1..76f852601 100644
--- a/src/client/views/nodes/DocumentContentsView.tsx
+++ b/src/client/views/nodes/DocumentContentsView.tsx
@@ -23,7 +23,7 @@ import { HistogramBox } from "../../northstar/dash-nodes/HistogramBox";
 import React = require("react");
 import { Document } from "../../../fields/Document";
 import { FieldViewProps } from "./FieldView";
-import { Without } from "../../../Utils";
+import { Without, OmitKeys } from "../../../Utils";
 const JsxParser = require('react-jsx-parser').default; //TODO Why does this need to be imported like this?
 
 type BindingProps = Without<FieldViewProps, 'fieldKey'>;
@@ -44,35 +44,8 @@ export class DocumentContentsView extends React.Component<DocumentViewProps & {
 
 
     CreateBindings(): JsxBindings {
-        let {
-            Document,
-            isSelected,
-            select,
-            isTopMost,
-            selectOnLoad,
-            ScreenToLocalTransform,
-            ContainingCollectionView,
-            addDocument,
-            removeDocument,
-            onActiveChanged,
-            parentActive: active,
-        } = this.props;
-        let bindings: JsxBindings = {
-            props: {
-                Document,
-                isSelected,
-                select,
-                isTopMost,
-                selectOnLoad,
-                ScreenToLocalTransform,
-                ContainingCollectionView,
-                active,
-                onActiveChanged,
-                addDocument,
-                removeDocument,
-                focus,
-            }
-        };
+        let bindings: JsxBindings = { props: OmitKeys(this.props, ['parentActive'], (obj: any) => obj.active = this.props.parentActive) };
+
         for (const key of this.layoutKeys) {
             bindings[key.Name + "Key"] = key; // this maps string values of the form <keyname>Key to an actual key Kestore.keyname  e.g,   "DataKey" => KeyStore.Data
         }
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 935540af1..bcd746024 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -28,7 +28,6 @@ import React = require("react");
 export interface DocumentViewProps {
     ContainingCollectionView: Opt<CollectionView | CollectionPDFView | CollectionVideoView>;
     Document: Document;
-    opacity: number;
     addDocument?: (doc: Document, allowDuplicates?: boolean) => boolean;
     removeDocument?: (doc: Document) => boolean;
     moveDocument?: (doc: Document, targetCollection: Document, addDocument: (document: Document) => boolean) => boolean;
diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx
index 562de4827..ebd25f937 100644
--- a/src/client/views/nodes/FieldView.tsx
+++ b/src/client/views/nodes/FieldView.tsx
@@ -19,7 +19,7 @@ import { ListField } from "../../../fields/ListField";
 import { DocumentContentsView } from "./DocumentContentsView";
 import { Transform } from "../../util/Transform";
 import { KeyStore } from "../../../fields/KeyStore";
-import { returnFalse, emptyDocFunction } from "../../../Utils";
+import { returnFalse, emptyDocFunction, emptyFunction, returnOne } from "../../../Utils";
 import { CollectionView } from "../collections/CollectionView";
 import { CollectionPDFView } from "../collections/CollectionPDFView";
 import { CollectionVideoView } from "../collections/CollectionVideoView";
@@ -83,7 +83,6 @@ export class FieldView extends React.Component<FieldViewProps> {
                 <DocumentContentsView Document={field}
                     addDocument={undefined}
                     removeDocument={undefined}
-                    opacity={1}
                     ScreenToLocalTransform={Transform.Identity}
                     ContentScaling={() => 1}
                     PanelWidth={() => 100}
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index 87c1bcb1e..ad1ed5df0 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -1,4 +1,4 @@
-import { action, IReactionDisposer, reaction } from "mobx";
+import { action, IReactionDisposer, reaction, trace, computed } from "mobx";
 import { baseKeymap } from "prosemirror-commands";
 import { history, redo, undo } from "prosemirror-history";
 import { keymap } from "prosemirror-keymap";
@@ -17,6 +17,7 @@ import React = require("react");
 import { TextField } from "../../../fields/TextField";
 import { KeyStore } from "../../../fields/KeyStore";
 import { MainOverlayTextBox } from "../MainOverlayTextBox";
+import { observer } from "mobx-react";
 const { buildMenuItems } = require("prosemirror-example-setup");
 const { menuBar } = require("prosemirror-menu");
 
@@ -41,6 +42,7 @@ export interface FormattedTextBoxOverlay {
     isOverlay?: boolean;
 }
 
+@observer
 export class FormattedTextBox extends React.Component<(FieldViewProps & FormattedTextBoxOverlay)> {
     public static LayoutString(fieldStr: string = "DataKey") {
         return FieldView.LayoutString(FormattedTextBox, fieldStr);
-- 
cgit v1.2.3-70-g09d2


From 13ced657b7a3292e57150bf5e44412d7068b7e3d Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Tue, 16 Apr 2019 00:37:07 -0400
Subject: code clean up and fix to performance issues.

---
 src/client/views/DocumentDecorations.tsx           |   7 +-
 src/client/views/Main.tsx                          |   2 +-
 src/client/views/collections/CollectionView.tsx    |   1 +
 .../CollectionFreeFormLinkView.tsx                 |   8 +-
 .../collectionFreeForm/CollectionFreeFormView.tsx  | 242 ++++++++++-----------
 .../collections/collectionFreeForm/MarqueeView.tsx |   6 +-
 .../views/nodes/CollectionFreeFormDocumentView.tsx |  33 +--
 src/client/views/nodes/DocumentView.scss           |   6 +-
 src/client/views/nodes/DocumentView.tsx            | 241 ++++++--------------
 src/client/views/nodes/ImageBox.tsx                |   2 +-
 10 files changed, 212 insertions(+), 336 deletions(-)

(limited to 'src/client/views/nodes/CollectionFreeFormDocumentView.tsx')

diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index b97a47a3c..06de3d733 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -124,7 +124,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
         this._dragging = true;
         document.removeEventListener("pointermove", this.onBackgroundMove);
         document.removeEventListener("pointerup", this.onBackgroundUp);
-        DragManager.StartDocumentDrag(SelectionManager.SelectedDocuments().map(docView => docView.ContentRef.current!), dragData, e.x, e.y, {
+        DragManager.StartDocumentDrag(SelectionManager.SelectedDocuments().map(docView => docView.ContentDiv!), dragData, e.x, e.y, {
             handlers: {
                 dragComplete: action(() => this._dragging = false),
             },
@@ -176,8 +176,6 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
     }
     onMinimizeMove = (e: PointerEvent): void => {
         e.stopPropagation();
-        if (e.button === 0) {
-        }
     }
     onMinimizeUp = (e: PointerEvent): void => {
         e.stopPropagation();
@@ -302,7 +300,8 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
 
         MainOverlayTextBox.Instance.SetTextDoc();
         SelectionManager.SelectedDocuments().forEach(element => {
-            const rect = element.screenRect();
+            const rect = element.ContentDiv ? element.ContentDiv.getBoundingClientRect() : new DOMRect();
+
             if (rect.width !== 0) {
                 let doc = element.props.Document;
                 let width = doc.GetNumber(KeyStore.Width, 0);
diff --git a/src/client/views/Main.tsx b/src/client/views/Main.tsx
index 6c18e9ad5..0469211fa 100644
--- a/src/client/views/Main.tsx
+++ b/src/client/views/Main.tsx
@@ -211,7 +211,7 @@ export class Main extends React.Component {
         let addSchemaNode = action(() => Documents.SchemaDocument([], { width: 200, height: 200, title: "a schema collection" }));
         let addTreeNode = action(() => Documents.TreeDocument(this._northstarSchemas, { width: 250, height: 400, title: "northstar schemas", copyDraggedItems: true }));
         let addVideoNode = action(() => Documents.VideoDocument(videourl, { width: 200, height: 200, title: "video node" }));
-        let addPDFNode = action(() => Documents.PdfDocument(pdfurl, { width: 200, height: 200, title: "a schema collection" }));
+        let addPDFNode = action(() => Documents.PdfDocument(pdfurl, { width: 200, height: 200, title: "a pdf doc" }));
         let addImageNode = action(() => Documents.ImageDocument(imgurl, { width: 200, height: 200, title: "an image of a cat" }));
         let addWebNode = action(() => Documents.WebDocument(weburl, { width: 200, height: 200, title: "a sample web page" }));
         let addAudioNode = action(() => Documents.AudioDocument(audiourl, { width: 200, height: 200, title: "audio node" }));
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index 1f69a69e8..bd7a5635f 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -10,6 +10,7 @@ import { CurrentUserUtils } from '../../../server/authentication/models/current_
 import { KeyStore } from '../../../fields/KeyStore';
 import { observer } from 'mobx-react';
 import { undoBatch } from '../../util/UndoManager';
+import { trace } from 'mobx';
 
 @observer
 export class CollectionView extends React.Component<FieldViewProps> {
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
index 081b3eb6c..8868f7df0 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
@@ -23,10 +23,10 @@ export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFo
         let l = this.props.LinkDocs;
         let a = this.props.A;
         let b = this.props.B;
-        let x1 = a.GetNumber(KeyStore.X, 0) + (a.GetBoolean(KeyStore.Minimized, false) ? 5 : a.GetNumber(KeyStore.Width, 0) / 2);
-        let y1 = a.GetNumber(KeyStore.Y, 0) + (a.GetBoolean(KeyStore.Minimized, false) ? 5 : a.GetNumber(KeyStore.Height, 0) / 2);
-        let x2 = b.GetNumber(KeyStore.X, 0) + (b.GetBoolean(KeyStore.Minimized, false) ? 5 : b.GetNumber(KeyStore.Width, 0) / 2);
-        let y2 = b.GetNumber(KeyStore.Y, 0) + (b.GetBoolean(KeyStore.Minimized, false) ? 5 : b.GetNumber(KeyStore.Height, 0) / 2);
+        let x1 = a.GetNumber(KeyStore.X, 0) + (a.GetBoolean(KeyStore.Minimized, false) ? 5 : a.Width() / 2);
+        let y1 = a.GetNumber(KeyStore.Y, 0) + (a.GetBoolean(KeyStore.Minimized, false) ? 5 : a.Height() / 2);
+        let x2 = b.GetNumber(KeyStore.X, 0) + (b.GetBoolean(KeyStore.Minimized, false) ? 5 : b.Width() / 2);
+        let y2 = b.GetNumber(KeyStore.Y, 0) + (b.GetBoolean(KeyStore.Minimized, false) ? 5 : b.Height() / 2);
         return (
             <line key={Utils.GenerateGuid()} className="collectionfreeformlinkview-linkLine" onPointerDown={this.onPointerDown}
                 style={{ strokeWidth: `${l.length * 5}` }}
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 03426cb27..e9ea3013c 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -1,4 +1,4 @@
-import { action, computed, observable, runInAction, untracked } from "mobx";
+import { action, computed, observable, runInAction, trace, untracked } from "mobx";
 import { observer } from "mobx-react";
 import Measure from "react-measure";
 import { Document } from "../../../../fields/Document";
@@ -13,8 +13,8 @@ import { Transform } from "../../../util/Transform";
 import { undoBatch } from "../../../util/UndoManager";
 import { COLLECTION_BORDER_WIDTH } from "../../../views/globalCssVariables.scss";
 import { InkingCanvas } from "../../InkingCanvas";
-import { Main } from "../../Main";
-import { CollectionFreeFormDocumentView, CollectionFreeFormDocumentViewProps } from "../../nodes/CollectionFreeFormDocumentView";
+import { MainOverlayTextBox } from "../../MainOverlayTextBox";
+import { CollectionFreeFormDocumentView } from "../../nodes/CollectionFreeFormDocumentView";
 import { DocumentContentsView } from "../../nodes/DocumentContentsView";
 import { DocumentViewProps } from "../../nodes/DocumentView";
 import { CollectionSubView, SubCollectionViewProps } from "../CollectionSubView";
@@ -24,12 +24,15 @@ import "./CollectionFreeFormView.scss";
 import { MarqueeView } from "./MarqueeView";
 import React = require("react");
 import v5 = require("uuid/v5");
-import { MainOverlayTextBox } from "../../MainOverlayTextBox";
+import { CollectionFreeFormLinkView } from "./CollectionFreeFormLinkView";
 
 @observer
 export class CollectionFreeFormView extends CollectionSubView {
-    public _canvasRef = React.createRef<HTMLDivElement>();
     private _selectOnLoaded: string = ""; // id of document that should be selected once it's loaded (used for click-to-type)
+    private _lastX: number = 0;
+    private _lastY: number = 0;
+    @observable private _pwidth: number = 0;
+    @observable private _pheight: number = 0;
 
     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 and receive text input
@@ -61,22 +64,15 @@ export class CollectionFreeFormView extends CollectionSubView {
         }, [] as Document[]);
     }
 
-    @observable public DownX: number = 0;
-    @observable public DownY: number = 0;
-    @observable private _lastX: number = 0;
-    @observable private _lastY: number = 0;
-    @observable private _pwidth: number = 0;
-    @observable private _pheight: number = 0;
-
-    @computed get panX(): number { return this.props.Document.GetNumber(KeyStore.PanX, 0); }
-    @computed get panY(): number { return this.props.Document.GetNumber(KeyStore.PanY, 0); }
-    @computed get scale(): number { return this.props.Document.GetNumber(KeyStore.Scale, 1); }
-    @computed get isAnnotationOverlay() { return this.props.fieldKey && this.props.fieldKey.Id === KeyStore.Annotations.Id; } // bcz: ? Why do we need to compare Id's?
+    get borderWidth() { return this.isAnnotationOverlay ? 0 : COLLECTION_BORDER_WIDTH; }
+    get isAnnotationOverlay() { return this.props.fieldKey && this.props.fieldKey.Id === KeyStore.Annotations.Id; } // bcz: ? Why do we need to compare Id's?
     @computed get nativeWidth() { return this.props.Document.GetNumber(KeyStore.NativeWidth, 0); }
     @computed get nativeHeight() { return this.props.Document.GetNumber(KeyStore.NativeHeight, 0); }
-    @computed get zoomScaling() { return this.props.Document.GetNumber(KeyStore.Scale, 1); }
-    @computed get centeringShiftX() { return !this.props.Document.GetNumber(KeyStore.NativeWidth, 0) ? this._pwidth / 2 : 0; }  // shift so pan position is at center of window for non-overlay collections
-    @computed get centeringShiftY() { return !this.props.Document.GetNumber(KeyStore.NativeHeight, 0) ? this._pheight / 2 : 0; }// shift so pan position is at center of window for non-overlay collections
+    panX = () => this.props.Document.GetNumber(KeyStore.PanX, 0);
+    panY = () => this.props.Document.GetNumber(KeyStore.PanY, 0);
+    zoomScaling = () => this.props.Document.GetNumber(KeyStore.Scale, 1);
+    centeringShiftX = () => !this.nativeWidth ? this._pwidth / 2 : 0;  // shift so pan position is at center of window for non-overlay collections
+    centeringShiftY = () => !this.nativeHeight ? this._pheight / 2 : 0;// shift so pan position is at center of window for non-overlay collections
 
     @undoBatch
     @action
@@ -89,6 +85,7 @@ export class CollectionFreeFormView extends CollectionSubView {
                 de.data.droppedDocuments.map(d => {
                     d.SetNumber(KeyStore.X, x + (d.GetNumber(KeyStore.X, 0) - dropX));
                     d.SetNumber(KeyStore.Y, y + (d.GetNumber(KeyStore.Y, 0) - dropY));
+                    console.log("x = " + d.GetNumber(KeyStore.X, 0) + " y = " + d.GetNumber(KeyStore.X, 0));
                     if (!d.GetNumber(KeyStore.Width, 0)) {
                         d.SetNumber(KeyStore.Width, 300);
                     }
@@ -115,13 +112,13 @@ export class CollectionFreeFormView extends CollectionSubView {
             var dv = DocumentManager.Instance.getDocumentView(doc);
             return childSelected || (dv && SelectionManager.IsSelected(dv) ? true : false);
         }, false);
-        if (((e.button === 2 && (!this.isAnnotationOverlay || this.zoomScaling !== 1)) || (e.button === 0 && e.altKey)) && (childSelected || this.props.active())) {
+        if (((e.button === 2 && (!this.isAnnotationOverlay || this.zoomScaling() !== 1)) || (e.button === 0 && e.altKey)) && (childSelected || this.props.active())) {
             document.removeEventListener("pointermove", this.onPointerMove);
             document.addEventListener("pointermove", this.onPointerMove);
             document.removeEventListener("pointerup", this.onPointerUp);
             document.addEventListener("pointerup", this.onPointerUp);
-            this._lastX = this.DownX = e.pageX;
-            this._lastY = this.DownY = e.pageY;
+            this._lastX = e.pageX;
+            this._lastY = e.pageY;
         }
     }
 
@@ -141,9 +138,9 @@ export class CollectionFreeFormView extends CollectionSubView {
             let [dx, dy] = this.getTransform().transformDirection(e.clientX - this._lastX, e.clientY - this._lastY);
             if (!this.isAnnotationOverlay) {
                 let minx = docs.length ? docs[0].GetNumber(KeyStore.X, 0) : 0;
-                let maxx = docs.length ? docs[0].GetNumber(KeyStore.Width, 0) + minx : minx;
+                let maxx = docs.length ? docs[0].Width() + minx : minx;
                 let miny = docs.length ? docs[0].GetNumber(KeyStore.Y, 0) : 0;
-                let maxy = docs.length ? docs[0].GetNumber(KeyStore.Height, 0) + miny : miny;
+                let maxy = docs.length ? docs[0].Height() + miny : miny;
                 let ranges = docs.filter(doc => doc).reduce((range, doc) => {
                     let x = doc.GetNumber(KeyStore.X, 0);
                     let xe = x + doc.GetNumber(KeyStore.Width, 0);
@@ -152,8 +149,8 @@ export class CollectionFreeFormView extends CollectionSubView {
                     return [[range[0][0] > x ? x : range[0][0], range[0][1] < xe ? xe : range[0][1]],
                     [range[1][0] > y ? y : range[1][0], range[1][1] < ye ? ye : range[1][1]]];
                 }, [[minx, maxx], [miny, maxy]]);
-                let panelwidth = this._pwidth / this.scale / 2;
-                let panelheight = this._pheight / this.scale / 2;
+                let panelwidth = this._pwidth / this.zoomScaling() / 2;
+                let panelheight = this._pheight / this.zoomScaling() / 2;
                 if (x - dx < ranges[0][0] - panelwidth) x = ranges[0][1] + panelwidth + dx;
                 if (x - dx > ranges[0][1] + panelwidth) x = ranges[0][0] - panelwidth + dx;
                 if (y - dy < ranges[1][0] - panelheight) y = ranges[1][1] + panelheight + dy;
@@ -180,31 +177,23 @@ export class CollectionFreeFormView extends CollectionSubView {
             return;
         }
         e.stopPropagation();
-        let coefficient = 1000;
+        const coefficient = 1000;
 
         if (e.ctrlKey) {
-            var nativeWidth = this.props.Document.GetNumber(KeyStore.NativeWidth, 0);
-            var nativeHeight = this.props.Document.GetNumber(KeyStore.NativeHeight, 0);
-            const coefficient = 1000;
             let deltaScale = (1 - (e.deltaY / coefficient));
-            this.props.Document.SetNumber(KeyStore.NativeWidth, nativeWidth * deltaScale);
-            this.props.Document.SetNumber(KeyStore.NativeHeight, nativeHeight * deltaScale);
+            this.props.Document.SetNumber(KeyStore.NativeWidth, this.nativeWidth * deltaScale);
+            this.props.Document.SetNumber(KeyStore.NativeHeight, this.nativeHeight * deltaScale);
             e.stopPropagation();
             e.preventDefault();
         } else {
             // if (modes[e.deltaMode] === 'pixels') coefficient = 50;
             // else if (modes[e.deltaMode] === 'lines') coefficient = 1000; // This should correspond to line-height??
-            let transform = this.getTransform();
-
             let deltaScale = (1 - (e.deltaY / coefficient));
-            if (deltaScale * this.zoomScaling < 1 && this.isAnnotationOverlay) {
-                deltaScale = 1 / this.zoomScaling;
+            if (deltaScale * this.zoomScaling() < 1 && this.isAnnotationOverlay) {
+                deltaScale = 1 / this.zoomScaling();
             }
-            let [x, y] = transform.transformPoint(e.clientX, e.clientY);
-
-            let localTransform = this.getLocalTransform();
-            localTransform = localTransform.inverse().scaleAbout(deltaScale, x, y);
-            // console.log(localTransform)
+            let [x, y] = this.getTransform().transformPoint(e.clientX, e.clientY);
+            let localTransform = this.getLocalTransform().inverse().scaleAbout(deltaScale, x, y);
 
             this.props.Document.SetNumber(KeyStore.Scale, localTransform.Scale);
             this.SetPan(-localTransform.TranslateX / localTransform.Scale, -localTransform.TranslateY / localTransform.Scale);
@@ -215,9 +204,9 @@ export class CollectionFreeFormView extends CollectionSubView {
     @action
     private SetPan(panX: number, panY: number) {
         MainOverlayTextBox.Instance.SetTextDoc();
-        var x1 = this.getLocalTransform().inverse().Scale;
-        const newPanX = Math.min((1 - 1 / x1) * this.nativeWidth, Math.max(0, panX));
-        const newPanY = Math.min((1 - 1 / x1) * this.nativeHeight, Math.max(0, panY));
+        var scale = this.getLocalTransform().inverse().Scale;
+        const newPanX = Math.min((1 - 1 / scale) * this.nativeWidth, Math.max(0, panX));
+        const newPanY = Math.min((1 - 1 / scale) * this.nativeHeight, Math.max(0, panY));
         this.props.Document.SetNumber(KeyStore.PanX, this.isAnnotationOverlay ? newPanX : panX);
         this.props.Document.SetNumber(KeyStore.PanY, this.isAnnotationOverlay ? newPanY : panY);
     }
@@ -233,39 +222,18 @@ export class CollectionFreeFormView extends CollectionSubView {
 
     @action
     bringToFront(doc: Document) {
-        const { fieldKey: fieldKey, Document: Document } = this.props;
-
-        const value: Document[] = Document.GetList<Document>(fieldKey, []).slice();
-        value.sort((doc1, doc2) => {
-            if (doc1 === doc) {
-                return 1;
-            }
-            if (doc2 === doc) {
-                return -1;
-            }
+        this.props.Document.GetList<Document>(this.props.fieldKey, []).slice().sort((doc1, doc2) => {
+            if (doc1 === doc) return 1;
+            if (doc2 === doc) return -1;
             return doc1.GetNumber(KeyStore.ZIndex, 0) - doc2.GetNumber(KeyStore.ZIndex, 0);
-        }).map((doc, index) =>
-            doc.SetNumber(KeyStore.ZIndex, index + 1));
+        }).map((doc, index) => doc.SetNumber(KeyStore.ZIndex, index + 1));
         return doc;
     }
 
-    @computed get backgroundLayout(): string | undefined {
-        let field = this.props.Document.GetT(KeyStore.BackgroundLayout, TextField);
-        if (field && field !== FieldWaiting) {
-            return field.Data;
-        }
-    }
-    @computed get overlayLayout(): string | undefined {
-        let field = this.props.Document.GetT(KeyStore.OverlayLayout, TextField);
-        if (field && field !== FieldWaiting) {
-            return field.Data;
-        }
-    }
-
     focusDocument = (doc: Document) => {
-        let x = doc.GetNumber(KeyStore.X, 0) + doc.GetNumber(KeyStore.Width, 0) / 2;
-        let y = doc.GetNumber(KeyStore.Y, 0) + doc.GetNumber(KeyStore.Height, 0) / 2;
-        this.SetPan(x, y);
+        this.SetPan(
+            doc.GetNumber(KeyStore.X, 0) + doc.Width() / 2,
+            doc.GetNumber(KeyStore.Y, 0) + doc.Height() / 2);
         this.props.focus(this.props.Document);
     }
 
@@ -290,92 +258,112 @@ export class CollectionFreeFormView extends CollectionSubView {
 
     @computed
     get views() {
-        let pw = this.props.CollectionView.props
+        trace();
         var curPage = this.props.Document.GetNumber(KeyStore.CurPage, -1);
         let docviews = this.props.Document.GetList(this.props.fieldKey, [] as Document[]).filter(doc => doc).reduce((prev, doc) => {
             var page = doc.GetNumber(KeyStore.Page, -1);
-            var zoom = doc.GetNumber(KeyStore.Zoom, 1);
-            let zoomFade = 1;
-            var documentView = DocumentManager.Instance.getDocumentView(doc);
-            if (documentView) {
-                let transform = (documentView.props.ScreenToLocalTransform().scale(documentView.props.ContentScaling())).inverse();
-                var [sptX, sptY] = transform.transformPoint(0, 0);
-                let [bptX, bptY] = transform.transformPoint(documentView.props.PanelWidth(), documentView.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;
-                let fadeUp = .75 * 1800;
-                let fadeDown = .075 * 1800;
-                zoomFade = w < fadeDown || w > fadeUp ? Math.max(0, Math.min(1, 2 - (w < fadeDown ? fadeDown / w : w / fadeUp))) : 1;
-            }
             if (page === curPage || page === -1) {
-                prev.push(<CollectionFreeFormDocumentView key={doc.Id} {...this.getDocumentViewProps(doc)} zoomFade={zoomFade} />);
+                prev.push(<CollectionFreeFormDocumentView key={doc.Id} {...this.getDocumentViewProps(doc)} />);
             }
             return prev;
         }, [] as JSX.Element[]);
 
-        setTimeout(() => { // bcz: surely there must be a better way ....
-            this._selectOnLoaded = "";
-        }, 600);
+        setTimeout(() => this._selectOnLoaded = "", 600);// bcz: surely there must be a better way ....
 
         return docviews;
     }
 
-    @computed
-    get backgroundView() {
-        return !this.backgroundLayout ? (null) :
-            (<DocumentContentsView {...this.getDocumentViewProps(this.props.Document)}
-                layoutKey={KeyStore.BackgroundLayout} isTopMost={this.props.isTopMost} isSelected={returnFalse} select={emptyFunction} />);
-    }
-    @computed
-    get overlayView() {
-        return !this.overlayLayout ? (null) :
-            (<DocumentContentsView {...this.getDocumentViewProps(this.props.Document)}
-                layoutKey={KeyStore.OverlayLayout} isTopMost={this.props.isTopMost} isSelected={returnFalse} select={emptyFunction} />);
+    @action
+    onResize = (r: any) => {
+        this._pwidth = r.entry.width;
+        this._pheight = r.entry.height;
     }
-
-    @computed
-    get borderWidth() {
-        return this.isAnnotationOverlay ? 0 : COLLECTION_BORDER_WIDTH;
+    @action
+    onCursorMove = (e: React.PointerEvent) => {
+        super.setCursorPosition(this.getTransform().transformPoint(e.clientX, e.clientY));
     }
-    getTransform = (): Transform => this.props.ScreenToLocalTransform().translate(-this.borderWidth, -this.borderWidth).translate(-this.centeringShiftX, -this.centeringShiftY).transform(this.getLocalTransform());
+    getTransform = (): Transform => this.props.ScreenToLocalTransform().translate(-this.borderWidth, -this.borderWidth).translate(-this.centeringShiftX(), -this.centeringShiftY()).transform(this.getLocalTransform());
     getContainerTransform = (): Transform => this.props.ScreenToLocalTransform().translate(-this.borderWidth, -this.borderWidth);
-    getLocalTransform = (): Transform => Transform.Identity().scale(1 / this.scale).translate(this.panX, this.panY);
-    noScaling = () => 1;
+    getLocalTransform = (): Transform => Transform.Identity().scale(1 / this.zoomScaling()).translate(this.panX(), this.panY());
+    noScaling = returnOne;
     childViews = () => this.views;
 
     render() {
-        const [dx, dy] = [this.centeringShiftX, this.centeringShiftY];
-        const panx: number = -this.props.Document.GetNumber(KeyStore.PanX, 0);
-        const pany: number = -this.props.Document.GetNumber(KeyStore.PanY, 0);
-        const zoom: number = this.zoomScaling;// needs to be a variable outside of the <Measure> otherwise, reactions won't fire
-        const backgroundView = this.backgroundView; // needs to be a variable outside of the <Measure> otherwise, reactions won't fire
-        const overlayView = this.overlayView;// needs to be a variable outside of the <Measure> otherwise, reactions won't fire
-
+        trace();
+        const containerName = `collectionfreeformview${this.isAnnotationOverlay ? "-overlay" : "-container"}`;
         return (
-            <Measure onResize={(r: any) => runInAction(() => { this._pwidth = r.entry.width; this._pheight = r.entry.height; })}>
+            <Measure onResize={this.onResize}>
                 {({ measureRef }) => (
-                    <div className={`collectionfreeformview-measure`} ref={measureRef}>
-                        <div className={`collectionfreeformview${this.isAnnotationOverlay ? "-overlay" : "-container"}`}
-                            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} ref={this.createDropTarget}>
+                    <div className="collectionfreeformview-measure" ref={measureRef}>
+                        <div className={containerName} ref={this.createDropTarget} onWheel={this.onPointerWheel}
+                            onPointerDown={this.onPointerDown} onPointerMove={this.onCursorMove} onDrop={this.onDrop.bind(this)} onDragOver={this.onDragOver} >
                             <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(${zoom}, ${zoom}) translate(${panx}px, ${pany}px)` }}>
-                                    {backgroundView}
-                                    <CollectionFreeFormLinksView {...this.props}>
+                                <CollectionFreeFormViewPannableContents centeringShiftX={this.centeringShiftX} centeringShiftY={this.centeringShiftY}
+                                    zoomScaling={this.zoomScaling} panX={this.panX} panY={this.panY}>
+                                    <CollectionFreeFormBackgroundView {...this.getDocumentViewProps(this.props.Document)} />
+                                    <CollectionFreeFormLinksView {...this.props} key="freeformLinks">
                                         <InkingCanvas getScreenTransform={this.getTransform} Document={this.props.Document} >
                                             {this.childViews}
                                         </InkingCanvas>
                                     </CollectionFreeFormLinksView>
-                                    <CollectionFreeFormRemoteCursors {...this.props} />
-                                </div>
-                                {overlayView}
+                                    <CollectionFreeFormRemoteCursors {...this.props} key="remoteCursors" />
+                                </CollectionFreeFormViewPannableContents>
+                                <CollectionFreeFormOverlayView {...this.getDocumentViewProps(this.props.Document)} />
                             </MarqueeView>
                         </div>
                     </div>)}
             </Measure>
         );
     }
+}
+
+
+@observer
+class CollectionFreeFormOverlayView extends React.Component<DocumentViewProps> {
+    @computed get overlayView() {
+        let overlayLayout = this.props.Document.GetText(KeyStore.OverlayLayout, "");
+        return !overlayLayout ? (null) :
+            (<DocumentContentsView {...this.props} layoutKey={KeyStore.OverlayLayout}
+                isTopMost={this.props.isTopMost} isSelected={returnFalse} select={emptyFunction} />);
+    }
+    render() {
+        return this.overlayView;
+    }
+}
+
+@observer
+class CollectionFreeFormBackgroundView extends React.Component<DocumentViewProps> {
+    @computed get backgroundView() {
+        let backgroundLayout = this.props.Document.GetText(KeyStore.BackgroundLayout, "");
+        return !backgroundLayout ? (null) :
+            (<DocumentContentsView {...this.props} layoutKey={KeyStore.BackgroundLayout}
+                isTopMost={this.props.isTopMost} isSelected={returnFalse} select={emptyFunction} />);
+    }
+    render() {
+        return this.backgroundView;
+    }
+}
+
+interface CollectionFreeFormViewPannableContentsProps {
+    centeringShiftX: () => number;
+    centeringShiftY: () => number;
+    panX: () => number;
+    panY: () => number;
+    zoomScaling: () => number;
+}
+
+@observer
+class CollectionFreeFormViewPannableContents extends React.Component<CollectionFreeFormViewPannableContentsProps>{
+    render() {
+        const cenx = this.props.centeringShiftX();
+        const ceny = this.props.centeringShiftY();
+        const panx = -this.props.panX();
+        const pany = -this.props.panY();
+        const zoom = this.props.zoomScaling();// needs to be a variable outside of the <Measure> otherwise, reactions won't fire
+        return <div className="collectionfreeformview" style={{ transform: `translate(${cenx}px, ${ceny}px) scale(${zoom}, ${zoom}) translate(${panx}px, ${pany}px)` }}>
+            {this.props.children}
+        </div>;
+    }
 }
\ 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 783470286..96d59c831 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -147,7 +147,7 @@ export class MarqueeView extends React.Component<MarqueeViewProps>
                 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, -1);
-                d.SetText(KeyStore.Title, "" + d.GetNumber(KeyStore.Width, 0) + " " + d.GetNumber(KeyStore.Height, 0));
+                d.SetText(KeyStore.Title, "" + d.Width() + " " + d.Height());
                 return d;
             });
             let ink = this.props.container.props.Document.GetT(KeyStore.Ink, InkField);
@@ -211,8 +211,8 @@ export class MarqueeView extends React.Component<MarqueeViewProps>
             var z = doc.GetNumber(KeyStore.Zoom, 1);
             var x = doc.GetNumber(KeyStore.X, 0);
             var y = doc.GetNumber(KeyStore.Y, 0);
-            var w = doc.GetNumber(KeyStore.Width, 0) / z;
-            var h = doc.GetNumber(KeyStore.Height, 0) / z;
+            var w = doc.Width() / z;
+            var h = doc.Height() / z;
             if (this.intersectRect({ left: x, top: y, width: w, height: h }, selRect)) {
                 selection.push(doc);
             }
diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
index b00cefbf6..68e5a70fb 100644
--- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
+++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
@@ -9,17 +9,12 @@ import React = require("react");
 import { OmitKeys } from "../../../Utils";
 
 export interface CollectionFreeFormDocumentViewProps extends DocumentViewProps {
-    zoomFade: number;
 }
 
 @observer
 export class CollectionFreeFormDocumentView extends React.Component<CollectionFreeFormDocumentViewProps> {
     private _mainCont = React.createRef<HTMLDivElement>();
 
-    constructor(props: CollectionFreeFormDocumentViewProps) {
-        super(props);
-    }
-
     @computed
     get transform(): string {
         return `scale(${this.props.ContentScaling()}, ${this.props.ContentScaling()}) translate(${this.props.Document.GetNumber(KeyStore.X, 0)}px, ${this.props.Document.GetNumber(KeyStore.Y, 0)}px) scale(${this.zoom}, ${this.zoom}) `;
@@ -50,33 +45,41 @@ export class CollectionFreeFormDocumentView extends React.Component<CollectionFr
         this.props.Document.SetData(KeyStore.ZIndex, h, NumberField);
     }
 
-    contentScaling = () => this.nativeWidth > 0 ? this.width / this.nativeWidth : 1;
-
     getTransform = (): Transform =>
         this.props.ScreenToLocalTransform()
             .translate(-this.props.Document.GetNumber(KeyStore.X, 0), -this.props.Document.GetNumber(KeyStore.Y, 0))
             .scale(1 / this.contentScaling()).scale(1 / this.zoom)
 
+    contentScaling = () => this.nativeWidth > 0 ? this.width / this.nativeWidth : 1;
+    panelWidth = () => this.props.Document.GetBoolean(KeyStore.Minimized, false) ? 10 : this.props.PanelWidth();
+    panelHeight = () => this.props.Document.GetBoolean(KeyStore.Minimized, false) ? 10 : this.props.PanelHeight();
+
     @computed
     get docView() {
-        return <DocumentView {...this.docViewProps}
+        return <DocumentView {...OmitKeys(this.props, ['zoomFade'])}
             ContentScaling={this.contentScaling}
             ScreenToLocalTransform={this.getTransform}
             PanelWidth={this.panelWidth}
             PanelHeight={this.panelHeight}
         />;
     }
-    @computed
-    get docViewProps(): DocumentViewProps {
-        return (OmitKeys(this.props, ['zoomFade']));
-    }
-    panelWidth = () => this.props.Document.GetBoolean(KeyStore.Minimized, false) ? 10 : this.props.PanelWidth();
-    panelHeight = () => this.props.Document.GetBoolean(KeyStore.Minimized, false) ? 10 : this.props.PanelHeight();
 
     render() {
+        trace();
+        let zoomFade = 1;
+        // //var zoom = doc.GetNumber(KeyStore.Zoom, 1);
+        // let transform = (this.props.ScreenToLocalTransform().scale(this.props.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;
+        // let fadeUp = .75 * 1800;
+        // let fadeDown = .075 * 1800;
+        // zoomFade = w < fadeDown || w > fadeUp ? Math.max(0, Math.min(1, 2 - (w < fadeDown ? fadeDown / w : w / fadeUp))) : 1;
+
         return (
             <div className="collectionFreeFormDocumentView-container" ref={this._mainCont} style={{
-                opacity: this.props.zoomFade,
+                opacity: zoomFade,
                 transformOrigin: "left top",
                 transform: this.transform,
                 pointerEvents: "all",
diff --git a/src/client/views/nodes/DocumentView.scss b/src/client/views/nodes/DocumentView.scss
index 5071c9440..6383ac3f6 100644
--- a/src/client/views/nodes/DocumentView.scss
+++ b/src/client/views/nodes/DocumentView.scss
@@ -1,10 +1,11 @@
 @import "../globalCssVariables";
 
-.documentView-node .documentView-node-topMost {
+.documentView-node, .documentView-node-topMost {
   position: inherit;
   top: 0;
   left:0;
   background: $light-color; //overflow: hidden;
+  transform-origin: left top;
 
   &.minimized {
     width: 30px;
@@ -36,7 +37,8 @@
   height: 10px;
   width: 10px;
   border-radius: 2px;
-  background: $dark-color
+  background: $dark-color;
+  transform-origin: left top;
 }
 
 .minimized-box:hover {
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 20592894f..293fcc087 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -65,14 +65,12 @@ export function FakeJsxArgs(keys: string[], fields: string[] = []): JsxArgs {
     let Keys: { [name: string]: any } = {};
     let Fields: { [name: string]: any } = {};
     for (const key of keys) {
-        let fn = emptyFunction;
-        Object.defineProperty(fn, "name", { value: key + "Key" });
-        Keys[key] = fn;
+        Object.defineProperty(emptyFunction, "name", { value: key + "Key" });
+        Keys[key] = emptyFunction;
     }
     for (const field of fields) {
-        let fn = emptyFunction;
-        Object.defineProperty(fn, "name", { value: field });
-        Fields[field] = fn;
+        Object.defineProperty(emptyFunction, "name", { value: field });
+        Fields[field] = emptyFunction;
     }
     let args: JsxArgs = {
         Document: function Document() { },
@@ -85,18 +83,18 @@ export function FakeJsxArgs(keys: string[], fields: string[] = []): JsxArgs {
 
 @observer
 export class DocumentView extends React.Component<DocumentViewProps> {
-    private _mainCont = React.createRef<HTMLDivElement>();
-    public get ContentRef() {
-        return this._mainCont;
-    }
     private _downX: number = 0;
     private _downY: number = 0;
+    private _mainCont = React.createRef<HTMLDivElement>();
+    private _dropDisposer?: DragManager.DragDropDisposer;
+
+    public get ContentDiv() { return this._mainCont.current; }
     @computed get active(): boolean { return SelectionManager.IsSelected(this) || this.props.parentActive(); }
     @computed get topMost(): boolean { return this.props.isTopMost; }
     @computed get layout(): string { return this.props.Document.GetText(KeyStore.Layout, "<p>Error loading layout data</p>"); }
     @computed get layoutKeys(): Key[] { return this.props.Document.GetData(KeyStore.LayoutKeys, ListField, new Array<Key>()); }
     @computed get layoutFields(): Key[] { return this.props.Document.GetData(KeyStore.LayoutFields, ListField, new Array<Key>()); }
-    screenRect = (): ClientRect | DOMRect => this._mainCont.current ? this._mainCont.current.getBoundingClientRect() : new DOMRect();
+
     onPointerDown = (e: React.PointerEvent): void => {
         this._downX = e.clientX;
         this._downY = e.clientY;
@@ -118,11 +116,9 @@ export class DocumentView extends React.Component<DocumentViewProps> {
         }
     }
 
-    private dropDisposer?: DragManager.DragDropDisposer;
-
     componentDidMount() {
         if (this._mainCont.current) {
-            this.dropDisposer = DragManager.MakeDropTarget(this._mainCont.current, {
+            this._dropDisposer = DragManager.MakeDropTarget(this._mainCont.current, {
                 handlers: { drop: this.drop.bind(this) }
             });
         }
@@ -130,29 +126,26 @@ export class DocumentView extends React.Component<DocumentViewProps> {
     }
 
     componentDidUpdate() {
-        if (this.dropDisposer) {
-            this.dropDisposer();
+        if (this._dropDisposer) {
+            this._dropDisposer();
         }
         if (this._mainCont.current) {
-            this.dropDisposer = DragManager.MakeDropTarget(this._mainCont.current, {
+            this._dropDisposer = DragManager.MakeDropTarget(this._mainCont.current, {
                 handlers: { drop: this.drop.bind(this) }
             });
         }
     }
 
     componentWillUnmount() {
-        if (this.dropDisposer) {
-            this.dropDisposer();
+        if (this._dropDisposer) {
+            this._dropDisposer();
         }
         runInAction(() => DocumentManager.Instance.DocumentViews.splice(DocumentManager.Instance.DocumentViews.indexOf(this), 1));
     }
 
     startDragging(x: number, y: number, dropAliasOfDraggedDoc: boolean) {
         if (this._mainCont.current) {
-            const [left, top] = this.props
-                .ScreenToLocalTransform()
-                .inverse()
-                .transformPoint(0, 0);
+            const [left, top] = this.props.ScreenToLocalTransform().inverse().transformPoint(0, 0);
             let dragData = new DragManager.DocumentDragData([this.props.Document]);
             dragData.aliasOnDrop = dropAliasOfDraggedDoc;
             dragData.xOffset = x - left;
@@ -171,10 +164,7 @@ export class DocumentView extends React.Component<DocumentViewProps> {
         if (e.cancelBubble) {
             return;
         }
-        if (
-            Math.abs(this._downX - e.clientX) > 3 ||
-            Math.abs(this._downY - e.clientY) > 3
-        ) {
+        if (Math.abs(this._downX - e.clientX) > 3 || Math.abs(this._downY - e.clientY) > 3) {
             document.removeEventListener("pointermove", this.onPointerMove);
             document.removeEventListener("pointerup", this.onPointerUp);
             if (!this.topMost || e.buttons === 2 || e.altKey) {
@@ -188,22 +178,17 @@ export class DocumentView extends React.Component<DocumentViewProps> {
         document.removeEventListener("pointermove", this.onPointerMove);
         document.removeEventListener("pointerup", this.onPointerUp);
         e.stopPropagation();
-        if (!SelectionManager.IsSelected(this) &&
-            e.button !== 2 &&
-            Math.abs(e.clientX - this._downX) < 4 &&
-            Math.abs(e.clientY - this._downY) < 4
-        ) {
+        if (!SelectionManager.IsSelected(this) && e.button !== 2 &&
+            Math.abs(e.clientX - this._downX) < 4 && Math.abs(e.clientY - this._downY) < 4) {
             SelectionManager.SelectDoc(this, e.ctrlKey);
         }
     }
-    stopPropogation = (e: React.SyntheticEvent) => {
+    stopPropagation = (e: React.SyntheticEvent) => {
         e.stopPropagation();
     }
 
     deleteClicked = (): void => {
-        if (this.props.removeDocument) {
-            this.props.removeDocument(this.props.Document);
-        }
+        this.props.removeDocument && this.props.removeDocument(this.props.Document);
     }
 
     fieldsClicked = (e: React.MouseEvent): void => {
@@ -214,30 +199,20 @@ export class DocumentView extends React.Component<DocumentViewProps> {
     fullScreenClicked = (e: React.MouseEvent): void => {
         CollectionDockingView.Instance.OpenFullScreen((this.props.Document.GetPrototype() as Document).MakeDelegate());
         ContextMenu.Instance.clearItems();
-        ContextMenu.Instance.addItem({
-            description: "Close Full Screen",
-            event: this.closeFullScreenClicked
-        });
+        ContextMenu.Instance.addItem({ description: "Close Full Screen", event: this.closeFullScreenClicked });
         ContextMenu.Instance.displayMenu(e.pageX - 15, e.pageY - 15);
     }
 
     closeFullScreenClicked = (e: React.MouseEvent): void => {
         CollectionDockingView.Instance.CloseFullScreen();
         ContextMenu.Instance.clearItems();
-        ContextMenu.Instance.addItem({
-            description: "Full Screen",
-            event: this.fullScreenClicked
-        });
+        ContextMenu.Instance.addItem({ description: "Full Screen", event: this.fullScreenClicked });
         ContextMenu.Instance.displayMenu(e.pageX - 15, e.pageY - 15);
     }
 
     @action
     public minimize = (): void => {
-        this.props.Document.SetData(
-            KeyStore.Minimized,
-            true as boolean,
-            BooleanField
-        );
+        this.props.Document.SetBoolean(KeyStore.Minimized, true);
         SelectionManager.DeselectAll();
     }
 
@@ -253,9 +228,9 @@ export class DocumentView extends React.Component<DocumentViewProps> {
                 sourceDoc.GetTAsync(KeyStore.Prototype, Document).then(protoSrc =>
                     runInAction(() => {
                         let batch = UndoManager.StartBatch("document view drop");
-                        linkDoc.Set(KeyStore.Title, new TextField("New Link"));
-                        linkDoc.Set(KeyStore.LinkDescription, new TextField(""));
-                        linkDoc.Set(KeyStore.LinkTags, new TextField("Default"));
+                        linkDoc.SetText(KeyStore.Title, "New Link");
+                        linkDoc.SetText(KeyStore.LinkDescription, "");
+                        linkDoc.SetText(KeyStore.LinkTags, "Default");
 
                         let dstTarg = protoDest ? protoDest : destDoc;
                         let srcTarg = protoSrc ? protoSrc : sourceDoc;
@@ -286,11 +261,8 @@ export class DocumentView extends React.Component<DocumentViewProps> {
     }
 
     onDrop = (e: React.DragEvent) => {
-        if (e.isDefaultPrevented()) {
-            return;
-        }
         let text = e.dataTransfer.getData("text/plain");
-        if (text && text.startsWith("<div")) {
+        if (!e.isDefaultPrevented() && text && text.startsWith("<div")) {
             let oldLayout = this.props.Document.GetText(KeyStore.Layout, "");
             let layout = text.replace("{layout}", oldLayout);
             this.props.Document.SetText(KeyStore.Layout, layout);
@@ -302,145 +274,56 @@ export class DocumentView extends React.Component<DocumentViewProps> {
     @action
     onContextMenu = (e: React.MouseEvent): void => {
         e.stopPropagation();
-        let moved =
-            Math.abs(this._downX - e.clientX) > 3 ||
-            Math.abs(this._downY - e.clientY) > 3;
-        if (moved || e.isDefaultPrevented()) {
-            e.preventDefault();
+        e.preventDefault();
+        if (Math.abs(this._downX - e.clientX) > 3 || Math.abs(this._downY - e.clientY) > 3 ||
+            e.isDefaultPrevented()) {
             return;
         }
-        e.preventDefault();
 
-        if (!this.isMinimized()) {
-            ContextMenu.Instance.addItem({
-                description: "Minimize",
-                event: this.minimize
-            });
-        }
-        ContextMenu.Instance.addItem({
-            description: "Full Screen",
-            event: this.fullScreenClicked
-        });
-        ContextMenu.Instance.addItem({
-            description: "Fields",
-            event: this.fieldsClicked
-        });
-        ContextMenu.Instance.addItem({
-            description: "Center",
-            event: () => this.props.focus(this.props.Document)
-        });
-        ContextMenu.Instance.addItem({
-            description: "Open Right",
-            event: () =>
-                CollectionDockingView.Instance.AddRightSplit(this.props.Document)
-        });
-        ContextMenu.Instance.addItem({
-            description: "Copy URL",
-            event: () => {
-                Utils.CopyText(ServerUtils.prepend("/doc/" + this.props.Document.Id));
-            }
-        });
-        ContextMenu.Instance.addItem({
-            description: "Copy ID",
-            event: () => {
-                Utils.CopyText(this.props.Document.Id);
-            }
-        });
+        !this.isMinimized() && ContextMenu.Instance.addItem({ description: "Minimize", event: this.minimize });
+        ContextMenu.Instance.addItem({ description: "Full Screen", event: this.fullScreenClicked });
+        ContextMenu.Instance.addItem({ description: "Fields", event: this.fieldsClicked });
+        ContextMenu.Instance.addItem({ description: "Center", event: () => this.props.focus(this.props.Document) });
+        ContextMenu.Instance.addItem({ description: "Open Right", event: () => CollectionDockingView.Instance.AddRightSplit(this.props.Document) });
+        ContextMenu.Instance.addItem({ description: "Copy URL", event: () => Utils.CopyText(ServerUtils.prepend("/doc/" + this.props.Document.Id)) });
+        ContextMenu.Instance.addItem({ description: "Copy ID", event: () => Utils.CopyText(this.props.Document.Id) });
         //ContextMenu.Instance.addItem({ description: "Docking", event: () => this.props.Document.SetNumber(KeyStore.ViewType, CollectionViewType.Docking) })
-        ContextMenu.Instance.displayMenu(e.pageX - 15, e.pageY - 15);
-        if (!this.topMost) {
-            // DocumentViews should stop propagation of this event
-            e.stopPropagation();
-        }
-
-        ContextMenu.Instance.addItem({
-            description: "Delete",
-            event: this.deleteClicked
-        });
+        ContextMenu.Instance.addItem({ description: "Delete", event: this.deleteClicked });
         ContextMenu.Instance.displayMenu(e.pageX - 15, e.pageY - 15);
         SelectionManager.SelectDoc(this, e.ctrlKey);
     }
 
-    isMinimized = () => {
-        let field = this.props.Document.GetT(KeyStore.Minimized, BooleanField);
-        if (field && field !== FieldWaiting) {
-            return field.Data;
-        }
-    }
-
     @action
-    expand = () => {
-        this.props.Document.SetData(
-            KeyStore.Minimized,
-            false as boolean,
-            BooleanField
-        );
-    }
-
+    expand = () => this.props.Document.SetBoolean(KeyStore.Minimized, false)
+    isMinimized = () => this.props.Document.GetBoolean(KeyStore.Minimized, false);
     isSelected = () => SelectionManager.IsSelected(this);
+    select = (ctrlPressed: boolean) => SelectionManager.SelectDoc(this, ctrlPressed);
 
-    select = (ctrlPressed: boolean) => {
-        SelectionManager.SelectDoc(this, ctrlPressed);
-    }
-
-    @computed get nativeWidth(): number { return this.props.Document.GetNumber(KeyStore.NativeWidth, 0); }
-    @computed get nativeHeight(): number { return this.props.Document.GetNumber(KeyStore.NativeHeight, 0); }
-    @computed
-    get contents() {
-        return (<DocumentContentsView
-            {...this.props}
-            isSelected={this.isSelected}
-            select={this.select}
-            layoutKey={KeyStore.Layout}
-        />);
-    }
+    @computed get nativeWidth() { return this.props.Document.GetNumber(KeyStore.NativeWidth, 0); }
+    @computed get nativeHeight() { return this.props.Document.GetNumber(KeyStore.NativeHeight, 0); }
+    @computed get contents() { return (<DocumentContentsView {...this.props} isSelected={this.isSelected} select={this.select} layoutKey={KeyStore.Layout} />); }
 
     render() {
-        if (!this.props.Document) {
-            return null;
-        }
-
         var scaling = this.props.ContentScaling();
-        var nativeWidth = this.nativeWidth;
-        var nativeHeight = this.nativeHeight;
+        var nativeHeight = this.nativeHeight > 0 ? this.nativeHeight.toString() + "px" : "100%";
+        var nativeWidth = this.nativeWidth > 0 ? this.nativeWidth.toString() + "px" : "100%";
 
         if (this.isMinimized()) {
-            return (
-                <div
-                    className="minimized-box"
-                    ref={this._mainCont}
-                    style={{
-                        transformOrigin: "left top",
-                        transform: `scale(${scaling} , ${scaling})`
-                    }}
-                    onClick={this.expand}
-                    onDrop={this.onDrop}
-                    onPointerDown={this.onPointerDown}
-                />
-            );
-        } else {
-            var backgroundcolor = this.props.Document.GetText(
-                KeyStore.BackgroundColor,
-                ""
-            );
-            return (
-                <div
-                    className={`documentView-node${this.props.isTopMost ? "-topmost" : ""}`}
-                    ref={this._mainCont}
-                    style={{
-                        background: backgroundcolor,
-                        width: nativeWidth > 0 ? nativeWidth.toString() + "px" : "100%",
-                        height: nativeHeight > 0 ? nativeHeight.toString() + "px" : "100%",
-                        transformOrigin: "left top",
-                        transform: `scale(${scaling} , ${scaling})`
-                    }}
-                    onDrop={this.onDrop}
-                    onContextMenu={this.onContextMenu}
-                    onPointerDown={this.onPointerDown}
-                >
-                    {this.contents}
-                </div>
-            );
+            return <div className="minimized-box" ref={this._mainCont} onClick={this.expand} onDrop={this.onDrop}
+                style={{ transform: `scale(${scaling} , ${scaling})` }} onPointerDown={this.onPointerDown} />;
         }
+        return (
+            <div className={`documentView-node${this.props.isTopMost ? "-topmost" : ""}`}
+                ref={this._mainCont}
+                style={{
+                    background: this.props.Document.GetText(KeyStore.BackgroundColor, ""),
+                    width: nativeWidth, height: nativeHeight,
+                    transform: `scale(${scaling}, ${scaling})`
+                }}
+                onDrop={this.onDrop} onContextMenu={this.onContextMenu} onPointerDown={this.onPointerDown}
+            >
+                {this.contents}
+            </div>
+        );
     }
 }
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index 9bdbfbb5d..edd7f55fc 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -81,7 +81,7 @@ export class ImageBox extends React.Component<FieldViewProps> {
                     }
                     e.stopPropagation();
                 }
-            }))
+            }));
             // de.data.removeDocument()  bcz: need to implement
         }
     }
-- 
cgit v1.2.3-70-g09d2


From caecf2452c4af5caf8b298719d53274b6709c194 Mon Sep 17 00:00:00 2001
From: bob <bcz@cs.brown.edu>
Date: Tue, 16 Apr 2019 15:00:14 -0400
Subject: removed traces()played with image box stacking.

---
 .../collectionFreeForm/CollectionFreeFormView.tsx  |  2 --
 .../views/nodes/CollectionFreeFormDocumentView.tsx |  1 -
 src/client/views/nodes/ImageBox.scss               | 12 +++++++-
 src/client/views/nodes/ImageBox.tsx                | 34 +++++++++++++++++++---
 4 files changed, 41 insertions(+), 8 deletions(-)

(limited to 'src/client/views/nodes/CollectionFreeFormDocumentView.tsx')

diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 50f0a6164..3ae64d2c6 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -254,7 +254,6 @@ export class CollectionFreeFormView extends CollectionSubView {
 
     @computed
     get views() {
-        trace();
         var curPage = this.props.Document.GetNumber(KeyStore.CurPage, -1);
         let docviews = this.props.Document.GetList(this.props.fieldKey, [] as Document[]).filter(doc => doc).reduce((prev, doc) => {
             var page = doc.GetNumber(KeyStore.Page, -1);
@@ -280,7 +279,6 @@ export class CollectionFreeFormView extends CollectionSubView {
     }
 
     render() {
-        trace();
         const containerName = `collectionfreeformview${this.isAnnotationOverlay ? "-overlay" : "-container"}`;
         return (
             <Measure onResize={this.onResize}>
diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
index 68e5a70fb..8cf7a0dd2 100644
--- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
+++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
@@ -65,7 +65,6 @@ export class CollectionFreeFormDocumentView extends React.Component<CollectionFr
     }
 
     render() {
-        trace();
         let zoomFade = 1;
         // //var zoom = doc.GetNumber(KeyStore.Zoom, 1);
         // let transform = (this.props.ScreenToLocalTransform().scale(this.props.ContentScaling())).inverse();
diff --git a/src/client/views/nodes/ImageBox.scss b/src/client/views/nodes/ImageBox.scss
index 487038841..f4b3837ff 100644
--- a/src/client/views/nodes/ImageBox.scss
+++ b/src/client/views/nodes/ImageBox.scss
@@ -8,6 +8,16 @@
   max-height: 100%;
 }
 
+.imageBox-dot {
+    position:absolute;
+    bottom: 10;
+    left: 0;
+    border-radius: 10px;
+    width:20px;
+    height:20px;
+    background:gray;
+}
+
 .imageBox-cont img {
     height: 100%;
     width:100%;
@@ -18,4 +28,4 @@
   border: none;
   width: 100%;
   height: 100%;
-}
+}
\ No newline at end of file
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index edd7f55fc..ac54321d5 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -13,9 +13,12 @@ import React = require("react");
 import { Utils } from '../../../Utils';
 import { ListField } from '../../../fields/ListField';
 import { DragManager } from '../../util/DragManager';
-import { undoBatch } from '../../util/UndoManager';
+import { undoBatch, UndoManager } from '../../util/UndoManager';
 import { TextField } from '../../../fields/TextField';
 import { Document } from '../../../fields/Document';
+import { RouteStore } from '../../../server/RouteStore';
+import { ServerUtils } from '../../../server/ServerUtil';
+import { CollectionSubView } from '../collections/CollectionSubView';
 
 @observer
 export class ImageBox extends React.Component<FieldViewProps> {
@@ -43,7 +46,7 @@ export class ImageBox extends React.Component<FieldViewProps> {
     onLoad = (target: any) => {
         var h = this._imgRef.current!.naturalHeight;
         var w = this._imgRef.current!.naturalWidth;
-        this.props.Document.SetNumber(KeyStore.NativeHeight, this.props.Document.GetNumber(KeyStore.NativeWidth, 0) * h / w);
+        if (this._photoIndex == 0) this.props.Document.SetNumber(KeyStore.NativeHeight, this.props.Document.GetNumber(KeyStore.NativeWidth, 0) * h / w);
     }
 
     componentDidMount() {
@@ -61,6 +64,12 @@ export class ImageBox extends React.Component<FieldViewProps> {
     componentWillUnmount() {
     }
 
+    onDrop = (e: React.DragEvent) => {
+        e.stopPropagation();
+        e.preventDefault();
+        console.log("IMPLEMENT ME PLEASE")
+    }
+
 
     @undoBatch
     drop = (e: Event, de: DragManager.DropEvent) => {
@@ -139,6 +148,22 @@ export class ImageBox extends React.Component<FieldViewProps> {
         }
     }
 
+    @action
+    onDotDown(index: number) {
+        this._photoIndex = index;
+    }
+
+    dots(paths: string[]) {
+        let nativeWidth = this.props.Document.GetNumber(KeyStore.NativeWidth, 1);
+        let dist = Math.min(nativeWidth / paths.length, 40);
+        let left = (nativeWidth - paths.length * dist) / 2;
+        return paths.map((p, i) =>
+            <div className="imageBox-placer"  >
+                <div className="imageBox-dot" style={{ transform: `translate(${i * dist + left}px, 0px)` }} key={`i`} onPointerDown={(e: React.PointerEvent) => { e.stopPropagation(); this.onDotDown(i); }} />
+            </div>
+        )
+    }
+
     render() {
         let field = this.props.Document.Get(this.props.fieldKey);
         let paths: string[] = ["http://www.cs.brown.edu/~bcz/face.gif"];
@@ -147,8 +172,9 @@ export class ImageBox extends React.Component<FieldViewProps> {
         else if (field instanceof ListField) paths = field.Data.filter(val => val as ImageField).map(p => (p as ImageField).Data.href);
         let nativeWidth = this.props.Document.GetNumber(KeyStore.NativeWidth, 1);
         return (
-            <div className="imageBox-cont" onPointerDown={this.onPointerDown} ref={this.createDropTarget} onContextMenu={this.specificContextMenu}>
-                <img src={paths[0]} width={nativeWidth} alt="Image not found" ref={this._imgRef} onLoad={this.onLoad} />
+            <div className="imageBox-cont" onPointerDown={this.onPointerDown} onDrop={this.onDrop} ref={this.createDropTarget} onContextMenu={this.specificContextMenu}>
+                <img src={paths[Math.min(paths.length, this._photoIndex)]} style={{ objectFit: (this._photoIndex == 0 ? undefined : "contain") }} width={nativeWidth} alt="Image not found" ref={this._imgRef} onLoad={this.onLoad} />
+                {this.dots(paths)}
                 {this.lightbox(paths)}
             </div>);
     }
-- 
cgit v1.2.3-70-g09d2

