From 646de60fc314198b97172c62f414ffb9576ffb98 Mon Sep 17 00:00:00 2001
From: bob <bcz@cs.brown.edu>
Date: Mon, 3 Feb 2020 11:33:24 -0500
Subject: fixed timeline bug.  made multirow/multicol use same fields.

---
 .../CollectionFreeFormLayoutEngines.tsx            | 28 ++++++++++++----------
 1 file changed, 16 insertions(+), 12 deletions(-)

(limited to 'src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx')

diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx
index f08c2506e..da0b51196 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx
@@ -204,7 +204,21 @@ export function computeTimelineLayout(
         x += scaling * (key - prevKey);
         const stack = findStack(x, stacking);
         prevKey = key;
-        !stack && Math.abs(x - (curTime - minTime) * scaling) > pivotAxisWidth && groupNames.push({ type: "text", text: key.toString(), x: x, y: stack * 25, height: fontHeight, fontSize });
+        !stack && (curTime === undefined || Math.abs(x - (curTime - minTime) * scaling) > pivotAxisWidth) && groupNames.push({ type: "text", text: key.toString(), x: x, y: stack * 25, height: fontHeight, fontSize });
+        newFunction(keyDocs, key);
+    });
+    if (sortedKeys.length && curTime > sortedKeys[sortedKeys.length - 1]) {
+        x = (curTime - minTime) * scaling;
+        groupNames.push({ type: "text", text: curTime.toString(), x: x, y: 0, zIndex: 1000, color: "orange", height: fontHeight, fontSize });
+    }
+    if (Math.ceil(maxTime - minTime) * scaling > x + 25) {
+        groupNames.push({ type: "text", text: Math.ceil(maxTime).toString(), x: Math.ceil(maxTime - minTime) * scaling, y: 0, height: fontHeight, fontSize });
+    }
+
+    const divider = { type: "div", color: "black", x: 0, y: 0, width: panelDim[0], height: 1 } as any;
+    return normalizeResults(panelDim, fontHeight, childPairs, docMap, poolData, viewDefsToJSX, groupNames, (maxTime - minTime) * scaling, [divider]);
+
+    function newFunction(keyDocs: Doc[], key: number) {
         keyDocs.forEach(doc => {
             const stack = findStack(x, stacking);
             const layoutDoc = Doc.Layout(doc);
@@ -215,22 +229,12 @@ export function computeTimelineLayout(
                 wid = layoutDoc._nativeHeight ? (NumCast(layoutDoc._nativeWidth) / NumCast(layoutDoc._nativeHeight)) * pivotAxisWidth : pivotAxisWidth;
             }
             docMap.set(doc, {
-                x: x, y: - Math.sqrt(stack) * pivotAxisWidth / 2 - pivotAxisWidth + (pivotAxisWidth - hgt) / 2,
+                x: x, y: -Math.sqrt(stack) * pivotAxisWidth / 2 - pivotAxisWidth + (pivotAxisWidth - hgt) / 2,
                 zIndex: (curTime === key ? 1000 : zind++), highlight: curTime === key, width: wid / (Math.max(stack, 1)), height: hgt
             });
             stacking[stack] = x + pivotAxisWidth;
         });
-    });
-    if (sortedKeys.length && curTime > sortedKeys[sortedKeys.length - 1]) {
-        x = (curTime - minTime) * scaling;
-        groupNames.push({ type: "text", text: curTime.toString(), x: x, y: 0, zIndex: 1000, color: "orange", height: fontHeight, fontSize });
     }
