From f6c6220d92b8556615f3c17463ca5b0c7452b439 Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Thu, 28 Mar 2019 00:27:36 -0400
Subject: placeholder for drawing links.

---
 .../views/nodes/CollectionFreeFormDocumentView.tsx | 42 +++++++++++++++++++++-
 1 file changed, 41 insertions(+), 1 deletion(-)

(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 50dc5a619..ed3468400 100644
--- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
+++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
@@ -1,4 +1,4 @@
-import { computed, trace } from "mobx";
+import { computed, trace, reaction, runInAction, observable } from "mobx";
 import { observer } from "mobx-react";
 import { KeyStore } from "../../../fields/KeyStore";
 import { NumberField } from "../../../fields/NumberField";
@@ -6,6 +6,8 @@ import { Transform } from "../../util/Transform";
 import { DocumentView, DocumentViewProps } from "./DocumentView";
 import "./DocumentView.scss";
 import React = require("react");
+import { Document } from "../../../fields/Document";
+import { DocumentManager } from "../../util/DocumentManager";
 
 
 @observer
@@ -67,8 +69,46 @@ export class CollectionFreeFormDocumentView extends React.Component<DocumentView
             ScreenToLocalTransform={this.getTransform}
         />
     }
+    @observable _docView1: DocumentView | null = null;
+    @observable _docView2: DocumentView | null = null;
+
+    componentDidMount() {
+        reaction(() => {
+            let linkFrom = this.props.Document.GetT(KeyStore.LinkedFromDocs, Document);
+            let linkTo = this.props.Document.GetT(KeyStore.LinkedToDocs, Document);
+            let docView1: DocumentView | null = null;
+            let docView2: DocumentView | null = null;
+            if (linkFrom instanceof Document && linkTo instanceof Document) {
+                docView1 = DocumentManager.Instance.getDocumentView(linkFrom);
+                docView2 = DocumentManager.Instance.getDocumentView(linkTo);
+            }
+            return [docView1, docView2];
+        }, (vals) => runInAction(() => {
+            this._docView1 = vals[0];
+            this._docView2 = vals[1];
+        }), { fireImmediately: true });
+    }
 
     render() {
+        if (this._docView1 != null && this._docView2 != null) {
+            let doc1 = this._docView1.props.Document;
+            let doc2 = this._docView2.props.Document;
+            let x1 = doc1.GetNumber(KeyStore.X, 0) + doc1.GetNumber(KeyStore.Width, 0) / 2;
+            let y1 = doc1.GetNumber(KeyStore.Y, 0) + doc1.GetNumber(KeyStore.Height, 0) / 2;
+            let x2 = doc2.GetNumber(KeyStore.X, 0) + doc2.GetNumber(KeyStore.Width, 0) / 2;
+            let y2 = doc2.GetNumber(KeyStore.Y, 0) + doc2.GetNumber(KeyStore.Height, 0) / 2;
+            let lx = Math.min(x1, x2);
+            let ly = Math.min(y1, y2);
+            let w = Math.max(x1, x2) - lx;
+            let h = Math.max(y1, y2) - ly;
+            let unflipped = (x1 == lx && y1 == ly) || (x2 == lx && y2 == ly);
+            return (
+                <div style={{ width: w, height: h, transform: `translate(${lx}px, ${ly}px)`, position: "absolute" }}>
+                    <svg width="5000" height="5000">
+                        <line x1="0" x2={`${w}`} y1={`${unflipped ? 0 : h}`} y2={`${unflipped ? h : 0}`} width="4" style={{ stroke: "black", strokeWidth: "5" }}  ></line>
+                    </svg>
+                </div>);
+        }
         return (
             <div className="collectionFreeFormDocumentView-container" ref={this._mainCont} style={{
                 transformOrigin: "left top",
-- 
cgit v1.2.3-70-g09d2


From b2558d67608ae20f291c6a1fdbaf1ed09b8c91d2 Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Thu, 28 Mar 2019 10:04:28 -0400
Subject: made links show up on collections

---
 src/client/util/DocumentManager.ts                 | 27 ++++++--
 .../views/collections/CollectionFreeFormView.tsx   | 72 ++++++++++++++++++++--
 .../views/nodes/CollectionFreeFormDocumentView.tsx | 38 ------------
 src/client/views/nodes/DocumentView.tsx            |  2 -
 4 files changed, 89 insertions(+), 50 deletions(-)

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

diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts
index 03df11ad7..5bc16343e 100644
--- a/src/client/util/DocumentManager.ts
+++ b/src/client/util/DocumentManager.ts
@@ -35,12 +35,6 @@ export class DocumentManager {
         DocumentManager.Instance.DocumentViews.map(view => {
             let doc = view.props.Document;
             // if (view.props.ContainingCollectionView instanceof CollectionFreeFormView) {
-            //     if (Object.is(doc, toFind)) {
-            //         toReturn = view;
-            //         return;
-            //     }
-            // }
-
 
             if (Object.is(doc, toFind)) {
                 toReturn = view;
@@ -52,6 +46,27 @@ export class DocumentManager {
             }
         })
 
+        return (toReturn);
+    }
+    public getDocumentViews(toFind: Document): DocumentView[] {
+
+        let toReturn: DocumentView[] = [];
+
+        //gets document view that is in a freeform canvas collection
+        DocumentManager.Instance.DocumentViews.map(view => {
+            let doc = view.props.Document;
+            // if (view.props.ContainingCollectionView instanceof CollectionFreeFormView) {
+
+            if (Object.is(doc, toFind)) {
+                toReturn.push(view);
+            } else {
+                let docSrc = doc.GetT(KeyStore.Prototype, Document);
+                if (docSrc && docSrc != FieldWaiting && Object.is(docSrc, toFind)) {
+                    toReturn.push(view);
+                }
+            }
+        })
+
         return (toReturn);
     }
 }
\ No newline at end of file
diff --git a/src/client/views/collections/CollectionFreeFormView.tsx b/src/client/views/collections/CollectionFreeFormView.tsx
index 1eab3e475..d75c53b7e 100644
--- a/src/client/views/collections/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/CollectionFreeFormView.tsx
@@ -1,7 +1,7 @@
-import { action, computed, observable } from "mobx";
+import { action, computed, observable, reaction, runInAction } from "mobx";
 import { observer } from "mobx-react";
 import { Document } from "../../../fields/Document";
-import { FieldWaiting } from "../../../fields/Field";
+import { FieldWaiting, Field } from "../../../fields/Field";
 import { KeyStore } from "../../../fields/KeyStore";
 import { ListField } from "../../../fields/ListField";
 import { TextField } from "../../../fields/TextField";
@@ -11,14 +11,16 @@ import { undoBatch } from "../../util/UndoManager";
 import { InkingCanvas } from "../InkingCanvas";
 import { CollectionFreeFormDocumentView } from "../nodes/CollectionFreeFormDocumentView";
 import { DocumentContentsView } from "../nodes/DocumentContentsView";
-import { DocumentViewProps } from "../nodes/DocumentView";
+import { DocumentViewProps, DocumentView } from "../nodes/DocumentView";
 import "./CollectionFreeFormView.scss";
 import { COLLECTION_BORDER_WIDTH } from "./CollectionView";
-import { CollectionViewBase } from "./CollectionViewBase";
+import { CollectionViewBase, CollectionViewProps } from "./CollectionViewBase";
 import { MarqueeView } from "./MarqueeView";
 import { PreviewCursor } from "./PreviewCursor";
 import React = require("react");
 import v5 = require("uuid/v5");
+import { DocumentManager } from "../../util/DocumentManager";
+import { Utils } from "../../../Utils";
 
 @observer
 export class CollectionFreeFormView extends CollectionViewBase {
@@ -360,6 +362,7 @@ export class CollectionFreeFormView extends CollectionViewBase {
                     <InkingCanvas getScreenTransform={this.getTransform} Document={this.props.Document} />
                     <PreviewCursor container={this} addLiveTextDocument={this.addLiveTextBox} getTransform={this.getTransform} />
                     {this.views}
+                    <LinksView {...this.props} />
                     {super.getCursors().map(entry => {
                         if (entry.Data.length > 0) {
                             let id = entry.Data[0][0];
@@ -411,4 +414,65 @@ export class CollectionFreeFormView extends CollectionViewBase {
             </div>
         );
     }
+}
+
+@observer
+export class LinksView extends React.Component<CollectionViewProps> {
+    private _mainCont = React.createRef<HTMLDivElement>();
+
+    constructor(props: CollectionViewProps) {
+        super(props);
+    }
+
+    @observable _pairs: { a: DocumentView, b: DocumentView }[] = [];
+
+    findPairs() {
+        return DocumentManager.Instance.DocumentViews.filter(dv => dv.props.ContainingCollectionView && dv.props.ContainingCollectionView.props.Document === this.props.Document).reduce((pairs, dv) => {
+            let linksList = dv.props.Document.GetT(KeyStore.LinkedToDocs, ListField);
+            if (linksList && linksList != FieldWaiting && linksList.Data.length) {
+                pairs.push(...linksList.Data.reduce((pairs, link) => {
+                    if (link instanceof Document) {
+                        let linkToDoc = link.GetT(KeyStore.LinkedToDocs, Document);
+                        if (linkToDoc && linkToDoc != FieldWaiting) {
+                            DocumentManager.Instance.getDocumentViews(linkToDoc).map(docView1 =>
+                                pairs.push({ a: dv, b: docView1 })
+                            )
+                        }
+                    }
+                    return pairs;
+                }, [] as { a: DocumentView, b: DocumentView }[]));
+            }
+            return pairs;
+        }, [] as { a: DocumentView, b: DocumentView }[]);
+    }
+    componentDidMount() {
+        reaction(() => this.findPairs()
+            , (pairs) => runInAction(() => this._pairs = pairs));
+    }
+
+    render() {
+        if (!this._pairs.length)
+            return (null);
+        return <div>
+            {this._pairs.map(pair => {
+                let doc1 = pair.a.props.Document;
+                let doc2 = pair.b.props.Document;
+                let x1 = doc1.GetNumber(KeyStore.X, 0) + doc1.GetNumber(KeyStore.Width, 0) / 2;
+                let y1 = doc1.GetNumber(KeyStore.Y, 0) + doc1.GetNumber(KeyStore.Height, 0) / 2;
+                let x2 = doc2.GetNumber(KeyStore.X, 0) + doc2.GetNumber(KeyStore.Width, 0) / 2;
+                let y2 = doc2.GetNumber(KeyStore.Y, 0) + doc2.GetNumber(KeyStore.Height, 0) / 2;
+                let lx = Math.min(x1, x2);
+                let ly = Math.min(y1, y2);
+                let w = Math.max(x1, x2) - lx;
+                let h = Math.max(y1, y2) - ly;
+                let unflipped = (x1 == lx && y1 == ly) || (x2 == lx && y2 == ly);
+                return (
+                    <div key={Utils.GenerateGuid()} style={{ width: w, height: h, transform: `translate(${lx}px, ${ly}px)`, position: "absolute" }}>
+                        <svg width="5000" height="5000">
+                            <line x1="0" x2={`${w}`} y1={`${unflipped ? 0 : h}`} y2={`${unflipped ? h : 0}`} width="4" style={{ stroke: "black", strokeWidth: "5" }}  ></line>
+                        </svg>
+                    </div>);
+            })}
+        </div>
+    }
 }
\ No newline at end of file
diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
index ed3468400..7f951864e 100644
--- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
+++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
@@ -69,46 +69,8 @@ export class CollectionFreeFormDocumentView extends React.Component<DocumentView
             ScreenToLocalTransform={this.getTransform}
         />
     }
-    @observable _docView1: DocumentView | null = null;
-    @observable _docView2: DocumentView | null = null;
-
-    componentDidMount() {
-        reaction(() => {
-            let linkFrom = this.props.Document.GetT(KeyStore.LinkedFromDocs, Document);
-            let linkTo = this.props.Document.GetT(KeyStore.LinkedToDocs, Document);
-            let docView1: DocumentView | null = null;
-            let docView2: DocumentView | null = null;
-            if (linkFrom instanceof Document && linkTo instanceof Document) {
-                docView1 = DocumentManager.Instance.getDocumentView(linkFrom);
-                docView2 = DocumentManager.Instance.getDocumentView(linkTo);
-            }
-            return [docView1, docView2];
-        }, (vals) => runInAction(() => {
-            this._docView1 = vals[0];
-            this._docView2 = vals[1];
-        }), { fireImmediately: true });
-    }
 
     render() {
-        if (this._docView1 != null && this._docView2 != null) {
-            let doc1 = this._docView1.props.Document;
-            let doc2 = this._docView2.props.Document;
-            let x1 = doc1.GetNumber(KeyStore.X, 0) + doc1.GetNumber(KeyStore.Width, 0) / 2;
-            let y1 = doc1.GetNumber(KeyStore.Y, 0) + doc1.GetNumber(KeyStore.Height, 0) / 2;
-            let x2 = doc2.GetNumber(KeyStore.X, 0) + doc2.GetNumber(KeyStore.Width, 0) / 2;
-            let y2 = doc2.GetNumber(KeyStore.Y, 0) + doc2.GetNumber(KeyStore.Height, 0) / 2;
-            let lx = Math.min(x1, x2);
-            let ly = Math.min(y1, y2);
-            let w = Math.max(x1, x2) - lx;
-            let h = Math.max(y1, y2) - ly;
-            let unflipped = (x1 == lx && y1 == ly) || (x2 == lx && y2 == ly);
-            return (
-                <div style={{ width: w, height: h, transform: `translate(${lx}px, ${ly}px)`, position: "absolute" }}>
-                    <svg width="5000" height="5000">
-                        <line x1="0" x2={`${w}`} y1={`${unflipped ? 0 : h}`} y2={`${unflipped ? h : 0}`} width="4" style={{ stroke: "black", strokeWidth: "5" }}  ></line>
-                    </svg>
-                </div>);
-        }
         return (
             <div className="collectionFreeFormDocumentView-container" ref={this._mainCont} style={{
                 transformOrigin: "left top",
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 108bd8e53..769d893f3 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -255,8 +255,6 @@ export class DocumentView extends React.Component<DocumentViewProps> {
                     linkDoc.Set(KeyStore.LinkedFromDocs, srcTarg);
                     dstTarg.GetOrCreateAsync(KeyStore.LinkedFromDocs, ListField, field => { (field as ListField<Document>).Data.push(linkDoc) })
                     srcTarg.GetOrCreateAsync(KeyStore.LinkedToDocs, ListField, field => { (field as ListField<Document>).Data.push(linkDoc) })
-                    if (this.props.AddDocument)
-                        this.props.AddDocument(linkDoc, false);
                 }))
             )
             e.stopPropagation();
-- 
cgit v1.2.3-70-g09d2


From 2ac86b53d28abb8be2f3abd501b801e543973e28 Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Sun, 31 Mar 2019 22:45:43 -0400
Subject: restructured inkingCanvas and linksViews

---
 src/client/views/InkingCanvas.scss                 | 164 +++------------------
 src/client/views/InkingCanvas.tsx                  | 121 +++++++--------
 src/client/views/InkingControl.scss                | 135 +++++++++++++++++
 src/client/views/InkingControl.tsx                 |   3 +-
 .../CollectionFreeFormLinksView.scss               |   3 +
 .../CollectionFreeFormLinksView.tsx                |   9 +-
 .../collectionFreeForm/CollectionFreeFormView.scss |  10 --
 .../collectionFreeForm/CollectionFreeFormView.tsx  |  10 +-
 .../views/nodes/CollectionFreeFormDocumentView.tsx |   6 +-
 src/client/views/nodes/PDFBox.tsx                  |  10 +-
 10 files changed, 233 insertions(+), 238 deletions(-)
 create mode 100644 src/client/views/InkingControl.scss

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

diff --git a/src/client/views/InkingCanvas.scss b/src/client/views/InkingCanvas.scss
index e79b146b9..6d7821cd2 100644
--- a/src/client/views/InkingCanvas.scss
+++ b/src/client/views/InkingCanvas.scss
@@ -1,149 +1,25 @@
 @import "global_variables";
-.inking-canvas {
+
+.inkingCanvas-paths, .inkingCanvas-paths-none {
     position: absolute;
     top: -50000px;
-    left: -50000px; // z-index: 99; //overlays ink on top of everything
-    svg {
-        position:absolute;
-        width: 100000px;
-        height: 100000px;
-        .highlight {
-            mix-blend-mode: multiply;
-        }
-    }
+    left: -50000px;
+    width: 100000px;
+    height: 100000px;
+    //z-index: 10000; // z-index: 99; //overlays ink on top of everything but that messes up blending and events don't propagate down to nested collections
+    .highlight {
+        mix-blend-mode: multiply;
+    }
+    .inkingCanvas-children {
+      transform: translate(50000px, 50000px);
+      pointer-events: none;
+    }
+    cursor:"crosshair";
+    pointer-events: auto;
+    
+}
+.inkingCanvas-paths-none {
+    pointer-events: none;
+    cursor: "arrow";
 }
 
-.inking-control {
-    position: absolute;
-    left: 70px;
-    bottom: 70px;
-    margin: 0;
-    padding: 0;
-    display: flex;
-    label,
-    input,
-    option {
-        font-size: 12px;
-    }
-    input[type="range"] {
-        -webkit-appearance: none;
-        background-color: transparent;
-        vertical-align: middle;
-        margin-top: 8px;
-        &:focus {
-            outline: none;
-        }
-        &::-webkit-slider-runnable-track {
-            width: 100%;
-            height: 3px;
-            border-radius: 1.5px;
-            cursor: pointer;
-            background: $intermediate-color;
-        }
-        &::-webkit-slider-thumb {
-            height: 12px;
-            width: 12px;
-            border: 1px solid $intermediate-color;
-            border-radius: 6px;
-            background: $light-color;
-            cursor: pointer;
-            -webkit-appearance: none;
-            margin-top: -4px;
-        }
-        &::-moz-range-track {
-            width: 100%;
-            height: 3px;
-            border-radius: 1.5px;
-            cursor: pointer;
-            background: $light-color;
-        }
-        &::-moz-range-thumb {
-            height: 12px;
-            width: 12px;
-            border: 1px solid $intermediate-color;
-            border-radius: 6px;
-            background: $light-color;
-            cursor: pointer;
-            -webkit-appearance: none;
-            margin-top: -4px;
-        }
-    }
-    input[type="text"] {
-        border: none;
-        padding: 0 0px;
-        background: transparent;
-        color: $dark-color;
-        font-size: 12px;
-        margin-top: 4px;
-    }
-    .ink-panel {
-        margin: 6px 12px 6px 0;
-        height: 30px;
-        vertical-align: middle;
-        line-height: 36px;
-        padding: 0 10px;
-        color: $intermediate-color;
-        &:first {
-            margin-top: 0;
-        }
-    }
-    .ink-tools {
-        display: flex;
-        background-color: transparent;
-        border-radius: 0;
-        padding: 0;
-        button {
-            height: 36px;
-            padding: 0px;
-            padding-bottom: 3px;
-            margin-left: 10px;
-            background-color: transparent;
-            color: $intermediate-color;
-        }
-        button:hover {
-            transform: scale(1.15);
-        }
-    }
-    .ink-size {
-        display: flex;
-        justify-content: space-between;
-        input[type="text"] {
-            width: 42px;
-        }
-        >* {
-            margin-right: 6px;
-            &:last-child {
-                margin-right: 0;
-            }
-        }
-    }
-    .ink-color {
-        display: flex;
-        position: relative;
-        padding-right: 0;
-        label {
-            margin-right: 6px;
-        }
-        .ink-color-display {
-            border-radius: 11px;
-            width: 22px;
-            height: 22px;
-            margin-top: 6px;
-            cursor: pointer;
-            text-align: center; //   span {
-            //     color: $light-color;
-            //     font-size: 8px;
-            //     user-select: none;
-            //   }
-        }
-        .ink-color-picker {
-            background-color: $light-color;
-            border-radius: 5px;
-            padding: 12px;
-            position: absolute;
-            bottom: 36px;
-            left: -3px;
-            box-shadow: $intermediate-color 0.2vw 0.2vw 0.8vw;
-        }
-    }
-}
\ No newline at end of file
diff --git a/src/client/views/InkingCanvas.tsx b/src/client/views/InkingCanvas.tsx
index 8fb74ec48..a971264b9 100644
--- a/src/client/views/InkingCanvas.tsx
+++ b/src/client/views/InkingCanvas.tsx
@@ -57,51 +57,62 @@ export class InkingCanvas extends React.Component<InkCanvasProps> {
     }
 
     @action
-    handleMouseDown = (e: React.PointerEvent): void => {
-        if (e.button != 0 ||
+    onPointerDown = (e: React.PointerEvent): void => {
+        this._isDrawing = false;
+        if (e.button != 0 || e.altKey || e.ctrlKey ||
             InkingControl.Instance.selectedTool === InkTool.None) {
             return;
         }
-        e.stopPropagation()
-        if (InkingControl.Instance.selectedTool === InkTool.Eraser) {
-            return
-        }
-        const point = this.relativeCoordinatesForEvent(e);
-
-        // start the new line, saves a uuid to represent the field of the stroke
-        this._idGenerator = Utils.GenerateGuid();
-        this.inkData.set(this._idGenerator,
-            {
-                pathData: [point],
-                color: InkingControl.Instance.selectedColor,
-                width: InkingControl.Instance.selectedWidth,
-                tool: InkingControl.Instance.selectedTool,
-                page: this.props.Document.GetNumber(KeyStore.CurPage, -1)
-            });
+        document.addEventListener("pointermove", this.onPointerMove, true);
+        document.addEventListener("pointerup", this.onPointerUp, true);
+        e.stopPropagation();
+
         this._isDrawing = true;
+        if (InkingControl.Instance.selectedTool != InkTool.Eraser) {
+            const point = this.relativeCoordinatesForEvent(e.clientX, e.clientY);
+
+            // start the new line, saves a uuid to represent the field of the stroke
+            this._idGenerator = Utils.GenerateGuid();
+            this.inkData.set(this._idGenerator,
+                {
+                    pathData: [point],
+                    color: InkingControl.Instance.selectedColor,
+                    width: InkingControl.Instance.selectedWidth,
+                    tool: InkingControl.Instance.selectedTool,
+                    page: this.props.Document.GetNumber(KeyStore.CurPage, -1)
+                });
+        }
     }
 
-    @action
-    handleMouseMove = (e: React.PointerEvent): void => {
-        if (!this._isDrawing ||
-            InkingControl.Instance.selectedTool === InkTool.None) {
-            return;
+    onPointerUp = (e: PointerEvent): void => {
+        if (this._isDrawing) {
+            document.removeEventListener("pointermove", this.onPointerMove);
+            document.removeEventListener("pointerup", this.onPointerUp);
+            this._isDrawing = false;
+            e.stopPropagation();
         }
-        e.stopPropagation()
-        if (InkingControl.Instance.selectedTool === InkTool.Eraser) {
-            return
-        }
-        const point = this.relativeCoordinatesForEvent(e);
+    }
 
-        // add points to new line as it is being drawn
-        let data = this.inkData;
-        let strokeData = data.get(this._idGenerator);
-        if (strokeData) {
-            strokeData.pathData.push(point);
-            data.set(this._idGenerator, strokeData);
+    @action
+    onPointerMove = (e: PointerEvent): void => {
+        if (this._isDrawing) {
+            e.stopPropagation()
+            e.preventDefault();
+            if (InkingControl.Instance.selectedTool === InkTool.Eraser) {
+                return
+            }
+            const point = this.relativeCoordinatesForEvent(e.clientX, e.clientY);
+
+            // add points to new line as it is being drawn
+            let data = this.inkData;
+            let strokeData = data.get(this._idGenerator);
+            if (strokeData) {
+                strokeData.pathData.push(point);
+                data.set(this._idGenerator, strokeData);
+            }
+
+            this.inkData = data;
         }
-
-        this.inkData = data;
     }
 
     @action
@@ -109,8 +120,8 @@ export class InkingCanvas extends React.Component<InkCanvasProps> {
         this._isDrawing = false;
     }
 
-    relativeCoordinatesForEvent = (e: React.MouseEvent): { x: number, y: number } => {
-        let [x, y] = this.props.getScreenTransform().transformPoint(e.clientX, e.clientY);
+    relativeCoordinatesForEvent = (ex: number, ey: number): { x: number, y: number } => {
+        let [x, y] = this.props.getScreenTransform().transformPoint(ex, ey);
         x += InkingCanvas.InkOffset;
         y += InkingCanvas.InkOffset;
         return { x, y };
@@ -124,32 +135,9 @@ export class InkingCanvas extends React.Component<InkCanvasProps> {
     }
 
     render() {
-        // styling for cursor
-        let canvasStyle = {};
-        if (InkingControl.Instance.selectedTool === InkTool.None) {
-            canvasStyle = { pointerEvents: "none" };
-        } else {
-            canvasStyle = { pointerEvents: "auto", cursor: "crosshair" };
-        }
-
-        // get data from server
-        // let inkField = this.props.Document.GetT(KeyStore.Ink, InkField);
-        // if (!inkField || inkField == FieldWaiting) {
-        //     return (<div className="inking-canvas" style={canvasStyle}
-        //         onMouseDown={this.handleMouseDown} onMouseMove={this.handleMouseMove} >
-        //         <svg>
-        //         </svg>
-        //     </div >)
-        // }
-
-        let lines = this.inkData;
-
         // parse data from server
-        let paths: Array<JSX.Element> = []
         let curPage = this.props.Document.GetNumber(KeyStore.CurPage, -1)
-        Array.from(lines).map(item => {
-            let id = item[0];
-            let strokeData = item[1];
+        let paths = Array.from(this.inkData).reduce((paths, [id, strokeData]) => {
             if (strokeData.page == -1 || strokeData.page == curPage)
                 paths.push(<InkingStroke key={id} id={id}
                     line={strokeData.pathData}
@@ -157,13 +145,16 @@ export class InkingCanvas extends React.Component<InkCanvasProps> {
                     width={strokeData.width}
                     tool={strokeData.tool}
                     deleteCallback={this.removeLine} />)
-        })
+            return paths;
+        }, [] as JSX.Element[]);
+        let svgCanvasStyle = InkingControl.Instance.selectedTool == InkTool.None ? "-none" : "";
 
         return (
-            <div className="inking-canvas" style={canvasStyle} onPointerDown={this.handleMouseDown} onPointerMove={this.handleMouseMove} >
-                <svg>
+            <div className="inkingCanvas" >
+                <svg className={`inkingCanvas-paths${svgCanvasStyle}`} onPointerDown={this.onPointerDown} >
                     {paths}
                 </svg>
+                {this.props.children}
             </div >
         )
     }
diff --git a/src/client/views/InkingControl.scss b/src/client/views/InkingControl.scss
new file mode 100644
index 000000000..0d8fd8784
--- /dev/null
+++ b/src/client/views/InkingControl.scss
@@ -0,0 +1,135 @@
+@import "global_variables";
+.inking-control {
+    position: absolute;
+    left: 70px;
+    bottom: 70px;
+    margin: 0;
+    padding: 0;
+    display: flex;
+    label,
+    input,
+    option {
+        font-size: 12px;
+    }
+    input[type="range"] {
+        -webkit-appearance: none;
+        background-color: transparent;
+        vertical-align: middle;
+        margin-top: 8px;
+        &:focus {
+            outline: none;
+        }
+        &::-webkit-slider-runnable-track {
+            width: 100%;
+            height: 3px;
+            border-radius: 1.5px;
+            cursor: pointer;
+            background: $intermediate-color;
+        }
+        &::-webkit-slider-thumb {
+            height: 12px;
+            width: 12px;
+            border: 1px solid $intermediate-color;
+            border-radius: 6px;
+            background: $light-color;
+            cursor: pointer;
+            -webkit-appearance: none;
+            margin-top: -4px;
+        }
+        &::-moz-range-track {
+            width: 100%;
+            height: 3px;
+            border-radius: 1.5px;
+            cursor: pointer;
+            background: $light-color;
+        }
+        &::-moz-range-thumb {
+            height: 12px;
+            width: 12px;
+            border: 1px solid $intermediate-color;
+            border-radius: 6px;
+            background: $light-color;
+            cursor: pointer;
+            -webkit-appearance: none;
+            margin-top: -4px;
+        }
+    }
+    input[type="text"] {
+        border: none;
+        padding: 0 0px;
+        background: transparent;
+        color: $dark-color;
+        font-size: 12px;
+        margin-top: 4px;
+    }
+    .ink-panel {
+        margin: 6px 12px 6px 0;
+        height: 30px;
+        vertical-align: middle;
+        line-height: 36px;
+        padding: 0 10px;
+        color: $intermediate-color;
+        &:first {
+            margin-top: 0;
+        }
+    }
+    .ink-tools {
+        display: flex;
+        background-color: transparent;
+        border-radius: 0;
+        padding: 0;
+        button {
+            height: 36px;
+            padding: 0px;
+            padding-bottom: 3px;
+            margin-left: 10px;
+            background-color: transparent;
+            color: $intermediate-color;
+        }
+        button:hover {
+            transform: scale(1.15);
+        }
+    }
+    .ink-size {
+        display: flex;
+        justify-content: space-between;
+        input[type="text"] {
+            width: 42px;
+        }
+        >* {
+            margin-right: 6px;
+            &:last-child {
+                margin-right: 0;
+            }
+        }
+    }
+    .ink-color {
+        display: flex;
+        position: relative;
+        padding-right: 0;
+        label {
+            margin-right: 6px;
+        }
+        .ink-color-display {
+            border-radius: 11px;
+            width: 22px;
+            height: 22px;
+            margin-top: 6px;
+            cursor: pointer;
+            text-align: center; //   span {
+            //     color: $light-color;
+            //     font-size: 8px;
+            //     user-select: none;
+            //   }
+        }
+        .ink-color-picker {
+            background-color: $light-color;
+            border-radius: 5px;
+            padding: 12px;
+            position: absolute;
+            bottom: 36px;
+            left: -3px;
+            box-shadow: $intermediate-color 0.2vw 0.2vw 0.8vw;
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/client/views/InkingControl.tsx b/src/client/views/InkingControl.tsx
index eb2172d03..c1519dff8 100644
--- a/src/client/views/InkingControl.tsx
+++ b/src/client/views/InkingControl.tsx
@@ -2,10 +2,9 @@ import { observable, action, computed } from "mobx";
 
 import { CirclePicker, ColorResult } from 'react-color'
 import React = require("react");
-import "./InkingCanvas.scss"
 import { InkTool } from "../../fields/InkField";
 import { observer } from "mobx-react";
-import "./InkingCanvas.scss"
+import "./InkingControl.scss"
 import { library } from '@fortawesome/fontawesome-svg-core';
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
 import { faPen, faHighlighter, faEraser, faBan } from '@fortawesome/free-solid-svg-icons';
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.scss b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.scss
index 9af0df7f5..4341c82f7 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.scss
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.scss
@@ -4,4 +4,7 @@
     width: 20000px; 
     height: 20000px;
     pointer-events: none;
+  }
+  .collectionfreeformlinksview-container {
+    pointer-events: none;
   }
\ No newline at end of file
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx
index ea392eaea..ef60aa672 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx
@@ -94,9 +94,12 @@ export class CollectionFreeFormLinksView extends React.Component<CollectionViewP
 
     render() {
         return (
-            <svg className="collectionfreeformlinksview-svgCanvas">
-                {this.uniqueConnections.map(c => <CollectionFreeFormLinkView key={Utils.GenerateGuid()} A={c.a} B={c.b} LinkDocs={c.l} />)}
+            <div className="collectionfreeformlinksview-container">
+                <svg className="collectionfreeformlinksview-svgCanvas">
+                    {this.uniqueConnections.map(c => <CollectionFreeFormLinkView key={Utils.GenerateGuid()} A={c.a} B={c.b} LinkDocs={c.l} />)}
+                </svg>
                 {this.props.children}
-            </svg>);
+            </div>
+        );
     }
 }
\ No newline at end of file
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss
index c979b27a9..81d21d89a 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss
@@ -7,9 +7,6 @@
   width: 100%;
   height: 100%;
   transform-origin: left top;
-  .inking-canvas {
-    transform-origin: 50000px 50000px;
-  }
 }
 .collectionfreeformview-container {
   .collectionfreeformview > .jsx-parser {
@@ -18,9 +15,6 @@
     width: 100%;
   }
 
-  .inking-canvas {
-    transform-origin: 50000px 50000px;
-  }
   //nested freeform views
   // .collectionfreeformview-container {
     // background-image: linear-gradient(to right, $light-color-secondary 1px, transparent 1px),
@@ -48,10 +42,6 @@
     background: $light-color-secondary;
   }
 
-  .inking-canvas {
-    transform-origin: 50000px 50000px;
-  }
-
   opacity: 0.99;
   border: 0px solid transparent;
   border-radius: $border-radius;
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index cdc5bdfb0..ae1c775e6 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -314,16 +314,18 @@ export class CollectionFreeFormView extends CollectionViewBase {
             <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}
-                style={{ borderWidth: `${COLLECTION_BORDER_WIDTH}px` }} tabIndex={0} ref={this.createDropTarget}>
+                style={{ borderWidth: `${COLLECTION_BORDER_WIDTH}px` }} ref={this.createDropTarget}>
                 <MarqueeView container={this} activeDocuments={this.getActiveDocuments} selectDocuments={this.selectDocuments}
                     addDocument={this.addDocument} removeDocument={this.props.removeDocument} addLiveTextDocument={this.addLiveTextBox}
                     getContainerTransform={this.getContainerTransform} getTransform={this.getTransform}>
                     <div className="collectionfreeformview" ref={this._canvasRef}
                         style={{ transform: `translate(${dx}px, ${dy}px) scale(${this.zoomScaling}, ${this.zoomScaling}) translate(${panx}px, ${pany}px)` }}>
                         {this.backgroundView}
-                        <CollectionFreeFormLinksView {...this.props} />
-                        {this.views}
-                        <InkingCanvas getScreenTransform={this.getTransform} Document={this.props.Document} />
+                        <CollectionFreeFormLinksView {...this.props}>
+                            <InkingCanvas getScreenTransform={this.getTransform} Document={this.props.Document} >
+                                {this.views}
+                            </InkingCanvas>
+                        </CollectionFreeFormLinksView>
                         {super.getCursors().map(entry => {
                             if (entry.Data.length > 0) {
                                 let id = entry.Data[0][0];
diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
index 7f951864e..d52b662bd 100644
--- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
+++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
@@ -1,4 +1,4 @@
-import { computed, trace, reaction, runInAction, observable } from "mobx";
+import { computed } from "mobx";
 import { observer } from "mobx-react";
 import { KeyStore } from "../../../fields/KeyStore";
 import { NumberField } from "../../../fields/NumberField";
@@ -6,8 +6,7 @@ import { Transform } from "../../util/Transform";
 import { DocumentView, DocumentViewProps } from "./DocumentView";
 import "./DocumentView.scss";
 import React = require("react");
-import { Document } from "../../../fields/Document";
-import { DocumentManager } from "../../util/DocumentManager";
+import { thisExpression } from "babel-types";
 
 
 @observer
@@ -75,6 +74,7 @@ export class CollectionFreeFormDocumentView extends React.Component<DocumentView
             <div className="collectionFreeFormDocumentView-container" ref={this._mainCont} style={{
                 transformOrigin: "left top",
                 transform: this.transform,
+                pointerEvents: "all",
                 width: this.width,
                 height: this.height,
                 position: "absolute",
diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx
index e273b0b4f..28a1f9757 100644
--- a/src/client/views/nodes/PDFBox.tsx
+++ b/src/client/views/nodes/PDFBox.tsx
@@ -87,7 +87,7 @@ export class PDFBox extends React.Component<FieldViewProps> {
     @observable private _interactive: boolean = false;
     @observable private _loaded: boolean = false;
 
-    @computed private get curPage() { return this.props.doc.GetNumber(KeyStore.CurPage, -1); }
+    @computed private get curPage() { return this.props.doc.GetNumber(KeyStore.CurPage, 1); }
     @computed private get thumbnailPage() { return this.props.doc.GetNumber(KeyStore.ThumbnailPage, -1); }
 
     componentDidMount() {
@@ -435,8 +435,6 @@ export class PDFBox extends React.Component<FieldViewProps> {
     @computed
     get pdfContent() {
         let page = this.curPage;
-        if (page == 0)
-            page = 1;
         const renderHeight = 2400;
         let pdfUrl = this.props.doc.GetT(this.props.fieldKey, PDFField);
         let xf = this.props.doc.GetNumber(KeyStore.NativeHeight, 0) / renderHeight;
@@ -463,10 +461,8 @@ export class PDFBox extends React.Component<FieldViewProps> {
         return [
             this._pageInfo.area.filter(() => this._pageInfo.area).map((element: any) => element),
             this._currAnno.map((element: any) => element),
-            <div key="pdfBox-contentShell">
-                {this.pdfContent}
-                {proxy}
-            </div>
+            this.pdfContent,
+            proxy
         ];
     }
 
-- 
cgit v1.2.3-70-g09d2