-    if (Math.ceil(maxTime - minTime) * scaling > x + 25) {
-        groupNames.push({ type: "text", text: Math.ceil(maxTime).toString(), x: Math.ceil(maxTime - minTime) * scaling, y: 0, height: fontHeight, fontSize });
-    }
-
-    const divider = { type: "div", color: "black", x: 0, y: 0, width: panelDim[0], height: 1 } as any;
-    return normalizeResults(panelDim, fontHeight, childPairs, docMap, poolData, viewDefsToJSX, groupNames, (maxTime - minTime) * scaling, [divider]);
 }
 
 function normalizeResults(panelDim: number[], fontHeight: number, childPairs: { data?: Doc, layout: Doc }[], docMap: Map<Doc, ViewDefBounds>,
-- 
cgit v1.2.3-70-g09d2


From 6b80df7d997fbde95b5571f790d9c0ed8e1950c4 Mon Sep 17 00:00:00 2001
From: bob <bcz@cs.brown.edu>
Date: Mon, 3 Feb 2020 13:01:49 -0500
Subject: attempt at performance tuning.

---
 .../CollectionFreeFormLayoutEngines.tsx             | 21 +++++++++++----------
 .../collectionFreeForm/CollectionFreeFormView.tsx   | 11 +++++++----
 .../views/nodes/CollectionFreeFormDocumentView.tsx  |  1 -
 src/client/views/nodes/RadialMenu.tsx               |  4 ++--
 src/new_fields/Doc.ts                               |  2 +-
 5 files changed, 21 insertions(+), 18 deletions(-)

(limited to 'src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx')

diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx
index da0b51196..bcd81e17a 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx
@@ -241,17 +241,15 @@ function normalizeResults(panelDim: number[], fontHeight: number, childPairs: {
     poolData: ObservableMap<string, PoolData>, viewDefsToJSX: (views: any) => ViewDefResult[], groupNames: PivotData[], minWidth: number, extras: PivotData[]) {
 
     const grpEles = groupNames.map(gn => ({ x: gn.x, y: gn.y, height: gn.height }) as PivotData);
-    const docEles = childPairs.filter(d => !d.layout.isMinimized).map(pair =>
-        docMap.get(pair.layout) || { x: NumCast(pair.layout.x), y: NumCast(pair.layout.y), width: pair.layout[WidthSym](), height: pair.layout[HeightSym]() } as PivotData // new pos is computed pos, or pos written to the document's fields
-    );
+    const docEles = childPairs.filter(d => !d.layout.isMinimized).map(pair => docMap.get(pair.layout) as PivotData);
     const aggBounds = aggregateBounds(docEles.concat(grpEles), 0, 0);
     aggBounds.r = Math.max(minWidth, aggBounds.r - aggBounds.x);
     const wscale = panelDim[0] / (aggBounds.r - aggBounds.x);
     let scale = wscale * (aggBounds.b - aggBounds.y) > panelDim[1] ? (panelDim[1]) / (aggBounds.b - aggBounds.y) : wscale;
     if (Number.isNaN(scale)) scale = 1;
 
-    childPairs.map(pair => {
-        const fallbackPos = {
+    childPairs.filter(d => !d.layout.isMinimized).map(pair => {
+        const newPosRaw = docMap.get(pair.layout) || {// new pos is computed pos, or pos written to the document's fields
             x: NumCast(pair.layout.x),
             y: NumCast(pair.layout.y),
             z: NumCast(pair.layout.z),
@@ -260,10 +258,14 @@ function normalizeResults(panelDim: number[], fontHeight: number, childPairs: {
             width: NumCast(pair.layout._width),
             height: NumCast(pair.layout._height)
         };
-        const newPosRaw = docMap.get(pair.layout) || fallbackPos; // new pos is computed pos, or pos written to the document's fields
         const newPos = {
-            x: newPosRaw.x * scale, y: newPosRaw.y * scale, z: newPosRaw.z, zIndex: newPosRaw.zIndex, highlight: newPosRaw.highlight,
-            width: (newPosRaw.width || 0) * scale, height: newPosRaw.height! * scale
+            x: newPosRaw.x * scale,
+            y: newPosRaw.y * scale,
+            z: newPosRaw.z,
+            highlight: newPosRaw.highlight,
+            zIndex: newPosRaw.zIndex,
+            width: (newPosRaw.width || 0) * scale,
+            height: newPosRaw.height! * scale
         };
         const lastPos = poolData.get(pair.layout[Id]); // last computed pos
         if (!lastPos || newPos.x !== lastPos.x || newPos.y !== lastPos.y || newPos.z !== lastPos.z || newPos.zIndex !== lastPos.zIndex || newPos.width !== lastPos.width || newPos.height !== lastPos.height) {
@@ -279,8 +281,7 @@ function normalizeResults(panelDim: number[], fontHeight: number, childPairs: {
             y: gname.y * scale,
             color: gname.color,
             width: gname.width === undefined ? undefined : gname.width * scale,
-            height: Math.max(fontHeight, gname.height! * scale),
-            // height: gname.height === undefined ? undefined : gname.height * scale,
+            height: Math.max(fontHeight, (gname.height || 0) * scale),
             fontSize: gname.fontSize
         }))))
     };
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 30ddd09e6..8c9933a9c 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -1,7 +1,7 @@
 import { library } from "@fortawesome/fontawesome-svg-core";
 import { faEye } from "@fortawesome/free-regular-svg-icons";
 import { faBraille, faChalkboard, faCompass, faCompressArrowsAlt, faExpandArrowsAlt, faFileUpload, faPaintBrush, faTable, faUpload } from "@fortawesome/free-solid-svg-icons";
-import { action, computed, observable, ObservableMap, reaction, runInAction, IReactionDisposer } from "mobx";
+import { action, computed, observable, ObservableMap, reaction, runInAction, IReactionDisposer, trace } from "mobx";
 import { observer } from "mobx-react";
 import { Doc, DocListCast, HeightSym, Opt, WidthSym, DocListCastAsync, Field } from "../../../../new_fields/Doc";
 import { documentSchema, positionSchema } from "../../../../new_fields/documentSchemas";
@@ -818,6 +818,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
     }
 
     get doLayoutComputation() {
+        trace();
         let computedElementData: { elements: ViewDefResult[] };
         switch (this.Document._freeformLayoutEngine) {
             case "timeline": computedElementData = this.doTimelineLayout(this._layoutPoolData); break;
@@ -838,12 +839,14 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
 
     componentDidMount() {
         super.componentDidMount();
-        this._layoutComputeReaction = reaction(() => { TraceMobx(); return this.doLayoutComputation; },
-            action((computation: { elements: ViewDefResult[] }) => computation && (this._layoutElements = computation.elements)),
+        this._layoutComputeReaction = reaction(
+            () => this.doLayoutComputation,
+            action((computation: { elements: ViewDefResult[] }) =>
+                computation && (this._layoutElements = computation.elements)),
             { fireImmediately: true, name: "doLayout" });
     }
     componentWillUnmount() {
-        this._layoutComputeReaction && this._layoutComputeReaction();
+        this._layoutComputeReaction?.();
     }
     @computed get views() { return this._layoutElements.filter(ele => ele.bounds && !ele.bounds.z).map(ele => ele.ele); }
     elementFunc = () => this._layoutElements;
diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
index ea7ed1d54..2a11267d4 100644
--- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
+++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
@@ -2,7 +2,6 @@ import anime from "animejs";
 import { computed, IReactionDisposer, observable, reaction, trace } from "mobx";
 import { observer } from "mobx-react";
 import { Doc, HeightSym, WidthSym } from "../../../new_fields/Doc";
-import { listSpec } from "../../../new_fields/Schema";
 import { Cast, NumCast, StrCast } from "../../../new_fields/Types";
 import { Transform } from "../../util/Transform";
 import { DocComponent } from "../DocComponent";
diff --git a/src/client/views/nodes/RadialMenu.tsx b/src/client/views/nodes/RadialMenu.tsx
index 74c5f53bd..9314a3899 100644
--- a/src/client/views/nodes/RadialMenu.tsx
+++ b/src/client/views/nodes/RadialMenu.tsx
@@ -70,8 +70,8 @@ export class RadialMenu extends React.Component {
         }
         this._shouldDisplay && (this._display = true);
         document.removeEventListener("pointermove", this.onPointerMove);
-        if (this._closest !== -1) {
-            this._items[this._closest]?.event();
+        if (this._closest !== -1 && this._items?.length > this._closest) {
+            this._items[this._closest].event();
         }
     }
     componentWillUnmount() {
diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts
index 4f6f80775..2b700863e 100644
--- a/src/new_fields/Doc.ts
+++ b/src/new_fields/Doc.ts
@@ -777,7 +777,7 @@ export namespace Doc {
     }
 
     export function matchFieldValue(doc: Doc, key: string, value: any): boolean {
-        const fieldVal = doc[key] ? doc[key] : doc[key + "_ext"];
+        const fieldVal = doc[key];
         if (Cast(fieldVal, listSpec("string"), []).length) {
             const vals = Cast(fieldVal, listSpec("string"), []);
             return vals.some(v => v === value);
-- 
cgit v1.2.3-70-g09d2


From aa1ade5b4464aaa56dcaa7b0fd888e5a96881af9 Mon Sep 17 00:00:00 2001
From: bob <bcz@cs.brown.edu>
Date: Mon, 3 Feb 2020 14:40:44 -0500
Subject: fixed pivot view column layout.

---
 .../CollectionFreeFormLayoutEngines.tsx            | 53 ++++++++++------------
 1 file changed, 25 insertions(+), 28 deletions(-)

(limited to 'src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx')

diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx
index bcd81e17a..859e78c17 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx
@@ -68,24 +68,27 @@ export function computePivotLayout(
     viewDefsToJSX: (views: any) => ViewDefResult[]
 ) {
     const fieldKey = "data";
-    const pivotAxisWidth = NumCast(pivotDoc.pivotWidth, 1000);
     const pivotColumnGroups = new Map<FieldResult<Field>, Doc[]>();
     const fontSize = NumCast(pivotDoc[fieldKey + "-timelineFontSize"], panelDim[1] > 58 ? 20 : Math.max(7, panelDim[1] / 3));
 
+    let maxInColumn = 1;
     const pivotFieldKey = toLabel(pivotDoc.pivotField);
     for (const doc of childDocs) {
         const val = Field.toString(doc[pivotFieldKey] as Field);
         if (val) {
             !pivotColumnGroups.get(val) && pivotColumnGroups.set(val, []);
             pivotColumnGroups.get(val)!.push(doc);
+            maxInColumn = Math.max(maxInColumn, pivotColumnGroups.get(val)?.length || 0);
         }
     }
 
-    const minSize = Array.from(pivotColumnGroups.entries()).reduce((min, pair) => Math.min(min, pair[1].length), Infinity);
-    let numCols = NumCast(pivotDoc.pivotNumColumns, Math.ceil(Math.sqrt(minSize)));
+    const colWidth = panelDim[0] / pivotColumnGroups.size;
+    const colHeight = panelDim[1];
+    const pivotAxisWidth = Math.sqrt(colWidth * colHeight / maxInColumn);
+    const numCols = Math.max(Math.round(colWidth / pivotAxisWidth), 1);
+
     const docMap = new Map<Doc, ViewDefBounds>();
-    const groupNames: PivotData[] = [];
-    numCols = Math.min(Math.max(1, panelDim[0] / pivotAxisWidth), numCols);
+    const groupNames: PivotData[] = [];;
 
     const expander = 1.05;
     const gap = .15;
@@ -205,7 +208,7 @@ export function computeTimelineLayout(
         const stack = findStack(x, stacking);
         prevKey = key;
         !stack && (curTime === undefined || Math.abs(x - (curTime - minTime) * scaling) > pivotAxisWidth) && groupNames.push({ type: "text", text: key.toString(), x: x, y: stack * 25, height: fontHeight, fontSize });
-        newFunction(keyDocs, key);
+        layoutDocsAtTime(keyDocs, key);
     });
     if (sortedKeys.length && curTime > sortedKeys[sortedKeys.length - 1]) {
         x = (curTime - minTime) * scaling;
@@ -218,7 +221,7 @@ export function computeTimelineLayout(
     const divider = { type: "div", color: "black", x: 0, y: 0, width: panelDim[0], height: 1 } as any;
     return normalizeResults(panelDim, fontHeight, childPairs, docMap, poolData, viewDefsToJSX, groupNames, (maxTime - minTime) * scaling, [divider]);
 
-    function newFunction(keyDocs: Doc[], key: number) {
+    function layoutDocsAtTime(keyDocs: Doc[], key: number) {
         keyDocs.forEach(doc => {
             const stack = findStack(x, stacking);
             const layoutDoc = Doc.Layout(doc);
@@ -249,27 +252,21 @@ function normalizeResults(panelDim: number[], fontHeight: number, childPairs: {
     if (Number.isNaN(scale)) scale = 1;
 
     childPairs.filter(d => !d.layout.isMinimized).map(pair => {
-        const newPosRaw = docMap.get(pair.layout) || {// new pos is computed pos, or pos written to the document's fields
-            x: NumCast(pair.layout.x),
-            y: NumCast(pair.layout.y),
-            z: NumCast(pair.layout.z),
-            highlight: undefined,
-            zIndex: NumCast(pair.layout.zIndex),
-            width: NumCast(pair.layout._width),
-            height: NumCast(pair.layout._height)
-        };
-        const newPos = {
-            x: newPosRaw.x * scale,
-            y: newPosRaw.y * scale,
-            z: newPosRaw.z,
-            highlight: newPosRaw.highlight,
-            zIndex: newPosRaw.zIndex,
-            width: (newPosRaw.width || 0) * scale,
-            height: newPosRaw.height! * scale
-        };
-        const lastPos = poolData.get(pair.layout[Id]); // last computed pos
-        if (!lastPos || newPos.x !== lastPos.x || newPos.y !== lastPos.y || newPos.z !== lastPos.z || newPos.zIndex !== lastPos.zIndex || newPos.width !== lastPos.width || newPos.height !== lastPos.height) {
-            runInAction(() => poolData.set(pair.layout[Id], { transition: "transform 1s", ...newPos }));
+        const newPosRaw = docMap.get(pair.layout);
+        if (newPosRaw) {
+            const newPos = {
+                x: newPosRaw.x * scale,
+                y: newPosRaw.y * scale,
+                z: newPosRaw.z,
+                highlight: newPosRaw.highlight,
+                zIndex: newPosRaw.zIndex,
+                width: (newPosRaw.width || 0) * scale,
+                height: newPosRaw.height! * scale
+            };
+            const lastPos = poolData.get(pair.layout[Id]); // last computed pos
+            if (!lastPos || newPos.x !== lastPos.x || newPos.y !== lastPos.y || newPos.z !== lastPos.z || newPos.zIndex !== lastPos.zIndex || newPos.width !== lastPos.width || newPos.height !== lastPos.height) {
+                runInAction(() => poolData.set(pair.layout[Id], { transition: "transform 1s", ...newPos }));
+            }
         }
     });
 
-- 
cgit v1.2.3-70-g09d2


From fdc0e0e157d70fdcc569525db58d8e6e642c0041 Mon Sep 17 00:00:00 2001
From: bob <bcz@cs.brown.edu>
Date: Mon, 3 Feb 2020 18:13:36 -0500
Subject: fixed performance of layoutengines.

---
 .../collectionFreeForm/CollectionFreeFormLayoutEngines.tsx   | 12 +++++-------
 src/client/views/nodes/ContentFittingDocumentView.tsx        | 11 ++++++++---
 2 files changed, 13 insertions(+), 10 deletions(-)

(limited to 'src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx')

diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx
index 859e78c17..63bcc68e5 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx
@@ -60,13 +60,14 @@ function toLabel(target: FieldResult<Field>) {
 }
 
 export function computePivotLayout(
-    poolData: ObservableMap<string, PoolData>,
+    poolData: Map<string, PoolData>,
     pivotDoc: Doc,
     childDocs: Doc[],
     childPairs: { layout: Doc, data?: Doc }[],
     panelDim: number[],
     viewDefsToJSX: (views: any) => ViewDefResult[]
 ) {
+    console.log("PIVOT " + pivotDoc[HeightSym]());
     const fieldKey = "data";
     const pivotColumnGroups = new Map<FieldResult<Field>, Doc[]>();
     const fontSize = NumCast(pivotDoc[fieldKey + "-timelineFontSize"], panelDim[1] > 58 ? 20 : Math.max(7, panelDim[1] / 3));
@@ -136,7 +137,7 @@ export function computePivotLayout(
 
 
 export function computeTimelineLayout(
-    poolData: ObservableMap<string, PoolData>,
+    poolData: Map<string, PoolData>,
     pivotDoc: Doc,
     childDocs: Doc[],
     childPairs: { layout: Doc, data?: Doc }[],
@@ -241,7 +242,7 @@ export function computeTimelineLayout(
 }
 
 function normalizeResults(panelDim: number[], fontHeight: number, childPairs: { data?: Doc, layout: Doc }[], docMap: Map<Doc, ViewDefBounds>,
-    poolData: ObservableMap<string, PoolData>, viewDefsToJSX: (views: any) => ViewDefResult[], groupNames: PivotData[], minWidth: number, extras: PivotData[]) {
+    poolData: Map<string, PoolData>, viewDefsToJSX: (views: any) => ViewDefResult[], groupNames: PivotData[], minWidth: number, extras: PivotData[]) {
 
     const grpEles = groupNames.map(gn => ({ x: gn.x, y: gn.y, height: gn.height }) as PivotData);
     const docEles = childPairs.filter(d => !d.layout.isMinimized).map(pair => docMap.get(pair.layout) as PivotData);
@@ -263,10 +264,7 @@ function normalizeResults(panelDim: number[], fontHeight: number, childPairs: {
                 width: (newPosRaw.width || 0) * scale,
                 height: newPosRaw.height! * scale
             };
-            const lastPos = poolData.get(pair.layout[Id]); // last computed pos
-            if (!lastPos || newPos.x !== lastPos.x || newPos.y !== lastPos.y || newPos.z !== lastPos.z || newPos.zIndex !== lastPos.zIndex || newPos.width !== lastPos.width || newPos.height !== lastPos.height) {
-                runInAction(() => poolData.set(pair.layout[Id], { transition: "transform 1s", ...newPos }));
-            }
+            poolData.set(pair.layout[Id], { transition: "transform 1s", ...newPos });
         }
     });
 
diff --git a/src/client/views/nodes/ContentFittingDocumentView.tsx b/src/client/views/nodes/ContentFittingDocumentView.tsx
index 51c8e00da..bd1b6166f 100644
--- a/src/client/views/nodes/ContentFittingDocumentView.tsx
+++ b/src/client/views/nodes/ContentFittingDocumentView.tsx
@@ -45,13 +45,14 @@ export class ContentFittingDocumentView extends React.Component<ContentFittingDo
     private get layoutDoc() { return this.props.Document && Doc.Layout(this.props.Document); }
     private get nativeWidth() { return NumCast(this.layoutDoc?._nativeWidth, this.props.PanelWidth()); }
     private get nativeHeight() { return NumCast(this.layoutDoc?._nativeHeight, this.props.PanelHeight()); }
-    private contentScaling = () => {
+    @computed get scaling() {
         const wscale = this.props.PanelWidth() / (this.nativeWidth || this.props.PanelWidth() || 1);
         if (wscale * this.nativeHeight > this.props.PanelHeight()) {
             return (this.props.PanelHeight() / (this.nativeHeight || this.props.PanelHeight() || 1)) || 1;
         }
         return wscale || 1;
     }
+    private contentScaling = () => this.scaling;
 
     @undoBatch
     @action
@@ -67,8 +68,12 @@ export class ContentFittingDocumentView extends React.Component<ContentFittingDo
         }
         return true;
     }
-    private PanelWidth = () => this.nativeWidth && (!this.props.Document || !this.props.Document._fitWidth) ? this.nativeWidth * this.contentScaling() : this.props.PanelWidth();
-    private PanelHeight = () => this.nativeHeight && (!this.props.Document || !this.props.Document._fitWidth) ? this.nativeHeight * this.contentScaling() : this.props.PanelHeight();
+    private PanelWidth = () => this.panelWidth;
+    private PanelHeight = () => this.panelHeight;;
+
+    @computed get panelWidth() { return this.nativeWidth && (!this.props.Document || !this.props.Document._fitWidth) ? this.nativeWidth * this.contentScaling() : this.props.PanelWidth(); }
+    @computed get panelHeight() { return this.nativeHeight && (!this.props.Document || !this.props.Document._fitWidth) ? this.nativeHeight * this.contentScaling() : this.props.PanelHeight(); }
+
     private getTransform = () => this.props.getTransform().translate(-this.centeringOffset, -this.centeringYOffset).scale(1 / this.contentScaling());
     private get centeringOffset() { return this.nativeWidth && (!this.props.Document || !this.props.Document._fitWidth) ? (this.props.PanelWidth() - this.nativeWidth * this.contentScaling()) / 2 : 0; }
     private get centeringYOffset() { return Math.abs(this.centeringOffset) < 0.001 ? (this.props.PanelHeight() - this.nativeHeight * this.contentScaling()) / 2 : 0; }
-- 
cgit v1.2.3-70-g09d2

