From 0dc39baf9630ae5aeaa41b89523ec6bf96d0b198 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Fri, 17 Nov 2023 21:53:36 -0500
Subject: major overhaul of resizing code.  updated doc fields for enabling
 native with modification to be cleaner.  added Vcenter option for text in
 menu bar.  fixed doc rotation.  enabled scaling of DataViz views.  fixed text
 sidebar opening size and sidebar issues with native dims for PDF/Web

---
 src/client/views/nodes/DataVizBox/DataVizBox.tsx | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

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

diff --git a/src/client/views/nodes/DataVizBox/DataVizBox.tsx b/src/client/views/nodes/DataVizBox/DataVizBox.tsx
index 299494c83..b3f813eda 100644
--- a/src/client/views/nodes/DataVizBox/DataVizBox.tsx
+++ b/src/client/views/nodes/DataVizBox/DataVizBox.tsx
@@ -115,8 +115,8 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
             layoutDoc: this.layoutDoc,
             records: this.records,
             axes: this.axes,
-            height: (this.props.PanelHeight() - 32) /* height of 'change view' button */ * 0.9,
-            width: this.props.PanelWidth() * 0.9,
+            height: (this.props.PanelHeight() * (this.props.NativeDimScaling?.() || 1) - 32) /* height of 'change view' button */ * 0.9,
+            width: this.props.PanelWidth() * (this.props.NativeDimScaling?.() || 1) * 0.9,
             margin: { top: 10, right: 25, bottom: 75, left: 45 },
         };
         if (!this.records.length) return 'no data/visualization';
@@ -133,6 +133,8 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
     };
 
     render() {
+        const scale = this.props.NativeDimScaling?.() || 1;
+
         return !this.records.length ? (
             // displays how to get data into the DataVizBox if its empty
             <div className="start-message">To create a DataViz box, either import / drag a CSV file into your canvas or copy a data table and use the command 'ctrl + p' to bring the data table to your canvas.</div>
@@ -141,6 +143,10 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
                 className="dataViz"
                 style={{
                     pointerEvents: this.props.isContentActive() === true ? 'all' : 'none',
+                    width: `${100 / scale}%`,
+                    height: `${100 / scale}%`,
+                    transform: `scale(${scale})`,
+                    position: 'absolute',
                 }}
                 onWheel={e => e.stopPropagation()}
                 ref={r =>
-- 
cgit v1.2.3-70-g09d2


From 1b568af6b2725b9eed6f591bfce193d39d5804de Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Sat, 18 Nov 2023 14:36:09 -0500
Subject: fixed scaling of dataviz boxes when native dims are set.

---
 src/client/views/nodes/DataVizBox/DataVizBox.tsx   | 34 ++++++++++------------
 .../views/nodes/DataVizBox/components/PieChart.tsx |  6 +---
 2 files changed, 17 insertions(+), 23 deletions(-)

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

diff --git a/src/client/views/nodes/DataVizBox/DataVizBox.tsx b/src/client/views/nodes/DataVizBox/DataVizBox.tsx
index b3f813eda..1cb0a50f3 100644
--- a/src/client/views/nodes/DataVizBox/DataVizBox.tsx
+++ b/src/client/views/nodes/DataVizBox/DataVizBox.tsx
@@ -109,28 +109,26 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
     };
 
     // toggles for user to decide which chart type to view the data in
-    renderVizView = () => {
+    @computed get renderVizView() {
+        const scale = this.props.NativeDimScaling?.() || 1;
         const sharedProps = {
             rootDoc: this.rootDoc,
             layoutDoc: this.layoutDoc,
             records: this.records,
             axes: this.axes,
-            height: (this.props.PanelHeight() * (this.props.NativeDimScaling?.() || 1) - 32) /* height of 'change view' button */ * 0.9,
-            width: this.props.PanelWidth() * (this.props.NativeDimScaling?.() || 1) * 0.9,
+            height: (this.props.PanelHeight() / scale - 32) /* height of 'change view' button */ * 0.9,
+            width: (this.props.PanelWidth() / scale) * 0.9,
             margin: { top: 10, right: 25, bottom: 75, left: 45 },
         };
         if (!this.records.length) return 'no data/visualization';
         switch (this.dataVizView) {
-            case DataVizView.TABLE:
-                return <TableBox {...sharedProps} docView={this.props.DocumentView} selectAxes={this.selectAxes} />;
-            case DataVizView.LINECHART:
-                return <LineChart {...sharedProps} dataDoc={this.dataDoc} fieldKey={this.fieldKey} ref={r => (this._vizRenderer = r ?? undefined)} />;
-            case DataVizView.HISTOGRAM:
-                return <Histogram {...sharedProps} dataDoc={this.dataDoc} fieldKey={this.fieldKey} ref={r => (this._vizRenderer = r ?? undefined)} />;
-            case DataVizView.PIECHART:
-                return <PieChart {...sharedProps} dataDoc={this.dataDoc} fieldKey={this.fieldKey} ref={r => (this._vizRenderer = r ?? undefined)} />;
-        }
-    };
+            case DataVizView.TABLE:     return <TableBox  {...sharedProps} docView={this.props.DocumentView} selectAxes={this.selectAxes} />;
+            case DataVizView.LINECHART: return <LineChart {...sharedProps} dataDoc={this.dataDoc} fieldKey={this.fieldKey} ref={r => (this._vizRenderer = r ?? undefined)} />;
+            case DataVizView.HISTOGRAM: return <Histogram {...sharedProps} dataDoc={this.dataDoc} fieldKey={this.fieldKey} ref={r => (this._vizRenderer = r ?? undefined)} />;
+            case DataVizView.PIECHART:  return <PieChart  {...sharedProps} dataDoc={this.dataDoc} fieldKey={this.fieldKey} ref={r => (this._vizRenderer = r ?? undefined)} 
+            margin={{ top: 10, right: 15, bottom: 15, left: 15 }} />;
+        } // prettier-ignore
+    }
 
     render() {
         const scale = this.props.NativeDimScaling?.() || 1;
@@ -160,12 +158,12 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
                     )
                 }>
                 <div className={'datatype-button'}>
-                    <Toggle text={'TABLE'} toggleType={ToggleType.BUTTON} type={Type.SEC} color={'black'} onClick={e => (this.layoutDoc._dataViz = DataVizView.TABLE)} toggleStatus={this.layoutDoc._dataViz == DataVizView.TABLE} />
-                    <Toggle text={'LINECHART'} toggleType={ToggleType.BUTTON} type={Type.SEC} color={'black'} onClick={e => (this.layoutDoc._dataViz = DataVizView.LINECHART)} toggleStatus={this.layoutDoc._dataViz == DataVizView.LINECHART} />
-                    <Toggle text={'HISTOGRAM'} toggleType={ToggleType.BUTTON} type={Type.SEC} color={'black'} onClick={e => (this.layoutDoc._dataViz = DataVizView.HISTOGRAM)} toggleStatus={this.layoutDoc._dataViz == DataVizView.HISTOGRAM} />
-                    <Toggle text={'PIE CHART'} toggleType={ToggleType.BUTTON} type={Type.SEC} color={'black'} onClick={e => (this.layoutDoc._dataViz = DataVizView.PIECHART)} toggleStatus={this.layoutDoc._dataViz == DataVizView.PIECHART} />
+                    <Toggle text={'  TABLE  '} toggleType={ToggleType.BUTTON} type={Type.SEC} color={'black'} onClick={e => (this.layoutDoc._dataViz = DataVizView.TABLE)} toggleStatus={this.layoutDoc._dataViz === DataVizView.TABLE} />
+                    <Toggle text={'LINECHART'} toggleType={ToggleType.BUTTON} type={Type.SEC} color={'black'} onClick={e => (this.layoutDoc._dataViz = DataVizView.LINECHART)} toggleStatus={this.layoutDoc._dataViz === DataVizView.LINECHART} />
+                    <Toggle text={'HISTOGRAM'} toggleType={ToggleType.BUTTON} type={Type.SEC} color={'black'} onClick={e => (this.layoutDoc._dataViz = DataVizView.HISTOGRAM)} toggleStatus={this.layoutDoc._dataViz === DataVizView.HISTOGRAM} />
+                    <Toggle text={'PIE CHART'} toggleType={ToggleType.BUTTON} type={Type.SEC} color={'black'} onClick={e => (this.layoutDoc._dataViz = DataVizView.PIECHART)} toggleStatus={this.layoutDoc._dataViz == -DataVizView.PIECHART} />
                 </div>
-                {this.renderVizView()}
+                {this.renderVizView}
             </div>
         );
     }
diff --git a/src/client/views/nodes/DataVizBox/components/PieChart.tsx b/src/client/views/nodes/DataVizBox/components/PieChart.tsx
index 561f39141..7303eb184 100644
--- a/src/client/views/nodes/DataVizBox/components/PieChart.tsx
+++ b/src/client/views/nodes/DataVizBox/components/PieChart.tsx
@@ -88,11 +88,7 @@ export class PieChart extends React.Component<PieChartProps> {
     componentDidMount = () => {
         this._disposers.chartData = reaction(
             () => ({ dataSet: this._pieChartData, w: this.width, h: this.height }),
-            ({ dataSet, w, h }) => {
-                if (dataSet!.length > 0) {
-                    this.drawChart(dataSet, w, h);
-                }
-            },
+            ({ dataSet, w, h }) => dataSet!.length > 0 && this.drawChart(dataSet, w, h),
             { fireImmediately: true }
         );
     };
-- 
cgit v1.2.3-70-g09d2


From c94bbf5b9f1a37630208d4ba64a93c5399044042 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Thu, 30 Nov 2023 20:47:28 -0500
Subject: completed transition from rootDoc => Document, dataDoc, layoutDoc

---
 src/client/views/DocComponent.tsx                  |   4 -
 src/client/views/SidebarAnnos.tsx                  |  22 ++--
 src/client/views/collections/CollectionView.tsx    |  32 ++---
 src/client/views/nodes/AudioBox.tsx                |  18 +--
 .../views/nodes/CollectionFreeFormDocumentView.tsx |   4 +-
 src/client/views/nodes/ComparisonBox.tsx           |  10 +-
 src/client/views/nodes/DataVizBox/DataVizBox.tsx   |  12 +-
 .../nodes/DataVizBox/components/LineChart.tsx      |   8 +-
 src/client/views/nodes/FunctionPlotBox.tsx         |   7 +-
 src/client/views/nodes/ImageBox.tsx                |  52 ++++----
 src/client/views/nodes/LoadingBox.tsx              |  16 +--
 src/client/views/nodes/MapBox/MapBox.tsx           |  44 +++----
 src/client/views/nodes/MapBox/MapBox2.tsx          |   6 +-
 src/client/views/nodes/PDFBox.tsx                  |  34 +++---
 src/client/views/nodes/ScreenshotBox.tsx           |  24 ++--
 src/client/views/nodes/ScriptingBox.tsx            |  58 +++++----
 src/client/views/nodes/VideoBox.tsx                |  36 +++---
 src/client/views/nodes/WebBox.tsx                  |  10 +-
 .../views/nodes/formattedText/FormattedTextBox.tsx | 131 +++++++++------------
 .../formattedText/FormattedTextBoxComment.tsx      |   2 +-
 20 files changed, 252 insertions(+), 278 deletions(-)

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

diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx
index c04359d80..04956d974 100644
--- a/src/client/views/DocComponent.tsx
+++ b/src/client/views/DocComponent.tsx
@@ -96,10 +96,6 @@ export function ViewBoxAnnotatableComponent<P extends ViewBoxAnnotatableProps>()
         @computed get Document() {
             return this.props.Document;
         }
-        // This is the "The Document" -- it encapsulates, data, layout, and any templates
-        @computed get rootDoc() {
-            return Cast(this.props.Document.rootDocument, Doc, null) || this.props.Document;
-        }
         // This is the rendering data of a document -- it may be "The Document", or it may be some template document that holds the rendering info
         @computed get layoutDoc() {
             return Doc.Layout(this.props.Document);
diff --git a/src/client/views/SidebarAnnos.tsx b/src/client/views/SidebarAnnos.tsx
index 1e1b8e0e6..9377aabe9 100644
--- a/src/client/views/SidebarAnnos.tsx
+++ b/src/client/views/SidebarAnnos.tsx
@@ -20,8 +20,8 @@ import React = require('react');
 
 interface ExtraProps {
     fieldKey: string;
+    Document: Doc;
     layoutDoc: Doc;
-    rootDoc: Doc;
     dataDoc: Doc;
     // usePanelWidth: boolean;
     showSidebar: boolean;
@@ -42,7 +42,7 @@ export class SidebarAnnos extends React.Component<FieldViewProps & ExtraProps> {
     _stackRef = React.createRef<CollectionStackingView>();
     @computed get allMetadata() {
         const keys = new Map<string, FieldResult<Field>>();
-        DocListCast(this.props.rootDoc[this.sidebarKey]).forEach(doc =>
+        DocListCast(this.props.Document[this.sidebarKey]).forEach(doc =>
             SearchUtil.documentKeys(doc)
                 .filter(key => key[0] && key[0] !== '_' && key[0] === key[0].toUpperCase())
                 .map(key => keys.set(key, doc[key]))
@@ -51,7 +51,7 @@ export class SidebarAnnos extends React.Component<FieldViewProps & ExtraProps> {
     }
     @computed get allHashtags() {
         const keys = new Set<string>();
-        DocListCast(this.props.rootDoc[this.sidebarKey]).forEach(doc => StrListCast(doc.tags).forEach(tag => keys.add(tag)));
+        DocListCast(this.props.Document[this.sidebarKey]).forEach(doc => StrListCast(doc.tags).forEach(tag => keys.add(tag)));
         return Array.from(keys.keys())
             .filter(key => key[0])
             .filter(key => !key.startsWith('_') && (key[0] === '#' || key[0] === key[0].toUpperCase()))
@@ -59,7 +59,7 @@ export class SidebarAnnos extends React.Component<FieldViewProps & ExtraProps> {
     }
     @computed get allUsers() {
         const keys = new Set<string>();
-        DocListCast(this.props.rootDoc[this.sidebarKey]).forEach(doc => keys.add(StrCast(doc.author)));
+        DocListCast(this.props.Document[this.sidebarKey]).forEach(doc => keys.add(StrCast(doc.author)));
         return Array.from(keys.keys()).sort();
     }
 
@@ -69,7 +69,7 @@ export class SidebarAnnos extends React.Component<FieldViewProps & ExtraProps> {
             .join(' ');
         const target = Docs.Create.TextDocument(startup, {
             title: '-note-',
-            annotationOn: this.props.rootDoc,
+            annotationOn: this.props.Document,
             _width: 200,
             _height: 50,
             _layout_fitWidth: true,
@@ -147,7 +147,7 @@ export class SidebarAnnos extends React.Component<FieldViewProps & ExtraProps> {
         return target;
     };
     makeDocUnfiltered = (doc: Doc) => {
-        if (DocListCast(this.props.rootDoc[this.sidebarKey]).find(anno => Doc.AreProtosEqual(doc.layout_unrendered ? DocCast(doc.annotationOn) : doc, anno))) {
+        if (DocListCast(this.props.Document[this.sidebarKey]).find(anno => Doc.AreProtosEqual(doc.layout_unrendered ? DocCast(doc.annotationOn) : doc, anno))) {
             if (this.childFilters()) {
                 // if any child filters exist, get rid of them
                 this.props.layoutDoc._childFilters = new List<string>();
@@ -188,7 +188,7 @@ export class SidebarAnnos extends React.Component<FieldViewProps & ExtraProps> {
         const renderTag = (tag: string) => {
             const active = this.childFilters().includes(`tags${Doc.FilterSep}${tag}${Doc.FilterSep}check`);
             return (
-                <div key={tag} className={`sidebarAnnos-filterTag${active ? '-active' : ''}`} onClick={e => Doc.setDocFilter(this.props.rootDoc, 'tags', tag, 'check', true, undefined, e.shiftKey)}>
+                <div key={tag} className={`sidebarAnnos-filterTag${active ? '-active' : ''}`} onClick={e => Doc.setDocFilter(this.props.Document, 'tags', tag, 'check', true, undefined, e.shiftKey)}>
                     {tag}
                 </div>
             );
@@ -196,7 +196,7 @@ export class SidebarAnnos extends React.Component<FieldViewProps & ExtraProps> {
         const renderMeta = (tag: string, dflt: FieldResult<Field>) => {
             const active = this.childFilters().includes(`${tag}${Doc.FilterSep}${Doc.FilterAny}${Doc.FilterSep}exists`);
             return (
-                <div key={tag} className={`sidebarAnnos-filterTag${active ? '-active' : ''}`} onClick={e => Doc.setDocFilter(this.props.rootDoc, tag, Doc.FilterAny, 'exists', true, undefined, e.shiftKey)}>
+                <div key={tag} className={`sidebarAnnos-filterTag${active ? '-active' : ''}`} onClick={e => Doc.setDocFilter(this.props.Document, tag, Doc.FilterAny, 'exists', true, undefined, e.shiftKey)}>
                     {tag}
                 </div>
             );
@@ -204,7 +204,7 @@ export class SidebarAnnos extends React.Component<FieldViewProps & ExtraProps> {
         const renderUsers = (user: string) => {
             const active = this.childFilters().includes(`author:${user}:check`);
             return (
-                <div key={user} className={`sidebarAnnos-filterUser${active ? '-active' : ''}`} onClick={e => Doc.setDocFilter(this.props.rootDoc, 'author', user, 'check', true, undefined, e.shiftKey)}>
+                <div key={user} className={`sidebarAnnos-filterUser${active ? '-active' : ''}`} onClick={e => Doc.setDocFilter(this.props.Document, 'author', user, 'check', true, undefined, e.shiftKey)}>
                     {user}
                 </div>
             );
@@ -215,9 +215,9 @@ export class SidebarAnnos extends React.Component<FieldViewProps & ExtraProps> {
                 style={{
                     position: 'absolute',
                     pointerEvents: this.props.isContentActive() ? 'all' : undefined,
-                    top: this.props.rootDoc.type !== DocumentType.RTF && StrCast(this.props.rootDoc._layout_showTitle) === 'title' ? 15 : 0,
+                    top: this.props.Document.type !== DocumentType.RTF && StrCast(this.props.Document._layout_showTitle) === 'title' ? 15 : 0,
                     right: 0,
-                    background: this.props.styleProvider?.(this.props.rootDoc, this.props, StyleProp.WidgetColor),
+                    background: this.props.styleProvider?.(this.props.Document, this.props, StyleProp.WidgetColor),
                     width: `100%`,
                     height: '100%',
                 }}>
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index 389a9a534..dc2ee63f5 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -141,7 +141,7 @@ export class CollectionView extends ViewBoxAnnotatableComponent<ViewBoxAnnotatab
     };
 
     setupViewTypes(category: string, func: (type_collection: CollectionViewType) => Doc) {
-        if (!Doc.IsSystem(this.rootDoc) && this.rootDoc._type_collection !== CollectionViewType.Docking && !this.rootDoc.isGroup && !this.rootDoc.annotationOn) {
+        if (!Doc.IsSystem(this.Document) && this.Document._type_collection !== CollectionViewType.Docking && !this.dataDoc.isGroup && !this.Document.annotationOn) {
             // prettier-ignore
             const subItems: ContextMenuProps[] = [
                 { description: 'Freeform',    event: () => func(CollectionViewType.Freeform), icon: 'signature' },
@@ -172,7 +172,7 @@ export class CollectionView extends ViewBoxAnnotatableComponent<ViewBoxAnnotatab
             // need to test this because GoldenLayout causes a parallel hierarchy in the React DOM for its children and the main document view7
             !Doc.noviceMode &&
                 this.setupViewTypes('Appearance...', vtype => {
-                    const newRendition = Doc.MakeEmbedding(this.rootDoc);
+                    const newRendition = Doc.MakeEmbedding(this.Document);
                     newRendition._type_collection = vtype;
                     this.props.addDocTab(newRendition, OpenWhere.addRight);
                     return newRendition;
@@ -180,18 +180,18 @@ export class CollectionView extends ViewBoxAnnotatableComponent<ViewBoxAnnotatab
 
             const options = cm.findByDescription('Options...');
             const optionItems = options && 'subitems' in options ? options.subitems : [];
-            !Doc.noviceMode ? optionItems.splice(0, 0, { description: `${this.rootDoc.forceActive ? 'Select' : 'Force'} Contents Active`, event: () => (this.rootDoc.forceActive = !this.rootDoc.forceActive), icon: 'project-diagram' }) : null;
-            if (this.rootDoc.childLayout instanceof Doc) {
-                optionItems.push({ description: 'View Child Layout', event: () => this.props.addDocTab(this.rootDoc.childLayout as Doc, OpenWhere.addRight), icon: 'project-diagram' });
+            !Doc.noviceMode ? optionItems.splice(0, 0, { description: `${this.Document.forceActive ? 'Select' : 'Force'} Contents Active`, event: () => (this.Document.forceActive = !this.Document.forceActive), icon: 'project-diagram' }) : null;
+            if (this.Document.childLayout instanceof Doc) {
+                optionItems.push({ description: 'View Child Layout', event: () => this.props.addDocTab(this.Document.childLayout as Doc, OpenWhere.addRight), icon: 'project-diagram' });
             }
-            if (this.rootDoc.childClickedOpenTemplateView instanceof Doc) {
-                optionItems.push({ description: 'View Child Detailed Layout', event: () => this.props.addDocTab(this.rootDoc.childClickedOpenTemplateView as Doc, OpenWhere.addRight), icon: 'project-diagram' });
+            if (this.Document.childClickedOpenTemplateView instanceof Doc) {
+                optionItems.push({ description: 'View Child Detailed Layout', event: () => this.props.addDocTab(this.Document.childClickedOpenTemplateView as Doc, OpenWhere.addRight), icon: 'project-diagram' });
             }
-            !Doc.noviceMode && optionItems.push({ description: `${this.rootDoc._isLightbox ? 'Unset' : 'Set'} is Lightbox`, event: () => (this.rootDoc._isLightbox = !this.rootDoc._isLightbox), icon: 'project-diagram' });
+            !Doc.noviceMode && optionItems.push({ description: `${this.layoutDoc._isLightbox ? 'Unset' : 'Set'} is Lightbox`, event: () => (this.layoutDoc._isLightbox = !this.layoutDoc._isLightbox), icon: 'project-diagram' });
 
             !options && cm.addItem({ description: 'Options...', subitems: optionItems, icon: 'hand-point-right' });
 
-            if (!Doc.noviceMode && !this.rootDoc.annotationOn) {
+            if (!Doc.noviceMode && !this.Document.annotationOn) {
                 const existingOnClick = cm.findByDescription('OnClick...');
                 const onClicks = existingOnClick && 'subitems' in existingOnClick ? existingOnClick.subitems : [];
                 const funcs = [
@@ -203,7 +203,7 @@ export class CollectionView extends ViewBoxAnnotatableComponent<ViewBoxAnnotatab
                         description: `Edit ${func.name} script`,
                         icon: 'edit',
                         event: (obj: any) => {
-                            const embedding = Doc.MakeEmbedding(this.rootDoc);
+                            const embedding = Doc.MakeEmbedding(this.Document);
                             DocUtils.makeCustomViewClicked(embedding, undefined, func.key);
                             this.props.addDocTab(embedding, OpenWhere.addRight);
                         },
@@ -213,16 +213,16 @@ export class CollectionView extends ViewBoxAnnotatableComponent<ViewBoxAnnotatab
                     onClicks.push({
                         description: `Set child ${childClick.title}`,
                         icon: 'edit',
-                        event: () => (Doc.GetProto(this.rootDoc)[StrCast(childClick.targetScriptKey)] = ObjectField.MakeCopy(ScriptCast(childClick.data))),
+                        event: () => (this.dataDoc[StrCast(childClick.targetScriptKey)] = ObjectField.MakeCopy(ScriptCast(childClick.data))),
                     })
                 );
-                !Doc.IsSystem(this.rootDoc) && !existingOnClick && cm.addItem({ description: 'OnClick...', noexpand: true, subitems: onClicks, icon: 'mouse-pointer' });
+                !Doc.IsSystem(this.Document) && !existingOnClick && cm.addItem({ description: 'OnClick...', noexpand: true, subitems: onClicks, icon: 'mouse-pointer' });
             }
 
             if (!Doc.noviceMode) {
                 const more = cm.findByDescription('More...');
                 const moreItems = more && 'subitems' in more ? more.subitems : [];
-                moreItems.push({ description: 'Export Image Hierarchy', icon: 'columns', event: () => ImageUtils.ExportHierarchyToFileSystem(this.rootDoc) });
+                moreItems.push({ description: 'Export Image Hierarchy', icon: 'columns', event: () => ImageUtils.ExportHierarchyToFileSystem(this.Document) });
                 !more && cm.addItem({ description: 'More...', subitems: moreItems, icon: 'hand-point-right' });
             }
         }
@@ -232,7 +232,7 @@ export class CollectionView extends ViewBoxAnnotatableComponent<ViewBoxAnnotatab
 
     childHideResizeHandles = () => this.props.childHideResizeHandles?.() ?? BoolCast(this.Document.childHideResizeHandles);
     childHideDecorationTitle = () => this.props.childHideDecorationTitle?.() ?? BoolCast(this.Document.childHideDecorationTitle);
-    childLayoutTemplate = () => this.props.childLayoutTemplate?.() || Cast(this.rootDoc.childLayoutTemplate, Doc, null);
+    childLayoutTemplate = () => this.props.childLayoutTemplate?.() || Cast(this.Document.childLayoutTemplate, Doc, null);
     isContentActive = (outsideReaction?: boolean) => this._isContentActive;
 
     render() {
@@ -249,7 +249,7 @@ export class CollectionView extends ViewBoxAnnotatableComponent<ViewBoxAnnotatab
             PanelHeight: this.props.PanelHeight,
             ScreenToLocalTransform: this.screenToLocalTransform,
             childLayoutTemplate: this.childLayoutTemplate,
-            childLayoutString: StrCast(this.rootDoc.childLayoutString, this.props.childLayoutString),
+            childLayoutString: StrCast(this.Document.childLayoutString, this.props.childLayoutString),
             childHideResizeHandles: this.childHideResizeHandles,
             childHideDecorationTitle: this.childHideDecorationTitle,
         };
@@ -257,7 +257,7 @@ export class CollectionView extends ViewBoxAnnotatableComponent<ViewBoxAnnotatab
             <div
                 className="collectionView"
                 onContextMenu={this.onContextMenu}
-                style={{ pointerEvents: this.props.DocumentView?.()?.props.docViewPath().lastElement()?.rootDoc?._type_collection === CollectionViewType.Freeform && this.rootDoc._lockedPosition ? 'none' : undefined }}>
+                style={{ pointerEvents: this.props.DocumentView?.()?.props.docViewPath().lastElement()?.rootDoc?._type_collection === CollectionViewType.Freeform && this.layoutDoc._lockedPosition ? 'none' : undefined }}>
                 {this.renderSubView(this.collectionViewType, props)}
             </div>
         );
diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx
index 807a77233..dacdbe986 100644
--- a/src/client/views/nodes/AudioBox.tsx
+++ b/src/client/views/nodes/AudioBox.tsx
@@ -139,17 +139,17 @@ export class AudioBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
         const timecode = Cast(this.layoutDoc._layout_currentTimecode, 'number', null);
         const anchor = addAsAnnotation
             ? CollectionStackedTimeline.createAnchor(
-                  this.rootDoc,
+                  this.Document,
                   this.dataDoc,
                   this.annotationKey,
                   this._ele?.currentTime || Cast(this.props.Document._layout_currentTimecode, 'number', null) || (this.mediaState === media_state.Recording ? (Date.now() - (this.recordingStart || 0)) / 1000 : undefined),
                   undefined,
                   undefined,
                   addAsAnnotation
-              ) || this.rootDoc
-            : Docs.Create.ConfigDocument({ title: '#' + timecode, _timecodeToShow: timecode, annotationOn: this.rootDoc });
+              ) || this.Document
+            : Docs.Create.ConfigDocument({ title: '#' + timecode, _timecodeToShow: timecode, annotationOn: this.Document });
 
-        PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: { ...(pinProps?.pinData ?? {}), temporal: true } }, this.rootDoc);
+        PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: { ...(pinProps?.pinData ?? {}), temporal: true } }, this.Document);
         return anchor;
     };
 
@@ -363,14 +363,14 @@ export class AudioBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
             returnFalse,
             returnFalse,
             action(() => {
-                const newDoc = DocUtils.GetNewTextDoc('', NumCast(this.rootDoc.x), NumCast(this.rootDoc.y) + NumCast(this.layoutDoc._height) + 10, NumCast(this.layoutDoc._width), 2 * NumCast(this.layoutDoc._height));
+                const newDoc = DocUtils.GetNewTextDoc('', NumCast(this.Document.x), NumCast(this.Document.y) + NumCast(this.layoutDoc._height) + 10, NumCast(this.layoutDoc._width), 2 * NumCast(this.layoutDoc._height));
                 const textField = Doc.LayoutFieldKey(newDoc);
                 Doc.GetProto(newDoc)[`${textField}_recordingSource`] = this.dataDoc;
                 Doc.GetProto(newDoc)[`${textField}_recordingStart`] = ComputedField.MakeFunction(`this.${textField}_recordingSource.${this.fieldKey}_recordingStart`);
                 Doc.GetProto(newDoc).mediaState = ComputedField.MakeFunction(`this.${textField}_recordingSource.mediaState`);
-                if (Doc.IsInMyOverlay(this.rootDoc)) {
-                    newDoc.overlayX = this.rootDoc.x;
-                    newDoc.overlayY = NumCast(this.rootDoc.y) + NumCast(this.rootDoc._height);
+                if (Doc.IsInMyOverlay(this.Document)) {
+                    newDoc.overlayX = this.Document.x;
+                    newDoc.overlayY = NumCast(this.Document.y) + NumCast(this.layoutDoc._height);
                     Doc.AddToMyOverlay(newDoc);
                 } else {
                     this.props.addDocument?.(newDoc);
@@ -424,7 +424,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
 
     // plays link
     playLink = (link: Doc, options: DocFocusOptions) => {
-        if (link.annotationOn === this.rootDoc) {
+        if (link.annotationOn === this.Document) {
             if (!this.layoutDoc.dontAutoPlayFollowedLinks) {
                 this.playFrom(this.timeline?.anchorStart(link) || 0, this.timeline?.anchorEnd(link));
             } else {
diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
index 2c53a1d5b..b7cd306ae 100644
--- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
+++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
@@ -72,7 +72,7 @@ export class CollectionFreeFormDocumentViewWrapper extends DocComponent<Collecti
     w_Highlight = ()       => this.Highlight; // prettier-ignore
     w_Width = ()           => this.Width; // prettier-ignore
     w_Height = ()          => this.Height; // prettier-ignore
-    w_AutoDim = ()         => this.AutoDim;
+    w_AutoDim = () => this.AutoDim;
     w_Transition = ()      => this.Transition; // prettier-ignore
     w_DataTransition = ()  => this.DataTransition; // prettier-ignore
 
@@ -254,7 +254,7 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
     //  undefined - this is not activated by a group
     isGroupActive = () => {
         if (this.CollectionFreeFormView.isAnyChildContentActive()) return undefined;
-        const isGroup = this.Document.isGroup && (!this.layoutDoc.backgroundColor || this.layoutDoc.backgroundColor === 'transparent');
+        const isGroup = this.dataDoc.isGroup && (!this.layoutDoc.backgroundColor || this.layoutDoc.backgroundColor === 'transparent');
         return isGroup ? (this.props.isDocumentActive?.() ? 'group' : this.props.isGroupActive?.() ? 'child' : 'inactive') : this.props.isGroupActive?.() ? 'child' : undefined;
     };
     public static CollectionFreeFormDocViewClassName = 'collectionFreeFormDocumentView-container';
diff --git a/src/client/views/nodes/ComparisonBox.tsx b/src/client/views/nodes/ComparisonBox.tsx
index ff394e5f5..b050e3252 100644
--- a/src/client/views/nodes/ComparisonBox.tsx
+++ b/src/client/views/nodes/ComparisonBox.tsx
@@ -44,7 +44,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl
     private internalDrop = (e: Event, dropEvent: DragManager.DropEvent, fieldKey: string) => {
         if (dropEvent.complete.docDragData) {
             const droppedDocs = dropEvent.complete.docDragData?.droppedDocuments;
-            const added = dropEvent.complete.docDragData.moveDocument?.(droppedDocs, this.rootDoc, (doc: Doc | Doc[]) => this.addDoc(doc instanceof Doc ? doc : doc.lastElement(), fieldKey));
+            const added = dropEvent.complete.docDragData.moveDocument?.(droppedDocs, this.Document, (doc: Doc | Doc[]) => this.addDoc(doc instanceof Doc ? doc : doc.lastElement(), fieldKey));
             Doc.SetContainer(droppedDocs.lastElement(), this.dataDoc);
             !added && e.preventDefault();
             e.stopPropagation(); // prevent parent Doc from registering new position so that it snaps back into place
@@ -93,18 +93,18 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl
 
     getAnchor = (addAsAnnotation: boolean, pinProps?: PinProps) => {
         const anchor = Docs.Create.ConfigDocument({
-            title: 'CompareAnchor:' + this.rootDoc.title,
+            title: 'CompareAnchor:' + this.Document.title,
             // set presentation timing properties for restoring view
             presentation_transition: 1000,
-            annotationOn: this.rootDoc,
+            annotationOn: this.Document,
         });
         if (anchor) {
             if (!addAsAnnotation) anchor.backgroundColor = 'transparent';
             /* addAsAnnotation &&*/ this.addDocument(anchor);
-            PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: { ...(pinProps?.pinData ?? {}), clippable: true } }, this.rootDoc);
+            PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: { ...(pinProps?.pinData ?? {}), clippable: true } }, this.Document);
             return anchor;
         }
-        return this.rootDoc;
+        return this.Document;
     };
 
     @undoBatch
diff --git a/src/client/views/nodes/DataVizBox/DataVizBox.tsx b/src/client/views/nodes/DataVizBox/DataVizBox.tsx
index 1cb0a50f3..cc2c44435 100644
--- a/src/client/views/nodes/DataVizBox/DataVizBox.tsx
+++ b/src/client/views/nodes/DataVizBox/DataVizBox.tsx
@@ -35,7 +35,7 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
 
     // all CSV records in the dataset (that aren't an empty row)
     @computed.struct get records() {
-        var records = DataVizBox.dataset.get(CsvCast(this.rootDoc[this.fieldKey]).url.href);
+        var records = DataVizBox.dataset.get(CsvCast(this.dataDoc[this.fieldKey]).url.href);
         return records?.filter(record => Object.keys(record).some(key => record[key])) ?? [];
     }
 
@@ -75,7 +75,7 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
     };
     getAnchor = (addAsAnnotation?: boolean, pinProps?: PinProps) => {
         const anchor = !pinProps
-            ? this.rootDoc
+            ? this.Document
             : this._vizRenderer?.getAnchor(pinProps) ??
               Docs.Create.ConfigDocument({
                   // when we clear selection -> we should have it so chartBox getAnchor returns undefined
@@ -99,20 +99,20 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
 
     componentDidMount() {
         this.props.setContentView?.(this);
-        if (!DataVizBox.dataset.has(CsvCast(this.rootDoc[this.fieldKey]).url.href)) this.fetchData();
+        if (!DataVizBox.dataset.has(CsvCast(this.dataDoc[this.fieldKey]).url.href)) this.fetchData();
     }
 
     fetchData = () => {
-        DataVizBox.dataset.set(CsvCast(this.rootDoc[this.fieldKey]).url.href, []); // assign temporary dataset as a lock to prevent duplicate server requests
+        DataVizBox.dataset.set(CsvCast(this.dataDoc[this.fieldKey]).url.href, []); // assign temporary dataset as a lock to prevent duplicate server requests
         fetch('/csvData?uri=' + this.dataUrl?.url.href) //
-            .then(res => res.json().then(action(res => !res.errno && DataVizBox.dataset.set(CsvCast(this.rootDoc[this.fieldKey]).url.href, res))));
+            .then(res => res.json().then(action(res => !res.errno && DataVizBox.dataset.set(CsvCast(this.dataDoc[this.fieldKey]).url.href, res))));
     };
 
     // toggles for user to decide which chart type to view the data in
     @computed get renderVizView() {
         const scale = this.props.NativeDimScaling?.() || 1;
         const sharedProps = {
-            rootDoc: this.rootDoc,
+            rootDoc: this.Document,
             layoutDoc: this.layoutDoc,
             records: this.records,
             axes: this.axes,
diff --git a/src/client/views/nodes/DataVizBox/components/LineChart.tsx b/src/client/views/nodes/DataVizBox/components/LineChart.tsx
index 3de7a0c4a..ad34a0c99 100644
--- a/src/client/views/nodes/DataVizBox/components/LineChart.tsx
+++ b/src/client/views/nodes/DataVizBox/components/LineChart.tsx
@@ -23,7 +23,7 @@ export interface SelectedDataPoint extends DataPoint {
     elem?: d3.Selection<d3.BaseType, unknown, SVGGElement, unknown>;
 }
 export interface LineChartProps {
-    rootDoc: Doc;
+    Document: Doc;
     layoutDoc: Doc;
     axes: string[];
     records: { [key: string]: any }[];
@@ -63,7 +63,7 @@ export class LineChart extends React.Component<LineChartProps> {
         return this.props.axes[1] + ' vs. ' + this.props.axes[0] + ' Line Chart';
     }
     @computed get parentViz() {
-        return DocCast(this.props.rootDoc.dataViz_parentViz);
+        return DocCast(this.props.Document.dataViz_parentViz);
         // return LinkManager.Instance.getAllRelatedLinks(this.props.rootDoc) // out of all links
         //     .filter(link => {
         //         return link.link_anchor_1 == this.props.rootDoc.dataViz_parentViz;
@@ -74,7 +74,7 @@ export class LineChart extends React.Component<LineChartProps> {
         // return selected x and y axes
         // otherwise, use the selection of whatever is linked to us
         const incomingVizBox = DocumentManager.Instance.getFirstDocumentView(this.parentViz)?.ComponentView as DataVizBox;
-        const highlitedRowIds = NumListCast(incomingVizBox?.rootDoc?.dataViz_highlitedRows);
+        const highlitedRowIds = NumListCast(incomingVizBox?.layoutDoc?.dataViz_highlitedRows);
         return this._tableData.filter((record, i) => highlitedRowIds.includes(this._tableDataIds[i])); // get all the datapoints they have selected field set by incoming anchor
     }
     @computed get rangeVals(): { xMin?: number; xMax?: number; yMin?: number; yMax?: number } {
@@ -170,7 +170,7 @@ export class LineChart extends React.Component<LineChartProps> {
             //
             title: 'line doc selection' + this._currSelected?.x,
         });
-        PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: pinProps?.pinData }, this.props.rootDoc);
+        PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: pinProps?.pinData }, this.props.Document);
         anchor.config_dataVizSelection = this._currSelected ? new List<number>([this._currSelected.x, this._currSelected.y]) : undefined;
         return anchor;
     };
diff --git a/src/client/views/nodes/FunctionPlotBox.tsx b/src/client/views/nodes/FunctionPlotBox.tsx
index daf6cd9a6..5ed5fa8fd 100644
--- a/src/client/views/nodes/FunctionPlotBox.tsx
+++ b/src/client/views/nodes/FunctionPlotBox.tsx
@@ -43,11 +43,8 @@ export class FunctionPlotBox extends ViewBoxAnnotatableComponent<FieldViewProps>
         );
     }
     getAnchor = (addAsAnnotation: boolean, pinProps?: PinProps) => {
-        const anchor = Docs.Create.ConfigDocument({
-            //
-            annotationOn: this.rootDoc,
-        });
-        PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: { ...(pinProps?.pinData ?? {}), datarange: true } }, this.rootDoc);
+        const anchor = Docs.Create.ConfigDocument({ annotationOn: this.Document });
+        PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: { ...(pinProps?.pinData ?? {}), datarange: true } }, this.Document);
         anchor.config_xRange = new List<number>(Array.from(this._plot.options.xAxis.domain));
         anchor.config_yRange = new List<number>(Array.from(this._plot.options.yAxis.domain));
         if (addAsAnnotation) this.addDocument(anchor);
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index 19e393968..7e85c33b8 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -89,26 +89,26 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
         const anchor =
             visibleAnchor ??
             Docs.Create.ConfigDocument({
-                title: 'ImgAnchor:' + this.rootDoc.title,
+                title: 'ImgAnchor:' + this.Document.title,
                 config_panX: NumCast(this.layoutDoc._freeform_panX),
                 config_panY: NumCast(this.layoutDoc._freeform_panY),
                 config_viewScale: Cast(this.layoutDoc._freeform_scale, 'number', null),
-                annotationOn: this.rootDoc,
+                annotationOn: this.Document,
             });
         if (anchor) {
             if (!addAsAnnotation) anchor.backgroundColor = 'transparent';
             addAsAnnotation && this.addDocument(anchor);
-            PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: { ...(pinProps?.pinData ?? {}), pannable: visibleAnchor ? false : true } }, this.rootDoc);
+            PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: { ...(pinProps?.pinData ?? {}), pannable: visibleAnchor ? false : true } }, this.Document);
             return anchor;
         }
-        return this.rootDoc;
+        return this.Document;
     };
 
     componentDidMount() {
         this._disposers.sizer = reaction(
             () => ({
                 forceFull: this.props.renderDepth < 1 || this.layoutDoc._showFullRes,
-                scrSize: (this.props.ScreenToLocalTransform().inverse().transformDirection(this.nativeSize.nativeWidth, this.nativeSize.nativeHeight)[0] / this.nativeSize.nativeWidth) * NumCast(this.rootDoc._freeform_scale, 1),
+                scrSize: (this.props.ScreenToLocalTransform().inverse().transformDirection(this.nativeSize.nativeWidth, this.nativeSize.nativeHeight)[0] / this.nativeSize.nativeWidth) * NumCast(this.layoutDoc._freeform_scale, 1),
                 selected: this.props.isSelected(),
             }),
             ({ forceFull, scrSize, selected }) => (this._curSuffix = selected ? '_o' : this.fieldKey === 'icon' ? '_m' : forceFull ? '_o' : scrSize < 0.25 ? '_s' : scrSize < 0.5 ? '_m' : scrSize < 0.8 ? '_l' : '_o'),
@@ -152,7 +152,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
             };
             if (de.metaKey || targetIsBullseye(e.target as HTMLElement)) {
                 added = de.complete.docDragData.droppedDocuments.reduce((last: boolean, drop: Doc) => {
-                    this.rootDoc[this.fieldKey + '_usePath'] = 'alternate:hover';
+                    this.layoutDoc[this.fieldKey + '_usePath'] = 'alternate:hover';
                     return last && Doc.AddDocToList(this.dataDoc, this.fieldKey + '-alternates', drop);
                 }, true);
             } else if (de.altKey || !this.dataDoc[this.fieldKey]) {
@@ -177,13 +177,13 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
 
     @undoBatch
     setNativeSize = action(() => {
-        const scaling = (this.props.DocumentView?.().props.ScreenToLocalTransform().Scale || 1) / NumCast(this.rootDoc._freeform_scale, 1);
+        const scaling = (this.props.DocumentView?.().props.ScreenToLocalTransform().Scale || 1) / NumCast(this.layoutDoc._freeform_scale, 1);
         const nscale = NumCast(this.props.PanelWidth()) / scaling;
         const nw = nscale / NumCast(this.dataDoc[this.fieldKey + '_nativeWidth']);
         this.dataDoc[this.fieldKey + '_nativeHeight'] = NumCast(this.dataDoc[this.fieldKey + '_nativeHeight']) * nw;
         this.dataDoc[this.fieldKey + '_nativeWidth'] = NumCast(this.dataDoc[this.fieldKey + '_nativeWidth']) * nw;
-        this.rootDoc._freeform_panX = nw * NumCast(this.rootDoc._freeform_panX);
-        this.rootDoc._freeform_panY = nw * NumCast(this.rootDoc._freeform_panY);
+        this.layoutDoc._freeform_panX = nw * NumCast(this.layoutDoc._freeform_panX);
+        this.layoutDoc._freeform_panY = nw * NumCast(this.layoutDoc._freeform_panY);
         this.dataDoc._freeform_panXMax = this.dataDoc._freeform_panXMax ? nw * NumCast(this.dataDoc._freeform_panXMax) : undefined;
         this.dataDoc._freeform_panXMin = this.dataDoc._freeform_panXMin ? nw * NumCast(this.dataDoc._freeform_panXMin) : undefined;
         this.dataDoc._freeform_panYMax = this.dataDoc._freeform_panYMax ? nw * NumCast(this.dataDoc._freeform_panYMax) : undefined;
@@ -206,17 +206,17 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
         if (!region) return;
         const cropping = Doc.MakeCopy(region, true);
         Doc.GetProto(region).lockedPosition = true;
-        Doc.GetProto(region).title = 'region:' + this.rootDoc.title;
+        Doc.GetProto(region).title = 'region:' + this.Document.title;
         Doc.GetProto(region).followLinkToggle = true;
         this.addDocument(region);
         const anchx = NumCast(cropping.x);
         const anchy = NumCast(cropping.y);
         const anchw = NumCast(cropping._width);
         const anchh = NumCast(cropping._height);
-        const viewScale = NumCast(this.rootDoc[this.fieldKey + '_nativeWidth']) / anchw;
-        cropping.title = 'crop: ' + this.rootDoc.title;
-        cropping.x = NumCast(this.rootDoc.x) + NumCast(this.rootDoc._width);
-        cropping.y = NumCast(this.rootDoc.y);
+        const viewScale = NumCast(this.dataDoc[this.fieldKey + '_nativeWidth']) / anchw;
+        cropping.title = 'crop: ' + this.Document.title;
+        cropping.x = NumCast(this.Document.x) + NumCast(this.layoutDoc._width);
+        cropping.y = NumCast(this.Document.y);
         cropping._width = anchw * (this.props.NativeDimScaling?.() || 1);
         cropping._height = anchh * (this.props.NativeDimScaling?.() || 1);
         cropping.onClick = undefined;
@@ -224,10 +224,10 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
         croppingProto.annotationOn = undefined;
         croppingProto.isDataDoc = true;
         croppingProto.backgroundColor = undefined;
-        croppingProto.proto = Cast(this.rootDoc.proto, Doc, null)?.proto; // set proto of cropping's data doc to be IMAGE_PROTO
+        croppingProto.proto = Cast(this.Document.proto, Doc, null)?.proto; // set proto of cropping's data doc to be IMAGE_PROTO
         croppingProto.type = DocumentType.IMG;
         croppingProto.layout = ImageBox.LayoutString('data');
-        croppingProto.data = ObjectField.MakeCopy(this.rootDoc[this.fieldKey] as ObjectField);
+        croppingProto.data = ObjectField.MakeCopy(this.dataDoc[this.fieldKey] as ObjectField);
         croppingProto['data_nativeWidth'] = anchw;
         croppingProto['data_nativeHeight'] = anchh;
         croppingProto.freeform_scale = viewScale;
@@ -240,8 +240,8 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
         croppingProto.freeform_panY_max = anchh / viewScale;
         if (addCrop) {
             DocUtils.MakeLink(region, cropping, { link_relationship: 'cropped image' });
-            cropping.x = NumCast(this.rootDoc.x) + NumCast(this.rootDoc._width);
-            cropping.y = NumCast(this.rootDoc.y);
+            cropping.x = NumCast(this.Document.x) + NumCast(this.layoutDoc._width);
+            cropping.y = NumCast(this.Document.y);
             this.props.addDocTab(cropping, OpenWhere.inParent);
         }
         DocumentManager.Instance.AddViewRenderedCb(cropping, dv => setTimeout(() => (dv.ComponentView as ImageBox).setNativeSize(), 200));
@@ -263,7 +263,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
                     ImageBox.setImageEditorOpen(true);
                     ImageBox.setImageEditorSource(this.choosePath(field.url));
                     ImageBox.addDoc = this.props.addDocument;
-                    ImageBox.imageRootDoc = this.rootDoc;
+                    ImageBox.imageRootDoc = this.Document;
                 }),
                 icon: 'pencil-alt',
             });
@@ -332,7 +332,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
         return !tags ? null : <img id={'google-tags'} src={'/assets/google_tags.png'} />;
     };
 
-    getScrollHeight = () => (this.props.layout_fitWidth?.(this.rootDoc) !== false && NumCast(this.rootDoc._freeform_scale, 1) === NumCast(this.rootDoc._freeform_scaleMin, 1) ? this.nativeSize.nativeHeight : undefined);
+    getScrollHeight = () => (this.props.layout_fitWidth?.(this.Document) !== false && NumCast(this.layoutDoc._freeform_scale, 1) === NumCast(this.dataDoc._freeform_scaleMin, 1) ? this.nativeSize.nativeHeight : undefined);
 
     @computed
     private get considerDownloadIcon() {
@@ -384,7 +384,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
         return { nativeWidth, nativeHeight, nativeOrientation };
     }
     @computed get overlayImageIcon() {
-        const usePath = this.rootDoc[`_${this.fieldKey}_usePath`];
+        const usePath = this.layoutDoc[`_${this.fieldKey}_usePath`];
         return (
             <Tooltip
                 title={
@@ -405,7 +405,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
                 <div
                     className="imageBox-alternateDropTarget"
                     ref={this._overlayIconRef}
-                    onPointerDown={e => setupMoveUpEvents(e.target, e, returnFalse, emptyFunction, e => (this.rootDoc[`_${this.fieldKey}_usePath`] = usePath === undefined ? 'alternate' : usePath === 'alternate' ? 'alternate:hover' : undefined))}
+                    onPointerDown={e => setupMoveUpEvents(e.target, e, returnFalse, emptyFunction, e => (this.layoutDoc[`_${this.fieldKey}_usePath`] = usePath === undefined ? 'alternate' : usePath === 'alternate' ? 'alternate:hover' : undefined))}
                     style={{
                         display: (this.props.isContentActive() !== false && DragManager.DocDragData?.canEmbed) || DocListCast(this.dataDoc[this.fieldKey + '-alternates']).length ? 'block' : 'none',
                         width: 'min(10%, 25px)',
@@ -434,7 +434,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
     @computed get content() {
         TraceMobx();
 
-        const backColor = DashColor(this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.BackgroundColor));
+        const backColor = DashColor(this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.BackgroundColor));
         const backAlpha = backColor.red() === 0 && backColor.green() === 0 && backColor.blue() === 0 ? backColor.alpha() : 1;
         const srcpath = this.layoutDoc.hideImage ? '' : this.paths[0];
         const fadepath = this.layoutDoc.hideImage ? '' : this.paths.lastElement();
@@ -452,7 +452,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
             transformOrigin = 'right top';
             transform = `translate(-100%, 0%) rotate(${rotation}deg) scale(${aspect})`;
         }
-        const usePath = this.rootDoc[`_${this.fieldKey}_usePath`];
+        const usePath = this.layoutDoc[`_${this.fieldKey}_usePath`];
 
         return (
             <div className="imageBox-cont" onPointerEnter={action(() => (this._isHovering = true))} onPointerLeave={action(() => (this._isHovering = false))} key={this.layoutDoc[Id]} ref={this.createDropTarget} onPointerDown={this.marqueeDown}>
@@ -481,7 +481,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
     }
     screenToLocalTransform = () => this.props.ScreenToLocalTransform().translate(0, NumCast(this.layoutDoc._layout_scrollTop) * this.props.ScreenToLocalTransform().Scale);
     marqueeDown = (e: React.PointerEvent) => {
-        if (!e.altKey && e.button === 0 && NumCast(this.rootDoc._freeform_scale, 1) <= NumCast(this.rootDoc.freeform_scaleMin, 1) && this.props.isContentActive(true) && ![InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(Doc.ActiveTool)) {
+        if (!e.altKey && e.button === 0 && NumCast(this.layoutDoc._freeform_scale, 1) <= NumCast(this.dataDoc.freeform_scaleMin, 1) && this.props.isContentActive(true) && ![InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(Doc.ActiveTool)) {
             setupMoveUpEvents(
                 this,
                 e,
@@ -529,7 +529,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
                     height: this.props.PanelWidth() ? undefined : `100%`,
                     pointerEvents: this.layoutDoc._lockedPosition ? 'none' : undefined,
                     borderRadius,
-                    overflow: this.layoutDoc.layout_fitWidth || this.props.layout_fitWidth?.(this.rootDoc) ? 'auto' : undefined,
+                    overflow: this.layoutDoc.layout_fitWidth || this.props.layout_fitWidth?.(this.Document) ? 'auto' : undefined,
                 }}>
                 <CollectionFreeFormView
                     ref={this._ffref}
diff --git a/src/client/views/nodes/LoadingBox.tsx b/src/client/views/nodes/LoadingBox.tsx
index 4bb0f14d2..86c91ae3c 100644
--- a/src/client/views/nodes/LoadingBox.tsx
+++ b/src/client/views/nodes/LoadingBox.tsx
@@ -57,13 +57,13 @@ export class LoadingBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
     _timer: any;
     @observable progress = '';
     componentDidMount() {
-        if (!LoadingBox.CurrentlyLoading?.includes(this.rootDoc)) {
-            this.rootDoc.loadingError = 'Upload interrupted, please try again';
+        if (!LoadingBox.CurrentlyLoading?.includes(this.Document)) {
+            this.Document.loadingError = 'Upload interrupted, please try again';
         } else {
             const updateFunc = async () => {
-                const result = await Networking.QueryYoutubeProgress(StrCast(this.rootDoc[Id])); // We use the guid of the overwriteDoc to track file uploads.
+                const result = await Networking.QueryYoutubeProgress(StrCast(this.Document[Id])); // We use the guid of the overwriteDoc to track file uploads.
                 runInAction(() => (this.progress = result.progress));
-                !this.rootDoc.loadingError && (this._timer = setTimeout(updateFunc, 1000));
+                !this.Document.loadingError && (this._timer = setTimeout(updateFunc, 1000));
             };
             this._timer = setTimeout(updateFunc, 1000);
         }
@@ -74,11 +74,11 @@ export class LoadingBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
 
     render() {
         return (
-            <div className="loadingBoxContainer" style={{ background: !this.rootDoc.loadingError ? '' : 'red' }}>
+            <div className="loadingBoxContainer" style={{ background: !this.Document.loadingError ? '' : 'red' }}>
                 <div className="loadingBox-textContainer">
-                    <span className="loadingBox-title">{StrCast(this.rootDoc.title)}</span>
-                    <p className="loadingBox-headerText">{StrCast(this.rootDoc.loadingError, 'Loading ' + (this.progress.replace('[download]', '') || '(can take several minutes)'))}</p>
-                    {this.rootDoc.loadingError ? null : (
+                    <span className="loadingBox-title">{StrCast(this.Document.title)}</span>
+                    <p className="loadingBox-headerText">{StrCast(this.Document.loadingError, 'Loading ' + (this.progress.replace('[download]', '') || '(can take several minutes)'))}</p>
+                    {this.rootDDocumentoc.loadingError ? null : (
                         <div className="loadingBox-spinner">
                             <ReactLoading type="spinningBubbles" color="blue" height={100} width={100} />
                         </div>
diff --git a/src/client/views/nodes/MapBox/MapBox.tsx b/src/client/views/nodes/MapBox/MapBox.tsx
index 9b75ca7e3..8d3cd1d96 100644
--- a/src/client/views/nodes/MapBox/MapBox.tsx
+++ b/src/client/views/nodes/MapBox/MapBox.tsx
@@ -195,7 +195,7 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
                 title="Toggle Sidebar"
                 style={{
                     display: !this.props.isContentActive() ? 'none' : undefined,
-                    top: StrCast(this.rootDoc._layout_showTitle) === 'title' ? 20 : 5,
+                    top: StrCast(this.layoutDoc._layout_showTitle) === 'title' ? 20 : 5,
                     backgroundColor: this.SidebarShown ? Colors.MEDIUM_BLUE : Colors.BLACK,
                 }}
                 onPointerDown={this.sidebarBtnDown}>
@@ -227,7 +227,7 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
         });
 
         const targetCreator = (annotationOn: Doc | undefined) => {
-            const target = DocUtils.GetNewTextDoc('Note linked to ' + this.rootDoc.title, 0, 0, 100, 100, undefined, annotationOn, undefined, 'yellow');
+            const target = DocUtils.GetNewTextDoc('Note linked to ' + this.Document.title, 0, 0, 100, 100, undefined, annotationOn, undefined, 'yellow');
             FormattedTextBox.SelectOnLoad = target[Id];
             return target;
         };
@@ -321,7 +321,7 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
     };
 
     @observable
-    bingSearchBarContents: any = this.rootDoc.map; // For Bing Maps: The contents of the Bing search bar (string)
+    bingSearchBarContents: any = this.dataDoc.map; // For Bing Maps: The contents of the Bing search bar (string)
 
     geoDataRequestOptions = {
         entityType: 'PopulatedPlace',
@@ -354,9 +354,9 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
     deselectPin = () => {
         if (this.selectedPin) {
             // Removes filter
-            Doc.setDocFilter(this.rootDoc, 'latitude', this.selectedPin.latitude, 'remove');
-            Doc.setDocFilter(this.rootDoc, 'longitude', this.selectedPin.longitude, 'remove');
-            Doc.setDocFilter(this.rootDoc, LinkedTo, `mapPin=${Field.toScriptString(DocCast(this.selectedPin))}`, 'remove');
+            Doc.setDocFilter(this.layoutDoc, 'latitude', this.selectedPin.latitude, 'remove');
+            Doc.setDocFilter(this.layoutDoc, 'longitude', this.selectedPin.longitude, 'remove');
+            Doc.setDocFilter(this.layoutDoc, LinkedTo, `mapPin=${Field.toScriptString(DocCast(this.selectedPin))}`, 'remove');
 
             const temp = this.selectedPin;
             if (!this._unmounting) {
@@ -369,7 +369,7 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
             }
             this.map_docToPinMap.set(temp, newpin);
             this.selectedPin = undefined;
-            this.bingSearchBarContents = this.rootDoc.map;
+            this.bingSearchBarContents = this.dataDoc.map;
         }
     };
 
@@ -388,7 +388,7 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
 
         // Doc.setDocFilter(this.rootDoc, 'latitude', this.selectedPin.latitude, 'match');
         // Doc.setDocFilter(this.rootDoc, 'longitude', this.selectedPin.longitude, 'match');
-        Doc.setDocFilter(this.rootDoc, LinkedTo, `mapPin=${Field.toScriptString(this.selectedPin)}`, 'check');
+        Doc.setDocFilter(this.layoutDoc, LinkedTo, `mapPin=${Field.toScriptString(this.selectedPin)}`, 'check');
 
         this.recolorPin(this.selectedPin, 'green');
 
@@ -457,8 +457,8 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
     getAnchor = (addAsAnnotation: boolean, pinProps?: PinProps, existingPin?: Doc) => {
         /// this should use SELECTED pushpin for lat/long  if there is a selection, otherwise CENTER
         const anchor = Docs.Create.ConfigDocument({
-            title: 'MapAnchor:' + this.rootDoc.title,
-            text: StrCast(this.selectedPin?.map) || StrCast(this.rootDoc.map) || 'map location',
+            title: 'MapAnchor:' + this.Document.title,
+            text: StrCast(this.selectedPin?.map) || StrCast(this.dataDoc.map) || 'map location',
             config_latitude: NumCast((existingPin ?? this.selectedPin)?.latitude ?? this.dataDoc.latitude),
             config_longitude: NumCast((existingPin ?? this.selectedPin)?.longitude ?? this.dataDoc.longitude),
             config_map_zoom: NumCast(this.dataDoc.map_zoom),
@@ -466,15 +466,15 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
             config_map: StrCast((existingPin ?? this.selectedPin)?.map) || StrCast(this.dataDoc.map),
             layout_unrendered: true,
             mapPin: existingPin ?? this.selectedPin,
-            annotationOn: this.rootDoc,
+            annotationOn: this.Document,
         });
         if (anchor) {
             if (!addAsAnnotation) anchor.backgroundColor = 'transparent';
             addAsAnnotation && this.addDocument(anchor);
-            PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: { ...(pinProps?.pinData ?? {}), map: true } }, this.rootDoc);
+            PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: { ...(pinProps?.pinData ?? {}), map: true } }, this.Document);
             return anchor;
         }
-        return this.rootDoc;
+        return this.Document;
     };
 
     map_docToPinMap = new Map<Doc, any>();
@@ -521,9 +521,9 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
     deleteSelectedPin = undoable(() => {
         if (this.selectedPin) {
             // Removes filter
-            Doc.setDocFilter(this.rootDoc, 'latitude', this.selectedPin.latitude, 'remove');
-            Doc.setDocFilter(this.rootDoc, 'longitude', this.selectedPin.longitude, 'remove');
-            Doc.setDocFilter(this.rootDoc, LinkedTo, `mapPin=${Field.toScriptString(DocCast(this.selectedPin))}`, 'remove');
+            Doc.setDocFilter(this.layoutDoc, 'latitude', this.selectedPin.latitude, 'remove');
+            Doc.setDocFilter(this.layoutDoc, 'longitude', this.selectedPin.longitude, 'remove');
+            Doc.setDocFilter(this.layoutDoc, LinkedTo, `mapPin=${Field.toScriptString(DocCast(this.selectedPin))}`, 'remove');
 
             this.removePushpin(this.selectedPin);
         }
@@ -611,7 +611,7 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
         this.MicrosoftMaps.Events.addHandler(this._bingMap.current, 'maptypechanged', undoable(this.updateMapType, 'Map ViewType Change'));
 
         this._disposers.mapLocation = reaction(
-            () => this.rootDoc.map,
+            () => this.dataDoc.map,
             mapLoc => (this.bingSearchBarContents = mapLoc),
             { fireImmediately: true }
         );
@@ -636,7 +636,7 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
         );
 
         this._disposers.location = reaction(
-            () => ({ lat: this.rootDoc.latitude, lng: this.rootDoc.longitude, zoom: this.rootDoc.map_zoom, mapType: this.rootDoc.map_type }),
+            () => ({ lat: this.dataDoc.latitude, lng: this.dataDoc.longitude, zoom: this.dataDoc.map_zoom, mapType: this.dataDoc.map_type }),
             locationObject => {
                 // if (this._bingMap.current)
                 try {
@@ -687,7 +687,7 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
                 }
             },
             e => {
-                const createPin = () => this.createPushpin(this.rootDoc.latitude, this.rootDoc.longitude, this.rootDoc.map);
+                const createPin = () => this.createPushpin(this.dataDoc.latitude, this.dataDoc.longitude, this.dataDoc.map);
                 if (this.bingSearchBarContents) {
                     this.bingSearch().then(createPin);
                 } else createPin();
@@ -703,7 +703,7 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
     render() {
         // bcz:  no idea what's going on here, but bings maps have some kind of bug
         // such that we need to delay rendering a second map on startup until the first map is rendered.
-        this.rootDoc[DocCss];
+        this.Document[DocCss];
         if (MapBox._rerenderDelay) {
             // prettier-ignore
             this._rerenderTimeout = this._rerenderTimeout ??
@@ -712,7 +712,7 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
                         MapBox._rerenderDelay = 0;
                     }
                     this._rerenderTimeout = undefined;
-                    this.rootDoc[DocCss] = this.rootDoc[DocCss] + 1;
+                    this.Document[DocCss] = this.Document[DocCss] + 1;
                 }), MapBox._rerenderDelay);
             return null;
         }
@@ -812,7 +812,7 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
                         ref={this._sidebarRef}
                         {...this.props}
                         fieldKey={this.fieldKey}
-                        rootDoc={this.rootDoc}
+                        Document={this.Document}
                         layoutDoc={this.layoutDoc}
                         dataDoc={this.dataDoc}
                         usePanelWidth={true}
diff --git a/src/client/views/nodes/MapBox/MapBox2.tsx b/src/client/views/nodes/MapBox/MapBox2.tsx
index 6bad7d724..a77bfc50a 100644
--- a/src/client/views/nodes/MapBox/MapBox2.tsx
+++ b/src/client/views/nodes/MapBox/MapBox2.tsx
@@ -445,7 +445,7 @@ export class MapBox2 extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
                 title="Toggle Sidebar"
                 style={{
                     display: !this.props.isContentActive() ? 'none' : undefined,
-                    top: StrCast(this.rootDoc._layout_showTitle) === 'title' ? 20 : 5,
+                    top: StrCast(this.layoutDoc._layout_showTitle) === 'title' ? 20 : 5,
                     backgroundColor: this.SidebarShown ? Colors.MEDIUM_BLUE : Colors.BLACK,
                 }}
                 onPointerDown={this.sidebarBtnDown}>
@@ -495,7 +495,7 @@ export class MapBox2 extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
         );
     }
 
-    getAnchor = (addAsAnnotation: boolean, pinProps?: PinProps) => AnchorMenu.Instance?.GetAnchor(this._savedAnnotations, addAsAnnotation) ?? this.rootDoc;
+    getAnchor = (addAsAnnotation: boolean, pinProps?: PinProps) => AnchorMenu.Instance?.GetAnchor(this._savedAnnotations, addAsAnnotation) ?? this.Document;
 
     /**
      * render contents in allMapMarkers (e.g. images with exifData) into google maps as map marker
@@ -577,7 +577,7 @@ export class MapBox2 extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
                         ref={this._sidebarRef}
                         {...this.props}
                         fieldKey={this.fieldKey}
-                        rootDoc={this.rootDoc}
+                        Document={this.Document}
                         layoutDoc={this.layoutDoc}
                         dataDoc={this.dataDoc}
                         usePanelWidth={true}
diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx
index 1035116d5..9787de0ab 100644
--- a/src/client/views/nodes/PDFBox.tsx
+++ b/src/client/views/nodes/PDFBox.tsx
@@ -97,7 +97,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
         if (!region) return;
         const cropping = Doc.MakeCopy(region, true);
         Doc.GetProto(region).lockedPosition = true;
-        Doc.GetProto(region).title = 'region:' + this.rootDoc.title;
+        Doc.GetProto(region).title = 'region:' + this.Document.title;
         Doc.GetProto(region).followLinkToggle = true;
         this.addDocument(region);
 
@@ -113,16 +113,16 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
         const anchw = NumCast(cropping._width) * (this.props.NativeDimScaling?.() || 1);
         const anchh = NumCast(cropping._height) * (this.props.NativeDimScaling?.() || 1);
         const viewScale = 1;
-        cropping.title = 'crop: ' + this.rootDoc.title;
-        cropping.x = NumCast(this.rootDoc.x) + NumCast(this.rootDoc._width);
-        cropping.y = NumCast(this.rootDoc.y);
+        cropping.title = 'crop: ' + this.Document.title;
+        cropping.x = NumCast(this.Document.x) + NumCast(this.layoutDoc._width);
+        cropping.y = NumCast(this.Document.y);
         cropping._width = anchw;
         cropping._height = anchh;
         cropping.onClick = undefined;
         const croppingProto = Doc.GetProto(cropping);
         croppingProto.annotationOn = undefined;
         croppingProto.isDataDoc = true;
-        croppingProto.proto = Cast(this.rootDoc.proto, Doc, null)?.proto; // set proto of cropping's data doc to be IMAGE_PROTO
+        croppingProto.proto = Cast(this.Document.proto, Doc, null)?.proto; // set proto of cropping's data doc to be IMAGE_PROTO
         croppingProto.type = DocumentType.IMG;
         croppingProto.layout = ImageBox.LayoutString('data');
         croppingProto.data = new ImageField(Utils.CorsProxy('http://www.cs.brown.edu/~bcz/noImage.png'));
@@ -139,8 +139,8 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
             htmlString,
             anchw,
             anchh,
-            (NumCast(region.y) * this.props.PanelWidth()) / NumCast(this.rootDoc[this.fieldKey + '_nativeWidth']),
-            (NumCast(region.x) * this.props.PanelWidth()) / NumCast(this.rootDoc[this.fieldKey + '_nativeWidth']),
+            (NumCast(region.y) * this.props.PanelWidth()) / NumCast(this.dataDoc[this.fieldKey + '_nativeWidth']),
+            (NumCast(region.x) * this.props.PanelWidth()) / NumCast(this.dataDoc[this.fieldKey + '_nativeWidth']),
             4
         )
             .then((data_url: any) => {
@@ -173,7 +173,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
                 this.props.PanelWidth(),
                 this.props.PanelHeight(),
                 NumCast(this.layoutDoc._layout_scrollTop),
-                NumCast(this.rootDoc[this.fieldKey + '_nativeHeight'], 1),
+                NumCast(this.dataDoc[this.fieldKey + '_nativeHeight'], 1),
                 true,
                 this.layoutDoc[Id] + '-icon',
                 (iconFile: string, nativeWidth: number, nativeHeight: number) => {
@@ -200,13 +200,13 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
             { fireImmediately: true }
         );
         this._disposers.scroll = reaction(
-            () => this.rootDoc.layout_scrollTop,
+            () => this.layoutDoc.layout_scrollTop,
             () => {
                 if (!(ComputedField.WithoutComputed(() => FieldValue(this.props.Document[this.SidebarKey + '_panY'])) instanceof ComputedField)) {
                     this.props.Document[this.SidebarKey + '_panY'] = ComputedField.MakeFunction('this.layout_scrollTop');
                 }
-                this.props.Document[this.SidebarKey + '_freeform_scale'] = 1;
-                this.props.Document[this.SidebarKey + '_freeform_panX'] = 0;
+                this.layoutDoc[this.SidebarKey + '_freeform_scale'] = 1;
+                this.layoutDoc[this.SidebarKey + '_freeform_panX'] = 0;
             }
         );
     }
@@ -236,12 +236,12 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
         }
         const docAnchor = () =>
             Docs.Create.ConfigDocument({
-                title: StrCast(this.rootDoc.title + '@' + NumCast(this.layoutDoc._layout_scrollTop)?.toFixed(0)),
-                annotationOn: this.rootDoc,
+                title: StrCast(this.Document.title + '@' + NumCast(this.layoutDoc._layout_scrollTop)?.toFixed(0)),
+                annotationOn: this.Document,
             });
         const visibleAnchor = this._pdfViewer?._getAnchor?.(this._pdfViewer.savedAnnotations(), true);
         const anchor = visibleAnchor ?? docAnchor();
-        PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: { ...(pinProps?.pinData ?? {}), scrollable: true, pannable: true } }, this.rootDoc);
+        PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: { ...(pinProps?.pinData ?? {}), scrollable: true, pannable: true } }, this.Document);
         anchor.text = ele?.textContent ?? '';
         anchor.text_html = ele?.innerHTML;
         addAsAnnotation && this.addDocument(anchor);
@@ -434,7 +434,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
         return PDFBox.sidebarResizerWidth + nativeDiff * (this.props.NativeDimScaling?.() || 1);
     };
     @undoBatch
-    toggleSidebarType = () => (this.rootDoc[this.SidebarKey + '_type_collection'] = this.rootDoc[this.SidebarKey + '_type_collection'] === CollectionViewType.Freeform ? CollectionViewType.Stacking : CollectionViewType.Freeform);
+    toggleSidebarType = () => (this.dataDoc[this.SidebarKey + '_type_collection'] = this.dataDoc[this.SidebarKey + '_type_collection'] === CollectionViewType.Freeform ? CollectionViewType.Stacking : CollectionViewType.Freeform);
     specificContextMenu = (e: React.MouseEvent): void => {
         const cm = ContextMenu.Instance;
         const options = cm.findByDescription('Options...');
@@ -473,7 +473,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
                 title="Toggle Sidebar"
                 style={{
                     display: !this.props.isContentActive() ? 'none' : undefined,
-                    top: StrCast(this.rootDoc._layout_showTitle) === 'title' ? 20 : 5,
+                    top: StrCast(this.layoutDoc._layout_showTitle) === 'title' ? 20 : 5,
                     backgroundColor: this.SidebarShown ? Colors.MEDIUM_BLUE : Colors.BLACK,
                 }}
                 onPointerDown={e => this.sidebarBtnDown(e, true)}>
@@ -509,7 +509,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
                 <SidebarAnnos
                     ref={this._sidebarRef}
                     {...this.props}
-                    rootDoc={this.rootDoc}
+                    Document={this.Document}
                     layoutDoc={this.layoutDoc}
                     dataDoc={this.dataDoc}
                     setHeight={emptyFunction}
diff --git a/src/client/views/nodes/ScreenshotBox.tsx b/src/client/views/nodes/ScreenshotBox.tsx
index 224bc6f67..6caef0daa 100644
--- a/src/client/views/nodes/ScreenshotBox.tsx
+++ b/src/client/views/nodes/ScreenshotBox.tsx
@@ -123,9 +123,9 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl
 
     constructor(props: any) {
         super(props);
-        if (this.rootDoc.videoWall) {
-            this.rootDoc.nativeWidth = undefined;
-            this.rootDoc.nativeHeight = undefined;
+        if (this.dataDoc.videoWall) {
+            this.layoutDoc.nativeWidth = undefined;
+            this.layoutDoc.nativeHeight = undefined;
             this.layoutDoc.popOff = 0;
             this.layoutDoc.popOut = 1;
         } else {
@@ -134,7 +134,7 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl
     }
     getAnchor = (addAsAnnotation: boolean) => {
         const startTime = Cast(this.layoutDoc._layout_currentTimecode, 'number', null) || (this._videoRec ? (Date.now() - (this.recordingStart || 0)) / 1000 : undefined);
-        return CollectionStackedTimeline.createAnchor(this.rootDoc, this.dataDoc, this.annotationKey, startTime, startTime === undefined ? undefined : startTime + 3, undefined, addAsAnnotation) || this.rootDoc;
+        return CollectionStackedTimeline.createAnchor(this.Document, this.dataDoc, this.annotationKey, startTime, startTime === undefined ? undefined : startTime + 3, undefined, addAsAnnotation) || this.Document;
     };
 
     videoLoad = () => {
@@ -151,7 +151,7 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl
     componentDidMount() {
         this.dataDoc.nativeWidth = this.dataDoc.nativeHeight = 0;
         this.props.setContentView?.(this); // this tells the DocumentView that this ScreenshotBox is the "content" of the document.  this allows the DocumentView to indirectly call getAnchor() on the AudioBox when making a link.
-        // this.rootDoc.videoWall && reaction(() => ({ width: this.props.PanelWidth(), height: this.props.PanelHeight() }),
+        // this.layoutDoc.videoWall && reaction(() => ({ width: this.props.PanelWidth(), height: this.props.PanelHeight() }),
         //     ({ width, height }) => {
         //         if (this._camera) {
         //             const angle = -Math.abs(1 - width / height);
@@ -173,7 +173,7 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl
     };
 
     @computed get content() {
-        if (this.rootDoc.videoWall) return null;
+        if (this.layoutDoc.videoWall) return null;
         return (
             <video
                 className={'videoBox-content'}
@@ -181,7 +181,7 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl
                 ref={r => {
                     this._videoRef = r;
                     setTimeout(() => {
-                        if (this.rootDoc.mediaState === media_state.PendingRecording && this._videoRef) {
+                        if (this.layoutDoc.mediaState === media_state.PendingRecording && this._videoRef) {
                             this.toggleRecording();
                         }
                     }, 100);
@@ -202,12 +202,12 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl
     // @observable _raised = [] as { coord: Vector2, off: Vector3 }[];
     // @action setRaised = (r: { coord: Vector2, off: Vector3 }[]) => this._raised = r;
     @computed get threed() {
-        // if (this.rootDoc.videoWall) {
+        // if (this.layoutDoc.videoWall) {
         //     const screens: any[] = [];
         //     const colors = ["yellow", "red", "orange", "brown", "maroon", "gray"];
         //     let count = 0;
         //     numberRange(this._numScreens).forEach(x => numberRange(this._numScreens).forEach(y => screens.push(
-        //         <VideoTile rootDoc={this.rootDoc} color={colors[count++ % colors.length]} x={x} y={y} raised={this._raised} setRaised={this.setRaised} />)));
+        //         <VideoTile rootDoc={this.layoutDoc} color={colors[count++ % colors.length]} x={x} y={y} raised={this._raised} setRaised={this.setRaised} />)));
         //     return <Canvas key="canvas" id="CANCAN" style={{ width: this.props.PanelWidth(), height: this.props.PanelHeight() }} gl={{ antialias: false }} colorManagement={false} onCreated={props => {
         //         this._camera = props.camera;
         //         props.camera.position.set(this._numScreens / 2, this._numScreens / 2, this._numScreens - 2);
@@ -250,7 +250,7 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl
                     this.dataDoc[this.fieldKey + '_presentation'] = JSON.stringify(presCopy);
                 }
                 TrackMovements.Instance.finish();
-                const file = new File(vid_chunks, `${this.rootDoc[Id]}.mkv`, { type: vid_chunks[0].type, lastModified: Date.now() });
+                const file = new File(vid_chunks, `${this.Document[Id]}.mkv`, { type: vid_chunks[0].type, lastModified: Date.now() });
                 const [{ result }] = await Networking.UploadFilesToServer({ file });
                 this.dataDoc[this.fieldKey + '_duration'] = (new Date().getTime() - this.recordingStart!) / 1000;
                 if (!(result instanceof Error)) {
@@ -279,13 +279,13 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl
             const ind = DocUtils.ActiveRecordings.indexOf(this);
             ind !== -1 && DocUtils.ActiveRecordings.splice(ind, 1);
 
-            CaptureManager.Instance.open(this.rootDoc);
+            CaptureManager.Instance.open(this.Document);
         }
     };
 
     setupDictation = () => {
         if (this.dataDoc[this.fieldKey + '_dictation']) return;
-        const dictationText = DocUtils.GetNewTextDoc('dictation', NumCast(this.rootDoc.x), NumCast(this.rootDoc.y) + NumCast(this.layoutDoc._height) + 10, NumCast(this.layoutDoc._width), 2 * NumCast(this.layoutDoc._height));
+        const dictationText = DocUtils.GetNewTextDoc('dictation', NumCast(this.Document.x), NumCast(this.Document.y) + NumCast(this.layoutDoc._height) + 10, NumCast(this.layoutDoc._width), 2 * NumCast(this.layoutDoc._height));
         const textField = Doc.LayoutFieldKey(dictationText);
         dictationText._layout_autoHeight = false;
         const dictationTextProto = Doc.GetProto(dictationText);
diff --git a/src/client/views/nodes/ScriptingBox.tsx b/src/client/views/nodes/ScriptingBox.tsx
index a51a83b26..127edaed7 100644
--- a/src/client/views/nodes/ScriptingBox.tsx
+++ b/src/client/views/nodes/ScriptingBox.tsx
@@ -61,7 +61,7 @@ export class ScriptingBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatable
     constructor(props: any) {
         super(props);
         if (!this.compileParams.length) {
-            const params = ScriptCast(this.rootDoc[this.props.fieldKey])?.script.options.params as { [key: string]: any };
+            const params = ScriptCast(this.dataDoc[this.props.fieldKey])?.script.options.params as { [key: string]: any };
             if (params) {
                 this.compileParams = Array.from(Object.keys(params))
                     .filter(p => !p.startsWith('_'))
@@ -78,30 +78,30 @@ export class ScriptingBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatable
         return this.compileParams.map(p => p.split(':')[1].trim());
     }
     @computed({ keepAlive: true }) get rawScript() {
-        return ScriptCast(this.rootDoc[this.fieldKey])?.script.originalScript ?? '';
+        return ScriptCast(this.dataDoc[this.fieldKey])?.script.originalScript ?? '';
     }
     @computed({ keepAlive: true }) get functionName() {
-        return StrCast(this.rootDoc[this.props.fieldKey + '-functionName'], '');
+        return StrCast(this.dataDoc[this.fieldKey + '-functionName'], '');
     }
     @computed({ keepAlive: true }) get functionDescription() {
-        return StrCast(this.rootDoc[this.props.fieldKey + '-functionDescription'], '');
+        return StrCast(this.dataDoc[this.fieldKey + '-functionDescription'], '');
     }
     @computed({ keepAlive: true }) get compileParams() {
-        return Cast(this.rootDoc[this.props.fieldKey + '-params'], listSpec('string'), []);
+        return Cast(this.dataDoc[this.fieldKey + '-params'], listSpec('string'), []);
     }
 
     set rawScript(value) {
-        Doc.SetInPlace(this.rootDoc, this.props.fieldKey, new ScriptField(undefined, undefined, value), true);
+        this.dataDoc[this.fieldKey] = new ScriptField(undefined, undefined, value);
     }
     set functionName(value) {
-        Doc.SetInPlace(this.rootDoc, this.props.fieldKey + '-functionName', value, true);
+        this.dataDoc[this.fieldKey + '-functionName'] = value;
     }
     set functionDescription(value) {
-        Doc.SetInPlace(this.rootDoc, this.props.fieldKey + '-functionDescription', value, true);
+        this.dataDoc[this.fieldKey + '-functionDescription'] = value;
     }
 
     set compileParams(value) {
-        Doc.SetInPlace(this.rootDoc, this.props.fieldKey + '-params', new List<string>(value), true);
+        this.dataDoc[this.fieldKey + '-params'] = new List<string>(value);
     }
 
     getValue(result: any, descrip: boolean) {
@@ -165,9 +165,7 @@ export class ScriptingBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatable
 
     // only included in buttons, transforms scripting UI to a button
     @action
-    onFinish = () => {
-        this.rootDoc.layout_fieldKey = 'layout';
-    };
+    onFinish = () => (this.layoutDoc.layout_fieldKey = 'layout');
 
     // displays error message
     @action
@@ -189,7 +187,7 @@ export class ScriptingBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatable
                   params,
                   typecheck: false,
               });
-        Doc.SetInPlace(this.rootDoc, this.fieldKey, result.compiled ? new ScriptField(result, undefined, this.rawText) : undefined, true);
+        this.dataDoc[this.fieldKey] = result.compiled ? new ScriptField(result, undefined, this.rawText) : undefined;
         this.onError(result.compiled ? undefined : result.errors);
         return result.compiled;
     };
@@ -199,9 +197,9 @@ export class ScriptingBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatable
     onRun = () => {
         if (this.onCompile()) {
             const bindings: { [name: string]: any } = {};
-            this.paramsNames.forEach(key => (bindings[key] = this.rootDoc[key]));
+            this.paramsNames.forEach(key => (bindings[key] = this.dataDoc[key]));
             // binds vars so user doesnt have to refer to everything as this.<var>
-            ScriptCast(this.rootDoc[this.fieldKey], null)?.script.run({ ...bindings, self: this.rootDoc, this: this.layoutDoc }, this.onError);
+            ScriptCast(this.dataDoc[this.fieldKey], null)?.script.run({ ...bindings, this: this.Document }, this.onError);
         }
     };
 
@@ -270,7 +268,7 @@ export class ScriptingBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatable
     @action
     onDrop = (e: Event, de: DragManager.DropEvent, fieldKey: string) => {
         if (de.complete.docDragData) {
-            de.complete.docDragData.droppedDocuments.forEach(doc => Doc.SetInPlace(this.rootDoc, fieldKey, doc, true));
+            de.complete.docDragData.droppedDocuments.forEach(doc => (this.dataDoc[fieldKey] = doc));
             e.stopPropagation();
             return true;
         }
@@ -280,7 +278,7 @@ export class ScriptingBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatable
     // deletes a param from all areas in which it is stored
     @action
     onDelete = (num: number) => {
-        Doc.SetInPlace(this.rootDoc, this.paramsNames[num], undefined, true);
+        this.dataDoc[this.paramsNames[num]] = undefined;
         this.compileParams.splice(num, 1);
         return true;
     };
@@ -290,13 +288,13 @@ export class ScriptingBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatable
     viewChanged = (e: React.ChangeEvent, name: string) => {
         //@ts-ignore
         const val = e.target.selectedOptions[0].value;
-        Doc.SetInPlace(this.rootDoc, name, val[0] === 'S' ? val.substring(1) : val[0] === 'N' ? parseInt(val.substring(1)) : val.substring(1) === 'true', true);
+        this.dataDoc[name] = val[0] === 'S' ? val.substring(1) : val[0] === 'N' ? parseInt(val.substring(1)) : val.substring(1) === 'true';
     };
 
     // creates a copy of the script document
     onCopy = () => {
-        const copy = Doc.MakeCopy(this.rootDoc, true);
-        copy.x = NumCast(this.dataDoc.x) + NumCast(this.dataDoc._width);
+        const copy = Doc.MakeCopy(this.Document, true);
+        copy.x = NumCast(this.Document.x) + NumCast(this.dataDoc._width);
         this.props.addDocument?.(copy);
     };
 
@@ -346,8 +344,8 @@ export class ScriptingBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatable
                     maxHeight={72}
                     height={35}
                     fontSize={14}
-                    contents={StrCast(DocCast(this.rootDoc[parameter])?.title, 'undefined')}
-                    GetValue={() => StrCast(DocCast(this.rootDoc[parameter])?.title, 'undefined')}
+                    contents={StrCast(DocCast(this.dataDoc[parameter])?.title, 'undefined')}
+                    GetValue={() => StrCast(DocCast(this.dataDoc[parameter])?.title, 'undefined')}
                     SetValue={action((value: string) => {
                         const script = CompileScript(value, {
                             addReturn: true,
@@ -357,7 +355,7 @@ export class ScriptingBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatable
                         const results = script.compiled && script.run();
                         if (results && results.success) {
                             this._errorMessage = '';
-                            Doc.SetInPlace(this.rootDoc, parameter, results.result, true);
+                            this.dataDoc[parameter] = results.result;
                             return true;
                         }
                         this._errorMessage = 'invalid document';
@@ -370,7 +368,7 @@ export class ScriptingBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatable
 
     // rendering when a string's value can be set in applied UI
     renderBasicType(parameter: string, isNum: boolean) {
-        const strVal = isNum ? NumCast(this.rootDoc[parameter]).toString() : StrCast(this.rootDoc[parameter]);
+        const strVal = isNum ? NumCast(this.dataDoc[parameter]).toString() : StrCast(this.dataDoc[parameter]);
         return (
             <div className="scriptingBox-paramInputs" style={{ overflowY: 'hidden' }}>
                 <EditableView
@@ -384,7 +382,7 @@ export class ScriptingBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatable
                         const setValue = isNum ? parseInt(value) : value;
                         if (setValue !== undefined && setValue !== ' ') {
                             this._errorMessage = '';
-                            Doc.SetInPlace(this.rootDoc, parameter, setValue, true);
+                            this.dataDoc[parameter] = setValue;
                             return true;
                         }
                         this._errorMessage = 'invalid input';
@@ -405,7 +403,7 @@ export class ScriptingBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatable
                             className="scriptingBox-viewPicker"
                             onPointerDown={e => e.stopPropagation()}
                             onChange={e => this.viewChanged(e, parameter)}
-                            value={typeof this.rootDoc[parameter] === 'string' ? 'S' + StrCast(this.rootDoc[parameter]) : typeof this.rootDoc[parameter] === 'number' ? 'N' + NumCast(this.rootDoc[parameter]) : 'B' + BoolCast(this.rootDoc[parameter])}>
+                            value={typeof this.dataDoc[parameter] === 'string' ? 'S' + StrCast(this.dataDoc[parameter]) : typeof this.dataDoc[parameter] === 'number' ? 'N' + NumCast(this.dataDoc[parameter]) : 'B' + BoolCast(this.dataDoc[parameter])}>
                             {types.map((type, i) => (
                                 <option key={i} className="scriptingBox-viewOption" value={(typeof type === 'string' ? 'S' : typeof type === 'number' ? 'N' : 'B') + type}>
                                     {' '}
@@ -703,7 +701,7 @@ export class ScriptingBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatable
 
     // toolbar (with compile and apply buttons) for scripting UI
     renderScriptingTools() {
-        const buttonStyle = 'scriptingBox-button' + (StrCast(this.rootDoc.layout_fieldKey).startsWith('layout_on') ? '-finish' : '');
+        const buttonStyle = 'scriptingBox-button' + (StrCast(this.Document.layout_fieldKey).startsWith('layout_on') ? '-finish' : '');
         return (
             <div className="scriptingBox-toolbar">
                 <button
@@ -731,7 +729,7 @@ export class ScriptingBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatable
                     Save
                 </button>
 
-                {!StrCast(this.rootDoc.layout_fieldKey).startsWith('layout_on') ? null : ( // onClick, onChecked, etc need a Finish button to return to their default layout
+                {!StrCast(this.Document.layout_fieldKey).startsWith('layout_on') ? null : ( // onClick, onChecked, etc need a Finish button to return to their default layout
                     <button
                         className={buttonStyle}
                         onPointerDown={e => {
@@ -777,7 +775,7 @@ export class ScriptingBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatable
 
     // toolbar (with edit and run buttons and error message) for params UI
     renderTools(toolSet: string, func: () => void) {
-        const buttonStyle = 'scriptingBox-button' + (StrCast(this.rootDoc.layout_fieldKey).startsWith('layout_on') ? '-finish' : '');
+        const buttonStyle = 'scriptingBox-button' + (StrCast(this.Document.layout_fieldKey).startsWith('layout_on') ? '-finish' : '');
         return (
             <div className="scriptingBox-toolbar">
                 <button
@@ -796,7 +794,7 @@ export class ScriptingBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatable
                     }}>
                     {toolSet}
                 </button>
-                {!StrCast(this.rootDoc.layout_fieldKey).startsWith('layout_on') ? null : (
+                {!StrCast(this.Document.layout_fieldKey).startsWith('layout_on') ? null : (
                     <button
                         className={buttonStyle}
                         onPointerDown={e => {
diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx
index f87d94784..0f6c6724a 100644
--- a/src/client/views/nodes/VideoBox.tsx
+++ b/src/client/views/nodes/VideoBox.tsx
@@ -267,7 +267,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
             this.player && this._contentRef && this._contentRef.requestFullscreen();
         }
         try {
-            this._youtubePlayer && this.props.addDocTab(this.rootDoc, OpenWhere.add);
+            this._youtubePlayer && this.props.addDocTab(this.Document, OpenWhere.add);
         } catch (e) {
             console.log('Video FullScreen Exception:', e);
         }
@@ -329,7 +329,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
                 onClick: FollowLinkScript(),
             });
             this.props.addDocument?.(b);
-            DocUtils.MakeLink(b, this.rootDoc, { link_relationship: 'video snapshot' });
+            DocUtils.MakeLink(b, this.Document, { link_relationship: 'video snapshot' });
             Networking.PostToServer('/youtubeScreenshot', {
                 id: this.youtubeVideoId,
                 timecode: this.layoutDoc._layout_currentTimecode,
@@ -344,7 +344,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
             //convert to desired file format
             const dataUrl = canvas.toDataURL('image/png'); // can also use 'image/png'
             // if you want to preview the captured image,
-            const retitled = StrCast(this.rootDoc.title).replace(/[ -\.:]/g, '');
+            const retitled = StrCast(this.Document.title).replace(/[ -\.:]/g, '');
             const encodedFilename = encodeURIComponent('snapshot' + retitled + '_' + (this.layoutDoc._layout_currentTimecode || 0).toString().replace(/\./, '_'));
             const filename = basename(encodedFilename);
             Utils.convertDataUri(dataUrl, filename).then((returnedFilename: string) => returnedFilename && (cb ?? this.createSnapshotLink)(returnedFilename, downX, downY));
@@ -388,9 +388,9 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
         const marquee = AnchorMenu.Instance.GetAnchor?.(undefined, addAsAnnotation);
         if (!addAsAnnotation && marquee) marquee.backgroundColor = 'transparent';
         const anchor = addAsAnnotation
-            ? CollectionStackedTimeline.createAnchor(this.rootDoc, this.dataDoc, this.annotationKey, timecode ? timecode : undefined, undefined, marquee, addAsAnnotation) || this.rootDoc
-            : Docs.Create.ConfigDocument({ title: '#' + timecode, _timecodeToShow: timecode, annotationOn: this.rootDoc });
-        PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: { ...(pinProps?.pinData ?? {}), temporal: true } }, this.rootDoc);
+            ? CollectionStackedTimeline.createAnchor(this.Document, this.dataDoc, this.annotationKey, timecode ? timecode : undefined, undefined, marquee, addAsAnnotation) || this.Document
+            : Docs.Create.ConfigDocument({ title: '#' + timecode, _timecodeToShow: timecode, annotationOn: this.Document });
+        PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: { ...(pinProps?.pinData ?? {}), temporal: true } }, this.Document);
         return anchor;
     };
 
@@ -437,7 +437,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
             canvas.height = 100;
             canvas.width = 100;
             canvas.getContext('2d')?.drawImage(video, 0, 0, video.videoWidth, video.videoHeight, 0, 0, 100, 100);
-            const retitled = StrCast(this.rootDoc.title).replace(/[ -\.:]/g, '');
+            const retitled = StrCast(this.Document.title).replace(/[ -\.:]/g, '');
             const encodedFilename = encodeURIComponent('thumbnail' + retitled + '_' + video.currentTime.toString().replace(/\./, '_'));
             thumbnailPromises?.push(Utils.convertDataUri(canvas.toDataURL(), basename(encodedFilename), true));
             const newTime = video.currentTime + video.duration / (VideoBox.numThumbnails - 1);
@@ -498,7 +498,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
             const subitems: ContextMenuProps[] = [];
             subitems.push({ description: 'Full Screen', event: this.FullScreen, icon: 'expand' });
             subitems.push({ description: 'Take Snapshot', event: this.Snapshot, icon: 'expand-arrows-alt' });
-            this.rootDoc.type === DocumentType.SCREENSHOT &&
+            this.Document.type === DocumentType.SCREENSHOT &&
                 subitems.push({
                     description: 'Screen Capture',
                     event: async () => {
@@ -575,7 +575,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
                         key="video"
                         autoPlay={this._screenCapture}
                         ref={this.setVideoRef}
-                        style={this._fullScreen ? this.fullScreenSize() : this.isCropped ? { width: 'max-content', height: 'max-content', transform: `scale(${1 / NumCast(this.rootDoc._freeform_scale)})`, transformOrigin: 'top left' } : {}}
+                        style={this._fullScreen ? this.fullScreenSize() : this.isCropped ? { width: 'max-content', height: 'max-content', transform: `scale(${1 / NumCast(this.layoutDoc._freeform_scale)})`, transformOrigin: 'top left' } : {}}
                         onCanPlay={this.videoLoad}
                         controls={VideoBox._nativeControls}
                         onPlay={() => this.Play()}
@@ -902,7 +902,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
     scaling = () => this.props.NativeDimScaling?.() || 1;
 
     panelWidth = () => (this.props.PanelWidth() * this.heightPercent) / 100;
-    panelHeight = () => (this.layoutDoc._layout_fitWidth ? this.panelWidth() / (Doc.NativeAspect(this.rootDoc) || 1) : (this.props.PanelHeight() * this.heightPercent) / 100);
+    panelHeight = () => (this.layoutDoc._layout_fitWidth ? this.panelWidth() / (Doc.NativeAspect(this.dataDoc) || 1) : (this.props.PanelHeight() * this.heightPercent) / 100);
 
     screenToLocalTransform = () => {
         const offset = (this.props.PanelWidth() - this.panelWidth()) / 2 / this.scaling();
@@ -999,7 +999,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
         const cropping = Doc.MakeCopy(region, true);
         Doc.GetProto(region).backgroundColor = 'transparent';
         Doc.GetProto(region).lockedPosition = true;
-        Doc.GetProto(region).title = 'region:' + this.rootDoc.title;
+        Doc.GetProto(region).title = 'region:' + this.Document.title;
         Doc.GetProto(region).followLinkToggle = true;
         region._timecodeToHide = NumCast(region._timecodeToShow) + 0.0001;
         this.addDocument(region);
@@ -1007,10 +1007,10 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
         const anchy = NumCast(cropping.y);
         const anchw = NumCast(cropping._width);
         const anchh = NumCast(cropping._height);
-        const viewScale = NumCast(this.rootDoc[this.fieldKey + '_nativeWidth']) / anchw;
-        cropping.title = 'crop: ' + this.rootDoc.title;
-        cropping.x = NumCast(this.rootDoc.x) + NumCast(this.rootDoc._width);
-        cropping.y = NumCast(this.rootDoc.y);
+        const viewScale = NumCast(this.dataDoc[this.fieldKey + '_nativeWidth']) / anchw;
+        cropping.title = 'crop: ' + this.Document.title;
+        cropping.x = NumCast(this.Document.x) + NumCast(this.layoutDoc._width);
+        cropping.y = NumCast(this.Document.y);
         cropping._width = anchw * (this.props.NativeDimScaling?.() || 1);
         cropping._height = anchh * (this.props.NativeDimScaling?.() || 1);
         cropping.timecodeToHide = undefined;
@@ -1019,10 +1019,10 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
         const croppingProto = Doc.GetProto(cropping);
         croppingProto.annotationOn = undefined;
         croppingProto.isDataDoc = true;
-        croppingProto.proto = Cast(this.rootDoc.proto, Doc, null)?.proto; // set proto of cropping's data doc to be IMAGE_PROTO
+        croppingProto.proto = Cast(this.Document.proto, Doc, null)?.proto; // set proto of cropping's data doc to be IMAGE_PROTO
         croppingProto.type = DocumentType.VID;
         croppingProto.layout = VideoBox.LayoutString('data');
-        croppingProto.data = ObjectField.MakeCopy(this.rootDoc[this.fieldKey] as ObjectField);
+        croppingProto.data = ObjectField.MakeCopy(this.dataDoc[this.fieldKey] as ObjectField);
         croppingProto['data_nativeWidth'] = anchw;
         croppingProto['data_nativeHeight'] = anchh;
         croppingProto.videoCrop = true;
@@ -1093,7 +1093,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
                     {!this._mainCont.current || !this._annotationLayer.current ? null : (
                         <MarqueeAnnotator
                             ref={this._marqueeref}
-                            Document={this.rootDoc}
+                            Document={this.Document}
                             scrollTop={0}
                             annotationLayerScrollTop={0}
                             scaling={returnOne}
diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx
index 1e6d92327..b3afe6ba0 100644
--- a/src/client/views/nodes/WebBox.tsx
+++ b/src/client/views/nodes/WebBox.tsx
@@ -489,7 +489,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
                 this._scrollHeight = Math.max(this._scrollHeight, iframeContent.body.scrollHeight || 0);
                 if (this._scrollHeight) {
                     this.Document.nativeHeight = Math.min(NumCast(this.Document.nativeHeight), this._scrollHeight);
-                    this.layoutDoc.height = Math.min(NumCast(this.layoutDoc._height), (NumCast(this.layoutDoc._width) * NumCast(this.rootDoc.nativeHeight)) / NumCast(this.rootDoc.nativeWidth));
+                    this.layoutDoc.height = Math.min(NumCast(this.layoutDoc._height), (NumCast(this.layoutDoc._width) * NumCast(this.dataDoc.nativeHeight)) / NumCast(this.dataDoc.nativeWidth));
                 }
             };
             const swidth = Math.max(NumCast(this.layoutDoc.nativeWidth), iframeContent.body.scrollWidth || 0);
@@ -608,8 +608,8 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
     };
 
     back = (checkAvailable?: boolean) => {
-        const future = Cast(this.rootDoc[this.fieldKey + '_future'], listSpec('string'));
-        const history = Cast(this.rootDoc[this.fieldKey + '_history'], listSpec('string'), []);
+        const future = Cast(this.dataDoc[this.fieldKey + '_future'], listSpec('string'));
+        const history = Cast(this.dataDoc[this.fieldKey + '_history'], listSpec('string'), []);
         if (checkAvailable) return history.length;
         runInAction(() => {
             if (history.length) {
@@ -677,7 +677,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
         if (Field.toString(data) === this._url) return false;
         this._scrollHeight = 0;
         const oldUrl = this._url;
-        const history = Cast(this.rootDoc[this.fieldKey + '_history'], listSpec('string'), []);
+        const history = Cast(this.dataDoc[this.fieldKey + '_history'], listSpec('string'), []);
         const weburl = new WebField(Field.toString(data));
         this.dataDoc[this.fieldKey + '_future'] = new List<string>([]);
         this.dataDoc[this.fieldKey + '_history'] = new List<string>([...(history || []), oldUrl]);
@@ -1141,7 +1141,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
                         {...this.props}
                         whenChildContentsActiveChanged={this.whenChildContentsActiveChanged}
                         fieldKey={this.fieldKey + '_' + this._urlHash}
-                        rootDoc={this.rootDoc}
+                        Document={this.Document}
                         layoutDoc={this.layoutDoc}
                         dataDoc={this.dataDoc}
                         setHeight={emptyFunction}
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 252a7d884..f3929533d 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -144,13 +144,13 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
         return (this.props.forceAutoHeight || this.layoutDoc._layout_autoHeight) && !this.props.ignoreAutoHeight;
     }
     @computed get textHeight() {
-        return NumCast(this.rootDoc[this.fieldKey + '_height']);
+        return NumCast(this.dataDoc[this.fieldKey + '_height']);
     }
     @computed get scrollHeight() {
-        return NumCast(this.rootDoc[this.fieldKey + '_scrollHeight']);
+        return NumCast(this.dataDoc[this.fieldKey + '_scrollHeight']);
     }
     @computed get sidebarHeight() {
-        return !this.sidebarWidth() ? 0 : NumCast(this.rootDoc[this.SidebarKey + '_height']);
+        return !this.sidebarWidth() ? 0 : NumCast(this.dataDoc[this.SidebarKey + '_height']);
     }
     @computed get titleHeight() {
         return this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.HeaderMargin) || 0;
@@ -166,7 +166,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
     }
     @computed get config() {
         this._keymap = buildKeymap(schema, this.props);
-        this._rules = new RichTextRules(this.rootDoc, this);
+        this._rules = new RichTextRules(this.Document, this);
         return {
             schema,
             plugins: [
@@ -310,7 +310,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
             e.preventDefault();
             e.stopPropagation();
             const targetCreator = (annotationOn?: Doc) => {
-                const target = DocUtils.GetNewTextDoc('Note linked to ' + this.rootDoc.title, 0, 0, 100, 100, undefined, annotationOn);
+                const target = DocUtils.GetNewTextDoc('Note linked to ' + this.Document.title, 0, 0, 100, 100, undefined, annotationOn);
                 FormattedTextBox.SelectOnLoad = target[Id];
                 return target;
             };
@@ -339,7 +339,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
             const newText = state.doc.textBetween(0, state.doc.content.size, ' \n');
             const newJson = JSON.stringify(state.toJSON());
             const prevData = Cast(this.layoutDoc[this.fieldKey], RichTextField, null); // the actual text in the text box
-            const templateData = this.rootDoc !== this.layoutDoc ? prevData : undefined; // the default text stored in a layout template
+            const templateData = this.Document !== this.layoutDoc ? prevData : undefined; // the default text stored in a layout template
             const protoData = Cast(Cast(dataDoc.proto, Doc, null)?.[this.fieldKey], RichTextField, null); // the default text inherited from a prototype
             const effectiveAcl = GetEffectiveAcl(dataDoc);
 
@@ -365,7 +365,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
                             const numstring = NumCast(dataDoc[this.fieldKey], null);
                             dataDoc[this.fieldKey] = numstring !== undefined ? Number(newText) : new RichTextField(newJson, newText);
                             dataDoc[this.fieldKey + '_noTemplate'] = true; // mark the data field as being split from the template if it has been edited
-                            textChange && ScriptCast(this.layoutDoc.onTextChanged, null)?.script.run({ this: this.layoutDoc, self: this.rootDoc, text: newText });
+                            textChange && ScriptCast(this.layoutDoc.onTextChanged, null)?.script.run({ this: this.Document, text: newText });
                             unchanged = false;
                         }
                     } else {
@@ -373,7 +373,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
                         dataDoc[this.fieldKey] = undefined;
                         this._editorView.updateState(EditorState.fromJSON(this.config, JSON.parse((protoData || prevData).Data)));
                         dataDoc[this.fieldKey + '_noTemplate'] = undefined; // mark the data field as not being split from any template it might have
-                        ScriptCast(this.layoutDoc.onTextChanged, null)?.script.run({ this: this.layoutDoc, self: this.rootDoc, text: newText });
+                        ScriptCast(this.layoutDoc.onTextChanged, null)?.script.run({ this: this.layoutDoc, text: newText });
                         unchanged = false;
                     }
                     this._applyingChange = '';
@@ -450,7 +450,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
             tr = tr.setSelection(isNodeSel && false ? new NodeSelection(tr.doc.resolve(f)) : new TextSelection(tr.doc.resolve(f), tr.doc.resolve(t)));
             this._editorView?.dispatch(tr);
         }
-        oldAutoLinks.filter(oldLink => !newAutoLinks.has(oldLink) && oldLink.link_anchor_2 !== this.rootDoc).forEach(LinkManager.Instance.deleteLink);
+        oldAutoLinks.filter(oldLink => !newAutoLinks.has(oldLink) && oldLink.link_anchor_2 !== this.Document).forEach(LinkManager.Instance.deleteLink);
     };
 
     updateTitle = () => {
@@ -460,7 +460,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
             (title.startsWith('-') || title.startsWith('@')) &&
             this._editorView &&
             !this.dataDoc.title_custom &&
-            (Doc.LayoutFieldKey(this.rootDoc) === this.fieldKey || this.fieldKey === 'text')
+            (Doc.LayoutFieldKey(this.Document) === this.fieldKey || this.fieldKey === 'text')
         ) {
             let node = this._editorView.state.doc;
             while (node.firstChild && node.firstChild.type.name !== 'text') node = node.firstChild;
@@ -471,7 +471,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
             if (!(cfield instanceof ComputedField)) {
                 this.dataDoc.title = (prefix + str.substring(0, Math.min(40, str.length)) + (str.length > 40 ? '...' : '')).trim();
                 if (str.startsWith('@') && str.length > 1) {
-                    Doc.AddToMyPublished(this.rootDoc);
+                    Doc.AddToMyPublished(this.Document);
                 }
             }
         }
@@ -480,7 +480,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
     // creates links between terms in a document and published documents (myPublishedDocs) that have titles starting with an '@'
     hyperlinkTerm = (tr: any, target: Doc, newAutoLinks: Set<Doc>) => {
         const editorView = this._editorView;
-        if (editorView && (editorView as any).docView && !Doc.AreProtosEqual(target, this.rootDoc)) {
+        if (editorView && (editorView as any).docView && !Doc.AreProtosEqual(target, this.Document)) {
             const autoLinkTerm = StrCast(target.title).replace(/^@/, '');
             var alink: Doc | undefined;
             this.findInNode(editorView, editorView.state.doc, autoLinkTerm).forEach(sel => {
@@ -491,12 +491,12 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
                         if (node.firstChild === null && !node.marks.find((m: Mark) => m.type.name === schema.marks.noAutoLinkAnchor.name) && node.marks.find((m: Mark) => m.type.name === schema.marks.splitter.name)) {
                             alink =
                                 alink ??
-                                (LinkManager.Links(this.rootDoc).find(
+                                (LinkManager.Links(this.Document).find(
                                     link =>
-                                        Doc.AreProtosEqual(Cast(link.link_anchor_1, Doc, null), this.rootDoc) && //
+                                        Doc.AreProtosEqual(Cast(link.link_anchor_1, Doc, null), this.Document) && //
                                         Doc.AreProtosEqual(Cast(link.link_anchor_2, Doc, null), target)
                                 ) ||
-                                    DocUtils.MakeLink(this.rootDoc, target, { link_relationship: LinkManager.AutoKeywords })!);
+                                    DocUtils.MakeLink(this.Document, target, { link_relationship: LinkManager.AutoKeywords })!);
                             newAutoLinks.add(alink);
                             // DocCast(alink.link_anchor_1).followLinkLocation = 'add:right';
                             const allAnchors = [{ href: Doc.localServerPath(target), title: 'a link', anchorId: this.props.Document[Id] }];
@@ -602,7 +602,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
                     }
                     if (added) {
                         draggedDoc._freeform_fitContentsToBox = true;
-                        Doc.SetContainer(draggedDoc, this.rootDoc);
+                        Doc.SetContainer(draggedDoc, this.Document);
                         const view = this._editorView!;
                         try {
                             const pos = view.posAtCoords({ left: de.x, top: de.y })?.pos;
@@ -823,7 +823,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
         changeItems.push({
             description: 'plain',
             event: undoBatch(() => {
-                Doc.setNativeView(this.rootDoc);
+                Doc.setNativeView(this.Document);
                 this.layoutDoc.layout_autoHeightMargins = undefined;
             }),
             icon: 'eye',
@@ -832,8 +832,8 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
             description: 'metadata',
             event: undoBatch(() => {
                 this.dataDoc.layout_meta = Cast(Doc.UserDoc().emptyHeader, Doc, null)?.layout;
-                this.rootDoc.layout_fieldKey = 'layout_meta';
-                setTimeout(() => (this.rootDoc._headerHeight = this.rootDoc._layout_autoHeightMargins = 50), 50);
+                this.Document.layout_fieldKey = 'layout_meta';
+                setTimeout(() => (this.layoutDoc._headerHeight = this.layoutDoc._layout_autoHeightMargins = 50), 50);
             }),
             icon: 'eye',
         });
@@ -844,8 +844,8 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
                 description: StrCast(note.title),
                 event: undoBatch(() => {
                     this.layoutDoc.layout_autoHeightMargins = undefined;
-                    Doc.setNativeView(this.rootDoc);
-                    DocUtils.makeCustomViewClicked(this.rootDoc, Docs.Create.TreeDocument, StrCast(note.title), note);
+                    Doc.setNativeView(this.Document);
+                    DocUtils.makeCustomViewClicked(this.Document, Docs.Create.TreeDocument, StrCast(note.title), note);
                 }),
                 icon: icon,
             });
@@ -884,40 +884,23 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
         !Doc.noviceMode &&
             appearanceItems.push({
                 description: 'Broadcast Message',
-                event: () => DocServer.GetRefField('rtfProto').then(proto => proto instanceof Doc && (proto.BROADCAST_MESSAGE = Cast(this.rootDoc[this.fieldKey], RichTextField)?.Text)),
+                event: () => DocServer.GetRefField('rtfProto').then(proto => proto instanceof Doc && (proto.BROADCAST_MESSAGE = Cast(this.dataDoc[this.fieldKey], RichTextField)?.Text)),
                 icon: 'expand-arrows-alt',
             });
 
         appearanceItems.push({ description: 'Change Style...', noexpand: true, subitems: changeItems, icon: 'external-link-alt' });
-        // this.rootDoc.isTemplateDoc && appearanceItems.push({ description: "Make Default Layout", event: async () => Doc.UserDoc().defaultTextLayout = new PrefetchProxy(this.rootDoc), icon: "eye" });
 
         !Doc.noviceMode &&
             appearanceItems.push({
                 description: 'Make Default Layout',
                 event: () => {
                     if (!this.layoutDoc.isTemplateDoc) {
-                        const title = StrCast(this.rootDoc.title);
-                        this.rootDoc.title = 'text';
-                        MakeTemplate(this.rootDoc, true, title);
-                    } else if (!this.rootDoc.isTemplateDoc) {
-                        const title = StrCast(this.rootDoc.title);
-                        this.rootDoc.title = 'text';
-                        this.rootDoc.layout = this.layoutDoc.layout as string;
-                        this.rootDoc.title = this.layoutDoc.isTemplateForField as string;
-                        this.rootDoc.isTemplateDoc = false;
-                        this.rootDoc.isTemplateForField = '';
-                        this.rootDoc.layout_fieldKey = 'layout';
-                        MakeTemplate(this.rootDoc, true, title);
-                        setTimeout(() => {
-                            this.rootDoc._layout_autoHeight = this.layoutDoc._layout_autoHeight; // layout_autoHeight, width and height
-                            this.rootDoc._width = this.layoutDoc._width || 300; // are stored on the template, since we're getting rid of the old template
-                            this.rootDoc._height = this.layoutDoc._height || 200; // we need to copy them over to the root.  This should probably apply to all '_' fields
-                            this.rootDoc._backgroundColor = Cast(this.layoutDoc._backgroundColor, 'string', null);
-                            this.rootDoc.backgroundColor = Cast(this.layoutDoc.backgroundColor, 'string', null);
-                        }, 10);
+                        const title = StrCast(this.Document.title);
+                        this.Document.title = 'text';
+                        MakeTemplate(this.Document, true, title);
                     }
-                    Doc.UserDoc().defaultTextLayout = new PrefetchProxy(this.rootDoc);
-                    Doc.AddDocToList(Cast(Doc.UserDoc().template_notes, Doc, null), 'data', this.rootDoc);
+                    Doc.UserDoc().defaultTextLayout = new PrefetchProxy(this.Document);
+                    Doc.AddDocToList(Cast(Doc.UserDoc().template_notes, Doc, null), 'data', this.Document);
                 },
                 icon: 'eye',
             });
@@ -971,7 +954,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
 
     generateImage = async () => {
         GPTPopup.Instance?.setTextAnchor(this.getAnchor(false));
-        GPTPopup.Instance?.setImgTargetDoc(this.rootDoc);
+        GPTPopup.Instance?.setImgTargetDoc(this.Document);
         GPTPopup.Instance.addToCollection = this.props.addDocument;
         GPTPopup.Instance.setImgDesc((this.dataDoc.text as RichTextField)?.Text);
         GPTPopup.Instance.generateImage();
@@ -1071,13 +1054,13 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
                 anchor.presentation_zoomText = true;
                 return anchor;
             }
-            return anchorDoc ?? this.rootDoc;
+            return anchorDoc ?? this.Document;
         }
-        return anchorDoc ?? this.rootDoc;
+        return anchorDoc ?? this.Document;
     }
 
     getView = async (doc: Doc) => {
-        if (DocListCast(this.rootDoc[this.SidebarKey]).find(anno => Doc.AreProtosEqual(doc.layout_unrendered ? DocCast(doc.annotationOn) : doc, anno))) {
+        if (DocListCast(this.dataDoc[this.SidebarKey]).find(anno => Doc.AreProtosEqual(doc.layout_unrendered ? DocCast(doc.annotationOn) : doc, anno))) {
             !this.SidebarShown && this.toggleSidebar(false);
             setTimeout(() => this._sidebarRef?.current?.makeDocUnfiltered(doc));
         }
@@ -1141,7 +1124,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
                 setTimeout(() => clearStyleSheetRules(FormattedTextBox._highlightStyleSheet), Math.max(this._focusSpeed || 0, 3000));
                 return focusSpeed;
             } else {
-                return this.props.focus(this.rootDoc, options);
+                return this.props.focus(this.Document, options);
             }
         }
     };
@@ -1150,12 +1133,12 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
     // Since we also monitor all component height changes, this will update the document's height.
     resetNativeHeight = (scrollHeight: number) => {
         const nh = this.layoutDoc.isTemplateForField ? 0 : NumCast(this.layoutDoc._nativeHeight);
-        this.rootDoc[this.fieldKey + '_height'] = scrollHeight;
+        this.dataDoc[this.fieldKey + '_height'] = scrollHeight;
         if (nh) this.layoutDoc._nativeHeight = scrollHeight;
     };
 
     @computed get contentScaling() {
-        return Doc.NativeAspect(this.rootDoc, this.dataDoc, false) ? this.props.NativeDimScaling?.() || 1 : 1;
+        return Doc.NativeAspect(this.Document, this.dataDoc, false) ? this.props.NativeDimScaling?.() || 1 : 1;
     }
     componentDidMount() {
         !this.props.dontSelectOnLoad && this.props.setContentView?.(this); // this tells the DocumentView that this AudioBox is the "content" of the document.  this allows the DocumentView to indirectly call getAnchor() on the AudioBox when making a link.
@@ -1188,7 +1171,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
                     (!Array.from(FormattedTextBox._globalHighlights).includes('Bold Text') || this.props.isSelected()) && //
                     layout_autoHeight &&
                     newHeight &&
-                    newHeight !== this.rootDoc.height &&
+                    newHeight !== this.layoutDoc.height &&
                     !this.props.dontRegisterView
                 ) {
                     this.props.setHeight?.(newHeight);
@@ -1252,9 +1235,9 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
         );
 
         this._disposers.search = reaction(
-            () => Doc.IsSearchMatch(this.rootDoc),
+            () => Doc.IsSearchMatch(this.Document),
             search => (search ? this.highlightSearchTerms([Doc.SearchQuery()], search.searchMatch < 0) : this.unhighlightSearchTerms()),
-            { fireImmediately: Doc.IsSearchMatchUnmemoized(this.rootDoc) ? true : false }
+            { fireImmediately: Doc.IsSearchMatchUnmemoized(this.Document) ? true : false }
         );
 
         this._disposers.selected = reaction(
@@ -1420,7 +1403,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
                     const dashField = view.state.schema.nodes.paragraph.create({}, [
                         view.state.schema.nodes.dashField.create({ fieldKey: 'text', docId: pdfAnchor[Id], hideKey: true, editable: false }, undefined, [
                             view.state.schema.marks.linkAnchor.create({
-                                allAnchors: [{ href: `/doc/${this.rootDoc[Id]}`, title: this.rootDoc.title, anchorId: `${this.rootDoc[Id]}` }],
+                                allAnchors: [{ href: `/doc/${this.Document[Id]}`, title: this.Document.title, anchorId: `${this.Document[Id]}` }],
                                 title: `from: ${DocCast(pdfAnchor.embedContainer).title}`,
                                 noPreview: true,
                                 docref: false,
@@ -1430,7 +1413,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
                         ]),
                     ]);
 
-                    const link = DocUtils.MakeLink(pdfAnchor, this.rootDoc, { link_relationship: 'PDF pasted' });
+                    const link = DocUtils.MakeLink(pdfAnchor, this.Document, { link_relationship: 'PDF pasted' });
                     if (link) {
                         view.dispatch(view.state.tr.replaceSelectionWith(dashField, false).scrollIntoView().setMeta('paste', true).setMeta('uiEvent', 'paste'));
                     }
@@ -1528,7 +1511,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
             (this._editorView as any).TextView = this;
         }
 
-        const selectOnLoad = this.rootDoc[Id] === FormattedTextBox.SelectOnLoad && (!LightboxView.LightboxDoc || LightboxView.IsLightboxDocView(this.props.docViewPath()));
+        const selectOnLoad = this.Document[Id] === FormattedTextBox.SelectOnLoad && (!LightboxView.LightboxDoc || LightboxView.IsLightboxDocView(this.props.docViewPath()));
         if (this._editorView && selectOnLoad && !this.props.dontRegisterView && !this.props.dontSelectOnLoad && this.isActiveTab(this.ProseRef)) {
             const selLoadChar = FormattedTextBox.SelectOnLoadChar;
             FormattedTextBox.SelectOnLoad = '';
@@ -1571,8 +1554,8 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
             ...(Doc.UserDoc().fontColor !== 'transparent' && Doc.UserDoc().fontColor ? [schema.mark(schema.marks.pFontColor, { color: StrCast(Doc.UserDoc().fontColor) })] : []),
             ...(Doc.UserDoc().fontStyle === 'italics' ? [schema.mark(schema.marks.em)] : []),
             ...(Doc.UserDoc().textDecoration === 'underline' ? [schema.mark(schema.marks.underline)] : []),
-            ...(Doc.UserDoc().fontFamily ? [schema.mark(schema.marks.pFontFamily, { family: this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.FontFamily) })] : []),
-            ...(Doc.UserDoc().fontSize ? [schema.mark(schema.marks.pFontSize, { fontSize: this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.FontSize) })] : []),
+            ...(Doc.UserDoc().fontFamily ? [schema.mark(schema.marks.pFontFamily, { family: this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.FontFamily) })] : []),
+            ...(Doc.UserDoc().fontSize ? [schema.mark(schema.marks.pFontSize, { fontSize: this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.FontSize) })] : []),
             ...(Doc.UserDoc().fontWeight === 'bold' ? [schema.mark(schema.marks.strong)] : []),
             ...[schema.marks.user_mark.create({ userid: Doc.CurrentUserEmail, modified: Math.floor(Date.now() / 1000) })],
         ];
@@ -1765,7 +1748,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
         }
     }
     startUndoTypingBatch() {
-        !this._undoTyping && (this._undoTyping = UndoManager.StartBatch('text edits on ' + this.rootDoc.title));
+        !this._undoTyping && (this._undoTyping = UndoManager.StartBatch('text edits on ' + this.Document.title));
     }
     public endUndoTypingBatch() {
         this._undoTyping?.end();
@@ -1814,12 +1797,12 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
             }
             this._lastText = curText;
         }
-        if (StrCast(this.rootDoc.title).startsWith('@') && !this.dataDoc.title_custom) {
+        if (StrCast(this.Document.title).startsWith('@') && !this.dataDoc.title_custom) {
             UndoManager.RunInBatch(() => {
                 this.dataDoc.title_custom = true;
                 this.dataDoc.layout_showTitle = 'title';
                 const tr = this._editorView!.state.tr;
-                this._editorView?.dispatch(tr.setSelection(new TextSelection(tr.doc.resolve(0), tr.doc.resolve(StrCast(this.rootDoc.title).length + 2))).deleteSelection());
+                this._editorView?.dispatch(tr.setSelection(new TextSelection(tr.doc.resolve(0), tr.doc.resolve(StrCast(this.Document.title).length + 2))).deleteSelection());
             }, 'titler');
         }
     };
@@ -1845,7 +1828,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
         let stopPropagation = true;
         for (var i = state.selection.from; i <= state.selection.to; i++) {
             const node = state.doc.resolve(i);
-            if (state.doc.content.size - 1 > i && node?.marks?.().some(mark => mark.type === schema.marks.user_mark && mark.attrs.userid !== Doc.CurrentUserEmail) && [AclAugment, AclSelfEdit].includes(GetEffectiveAcl(this.rootDoc))) {
+            if (state.doc.content.size - 1 > i && node?.marks?.().some(mark => mark.type === schema.marks.user_mark && mark.attrs.userid !== Doc.CurrentUserEmail) && [AclAugment, AclSelfEdit].includes(GetEffectiveAcl(this.Document))) {
                 e.preventDefault();
             }
         }
@@ -1868,7 +1851,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
                 if (this._lastTimedMark?.attrs.userid === Doc.CurrentUserEmail) break;
             case ' ':
                 if (e.code !== 'Space') {
-                    [AclEdit, AclAugment, AclAdmin].includes(GetEffectiveAcl(this.rootDoc)) &&
+                    [AclEdit, AclAugment, AclAdmin].includes(GetEffectiveAcl(this.Document)) &&
                         this._editorView!.dispatch(this._editorView!.state.tr.removeStoredMark(schema.marks.user_mark).addStoredMark(schema.marks.user_mark.create({ userid: Doc.CurrentUserEmail, modified: Math.floor(Date.now() / 1000) })));
                 }
                 break;
@@ -1904,9 +1887,9 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
             const scrollHeight = this.ProseRef && Math.min(NumCast(this.layoutDoc.layout_maxAutoHeight, proseHeight), proseHeight);
             if (this.props.setHeight && scrollHeight && !this.props.dontRegisterView) {
                 // if top === 0, then the text box is growing upward (as the overlay caption) which doesn't contribute to the height computation
-                const setScrollHeight = () => (this.rootDoc[this.fieldKey + '_scrollHeight'] = scrollHeight);
+                const setScrollHeight = () => (this.dataDoc[this.fieldKey + '_scrollHeight'] = scrollHeight);
 
-                if (this.rootDoc === this.layoutDoc || this.layoutDoc.resolvedDataDoc) {
+                if (this.Document === this.layoutDoc || this.layoutDoc.resolvedDataDoc) {
                     setScrollHeight();
                 } else {
                     setTimeout(setScrollHeight, 10); // if we have a template that hasn't been resolved yet, we can't set the height or we'd be setting it on the unresolved template.  So set a timeout and hope its arrived...
@@ -1922,7 +1905,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
     };
     sidebarMoveDocument = (doc: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (doc: Doc | Doc[]) => boolean) => this.moveDocument(doc, targetCollection, addDocument, this.SidebarKey);
     sidebarRemDocument = (doc: Doc | Doc[]) => this.removeDocument(doc, this.SidebarKey);
-    setSidebarHeight = (height: number) => (this.rootDoc[this.SidebarKey + '_height'] = height);
+    setSidebarHeight = (height: number) => (this.dataDoc[this.SidebarKey + '_height'] = height);
     sidebarWidth = () => (Number(this.layout_sidebarWidthPercent.substring(0, this.layout_sidebarWidthPercent.length - 1)) / 100) * this.props.PanelWidth();
     sidebarScreenToLocal = () =>
         this.props
@@ -1951,7 +1934,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
         TraceMobx();
         const annotated = DocListCast(this.dataDoc[this.SidebarKey]).filter(d => d?.author).length;
         const color = !annotated ? Colors.WHITE : Colors.BLACK;
-        const backgroundColor = !annotated ? (this.sidebarWidth() ? Colors.MEDIUM_BLUE : Colors.BLACK) : this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.WidgetColor + (annotated ? ':annotated' : ''));
+        const backgroundColor = !annotated ? (this.sidebarWidth() ? Colors.MEDIUM_BLUE : Colors.BLACK) : this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.WidgetColor + (annotated ? ':annotated' : ''));
 
         return !annotated && (!this.props.isContentActive() || SnappingManager.GetIsDragging() || Doc.ActiveTool !== InkTool.None) ? null : (
             <div
@@ -1973,7 +1956,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
                 <SidebarAnnos
                     ref={this._sidebarRef}
                     {...this.props}
-                    rootDoc={this.rootDoc}
+                    Document={this.Document}
                     layoutDoc={this.layoutDoc}
                     dataDoc={this.dataDoc}
                     usePanelWidth={true}
@@ -2028,12 +2011,12 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
     }
     cycleAlternateText = () => {
         if (this.layoutDoc._layout_enableAltContentUI) {
-            const usePath = this.rootDoc[`_${this.props.fieldKey}_usePath`];
-            this.rootDoc[`_${this.props.fieldKey}_usePath`] = usePath === undefined ? 'alternate' : usePath === 'alternate' ? 'alternate:hover' : undefined;
+            const usePath = this.layoutDoc[`_${this.props.fieldKey}_usePath`];
+            this.layoutDoc[`_${this.props.fieldKey}_usePath`] = usePath === undefined ? 'alternate' : usePath === 'alternate' ? 'alternate:hover' : undefined;
         }
     };
     @computed get overlayAlternateIcon() {
-        const usePath = this.rootDoc[`_${this.props.fieldKey}_usePath`];
+        const usePath = this.layoutDoc[`_${this.props.fieldKey}_usePath`];
         return (
             <Tooltip
                 title={
@@ -2065,13 +2048,13 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
         );
     }
     @computed get fieldKey() {
-        const usePath = StrCast(this.rootDoc[`${this.props.fieldKey}_usePath`]);
+        const usePath = StrCast(this.layoutDoc[`${this.props.fieldKey}_usePath`]);
         return this.props.fieldKey + (usePath && (!usePath.includes(':hover') || this._isHovering || this.props.isContentActive()) ? `_${usePath.replace(':hover', '')}` : '');
     }
     @observable _isHovering = false;
     onPassiveWheel = (e: WheelEvent) => {
         if (e.clientX > this.ProseRef!.getBoundingClientRect().right) {
-            if (this.rootDoc[this.SidebarKey + '_type_collection'] === CollectionViewType.Freeform) {
+            if (this.dataDoc[this.SidebarKey + '_type_collection'] === CollectionViewType.Freeform) {
                 // if the scrolled freeform is a child of the sidebar component, we need to let the event go through
                 // so react can let the freeform view handle it. We prevent default to stop any containing views from scrolling
                 e.preventDefault();
diff --git a/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx b/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx
index e7ca26d5c..4212d46eb 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx
@@ -135,7 +135,7 @@ export class FormattedTextBoxComment {
             naft &&
                 LinkDocPreview.SetLinkInfo({
                     docProps: textBox.props,
-                    linkSrc: textBox.rootDoc,
+                    linkSrc: textBox.Document,
                     linkDoc: linkDoc ? (DocServer.GetCachedRefField(linkDoc) as Doc) : undefined,
                     location: (pos => [pos.left, pos.top + 25])(view.coordsAtPos(state.selection.from - Math.max(0, nbef - 1))),
                     hrefs,
-- 
cgit v1.2.3-70-g09d2


From 50e770e42bd036d092f3c774921be87045dcd1ef Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Thu, 30 Nov 2023 21:01:57 -0500
Subject: final rootDoc refactoring

---
 src/client/util/CurrentUserUtils.ts                |   4 +-
 src/client/util/DragManager.ts                     |   6 +-
 .../util/Import & Export/DirectoryImportBox.tsx    |   4 +-
 src/client/util/SearchUtil.ts                      |   6 +-
 src/client/util/SelectionManager.ts                |   2 +-
 src/client/util/SharingManager.tsx                 |   6 +-
 src/client/views/DashboardView.tsx                 |   2 +-
 src/client/views/DocumentButtonBar.tsx             |  16 ++--
 src/client/views/DocumentDecorations.tsx           | 100 ++++++++++-----------
 src/client/views/FilterPanel.tsx                   |   8 +-
 src/client/views/GestureOverlay.tsx                |   2 +-
 src/client/views/InkStrokeProperties.ts            |  16 ++--
 src/client/views/MarqueeAnnotator.tsx              |   6 +-
 src/client/views/PropertiesButtons.tsx             |  20 ++---
 src/client/views/PropertiesDocContextSelector.tsx  |   2 +-
 src/client/views/PropertiesView.tsx                |   8 +-
 src/client/views/StyleProvider.tsx                 |   8 +-
 .../views/collections/CollectionNoteTakingView.tsx |   4 +-
 .../views/collections/CollectionStackingView.tsx   |   8 +-
 src/client/views/collections/CollectionSubView.tsx |   4 +-
 src/client/views/collections/CollectionView.tsx    |   2 +-
 src/client/views/collections/TabDocView.tsx        |   4 +-
 src/client/views/collections/TreeView.tsx          |   2 +-
 .../CollectionFreeFormLinkView.tsx                 |  12 +--
 .../collectionFreeForm/CollectionFreeFormView.tsx  |  14 +--
 .../collectionLinear/CollectionLinearView.tsx      |   4 +-
 .../collectionSchema/CollectionSchemaView.tsx      |   4 +-
 src/client/views/global/globalScripts.ts           |  24 ++---
 src/client/views/linking/LinkMenu.tsx              |   2 +-
 src/client/views/linking/LinkMenuGroup.tsx         |   4 +-
 src/client/views/linking/LinkMenuItem.tsx          |   2 +-
 .../components/Recommendation/Recommendation.tsx   |   2 +-
 src/client/views/nodes/ColorBox.tsx                |   6 +-
 src/client/views/nodes/DataVizBox/DataVizBox.tsx   |   2 +-
 .../nodes/DataVizBox/components/Histogram.tsx      |  11 ++-
 .../nodes/DataVizBox/components/LineChart.tsx      |   4 +-
 .../views/nodes/DataVizBox/components/PieChart.tsx |  10 +--
 .../views/nodes/DataVizBox/components/TableBox.tsx |  16 ++--
 src/client/views/nodes/DocumentIcon.tsx            |   4 +-
 src/client/views/nodes/DocumentLinksButton.tsx     |   2 +-
 src/client/views/nodes/DocumentView.tsx            |   8 +-
 .../views/nodes/FontIconBox/ButtonInterface.ts     |  10 +--
 src/client/views/nodes/LinkBox.tsx                 |   8 +-
 src/client/views/nodes/MapBox/MapBox.tsx           |   4 +-
 .../views/nodes/formattedText/DashFieldView.tsx    |   2 +-
 .../views/nodes/formattedText/FormattedTextBox.tsx |   2 +-
 .../views/nodes/formattedText/RichTextMenu.tsx     |   4 +-
 47 files changed, 200 insertions(+), 201 deletions(-)

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

diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index 7070a47e8..a4eaa71ef 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -110,7 +110,7 @@ export class CurrentUserUtils {
         const tempClicks = DocCast(doc[field]);
         const reqdClickOpts:DocumentOptions = {_width: 300, _height:200, isSystem: true};
         const reqdTempOpts:{opts:DocumentOptions, script: string}[] = [
-            { opts: { title: "Open In Target",        targetScriptKey: "onChildClick"},       script: "docCastAsync(documentView?.props.docViewPath().lastElement()?.rootDoc.target).then((target) => target && (target.proto.data = new List([self])))"},
+            { opts: { title: "Open In Target",        targetScriptKey: "onChildClick"},       script: "docCastAsync(documentView?.props.docViewPath().lastElement()?.Document.target).then((target) => target && (target.proto.data = new List([self])))"},
             { opts: { title: "Open Detail On Right",  targetScriptKey: "onChildDoubleClick"}, script: `openDoc(this.doubleClickView.${OpenWhere.addRight})`}];
         const reqdClickList = reqdTempOpts.map(opts => {
             const allOpts = {...reqdClickOpts, ...opts.opts};
@@ -816,7 +816,7 @@ export class CurrentUserUtils {
     // When the user views one of these documents, it will be added to the sharing documents 'viewed' list field
     // The sharing document also stores the user's color value which helps distinguish shared documents from personal documents
     static setupSharedDocs(doc: Doc, sharingDocumentId: string) {
-        const dblClkScript = "{scriptContext.openLevel(documentView); addDocToList(documentView.props.treeViewDoc, 'viewed', documentView.rootDoc);}";
+        const dblClkScript = "{scriptContext.openLevel(documentView); addDocToList(documentView.props.treeViewDoc, 'viewed', documentView.Document);}";
         
         const sharedScripts = {  treeView_ChildDoubleClick: dblClkScript,  }
         const sharedDocOpts:DocumentOptions = {
diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts
index 6e4de252d..162a0a11f 100644
--- a/src/client/util/DragManager.ts
+++ b/src/client/util/DragManager.ts
@@ -261,7 +261,7 @@ export namespace DragManager {
 
     // drags a linker button and creates a link on drop
     export function StartLinkDrag(ele: HTMLElement, sourceView: DocumentView, sourceDocGetAnchor: undefined | ((addAsAnnotation: boolean) => Doc), downX: number, downY: number, options?: DragOptions) {
-        StartDrag([ele], new DragManager.LinkDragData(sourceView, () => sourceDocGetAnchor?.(true) ?? sourceView.rootDoc), downX, downY, options);
+        StartDrag([ele], new DragManager.LinkDragData(sourceView, () => sourceDocGetAnchor?.(true) ?? sourceView.Document), downX, downY, options);
     }
 
     // drags a column from a schema view
@@ -611,7 +611,7 @@ export namespace DragManager {
 
 ScriptingGlobals.add(function toggleRaiseOnDrag(readOnly?: boolean) {
     if (readOnly) {
-        return SelectionManager.Views().some(dv => dv.rootDoc.keepZWhenDragged);
+        return SelectionManager.Views().some(dv => dv.Document.keepZWhenDragged);
     }
-    SelectionManager.Views().map(dv => (dv.rootDoc.keepZWhenDragged = !dv.rootDoc.keepZWhenDragged));
+    SelectionManager.Views().map(dv => (dv.Document.keepZWhenDragged = !dv.Document.keepZWhenDragged));
 });
diff --git a/src/client/util/Import & Export/DirectoryImportBox.tsx b/src/client/util/Import & Export/DirectoryImportBox.tsx
index 1a4c2450e..c45143f43 100644
--- a/src/client/util/Import & Export/DirectoryImportBox.tsx	
+++ b/src/client/util/Import & Export/DirectoryImportBox.tsx	
@@ -112,7 +112,7 @@ export class DirectoryImportBox extends React.Component<FieldViewProps> {
                 sizes.push(file.size);
                 modifiedDates.push(file.lastModified);
             });
-            collector.push(...(await Networking.UploadFilesToServer<Upload.ImageInformation>(batch.map(file =>({file})))));
+            collector.push(...(await Networking.UploadFilesToServer<Upload.ImageInformation>(batch.map(file => ({ file })))));
             runInAction(() => (this.completed += batch.length));
         });
 
@@ -158,7 +158,7 @@ export class DirectoryImportBox extends React.Component<FieldViewProps> {
             y: NumCast(doc.y) + offset,
         };
         const parent = this.props.DocumentView?.().props.docViewPath().lastElement();
-        if (parent?.rootDoc.type === DocumentType.COL) {
+        if (parent?.Document.type === DocumentType.COL) {
             let importContainer: Doc;
             if (docs.length < 50) {
                 importContainer = Docs.Create.MasonryDocument(docs, options);
diff --git a/src/client/util/SearchUtil.ts b/src/client/util/SearchUtil.ts
index 560d6b30f..e51770c25 100644
--- a/src/client/util/SearchUtil.ts
+++ b/src/client/util/SearchUtil.ts
@@ -9,7 +9,7 @@ import { StrCast } from '../../fields/Types';
 export namespace SearchUtil {
     export type HighlightingResult = { [id: string]: { [key: string]: string[] } };
 
-    export function SearchCollection(rootDoc: Opt<Doc>, query: string) {
+    export function SearchCollection(collectionDoc: Opt<Doc>, query: string) {
         const blockedTypes = [DocumentType.PRESELEMENT, DocumentType.CONFIG, DocumentType.KVP, DocumentType.FONTICON, DocumentType.BUTTON, DocumentType.SCRIPTING];
         const blockedKeys = [
             'x',
@@ -48,8 +48,8 @@ export namespace SearchUtil {
         query = query.toLowerCase();
 
         const results = new Map<Doc, string[]>();
-        if (rootDoc) {
-            const docs = DocListCast(rootDoc[Doc.LayoutFieldKey(rootDoc)]);
+        if (collectionDoc) {
+            const docs = DocListCast(collectionDoc[Doc.LayoutFieldKey(collectionDoc)]);
             const docIDs: String[] = [];
             SearchUtil.foreachRecursiveDoc(docs, (depth: number, doc: Doc) => {
                 const dtype = StrCast(doc.type) as DocumentType;
diff --git a/src/client/util/SelectionManager.ts b/src/client/util/SelectionManager.ts
index f7e6fa2dc..25f158f40 100644
--- a/src/client/util/SelectionManager.ts
+++ b/src/client/util/SelectionManager.ts
@@ -81,7 +81,7 @@ export namespace SelectionManager {
         return manager.SelectedSchemaDocument;
     }
     export function Docs(): Doc[] {
-        return manager.SelectedViews.map(dv => dv.rootDoc).filter(doc => doc?._type_collection !== CollectionViewType.Docking);
+        return manager.SelectedViews.map(dv => dv.Document).filter(doc => doc?._type_collection !== CollectionViewType.Docking);
     }
 }
 ScriptingGlobals.add(function SelectionManager_selectedDocType(type: string, expertMode: boolean, checkContext?: boolean) {
diff --git a/src/client/util/SharingManager.tsx b/src/client/util/SharingManager.tsx
index 8d59426ec..34e294a4a 100644
--- a/src/client/util/SharingManager.tsx
+++ b/src/client/util/SharingManager.tsx
@@ -162,7 +162,7 @@ export class SharingManager extends React.Component<{}> {
         const { user, sharingDoc } = recipient;
         const target = targetDoc || this.targetDoc!;
         const acl = `acl-${normalizeEmail(user.email)}`;
-        const docs = SelectionManager.Views().length < 2 ? [target] : SelectionManager.Views().map(docView => docView.rootDoc);
+        const docs = SelectionManager.Views().length < 2 ? [target] : SelectionManager.Views().map(docView => docView.Document);
         docs.map(doc => (this.layoutDocAcls || doc.dockingConfig ? doc : Doc.GetProto(doc))).forEach(doc => {
             distributeAcls(acl, permission as SharingPermissions, doc, undefined, this.upgradeNested ? true : undefined);
             if (permission !== SharingPermissions.None) {
@@ -180,7 +180,7 @@ export class SharingManager extends React.Component<{}> {
         const target = targetDoc || this.targetDoc!;
         const acl = `acl-${normalizeEmail(StrCast(group.title))}`;
 
-        const docs = SelectionManager.Views().length < 2 ? [target] : SelectionManager.Views().map(docView => docView.rootDoc);
+        const docs = SelectionManager.Views().length < 2 ? [target] : SelectionManager.Views().map(docView => docView.Document);
         docs.map(doc => (this.layoutDocAcls || doc.dockingConfig ? doc : Doc.GetProto(doc))).forEach(doc => {
             distributeAcls(acl, permission as SharingPermissions, doc, undefined, this.upgradeNested ? true : undefined);
 
@@ -444,7 +444,7 @@ export class SharingManager extends React.Component<{}> {
         const users = this.individualSort === 'ascending' ? this.users.slice().sort(this.sortUsers) : this.individualSort === 'descending' ? this.users.slice().sort(this.sortUsers).reverse() : this.users;
         const groups = this.groupSort === 'ascending' ? groupList.slice().sort(this.sortGroups) : this.groupSort === 'descending' ? groupList.slice().sort(this.sortGroups).reverse() : groupList;
 
-        let docs = SelectionManager.Views().length < 2 ? [this.targetDoc] : SelectionManager.Views().map(docView => docView.rootDoc);
+        let docs = SelectionManager.Views().length < 2 ? [this.targetDoc] : SelectionManager.Views().map(docView => docView.Document);
 
         if (this.myDocAcls) {
             const newDocs: Doc[] = [];
diff --git a/src/client/views/DashboardView.tsx b/src/client/views/DashboardView.tsx
index 2765e95e6..04fb1fe80 100644
--- a/src/client/views/DashboardView.tsx
+++ b/src/client/views/DashboardView.tsx
@@ -429,7 +429,7 @@ export class DashboardView extends React.Component {
             isSystem: true,
             layout_explainer: 'All of the trails that you have created will appear here.',
         };
-        const myTrails = DocUtils.AssignScripts(Docs.Create.TreeDocument([], reqdOpts), { treeView_ChildDoubleClick: 'openPresentation(documentView.rootDoc)' });
+        const myTrails = DocUtils.AssignScripts(Docs.Create.TreeDocument([], reqdOpts), { treeView_ChildDoubleClick: 'openPresentation(documentView.Document)' });
         dashboardDoc.myTrails = new PrefetchProxy(myTrails);
 
         const contextMenuScripts = [reqdBtnScript.onClick];
diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx
index bd82f7782..59d7e75da 100644
--- a/src/client/views/DocumentButtonBar.tsx
+++ b/src/client/views/DocumentButtonBar.tsx
@@ -229,7 +229,7 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV
                             onPointerEnter={action(e => (this.subPin = allDocs ? 'All ' : ''))}
                             onPointerLeave={action(e => (this.subPin = ''))}
                             onClick={e => {
-                                this.props.views().forEach(dv => click(dv!.rootDoc));
+                                this.props.views().forEach(dv => click(dv!.Document));
                                 e.stopPropagation();
                             }}
                         />
@@ -356,7 +356,7 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV
                                 const docs = this.props
                                     .views()
                                     .filter(v => v)
-                                    .map(dv => dv!.rootDoc);
+                                    .map(dv => dv!.Document);
                                 TabDocView.PinDoc(docs, {
                                     pinAudioPlay: true,
                                     pinDocLayout: pinLayoutView,
@@ -379,7 +379,7 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV
                         const docs = this.props
                             .views()
                             .filter(v => v)
-                            .map(dv => dv!.rootDoc);
+                            .map(dv => dv!.Document);
                         TabDocView.PinDoc(docs, { pinAudioPlay: true, pinDocLayout: e.shiftKey, pinData: { dataview: e.altKey }, activeFrame: Cast(docs.lastElement()?.activeFrame, 'number', null) });
                         e.stopPropagation();
                     }}>
@@ -560,9 +560,9 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV
     @action
     toggleTrail = (e: React.PointerEvent) => {
         const rootView = this.props.views()[0];
-        const rootDoc = rootView?.rootDoc;
-        if (rootDoc) {
-            const anchor = rootView.ComponentView?.getAnchor?.(true) ?? rootDoc;
+        const doc = rootView?.Document;
+        if (doc) {
+            const anchor = rootView.ComponentView?.getAnchor?.(true) ?? doc;
             const trail = DocCast(anchor.presentationTrail) ?? Doc.MakeCopy(DocCast(Doc.UserDoc().emptyTrail), true);
             if (trail !== anchor.presentationTrail) {
                 DocUtils.MakeLink(anchor, trail, { link_relationship: 'link trail' });
@@ -589,9 +589,9 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV
                     <div style={{ position: 'absolute', zIndex: 1000 }}>
                         <LinkPopup
                             key="popup"
-                            linkCreated={link => (link.link_displayLine = !IsFollowLinkScript(this.props.views().lastElement()?.rootDoc.onClick))}
+                            linkCreated={link => (link.link_displayLine = !IsFollowLinkScript(this.props.views().lastElement()?.Document.onClick))}
                             linkCreateAnchor={() => this.props.views().lastElement()?.ComponentView?.getAnchor?.(true)}
-                            linkFrom={() => this.props.views().lastElement()?.rootDoc}
+                            linkFrom={() => this.props.views().lastElement()?.Document}
                         />
                     </div>
                 ) : (
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 4ede2e2bb..719055149 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -116,11 +116,11 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
                     SelectionManager.Views().forEach(d => {
                         if (titleFieldKey === 'title') {
                             d.dataDoc.title_custom = !this._accumulatedTitle.startsWith('-');
-                            if (StrCast(d.rootDoc.title).startsWith('@') && !this._accumulatedTitle.startsWith('@')) {
-                                Doc.RemFromMyPublished(d.rootDoc);
+                            if (StrCast(d.Document.title).startsWith('@') && !this._accumulatedTitle.startsWith('@')) {
+                                Doc.RemFromMyPublished(d.Document);
                             }
-                            if (!StrCast(d.rootDoc.title).startsWith('@') && this._accumulatedTitle.startsWith('@')) {
-                                Doc.AddToMyPublished(d.rootDoc);
+                            if (!StrCast(d.Document.title).startsWith('@') && this._accumulatedTitle.startsWith('@')) {
+                                Doc.AddToMyPublished(d.Document);
                             }
                         }
                         //@ts-ignore
@@ -128,20 +128,20 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
 
                         if (titleField.toString().startsWith('<this>')) {
                             const title = titleField.toString().replace(/<this>\.?/, '');
-                            const curKey = Doc.LayoutFieldKey(d.rootDoc);
+                            const curKey = Doc.LayoutFieldKey(d.Document);
                             if (curKey !== title) {
                                 if (title) {
                                     if (d.dataDoc[title] === undefined || d.dataDoc[title] instanceof RichTextField || typeof d.dataDoc[title] === 'string') {
-                                        d.rootDoc.layout_fieldKey = `layout_${title}`;
-                                        d.rootDoc[`layout_${title}`] = FormattedTextBox.LayoutString(title);
-                                        d.rootDoc[`${title}_nativeWidth`] = d.rootDoc[`${title}_nativeHeight`] = 0;
+                                        d.Document.layout_fieldKey = `layout_${title}`;
+                                        d.Document[`layout_${title}`] = FormattedTextBox.LayoutString(title);
+                                        d.Document[`${title}_nativeWidth`] = d.Document[`${title}_nativeHeight`] = 0;
                                     }
                                 } else {
-                                    d.rootDoc.layout_fieldKey = undefined;
+                                    d.Document.layout_fieldKey = undefined;
                                 }
                             }
                         } else {
-                            Doc.SetInPlace(d.rootDoc, titleFieldKey, titleField, true);
+                            Doc.SetInPlace(d.Document, titleFieldKey, titleField, true);
                         }
                     }),
                 'edit title'
@@ -157,7 +157,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
     };
 
     onContainerDown = (e: React.PointerEvent) => {
-        const effectiveLayoutAcl = GetEffectiveAcl(SelectionManager.Views()[0].rootDoc);
+        const effectiveLayoutAcl = GetEffectiveAcl(SelectionManager.Views()[0].Document);
         if (effectiveLayoutAcl == AclAdmin || effectiveLayoutAcl == AclEdit || effectiveLayoutAcl == AclAugment) {
             setupMoveUpEvents(this, e, e => this.onBackgroundMove(true, e), emptyFunction, emptyFunction);
             e.stopPropagation();
@@ -165,7 +165,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
     };
 
     onTitleDown = (e: React.PointerEvent) => {
-        const effectiveLayoutAcl = GetEffectiveAcl(SelectionManager.Views()[0].rootDoc);
+        const effectiveLayoutAcl = GetEffectiveAcl(SelectionManager.Views()[0].Document);
         if (effectiveLayoutAcl == AclAdmin || effectiveLayoutAcl == AclEdit || effectiveLayoutAcl == AclAugment) {
             setupMoveUpEvents(
                 this,
@@ -189,12 +189,12 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
     @action
     onBackgroundMove = (dragTitle: boolean, e: PointerEvent): boolean => {
         const dragDocView = SelectionManager.Views()[0];
-        const effectiveLayoutAcl = GetEffectiveAcl(dragDocView.rootDoc);
+        const effectiveLayoutAcl = GetEffectiveAcl(dragDocView.Document);
         if (effectiveLayoutAcl != AclAdmin && effectiveLayoutAcl != AclEdit && effectiveLayoutAcl != AclAugment) {
             return false;
         }
         const containers = new Set<Doc | undefined>();
-        SelectionManager.Views().forEach(v => containers.add(DocCast(v.rootDoc.embedContainer)));
+        SelectionManager.Views().forEach(v => containers.add(DocCast(v.Document.embedContainer)));
         if (containers.size > 1) return false;
         const { left, top } = dragDocView.getBounds() || { left: 0, top: 0 };
         const dragData = new DragManager.DocumentDragData(
@@ -256,7 +256,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
     };
 
     onMaximizeDown = (e: React.PointerEvent) => {
-        setupMoveUpEvents(this, e, () => DragManager.StartWindowDrag?.(e, [SelectionManager.Views().lastElement().rootDoc]) ?? false, emptyFunction, this.onMaximizeClick, false, false);
+        setupMoveUpEvents(this, e, () => DragManager.StartWindowDrag?.(e, [SelectionManager.Views().lastElement().Document]) ?? false, emptyFunction, this.onMaximizeClick, false, false);
         e.stopPropagation();
     };
     onMaximizeClick = (e: any): void => {
@@ -264,19 +264,19 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
         if (selectedDocs.length) {
             if (e.ctrlKey) {
                 // open an embedding in a new tab with Ctrl Key
-                CollectionDockingView.AddSplit(Doc.BestEmbedding(selectedDocs[0].rootDoc), OpenWhereMod.right);
+                CollectionDockingView.AddSplit(Doc.BestEmbedding(selectedDocs[0].Document), OpenWhereMod.right);
             } else if (e.shiftKey) {
                 // open centered in a new workspace with Shift Key
-                const embedding = Doc.MakeEmbedding(selectedDocs[0].rootDoc);
+                const embedding = Doc.MakeEmbedding(selectedDocs[0].Document);
                 embedding.embedContainer = undefined;
                 embedding.x = -NumCast(embedding._width) / 2;
                 embedding.y = -NumCast(embedding._height) / 2;
                 CollectionDockingView.AddSplit(Docs.Create.FreeformDocument([embedding], { title: 'Tab for ' + embedding.title }), OpenWhereMod.right);
             } else if (e.altKey) {
                 // open same document in new tab
-                CollectionDockingView.ToggleSplit(selectedDocs[0].rootDoc, OpenWhereMod.right);
+                CollectionDockingView.ToggleSplit(selectedDocs[0].Document, OpenWhereMod.right);
             } else {
-                var openDoc = selectedDocs[0].rootDoc;
+                var openDoc = selectedDocs[0].Document;
                 if (openDoc.layout_fieldKey === 'layout_icon') {
                     openDoc = DocListCast(openDoc.proto_embeddings).find(embedding => !embedding.embedContainer) ?? Doc.MakeEmbedding(openDoc);
                     Doc.deiconifyView(openDoc);
@@ -284,7 +284,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
                 LightboxView.Instance.SetLightboxDoc(
                     openDoc,
                     undefined,
-                    selectedDocs.slice(1).map(view => view.rootDoc)
+                    selectedDocs.slice(1).map(view => view.Document)
                 );
             }
         }
@@ -346,9 +346,9 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
     setRotateCenter = (seldocview: DocumentView, rotCenter: number[]) => {
         const newloccentern = seldocview.props.ScreenToLocalTransform().transformPoint(rotCenter[0], rotCenter[1]);
         const newlocenter = [newloccentern[0] - NumCast(seldocview.layoutDoc._width) / 2, newloccentern[1] - NumCast(seldocview.layoutDoc._height) / 2];
-        const final = Utils.rotPt(newlocenter[0], newlocenter[1], -(NumCast(seldocview.rootDoc._rotation) / 180) * Math.PI);
-        seldocview.rootDoc.rotation_centerX = final.x / NumCast(seldocview.layoutDoc._width);
-        seldocview.rootDoc.rotation_centerY = final.y / NumCast(seldocview.layoutDoc._height);
+        const final = Utils.rotPt(newlocenter[0], newlocenter[1], -(NumCast(seldocview.Document._rotation) / 180) * Math.PI);
+        seldocview.Document.rotation_centerX = final.x / NumCast(seldocview.layoutDoc._width);
+        seldocview.Document.rotation_centerY = final.y / NumCast(seldocview.layoutDoc._height);
     };
 
     @action
@@ -361,7 +361,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
             (e: PointerEvent, down: number[], delta: number[]) => // return false to keep getting events
                 this.setRotateCenter(seldocview, [this.rotCenter[0] + delta[0], this.rotCenter[1] + delta[1]]) as any as boolean, 
             action(e => (this._isRotating = false)), // upEvent
-            action(e => (seldocview.rootDoc.rotation_centerX = seldocview.rootDoc.rotation_centerY = 0))
+            action(e => (seldocview.Document.rotation_centerX = seldocview.Document.rotation_centerY = 0))
         ); // prettier-ignore
     };
 
@@ -375,22 +375,22 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
         const infos = new Map<Doc, { unrotatedDocPos: { x: number; y: number }; startRotCtr: { x: number; y: number }; accumRot: number }>();
         const seldocview = SelectionManager.Views()[0];
         SelectionManager.Views().forEach(dv => {
-            const accumRot = (NumCast(dv.rootDoc._rotation) / 180) * Math.PI;
+            const accumRot = (NumCast(dv.Document._rotation) / 180) * Math.PI;
             const localRotCtr = dv.props.ScreenToLocalTransform().transformPoint(rcScreen.X, rcScreen.Y);
-            const localRotCtrOffset = [localRotCtr[0] - NumCast(dv.rootDoc.width) / 2, localRotCtr[1] - NumCast(dv.rootDoc.height) / 2];
+            const localRotCtrOffset = [localRotCtr[0] - NumCast(dv.Document.width) / 2, localRotCtr[1] - NumCast(dv.Document.height) / 2];
             const startRotCtr = Utils.rotPt(localRotCtrOffset[0], localRotCtrOffset[1], -accumRot);
-            const unrotatedDocPos = { x: NumCast(dv.rootDoc.x) + localRotCtrOffset[0] - startRotCtr.x, y: NumCast(dv.rootDoc.y) + localRotCtrOffset[1] - startRotCtr.y };
-            infos.set(dv.rootDoc, { unrotatedDocPos, startRotCtr, accumRot });
+            const unrotatedDocPos = { x: NumCast(dv.Document.x) + localRotCtrOffset[0] - startRotCtr.x, y: NumCast(dv.Document.y) + localRotCtrOffset[1] - startRotCtr.y };
+            infos.set(dv.Document, { unrotatedDocPos, startRotCtr, accumRot });
         });
         const infoRot = (angle: number, isAbs = false) => {
             SelectionManager.Views().forEach(
                 action(dv => {
-                    const { unrotatedDocPos, startRotCtr, accumRot } = infos.get(dv.rootDoc)!;
+                    const { unrotatedDocPos, startRotCtr, accumRot } = infos.get(dv.Document)!;
                     const endRotCtr = Utils.rotPt(startRotCtr.x, startRotCtr.y, isAbs ? angle : accumRot + angle);
-                    infos.set(dv.rootDoc, { unrotatedDocPos, startRotCtr, accumRot: isAbs ? angle : accumRot + angle });
-                    dv.rootDoc.x = infos.get(dv.rootDoc)!.unrotatedDocPos.x - (endRotCtr.x - startRotCtr.x);
-                    dv.rootDoc.y = infos.get(dv.rootDoc)!.unrotatedDocPos.y - (endRotCtr.y - startRotCtr.y);
-                    dv.rootDoc._rotation = ((isAbs ? 0 : NumCast(dv.rootDoc._rotation)) + (angle * 180) / Math.PI) % 360; // Rotation between -360 and 360
+                    infos.set(dv.Document, { unrotatedDocPos, startRotCtr, accumRot: isAbs ? angle : accumRot + angle });
+                    dv.Document.x = infos.get(dv.Document)!.unrotatedDocPos.x - (endRotCtr.x - startRotCtr.x);
+                    dv.Document.y = infos.get(dv.Document)!.unrotatedDocPos.y - (endRotCtr.y - startRotCtr.y);
+                    dv.Document._rotation = ((isAbs ? 0 : NumCast(dv.Document._rotation)) + (angle * 180) / Math.PI) % 360; // Rotation between -360 and 360
                 })
             );
         };
@@ -410,7 +410,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
                 return false;
             }, // moveEvent
             action(() => {
-                const oldRotation = NumCast(seldocview.rootDoc._rotation);
+                const oldRotation = NumCast(seldocview.Document._rotation);
                 const diff = oldRotation - Math.round(oldRotation / 45) * 45;
                 if (Math.abs(diff) < 5) {
                     if (selectedInk.length) {
@@ -459,7 +459,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
     };
     onPointerMove = (e: PointerEvent, down: number[], move: number[]): boolean => {
         const first = SelectionManager.Views()[0];
-        const effectiveAcl = GetEffectiveAcl(first.rootDoc);
+        const effectiveAcl = GetEffectiveAcl(first.Document);
         if (!(effectiveAcl == AclAdmin || effectiveAcl == AclEdit || effectiveAcl == AclAugment)) return false;
         if (!first) return false;
         var fixedAspect = Doc.NativeAspect(first.layoutDoc);
@@ -514,7 +514,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
     // resize a single DocumentView about the specified reference point, possibly setting/updating the native dimensions of the Doc
     //
     resizeView = (docView: DocumentView, refPt: number[], scale: { x: number; y: number }, opts: { dragHdl: string; ctrlKey: boolean }) => {
-        const doc = docView.rootDoc;
+        const doc = docView.Document;
         if (doc.isGroup) {
             DocListCast(doc.data)
                 .map(member => DocumentManager.Instance.getDocumentView(member, docView)!)
@@ -615,7 +615,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
                 return selected.ComponentView.getTitle();
             }
             if (this._titleControlString.startsWith('=')) {
-                return ScriptField.MakeFunction(this._titleControlString.substring(1), { doc: Doc.name })!.script.run({ self: selected.rootDoc, this: selected.layoutDoc }, console.log).result?.toString() || '';
+                return ScriptField.MakeFunction(this._titleControlString.substring(1), { doc: Doc.name })!.script.run({ self: selected.Document, this: selected.layoutDoc }, console.log).result?.toString() || '';
             }
             if (this._titleControlString.startsWith('#')) {
                 return Field.toString(selected.props.Document[this._titleControlString.substring(1)] as Field) || '-unset-';
@@ -645,24 +645,24 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
         }
 
         // sharing
-        const acl = GetEffectiveAcl(!this._showLayoutAcl ? Doc.GetProto(seldocview.rootDoc) : seldocview.rootDoc);
+        const acl = GetEffectiveAcl(!this._showLayoutAcl ? Doc.GetProto(seldocview.Document) : seldocview.Document);
         const docShareMode = HierarchyMapping.get(acl)!.name;
         const shareMode = StrCast(docShareMode);
         var shareSymbolIcon = ReverseHierarchyMap.get(shareMode)?.image;
 
         // hide the decorations if the parent chooses to hide it or if the document itself hides it
-        const hideDecorations = SnappingManager.GetIsResizing() || seldocview.props.hideDecorations || seldocview.rootDoc.layout_hideDecorations;
+        const hideDecorations = SnappingManager.GetIsResizing() || seldocview.props.hideDecorations || seldocview.Document.layout_hideDecorations;
         const hideResizers =
-            ![AclAdmin, AclEdit, AclAugment].includes(GetEffectiveAcl(seldocview.rootDoc)) || hideDecorations || seldocview.props.hideResizeHandles || seldocview.rootDoc.layout_hideResizeHandles || this._isRounding || this._isRotating;
-        const hideTitle = this._showNothing || hideDecorations || seldocview.props.hideDecorationTitle || seldocview.rootDoc.layout_hideDecorationTitle || this._isRounding || this._isRotating;
-        const hideDocumentButtonBar = hideDecorations || seldocview.props.hideDocumentButtonBar || seldocview.rootDoc.layout_hideDocumentButtonBar || this._isRounding || this._isRotating;
+            ![AclAdmin, AclEdit, AclAugment].includes(GetEffectiveAcl(seldocview.Document)) || hideDecorations || seldocview.props.hideResizeHandles || seldocview.Document.layout_hideResizeHandles || this._isRounding || this._isRotating;
+        const hideTitle = this._showNothing || hideDecorations || seldocview.props.hideDecorationTitle || seldocview.Document.layout_hideDecorationTitle || this._isRounding || this._isRotating;
+        const hideDocumentButtonBar = hideDecorations || seldocview.props.hideDocumentButtonBar || seldocview.Document.layout_hideDocumentButtonBar || this._isRounding || this._isRotating;
         // if multiple documents have been opened at the same time, then don't show open button
         const hideOpenButton =
             this._showNothing ||
             hideDecorations ||
             seldocview.props.hideOpenButton ||
-            seldocview.rootDoc.layout_hideOpenButton ||
-            SelectionManager.Views().some(docView => docView.rootDoc._dragOnlyWithinContainer || docView.rootDoc.isGroup || docView.rootDoc.layout_hideOpenButton) ||
+            seldocview.Document.layout_hideOpenButton ||
+            SelectionManager.Views().some(docView => docView.Document._dragOnlyWithinContainer || docView.Document.isGroup || docView.Document.layout_hideOpenButton) ||
             this._isRounding ||
             this._isRotating;
         const hideDeleteButton =
@@ -671,10 +671,10 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
             this._isRounding ||
             this._isRotating ||
             seldocview.props.hideDeleteButton ||
-            seldocview.rootDoc.hideDeleteButton ||
+            seldocview.Document.hideDeleteButton ||
             SelectionManager.Views().some(docView => {
                 const collectionAcl = docView.props.docViewPath()?.lastElement() ? GetEffectiveAcl(docView.props.docViewPath().lastElement().dataDoc) : AclEdit;
-                return collectionAcl !== AclAdmin && collectionAcl !== AclEdit && GetEffectiveAcl(docView.rootDoc) !== AclAdmin;
+                return collectionAcl !== AclAdmin && collectionAcl !== AclEdit && GetEffectiveAcl(docView.Document) !== AclAdmin;
             });
         const topBtn = (key: string, icon: string, pointerDown: undefined | ((e: React.PointerEvent) => void), click: undefined | ((e: any) => void), title: string) => (
             <Tooltip key={key} title={<div className="dash-tooltip">{title}</div>} placement="top">
@@ -686,13 +686,13 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
 
         const bounds = this.ClippedBounds;
         const useLock = bounds.r - bounds.x > 135 && seldocview.CollectionFreeFormDocumentView;
-        const useRotation = !hideResizers && seldocview.rootDoc.type !== DocumentType.EQUATION && seldocview.CollectionFreeFormDocumentView; // when do we want an object to not rotate?
+        const useRotation = !hideResizers && seldocview.Document.type !== DocumentType.EQUATION && seldocview.CollectionFreeFormDocumentView; // when do we want an object to not rotate?
         const rotation = SelectionManager.Views().length == 1 ? seldocview.screenToLocalTransform().inverse().RotateDeg : 0;
 
         // Radius constants
         const useRounding = seldocview.ComponentView instanceof ImageBox || seldocview.ComponentView instanceof FormattedTextBox || seldocview.ComponentView instanceof CollectionFreeFormView;
-        const borderRadius = numberValue(Cast(seldocview.rootDoc.layout_borderRounding, 'string', null));
-        const docMax = Math.min(NumCast(seldocview.rootDoc.width) / 2, NumCast(seldocview.rootDoc.height) / 2);
+        const borderRadius = numberValue(Cast(seldocview.Document.layout_borderRounding, 'string', null));
+        const docMax = Math.min(NumCast(seldocview.Document.width) / 2, NumCast(seldocview.Document.height) / 2);
         const maxDist = Math.min((this.Bounds.r - this.Bounds.x) / 2, (this.Bounds.b - this.Bounds.y) / 2);
         const radiusHandle = (borderRadius / docMax) * maxDist;
         const radiusHandleLocation = Math.min(radiusHandle, maxDist);
@@ -740,7 +740,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
                 {sharingMenu}
                 {!useLock ? null : (
                     <Tooltip key="lock" title={<div className="dash-tooltip">toggle ability to interact with document</div>} placement="top">
-                        <div className="documentDecorations-lock" style={{ color: seldocview.rootDoc._lockedPosition ? 'red' : undefined }} onPointerDown={this.onLockDown}>
+                        <div className="documentDecorations-lock" style={{ color: seldocview.Document._lockedPosition ? 'red' : undefined }} onPointerDown={this.onLockDown}>
                             <FontAwesomeIcon size="sm" icon="lock" />
                         </div>
                     </Tooltip>
diff --git a/src/client/views/FilterPanel.tsx b/src/client/views/FilterPanel.tsx
index cb5c9b085..1deca401d 100644
--- a/src/client/views/FilterPanel.tsx
+++ b/src/client/views/FilterPanel.tsx
@@ -21,7 +21,7 @@ import { List } from '../../fields/List';
 import { emptyFunction } from '../../Utils';
 
 interface filterProps {
-    rootDoc: Doc;
+    Document: Doc;
 }
 
 @observer
@@ -34,7 +34,7 @@ export class FilterPanel extends React.Component<filterProps> {
      * @returns the relevant doc according to the value of FilterBox._filterScope i.e. either the Current Dashboard or the Current Collection
      */
     @computed get targetDoc() {
-        return this.props.rootDoc;
+        return this.props.Document;
     }
     @computed get targetDocChildKey() {
         const targetView = DocumentManager.Instance.getFirstDocumentView(this.targetDoc);
@@ -113,7 +113,7 @@ export class FilterPanel extends React.Component<filterProps> {
     // }
 
     gatherFieldValues(childDocs: Doc[], facetKey: string) {
-        const valueSet = new Set<string>(StrListCast(this.props.rootDoc.childFilters).map(filter => filter.split(Doc.FilterSep)[1]));
+        const valueSet = new Set<string>(StrListCast(this.props.Document.childFilters).map(filter => filter.split(Doc.FilterSep)[1]));
         let rtFields = 0;
         let subDocs = childDocs;
         if (subDocs.length > 0) {
@@ -224,7 +224,7 @@ export class FilterPanel extends React.Component<filterProps> {
     facetValues = (facetHeader: string) => {
         const allCollectionDocs = new Set<Doc>();
         SearchUtil.foreachRecursiveDoc(this.targetDocChildren, (depth: number, doc: Doc) => allCollectionDocs.add(doc));
-        const set = new Set<string>([...StrListCast(this.props.rootDoc.childFilters).map(filter => filter.split(Doc.FilterSep)[1]), Doc.FilterNone, Doc.FilterAny]);
+        const set = new Set<string>([...StrListCast(this.props.Document.childFilters).map(filter => filter.split(Doc.FilterSep)[1]), Doc.FilterNone, Doc.FilterAny]);
         if (facetHeader === 'tags')
             allCollectionDocs.forEach(child =>
                 StrListCast(child[facetHeader])
diff --git a/src/client/views/GestureOverlay.tsx b/src/client/views/GestureOverlay.tsx
index 09be95542..508339efc 100644
--- a/src/client/views/GestureOverlay.tsx
+++ b/src/client/views/GestureOverlay.tsx
@@ -386,7 +386,7 @@ export class GestureOverlay extends React.Component<React.PropsWithChildren<Gest
 
     @computed get elements() {
         const selView = GestureOverlay.DownDocView;
-        const width = Number(ActiveInkWidth()) * NumCast(selView?.rootDoc._freeform_scale, 1); // * (selView?.props.ScreenToLocalTransform().Scale || 1);
+        const width = Number(ActiveInkWidth()) * NumCast(selView?.Document._freeform_scale, 1); // * (selView?.props.ScreenToLocalTransform().Scale || 1);
         const rect = this._overlayRef.current?.getBoundingClientRect();
         const B = { left: -20000, right: 20000, top: -20000, bottom: 20000, width: 40000, height: 40000 }; //this.getBounds(this._points, true);
         B.left = B.left - width / 2;
diff --git a/src/client/views/InkStrokeProperties.ts b/src/client/views/InkStrokeProperties.ts
index 62165bc48..9efa7baac 100644
--- a/src/client/views/InkStrokeProperties.ts
+++ b/src/client/views/InkStrokeProperties.ts
@@ -49,7 +49,7 @@ export class InkStrokeProperties {
         (strokes instanceof DocumentView ? [strokes] : strokes)?.forEach(
             action(inkView => {
                 if (!requireCurrPoint || this._currentPoint !== -1) {
-                    const doc = inkView.rootDoc;
+                    const doc = inkView.Document;
                     if (doc.type === DocumentType.INK && doc.width && doc.height) {
                         const ink = Cast(doc.stroke, InkField)?.inkData;
                         if (ink) {
@@ -86,7 +86,7 @@ export class InkStrokeProperties {
     @action
     addPoints = (inkView: DocumentView, t: number, i: number, controls: { X: number; Y: number }[]) => {
         this.applyFunction(inkView, (view: DocumentView, ink: InkData) => {
-            const doc = view.rootDoc;
+            const doc = view.Document;
             const array = [controls[i], controls[i + 1], controls[i + 2], controls[i + 3]];
             const newsegs = new Bezier(array.map(p => ({ x: p.X, y: p.Y }))).split(t);
             const splicepts = [...newsegs.left.points, ...newsegs.right.points];
@@ -159,7 +159,7 @@ export class InkStrokeProperties {
         this.applyFunction(
             inkView,
             (view: DocumentView, ink: InkData) => {
-                const doc = view.rootDoc;
+                const doc = view.Document;
                 const newPoints = ink.slice();
                 const brokenIndices = NumListCast(doc.brokenInkIndices);
                 if (preserve || this._currentPoint === 0 || this._currentPoint === ink.length - 1 || brokenIndices.includes(this._currentPoint)) {
@@ -335,7 +335,7 @@ export class InkStrokeProperties {
      * Handles the movement/scaling of a control point.
      */
     snapControl = (inkView: DocumentView, controlIndex: number) => {
-        const inkDoc = inkView.rootDoc;
+        const inkDoc = inkView.Document;
         const ink = Cast(inkDoc[Doc.LayoutFieldKey(inkDoc)], InkField)?.inkData;
 
         if (ink) {
@@ -378,9 +378,9 @@ export class InkStrokeProperties {
             .filter(doc => doc.type === DocumentType.INK)
             .forEach(doc => {
                 const testInkView = DocumentManager.Instance.getDocumentView(doc, containingDocView);
-                const snapped = testInkView?.ComponentView?.snapPt?.(screenDragPt, doc === inkView.rootDoc ? this.excludeSelfSnapSegs(ink, controlIndex) : []);
+                const snapped = testInkView?.ComponentView?.snapPt?.(screenDragPt, doc === inkView.Document ? this.excludeSelfSnapSegs(ink, controlIndex) : []);
                 if (snapped && snapped.distance < snapData.distance) {
-                    const snappedInkPt = doc === inkView.rootDoc ? snapped.nearestPt : inkView.ComponentView?.ptFromScreen?.(testInkView?.ComponentView?.ptToScreen?.(snapped.nearestPt) ?? { X: 0, Y: 0 }); // convert from snapped ink coordinate system to dragged ink coordinate system by converting to/from screen space
+                    const snappedInkPt = doc === inkView.Document ? snapped.nearestPt : inkView.ComponentView?.ptFromScreen?.(testInkView?.ComponentView?.ptToScreen?.(snapped.nearestPt) ?? { X: 0, Y: 0 }); // convert from snapped ink coordinate system to dragged ink coordinate system by converting to/from screen space
 
                     if (snappedInkPt) {
                         snapData = { nearestPt: snappedInkPt, distance: snapped.distance };
@@ -397,7 +397,7 @@ export class InkStrokeProperties {
      */
     snapHandleTangent = (inkView: DocumentView, controlIndex: number, handleIndexA: number, handleIndexB: number) => {
         this.applyFunction(inkView, (view: DocumentView, ink: InkData) => {
-            const doc = view.rootDoc;
+            const doc = view.Document;
             const brokenIndices = Cast(doc.brokenInkIndices, listSpec('number'), []);
             const ind = brokenIndices.findIndex(value => value === controlIndex);
             if (ind !== -1) {
@@ -459,7 +459,7 @@ export class InkStrokeProperties {
     @action
     moveTangentHandle = (inkView: DocumentView, deltaX: number, deltaY: number, handleIndex: number, oppositeHandleIndex: number, controlIndex: number) =>
         this.applyFunction(inkView, (view: DocumentView, ink: InkData) => {
-            const doc = view.rootDoc;
+            const doc = view.Document;
             const closed = InkingStroke.IsClosed(ink);
             const oldHandlePoint = ink[handleIndex];
             const oppositeHandlePoint = ink[oppositeHandleIndex];
diff --git a/src/client/views/MarqueeAnnotator.tsx b/src/client/views/MarqueeAnnotator.tsx
index 8b8838464..b9b7e3f0b 100644
--- a/src/client/views/MarqueeAnnotator.tsx
+++ b/src/client/views/MarqueeAnnotator.tsx
@@ -61,7 +61,7 @@ export class MarqueeAnnotator extends React.Component<MarqueeAnnotatorProps> {
         const savedAnnoMap = savedAnnotations?.values() && Array.from(savedAnnotations?.values()).length ? savedAnnotations : this.props.savedAnnotations();
         if (savedAnnoMap.size === 0) return undefined;
         const savedAnnos = Array.from(savedAnnoMap.values())[0];
-        const doc = this.props.docView().rootDoc;
+        const doc = this.props.docView().Document;
         const scale = (this.props.annotationLayerScaling?.() || 1) * NumCast(doc._freeform_scale, 1);
         if (savedAnnos.length && (savedAnnos[0] as any).marqueeing) {
             const anno = savedAnnos[0];
@@ -213,7 +213,7 @@ export class MarqueeAnnotator extends React.Component<MarqueeAnnotatorProps> {
                       dragComplete: e => {
                           if (!e.aborted && e.linkDocument) {
                               Doc.GetProto(e.linkDocument).link_relationship = 'cropped image';
-                              Doc.GetProto(e.linkDocument).title = 'crop: ' + this.props.docView().rootDoc.title;
+                              Doc.GetProto(e.linkDocument).title = 'crop: ' + this.props.docView().Document.title;
                               Doc.GetProto(e.linkDocument).link_displayLine = false;
                           }
                       },
@@ -242,7 +242,7 @@ export class MarqueeAnnotator extends React.Component<MarqueeAnnotatorProps> {
             // configure and show the annotation/link menu if a the drag region is big enough
             // copy the temporary marquee to allow for multiple selections (not currently available though).
             const copy = document.createElement('div');
-            const scale = (this.props.scaling?.() || 1) * NumCast(this.props.docView().rootDoc._freeform_scale, 1);
+            const scale = (this.props.scaling?.() || 1) * NumCast(this.props.docView().Document._freeform_scale, 1);
             ['border', 'opacity', 'top', 'left', 'width', 'height'].forEach(prop => (copy.style[prop as any] = marqueeStyle[prop as any]));
             copy.className = 'marqueeAnnotator-annotationBox';
             copy.style.top = parseInt(marqueeStyle.top.toString().replace('px', '')) / scale + this.props.scrollTop + 'px';
diff --git a/src/client/views/PropertiesButtons.tsx b/src/client/views/PropertiesButtons.tsx
index 84b1bf038..7a8a0bfb9 100644
--- a/src/client/views/PropertiesButtons.tsx
+++ b/src/client/views/PropertiesButtons.tsx
@@ -40,7 +40,7 @@ export class PropertiesButtons extends React.Component<{}, {}> {
     @observable public static Instance: PropertiesButtons;
 
     @computed get selectedDoc() {
-        return SelectionManager.SelectedSchemaDoc() || SelectionManager.Views().lastElement()?.rootDoc;
+        return SelectionManager.SelectedSchemaDoc() || SelectionManager.Views().lastElement()?.Document;
     }
     @computed get selectedLayoutDoc() {
         return SelectionManager.SelectedSchemaDoc() || SelectionManager.Views().lastElement()?.layoutDoc;
@@ -65,7 +65,7 @@ export class PropertiesButtons extends React.Component<{}, {}> {
                 toggleType={ToggleType.BUTTON}
                 onClick={undoable(() => {
                     if (SelectionManager.Views().length > 1) {
-                        SelectionManager.Views().forEach(dv => (onClick ?? onPropToggle)(dv, dv.rootDoc, property));
+                        SelectionManager.Views().forEach(dv => (onClick ?? onPropToggle)(dv, dv.Document, property));
                     } else if (targetDoc) (onClick ?? onPropToggle)(undefined, targetDoc, property);
                 }, property)}
             />
@@ -83,7 +83,7 @@ export class PropertiesButtons extends React.Component<{}, {}> {
             on => 'window-restore',
             onClick => {
                 SelectionManager.Views().forEach(dv => {
-                    const containerDoc = dv.rootDoc;
+                    const containerDoc = dv.Document;
                     //containerDoc.followAllLinks =
                     // containerDoc.noShadow =
                     // containerDoc.layout_disableBrushing =
@@ -92,7 +92,7 @@ export class PropertiesButtons extends React.Component<{}, {}> {
                     containerDoc._isLightbox = !containerDoc._isLightbox;
                     //containerDoc._xPadding = containerDoc._yPadding = containerDoc._isLightbox ? 10 : undefined;
                     const containerContents = DocListCast(dv.dataDoc[dv.props.fieldKey ?? Doc.LayoutFieldKey(containerDoc)]);
-                    //dv.rootDoc.onClick = ScriptField.MakeScript('{self.data = undefined; documentView.select(false)}', { documentView: 'any' });
+                    //dv.Docuemnt.onClick = ScriptField.MakeScript('{self.data = undefined; documentView.select(false)}', { documentView: 'any' });
                     containerContents.forEach(doc => LinkManager.Links(doc).forEach(link => (link.link_displayLine = false)));
                 });
             }
@@ -106,7 +106,7 @@ export class PropertiesButtons extends React.Component<{}, {}> {
             on => 'Switch between title styles',
             on => (on ? <MdSubtitlesOff /> : <MdSubtitles />), // {currentIcon}, //(on ?  <MdSubtitles/> :)  , //,'text-width', on ?  <MdSubtitles/> : <MdSubtitlesOff/>,
             (dv, doc) => {
-                const tdoc = dv?.rootDoc || doc;
+                const tdoc = dv?.Document || doc;
                 const newtitle = !tdoc._layout_showTitle ? 'title' : tdoc._layout_showTitle === 'title' ? 'title:hover' : '';
                 tdoc._layout_showTitle = newtitle ? newtitle : undefined;
             }
@@ -201,7 +201,7 @@ export class PropertiesButtons extends React.Component<{}, {}> {
     //         on => 'window-restore',
     //         onClick => {
     //             SelectionManager.Views().forEach(dv => {
-    //                 const containerDoc = dv.rootDoc;
+    //                 const containerDoc = dv.Document;
     //                 //containerDoc.followAllLinks =
     //                 // containerDoc.noShadow =
     //                 // containerDoc.disableDocBrushing =
@@ -210,7 +210,7 @@ export class PropertiesButtons extends React.Component<{}, {}> {
     //                 containerDoc._isLightbox = !containerDoc._isLightbox;
     //                 //containerDoc._xPadding = containerDoc._yPadding = containerDoc._isLightbox ? 10 : undefined;
     //                 const containerContents = DocListCast(dv.dataDoc[dv.props.fieldKey ?? Doc.LayoutFieldKey(containerDoc)]);
-    //                 //dv.rootDoc.onClick = ScriptField.MakeScript('{self.data = undefined; documentView.select(false)}', { documentView: 'any' });
+    //                 //dv.Document.onClick = ScriptField.MakeScript('{self.data = undefined; documentView.select(false)}', { documentView: 'any' });
     //                 containerContents.forEach(doc => LinkManager.Links(doc).forEach(link => (link.layout_linkDisplay = false)));
     //             });
     //         }
@@ -236,7 +236,7 @@ export class PropertiesButtons extends React.Component<{}, {}> {
             '_layout_showCaption',
             on => `${on ? 'Hide' : 'Show'} caption footer`,
             on => (on ? <MdClosedCaptionDisabled /> : <MdClosedCaption />), //'closed-captioning',
-            (dv, doc) => ((dv?.rootDoc || doc)._layout_showCaption = (dv?.rootDoc || doc)._layout_showCaption === undefined ? 'caption' : undefined)
+            (dv, doc) => ((dv?.Document || doc)._layout_showCaption = (dv?.Document || doc)._layout_showCaption === undefined ? 'caption' : undefined)
         );
     }
 
@@ -247,7 +247,7 @@ export class PropertiesButtons extends React.Component<{}, {}> {
             '_chromeHidden',
             on => `${on ? 'Show' : 'Hide'} editing UI`,
             on => (on ? <TbEditCircle /> : <TbEditCircleOff />), // 'edit',
-            (dv, doc) => ((dv?.rootDoc || doc)._chromeHidden = !(dv?.rootDoc || doc)._chromeHidden)
+            (dv, doc) => ((dv?.Document || doc)._chromeHidden = !(dv?.Document || doc)._chromeHidden)
         );
     }
 
@@ -443,7 +443,7 @@ export class PropertiesButtons extends React.Component<{}, {}> {
 
     @undoBatch
     editOnClickScript = () => {
-        if (SelectionManager.Views().length) SelectionManager.Views().forEach(dv => DocUtils.makeCustomViewClicked(dv.rootDoc, undefined, 'onClick'));
+        if (SelectionManager.Views().length) SelectionManager.Views().forEach(dv => DocUtils.makeCustomViewClicked(dv.Document, undefined, 'onClick'));
         else this.selectedDoc && DocUtils.makeCustomViewClicked(this.selectedDoc, undefined, 'onClick');
     };
 
diff --git a/src/client/views/PropertiesDocContextSelector.tsx b/src/client/views/PropertiesDocContextSelector.tsx
index d157e7b1c..196250167 100644
--- a/src/client/views/PropertiesDocContextSelector.tsx
+++ b/src/client/views/PropertiesDocContextSelector.tsx
@@ -21,7 +21,7 @@ export class PropertiesDocContextSelector extends React.Component<PropertiesDocC
     @computed get _docs() {
         if (!this.props.DocView) return [];
         const target = this.props.DocView.props.Document;
-        const targetContext = this.props.DocView.props.docViewPath().lastElement()?.rootDoc;
+        const targetContext = this.props.DocView.props.docViewPath().lastElement()?.Document;
         const embeddings = DocListCast(target.proto_embeddings);
         const containerProtos = embeddings.filter(embedding => embedding.embedContainer && embedding.embedContainer instanceof Doc).reduce((set, embedding) => set.add(Cast(embedding.embedContainer, Doc, null)), new Set<Doc>());
         const containerSets = Array.from(containerProtos.keys()).map(container => DocListCast(container.proto_embeddings));
diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx
index 5c7af65ee..cde7eeb08 100644
--- a/src/client/views/PropertiesView.tsx
+++ b/src/client/views/PropertiesView.tsx
@@ -449,7 +449,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
      */
     @computed get sharingTable() {
         // all selected docs
-        const docs = SelectionManager.Views().length < 2 && this.selectedDoc ? [this.selectedDoc] : SelectionManager.Views().map(docView => docView.rootDoc);
+        const docs = SelectionManager.Views().length < 2 && this.selectedDoc ? [this.selectedDoc] : SelectionManager.Views().map(docView => docView.Document);
         const target = docs[0];
 
         const showAdmin = GetEffectiveAcl(target) == AclAdmin;
@@ -565,7 +565,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
 
     @computed get editableTitle() {
         const titles = new Set<string>();
-        SelectionManager.Views().forEach(dv => titles.add(StrCast(dv.rootDoc.title)));
+        SelectionManager.Views().forEach(dv => titles.add(StrCast(dv.Document.title)));
         const title = Array.from(titles.keys()).length > 1 ? '--multiple selected--' : StrCast(this.selectedDoc?.title);
         return (
             <div>
@@ -622,7 +622,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
     @action
     setTitle = (value: string | number) => {
         if (SelectionManager.Views().length > 1) {
-            SelectionManager.Views().map(dv => Doc.SetInPlace(dv.rootDoc, 'title', value, true));
+            SelectionManager.Views().map(dv => Doc.SetInPlace(dv.Document, 'title', value, true));
         } else if (this.dataDoc) {
             if (this.selectedDoc) Doc.SetInPlace(this.selectedDoc, 'title', value, true);
             else KeyValueBox.SetField(this.dataDoc, 'title', value as string, true);
@@ -1172,7 +1172,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
         return (
             <PropertiesSection title="Filters" isOpen={this.openFilters} setIsOpen={bool => (this.openFilters = bool)} onDoubleClick={() => this.CloseAll()}>
                 <div className="propertiesView-content filters" style={{ position: 'relative', height: 'auto' }}>
-                    <FilterPanel rootDoc={this.selectedDoc ?? Doc.ActiveDashboard!} />
+                    <FilterPanel Document={this.selectedDoc ?? Doc.ActiveDashboard!} />
                 </div>
             </PropertiesSection>
         );
diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx
index 4a8a62277..fa2768d79 100644
--- a/src/client/views/StyleProvider.tsx
+++ b/src/client/views/StyleProvider.tsx
@@ -249,7 +249,7 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewProps
                 default:
                     return doc.z
                         ? `#9c9396  ${StrCast(doc?.layout_boxShadow, '10px 10px 0.9vw')}` // if it's a floating doc, give it a big shadow
-                        : props?.docViewPath().lastElement()?.rootDoc._freeform_useClusters
+                        : props?.docViewPath().lastElement()?.Document._freeform_useClusters
                         ? `${backgroundCol()} ${StrCast(doc.layout_boxShadow, `0vw 0vw ${(lockedPosition() ? 100 : 50) / (docProps?.NativeDimScaling?.() || 1)}px`)}` // if it's just in a cluster, make the shadown roughly match the cluster border extent
                         : NumCast(doc.group, -1) !== -1
                         ? `gray ${StrCast(doc.layout_boxShadow, `0vw 0vw ${(lockedPosition() ? 100 : 50) / (docProps?.NativeDimScaling?.() || 1)}px`)}` // if it's just in a cluster, make the shadown roughly match the cluster border extent
@@ -270,7 +270,7 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewProps
             return undefined; // fixes problem with tree view elements getting pointer events when the tree view is not active
         case StyleProp.Decorations:
             const lock = () => {
-                if (props?.docViewPath().lastElement()?.rootDoc?._type_collection === CollectionViewType.Freeform) {
+                if (props?.docViewPath().lastElement()?.Document?._type_collection === CollectionViewType.Freeform) {
                     return doc?.pointerEvents !== 'none' ? null : (
                         <div className="styleProvider-lock" onClick={() => toggleLockedPosition(doc)}>
                             <FontAwesomeIcon icon='lock' size="lg" />
@@ -315,9 +315,9 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewProps
                             color={SettingsManager.userColor}
                             background={showFilterIcon}
                             items={[ ...(dashView ? [dashView]: []), ...(props?.docViewPath?.()??[]), ...(props?.DocumentView?[props?.DocumentView?.()]:[])]
-                                    .filter(dv => StrListCast(dv.rootDoc.childFilters).length || StrListCast(dv.rootDoc.childRangeFilters).length)
+                                    .filter(dv => StrListCast(dv.Document.childFilters).length || StrListCast(dv.Document.childRangeFilters).length)
                                     .map(dv => ({
-                                text: StrCast(dv.rootDoc.title),
+                                text: StrCast(dv.Document.title),
                                 val: dv as any,
                                 style: {color:SettingsManager.userColor, background:SettingsManager.userBackgroundColor},
                             } as IListItemProps)) }
diff --git a/src/client/views/collections/CollectionNoteTakingView.tsx b/src/client/views/collections/CollectionNoteTakingView.tsx
index edf9f1f2c..01915f2f7 100644
--- a/src/client/views/collections/CollectionNoteTakingView.tsx
+++ b/src/client/views/collections/CollectionNoteTakingView.tsx
@@ -407,9 +407,9 @@ export class CollectionNoteTakingView extends CollectionSubView() {
     @action
     onKeyDown = (e: React.KeyboardEvent, fieldProps: FieldViewProps) => {
         const docView = fieldProps.DocumentView?.();
-        if (docView && (e.ctrlKey || docView.rootDoc._createDocOnCR) && ['Enter'].includes(e.key)) {
+        if (docView && (e.ctrlKey || docView.Document._createDocOnCR) && ['Enter'].includes(e.key)) {
             e.stopPropagation?.();
-            const newDoc = Doc.MakeCopy(docView.rootDoc, true);
+            const newDoc = Doc.MakeCopy(docView.Document, true);
             Doc.GetProto(newDoc).text = undefined;
             FormattedTextBox.SelectOnLoad = newDoc[Id];
             return this.addDocument?.(newDoc);
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index 582baa7b5..c1333c90e 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -285,11 +285,11 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
             e.stopPropagation?.();
             const below = !e.altKey && e.key !== 'Tab';
             const layout_fieldKey = StrCast(docView.LayoutFieldKey);
-            const newDoc = Doc.MakeCopy(docView.rootDoc, true);
-            const dataField = docView.rootDoc[Doc.LayoutFieldKey(newDoc)];
+            const newDoc = Doc.MakeCopy(docView.Document, true);
+            const dataField = docView.Document[Doc.LayoutFieldKey(newDoc)];
             newDoc[DocData][Doc.LayoutFieldKey(newDoc)] = dataField === undefined || Cast(dataField, listSpec(Doc), null)?.length !== undefined ? new List<Doc>([]) : undefined;
-            if (layout_fieldKey !== 'layout' && docView.rootDoc[layout_fieldKey] instanceof Doc) {
-                newDoc[layout_fieldKey] = docView.rootDoc[layout_fieldKey];
+            if (layout_fieldKey !== 'layout' && docView.Document[layout_fieldKey] instanceof Doc) {
+                newDoc[layout_fieldKey] = docView.Document[layout_fieldKey];
             }
             Doc.GetProto(newDoc).text = undefined;
             FormattedTextBox.SelectOnLoad = newDoc[Id];
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index 9dcd09b17..43653ed75 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -104,8 +104,8 @@ export function CollectionSubView<X>(moreProps?: X) {
                 // Finally, if it's not a doc or a list and the document is a template, we try to render the root doc.
                 // For example, if an image doc is rendered with a slide template, the template will try to render the data field as a collection.
                 // Since the data field is actually an image, we set the list of documents to the singleton of root document's proto which will be an image.
-                const rootDoc = Cast(this.props.Document.rootDocument, Doc, null);
-                rawdocs = rootDoc && !this.props.isAnnotationOverlay ? [Doc.GetProto(rootDoc)] : [];
+                const rootDocument = Cast(this.props.Document.rootDocument, Doc, null);
+                rawdocs = rootDocument && !this.props.isAnnotationOverlay ? [Doc.GetProto(rootDocument)] : [];
             }
 
             const childDocs = rawdocs.filter(d => !(d instanceof Promise) && GetEffectiveAcl(Doc.GetProto(d)) !== AclPrivate && (this.props.ignoreUnrendered || !d.layout_unrendered)).map(d => d as Doc);
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index dc2ee63f5..898b453f4 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -257,7 +257,7 @@ export class CollectionView extends ViewBoxAnnotatableComponent<ViewBoxAnnotatab
             <div
                 className="collectionView"
                 onContextMenu={this.onContextMenu}
-                style={{ pointerEvents: this.props.DocumentView?.()?.props.docViewPath().lastElement()?.rootDoc?._type_collection === CollectionViewType.Freeform && this.layoutDoc._lockedPosition ? 'none' : undefined }}>
+                style={{ pointerEvents: this.props.DocumentView?.()?.props.docViewPath().lastElement()?.Document?._type_collection === CollectionViewType.Freeform && this.layoutDoc._lockedPosition ? 'none' : undefined }}>
                 {this.renderSubView(this.collectionViewType, props)}
             </div>
         );
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index 6f8476f10..a5cf89217 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -378,9 +378,9 @@ export class TabDocView extends React.Component<TabDocViewProps> {
             case undefined:
             case OpenWhere.lightbox:   if (this.layoutDoc?._isLightbox) {
                                             const lightboxView = !doc.annotationOn && DocCast(doc.embedContainer) ? DocumentManager.Instance.getFirstDocumentView(DocCast(doc.embedContainer)) : undefined;
-                                            const data = lightboxView?.dataDoc[Doc.LayoutFieldKey(lightboxView.rootDoc)];
+                                            const data = lightboxView?.dataDoc[Doc.LayoutFieldKey(lightboxView.Document)];
                                             if (lightboxView && (!data || data instanceof List)) {
-                                                lightboxView.layoutDoc[Doc.LayoutFieldKey(lightboxView.rootDoc)] = new List<Doc>([doc]);
+                                                lightboxView.layoutDoc[Doc.LayoutFieldKey(lightboxView.Document)] = new List<Doc>([doc]);
                                                 return true;
                                             }
                                        }
diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx
index ee5f9fd95..6cd111ac4 100644
--- a/src/client/views/collections/TreeView.tsx
+++ b/src/client/views/collections/TreeView.tsx
@@ -215,7 +215,7 @@ export class TreeView extends React.Component<TreeViewProps> {
             this.treeViewOpen = !this.treeViewOpen;
         } else {
             // choose an appropriate embedding or make one. --- choose the first embedding that (1) user owns,  (2) has no context field ... otherwise make a new embedding
-            const bestEmbedding = docView.rootDoc.author === Doc.CurrentUserEmail && !Doc.IsDataProto(docView.props.Document) ? docView.rootDoc : Doc.BestEmbedding(docView.rootDoc);
+            const bestEmbedding = docView.Document.author === Doc.CurrentUserEmail && !Doc.IsDataProto(docView.props.Document) ? docView.Document : Doc.BestEmbedding(docView.Document);
             this.props.addDocTab(bestEmbedding, OpenWhere.lightbox);
         }
     };
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
index aca6df3c9..5e0cf1d23 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
@@ -37,11 +37,11 @@ export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFo
         this._anchorDisposer = reaction(
             () => [
                 this.props.A.props.ScreenToLocalTransform(),
-                Cast(Cast(Cast(this.props.A.rootDoc, Doc, null)?.link_anchor_1, Doc, null)?.annotationOn, Doc, null)?.layout_scrollTop,
-                Cast(Cast(Cast(this.props.A.rootDoc, Doc, null)?.link_anchor_1, Doc, null)?.annotationOn, Doc, null)?.[DocCss],
+                Cast(Cast(Cast(this.props.A.Document, Doc, null)?.link_anchor_1, Doc, null)?.annotationOn, Doc, null)?.layout_scrollTop,
+                Cast(Cast(Cast(this.props.A.Document, Doc, null)?.link_anchor_1, Doc, null)?.annotationOn, Doc, null)?.[DocCss],
                 this.props.B.props.ScreenToLocalTransform(),
-                Cast(Cast(Cast(this.props.A.rootDoc, Doc, null)?.link_anchor_2, Doc, null)?.annotationOn, Doc, null)?.layout_scrollTop,
-                Cast(Cast(Cast(this.props.A.rootDoc, Doc, null)?.link_anchor_2, Doc, null)?.annotationOn, Doc, null)?.[DocCss],
+                Cast(Cast(Cast(this.props.A.Document, Doc, null)?.link_anchor_2, Doc, null)?.annotationOn, Doc, null)?.layout_scrollTop,
+                Cast(Cast(Cast(this.props.A.Document, Doc, null)?.link_anchor_2, Doc, null)?.annotationOn, Doc, null)?.[DocCss],
             ],
             action(() => {
                 this._start = Date.now();
@@ -223,8 +223,8 @@ export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFo
         const pt2normlen = Math.sqrt(pt2norm[0] * pt2norm[0] + pt2norm[1] * pt2norm[1]) || 1;
         const pt1normalized = [pt1norm[0] / pt1normlen, pt1norm[1] / pt1normlen];
         const pt2normalized = [pt2norm[0] / pt2normlen, pt2norm[1] / pt2normlen];
-        const aActive = A.isSelected() || A.rootDoc[Brushed];
-        const bActive = B.isSelected() || B.rootDoc[Brushed];
+        const aActive = A.isSelected() || A.Document[Brushed];
+        const bActive = B.isSelected() || B.Document[Brushed];
 
         const textX = (Math.min(pt1[0], pt2[0]) + Math.max(pt1[0], pt2[0])) / 2 + NumCast(LinkDocs[0].link_relationship_OffsetX);
         const textY = (pt1[1] + pt2[1]) / 2 + NumCast(LinkDocs[0].link_relationship_OffsetY);
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 307aa8882..fb29fb0d3 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -1790,7 +1790,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
                 brushedView={this.brushedView}
                 isAnnotationOverlay={this.isAnnotationOverlay}
                 transform={this.PanZoomCenterXf}
-                transition={this._panZoomTransition ? `transform ${this._panZoomTransition}ms` : Cast(this.layoutDoc._viewTransition, 'string', Cast(this.props.DocumentView?.()?.rootDoc._viewTransition, 'string', null))}
+                transition={this._panZoomTransition ? `transform ${this._panZoomTransition}ms` : Cast(this.layoutDoc._viewTransition, 'string', Cast(this.props.DocumentView?.()?.Document._viewTransition, 'string', null))}
                 viewDefDivClick={this.props.viewDefDivClick}>
                 {this.underlayViews}
                 {this.contentViews}
@@ -1931,7 +1931,7 @@ export function CollectionBrowseClick(dv: DocumentView, clientX: number, clientY
     const browseTransitionTime = 500;
     SelectionManager.DeselectAll();
     dv &&
-        DocumentManager.Instance.showDocument(dv.rootDoc, { zoomScale: 0.8, willZoomCentered: true }, (focused: boolean) => {
+        DocumentManager.Instance.showDocument(dv.Document, { zoomScale: 0.8, willZoomCentered: true }, (focused: boolean) => {
             if (!focused) {
                 const selfFfview = !dv.Document.isGroup && dv.ComponentView instanceof CollectionFreeFormView ? dv.ComponentView : undefined;
                 let containers = dv.props.docViewPath();
@@ -1960,19 +1960,19 @@ ScriptingGlobals.add(function curKeyFrame(readOnly: boolean) {
 });
 ScriptingGlobals.add(function pinWithView(pinContent: boolean) {
     SelectionManager.Views().forEach(view =>
-        view.props.pinToPres(view.rootDoc, {
-            currentFrame: Cast(view.rootDoc.currentFrame, 'number', null),
+        view.props.pinToPres(view.Document, {
+            currentFrame: Cast(view.Document.currentFrame, 'number', null),
             pinData: {
                 poslayoutview: pinContent,
                 dataview: pinContent,
             },
-            pinViewport: MarqueeView.CurViewBounds(view.rootDoc, view.props.PanelWidth(), view.props.PanelHeight()),
+            pinViewport: MarqueeView.CurViewBounds(view.Document, view.props.PanelWidth(), view.props.PanelHeight()),
         })
     );
 });
 ScriptingGlobals.add(function bringToFront() {
-    SelectionManager.Views().forEach(view => view.CollectionFreeFormView?.bringToFront(view.rootDoc));
+    SelectionManager.Views().forEach(view => view.CollectionFreeFormView?.bringToFront(view.Document));
 });
 ScriptingGlobals.add(function sendToBack(doc: Doc) {
-    SelectionManager.Views().forEach(view => view.CollectionFreeFormView?.bringToFront(view.rootDoc, true));
+    SelectionManager.Views().forEach(view => view.CollectionFreeFormView?.bringToFront(view.Document, true));
 });
diff --git a/src/client/views/collections/collectionLinear/CollectionLinearView.tsx b/src/client/views/collections/collectionLinear/CollectionLinearView.tsx
index 96eabd88c..a367e3e73 100644
--- a/src/client/views/collections/collectionLinear/CollectionLinearView.tsx
+++ b/src/client/views/collections/collectionLinear/CollectionLinearView.tsx
@@ -126,8 +126,8 @@ export class CollectionLinearView extends CollectionSubView() {
                     Currently playing:
                     {CollectionStackedTimeline.CurrentlyPlaying.map((clip, i) => (
                         <>
-                            <span className="audio-title" onPointerDown={() => DocumentManager.Instance.showDocument(clip.rootDoc, { willZoomCentered: true })}>
-                                {clip.rootDoc.title + (i === CollectionStackedTimeline.CurrentlyPlaying.length - 1 ? '  ' : ',')}
+                            <span className="audio-title" onPointerDown={() => DocumentManager.Instance.showDocument(clip.Document, { willZoomCentered: true })}>
+                                {clip.Document.title + (i === CollectionStackedTimeline.CurrentlyPlaying.length - 1 ? '  ' : ',')}
                             </span>
                             <FontAwesomeIcon icon={!clip.ComponentView?.IsPlaying?.() ? 'play' : 'pause'} size="lg" onPointerDown={() => clip.ComponentView?.TogglePause?.()} />{' '}
                             <FontAwesomeIcon icon="times" size="lg" onPointerDown={() => clip.ComponentView?.Pause?.()} />{' '}
diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
index 22b80e21d..0b292a445 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
@@ -416,8 +416,8 @@ export class CollectionSchemaView extends CollectionSubView() {
     @action
     clearSelection = () => SelectionManager.DeselectAll();
 
-    selectRows = (rootDoc: Doc, lastSelected: Doc) => {
-        const index = this.rowIndex(rootDoc);
+    selectRows = (doc: Doc, lastSelected: Doc) => {
+        const index = this.rowIndex(doc);
         const lastSelectedRow = this.rowIndex(lastSelected);
         const startRow = Math.min(lastSelectedRow, index);
         const endRow = Math.max(lastSelectedRow, index);
diff --git a/src/client/views/global/globalScripts.ts b/src/client/views/global/globalScripts.ts
index f2ab4ff4b..0ad76db35 100644
--- a/src/client/views/global/globalScripts.ts
+++ b/src/client/views/global/globalScripts.ts
@@ -41,22 +41,22 @@ ScriptingGlobals.add(function setBackgroundColor(color?: string, checkResult?: b
     } else if (selectedViews.length) {
         if (checkResult) {
             const selView = selectedViews.lastElement();
-            const fieldKey = selView.rootDoc.type === DocumentType.INK ? 'fillColor' : 'backgroundColor';
-            const layoutFrameNumber = Cast(selView.props.docViewPath().lastElement()?.rootDoc?._currentFrame, 'number'); // frame number that container is at which determines layout frame values
-            const contentFrameNumber = Cast(selView.rootDoc?._currentFrame, 'number', layoutFrameNumber ?? null); // frame number that content is at which determines what content is displayed
-            return CollectionFreeFormDocumentView.getStringValues(selView?.rootDoc, contentFrameNumber)[fieldKey] ?? 'transparent';
+            const fieldKey = selView.Document.type === DocumentType.INK ? 'fillColor' : 'backgroundColor';
+            const layoutFrameNumber = Cast(selView.props.docViewPath().lastElement()?.Document?._currentFrame, 'number'); // frame number that container is at which determines layout frame values
+            const contentFrameNumber = Cast(selView.Document?._currentFrame, 'number', layoutFrameNumber ?? null); // frame number that content is at which determines what content is displayed
+            return CollectionFreeFormDocumentView.getStringValues(selView?.Document, contentFrameNumber)[fieldKey] ?? 'transparent';
         }
         selectedViews.some(dv => dv.ComponentView instanceof InkingStroke) && SetActiveFillColor(color ?? 'transparent');
         selectedViews.forEach(dv => {
-            const fieldKey = dv.rootDoc.type === DocumentType.INK ? 'fillColor' : 'backgroundColor';
-            const layoutFrameNumber = Cast(dv.props.docViewPath().lastElement()?.rootDoc?._currentFrame, 'number'); // frame number that container is at which determines layout frame values
-            const contentFrameNumber = Cast(dv.rootDoc?._currentFrame, 'number', layoutFrameNumber ?? null); // frame number that content is at which determines what content is displayed
+            const fieldKey = dv.Document.type === DocumentType.INK ? 'fillColor' : 'backgroundColor';
+            const layoutFrameNumber = Cast(dv.props.docViewPath().lastElement()?.Document?._currentFrame, 'number'); // frame number that container is at which determines layout frame values
+            const contentFrameNumber = Cast(dv.Document?._currentFrame, 'number', layoutFrameNumber ?? null); // frame number that content is at which determines what content is displayed
             if (contentFrameNumber !== undefined) {
                 const obj: { [key: string]: Opt<string> } = {};
                 obj[fieldKey] = color;
-                CollectionFreeFormDocumentView.setStringValues(contentFrameNumber, dv.rootDoc, obj);
+                CollectionFreeFormDocumentView.setStringValues(contentFrameNumber, dv.Document, obj);
             } else {
-                dv.rootDoc['_' + fieldKey] = color;
+                dv.Document['_' + fieldKey] = color;
             }
         });
     } else {
@@ -377,12 +377,12 @@ ScriptingGlobals.add(function setInkProperty(option: 'inkMask' | 'fillColor' | '
  **/
 ScriptingGlobals.add(function webSetURL(url: string, checkResult?: boolean) {
     const selected = SelectionManager.Views().lastElement();
-    if (selected?.rootDoc.type === DocumentType.WEB) {
+    if (selected?.Document.type === DocumentType.WEB) {
         if (checkResult) {
-            return StrCast(selected.rootDoc.data, Cast(selected.rootDoc.data, WebField, null)?.url?.href);
+            return StrCast(selected.Document.data, Cast(selected.Document.data, WebField, null)?.url?.href);
         }
         selected.ComponentView?.setData?.(url);
-        //selected.rootDoc.data = new WebField(url);
+        //selected.Document.data = new WebField(url);
     }
 });
 ScriptingGlobals.add(function webForward(checkResult?: boolean) {
diff --git a/src/client/views/linking/LinkMenu.tsx b/src/client/views/linking/LinkMenu.tsx
index 9dc133e28..3082c632d 100644
--- a/src/client/views/linking/LinkMenu.tsx
+++ b/src/client/views/linking/LinkMenu.tsx
@@ -54,7 +54,7 @@ export class LinkMenu extends React.Component<Props> {
     };
 
     render() {
-        const sourceDoc = this.props.docView.rootDoc;
+        const sourceDoc = this.props.docView.Document;
         const sourceAnchor = this.props.docView.anchorViewDoc ?? sourceDoc;
         const style = this.props.style ?? (dv => ({ left: dv?.left || 0, top: this.props.docView.topMost ? undefined : (dv?.bottom || 0) + 15, bottom: this.props.docView.topMost ? 20 : undefined, maxWidth: 200 }))(this.props.docView.getBounds());
 
diff --git a/src/client/views/linking/LinkMenuGroup.tsx b/src/client/views/linking/LinkMenuGroup.tsx
index c1a5a634c..5453ed07b 100644
--- a/src/client/views/linking/LinkMenuGroup.tsx
+++ b/src/client/views/linking/LinkMenuGroup.tsx
@@ -46,14 +46,14 @@ export class LinkMenuGroup extends React.Component<LinkMenuGroupProps> {
         const groupItems = Array.from(set.keys()).map(linkDoc => {
             const sourceDoc =
                 this.props.docView.anchorViewDoc ??
-                (this.props.docView.rootDoc.type === DocumentType.LINK //
+                (this.props.docView.Document.type === DocumentType.LINK //
                     ? this.props.docView.props.LayoutTemplateString?.includes('link_anchor_1')
                         ? DocCast(linkDoc.link_anchor_1)
                         : DocCast(linkDoc.link_anchor_2)
                     : this.props.sourceDoc);
             const destDoc = !sourceDoc
                 ? undefined
-                : this.props.docView.rootDoc.type === DocumentType.LINK
+                : this.props.docView.Document.type === DocumentType.LINK
                 ? this.props.docView.props.LayoutTemplateString?.includes('link_anchor_1')
                     ? DocCast(linkDoc.link_anchor_2)
                     : DocCast(linkDoc.link_anchor_1)
diff --git a/src/client/views/linking/LinkMenuItem.tsx b/src/client/views/linking/LinkMenuItem.tsx
index bf2a4e1a9..611771fff 100644
--- a/src/client/views/linking/LinkMenuItem.tsx
+++ b/src/client/views/linking/LinkMenuItem.tsx
@@ -82,7 +82,7 @@ export class LinkMenuItem extends React.Component<LinkMenuItemProps> {
             },
             emptyFunction,
             action(() => {
-                const trail = DocCast(this.props.docView.rootDoc.presentationTrail);
+                const trail = DocCast(this.props.docView.Document.presentationTrail);
                 if (trail) {
                     Doc.ActivePresentation = trail;
                     DocumentViewInternal.addDocTabFunc(trail, OpenWhere.replaceRight);
diff --git a/src/client/views/newlightbox/components/Recommendation/Recommendation.tsx b/src/client/views/newlightbox/components/Recommendation/Recommendation.tsx
index 96846673b..a085e4a66 100644
--- a/src/client/views/newlightbox/components/Recommendation/Recommendation.tsx
+++ b/src/client/views/newlightbox/components/Recommendation/Recommendation.tsx
@@ -19,7 +19,7 @@ export const Recommendation = (props: IRecommendation) => {
                 if (source == 'Dash' && docId) {
                     const docView = DocumentManager.Instance.getDocumentViewsById(docId).lastElement();
                     if (docView) {
-                        doc = docView.rootDoc;
+                        doc = docView.Document;
                     }
                 } else if (data) {
                     switch (type) {
diff --git a/src/client/views/nodes/ColorBox.tsx b/src/client/views/nodes/ColorBox.tsx
index 4c7ea4002..2a20d935b 100644
--- a/src/client/views/nodes/ColorBox.tsx
+++ b/src/client/views/nodes/ColorBox.tsx
@@ -60,7 +60,7 @@ export class ColorBox extends ViewBoxBaseComponent<FieldViewProps>() {
                 style={{ transform: `scale(${scaling})`, width: `${100 * scaling}%`, height: `${100 * scaling}%` }}>
                 <SketchPicker
                     onChange={c => Doc.ActiveTool === InkTool.None && ColorBox.switchColor(c)}
-                    color={StrCast(SelectionManager.Views()?.[0]?.rootDoc?._backgroundColor, ActiveInkColor())}
+                    color={StrCast(SelectionManager.Views()?.[0]?.Document?._backgroundColor, ActiveInkColor())}
                     presetColors={['#D0021B', '#F5A623', '#F8E71C', '#8B572A', '#7ED321', '#417505', '#9013FE', '#4A90E2', '#50E3C2', '#B8E986', '#000000', '#4A4A4A', '#9B9B9B', '#FFFFFF', '#f1efeb', 'transparent']}
                 />
 
@@ -74,8 +74,8 @@ export class ColorBox extends ViewBoxBaseComponent<FieldViewProps>() {
                         onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
                             SetActiveInkWidth(e.target.value);
                             SelectionManager.Views()
-                                .filter(i => StrCast(i.rootDoc.type) === DocumentType.INK)
-                                .map(i => (i.rootDoc.stroke_width = Number(e.target.value)));
+                                .filter(i => StrCast(i.Document.type) === DocumentType.INK)
+                                .map(i => (i.Document.stroke_width = Number(e.target.value)));
                         }}
                     />
                 </div>
diff --git a/src/client/views/nodes/DataVizBox/DataVizBox.tsx b/src/client/views/nodes/DataVizBox/DataVizBox.tsx
index cc2c44435..a626772e4 100644
--- a/src/client/views/nodes/DataVizBox/DataVizBox.tsx
+++ b/src/client/views/nodes/DataVizBox/DataVizBox.tsx
@@ -112,7 +112,7 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
     @computed get renderVizView() {
         const scale = this.props.NativeDimScaling?.() || 1;
         const sharedProps = {
-            rootDoc: this.Document,
+            Document: this.Document,
             layoutDoc: this.layoutDoc,
             records: this.records,
             axes: this.axes,
diff --git a/src/client/views/nodes/DataVizBox/components/Histogram.tsx b/src/client/views/nodes/DataVizBox/components/Histogram.tsx
index e67e2bf31..a1bd316f0 100644
--- a/src/client/views/nodes/DataVizBox/components/Histogram.tsx
+++ b/src/client/views/nodes/DataVizBox/components/Histogram.tsx
@@ -10,14 +10,13 @@ import { List } from '../../../../../fields/List';
 import { listSpec } from '../../../../../fields/Schema';
 import { Cast, DocCast, StrCast } from '../../../../../fields/Types';
 import { Docs } from '../../../../documents/Documents';
-import { LinkManager } from '../../../../util/LinkManager';
 import { undoable } from '../../../../util/UndoManager';
 import { PinProps, PresBox } from '../../trails';
 import { scaleCreatorNumerical, yAxisCreator } from '../utils/D3Utils';
 import './Chart.scss';
 
 export interface HistogramProps {
-    rootDoc: Doc;
+    Document: Doc;
     layoutDoc: Doc;
     axes: string[];
     records: { [key: string]: any }[];
@@ -83,9 +82,9 @@ export class Histogram extends React.Component<HistogramProps> {
     }
 
     @computed get parentViz() {
-        return DocCast(this.props.rootDoc.dataViz_parentViz);
-        // return LinkManager.Instance.getAllRelatedLinks(this.props.rootDoc) // out of all links
-        //     .filter(link => link.link_anchor_1 == this.props.rootDoc.dataViz_parentViz) // get links where this chart doc is the target of the link
+        return DocCast(this.props.Document.dataViz_parentViz);
+        // return LinkManager.Instance.getAllRelatedLinks(this.props.Document) // out of all links
+        //     .filter(link => link.link_anchor_1 == this.props.Document.dataViz_parentViz) // get links where this chart doc is the target of the link
         //     .map(link => DocCast(link.link_anchor_1)); // then return the source of the link
     }
 
@@ -115,7 +114,7 @@ export class Histogram extends React.Component<HistogramProps> {
         const anchor = Docs.Create.ConfigDocument({
             title: 'histogram doc selection' + this._currSelected,
         });
-        PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: pinProps?.pinData }, this.props.rootDoc);
+        PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: pinProps?.pinData }, this.props.Document);
         return anchor;
     };
 
diff --git a/src/client/views/nodes/DataVizBox/components/LineChart.tsx b/src/client/views/nodes/DataVizBox/components/LineChart.tsx
index ad34a0c99..7e0391879 100644
--- a/src/client/views/nodes/DataVizBox/components/LineChart.tsx
+++ b/src/client/views/nodes/DataVizBox/components/LineChart.tsx
@@ -64,9 +64,9 @@ export class LineChart extends React.Component<LineChartProps> {
     }
     @computed get parentViz() {
         return DocCast(this.props.Document.dataViz_parentViz);
-        // return LinkManager.Instance.getAllRelatedLinks(this.props.rootDoc) // out of all links
+        // return LinkManager.Instance.getAllRelatedLinks(this.props.Document) // out of all links
         //     .filter(link => {
-        //         return link.link_anchor_1 == this.props.rootDoc.dataViz_parentViz;
+        //         return link.link_anchor_1 == this.props.Document.dataViz_parentViz;
         //     }) // get links where this chart doc is the target of the link
         //     .map(link => DocCast(link.link_anchor_1)); // then return the source of the link
     }
diff --git a/src/client/views/nodes/DataVizBox/components/PieChart.tsx b/src/client/views/nodes/DataVizBox/components/PieChart.tsx
index 7303eb184..4dbd67485 100644
--- a/src/client/views/nodes/DataVizBox/components/PieChart.tsx
+++ b/src/client/views/nodes/DataVizBox/components/PieChart.tsx
@@ -15,7 +15,7 @@ import './Chart.scss';
 import { Checkbox } from '@material-ui/core';
 
 export interface PieChartProps {
-    rootDoc: Doc;
+    Document: Doc;
     layoutDoc: Doc;
     axes: string[];
     records: { [key: string]: any }[];
@@ -76,9 +76,9 @@ export class PieChart extends React.Component<PieChartProps> {
     }
 
     @computed get parentViz() {
-        return DocCast(this.props.rootDoc.dataViz_parentViz);
-        // return LinkManager.Instance.getAllRelatedLinks(this.props.rootDoc) // out of all links
-        //     .filter(link => link.link_anchor_1 == this.props.rootDoc.dataViz_parentViz) // get links where this chart doc is the target of the link
+        return DocCast(this.props.Document.dataViz_parentViz);
+        // return LinkManager.Instance.getAllRelatedLinks(this.props.Document) // out of all links
+        //     .filter(link => link.link_anchor_1 == this.props.Document.dataViz_parentViz) // get links where this chart doc is the target of the link
         //     .map(link => DocCast(link.link_anchor_1)); // then return the source of the link
     }
 
@@ -101,7 +101,7 @@ export class PieChart extends React.Component<PieChartProps> {
             //
             title: 'piechart doc selection' + this._currSelected,
         });
-        PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: pinProps?.pinData }, this.props.rootDoc);
+        PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: pinProps?.pinData }, this.props.Document);
         return anchor;
     };
 
diff --git a/src/client/views/nodes/DataVizBox/components/TableBox.tsx b/src/client/views/nodes/DataVizBox/components/TableBox.tsx
index 147dfb182..9ac06cf3c 100644
--- a/src/client/views/nodes/DataVizBox/components/TableBox.tsx
+++ b/src/client/views/nodes/DataVizBox/components/TableBox.tsx
@@ -14,7 +14,7 @@ import { DATA_VIZ_TABLE_ROW_HEIGHT } from '../../../global/globalCssVariables.sc
 import './Chart.scss';
 
 interface TableBoxProps {
-    rootDoc: Doc;
+    Document: Doc;
     layoutDoc: Doc;
     records: { [key: string]: any }[];
     selectAxes: (axes: string[]) => void;
@@ -57,9 +57,9 @@ export class TableBox extends React.Component<TableBoxProps> {
     }
 
     @computed get parentViz() {
-        return DocCast(this.props.rootDoc.dataViz_parentViz);
-        // return LinkManager.Instance.getAllRelatedLinks(this.props.rootDoc) // out of all links
-        //     .filter(link => link.link_anchor_1 == this.props.rootDoc.dataViz_parentViz) // get links where this chart doc is the target of the link
+        return DocCast(this.props.Document.dataViz_parentViz);
+        // return LinkManager.Instance.getAllRelatedLinks(this.props.Document) // out of all links
+        //     .filter(link => link.link_anchor_1 == this.props.Document.dataViz_parentViz) // get links where this chart doc is the target of the link
         //     .map(link => DocCast(link.link_anchor_1)); // then return the source of the link
     }
 
@@ -119,12 +119,12 @@ export class TableBox extends React.Component<TableBoxProps> {
             e,
             e => {
                 // dragging off a column to create a brushed DataVizBox
-                const sourceAnchorCreator = () => this.props.docView?.()!.rootDoc!;
+                const sourceAnchorCreator = () => this.props.docView?.()!.Document!;
                 const targetCreator = (annotationOn: Doc | undefined) => {
-                    const embedding = Doc.MakeEmbedding(this.props.docView?.()!.rootDoc!);
+                    const embedding = Doc.MakeEmbedding(this.props.docView?.()!.Document!);
                     embedding._dataViz = DataVizView.TABLE;
                     embedding._dataViz_axes = new List<string>([col, col]);
-                    embedding._dataViz_parentViz = this.props.rootDoc;
+                    embedding._dataViz_parentViz = this.props.Document;
                     embedding.annotationOn = annotationOn;
                     embedding.histogramBarColors = Field.Copy(this.props.layoutDoc.histogramBarColors);
                     embedding.defaultHistogramColor = this.props.layoutDoc.defaultHistogramColor;
@@ -138,7 +138,7 @@ export class TableBox extends React.Component<TableBoxProps> {
                                 e.linkDocument.link_displayLine = true;
                                 e.linkDocument.link_matchEmbeddings = true;
                                 e.linkDocument.link_displayArrow = true;
-                                // e.annoDragData.linkSourceDoc.followLinkToggle = e.annoDragData.dropDocument.annotationOn === this.props.rootDoc;
+                                // e.annoDragData.linkSourceDoc.followLinkToggle = e.annoDragData.dropDocument.annotationOn === this.props.Document;
                                 // e.annoDragData.linkSourceDoc.followLinkZoom = false;
                             }
                         },
diff --git a/src/client/views/nodes/DocumentIcon.tsx b/src/client/views/nodes/DocumentIcon.tsx
index bccbd66e8..49592d993 100644
--- a/src/client/views/nodes/DocumentIcon.tsx
+++ b/src/client/views/nodes/DocumentIcon.tsx
@@ -33,7 +33,7 @@ export class DocumentIcon extends React.Component<{ view: DocumentView; index: n
                     background: SettingsManager.userBackgroundColor,
                     transform: `translate(${(left + right) / 2}px, ${top}px)`,
                 }}>
-                <Tooltip title={<>{this.props.view.rootDoc.title}</>}>
+                <Tooltip title={<>{this.props.view.Document.title}</>}>
                     <p>d{this.props.index}</p>
                 </Tooltip>
             </div>
@@ -59,7 +59,7 @@ export class DocumentIconContainer extends React.Component {
                                 const match = node.text.match(/d([0-9]+)/);
                                 if (match) {
                                     const m = parseInt(match[1]);
-                                    const doc = DocumentIcon.DocViews[m].rootDoc;
+                                    const doc = DocumentIcon.DocViews[m].Document;
                                     usedDocuments.add(m);
                                     return factory.createIdentifier(`idToDoc("${doc[Id]}")`);
                                 }
diff --git a/src/client/views/nodes/DocumentLinksButton.tsx b/src/client/views/nodes/DocumentLinksButton.tsx
index 50a7f5d7b..ce3650749 100644
--- a/src/client/views/nodes/DocumentLinksButton.tsx
+++ b/src/client/views/nodes/DocumentLinksButton.tsx
@@ -69,7 +69,7 @@ export class DocumentLinksButton extends React.Component<DocumentLinksButtonProp
             this.onLinkButtonMoved,
             emptyFunction,
             action((e, doubleTap) => {
-                doubleTap && DocumentView.showBackLinks(this.props.View.rootDoc);
+                doubleTap && DocumentView.showBackLinks(this.props.View.Document);
             }),
             undefined,
             undefined,
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index b6e90cbf4..81f1a4f03 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -1385,11 +1385,11 @@ export class DocumentView extends React.Component<DocumentViewProps> {
     };
     public setViewTransition = (transProp: string, timeInMs: number, afterTrans?: () => void, dataTrans = false) => {
         this.layoutDoc._viewTransition = `${transProp} ${timeInMs}ms`;
-        if (dataTrans) this.rootDoc._dataTransition = `${transProp} ${timeInMs}ms`;
+        if (dataTrans) this.Document._dataTransition = `${transProp} ${timeInMs}ms`;
         this.ViewTimer && clearTimeout(this.ViewTimer);
         return (this.ViewTimer = setTimeout(() => {
             this.layoutDoc._viewTransition = undefined;
-            this.rootDoc._dataTransition = 'inherit';
+            this.Document._dataTransition = 'inherit';
             afterTrans?.();
         }, timeInMs + 10));
     };
@@ -1427,7 +1427,7 @@ export class DocumentView extends React.Component<DocumentViewProps> {
     get topMost() {
         return this.props.renderDepth === 0;
     }
-    get rootDoc() {
+    get Document() {
         return this.Document;
     }
     get dataDoc() {
@@ -1440,7 +1440,7 @@ export class DocumentView extends React.Component<DocumentViewProps> {
         return this.docView?._componentView;
     }
     get allLinks() {
-        return (this.docView?.allLinks || []).filter(link => !link.link_matchEmbeddings || link.link_anchor_1 === this.Document || link.link_anchor_2 === this.rootDoc);
+        return (this.docView?.allLinks || []).filter(link => !link.link_matchEmbeddings || link.link_anchor_1 === this.Document || link.link_anchor_2 === this.Document);
     }
     get LayoutFieldKey() {
         return this.docView?.LayoutFieldKey || 'layout';
diff --git a/src/client/views/nodes/FontIconBox/ButtonInterface.ts b/src/client/views/nodes/FontIconBox/ButtonInterface.ts
index 0aa2ac8e1..1c034bfbe 100644
--- a/src/client/views/nodes/FontIconBox/ButtonInterface.ts
+++ b/src/client/views/nodes/FontIconBox/ButtonInterface.ts
@@ -1,12 +1,12 @@
-import { Doc } from "../../../../fields/Doc";
-import { IconProp } from "@fortawesome/fontawesome-svg-core";
-import { ButtonType } from "./FontIconBox";
+import { Doc } from '../../../../fields/Doc';
+import { IconProp } from '@fortawesome/fontawesome-svg-core';
+import { ButtonType } from './FontIconBox';
 
 export interface IButtonProps {
     type: string | ButtonType;
-    rootDoc: Doc;
+    Document: Doc;
     label: any;
     icon: IconProp;
     color: string;
     backgroundColor: string;
-}
\ No newline at end of file
+}
diff --git a/src/client/views/nodes/LinkBox.tsx b/src/client/views/nodes/LinkBox.tsx
index 30cd65cb4..743075c89 100644
--- a/src/client/views/nodes/LinkBox.tsx
+++ b/src/client/views/nodes/LinkBox.tsx
@@ -35,8 +35,8 @@ export class LinkBox extends ViewBoxBaseComponent<FieldViewProps>() {
         if (this.layoutDoc._layout_isSvg && this.anchor1 && this.anchor2 && this.anchor1.CollectionFreeFormView) {
             const a_invXf = this.anchor1.props.ScreenToLocalTransform().inverse();
             const b_invXf = this.anchor2.props.ScreenToLocalTransform().inverse();
-            const a_scrBds = { tl: a_invXf.transformPoint(0, 0), br: a_invXf.transformPoint(NumCast(this.anchor1.rootDoc._width), NumCast(this.anchor1.rootDoc._height)) };
-            const b_scrBds = { tl: b_invXf.transformPoint(0, 0), br: b_invXf.transformPoint(NumCast(this.anchor2.rootDoc._width), NumCast(this.anchor2.rootDoc._height)) };
+            const a_scrBds = { tl: a_invXf.transformPoint(0, 0), br: a_invXf.transformPoint(NumCast(this.anchor1.Document._width), NumCast(this.anchor1.Document._height)) };
+            const b_scrBds = { tl: b_invXf.transformPoint(0, 0), br: b_invXf.transformPoint(NumCast(this.anchor2.Document._width), NumCast(this.anchor2.Document._height)) };
 
             const pts = [] as number[][];
             pts.push([(a_scrBds.tl[0] + a_scrBds.br[0]) / 2, (a_scrBds.tl[1] + a_scrBds.br[1]) / 2]);
@@ -65,8 +65,8 @@ export class LinkBox extends ViewBoxBaseComponent<FieldViewProps>() {
                     const this_xf = parxf?.screenToLocalXf ?? Transform.Identity; //this.props.ScreenToLocalTransform();
                     const a_invXf = a.props.ScreenToLocalTransform().inverse();
                     const b_invXf = b.props.ScreenToLocalTransform().inverse();
-                    const a_scrBds = { tl: a_invXf.transformPoint(0, 0), br: a_invXf.transformPoint(NumCast(a.rootDoc._width), NumCast(a.rootDoc._height)) };
-                    const b_scrBds = { tl: b_invXf.transformPoint(0, 0), br: b_invXf.transformPoint(NumCast(b.rootDoc._width), NumCast(b.rootDoc._height)) };
+                    const a_scrBds = { tl: a_invXf.transformPoint(0, 0), br: a_invXf.transformPoint(NumCast(a.Document._width), NumCast(a.Document._height)) };
+                    const b_scrBds = { tl: b_invXf.transformPoint(0, 0), br: b_invXf.transformPoint(NumCast(b.Document._width), NumCast(b.Document._height)) };
                     const a_bds = { tl: this_xf.transformPoint(a_scrBds.tl[0], a_scrBds.tl[1]), br: this_xf.transformPoint(a_scrBds.br[0], a_scrBds.br[1]) };
                     const b_bds = { tl: this_xf.transformPoint(b_scrBds.tl[0], b_scrBds.tl[1]), br: this_xf.transformPoint(b_scrBds.br[0], b_scrBds.br[1]) };
 
diff --git a/src/client/views/nodes/MapBox/MapBox.tsx b/src/client/views/nodes/MapBox/MapBox.tsx
index 8d3cd1d96..14a8a387a 100644
--- a/src/client/views/nodes/MapBox/MapBox.tsx
+++ b/src/client/views/nodes/MapBox/MapBox.tsx
@@ -386,8 +386,8 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
         this.selectedPin = pinDoc;
         this.bingSearchBarContents = pinDoc.map;
 
-        // Doc.setDocFilter(this.rootDoc, 'latitude', this.selectedPin.latitude, 'match');
-        // Doc.setDocFilter(this.rootDoc, 'longitude', this.selectedPin.longitude, 'match');
+        // Doc.setDocFilter(this.Document, 'latitude', this.selectedPin.latitude, 'match');
+        // Doc.setDocFilter(this.Document, 'longitude', this.selectedPin.longitude, 'match');
         Doc.setDocFilter(this.layoutDoc, LinkedTo, `mapPin=${Field.toScriptString(this.selectedPin)}`, 'check');
 
         this.recolorPin(this.selectedPin, 'green');
diff --git a/src/client/views/nodes/formattedText/DashFieldView.tsx b/src/client/views/nodes/formattedText/DashFieldView.tsx
index 130ac40c8..a914084f9 100644
--- a/src/client/views/nodes/formattedText/DashFieldView.tsx
+++ b/src/client/views/nodes/formattedText/DashFieldView.tsx
@@ -147,7 +147,7 @@ export class DashFieldViewInternal extends React.Component<IDashFieldViewInterna
     createPivotForField = (e: React.MouseEvent) => {
         let container = this.props.tbox.props.DocumentView?.().props.docViewPath().lastElement();
         if (container) {
-            const embedding = Doc.MakeEmbedding(container.rootDoc);
+            const embedding = Doc.MakeEmbedding(container.Document);
             embedding._type_collection = CollectionViewType.Time;
             const colHdrKey = '_' + container.LayoutFieldKey + '_columnHeaders';
             let list = Cast(embedding[colHdrKey], listSpec(SchemaHeaderField));
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index f3929533d..8a927560d 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -1511,7 +1511,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
             (this._editorView as any).TextView = this;
         }
 
-        const selectOnLoad = this.Document[Id] === FormattedTextBox.SelectOnLoad && (!LightboxView.LightboxDoc || LightboxView.IsLightboxDocView(this.props.docViewPath()));
+        const selectOnLoad = DocCast(this.Document.rootDocument, this.Document)[Id] === FormattedTextBox.SelectOnLoad && (!LightboxView.LightboxDoc || LightboxView.IsLightboxDocView(this.props.docViewPath()));
         if (this._editorView && selectOnLoad && !this.props.dontRegisterView && !this.props.dontSelectOnLoad && this.isActiveTab(this.ProseRef)) {
             const selLoadChar = FormattedTextBox.SelectOnLoadChar;
             FormattedTextBox.SelectOnLoad = '';
diff --git a/src/client/views/nodes/formattedText/RichTextMenu.tsx b/src/client/views/nodes/formattedText/RichTextMenu.tsx
index 816a89489..791a1bfe7 100644
--- a/src/client/views/nodes/formattedText/RichTextMenu.tsx
+++ b/src/client/views/nodes/formattedText/RichTextMenu.tsx
@@ -239,7 +239,7 @@ export class RichTextMenu extends AntimodeMenu<AntimodeMenuProps> {
                 m.type === state.schema.marks.marker && activeHighlights.add(String(m.attrs.highlight));
             });
         } else if (SelectionManager.Views().some(dv => dv.ComponentView instanceof EquationBox)) {
-            SelectionManager.Views().forEach(dv => StrCast(dv.rootDoc._text_fontSize) && activeSizes.add(StrCast(dv.rootDoc._text_fontSize)));
+            SelectionManager.Views().forEach(dv => StrCast(dv.Document._text_fontSize) && activeSizes.add(StrCast(dv.Document._text_fontSize)));
         }
         return { activeFamilies: Array.from(activeFamilies), activeSizes: Array.from(activeSizes), activeColors: Array.from(activeColors), activeHighlights: Array.from(activeHighlights) };
     }
@@ -359,7 +359,7 @@ export class RichTextMenu extends AntimodeMenu<AntimodeMenuProps> {
                 this.view.focus();
             }
         } else if (SelectionManager.Views().some(dv => dv.ComponentView instanceof EquationBox)) {
-            SelectionManager.Views().forEach(dv => (dv.rootDoc._text_fontSize = fontSize));
+            SelectionManager.Views().forEach(dv => (dv.Document._text_fontSize = fontSize));
         } else Doc.UserDoc().fontSize = fontSize;
         this.updateMenu(this.view, undefined, this.props, this.layoutDoc);
     };
-- 
cgit v1.2.3-70-g09d2


From adf56d455ab0e429b7eac3430890ba7677cce8d9 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Fri, 15 Dec 2023 11:16:37 -0500
Subject: more fixes for mapbox and dataviz

---
 package-lock.json                                  | 2188 +++++++++++++++++++-
 package.json                                       |    3 +
 src/client/views/nodes/DataVizBox/DataVizBox.tsx   |   14 +-
 .../nodes/DataVizBox/components/Histogram.tsx      |  102 +-
 .../nodes/DataVizBox/components/LineChart.tsx      |   66 +-
 .../views/nodes/DataVizBox/components/PieChart.tsx |   88 +-
 .../views/nodes/DataVizBox/components/TableBox.tsx |   79 +-
 src/client/views/nodes/MapBox/AnimationUtility.ts  |  482 ++---
 .../views/nodes/MapBox/DirectionsAnchorMenu.tsx    |   69 +-
 .../views/nodes/MapboxMapBox/MapboxContainer.tsx   |   66 +-
 webpack.config.js                                  |    2 +-
 11 files changed, 2636 insertions(+), 523 deletions(-)

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

diff --git a/package-lock.json b/package-lock.json
index 18c4f3d05..6496b4184 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -25,6 +25,7 @@
                 "@mui/material": "^5.14.19",
                 "@octokit/core": "^5.0.2",
                 "@react-google-maps/api": "^2.19.2",
+                "@turf/turf": "^6.5.0",
                 "@types/bezier-js": "^4.1.3",
                 "@types/cors": "^2.8.17",
                 "@types/d3-axis": "^3.0.6",
@@ -113,6 +114,7 @@
                 "jsonschema": "^1.4.1",
                 "jszip": "^3.10.1",
                 "lodash": "^4.17.21",
+                "mapbox-gl": "^3.0.1",
                 "mathquill": "^0.10.1-a",
                 "md5-file": "^5.0.0",
                 "memorystream": "^0.3.1",
@@ -163,6 +165,7 @@
                 "react-icons": "^4.12.0",
                 "react-jsx-parser": "^1.29.0",
                 "react-loading": "^2.0.3",
+                "react-map-gl": "^7.1.6",
                 "react-markdown": "^9.0.1",
                 "react-measure": "^2.5.2",
                 "react-resizable": "^3.0.5",
@@ -3126,6 +3129,42 @@
             "integrity": "sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==",
             "dev": true
         },
+        "node_modules/@mapbox/geojson-rewind": {
+            "version": "0.5.2",
+            "resolved": "https://registry.npmjs.org/@mapbox/geojson-rewind/-/geojson-rewind-0.5.2.tgz",
+            "integrity": "sha512-tJaT+RbYGJYStt7wI3cq4Nl4SXxG8W7JDG5DMJu97V25RnbNg3QtQtf+KD+VLjNpWKYsRvXDNmNrBgEETr1ifA==",
+            "dependencies": {
+                "get-stream": "^6.0.1",
+                "minimist": "^1.2.6"
+            },
+            "bin": {
+                "geojson-rewind": "geojson-rewind"
+            }
+        },
+        "node_modules/@mapbox/geojson-rewind/node_modules/get-stream": {
+            "version": "6.0.1",
+            "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz",
+            "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==",
+            "engines": {
+                "node": ">=10"
+            },
+            "funding": {
+                "url": "https://github.com/sponsors/sindresorhus"
+            }
+        },
+        "node_modules/@mapbox/jsonlint-lines-primitives": {
+            "version": "2.0.2",
+            "resolved": "https://registry.npmjs.org/@mapbox/jsonlint-lines-primitives/-/jsonlint-lines-primitives-2.0.2.tgz",
+            "integrity": "sha512-rY0o9A5ECsTQRVhv7tL/OyDpGAoUB4tTvLiW1DSzQGq4bvTPhNw1VpSNjDJc5GFZ2XuyOtSWSVN05qOtcD71qQ==",
+            "engines": {
+                "node": ">= 0.6"
+            }
+        },
+        "node_modules/@mapbox/mapbox-gl-supported": {
+            "version": "2.0.1",
+            "resolved": "https://registry.npmjs.org/@mapbox/mapbox-gl-supported/-/mapbox-gl-supported-2.0.1.tgz",
+            "integrity": "sha512-HP6XvfNIzfoMVfyGjBckjiAOQK9WfX0ywdLubuPMPv+Vqf5fj0uCbgBQYpiqcWZT6cbyyRnTSXDheT1ugvF6UQ=="
+        },
         "node_modules/@mapbox/node-pre-gyp": {
             "version": "1.0.11",
             "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.11.tgz",
@@ -3228,6 +3267,55 @@
             "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
             "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
         },
+        "node_modules/@mapbox/point-geometry": {
+            "version": "0.1.0",
+            "resolved": "https://registry.npmjs.org/@mapbox/point-geometry/-/point-geometry-0.1.0.tgz",
+            "integrity": "sha512-6j56HdLTwWGO0fJPlrZtdU/B13q8Uwmo18Ck2GnGgN9PCFyKTZ3UbXeEdRFh18i9XQ92eH2VdtpJHpBD3aripQ=="
+        },
+        "node_modules/@mapbox/tiny-sdf": {
+            "version": "2.0.6",
+            "resolved": "https://registry.npmjs.org/@mapbox/tiny-sdf/-/tiny-sdf-2.0.6.tgz",
+            "integrity": "sha512-qMqa27TLw+ZQz5Jk+RcwZGH7BQf5G/TrutJhspsca/3SHwmgKQ1iq+d3Jxz5oysPVYTGP6aXxCo5Lk9Er6YBAA=="
+        },
+        "node_modules/@mapbox/unitbezier": {
+            "version": "0.0.1",
+            "resolved": "https://registry.npmjs.org/@mapbox/unitbezier/-/unitbezier-0.0.1.tgz",
+            "integrity": "sha512-nMkuDXFv60aBr9soUG5q+GvZYL+2KZHVvsqFCzqnkGEf46U2fvmytHaEVc1/YZbiLn8X+eR3QzX1+dwDO1lxlw=="
+        },
+        "node_modules/@mapbox/vector-tile": {
+            "version": "1.3.1",
+            "resolved": "https://registry.npmjs.org/@mapbox/vector-tile/-/vector-tile-1.3.1.tgz",
+            "integrity": "sha512-MCEddb8u44/xfQ3oD+Srl/tNcQoqTw3goGk2oLsrFxOTc3dUp+kAnby3PvAeeBYSMSjSPD1nd1AJA6W49WnoUw==",
+            "dependencies": {
+                "@mapbox/point-geometry": "~0.1.0"
+            }
+        },
+        "node_modules/@mapbox/whoots-js": {
+            "version": "3.1.0",
+            "resolved": "https://registry.npmjs.org/@mapbox/whoots-js/-/whoots-js-3.1.0.tgz",
+            "integrity": "sha512-Es6WcD0nO5l+2BOQS4uLfNPYQaNDfbot3X1XUoloz+x0mPDS3eeORZJl06HXjwBG1fOGwCRnzK88LMdxKRrd6Q==",
+            "engines": {
+                "node": ">=6.0.0"
+            }
+        },
+        "node_modules/@maplibre/maplibre-gl-style-spec": {
+            "version": "19.3.3",
+            "resolved": "https://registry.npmjs.org/@maplibre/maplibre-gl-style-spec/-/maplibre-gl-style-spec-19.3.3.tgz",
+            "integrity": "sha512-cOZZOVhDSulgK0meTsTkmNXb1ahVvmTmWmfx9gRBwc6hq98wS9JP35ESIoNq3xqEan+UN+gn8187Z6E4NKhLsw==",
+            "dependencies": {
+                "@mapbox/jsonlint-lines-primitives": "~2.0.2",
+                "@mapbox/unitbezier": "^0.0.1",
+                "json-stringify-pretty-compact": "^3.0.0",
+                "minimist": "^1.2.8",
+                "rw": "^1.3.3",
+                "sort-object": "^3.0.3"
+            },
+            "bin": {
+                "gl-style-format": "dist/gl-style-format.mjs",
+                "gl-style-migrate": "dist/gl-style-migrate.mjs",
+                "gl-style-validate": "dist/gl-style-validate.mjs"
+            }
+        },
         "node_modules/@mongodb-js/saslprep": {
             "version": "1.1.1",
             "resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.1.1.tgz",
@@ -3775,11 +3863,1588 @@
             "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==",
             "dev": true
         },
-        "node_modules/@tsconfig/node16": {
-            "version": "1.0.4",
-            "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz",
-            "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==",
-            "dev": true
+        "node_modules/@tsconfig/node16": {
+            "version": "1.0.4",
+            "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz",
+            "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==",
+            "dev": true
+        },
+        "node_modules/@turf/along": {
+            "version": "6.5.0",
+            "resolved": "https://registry.npmjs.org/@turf/along/-/along-6.5.0.tgz",
+            "integrity": "sha512-LLyWQ0AARqJCmMcIEAXF4GEu8usmd4Kbz3qk1Oy5HoRNpZX47+i5exQtmIWKdqJ1MMhW26fCTXgpsEs5zgJ5gw==",
+            "dependencies": {
+                "@turf/bearing": "^6.5.0",
+                "@turf/destination": "^6.5.0",
+                "@turf/distance": "^6.5.0",
+                "@turf/helpers": "^6.5.0",
+                "@turf/invariant": "^6.5.0"
+            },
+            "funding": {
+                "url": "https://opencollective.com/turf"
+            }
+        },
+        "node_modules/@turf/angle": {
+            "version": "6.5.0",
+            "resolved": "https://registry.npmjs.org/@turf/angle/-/angle-6.5.0.tgz",
+            "integrity": "sha512-4pXMbWhFofJJAOvTMCns6N4C8CMd5Ih4O2jSAG9b3dDHakj3O4yN1+Zbm+NUei+eVEZ9gFeVp9svE3aMDenIkw==",
+            "dependencies": {
+                "@turf/bearing": "^6.5.0",
+                "@turf/helpers": "^6.5.0",
+                "@turf/invariant": "^6.5.0",
+                "@turf/rhumb-bearing": "^6.5.0"
+            },
+            "funding": {
+                "url": "https://opencollective.com/turf"
+            }
+        },
+        "node_modules/@turf/area": {
+            "version": "6.5.0",
+            "resolved": "https://registry.npmjs.org/@turf/area/-/area-6.5.0.tgz",
+            "integrity": "sha512-xCZdiuojokLbQ+29qR6qoMD89hv+JAgWjLrwSEWL+3JV8IXKeNFl6XkEJz9HGkVpnXvQKJoRz4/liT+8ZZ5Jyg==",
+            "dependencies": {
+                "@turf/helpers": "^6.5.0",
+                "@turf/meta": "^6.5.0"
+            },
+            "funding": {
+                "url": "https://opencollective.com/turf"
+            }
+        },
+        "node_modules/@turf/bbox": {
+            "version": "6.5.0",
+            "resolved": "https://registry.npmjs.org/@turf/bbox/-/bbox-6.5.0.tgz",
+            "integrity": "sha512-RBbLaao5hXTYyyg577iuMtDB8ehxMlUqHEJiMs8jT1GHkFhr6sYre3lmLsPeYEi/ZKj5TP5tt7fkzNdJ4GIVyw==",
+            "dependencies": {
+                "@turf/helpers": "^6.5.0",
+                "@turf/meta": "^6.5.0"
+            },
+            "funding": {
+                "url": "https://opencollective.com/turf"
+            }
+        },
+        "node_modules/@turf/bbox-clip": {
+            "version": "6.5.0",
+            "resolved": "https://registry.npmjs.org/@turf/bbox-clip/-/bbox-clip-6.5.0.tgz",
+            "integrity": "sha512-F6PaIRF8WMp8EmgU/Ke5B1Y6/pia14UAYB5TiBC668w5rVVjy5L8rTm/m2lEkkDMHlzoP9vNY4pxpNthE7rLcQ==",
+            "dependencies": {
+                "@turf/helpers": "^6.5.0",
+                "@turf/invariant": "^6.5.0"
+            },
+            "funding": {
+                "url": "https://opencollective.com/turf"
+            }
+        },
+        "node_modules/@turf/bbox-polygon": {
+            "version": "6.5.0",
+            "resolved": "https://registry.npmjs.org/@turf/bbox-polygon/-/bbox-polygon-6.5.0.tgz",
+            "integrity": "sha512-+/r0NyL1lOG3zKZmmf6L8ommU07HliP4dgYToMoTxqzsWzyLjaj/OzgQ8rBmv703WJX+aS6yCmLuIhYqyufyuw==",
+            "dependencies": {
+                "@turf/helpers": "^6.5.0"
+            },
+            "funding": {
+                "url": "https://opencollective.com/turf"
+            }
+        },
+        "node_modules/@turf/bearing": {
+            "version": "6.5.0",
+            "resolved": "https://registry.npmjs.org/@turf/bearing/-/bearing-6.5.0.tgz",
+            "integrity": "sha512-dxINYhIEMzgDOztyMZc20I7ssYVNEpSv04VbMo5YPQsqa80KO3TFvbuCahMsCAW5z8Tncc8dwBlEFrmRjJG33A==",
+            "dependencies": {
+                "@turf/helpers": "^6.5.0",
+                "@turf/invariant": "^6.5.0"
+            },
+            "funding": {
+                "url": "https://opencollective.com/turf"
+            }
+        },
+        "node_modules/@turf/bezier-spline": {
+            "version": "6.5.0",
+            "resolved": "https://registry.npmjs.org/@turf/bezier-spline/-/bezier-spline-6.5.0.tgz",
+            "integrity": "sha512-vokPaurTd4PF96rRgGVm6zYYC5r1u98ZsG+wZEv9y3kJTuJRX/O3xIY2QnTGTdbVmAJN1ouOsD0RoZYaVoXORQ==",
+            "dependencies": {
+                "@turf/helpers": "^6.5.0",
+                "@turf/invariant": "^6.5.0"
+            },
+            "funding": {
+                "url": "https://opencollective.com/turf"
+            }
+        },
+        "node_modules/@turf/boolean-clockwise": {
+            "version": "6.5.0",
+            "resolved": "https://registry.npmjs.org/@turf/boolean-clockwise/-/boolean-clockwise-6.5.0.tgz",
+            "integrity": "sha512-45+C7LC5RMbRWrxh3Z0Eihsc8db1VGBO5d9BLTOAwU4jR6SgsunTfRWR16X7JUwIDYlCVEmnjcXJNi/kIU3VIw==",
+            "dependencies": {
+                "@turf/helpers": "^6.5.0",
+                "@turf/invariant": "^6.5.0"
+            },
+            "funding": {
+                "url": "https://opencollective.com/turf"
+            }
+        },
+        "node_modules/@turf/boolean-contains": {
+            "version": "6.5.0",
+            "resolved": "https://registry.npmjs.org/@turf/boolean-contains/-/boolean-contains-6.5.0.tgz",
+            "integrity": "sha512-4m8cJpbw+YQcKVGi8y0cHhBUnYT+QRfx6wzM4GI1IdtYH3p4oh/DOBJKrepQyiDzFDaNIjxuWXBh0ai1zVwOQQ==",
+            "dependencies": {
+                "@turf/bbox": "^6.5.0",
+                "@turf/boolean-point-in-polygon": "^6.5.0",
+                "@turf/boolean-point-on-line": "^6.5.0",
+                "@turf/helpers": "^6.5.0",
+                "@turf/invariant": "^6.5.0"
+            },
+            "funding": {
+                "url": "https://opencollective.com/turf"
+            }
+        },
+        "node_modules/@turf/boolean-crosses": {
+            "version": "6.5.0",
+            "resolved": "https://registry.npmjs.org/@turf/boolean-crosses/-/boolean-crosses-6.5.0.tgz",
+            "integrity": "sha512-gvshbTPhAHporTlQwBJqyfW+2yV8q/mOTxG6PzRVl6ARsqNoqYQWkd4MLug7OmAqVyBzLK3201uAeBjxbGw0Ng==",
+            "dependencies": {
+                "@turf/boolean-point-in-polygon": "^6.5.0",
+                "@turf/helpers": "^6.5.0",
+                "@turf/invariant": "^6.5.0",
+                "@turf/line-intersect": "^6.5.0",
+                "@turf/polygon-to-line": "^6.5.0"
+            },
+            "funding": {
+                "url": "https://opencollective.com/turf"
+            }
+        },
+        "node_modules/@turf/boolean-disjoint": {
+            "version": "6.5.0",
+            "resolved": "https://registry.npmjs.org/@turf/boolean-disjoint/-/boolean-disjoint-6.5.0.tgz",
+            "integrity": "sha512-rZ2ozlrRLIAGo2bjQ/ZUu4oZ/+ZjGvLkN5CKXSKBcu6xFO6k2bgqeM8a1836tAW+Pqp/ZFsTA5fZHsJZvP2D5g==",
+            "dependencies": {
+                "@turf/boolean-point-in-polygon": "^6.5.0",
+                "@turf/helpers": "^6.5.0",
+                "@turf/line-intersect": "^6.5.0",
+                "@turf/meta": "^6.5.0",
+                "@turf/polygon-to-line": "^6.5.0"
+            },
+            "funding": {
+                "url": "https://opencollective.com/turf"
+            }
+        },
+        "node_modules/@turf/boolean-equal": {
+            "version": "6.5.0",
+            "resolved": "https://registry.npmjs.org/@turf/boolean-equal/-/boolean-equal-6.5.0.tgz",
+            "integrity": "sha512-cY0M3yoLC26mhAnjv1gyYNQjn7wxIXmL2hBmI/qs8g5uKuC2hRWi13ydufE3k4x0aNRjFGlg41fjoYLwaVF+9Q==",
+            "dependencies": {
+                "@turf/clean-coords": "^6.5.0",
+                "@turf/helpers": "^6.5.0",
+                "@turf/invariant": "^6.5.0",
+                "geojson-equality": "0.1.6"
+            },
+            "funding": {
+                "url": "https://opencollective.com/turf"
+            }
+        },
+        "node_modules/@turf/boolean-intersects": {
+            "version": "6.5.0",
+            "resolved": "https://registry.npmjs.org/@turf/boolean-intersects/-/boolean-intersects-6.5.0.tgz",
+            "integrity": "sha512-nIxkizjRdjKCYFQMnml6cjPsDOBCThrt+nkqtSEcxkKMhAQj5OO7o2CecioNTaX8EayqwMGVKcsz27oP4mKPTw==",
+            "dependencies": {
+                "@turf/boolean-disjoint": "^6.5.0",
+                "@turf/helpers": "^6.5.0",
+                "@turf/meta": "^6.5.0"
+            },
+            "funding": {
+                "url": "https://opencollective.com/turf"
+            }
+        },
+        "node_modules/@turf/boolean-overlap": {
+            "version": "6.5.0",
+            "resolved": "https://registry.npmjs.org/@turf/boolean-overlap/-/boolean-overlap-6.5.0.tgz",
+            "integrity": "sha512-8btMIdnbXVWUa1M7D4shyaSGxLRw6NjMcqKBcsTXcZdnaixl22k7ar7BvIzkaRYN3SFECk9VGXfLncNS3ckQUw==",
+            "dependencies": {
+                "@turf/helpers": "^6.5.0",
+                "@turf/invariant": "^6.5.0",
+                "@turf/line-intersect": "^6.5.0",
+                "@turf/line-overlap": "^6.5.0",
+                "@turf/meta": "^6.5.0",
+                "geojson-equality": "0.1.6"
+            },
+            "funding": {
+                "url": "https://opencollective.com/turf"
+            }
+        },
+        "node_modules/@turf/boolean-parallel": {
+            "version": "6.5.0",
+            "resolved": "https://registry.npmjs.org/@turf/boolean-parallel/-/boolean-parallel-6.5.0.tgz",
+            "integrity": "sha512-aSHJsr1nq9e5TthZGZ9CZYeXklJyRgR5kCLm5X4urz7+MotMOp/LsGOsvKvK9NeUl9+8OUmfMn8EFTT8LkcvIQ==",
+            "dependencies": {
+                "@turf/clean-coords": "^6.5.0",
+                "@turf/helpers": "^6.5.0",
+                "@turf/line-segment": "^6.5.0",
+                "@turf/rhumb-bearing": "^6.5.0"
+            },
+            "funding": {
+                "url": "https://opencollective.com/turf"
+            }
+        },
+        "node_modules/@turf/boolean-point-in-polygon": {
+            "version": "6.5.0",
+            "resolved": "https://registry.npmjs.org/@turf/boolean-point-in-polygon/-/boolean-point-in-polygon-6.5.0.tgz",
+            "integrity": "sha512-DtSuVFB26SI+hj0SjrvXowGTUCHlgevPAIsukssW6BG5MlNSBQAo70wpICBNJL6RjukXg8d2eXaAWuD/CqL00A==",
+            "dependencies": {
+                "@turf/helpers": "^6.5.0",
+                "@turf/invariant": "^6.5.0"
+            },
+            "funding": {
+                "url": "https://opencollective.com/turf"
+            }
+        },
+        "node_modules/@turf/boolean-point-on-line": {
+            "version": "6.5.0",
+            "resolved": "https://registry.npmjs.org/@turf/boolean-point-on-line/-/boolean-point-on-line-6.5.0.tgz",
+            "integrity": "sha512-A1BbuQ0LceLHvq7F/P7w3QvfpmZqbmViIUPHdNLvZimFNLo4e6IQunmzbe+8aSStH9QRZm3VOflyvNeXvvpZEQ==",
+            "dependencies": {
+                "@turf/helpers": "^6.5.0",
+                "@turf/invariant": "^6.5.0"
+            },
+            "funding": {
+                "url": "https://opencollective.com/turf"
+            }
+        },
+        "node_modules/@turf/boolean-within": {
+            "version": "6.5.0",
+            "resolved": "https://registry.npmjs.org/@turf/boolean-within/-/boolean-within-6.5.0.tgz",
+            "integrity": "sha512-YQB3oU18Inx35C/LU930D36RAVe7LDXk1kWsQ8mLmuqYn9YdPsDQTMTkLJMhoQ8EbN7QTdy333xRQ4MYgToteQ==",
+            "dependencies": {
+                "@turf/bbox": "^6.5.0",
+                "@turf/boolean-point-in-polygon": "^6.5.0",
+                "@turf/boolean-point-on-line": "^6.5.0",
+                "@turf/helpers": "^6.5.0",
+                "@turf/invariant": "^6.5.0"
+            },
+            "funding": {
+                "url": "https://opencollective.com/turf"
+            }
+        },
+        "node_modules/@turf/buffer": {
+            "version": "6.5.0",
+            "resolved": "https://registry.npmjs.org/@turf/buffer/-/buffer-6.5.0.tgz",
+            "integrity": "sha512-qeX4N6+PPWbKqp1AVkBVWFerGjMYMUyencwfnkCesoznU6qvfugFHNAngNqIBVnJjZ5n8IFyOf+akcxnrt9sNg==",
+            "dependencies": {
+                "@turf/bbox": "^6.5.0",
+                "@turf/center": "^6.5.0",
+                "@turf/helpers": "^6.5.0",
+                "@turf/meta": "^6.5.0",
+                "@turf/projection": "^6.5.0",
+                "d3-geo": "1.7.1",
+                "turf-jsts": "*"
+            },
+            "funding": {
+                "url": "https://opencollective.com/turf"
+            }
+        },
+        "node_modules/@turf/buffer/node_modules/d3-array": {
+            "version": "1.2.4",
+            "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-1.2.4.tgz",
+            "integrity": "sha512-KHW6M86R+FUPYGb3R5XiYjXPq7VzwxZ22buHhAEVG5ztoEcZZMLov530mmccaqA1GghZArjQV46fuc8kUqhhHw=="
+        },
+        "node_modules/@turf/buffer/node_modules/d3-geo": {
+            "version": "1.7.1",
+            "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-1.7.1.tgz",
+            "integrity": "sha512-O4AempWAr+P5qbk2bC2FuN/sDW4z+dN2wDf9QV3bxQt4M5HfOEeXLgJ/UKQW0+o1Dj8BE+L5kiDbdWUMjsmQpw==",
+            "dependencies": {
+                "d3-array": "1"
+            }
+        },
+        "node_modules/@turf/center": {
+            "version": "6.5.0",
+            "resolved": "https://registry.npmjs.org/@turf/center/-/center-6.5.0.tgz",
+            "integrity": "sha512-T8KtMTfSATWcAX088rEDKjyvQCBkUsLnK/Txb6/8WUXIeOZyHu42G7MkdkHRoHtwieLdduDdmPLFyTdG5/e7ZQ==",
+            "dependencies": {
+                "@turf/bbox": "^6.5.0",
+                "@turf/helpers": "^6.5.0"
+            },
+            "funding": {
+                "url": "https://opencollective.com/turf"
+            }
+        },
+        "node_modules/@turf/center-mean": {
+            "version": "6.5.0",
+            "resolved": "https://registry.npmjs.org/@turf/center-mean/-/center-mean-6.5.0.tgz",
+            "integrity": "sha512-AAX6f4bVn12pTVrMUiB9KrnV94BgeBKpyg3YpfnEbBpkN/znfVhL8dG8IxMAxAoSZ61Zt9WLY34HfENveuOZ7Q==",
+            "dependencies": {
+                "@turf/bbox": "^6.5.0",
+                "@turf/helpers": "^6.5.0",
+                "@turf/meta": "^6.5.0"
+            },
+            "funding": {
+                "url": "https://opencollective.com/turf"
+            }
+        },
+        "node_modules/@turf/center-median": {
+            "version": "6.5.0",
+            "resolved": "https://registry.npmjs.org/@turf/center-median/-/center-median-6.5.0.tgz",
+            "integrity": "sha512-dT8Ndu5CiZkPrj15PBvslpuf01ky41DEYEPxS01LOxp5HOUHXp1oJxsPxvc+i/wK4BwccPNzU1vzJ0S4emd1KQ==",
+            "dependencies": {
+                "@turf/center-mean": "^6.5.0",
+                "@turf/centroid": "^6.5.0",
+                "@turf/distance": "^6.5.0",
+                "@turf/helpers": "^6.5.0",
+                "@turf/meta": "^6.5.0"
+            },
+            "funding": {
+                "url": "https://opencollective.com/turf"
+            }
+        },
+        "node_modules/@turf/center-of-mass": {
+            "version": "6.5.0",
+            "resolved": "https://registry.npmjs.org/@turf/center-of-mass/-/center-of-mass-6.5.0.tgz",
+            "integrity": "sha512-EWrriU6LraOfPN7m1jZi+1NLTKNkuIsGLZc2+Y8zbGruvUW+QV7K0nhf7iZWutlxHXTBqEXHbKue/o79IumAsQ==",
+            "dependencies": {
+                "@turf/centroid": "^6.5.0",
+                "@turf/convex": "^6.5.0",
+                "@turf/helpers": "^6.5.0",
+                "@turf/invariant": "^6.5.0",
+                "@turf/meta": "^6.5.0"
+            },
+            "funding": {
+                "url": "https://opencollective.com/turf"
+            }
+        },
+        "node_modules/@turf/centroid": {
+            "version": "6.5.0",
+            "resolved": "https://registry.npmjs.org/@turf/centroid/-/centroid-6.5.0.tgz",
+            "integrity": "sha512-MwE1oq5E3isewPprEClbfU5pXljIK/GUOMbn22UM3IFPDJX0KeoyLNwghszkdmFp/qMGL/M13MMWvU+GNLXP/A==",
+            "dependencies": {
+                "@turf/helpers": "^6.5.0",
+                "@turf/meta": "^6.5.0"
+            },
+            "funding": {
+                "url": "https://opencollective.com/turf"
+            }
+        },
+        "node_modules/@turf/circle": {
+            "version": "6.5.0",
+            "resolved": "https://registry.npmjs.org/@turf/circle/-/circle-6.5.0.tgz",
+            "integrity": "sha512-oU1+Kq9DgRnoSbWFHKnnUdTmtcRUMmHoV9DjTXu9vOLNV5OWtAAh1VZ+mzsioGGzoDNT/V5igbFOkMfBQc0B6A==",
+            "dependencies": {
+                "@turf/destination": "^6.5.0",
+                "@turf/helpers": "^6.5.0"
+            },
+            "funding": {
+                "url": "https://opencollective.com/turf"
+            }
+        },
+        "node_modules/@turf/clean-coords": {
+            "version": "6.5.0",
+            "resolved": "https://registry.npmjs.org/@turf/clean-coords/-/clean-coords-6.5.0.tgz",
+            "integrity": "sha512-EMX7gyZz0WTH/ET7xV8MyrExywfm9qUi0/MY89yNffzGIEHuFfqwhcCqZ8O00rZIPZHUTxpmsxQSTfzJJA1CPw==",
+            "dependencies": {
+                "@turf/helpers": "^6.5.0",
+                "@turf/invariant": "^6.5.0"
+            },
+            "funding": {
+                "url": "https://opencollective.com/turf"
+            }
+        },
+        "node_modules/@turf/clone": {
+            "version": "6.5.0",
+            "resolved": "https://registry.npmjs.org/@turf/clone/-/clone-6.5.0.tgz",
+            "integrity": "sha512-mzVtTFj/QycXOn6ig+annKrM6ZlimreKYz6f/GSERytOpgzodbQyOgkfwru100O1KQhhjSudKK4DsQ0oyi9cTw==",
+            "dependencies": {
+                "@turf/helpers": "^6.5.0"
+            },
+            "funding": {
+                "url": "https://opencollective.com/turf"
+            }
+        },
+        "node_modules/@turf/clusters": {
+            "version": "6.5.0",
+            "resolved": "https://registry.npmjs.org/@turf/clusters/-/clusters-6.5.0.tgz",
+            "integrity": "sha512-Y6gfnTJzQ1hdLfCsyd5zApNbfLIxYEpmDibHUqR5z03Lpe02pa78JtgrgUNt1seeO/aJ4TG1NLN8V5gOrHk04g==",
+            "dependencies": {
+                "@turf/helpers": "^6.5.0",
+                "@turf/meta": "^6.5.0"
+            },
+            "funding": {
+                "url": "https://opencollective.com/turf"
+            }
+        },
+        "node_modules/@turf/clusters-dbscan": {
+            "version": "6.5.0",
+            "resolved": "https://registry.npmjs.org/@turf/clusters-dbscan/-/clusters-dbscan-6.5.0.tgz",
+            "integrity": "sha512-SxZEE4kADU9DqLRiT53QZBBhu8EP9skviSyl+FGj08Y01xfICM/RR9ACUdM0aEQimhpu+ZpRVcUK+2jtiCGrYQ==",
+            "dependencies": {
+                "@turf/clone": "^6.5.0",
+                "@turf/distance": "^6.5.0",
+                "@turf/helpers": "^6.5.0",
+                "@turf/meta": "^6.5.0",
+                "density-clustering": "1.3.0"
+            },
+            "funding": {
+                "url": "https://opencollective.com/turf"
+            }
+        },
+        "node_modules/@turf/clusters-kmeans": {
+            "version": "6.5.0",
+            "resolved": "https://registry.npmjs.org/@turf/clusters-kmeans/-/clusters-kmeans-6.5.0.tgz",
+            "integrity": "sha512-DwacD5+YO8kwDPKaXwT9DV46tMBVNsbi1IzdajZu1JDSWoN7yc7N9Qt88oi+p30583O0UPVkAK+A10WAQv4mUw==",
+            "dependencies": {
+                "@turf/clone": "^6.5.0",
+                "@turf/helpers": "^6.5.0",
+                "@turf/invariant": "^6.5.0",
+                "@turf/meta": "^6.5.0",
+                "skmeans": "0.9.7"
+            },
+            "funding": {
+                "url": "https://opencollective.com/turf"
+            }
+        },
+        "node_modules/@turf/collect": {
+            "version": "6.5.0",
+            "resolved": "https://registry.npmjs.org/@turf/collect/-/collect-6.5.0.tgz",
+            "integrity": "sha512-4dN/T6LNnRg099m97BJeOcTA5fSI8cu87Ydgfibewd2KQwBexO69AnjEFqfPX3Wj+Zvisj1uAVIZbPmSSrZkjg==",
+            "dependencies": {
+                "@turf/bbox": "^6.5.0",
+                "@turf/boolean-point-in-polygon": "^6.5.0",
+                "@turf/helpers": "^6.5.0",
+                "rbush": "2.x"
+            },
+            "funding": {
+                "url": "https://opencollective.com/turf"
+            }
+        },
+        "node_modules/@turf/combine": {
+            "version": "6.5.0",
+            "resolved": "https://registry.npmjs.org/@turf/combine/-/combine-6.5.0.tgz",
+            "integrity": "sha512-Q8EIC4OtAcHiJB3C4R+FpB4LANiT90t17uOd851qkM2/o6m39bfN5Mv0PWqMZIHWrrosZqRqoY9dJnzz/rJxYQ==",
+            "dependencies": {
+                "@turf/helpers": "^6.5.0",
+                "@turf/meta": "^6.5.0"
+            },
+            "funding": {
+                "url": "https://opencollective.com/turf"
+            }
+        },
+        "node_modules/@turf/concave": {
+            "version": "6.5.0",
+            "resolved": "https://registry.npmjs.org/@turf/concave/-/concave-6.5.0.tgz",
+            "integrity": "sha512-I/sUmUC8TC5h/E2vPwxVht+nRt+TnXIPRoztDFvS8/Y0+cBDple9inLSo9nnPXMXidrBlGXZ9vQx/BjZUJgsRQ==",
+            "dependencies": {
+                "@turf/clone": "^6.5.0",
+                "@turf/distance": "^6.5.0",
+                "@turf/helpers": "^6.5.0",
+                "@turf/invariant": "^6.5.0",
+                "@turf/meta": "^6.5.0",
+                "@turf/tin": "^6.5.0",
+                "topojson-client": "3.x",
+                "topojson-server": "3.x"
+            },
+            "funding": {
+                "url": "https://opencollective.com/turf"
+            }
+        },
+        "node_modules/@turf/convex": {
+            "version": "6.5.0",
+            "resolved": "https://registry.npmjs.org/@turf/convex/-/convex-6.5.0.tgz",
+            "integrity": "sha512-x7ZwC5z7PJB0SBwNh7JCeCNx7Iu+QSrH7fYgK0RhhNop13TqUlvHMirMLRgf2db1DqUetrAO2qHJeIuasquUWg==",
+            "dependencies": {
+                "@turf/helpers": "^6.5.0",
+                "@turf/meta": "^6.5.0",
+                "concaveman": "*"
+            },
+            "funding": {
+                "url": "https://opencollective.com/turf"
+            }
+        },
+        "node_modules/@turf/destination": {
+            "version": "6.5.0",
+            "resolved": "https://registry.npmjs.org/@turf/destination/-/destination-6.5.0.tgz",
+            "integrity": "sha512-4cnWQlNC8d1tItOz9B4pmJdWpXqS0vEvv65bI/Pj/genJnsL7evI0/Xw42RvEGROS481MPiU80xzvwxEvhQiMQ==",
+            "dependencies": {
+                "@turf/helpers": "^6.5.0",
+                "@turf/invariant": "^6.5.0"
+            },
+            "funding": {
+                "url": "https://opencollective.com/turf"
+            }
+        },
+        "node_modules/@turf/difference": {
+            "version": "6.5.0",
+            "resolved": "https://registry.npmjs.org/@turf/difference/-/difference-6.5.0.tgz",
+            "integrity": "sha512-l8iR5uJqvI+5Fs6leNbhPY5t/a3vipUF/3AeVLpwPQcgmedNXyheYuy07PcMGH5Jdpi5gItOiTqwiU/bUH4b3A==",
+            "dependencies": {
+                "@turf/helpers": "^6.5.0",
+                "@turf/invariant": "^6.5.0",
+                "polygon-clipping": "^0.15.3"
+            },
+            "funding": {
+                "url": "https://opencollective.com/turf"
+            }
+        },
+        "node_modules/@turf/dissolve": {
+            "version": "6.5.0",
+            "resolved": "https://registry.npmjs.org/@turf/dissolve/-/dissolve-6.5.0.tgz",
+            "integrity": "sha512-WBVbpm9zLTp0Bl9CE35NomTaOL1c4TQCtEoO43YaAhNEWJOOIhZMFJyr8mbvYruKl817KinT3x7aYjjCMjTAsQ==",
+            "dependencies": {
+                "@turf/helpers": "^6.5.0",
+                "@turf/invariant": "^6.5.0",
+                "@turf/meta": "^6.5.0",
+                "polygon-clipping": "^0.15.3"
+            },
+            "funding": {
+                "url": "https://opencollective.com/turf"
+            }
+        },
+        "node_modules/@turf/distance": {
+            "version": "6.5.0",
+            "resolved": "https://registry.npmjs.org/@turf/distance/-/distance-6.5.0.tgz",
+            "integrity": "sha512-xzykSLfoURec5qvQJcfifw/1mJa+5UwByZZ5TZ8iaqjGYN0vomhV9aiSLeYdUGtYRESZ+DYC/OzY+4RclZYgMg==",
+            "dependencies": {
+                "@turf/helpers": "^6.5.0",
+                "@turf/invariant": "^6.5.0"
+            },
+            "funding": {
+                "url": "https://opencollective.com/turf"
+            }
+        },
+        "node_modules/@turf/distance-weight": {
+            "version": "6.5.0",
+            "resolved": "https://registry.npmjs.org/@turf/distance-weight/-/distance-weight-6.5.0.tgz",
+            "integrity": "sha512-a8qBKkgVNvPKBfZfEJZnC3DV7dfIsC3UIdpRci/iap/wZLH41EmS90nM+BokAJflUHYy8PqE44wySGWHN1FXrQ==",
+            "dependencies": {
+                "@turf/centroid": "^6.5.0",
+                "@turf/helpers": "^6.5.0",
+                "@turf/invariant": "^6.5.0",
+                "@turf/meta": "^6.5.0"
+            },
+            "funding": {
+                "url": "https://opencollective.com/turf"
+            }
+        },
+        "node_modules/@turf/ellipse": {
+            "version": "6.5.0",
+            "resolved": "https://registry.npmjs.org/@turf/ellipse/-/ellipse-6.5.0.tgz",
+            "integrity": "sha512-kuXtwFviw/JqnyJXF1mrR/cb496zDTSbGKtSiolWMNImYzGGkbsAsFTjwJYgD7+4FixHjp0uQPzo70KDf3AIBw==",
+            "dependencies": {
+                "@turf/helpers": "^6.5.0",
+                "@turf/invariant": "^6.5.0",
+                "@turf/rhumb-destination": "^6.5.0",
+                "@turf/transform-rotate": "^6.5.0"
+            },
+            "funding": {
+                "url": "https://opencollective.com/turf"
+            }
+        },
+        "node_modules/@turf/envelope": {
+            "version": "6.5.0",
+            "resolved": "https://registry.npmjs.org/@turf/envelope/-/envelope-6.5.0.tgz",
+            "integrity": "sha512-9Z+FnBWvOGOU4X+fMZxYFs1HjFlkKqsddLuMknRaqcJd6t+NIv5DWvPtDL8ATD2GEExYDiFLwMdckfr1yqJgHA==",
+            "dependencies": {
+                "@turf/bbox": "^6.5.0",
+                "@turf/bbox-polygon": "^6.5.0",
+                "@turf/helpers": "^6.5.0"
+            },
+            "funding": {
+                "url": "https://opencollective.com/turf"
+            }
+        },
+        "node_modules/@turf/explode": {
+            "version": "6.5.0",
+            "resolved": "https://registry.npmjs.org/@turf/explode/-/explode-6.5.0.tgz",
+            "integrity": "sha512-6cSvMrnHm2qAsace6pw9cDmK2buAlw8+tjeJVXMfMyY+w7ZUi1rprWMsY92J7s2Dar63Bv09n56/1V7+tcj52Q==",
+            "dependencies": {
+                "@turf/helpers": "^6.5.0",
+                "@turf/meta": "^6.5.0"
+            },
+            "funding": {
+                "url": "https://opencollective.com/turf"
+            }
+        },
+        "node_modules/@turf/flatten": {
+            "version": "6.5.0",
+            "resolved": "https://registry.npmjs.org/@turf/flatten/-/flatten-6.5.0.tgz",
+            "integrity": "sha512-IBZVwoNLVNT6U/bcUUllubgElzpMsNoCw8tLqBw6dfYg9ObGmpEjf9BIYLr7a2Yn5ZR4l7YIj2T7kD5uJjZADQ==",
+            "dependencies": {
+                "@turf/helpers": "^6.5.0",
+                "@turf/meta": "^6.5.0"
+            },
+            "funding": {
+                "url": "https://opencollective.com/turf"
+            }
+        },
+        "node_modules/@turf/flip": {
+            "version": "6.5.0",
+            "resolved": "https://registry.npmjs.org/@turf/flip/-/flip-6.5.0.tgz",
+            "integrity": "sha512-oyikJFNjt2LmIXQqgOGLvt70RgE2lyzPMloYWM7OR5oIFGRiBvqVD2hA6MNw6JewIm30fWZ8DQJw1NHXJTJPbg==",
+            "dependencies": {
+                "@turf/clone": "^6.5.0",
+                "@turf/helpers": "^6.5.0",
+                "@turf/meta": "^6.5.0"
+            },
+            "funding": {
+                "url": "https://opencollective.com/turf"
+            }
+        },
+        "node_modules/@turf/great-circle": {
+            "version": "6.5.0",
+            "resolved": "https://registry.npmjs.org/@turf/great-circle/-/great-circle-6.5.0.tgz",
+            "integrity": "sha512-7ovyi3HaKOXdFyN7yy1yOMa8IyOvV46RC1QOQTT+RYUN8ke10eyqExwBpL9RFUPvlpoTzoYbM/+lWPogQlFncg==",
+            "dependencies": {
+                "@turf/helpers": "^6.5.0",
+                "@turf/invariant": "^6.5.0"
+            },
+            "funding": {
+                "url": "https://opencollective.com/turf"
+            }
+        },
+        "node_modules/@turf/helpers": {
+            "version": "6.5.0",
+            "resolved": "https://registry.npmjs.org/@turf/helpers/-/helpers-6.5.0.tgz",
+            "integrity": "sha512-VbI1dV5bLFzohYYdgqwikdMVpe7pJ9X3E+dlr425wa2/sMJqYDhTO++ec38/pcPvPE6oD9WEEeU3Xu3gza+VPw==",
+            "funding": {
+                "url": "https://opencollective.com/turf"
+            }
+        },
+        "node_modules/@turf/hex-grid": {
+            "version": "6.5.0",
+            "resolved": "https://registry.npmjs.org/@turf/hex-grid/-/hex-grid-6.5.0.tgz",
+            "integrity": "sha512-Ln3tc2tgZT8etDOldgc6e741Smg1CsMKAz1/Mlel+MEL5Ynv2mhx3m0q4J9IB1F3a4MNjDeVvm8drAaf9SF33g==",
+            "dependencies": {
+                "@turf/distance": "^6.5.0",
+                "@turf/helpers": "^6.5.0",
+                "@turf/intersect": "^6.5.0",
+                "@turf/invariant": "^6.5.0"
+            },
+            "funding": {
+                "url": "https://opencollective.com/turf"
+            }
+        },
+        "node_modules/@turf/interpolate": {
+            "version": "6.5.0",
+            "resolved": "https://registry.npmjs.org/@turf/interpolate/-/interpolate-6.5.0.tgz",
+            "integrity": "sha512-LSH5fMeiGyuDZ4WrDJNgh81d2DnNDUVJtuFryJFup8PV8jbs46lQGfI3r1DJ2p1IlEJIz3pmAZYeTfMMoeeohw==",
+            "dependencies": {
+                "@turf/bbox": "^6.5.0",
+                "@turf/centroid": "^6.5.0",
+                "@turf/clone": "^6.5.0",
+                "@turf/distance": "^6.5.0",
+                "@turf/helpers": "^6.5.0",
+                "@turf/hex-grid": "^6.5.0",
+                "@turf/invariant": "^6.5.0",
+                "@turf/meta": "^6.5.0",
+                "@turf/point-grid": "^6.5.0",
+                "@turf/square-grid": "^6.5.0",
+                "@turf/triangle-grid": "^6.5.0"
+            },
+            "funding": {
+                "url": "https://opencollective.com/turf"
+            }
+        },
+        "node_modules/@turf/intersect": {
+            "version": "6.5.0",
+            "resolved": "https://registry.npmjs.org/@turf/intersect/-/intersect-6.5.0.tgz",
+            "integrity": "sha512-2legGJeKrfFkzntcd4GouPugoqPUjexPZnOvfez+3SfIMrHvulw8qV8u7pfVyn2Yqs53yoVCEjS5sEpvQ5YRQg==",
+            "dependencies": {
+                "@turf/helpers": "^6.5.0",
+                "@turf/invariant": "^6.5.0",
+                "polygon-clipping": "^0.15.3"
+            },
+            "funding": {
+                "url": "https://opencollective.com/turf"
+            }
+        },
+        "node_modules/@turf/invariant": {
+            "version": "6.5.0",
+            "resolved": "https://registry.npmjs.org/@turf/invariant/-/invariant-6.5.0.tgz",
+            "integrity": "sha512-Wv8PRNCtPD31UVbdJE/KVAWKe7l6US+lJItRR/HOEW3eh+U/JwRCSUl/KZ7bmjM/C+zLNoreM2TU6OoLACs4eg==",
+            "dependencies": {
+                "@turf/helpers": "^6.5.0"
+            },
+            "funding": {
+                "url": "https://opencollective.com/turf"
+            }
+        },
+        "node_modules/@turf/isobands": {
+            "version": "6.5.0",
+            "resolved": "https://registry.npmjs.org/@turf/isobands/-/isobands-6.5.0.tgz",
+            "integrity": "sha512-4h6sjBPhRwMVuFaVBv70YB7eGz+iw0bhPRnp+8JBdX1UPJSXhoi/ZF2rACemRUr0HkdVB/a1r9gC32vn5IAEkw==",
+            "dependencies": {
+                "@turf/area": "^6.5.0",
+                "@turf/bbox": "^6.5.0",
+                "@turf/boolean-point-in-polygon": "^6.5.0",
+                "@turf/explode": "^6.5.0",
+                "@turf/helpers": "^6.5.0",
+                "@turf/invariant": "^6.5.0",
+                "@turf/meta": "^6.5.0",
+                "object-assign": "*"
+            },
+            "funding": {
+                "url": "https://opencollective.com/turf"
+            }
+        },
+        "node_modules/@turf/isolines": {
+            "version": "6.5.0",
+            "resolved": "https://registry.npmjs.org/@turf/isolines/-/isolines-6.5.0.tgz",
+            "integrity": "sha512-6ElhiLCopxWlv4tPoxiCzASWt/jMRvmp6mRYrpzOm3EUl75OhHKa/Pu6Y9nWtCMmVC/RcWtiiweUocbPLZLm0A==",
+            "dependencies": {
+                "@turf/bbox": "^6.5.0",
+                "@turf/helpers": "^6.5.0",
+                "@turf/invariant": "^6.5.0",
+                "@turf/meta": "^6.5.0",
+                "object-assign": "*"
+            },
+            "funding": {
+                "url": "https://opencollective.com/turf"
+            }
+        },
+        "node_modules/@turf/kinks": {
+            "version": "6.5.0",
+            "resolved": "https://registry.npmjs.org/@turf/kinks/-/kinks-6.5.0.tgz",
+            "integrity": "sha512-ViCngdPt1eEL7hYUHR2eHR662GvCgTc35ZJFaNR6kRtr6D8plLaDju0FILeFFWSc+o8e3fwxZEJKmFj9IzPiIQ==",
+            "dependencies": {
+                "@turf/helpers": "^6.5.0"
+            },
+            "funding": {
+                "url": "https://opencollective.com/turf"
+            }
+        },
+        "node_modules/@turf/length": {
+            "version": "6.5.0",
+            "resolved": "https://registry.npmjs.org/@turf/length/-/length-6.5.0.tgz",
+            "integrity": "sha512-5pL5/pnw52fck3oRsHDcSGrj9HibvtlrZ0QNy2OcW8qBFDNgZ4jtl6U7eATVoyWPKBHszW3dWETW+iLV7UARig==",
+            "dependencies": {
+                "@turf/distance": "^6.5.0",
+                "@turf/helpers": "^6.5.0",
+                "@turf/meta": "^6.5.0"
+            },
+            "funding": {
+                "url": "https://opencollective.com/turf"
+            }
+        },
+        "node_modules/@turf/line-arc": {
+            "version": "6.5.0",
+            "resolved": "https://registry.npmjs.org/@turf/line-arc/-/line-arc-6.5.0.tgz",
+            "integrity": "sha512-I6c+V6mIyEwbtg9P9zSFF89T7QPe1DPTG3MJJ6Cm1MrAY0MdejwQKOpsvNl8LDU2ekHOlz2kHpPVR7VJsoMllA==",
+            "dependencies": {
+                "@turf/circle": "^6.5.0",
+                "@turf/destination": "^6.5.0",
+                "@turf/helpers": "^6.5.0"
+            },
+            "funding": {
+                "url": "https://opencollective.com/turf"
+            }
+        },
+        "node_modules/@turf/line-chunk": {
+            "version": "6.5.0",
+            "resolved": "https://registry.npmjs.org/@turf/line-chunk/-/line-chunk-6.5.0.tgz",
+            "integrity": "sha512-i1FGE6YJaaYa+IJesTfyRRQZP31QouS+wh/pa6O3CC0q4T7LtHigyBSYjrbjSLfn2EVPYGlPCMFEqNWCOkC6zg==",
+            "dependencies": {
+                "@turf/helpers": "^6.5.0",
+                "@turf/length": "^6.5.0",
+                "@turf/line-slice-along": "^6.5.0",
+                "@turf/meta": "^6.5.0"
+            },
+            "funding": {
+                "url": "https://opencollective.com/turf"
+            }
+        },
+        "node_modules/@turf/line-intersect": {
+            "version": "6.5.0",
+            "resolved": "https://registry.npmjs.org/@turf/line-intersect/-/line-intersect-6.5.0.tgz",
+            "integrity": "sha512-CS6R1tZvVQD390G9Ea4pmpM6mJGPWoL82jD46y0q1KSor9s6HupMIo1kY4Ny+AEYQl9jd21V3Scz20eldpbTVA==",
+            "dependencies": {
+                "@turf/helpers": "^6.5.0",
+                "@turf/invariant": "^6.5.0",
+                "@turf/line-segment": "^6.5.0",
+                "@turf/meta": "^6.5.0",
+                "geojson-rbush": "3.x"
+            },
+            "funding": {
+                "url": "https://opencollective.com/turf"
+            }
+        },
+        "node_modules/@turf/line-offset": {
+            "version": "6.5.0",
+            "resolved": "https://registry.npmjs.org/@turf/line-offset/-/line-offset-6.5.0.tgz",
+            "integrity": "sha512-CEXZbKgyz8r72qRvPchK0dxqsq8IQBdH275FE6o4MrBkzMcoZsfSjghtXzKaz9vvro+HfIXal0sTk2mqV1lQTw==",
+            "dependencies": {
+                "@turf/helpers": "^6.5.0",
+                "@turf/invariant": "^6.5.0",
+                "@turf/meta": "^6.5.0"
+            },
+            "funding": {
+                "url": "https://opencollective.com/turf"
+            }
+        },
+        "node_modules/@turf/line-overlap": {
+            "version": "6.5.0",
+            "resolved": "https://registry.npmjs.org/@turf/line-overlap/-/line-overlap-6.5.0.tgz",
+            "integrity": "sha512-xHOaWLd0hkaC/1OLcStCpfq55lPHpPNadZySDXYiYjEz5HXr1oKmtMYpn0wGizsLwrOixRdEp+j7bL8dPt4ojQ==",
+            "dependencies": {
+                "@turf/boolean-point-on-line": "^6.5.0",
+                "@turf/helpers": "^6.5.0",
+                "@turf/invariant": "^6.5.0",
+                "@turf/line-segment": "^6.5.0",
+                "@turf/meta": "^6.5.0",
+                "@turf/nearest-point-on-line": "^6.5.0",
+                "deep-equal": "1.x",
+                "geojson-rbush": "3.x"
+            },
+            "funding": {
+                "url": "https://opencollective.com/turf"
+            }
+        },
+        "node_modules/@turf/line-segment": {
+            "version": "6.5.0",
+            "resolved": "https://registry.npmjs.org/@turf/line-segment/-/line-segment-6.5.0.tgz",
+            "integrity": "sha512-jI625Ho4jSuJESNq66Mmi290ZJ5pPZiQZruPVpmHkUw257Pew0alMmb6YrqYNnLUuiVVONxAAKXUVeeUGtycfw==",
+            "dependencies": {
+                "@turf/helpers": "^6.5.0",
+                "@turf/invariant": "^6.5.0",
+                "@turf/meta": "^6.5.0"
+            },
+            "funding": {
+                "url": "https://opencollective.com/turf"
+            }
+        },
+        "node_modules/@turf/line-slice": {
+            "version": "6.5.0",
+            "resolved": "https://registry.npmjs.org/@turf/line-slice/-/line-slice-6.5.0.tgz",
+            "integrity": "sha512-vDqJxve9tBHhOaVVFXqVjF5qDzGtKWviyjbyi2QnSnxyFAmLlLnBfMX8TLQCAf2GxHibB95RO5FBE6I2KVPRuw==",
+            "dependencies": {
+                "@turf/helpers": "^6.5.0",
+                "@turf/invariant": "^6.5.0",
+                "@turf/nearest-point-on-line": "^6.5.0"
+            },
+            "funding": {
+                "url": "https://opencollective.com/turf"
+            }
+        },
+        "node_modules/@turf/line-slice-along": {
+            "version": "6.5.0",
+            "resolved": "https://registry.npmjs.org/@turf/line-slice-along/-/line-slice-along-6.5.0.tgz",
+            "integrity": "sha512-KHJRU6KpHrAj+BTgTNqby6VCTnDzG6a1sJx/I3hNvqMBLvWVA2IrkR9L9DtsQsVY63IBwVdQDqiwCuZLDQh4Ng==",
+            "dependencies": {
+                "@turf/bearing": "^6.5.0",
+                "@turf/destination": "^6.5.0",
+                "@turf/distance": "^6.5.0",
+                "@turf/helpers": "^6.5.0"
+            },
+            "funding": {
+                "url": "https://opencollective.com/turf"
+            }
+        },
+        "node_modules/@turf/line-split": {
+            "version": "6.5.0",
+            "resolved": "https://registry.npmjs.org/@turf/line-split/-/line-split-6.5.0.tgz",
+            "integrity": "sha512-/rwUMVr9OI2ccJjw7/6eTN53URtGThNSD5I0GgxyFXMtxWiloRJ9MTff8jBbtPWrRka/Sh2GkwucVRAEakx9Sw==",
+            "dependencies": {
+                "@turf/bbox": "^6.5.0",
+                "@turf/helpers": "^6.5.0",
+                "@turf/invariant": "^6.5.0",
+                "@turf/line-intersect": "^6.5.0",
+                "@turf/line-segment": "^6.5.0",
+                "@turf/meta": "^6.5.0",
+                "@turf/nearest-point-on-line": "^6.5.0",
+                "@turf/square": "^6.5.0",
+                "@turf/truncate": "^6.5.0",
+                "geojson-rbush": "3.x"
+            },
+            "funding": {
+                "url": "https://opencollective.com/turf"
+            }
+        },
+        "node_modules/@turf/line-to-polygon": {
+            "version": "6.5.0",
+            "resolved": "https://registry.npmjs.org/@turf/line-to-polygon/-/line-to-polygon-6.5.0.tgz",
+            "integrity": "sha512-qYBuRCJJL8Gx27OwCD1TMijM/9XjRgXH/m/TyuND4OXedBpIWlK5VbTIO2gJ8OCfznBBddpjiObLBrkuxTpN4Q==",
+            "dependencies": {
+                "@turf/bbox": "^6.5.0",
+                "@turf/clone": "^6.5.0",
+                "@turf/helpers": "^6.5.0",
+                "@turf/invariant": "^6.5.0"
+            },
+            "funding": {
+                "url": "https://opencollective.com/turf"
+            }
+        },
+        "node_modules/@turf/mask": {
+            "version": "6.5.0",
+            "resolved": "https://registry.npmjs.org/@turf/mask/-/mask-6.5.0.tgz",
+            "integrity": "sha512-RQha4aU8LpBrmrkH8CPaaoAfk0Egj5OuXtv6HuCQnHeGNOQt3TQVibTA3Sh4iduq4EPxnZfDjgsOeKtrCA19lg==",
+            "dependencies": {
+                "@turf/helpers": "^6.5.0",
+                "polygon-clipping": "^0.15.3"
+            },
+            "funding": {
+                "url": "https://opencollective.com/turf"
+            }
+        },
+        "node_modules/@turf/meta": {
+            "version": "6.5.0",
+            "resolved": "https://registry.npmjs.org/@turf/meta/-/meta-6.5.0.tgz",
+            "integrity": "sha512-RrArvtsV0vdsCBegoBtOalgdSOfkBrTJ07VkpiCnq/491W67hnMWmDu7e6Ztw0C3WldRYTXkg3SumfdzZxLBHA==",
+            "dependencies": {
+                "@turf/helpers": "^6.5.0"
+            },
+            "funding": {
+                "url": "https://opencollective.com/turf"
+            }
+        },
+        "node_modules/@turf/midpoint": {
+            "version": "6.5.0",
+            "resolved": "https://registry.npmjs.org/@turf/midpoint/-/midpoint-6.5.0.tgz",
+            "integrity": "sha512-MyTzV44IwmVI6ec9fB2OgZ53JGNlgOpaYl9ArKoF49rXpL84F9rNATndbe0+MQIhdkw8IlzA6xVP4lZzfMNVCw==",
+            "dependencies": {
+                "@turf/bearing": "^6.5.0",
+                "@turf/destination": "^6.5.0",
+                "@turf/distance": "^6.5.0",
+                "@turf/helpers": "^6.5.0"
+            },
+            "funding": {
+                "url": "https://opencollective.com/turf"
+            }
+        },
+        "node_modules/@turf/moran-index": {
+            "version": "6.5.0",
+            "resolved": "https://registry.npmjs.org/@turf/moran-index/-/moran-index-6.5.0.tgz",
+            "integrity": "sha512-ItsnhrU2XYtTtTudrM8so4afBCYWNaB0Mfy28NZwLjB5jWuAsvyV+YW+J88+neK/ougKMTawkmjQqodNJaBeLQ==",
+            "dependencies": {
+                "@turf/distance-weight": "^6.5.0",
+                "@turf/helpers": "^6.5.0",
+                "@turf/meta": "^6.5.0"
+            },
+            "funding": {
+                "url": "https://opencollective.com/turf"
+            }
+        },
+        "node_modules/@turf/nearest-point": {
+            "version": "6.5.0",
+            "resolved": "https://registry.npmjs.org/@turf/nearest-point/-/nearest-point-6.5.0.tgz",
+            "integrity": "sha512-fguV09QxilZv/p94s8SMsXILIAMiaXI5PATq9d7YWijLxWUj6Q/r43kxyoi78Zmwwh1Zfqz9w+bCYUAxZ5+euA==",
+            "dependencies": {
+                "@turf/clone": "^6.5.0",
+                "@turf/distance": "^6.5.0",
+                "@turf/helpers": "^6.5.0",
+                "@turf/meta": "^6.5.0"
+            },
+            "funding": {
+                "url": "https://opencollective.com/turf"
+            }
+        },
+        "node_modules/@turf/nearest-point-on-line": {
+            "version": "6.5.0",
+            "resolved": "https://registry.npmjs.org/@turf/nearest-point-on-line/-/nearest-point-on-line-6.5.0.tgz",
+            "integrity": "sha512-WthrvddddvmymnC+Vf7BrkHGbDOUu6Z3/6bFYUGv1kxw8tiZ6n83/VG6kHz4poHOfS0RaNflzXSkmCi64fLBlg==",
+            "dependencies": {
+                "@turf/bearing": "^6.5.0",
+                "@turf/destination": "^6.5.0",
+                "@turf/distance": "^6.5.0",
+                "@turf/helpers": "^6.5.0",
+                "@turf/invariant": "^6.5.0",
+                "@turf/line-intersect": "^6.5.0",
+                "@turf/meta": "^6.5.0"
+            },
+            "funding": {
+                "url": "https://opencollective.com/turf"
+            }
+        },
+        "node_modules/@turf/nearest-point-to-line": {
+            "version": "6.5.0",
+            "resolved": "https://registry.npmjs.org/@turf/nearest-point-to-line/-/nearest-point-to-line-6.5.0.tgz",
+            "integrity": "sha512-PXV7cN0BVzUZdjj6oeb/ESnzXSfWmEMrsfZSDRgqyZ9ytdiIj/eRsnOXLR13LkTdXVOJYDBuf7xt1mLhM4p6+Q==",
+            "dependencies": {
+                "@turf/helpers": "^6.5.0",
+                "@turf/invariant": "^6.5.0",
+                "@turf/meta": "^6.5.0",
+                "@turf/point-to-line-distance": "^6.5.0",
+                "object-assign": "*"
+            },
+            "funding": {
+                "url": "https://opencollective.com/turf"
+            }
+        },
+        "node_modules/@turf/planepoint": {
+            "version": "6.5.0",
+            "resolved": "https://registry.npmjs.org/@turf/planepoint/-/planepoint-6.5.0.tgz",
+            "integrity": "sha512-R3AahA6DUvtFbka1kcJHqZ7DMHmPXDEQpbU5WaglNn7NaCQg9HB0XM0ZfqWcd5u92YXV+Gg8QhC8x5XojfcM4Q==",
+            "dependencies": {
+                "@turf/helpers": "^6.5.0",
+                "@turf/invariant": "^6.5.0"
+            },
+            "funding": {
+                "url": "https://opencollective.com/turf"
+            }
+        },
+        "node_modules/@turf/point-grid": {
+            "version": "6.5.0",
+            "resolved": "https://registry.npmjs.org/@turf/point-grid/-/point-grid-6.5.0.tgz",
+            "integrity": "sha512-Iq38lFokNNtQJnOj/RBKmyt6dlof0yhaHEDELaWHuECm1lIZLY3ZbVMwbs+nXkwTAHjKfS/OtMheUBkw+ee49w==",
+            "dependencies": {
+                "@turf/boolean-within": "^6.5.0",
+                "@turf/distance": "^6.5.0",
+                "@turf/helpers": "^6.5.0",
+                "@turf/invariant": "^6.5.0"
+            },
+            "funding": {
+                "url": "https://opencollective.com/turf"
+            }
+        },
+        "node_modules/@turf/point-on-feature": {
+            "version": "6.5.0",
+            "resolved": "https://registry.npmjs.org/@turf/point-on-feature/-/point-on-feature-6.5.0.tgz",
+            "integrity": "sha512-bDpuIlvugJhfcF/0awAQ+QI6Om1Y1FFYE8Y/YdxGRongivix850dTeXCo0mDylFdWFPGDo7Mmh9Vo4VxNwW/TA==",
+            "dependencies": {
+                "@turf/boolean-point-in-polygon": "^6.5.0",
+                "@turf/center": "^6.5.0",
+                "@turf/explode": "^6.5.0",
+                "@turf/helpers": "^6.5.0",
+                "@turf/nearest-point": "^6.5.0"
+            },
+            "funding": {
+                "url": "https://opencollective.com/turf"
+            }
+        },
+        "node_modules/@turf/point-to-line-distance": {
+            "version": "6.5.0",
+            "resolved": "https://registry.npmjs.org/@turf/point-to-line-distance/-/point-to-line-distance-6.5.0.tgz",
+            "integrity": "sha512-opHVQ4vjUhNBly1bob6RWy+F+hsZDH9SA0UW36pIRzfpu27qipU18xup0XXEePfY6+wvhF6yL/WgCO2IbrLqEA==",
+            "dependencies": {
+                "@turf/bearing": "^6.5.0",
+                "@turf/distance": "^6.5.0",
+                "@turf/helpers": "^6.5.0",
+                "@turf/invariant": "^6.5.0",
+                "@turf/meta": "^6.5.0",
+                "@turf/projection": "^6.5.0",
+                "@turf/rhumb-bearing": "^6.5.0",
+                "@turf/rhumb-distance": "^6.5.0"
+            },
+            "funding": {
+                "url": "https://opencollective.com/turf"
+            }
+        },
+        "node_modules/@turf/points-within-polygon": {
+            "version": "6.5.0",
+            "resolved": "https://registry.npmjs.org/@turf/points-within-polygon/-/points-within-polygon-6.5.0.tgz",
+            "integrity": "sha512-YyuheKqjliDsBDt3Ho73QVZk1VXX1+zIA2gwWvuz8bR1HXOkcuwk/1J76HuFMOQI3WK78wyAi+xbkx268PkQzQ==",
+            "dependencies": {
+                "@turf/boolean-point-in-polygon": "^6.5.0",
+                "@turf/helpers": "^6.5.0",
+                "@turf/meta": "^6.5.0"
+            },
+            "funding": {
+                "url": "https://opencollective.com/turf"
+            }
+        },
+        "node_modules/@turf/polygon-smooth": {
+            "version": "6.5.0",
+            "resolved": "https://registry.npmjs.org/@turf/polygon-smooth/-/polygon-smooth-6.5.0.tgz",
+            "integrity": "sha512-LO/X/5hfh/Rk4EfkDBpLlVwt3i6IXdtQccDT9rMjXEP32tRgy0VMFmdkNaXoGlSSKf/1mGqLl4y4wHd86DqKbg==",
+            "dependencies": {
+                "@turf/helpers": "^6.5.0",
+                "@turf/meta": "^6.5.0"
+            },
+            "funding": {
+                "url": "https://opencollective.com/turf"
+            }
+        },
+        "node_modules/@turf/polygon-tangents": {
+            "version": "6.5.0",
+            "resolved": "https://registry.npmjs.org/@turf/polygon-tangents/-/polygon-tangents-6.5.0.tgz",
+            "integrity": "sha512-sB4/IUqJMYRQH9jVBwqS/XDitkEfbyqRy+EH/cMRJURTg78eHunvJ708x5r6umXsbiUyQU4eqgPzEylWEQiunw==",
+            "dependencies": {
+                "@turf/bbox": "^6.5.0",
+                "@turf/boolean-within": "^6.5.0",
+                "@turf/explode": "^6.5.0",
+                "@turf/helpers": "^6.5.0",
+                "@turf/invariant": "^6.5.0",
+                "@turf/nearest-point": "^6.5.0"
+            },
+            "funding": {
+                "url": "https://opencollective.com/turf"
+            }
+        },
+        "node_modules/@turf/polygon-to-line": {
+            "version": "6.5.0",
+            "resolved": "https://registry.npmjs.org/@turf/polygon-to-line/-/polygon-to-line-6.5.0.tgz",
+            "integrity": "sha512-5p4n/ij97EIttAq+ewSnKt0ruvuM+LIDzuczSzuHTpq4oS7Oq8yqg5TQ4nzMVuK41r/tALCk7nAoBuw3Su4Gcw==",
+            "dependencies": {
+                "@turf/helpers": "^6.5.0",
+                "@turf/invariant": "^6.5.0"
+            },
+            "funding": {
+                "url": "https://opencollective.com/turf"
+            }
+        },
+        "node_modules/@turf/polygonize": {
+            "version": "6.5.0",
+            "resolved": "https://registry.npmjs.org/@turf/polygonize/-/polygonize-6.5.0.tgz",
+            "integrity": "sha512-a/3GzHRaCyzg7tVYHo43QUChCspa99oK4yPqooVIwTC61npFzdrmnywMv0S+WZjHZwK37BrFJGFrZGf6ocmY5w==",
+            "dependencies": {
+                "@turf/boolean-point-in-polygon": "^6.5.0",
+                "@turf/envelope": "^6.5.0",
+                "@turf/helpers": "^6.5.0",
+                "@turf/invariant": "^6.5.0",
+                "@turf/meta": "^6.5.0"
+            },
+            "funding": {
+                "url": "https://opencollective.com/turf"
+            }
+        },
+        "node_modules/@turf/projection": {
+            "version": "6.5.0",
+            "resolved": "https://registry.npmjs.org/@turf/projection/-/projection-6.5.0.tgz",
+            "integrity": "sha512-/Pgh9mDvQWWu8HRxqpM+tKz8OzgauV+DiOcr3FCjD6ubDnrrmMJlsf6fFJmggw93mtVPrZRL6yyi9aYCQBOIvg==",
+            "dependencies": {
+                "@turf/clone": "^6.5.0",
+                "@turf/helpers": "^6.5.0",
+                "@turf/meta": "^6.5.0"
+            },
+            "funding": {
+                "url": "https://opencollective.com/turf"
+            }
+        },
+        "node_modules/@turf/random": {
+            "version": "6.5.0",
+            "resolved": "https://registry.npmjs.org/@turf/random/-/random-6.5.0.tgz",
+            "integrity": "sha512-8Q25gQ/XbA7HJAe+eXp4UhcXM9aOOJFaxZ02+XSNwMvY8gtWSCBLVqRcW4OhqilgZ8PeuQDWgBxeo+BIqqFWFQ==",
+            "dependencies": {
+                "@turf/helpers": "^6.5.0"
+            },
+            "funding": {
+                "url": "https://opencollective.com/turf"
+            }
+        },
+        "node_modules/@turf/rectangle-grid": {
+            "version": "6.5.0",
+            "resolved": "https://registry.npmjs.org/@turf/rectangle-grid/-/rectangle-grid-6.5.0.tgz",
+            "integrity": "sha512-yQZ/1vbW68O2KsSB3OZYK+72aWz/Adnf7m2CMKcC+aq6TwjxZjAvlbCOsNUnMAuldRUVN1ph6RXMG4e9KEvKvg==",
+            "dependencies": {
+                "@turf/boolean-intersects": "^6.5.0",
+                "@turf/distance": "^6.5.0",
+                "@turf/helpers": "^6.5.0"
+            },
+            "funding": {
+                "url": "https://opencollective.com/turf"
+            }
+        },
+        "node_modules/@turf/rewind": {
+            "version": "6.5.0",
+            "resolved": "https://registry.npmjs.org/@turf/rewind/-/rewind-6.5.0.tgz",
+            "integrity": "sha512-IoUAMcHWotBWYwSYuYypw/LlqZmO+wcBpn8ysrBNbazkFNkLf3btSDZMkKJO/bvOzl55imr/Xj4fi3DdsLsbzQ==",
+            "dependencies": {
+                "@turf/boolean-clockwise": "^6.5.0",
+                "@turf/clone": "^6.5.0",
+                "@turf/helpers": "^6.5.0",
+                "@turf/invariant": "^6.5.0",
+                "@turf/meta": "^6.5.0"
+            },
+            "funding": {
+                "url": "https://opencollective.com/turf"
+            }
+        },
+        "node_modules/@turf/rhumb-bearing": {
+            "version": "6.5.0",
+            "resolved": "https://registry.npmjs.org/@turf/rhumb-bearing/-/rhumb-bearing-6.5.0.tgz",
+            "integrity": "sha512-jMyqiMRK4hzREjQmnLXmkJ+VTNTx1ii8vuqRwJPcTlKbNWfjDz/5JqJlb5NaFDcdMpftWovkW5GevfnuzHnOYA==",
+            "dependencies": {
+                "@turf/helpers": "^6.5.0",
+                "@turf/invariant": "^6.5.0"
+            },
+            "funding": {
+                "url": "https://opencollective.com/turf"
+            }
+        },
+        "node_modules/@turf/rhumb-destination": {
+            "version": "6.5.0",
+            "resolved": "https://registry.npmjs.org/@turf/rhumb-destination/-/rhumb-destination-6.5.0.tgz",
+            "integrity": "sha512-RHNP1Oy+7xTTdRrTt375jOZeHceFbjwohPHlr9Hf68VdHHPMAWgAKqiX2YgSWDcvECVmiGaBKWus1Df+N7eE4Q==",
+            "dependencies": {
+                "@turf/helpers": "^6.5.0",
+                "@turf/invariant": "^6.5.0"
+            },
+            "funding": {
+                "url": "https://opencollective.com/turf"
+            }
+        },
+        "node_modules/@turf/rhumb-distance": {
+            "version": "6.5.0",
+            "resolved": "https://registry.npmjs.org/@turf/rhumb-distance/-/rhumb-distance-6.5.0.tgz",
+            "integrity": "sha512-oKp8KFE8E4huC2Z1a1KNcFwjVOqa99isxNOwfo4g3SUABQ6NezjKDDrnvC4yI5YZ3/huDjULLBvhed45xdCrzg==",
+            "dependencies": {
+                "@turf/helpers": "^6.5.0",
+                "@turf/invariant": "^6.5.0"
+            },
+            "funding": {
+                "url": "https://opencollective.com/turf"
+            }
+        },
+        "node_modules/@turf/sample": {
+            "version": "6.5.0",
+            "resolved": "https://registry.npmjs.org/@turf/sample/-/sample-6.5.0.tgz",
+            "integrity": "sha512-kSdCwY7el15xQjnXYW520heKUrHwRvnzx8ka4eYxX9NFeOxaFITLW2G7UtXb6LJK8mmPXI8Aexv23F2ERqzGFg==",
+            "dependencies": {
+                "@turf/helpers": "^6.5.0"
+            },
+            "funding": {
+                "url": "https://opencollective.com/turf"
+            }
+        },
+        "node_modules/@turf/sector": {
+            "version": "6.5.0",
+            "resolved": "https://registry.npmjs.org/@turf/sector/-/sector-6.5.0.tgz",
+            "integrity": "sha512-cYUOkgCTWqa23SOJBqxoFAc/yGCUsPRdn/ovbRTn1zNTm/Spmk6hVB84LCKOgHqvSF25i0d2kWqpZDzLDdAPbw==",
+            "dependencies": {
+                "@turf/circle": "^6.5.0",
+                "@turf/helpers": "^6.5.0",
+                "@turf/invariant": "^6.5.0",
+                "@turf/line-arc": "^6.5.0",
+                "@turf/meta": "^6.5.0"
+            },
+            "funding": {
+                "url": "https://opencollective.com/turf"
+            }
+        },
+        "node_modules/@turf/shortest-path": {
+            "version": "6.5.0",
+            "resolved": "https://registry.npmjs.org/@turf/shortest-path/-/shortest-path-6.5.0.tgz",
+            "integrity": "sha512-4de5+G7+P4hgSoPwn+SO9QSi9HY5NEV/xRJ+cmoFVRwv2CDsuOPDheHKeuIAhKyeKDvPvPt04XYWbac4insJMg==",
+            "dependencies": {
+                "@turf/bbox": "^6.5.0",
+                "@turf/bbox-polygon": "^6.5.0",
+                "@turf/boolean-point-in-polygon": "^6.5.0",
+                "@turf/clean-coords": "^6.5.0",
+                "@turf/distance": "^6.5.0",
+                "@turf/helpers": "^6.5.0",
+                "@turf/invariant": "^6.5.0",
+                "@turf/meta": "^6.5.0",
+                "@turf/transform-scale": "^6.5.0"
+            },
+            "funding": {
+                "url": "https://opencollective.com/turf"
+            }
+        },
+        "node_modules/@turf/simplify": {
+            "version": "6.5.0",
+            "resolved": "https://registry.npmjs.org/@turf/simplify/-/simplify-6.5.0.tgz",
+            "integrity": "sha512-USas3QqffPHUY184dwQdP8qsvcVH/PWBYdXY5am7YTBACaQOMAlf6AKJs9FT8jiO6fQpxfgxuEtwmox+pBtlOg==",
+            "dependencies": {
+                "@turf/clean-coords": "^6.5.0",
+                "@turf/clone": "^6.5.0",
+                "@turf/helpers": "^6.5.0",
+                "@turf/meta": "^6.5.0"
+            },
+            "funding": {
+                "url": "https://opencollective.com/turf"
+            }
+        },
+        "node_modules/@turf/square": {
+            "version": "6.5.0",
+            "resolved": "https://registry.npmjs.org/@turf/square/-/square-6.5.0.tgz",
+            "integrity": "sha512-BM2UyWDmiuHCadVhHXKIx5CQQbNCpOxB6S/aCNOCLbhCeypKX5Q0Aosc5YcmCJgkwO5BERCC6Ee7NMbNB2vHmQ==",
+            "dependencies": {
+                "@turf/distance": "^6.5.0",
+                "@turf/helpers": "^6.5.0"
+            },
+            "funding": {
+                "url": "https://opencollective.com/turf"
+            }
+        },
+        "node_modules/@turf/square-grid": {
+            "version": "6.5.0",
+            "resolved": "https://registry.npmjs.org/@turf/square-grid/-/square-grid-6.5.0.tgz",
+            "integrity": "sha512-mlR0ayUdA+L4c9h7p4k3pX6gPWHNGuZkt2c5II1TJRmhLkW2557d6b/Vjfd1z9OVaajb1HinIs1FMSAPXuuUrA==",
+            "dependencies": {
+                "@turf/helpers": "^6.5.0",
+                "@turf/rectangle-grid": "^6.5.0"
+            },
+            "funding": {
+                "url": "https://opencollective.com/turf"
+            }
+        },
+        "node_modules/@turf/standard-deviational-ellipse": {
+            "version": "6.5.0",
+            "resolved": "https://registry.npmjs.org/@turf/standard-deviational-ellipse/-/standard-deviational-ellipse-6.5.0.tgz",
+            "integrity": "sha512-02CAlz8POvGPFK2BKK8uHGUk/LXb0MK459JVjKxLC2yJYieOBTqEbjP0qaWhiBhGzIxSMaqe8WxZ0KvqdnstHA==",
+            "dependencies": {
+                "@turf/center-mean": "^6.5.0",
+                "@turf/ellipse": "^6.5.0",
+                "@turf/helpers": "^6.5.0",
+                "@turf/invariant": "^6.5.0",
+                "@turf/meta": "^6.5.0",
+                "@turf/points-within-polygon": "^6.5.0"
+            },
+            "funding": {
+                "url": "https://opencollective.com/turf"
+            }
+        },
+        "node_modules/@turf/tag": {
+            "version": "6.5.0",
+            "resolved": "https://registry.npmjs.org/@turf/tag/-/tag-6.5.0.tgz",
+            "integrity": "sha512-XwlBvrOV38CQsrNfrxvBaAPBQgXMljeU0DV8ExOyGM7/hvuGHJw3y8kKnQ4lmEQcmcrycjDQhP7JqoRv8vFssg==",
+            "dependencies": {
+                "@turf/boolean-point-in-polygon": "^6.5.0",
+                "@turf/clone": "^6.5.0",
+                "@turf/helpers": "^6.5.0",
+                "@turf/meta": "^6.5.0"
+            },
+            "funding": {
+                "url": "https://opencollective.com/turf"
+            }
+        },
+        "node_modules/@turf/tesselate": {
+            "version": "6.5.0",
+            "resolved": "https://registry.npmjs.org/@turf/tesselate/-/tesselate-6.5.0.tgz",
+            "integrity": "sha512-M1HXuyZFCfEIIKkglh/r5L9H3c5QTEsnMBoZOFQiRnGPGmJWcaBissGb7mTFX2+DKE7FNWXh4TDnZlaLABB0dQ==",
+            "dependencies": {
+                "@turf/helpers": "^6.5.0",
+                "earcut": "^2.0.0"
+            },
+            "funding": {
+                "url": "https://opencollective.com/turf"
+            }
+        },
+        "node_modules/@turf/tin": {
+            "version": "6.5.0",
+            "resolved": "https://registry.npmjs.org/@turf/tin/-/tin-6.5.0.tgz",
+            "integrity": "sha512-YLYikRzKisfwj7+F+Tmyy/LE3d2H7D4kajajIfc9mlik2+esG7IolsX/+oUz1biguDYsG0DUA8kVYXDkobukfg==",
+            "dependencies": {
+                "@turf/helpers": "^6.5.0"
+            },
+            "funding": {
+                "url": "https://opencollective.com/turf"
+            }
+        },
+        "node_modules/@turf/transform-rotate": {
+            "version": "6.5.0",
+            "resolved": "https://registry.npmjs.org/@turf/transform-rotate/-/transform-rotate-6.5.0.tgz",
+            "integrity": "sha512-A2Ip1v4246ZmpssxpcL0hhiVBEf4L8lGnSPWTgSv5bWBEoya2fa/0SnFX9xJgP40rMP+ZzRaCN37vLHbv1Guag==",
+            "dependencies": {
+                "@turf/centroid": "^6.5.0",
+                "@turf/clone": "^6.5.0",
+                "@turf/helpers": "^6.5.0",
+                "@turf/invariant": "^6.5.0",
+                "@turf/meta": "^6.5.0",
+                "@turf/rhumb-bearing": "^6.5.0",
+                "@turf/rhumb-destination": "^6.5.0",
+                "@turf/rhumb-distance": "^6.5.0"
+            },
+            "funding": {
+                "url": "https://opencollective.com/turf"
+            }
+        },
+        "node_modules/@turf/transform-scale": {
+            "version": "6.5.0",
+            "resolved": "https://registry.npmjs.org/@turf/transform-scale/-/transform-scale-6.5.0.tgz",
+            "integrity": "sha512-VsATGXC9rYM8qTjbQJ/P7BswKWXHdnSJ35JlV4OsZyHBMxJQHftvmZJsFbOqVtQnIQIzf2OAly6rfzVV9QLr7g==",
+            "dependencies": {
+                "@turf/bbox": "^6.5.0",
+                "@turf/center": "^6.5.0",
+                "@turf/centroid": "^6.5.0",
+                "@turf/clone": "^6.5.0",
+                "@turf/helpers": "^6.5.0",
+                "@turf/invariant": "^6.5.0",
+                "@turf/meta": "^6.5.0",
+                "@turf/rhumb-bearing": "^6.5.0",
+                "@turf/rhumb-destination": "^6.5.0",
+                "@turf/rhumb-distance": "^6.5.0"
+            },
+            "funding": {
+                "url": "https://opencollective.com/turf"
+            }
+        },
+        "node_modules/@turf/transform-translate": {
+            "version": "6.5.0",
+            "resolved": "https://registry.npmjs.org/@turf/transform-translate/-/transform-translate-6.5.0.tgz",
+            "integrity": "sha512-NABLw5VdtJt/9vSstChp93pc6oel4qXEos56RBMsPlYB8hzNTEKYtC146XJvyF4twJeeYS8RVe1u7KhoFwEM5w==",
+            "dependencies": {
+                "@turf/clone": "^6.5.0",
+                "@turf/helpers": "^6.5.0",
+                "@turf/invariant": "^6.5.0",
+                "@turf/meta": "^6.5.0",
+                "@turf/rhumb-destination": "^6.5.0"
+            },
+            "funding": {
+                "url": "https://opencollective.com/turf"
+            }
+        },
+        "node_modules/@turf/triangle-grid": {
+            "version": "6.5.0",
+            "resolved": "https://registry.npmjs.org/@turf/triangle-grid/-/triangle-grid-6.5.0.tgz",
+            "integrity": "sha512-2jToUSAS1R1htq4TyLQYPTIsoy6wg3e3BQXjm2rANzw4wPQCXGOxrur1Fy9RtzwqwljlC7DF4tg0OnWr8RjmfA==",
+            "dependencies": {
+                "@turf/distance": "^6.5.0",
+                "@turf/helpers": "^6.5.0",
+                "@turf/intersect": "^6.5.0"
+            },
+            "funding": {
+                "url": "https://opencollective.com/turf"
+            }
+        },
+        "node_modules/@turf/truncate": {
+            "version": "6.5.0",
+            "resolved": "https://registry.npmjs.org/@turf/truncate/-/truncate-6.5.0.tgz",
+            "integrity": "sha512-pFxg71pLk+eJj134Z9yUoRhIi8vqnnKvCYwdT4x/DQl/19RVdq1tV3yqOT3gcTQNfniteylL5qV1uTBDV5sgrg==",
+            "dependencies": {
+                "@turf/helpers": "^6.5.0",
+                "@turf/meta": "^6.5.0"
+            },
+            "funding": {
+                "url": "https://opencollective.com/turf"
+            }
+        },
+        "node_modules/@turf/turf": {
+            "version": "6.5.0",
+            "resolved": "https://registry.npmjs.org/@turf/turf/-/turf-6.5.0.tgz",
+            "integrity": "sha512-ipMCPnhu59bh92MNt8+pr1VZQhHVuTMHklciQURo54heoxRzt1neNYZOBR6jdL+hNsbDGAECMuIpAutX+a3Y+w==",
+            "dependencies": {
+                "@turf/along": "^6.5.0",
+                "@turf/angle": "^6.5.0",
+                "@turf/area": "^6.5.0",
+                "@turf/bbox": "^6.5.0",
+                "@turf/bbox-clip": "^6.5.0",
+                "@turf/bbox-polygon": "^6.5.0",
+                "@turf/bearing": "^6.5.0",
+                "@turf/bezier-spline": "^6.5.0",
+                "@turf/boolean-clockwise": "^6.5.0",
+                "@turf/boolean-contains": "^6.5.0",
+                "@turf/boolean-crosses": "^6.5.0",
+                "@turf/boolean-disjoint": "^6.5.0",
+                "@turf/boolean-equal": "^6.5.0",
+                "@turf/boolean-intersects": "^6.5.0",
+                "@turf/boolean-overlap": "^6.5.0",
+                "@turf/boolean-parallel": "^6.5.0",
+                "@turf/boolean-point-in-polygon": "^6.5.0",
+                "@turf/boolean-point-on-line": "^6.5.0",
+                "@turf/boolean-within": "^6.5.0",
+                "@turf/buffer": "^6.5.0",
+                "@turf/center": "^6.5.0",
+                "@turf/center-mean": "^6.5.0",
+                "@turf/center-median": "^6.5.0",
+                "@turf/center-of-mass": "^6.5.0",
+                "@turf/centroid": "^6.5.0",
+                "@turf/circle": "^6.5.0",
+                "@turf/clean-coords": "^6.5.0",
+                "@turf/clone": "^6.5.0",
+                "@turf/clusters": "^6.5.0",
+                "@turf/clusters-dbscan": "^6.5.0",
+                "@turf/clusters-kmeans": "^6.5.0",
+                "@turf/collect": "^6.5.0",
+                "@turf/combine": "^6.5.0",
+                "@turf/concave": "^6.5.0",
+                "@turf/convex": "^6.5.0",
+                "@turf/destination": "^6.5.0",
+                "@turf/difference": "^6.5.0",
+                "@turf/dissolve": "^6.5.0",
+                "@turf/distance": "^6.5.0",
+                "@turf/distance-weight": "^6.5.0",
+                "@turf/ellipse": "^6.5.0",
+                "@turf/envelope": "^6.5.0",
+                "@turf/explode": "^6.5.0",
+                "@turf/flatten": "^6.5.0",
+                "@turf/flip": "^6.5.0",
+                "@turf/great-circle": "^6.5.0",
+                "@turf/helpers": "^6.5.0",
+                "@turf/hex-grid": "^6.5.0",
+                "@turf/interpolate": "^6.5.0",
+                "@turf/intersect": "^6.5.0",
+                "@turf/invariant": "^6.5.0",
+                "@turf/isobands": "^6.5.0",
+                "@turf/isolines": "^6.5.0",
+                "@turf/kinks": "^6.5.0",
+                "@turf/length": "^6.5.0",
+                "@turf/line-arc": "^6.5.0",
+                "@turf/line-chunk": "^6.5.0",
+                "@turf/line-intersect": "^6.5.0",
+                "@turf/line-offset": "^6.5.0",
+                "@turf/line-overlap": "^6.5.0",
+                "@turf/line-segment": "^6.5.0",
+                "@turf/line-slice": "^6.5.0",
+                "@turf/line-slice-along": "^6.5.0",
+                "@turf/line-split": "^6.5.0",
+                "@turf/line-to-polygon": "^6.5.0",
+                "@turf/mask": "^6.5.0",
+                "@turf/meta": "^6.5.0",
+                "@turf/midpoint": "^6.5.0",
+                "@turf/moran-index": "^6.5.0",
+                "@turf/nearest-point": "^6.5.0",
+                "@turf/nearest-point-on-line": "^6.5.0",
+                "@turf/nearest-point-to-line": "^6.5.0",
+                "@turf/planepoint": "^6.5.0",
+                "@turf/point-grid": "^6.5.0",
+                "@turf/point-on-feature": "^6.5.0",
+                "@turf/point-to-line-distance": "^6.5.0",
+                "@turf/points-within-polygon": "^6.5.0",
+                "@turf/polygon-smooth": "^6.5.0",
+                "@turf/polygon-tangents": "^6.5.0",
+                "@turf/polygon-to-line": "^6.5.0",
+                "@turf/polygonize": "^6.5.0",
+                "@turf/projection": "^6.5.0",
+                "@turf/random": "^6.5.0",
+                "@turf/rewind": "^6.5.0",
+                "@turf/rhumb-bearing": "^6.5.0",
+                "@turf/rhumb-destination": "^6.5.0",
+                "@turf/rhumb-distance": "^6.5.0",
+                "@turf/sample": "^6.5.0",
+                "@turf/sector": "^6.5.0",
+                "@turf/shortest-path": "^6.5.0",
+                "@turf/simplify": "^6.5.0",
+                "@turf/square": "^6.5.0",
+                "@turf/square-grid": "^6.5.0",
+                "@turf/standard-deviational-ellipse": "^6.5.0",
+                "@turf/tag": "^6.5.0",
+                "@turf/tesselate": "^6.5.0",
+                "@turf/tin": "^6.5.0",
+                "@turf/transform-rotate": "^6.5.0",
+                "@turf/transform-scale": "^6.5.0",
+                "@turf/transform-translate": "^6.5.0",
+                "@turf/triangle-grid": "^6.5.0",
+                "@turf/truncate": "^6.5.0",
+                "@turf/union": "^6.5.0",
+                "@turf/unkink-polygon": "^6.5.0",
+                "@turf/voronoi": "^6.5.0"
+            },
+            "funding": {
+                "url": "https://opencollective.com/turf"
+            }
+        },
+        "node_modules/@turf/union": {
+            "version": "6.5.0",
+            "resolved": "https://registry.npmjs.org/@turf/union/-/union-6.5.0.tgz",
+            "integrity": "sha512-igYWCwP/f0RFHIlC2c0SKDuM/ObBaqSljI3IdV/x71805QbIvY/BYGcJdyNcgEA6cylIGl/0VSlIbpJHZ9ldhw==",
+            "dependencies": {
+                "@turf/helpers": "^6.5.0",
+                "@turf/invariant": "^6.5.0",
+                "polygon-clipping": "^0.15.3"
+            },
+            "funding": {
+                "url": "https://opencollective.com/turf"
+            }
+        },
+        "node_modules/@turf/unkink-polygon": {
+            "version": "6.5.0",
+            "resolved": "https://registry.npmjs.org/@turf/unkink-polygon/-/unkink-polygon-6.5.0.tgz",
+            "integrity": "sha512-8QswkzC0UqKmN1DT6HpA9upfa1HdAA5n6bbuzHy8NJOX8oVizVAqfEPY0wqqTgboDjmBR4yyImsdPGUl3gZ8JQ==",
+            "dependencies": {
+                "@turf/area": "^6.5.0",
+                "@turf/boolean-point-in-polygon": "^6.5.0",
+                "@turf/helpers": "^6.5.0",
+                "@turf/meta": "^6.5.0",
+                "rbush": "^2.0.1"
+            },
+            "funding": {
+                "url": "https://opencollective.com/turf"
+            }
+        },
+        "node_modules/@turf/voronoi": {
+            "version": "6.5.0",
+            "resolved": "https://registry.npmjs.org/@turf/voronoi/-/voronoi-6.5.0.tgz",
+            "integrity": "sha512-C/xUsywYX+7h1UyNqnydHXiun4UPjK88VDghtoRypR9cLlb7qozkiLRphQxxsCM0KxyxpVPHBVQXdAL3+Yurow==",
+            "dependencies": {
+                "@turf/helpers": "^6.5.0",
+                "@turf/invariant": "^6.5.0",
+                "d3-voronoi": "1.1.2"
+            },
+            "funding": {
+                "url": "https://opencollective.com/turf"
+            }
         },
         "node_modules/@types/adm-zip": {
             "version": "0.5.5",
@@ -4415,6 +6080,14 @@
             "integrity": "sha512-OvlIYQK9tNneDlS0VN54LLd5uiPCBOp7gS5Z0f1mjoJYBrtStzgmJBxONW3U6OZqdtNzZPmn9BS/7WI7BFFcFQ==",
             "dev": true
         },
+        "node_modules/@types/mapbox-gl": {
+            "version": "2.7.19",
+            "resolved": "https://registry.npmjs.org/@types/mapbox-gl/-/mapbox-gl-2.7.19.tgz",
+            "integrity": "sha512-pkRdlhQJNbtwcKJSVC4uuOA6M3OlOObIMhNecqHB991oeaDF5XkjSIRaTE0lh5p4KClptSCxW6MBiREVRHrl2A==",
+            "dependencies": {
+                "@types/geojson": "*"
+            }
+        },
         "node_modules/@types/mdast": {
             "version": "4.0.3",
             "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.3.tgz",
@@ -5496,6 +7169,14 @@
                 "dequal": "^2.0.3"
             }
         },
+        "node_modules/arr-union": {
+            "version": "3.1.0",
+            "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz",
+            "integrity": "sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q==",
+            "engines": {
+                "node": ">=0.10.0"
+            }
+        },
         "node_modules/array-back": {
             "version": "2.0.0",
             "resolved": "https://registry.npmjs.org/array-back/-/array-back-2.0.0.tgz",
@@ -5703,6 +7384,14 @@
                 "node": "*"
             }
         },
+        "node_modules/assign-symbols": {
+            "version": "1.0.0",
+            "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz",
+            "integrity": "sha512-Q+JC7Whu8HhmTdBph/Tq59IoRtoy6KAm5zzPv00WdujX82lbAL8K7WVjne7vdCsAmbF4AYaDOPyO3k0kl8qIrw==",
+            "engines": {
+                "node": ">=0.10.0"
+            }
+        },
         "node_modules/ast-types-flow": {
             "version": "0.0.8",
             "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.8.tgz",
@@ -9255,6 +10944,23 @@
                 "node": ">= 0.8"
             }
         },
+        "node_modules/bytewise": {
+            "version": "1.1.0",
+            "resolved": "https://registry.npmjs.org/bytewise/-/bytewise-1.1.0.tgz",
+            "integrity": "sha512-rHuuseJ9iQ0na6UDhnrRVDh8YnWVlU6xM3VH6q/+yHDeUH2zIhUzP+2/h3LIrhLDBtTqzWpE3p3tP/boefskKQ==",
+            "dependencies": {
+                "bytewise-core": "^1.2.2",
+                "typewise": "^1.0.3"
+            }
+        },
+        "node_modules/bytewise-core": {
+            "version": "1.2.3",
+            "resolved": "https://registry.npmjs.org/bytewise-core/-/bytewise-core-1.2.3.tgz",
+            "integrity": "sha512-nZD//kc78OOxeYtRlVk8/zXqTB4gf/nlguL1ggWA8FuchMyOxcyHR4QPQZMUmA7czC+YnaBrPUCubqAWe50DaA==",
+            "dependencies": {
+                "typewise-core": "^1.2"
+            }
+        },
         "node_modules/cacheable-lookup": {
             "version": "7.0.0",
             "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-7.0.0.tgz",
@@ -9503,6 +11209,11 @@
                 "pnpm": ">=7"
             }
         },
+        "node_modules/cheap-ruler": {
+            "version": "3.0.2",
+            "resolved": "https://registry.npmjs.org/cheap-ruler/-/cheap-ruler-3.0.2.tgz",
+            "integrity": "sha512-02T332h1/HTN6cDSufLP8x4JzDs2+VC+8qZ/N0kWIVPyc2xUkWwWh3B2fJxR7raXkL4Mq7k554mfuM9ofv/vGg=="
+        },
         "node_modules/check-error": {
             "version": "1.0.3",
             "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz",
@@ -9920,6 +11631,35 @@
             "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
             "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="
         },
+        "node_modules/concaveman": {
+            "version": "1.2.1",
+            "resolved": "https://registry.npmjs.org/concaveman/-/concaveman-1.2.1.tgz",
+            "integrity": "sha512-PwZYKaM/ckQSa8peP5JpVr7IMJ4Nn/MHIaWUjP4be+KoZ7Botgs8seAZGpmaOM+UZXawcdYRao/px9ycrCihHw==",
+            "dependencies": {
+                "point-in-polygon": "^1.1.0",
+                "rbush": "^3.0.1",
+                "robust-predicates": "^2.0.4",
+                "tinyqueue": "^2.0.3"
+            }
+        },
+        "node_modules/concaveman/node_modules/quickselect": {
+            "version": "2.0.0",
+            "resolved": "https://registry.npmjs.org/quickselect/-/quickselect-2.0.0.tgz",
+            "integrity": "sha512-RKJ22hX8mHe3Y6wH/N3wCM6BWtjaxIyyUIkpHOvfFnxdI4yD4tBXEBKSbriGujF6jnSVkJrffuo6vxACiSSxIw=="
+        },
+        "node_modules/concaveman/node_modules/rbush": {
+            "version": "3.0.1",
+            "resolved": "https://registry.npmjs.org/rbush/-/rbush-3.0.1.tgz",
+            "integrity": "sha512-XRaVO0YecOpEuIvbhbpTrZgoiI6xBlz6hnlr6EHhd+0x9ase6EmeN+hdwwUaJvLcsFFQ8iWVF1GAK1yB0BWi0w==",
+            "dependencies": {
+                "quickselect": "^2.0.0"
+            }
+        },
+        "node_modules/concaveman/node_modules/robust-predicates": {
+            "version": "2.0.4",
+            "resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-2.0.4.tgz",
+            "integrity": "sha512-l4NwboJM74Ilm4VKfbAtFeGq7aEjWL+5kVFcmgFA2MrdnQWx9iE/tUGvxY5HyMI7o/WpSIUFLbC5fbeaHgSCYg=="
+        },
         "node_modules/confusing-browser-globals": {
             "version": "1.0.11",
             "resolved": "https://registry.npmjs.org/confusing-browser-globals/-/confusing-browser-globals-1.0.11.tgz",
@@ -10344,6 +12084,11 @@
                 "url": "https://github.com/sponsors/fb55"
             }
         },
+        "node_modules/csscolorparser": {
+            "version": "1.0.3",
+            "resolved": "https://registry.npmjs.org/csscolorparser/-/csscolorparser-1.0.3.tgz",
+            "integrity": "sha512-umPSgYwZkdFoUrH5hIq5kf0wPSXiro51nPw0j2K/c83KflkPSTBGMz6NJvMB+07VlL0y7VPo6QJcDjcgKTTm3w=="
+        },
         "node_modules/cssesc": {
             "version": "3.0.0",
             "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
@@ -10768,6 +12513,11 @@
                 "d3-selection": "2 - 3"
             }
         },
+        "node_modules/d3-voronoi": {
+            "version": "1.1.2",
+            "resolved": "https://registry.npmjs.org/d3-voronoi/-/d3-voronoi-1.1.2.tgz",
+            "integrity": "sha512-RhGS1u2vavcO7ay7ZNAPo4xeDh/VYeGof3x5ZLJBQgYhLegxr3s5IykvWmJ94FTU6mcbtp4sloqZ54mP6R4Utw=="
+        },
         "node_modules/d3-zoom": {
             "version": "3.0.0",
             "resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-3.0.0.tgz",
@@ -10932,6 +12682,25 @@
                 "node": ">=6"
             }
         },
+        "node_modules/deep-equal": {
+            "version": "1.1.2",
+            "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.2.tgz",
+            "integrity": "sha512-5tdhKF6DbU7iIzrIOa1AOUt39ZRm13cmL1cGEh//aqR8x9+tNfbywRf0n5FD/18OKMdo7DNEtrX2t22ZAkI+eg==",
+            "dependencies": {
+                "is-arguments": "^1.1.1",
+                "is-date-object": "^1.0.5",
+                "is-regex": "^1.1.4",
+                "object-is": "^1.1.5",
+                "object-keys": "^1.1.1",
+                "regexp.prototype.flags": "^1.5.1"
+            },
+            "engines": {
+                "node": ">= 0.4"
+            },
+            "funding": {
+                "url": "https://github.com/sponsors/ljharb"
+            }
+        },
         "node_modules/deep-extend": {
             "version": "0.6.0",
             "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
@@ -11126,7 +12895,6 @@
             "version": "1.2.1",
             "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz",
             "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==",
-            "dev": true,
             "dependencies": {
                 "define-data-property": "^1.0.1",
                 "has-property-descriptors": "^1.0.0",
@@ -11160,6 +12928,11 @@
             "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz",
             "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ=="
         },
+        "node_modules/density-clustering": {
+            "version": "1.3.0",
+            "resolved": "https://registry.npmjs.org/density-clustering/-/density-clustering-1.3.0.tgz",
+            "integrity": "sha512-icpmBubVTwLnsaor9qH/4tG5+7+f61VcqMN3V3pm9sxxSCt2Jcs0zWOgwZW9ARJYaKD3FumIgHiMOcIMRRAzFQ=="
+        },
         "node_modules/depcheck": {
             "version": "1.4.7",
             "resolved": "https://registry.npmjs.org/depcheck/-/depcheck-1.4.7.tgz",
@@ -11465,6 +13238,11 @@
                 "xtend": "^4.0.0"
             }
         },
+        "node_modules/earcut": {
+            "version": "2.2.4",
+            "resolved": "https://registry.npmjs.org/earcut/-/earcut-2.2.4.tgz",
+            "integrity": "sha512-/pjZsA1b4RPHbeWZQn66SWS8nZZWLQQ23oE3Eam7aroEFGEvwKAsJfZ9ytiEMycfzXWpca4FA9QIOehf7PocBQ=="
+        },
         "node_modules/eastasianwidth": {
             "version": "0.2.0",
             "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
@@ -13674,6 +15452,17 @@
             "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
             "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="
         },
+        "node_modules/extend-shallow": {
+            "version": "2.0.1",
+            "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+            "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==",
+            "dependencies": {
+                "is-extendable": "^0.1.0"
+            },
+            "engines": {
+                "node": ">=0.10.0"
+            }
+        },
         "node_modules/external-editor": {
             "version": "3.1.0",
             "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz",
@@ -14601,7 +16390,6 @@
             "version": "1.2.3",
             "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz",
             "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==",
-            "dev": true,
             "funding": {
                 "url": "https://github.com/sponsors/ljharb"
             }
@@ -14701,6 +16489,49 @@
                 "node": ">=6.9.0"
             }
         },
+        "node_modules/geojson-equality": {
+            "version": "0.1.6",
+            "resolved": "https://registry.npmjs.org/geojson-equality/-/geojson-equality-0.1.6.tgz",
+            "integrity": "sha512-TqG8YbqizP3EfwP5Uw4aLu6pKkg6JQK9uq/XZ1lXQntvTHD1BBKJWhNpJ2M0ax6TuWMP3oyx6Oq7FCIfznrgpQ==",
+            "dependencies": {
+                "deep-equal": "^1.0.0"
+            }
+        },
+        "node_modules/geojson-rbush": {
+            "version": "3.2.0",
+            "resolved": "https://registry.npmjs.org/geojson-rbush/-/geojson-rbush-3.2.0.tgz",
+            "integrity": "sha512-oVltQTXolxvsz1sZnutlSuLDEcQAKYC/uXt9zDzJJ6bu0W+baTI8LZBaTup5afzibEH4N3jlq2p+a152wlBJ7w==",
+            "dependencies": {
+                "@turf/bbox": "*",
+                "@turf/helpers": "6.x",
+                "@turf/meta": "6.x",
+                "@types/geojson": "7946.0.8",
+                "rbush": "^3.0.1"
+            }
+        },
+        "node_modules/geojson-rbush/node_modules/@types/geojson": {
+            "version": "7946.0.8",
+            "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.8.tgz",
+            "integrity": "sha512-1rkryxURpr6aWP7R786/UQOkJ3PcpQiWkAXBmdWc7ryFWqN6a4xfK7BtjXvFBKO9LjQ+MWQSWxYeZX1OApnArA=="
+        },
+        "node_modules/geojson-rbush/node_modules/quickselect": {
+            "version": "2.0.0",
+            "resolved": "https://registry.npmjs.org/quickselect/-/quickselect-2.0.0.tgz",
+            "integrity": "sha512-RKJ22hX8mHe3Y6wH/N3wCM6BWtjaxIyyUIkpHOvfFnxdI4yD4tBXEBKSbriGujF6jnSVkJrffuo6vxACiSSxIw=="
+        },
+        "node_modules/geojson-rbush/node_modules/rbush": {
+            "version": "3.0.1",
+            "resolved": "https://registry.npmjs.org/rbush/-/rbush-3.0.1.tgz",
+            "integrity": "sha512-XRaVO0YecOpEuIvbhbpTrZgoiI6xBlz6hnlr6EHhd+0x9ase6EmeN+hdwwUaJvLcsFFQ8iWVF1GAK1yB0BWi0w==",
+            "dependencies": {
+                "quickselect": "^2.0.0"
+            }
+        },
+        "node_modules/geojson-vt": {
+            "version": "3.2.1",
+            "resolved": "https://registry.npmjs.org/geojson-vt/-/geojson-vt-3.2.1.tgz",
+            "integrity": "sha512-EvGQQi/zPrDA6zr6BnJD/YhwAkBP8nnJ9emh3EnHQKVMfg/MRVtPbMYdgVy/IaEmn4UfagD2a6fafPDL5hbtwg=="
+        },
         "node_modules/get-caller-file": {
             "version": "2.0.5",
             "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
@@ -14780,6 +16611,14 @@
                 "url": "https://github.com/sponsors/ljharb"
             }
         },
+        "node_modules/get-value": {
+            "version": "2.0.6",
+            "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz",
+            "integrity": "sha512-Ln0UQDlxH1BapMu3GPtf7CuYNwRZf2gwCuPqbyG6pB8WfmFpzqcy4xtAaAMUhnNqjMKTiCPZG2oMT3YSx8U2NA==",
+            "engines": {
+                "node": ">=0.10.0"
+            }
+        },
         "node_modules/getpass": {
             "version": "0.1.7",
             "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz",
@@ -14797,6 +16636,11 @@
                 "omggif": "^1.0.10"
             }
         },
+        "node_modules/gl-matrix": {
+            "version": "3.4.3",
+            "resolved": "https://registry.npmjs.org/gl-matrix/-/gl-matrix-3.4.3.tgz",
+            "integrity": "sha512-wcCp8vu8FT22BnvKVPjXa/ICBWRq/zjFfdofZy1WSpQZpphblv12/bOQLBC1rMM7SGOFS9ltVmKOHil5+Ml7gA=="
+        },
         "node_modules/glob": {
             "version": "8.1.0",
             "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz",
@@ -15034,6 +16878,11 @@
             "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==",
             "dev": true
         },
+        "node_modules/grid-index": {
+            "version": "1.1.0",
+            "resolved": "https://registry.npmjs.org/grid-index/-/grid-index-1.1.0.tgz",
+            "integrity": "sha512-HZRwumpOGUrHyxO5bqKZL0B0GlUpwtCAzZ42sgxUPniu33R1LSFH5yrIcBCHjkctCAh3mtWKcKd9J4vDDdeVHA=="
+        },
         "node_modules/gtoken": {
             "version": "7.0.1",
             "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-7.0.1.tgz",
@@ -16501,7 +18350,6 @@
             "version": "1.0.5",
             "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz",
             "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==",
-            "dev": true,
             "dependencies": {
                 "has-tostringtag": "^1.0.0"
             },
@@ -16556,6 +18404,14 @@
                 "node": ">=0.4.0"
             }
         },
+        "node_modules/is-extendable": {
+            "version": "0.1.1",
+            "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz",
+            "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==",
+            "engines": {
+                "node": ">=0.10.0"
+            }
+        },
         "node_modules/is-extglob": {
             "version": "2.1.1",
             "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
@@ -17235,6 +19091,11 @@
             "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==",
             "dev": true
         },
+        "node_modules/json-stringify-pretty-compact": {
+            "version": "3.0.0",
+            "resolved": "https://registry.npmjs.org/json-stringify-pretty-compact/-/json-stringify-pretty-compact-3.0.0.tgz",
+            "integrity": "sha512-Rc2suX5meI0S3bfdZuA7JMFBGkJ875ApfVyq2WHELjBiiG22My/l7/8zPpH/CfFVQHuVLd8NLR0nv6vi0BYYKA=="
+        },
         "node_modules/json-stringify-safe": {
             "version": "5.0.1",
             "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
@@ -17916,6 +19777,41 @@
             "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==",
             "dev": true
         },
+        "node_modules/mapbox-gl": {
+            "version": "3.0.1",
+            "resolved": "https://registry.npmjs.org/mapbox-gl/-/mapbox-gl-3.0.1.tgz",
+            "integrity": "sha512-o7C6sAlj6Hkdd4xQVEgQflgJYNYyZOAtYahhIOb9m8chI8umtWcCp8Ie0iGLYJvce1WHRMa3WGzs69ggwuWlDA==",
+            "dependencies": {
+                "@mapbox/geojson-rewind": "^0.5.2",
+                "@mapbox/jsonlint-lines-primitives": "^2.0.2",
+                "@mapbox/mapbox-gl-supported": "^2.0.1",
+                "@mapbox/point-geometry": "^0.1.0",
+                "@mapbox/tiny-sdf": "^2.0.6",
+                "@mapbox/unitbezier": "^0.0.1",
+                "@mapbox/vector-tile": "^1.3.1",
+                "@mapbox/whoots-js": "^3.1.0",
+                "cheap-ruler": "^3.0.1",
+                "csscolorparser": "~1.0.3",
+                "earcut": "^2.2.4",
+                "geojson-vt": "^3.2.1",
+                "gl-matrix": "^3.4.3",
+                "grid-index": "^1.1.0",
+                "kdbush": "^4.0.1",
+                "murmurhash-js": "^1.0.0",
+                "pbf": "^3.2.1",
+                "potpack": "^2.0.0",
+                "quickselect": "^2.0.0",
+                "rw": "^1.3.3",
+                "supercluster": "^8.0.0",
+                "tinyqueue": "^2.0.3",
+                "vt-pbf": "^3.1.3"
+            }
+        },
+        "node_modules/mapbox-gl/node_modules/quickselect": {
+            "version": "2.0.0",
+            "resolved": "https://registry.npmjs.org/quickselect/-/quickselect-2.0.0.tgz",
+            "integrity": "sha512-RKJ22hX8mHe3Y6wH/N3wCM6BWtjaxIyyUIkpHOvfFnxdI4yD4tBXEBKSbriGujF6jnSVkJrffuo6vxACiSSxIw=="
+        },
         "node_modules/markdown-table": {
             "version": "3.0.3",
             "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-3.0.3.tgz",
@@ -19479,6 +21375,11 @@
                 "node": "*"
             }
         },
+        "node_modules/murmurhash-js": {
+            "version": "1.0.0",
+            "resolved": "https://registry.npmjs.org/murmurhash-js/-/murmurhash-js-1.0.0.tgz",
+            "integrity": "sha512-TvmkNhkv8yct0SVBSy+o8wYzXjE4Zz3PCesbfs8HiCXXdcTuocApFv11UWlNFWKYsP2okqrhb7JNlSm9InBhIw=="
+        },
         "node_modules/mute-stream": {
             "version": "0.0.8",
             "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz",
@@ -22598,11 +24499,25 @@
                 "url": "https://github.com/sponsors/ljharb"
             }
         },
+        "node_modules/object-is": {
+            "version": "1.1.5",
+            "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz",
+            "integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==",
+            "dependencies": {
+                "call-bind": "^1.0.2",
+                "define-properties": "^1.1.3"
+            },
+            "engines": {
+                "node": ">= 0.4"
+            },
+            "funding": {
+                "url": "https://github.com/sponsors/ljharb"
+            }
+        },
         "node_modules/object-keys": {
             "version": "1.1.1",
             "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
             "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==",
-            "dev": true,
             "engines": {
                 "node": ">= 0.4"
             }
@@ -23300,6 +25215,18 @@
             "resolved": "https://registry.npmjs.org/pause/-/pause-0.0.1.tgz",
             "integrity": "sha512-KG8UEiEVkR3wGEb4m5yZkVCzigAD+cVEJck2CzYZO37ZGJfctvVptVO192MwrtPhzONn6go8ylnOdMhKqi4nfg=="
         },
+        "node_modules/pbf": {
+            "version": "3.2.1",
+            "resolved": "https://registry.npmjs.org/pbf/-/pbf-3.2.1.tgz",
+            "integrity": "sha512-ClrV7pNOn7rtmoQVF4TS1vyU0WhYRnP92fzbfF75jAIwpnzdJXf8iTd4CMEqO4yUenH6NDqLiwjqlh6QgZzgLQ==",
+            "dependencies": {
+                "ieee754": "^1.1.12",
+                "resolve-protobuf-schema": "^2.1.0"
+            },
+            "bin": {
+                "pbf": "bin/pbf"
+            }
+        },
         "node_modules/pdf-parse": {
             "version": "1.1.1",
             "resolved": "https://registry.npmjs.org/pdf-parse/-/pdf-parse-1.1.1.tgz",
@@ -23531,6 +25458,19 @@
                 "node": ">=12.13.0"
             }
         },
+        "node_modules/point-in-polygon": {
+            "version": "1.1.0",
+            "resolved": "https://registry.npmjs.org/point-in-polygon/-/point-in-polygon-1.1.0.tgz",
+            "integrity": "sha512-3ojrFwjnnw8Q9242TzgXuTD+eKiutbzyslcq1ydfu82Db2y+Ogbmyrkpv0Hgj31qwT3lbS9+QAAO/pIQM35XRw=="
+        },
+        "node_modules/polygon-clipping": {
+            "version": "0.15.3",
+            "resolved": "https://registry.npmjs.org/polygon-clipping/-/polygon-clipping-0.15.3.tgz",
+            "integrity": "sha512-ho0Xx5DLkgxRx/+n4O74XyJ67DcyN3Tu9bGYKsnTukGAW6ssnuak6Mwcyb1wHy9MZc9xsUWqIoiazkZB5weECg==",
+            "dependencies": {
+                "splaytree": "^3.1.0"
+            }
+        },
         "node_modules/postcss": {
             "version": "8.4.32",
             "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.32.tgz",
@@ -23647,6 +25587,11 @@
                 "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
             }
         },
+        "node_modules/potpack": {
+            "version": "2.0.0",
+            "resolved": "https://registry.npmjs.org/potpack/-/potpack-2.0.0.tgz",
+            "integrity": "sha512-Q+/tYsFU9r7xoOJ+y/ZTtdVQwTWfzjbiXBDMM/JKUux3+QPP02iUuIoeBQ+Ot6oEDlC+/PGjB/5A3K7KKb7hcw=="
+        },
         "node_modules/prelude-ls": {
             "version": "1.2.1",
             "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
@@ -23856,6 +25801,11 @@
                 "prosemirror-transform": "^1.1.0"
             }
         },
+        "node_modules/protocol-buffers-schema": {
+            "version": "3.6.0",
+            "resolved": "https://registry.npmjs.org/protocol-buffers-schema/-/protocol-buffers-schema-3.6.0.tgz",
+            "integrity": "sha512-TdDRD+/QNdrCGCE7v8340QyuXd4kIWIgapsE2+n/SaGiSSbomYl4TjHlvIoCWRpE7wFt02EpB35VVA2ImcBVqw=="
+        },
         "node_modules/proxy-addr": {
             "version": "2.0.7",
             "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
@@ -24100,6 +26050,11 @@
                 "url": "https://github.com/sponsors/sindresorhus"
             }
         },
+        "node_modules/quickselect": {
+            "version": "1.1.1",
+            "resolved": "https://registry.npmjs.org/quickselect/-/quickselect-1.1.1.tgz",
+            "integrity": "sha512-qN0Gqdw4c4KGPsBOQafj6yj/PA6c/L63f6CaZ/DCF/xF4Esu3jVmKLUDYxghFx8Kb/O7y9tI7x2RjTSXwdK1iQ=="
+        },
         "node_modules/random-bytes": {
             "version": "1.0.0",
             "resolved": "https://registry.npmjs.org/random-bytes/-/random-bytes-1.0.0.tgz",
@@ -24174,6 +26129,14 @@
                 "url": "https://opencollective.com/webpack"
             }
         },
+        "node_modules/rbush": {
+            "version": "2.0.2",
+            "resolved": "https://registry.npmjs.org/rbush/-/rbush-2.0.2.tgz",
+            "integrity": "sha512-XBOuALcTm+O/H8G90b6pzu6nX6v2zCKiFG4BJho8a+bY6AER6t8uQUZdi5bomQc0AprCWhEGa7ncAbbRap0bRA==",
+            "dependencies": {
+                "quickselect": "^1.0.1"
+            }
+        },
         "node_modules/rc-switch": {
             "version": "4.1.0",
             "resolved": "https://registry.npmjs.org/rc-switch/-/rc-switch-4.1.0.tgz",
@@ -24410,6 +26373,29 @@
                 "react": ">=0.14.0"
             }
         },
+        "node_modules/react-map-gl": {
+            "version": "7.1.6",
+            "resolved": "https://registry.npmjs.org/react-map-gl/-/react-map-gl-7.1.6.tgz",
+            "integrity": "sha512-9XbrvpFF67Fyi+e6vRLJFnGpo3UF6ZHifIa8cS/wUYSsnv9sVyzGsN++FJy57zkz3Jh3kmf0xKZemR8K0FZLVw==",
+            "dependencies": {
+                "@maplibre/maplibre-gl-style-spec": "^19.2.1",
+                "@types/mapbox-gl": ">=1.0.0"
+            },
+            "peerDependencies": {
+                "mapbox-gl": ">=1.13.0",
+                "maplibre-gl": ">=1.13.0",
+                "react": ">=16.3.0",
+                "react-dom": ">=16.3.0"
+            },
+            "peerDependenciesMeta": {
+                "mapbox-gl": {
+                    "optional": true
+                },
+                "maplibre-gl": {
+                    "optional": true
+                }
+            }
+        },
         "node_modules/react-markdown": {
             "version": "9.0.1",
             "resolved": "https://registry.npmjs.org/react-markdown/-/react-markdown-9.0.1.tgz",
@@ -24775,7 +26761,6 @@
             "version": "1.5.1",
             "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.1.tgz",
             "integrity": "sha512-sy6TXMN+hnP/wMy+ISxg3krXx7BAtWVO4UouuCN/ziM9UEne0euamVNafDfvC83bRNr95y0V5iijeDQFUNpvrg==",
-            "dev": true,
             "dependencies": {
                 "call-bind": "^1.0.2",
                 "define-properties": "^1.2.0",
@@ -25197,6 +27182,14 @@
                 "node": ">=8"
             }
         },
+        "node_modules/resolve-protobuf-schema": {
+            "version": "2.1.0",
+            "resolved": "https://registry.npmjs.org/resolve-protobuf-schema/-/resolve-protobuf-schema-2.1.0.tgz",
+            "integrity": "sha512-kI5ffTiZWmJaS/huM8wZfEMer1eRd7oJQhDuxeCLe3t7N7mX3z94CN0xPxBQxFYQTSNz9T0i+v6inKqSdK8xrQ==",
+            "dependencies": {
+                "protocol-buffers-schema": "^3.3.1"
+            }
+        },
         "node_modules/responselike": {
             "version": "3.0.0",
             "resolved": "https://registry.npmjs.org/responselike/-/responselike-3.0.0.tgz",
@@ -25913,7 +27906,6 @@
             "version": "2.0.1",
             "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.1.tgz",
             "integrity": "sha512-tMNCiqYVkXIZgc2Hnoy2IvC/f8ezc5koaRFkCjrpWzGpCd3qbZXPzVy9MAZzK1ch/X0jvSkojys3oqJN0qCmdA==",
-            "dev": true,
             "dependencies": {
                 "define-data-property": "^1.0.1",
                 "functions-have-names": "^1.2.3",
@@ -25923,6 +27915,20 @@
                 "node": ">= 0.4"
             }
         },
+        "node_modules/set-value": {
+            "version": "2.0.1",
+            "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz",
+            "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==",
+            "dependencies": {
+                "extend-shallow": "^2.0.1",
+                "is-extendable": "^0.1.1",
+                "is-plain-object": "^2.0.3",
+                "split-string": "^3.0.1"
+            },
+            "engines": {
+                "node": ">=0.10.0"
+            }
+        },
         "node_modules/setimmediate": {
             "version": "1.0.5",
             "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz",
@@ -26165,6 +28171,11 @@
             "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
             "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
         },
+        "node_modules/skmeans": {
+            "version": "0.9.7",
+            "resolved": "https://registry.npmjs.org/skmeans/-/skmeans-0.9.7.tgz",
+            "integrity": "sha512-hNj1/oZ7ygsfmPZ7ZfN5MUBRoGg1gtpnImuJBgLO0ljQ67DtJuiQaiYdS4lUA6s0KCwnPhGivtC/WRwIZLkHyg=="
+        },
         "node_modules/slice-ansi": {
             "version": "2.1.0",
             "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz",
@@ -26279,6 +28290,38 @@
                 "uuid": "dist/bin/uuid"
             }
         },
+        "node_modules/sort-asc": {
+            "version": "0.2.0",
+            "resolved": "https://registry.npmjs.org/sort-asc/-/sort-asc-0.2.0.tgz",
+            "integrity": "sha512-umMGhjPeHAI6YjABoSTrFp2zaBtXBej1a0yKkuMUyjjqu6FJsTF+JYwCswWDg+zJfk/5npWUUbd33HH/WLzpaA==",
+            "engines": {
+                "node": ">=0.10.0"
+            }
+        },
+        "node_modules/sort-desc": {
+            "version": "0.2.0",
+            "resolved": "https://registry.npmjs.org/sort-desc/-/sort-desc-0.2.0.tgz",
+            "integrity": "sha512-NqZqyvL4VPW+RAxxXnB8gvE1kyikh8+pR+T+CXLksVRN9eiQqkQlPwqWYU0mF9Jm7UnctShlxLyAt1CaBOTL1w==",
+            "engines": {
+                "node": ">=0.10.0"
+            }
+        },
+        "node_modules/sort-object": {
+            "version": "3.0.3",
+            "resolved": "https://registry.npmjs.org/sort-object/-/sort-object-3.0.3.tgz",
+            "integrity": "sha512-nK7WOY8jik6zaG9CRwZTaD5O7ETWDLZYMM12pqY8htll+7dYeqGfEUPcUBHOpSJg2vJOrvFIY2Dl5cX2ih1hAQ==",
+            "dependencies": {
+                "bytewise": "^1.1.0",
+                "get-value": "^2.0.2",
+                "is-extendable": "^0.1.1",
+                "sort-asc": "^0.2.0",
+                "sort-desc": "^0.2.0",
+                "union-value": "^1.0.1"
+            },
+            "engines": {
+                "node": ">=0.10.0"
+            }
+        },
         "node_modules/source-map": {
             "version": "0.5.7",
             "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
@@ -26359,6 +28402,11 @@
                 "wbuf": "^1.7.3"
             }
         },
+        "node_modules/splaytree": {
+            "version": "3.1.2",
+            "resolved": "https://registry.npmjs.org/splaytree/-/splaytree-3.1.2.tgz",
+            "integrity": "sha512-4OM2BJgC5UzrhVnnJA4BkHKGtjXNzzUfpQjCO8I05xYPsfS/VuQDwjCGGMi8rYQilHEV4j8NBqTFbls/PZEE7A=="
+        },
         "node_modules/split-on-first": {
             "version": "1.1.0",
             "resolved": "https://registry.npmjs.org/split-on-first/-/split-on-first-1.1.0.tgz",
@@ -26372,6 +28420,40 @@
             "resolved": "https://registry.npmjs.org/split-skip/-/split-skip-0.0.2.tgz",
             "integrity": "sha512-weHOi8BolsDnGIwhhWHbA+wKSuSpvWwjRrdj8SdbIIis2vSwOE37CQP8x3EleuzxanUr3AK8BdUy4MkiOULPZg=="
         },
+        "node_modules/split-string": {
+            "version": "3.1.0",
+            "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz",
+            "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==",
+            "dependencies": {
+                "extend-shallow": "^3.0.0"
+            },
+            "engines": {
+                "node": ">=0.10.0"
+            }
+        },
+        "node_modules/split-string/node_modules/extend-shallow": {
+            "version": "3.0.2",
+            "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz",
+            "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==",
+            "dependencies": {
+                "assign-symbols": "^1.0.0",
+                "is-extendable": "^1.0.1"
+            },
+            "engines": {
+                "node": ">=0.10.0"
+            }
+        },
+        "node_modules/split-string/node_modules/is-extendable": {
+            "version": "1.0.1",
+            "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz",
+            "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==",
+            "dependencies": {
+                "is-plain-object": "^2.0.4"
+            },
+            "engines": {
+                "node": ">=0.10.0"
+            }
+        },
         "node_modules/sprintf-js": {
             "version": "1.0.3",
             "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
@@ -27034,7 +29116,8 @@
         "node_modules/text-table": {
             "version": "0.2.0",
             "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
-            "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw=="
+            "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==",
+            "dev": true
         },
         "node_modules/textarea-caret": {
             "version": "3.1.0",
@@ -27073,6 +29156,11 @@
             "resolved": "https://registry.npmjs.org/tinycolor2/-/tinycolor2-1.6.0.tgz",
             "integrity": "sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw=="
         },
+        "node_modules/tinyqueue": {
+            "version": "2.0.3",
+            "resolved": "https://registry.npmjs.org/tinyqueue/-/tinyqueue-2.0.3.tgz",
+            "integrity": "sha512-ppJZNDuKGgxzkHihX8v9v9G5f+18gzaTfrukGrq6ueg0lmH4nqVnA2IPG0AEH3jKEk2GRJCUhDoqpoiw3PHLBA=="
+        },
         "node_modules/titleize": {
             "version": "3.0.0",
             "resolved": "https://registry.npmjs.org/titleize/-/titleize-3.0.0.tgz",
@@ -27145,6 +29233,40 @@
                 "url": "https://github.com/sponsors/Borewit"
             }
         },
+        "node_modules/topojson-client": {
+            "version": "3.1.0",
+            "resolved": "https://registry.npmjs.org/topojson-client/-/topojson-client-3.1.0.tgz",
+            "integrity": "sha512-605uxS6bcYxGXw9qi62XyrV6Q3xwbndjachmNxu8HWTtVPxZfEJN9fd/SZS1Q54Sn2y0TMyMxFj/cJINqGHrKw==",
+            "dependencies": {
+                "commander": "2"
+            },
+            "bin": {
+                "topo2geo": "bin/topo2geo",
+                "topomerge": "bin/topomerge",
+                "topoquantize": "bin/topoquantize"
+            }
+        },
+        "node_modules/topojson-client/node_modules/commander": {
+            "version": "2.20.3",
+            "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
+            "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ=="
+        },
+        "node_modules/topojson-server": {
+            "version": "3.0.1",
+            "resolved": "https://registry.npmjs.org/topojson-server/-/topojson-server-3.0.1.tgz",
+            "integrity": "sha512-/VS9j/ffKr2XAOjlZ9CgyyeLmgJ9dMwq6Y0YEON8O7p/tGGk+dCWnrE03zEdu7i4L7YsFZLEPZPzCvcB7lEEXw==",
+            "dependencies": {
+                "commander": "2"
+            },
+            "bin": {
+                "geo2topo": "bin/geo2topo"
+            }
+        },
+        "node_modules/topojson-server/node_modules/commander": {
+            "version": "2.20.3",
+            "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
+            "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ=="
+        },
         "node_modules/touch": {
             "version": "3.1.0",
             "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz",
@@ -27820,6 +29942,11 @@
                 "node": "*"
             }
         },
+        "node_modules/turf-jsts": {
+            "version": "1.2.3",
+            "resolved": "https://registry.npmjs.org/turf-jsts/-/turf-jsts-1.2.3.tgz",
+            "integrity": "sha512-Ja03QIJlPuHt4IQ2FfGex4F4JAr8m3jpaHbFbQrgwr7s7L6U8ocrHiF3J1+wf9jzhGKxvDeaCAnGDot8OjGFyA=="
+        },
         "node_modules/tweetnacl": {
             "version": "0.14.5",
             "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
@@ -27963,6 +30090,19 @@
                 "node": ">=18"
             }
         },
+        "node_modules/typewise": {
+            "version": "1.0.3",
+            "resolved": "https://registry.npmjs.org/typewise/-/typewise-1.0.3.tgz",
+            "integrity": "sha512-aXofE06xGhaQSPzt8hlTY+/YWQhm9P0jYUp1f2XtmW/3Bk0qzXcyFWAtPoo2uTGQj1ZwbDuSyuxicq+aDo8lCQ==",
+            "dependencies": {
+                "typewise-core": "^1.2.0"
+            }
+        },
+        "node_modules/typewise-core": {
+            "version": "1.2.0",
+            "resolved": "https://registry.npmjs.org/typewise-core/-/typewise-core-1.2.0.tgz",
+            "integrity": "sha512-2SCC/WLzj2SbUwzFOzqMCkz5amXLlxtJqDKTICqg30x+2DZxcfZN2MvQZmGfXWKNWaKK9pBPsvkcwv8bF/gxKg=="
+        },
         "node_modules/typical": {
             "version": "2.6.1",
             "resolved": "https://registry.npmjs.org/typical/-/typical-2.6.1.tgz",
@@ -28082,6 +30222,20 @@
             "resolved": "https://registry.npmjs.org/uninstall/-/uninstall-0.0.0.tgz",
             "integrity": "sha512-pjP/0+A4gsbDVa8XH/S2GZdT9NPJW8NFMy3GI7HnsWG+NAmFSSj3QidNosXBI9cPtxxNExEDdhKFO6sli8K3mA=="
         },
+        "node_modules/union-value": {
+            "version": "1.0.1",
+            "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz",
+            "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==",
+            "dependencies": {
+                "arr-union": "^3.1.0",
+                "get-value": "^2.0.6",
+                "is-extendable": "^0.1.1",
+                "set-value": "^2.0.1"
+            },
+            "engines": {
+                "node": ">=0.10.0"
+            }
+        },
         "node_modules/unist-util-is": {
             "version": "6.0.0",
             "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.0.tgz",
@@ -28509,6 +30663,16 @@
                 "node": ">=0.10.0"
             }
         },
+        "node_modules/vt-pbf": {
+            "version": "3.1.3",
+            "resolved": "https://registry.npmjs.org/vt-pbf/-/vt-pbf-3.1.3.tgz",
+            "integrity": "sha512-2LzDFzt0mZKZ9IpVF2r69G9bXaP2Q2sArJCmcCgvfTdCCZzSyz4aCLoQyUilu37Ll56tCblIZrXFIjNUpGIlmA==",
+            "dependencies": {
+                "@mapbox/point-geometry": "0.1.0",
+                "@mapbox/vector-tile": "^1.3.1",
+                "pbf": "^3.2.1"
+            }
+        },
         "node_modules/w3c-keyname": {
             "version": "2.2.8",
             "resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.8.tgz",
diff --git a/package.json b/package.json
index fa0dc3ff5..98453a651 100644
--- a/package.json
+++ b/package.json
@@ -109,6 +109,7 @@
         "@mui/material": "^5.14.19",
         "@octokit/core": "^5.0.2",
         "@react-google-maps/api": "^2.19.2",
+        "@turf/turf": "^6.5.0",
         "@types/bezier-js": "^4.1.3",
         "@types/cors": "^2.8.17",
         "@types/d3-axis": "^3.0.6",
@@ -197,6 +198,7 @@
         "jsonschema": "^1.4.1",
         "jszip": "^3.10.1",
         "lodash": "^4.17.21",
+        "mapbox-gl": "^3.0.1",
         "mathquill": "^0.10.1-a",
         "md5-file": "^5.0.0",
         "memorystream": "^0.3.1",
@@ -247,6 +249,7 @@
         "react-icons": "^4.12.0",
         "react-jsx-parser": "^1.29.0",
         "react-loading": "^2.0.3",
+        "react-map-gl": "^7.1.6",
         "react-markdown": "^9.0.1",
         "react-measure": "^2.5.2",
         "react-resizable": "^3.0.5",
diff --git a/src/client/views/nodes/DataVizBox/DataVizBox.tsx b/src/client/views/nodes/DataVizBox/DataVizBox.tsx
index a626772e4..e31c04c40 100644
--- a/src/client/views/nodes/DataVizBox/DataVizBox.tsx
+++ b/src/client/views/nodes/DataVizBox/DataVizBox.tsx
@@ -98,7 +98,7 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
     };
 
     componentDidMount() {
-        this.props.setContentView?.(this);
+        this._props.setContentView?.(this);
         if (!DataVizBox.dataset.has(CsvCast(this.dataDoc[this.fieldKey]).url.href)) this.fetchData();
     }
 
@@ -110,19 +110,19 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
 
     // toggles for user to decide which chart type to view the data in
     @computed get renderVizView() {
-        const scale = this.props.NativeDimScaling?.() || 1;
+        const scale = this._props.NativeDimScaling?.() || 1;
         const sharedProps = {
             Document: this.Document,
             layoutDoc: this.layoutDoc,
             records: this.records,
             axes: this.axes,
-            height: (this.props.PanelHeight() / scale - 32) /* height of 'change view' button */ * 0.9,
-            width: (this.props.PanelWidth() / scale) * 0.9,
+            height: (this._props.PanelHeight() / scale - 32) /* height of 'change view' button */ * 0.9,
+            width: (this._props.PanelWidth() / scale) * 0.9,
             margin: { top: 10, right: 25, bottom: 75, left: 45 },
         };
         if (!this.records.length) return 'no data/visualization';
         switch (this.dataVizView) {
-            case DataVizView.TABLE:     return <TableBox  {...sharedProps} docView={this.props.DocumentView} selectAxes={this.selectAxes} />;
+            case DataVizView.TABLE:     return <TableBox  {...sharedProps} docView={this._props.DocumentView} selectAxes={this.selectAxes} />;
             case DataVizView.LINECHART: return <LineChart {...sharedProps} dataDoc={this.dataDoc} fieldKey={this.fieldKey} ref={r => (this._vizRenderer = r ?? undefined)} />;
             case DataVizView.HISTOGRAM: return <Histogram {...sharedProps} dataDoc={this.dataDoc} fieldKey={this.fieldKey} ref={r => (this._vizRenderer = r ?? undefined)} />;
             case DataVizView.PIECHART:  return <PieChart  {...sharedProps} dataDoc={this.dataDoc} fieldKey={this.fieldKey} ref={r => (this._vizRenderer = r ?? undefined)} 
@@ -131,7 +131,7 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
     }
 
     render() {
-        const scale = this.props.NativeDimScaling?.() || 1;
+        const scale = this._props.NativeDimScaling?.() || 1;
 
         return !this.records.length ? (
             // displays how to get data into the DataVizBox if its empty
@@ -140,7 +140,7 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
             <div
                 className="dataViz"
                 style={{
-                    pointerEvents: this.props.isContentActive() === true ? 'all' : 'none',
+                    pointerEvents: this._props.isContentActive() === true ? 'all' : 'none',
                     width: `${100 / scale}%`,
                     height: `${100 / scale}%`,
                     transform: `scale(${scale})`,
diff --git a/src/client/views/nodes/DataVizBox/components/Histogram.tsx b/src/client/views/nodes/DataVizBox/components/Histogram.tsx
index a1bd316f0..d786e84ad 100644
--- a/src/client/views/nodes/DataVizBox/components/Histogram.tsx
+++ b/src/client/views/nodes/DataVizBox/components/Histogram.tsx
@@ -1,7 +1,7 @@
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
 import { ColorPicker, EditableText, IconButton, Size, Type } from 'browndash-components';
 import * as d3 from 'd3';
-import { action, computed, IReactionDisposer, observable, reaction } from 'mobx';
+import { action, computed, IReactionDisposer, makeObservable, observable, reaction } from 'mobx';
 import { observer } from 'mobx-react';
 import * as React from 'react';
 import { FaFillDrip } from 'react-icons/fa';
@@ -14,6 +14,7 @@ import { undoable } from '../../../../util/UndoManager';
 import { PinProps, PresBox } from '../../trails';
 import { scaleCreatorNumerical, yAxisCreator } from '../utils/D3Utils';
 import './Chart.scss';
+import { ObservableReactComponent } from '../../../ObservableReactComponent';
 
 export interface HistogramProps {
     Document: Doc;
@@ -33,7 +34,7 @@ export interface HistogramProps {
 }
 
 @observer
-export class Histogram extends React.Component<HistogramProps> {
+export class Histogram extends ObservableReactComponent<HistogramProps> {
     private _disposers: { [key: string]: IReactionDisposer } = {};
     private _histogramRef: React.RefObject<HTMLDivElement> = React.createRef();
     private _histogramSvg: d3.Selection<SVGGElement, unknown, null, undefined> | undefined;
@@ -45,46 +46,51 @@ export class Histogram extends React.Component<HistogramProps> {
     private selectedData: any = undefined; // Selection of selected bar
     private hoverOverData: any = undefined; // Selection of bar being hovered over
 
+    constructor(props: any) {
+        super(props);
+        makeObservable(this);
+    }
+
     @computed get _tableDataIds() {
-        return !this.parentViz ? this.props.records.map((rec, i) => i) : NumListCast(this.parentViz.dataViz_selectedRows);
+        return !this.parentViz ? this._props.records.map((rec, i) => i) : NumListCast(this.parentViz.dataViz_selectedRows);
     }
     // returns all the data records that will be rendered by only returning those records that have been selected by the parent visualization (or all records if there is no parent)
     @computed get _tableData() {
-        return !this.parentViz ? this.props.records : this._tableDataIds.map(rowId => this.props.records[rowId]);
+        return !this.parentViz ? this._props.records : this._tableDataIds.map(rowId => this._props.records[rowId]);
     }
     // filters all data to just display selected data if brushed (created from an incoming link)
     @computed get _histogramData() {
-        if (this.props.axes.length < 1) return [];
-        if (this.props.axes.length < 2) {
-            var ax0 = this.props.axes[0];
-            if (/\d/.test(this.props.records[0][ax0])) {
+        if (this._props.axes.length < 1) return [];
+        if (this._props.axes.length < 2) {
+            var ax0 = this._props.axes[0];
+            if (/\d/.test(this._props.records[0][ax0])) {
                 this.numericalXData = true;
             }
-            return this._tableData.map(record => ({ [ax0]: record[this.props.axes[0]] }));
+            return this._tableData.map(record => ({ [ax0]: record[this._props.axes[0]] }));
         }
-        var ax0 = this.props.axes[0];
-        var ax1 = this.props.axes[1];
-        if (/\d/.test(this.props.records[0][ax0])) {
+        var ax0 = this._props.axes[0];
+        var ax1 = this._props.axes[1];
+        if (/\d/.test(this._props.records[0][ax0])) {
             this.numericalXData = true;
         }
-        if (/\d/.test(this.props.records[0][ax1])) {
+        if (/\d/.test(this._props.records[0][ax1])) {
             this.numericalYData = true;
         }
-        return this._tableData.map(record => ({ [ax0]: record[this.props.axes[0]], [ax1]: record[this.props.axes[1]] }));
+        return this._tableData.map(record => ({ [ax0]: record[this._props.axes[0]], [ax1]: record[this._props.axes[1]] }));
     }
 
     @computed get defaultGraphTitle() {
-        var ax0 = this.props.axes[0];
-        var ax1 = this.props.axes.length > 1 ? this.props.axes[1] : undefined;
-        if (this.props.axes.length < 2 || !ax1 || !/\d/.test(this.props.records[0][ax1]) || !this.numericalYData) {
+        var ax0 = this._props.axes[0];
+        var ax1 = this._props.axes.length > 1 ? this._props.axes[1] : undefined;
+        if (this._props.axes.length < 2 || !ax1 || !/\d/.test(this._props.records[0][ax1]) || !this.numericalYData) {
             return ax0 + ' Histogram';
         } else return ax0 + ' by ' + ax1 + ' Histogram';
     }
 
     @computed get parentViz() {
-        return DocCast(this.props.Document.dataViz_parentViz);
-        // return LinkManager.Instance.getAllRelatedLinks(this.props.Document) // out of all links
-        //     .filter(link => link.link_anchor_1 == this.props.Document.dataViz_parentViz) // get links where this chart doc is the target of the link
+        return DocCast(this._props.Document.dataViz_parentViz);
+        // return LinkManager.Instance.getAllRelatedLinks(this._props.Document) // out of all links
+        //     .filter(link => link.link_anchor_1 == this._props.Document.dataViz_parentViz) // get links where this chart doc is the target of the link
         //     .map(link => DocCast(link.link_anchor_1)); // then return the source of the link
     }
 
@@ -114,16 +120,16 @@ export class Histogram extends React.Component<HistogramProps> {
         const anchor = Docs.Create.ConfigDocument({
             title: 'histogram doc selection' + this._currSelected,
         });
-        PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: pinProps?.pinData }, this.props.Document);
+        PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: pinProps?.pinData }, this._props.Document);
         return anchor;
     };
 
     @computed get height() {
-        return this.props.height - this.props.margin.top - this.props.margin.bottom;
+        return this._props.height - this._props.margin.top - this._props.margin.bottom;
     }
 
     @computed get width() {
-        return this.props.width - this.props.margin.left - this.props.margin.right;
+        return this._props.width - this._props.margin.left - this._props.margin.right;
     }
 
     // cleans data by converting numerical data to numbers and taking out empty cells
@@ -211,10 +217,10 @@ export class Histogram extends React.Component<HistogramProps> {
             .select(this._histogramRef.current)
             .append('svg')
             .attr('class', 'graph')
-            .attr('width', width + this.props.margin.right + this.props.margin.left)
-            .attr('height', height + this.props.margin.top + this.props.margin.bottom)
+            .attr('width', width + this._props.margin.right + this._props.margin.left)
+            .attr('height', height + this._props.margin.top + this._props.margin.bottom)
             .append('g')
-            .attr('transform', 'translate(' + this.props.margin.left + ',' + this.props.margin.top + ')'));
+            .attr('transform', 'translate(' + this._props.margin.left + ',' + this._props.margin.top + ')'));
         var x = d3
             .scaleLinear()
             .domain(this.numericalXData ? [startingPoint!, endingPoint!] : [0, numBins])
@@ -382,7 +388,7 @@ export class Histogram extends React.Component<HistogramProps> {
             )
             .attr('fill', d => {
                 var barColor;
-                const barColors = StrListCast(this.props.layoutDoc.dataViz_histogram_barColors).map(each => each.split('::'));
+                const barColors = StrListCast(this._props.layoutDoc.dataViz_histogram_barColors).map(each => each.split('::'));
                 barColors.forEach(each => {
                     if (d[0] && d[0].toString() && each[0] == d[0].toString()) barColor = each[1];
                     else {
@@ -390,24 +396,24 @@ export class Histogram extends React.Component<HistogramProps> {
                         if (Number(range[0]) <= d[0] && d[0] <= Number(range[1])) barColor = each[1];
                     }
                 });
-                return barColor ? StrCast(barColor) : StrCast(this.props.layoutDoc.dataViz_histogram_defaultColor);
+                return barColor ? StrCast(barColor) : StrCast(this._props.layoutDoc.dataViz_histogram_defaultColor);
             });
     };
 
     @action changeSelectedColor = (color: string) => {
         this.curBarSelected.attr('fill', color);
-        const barName = StrCast(this._currSelected[this.props.axes[0]].replace(/\$/g, '').replace(/\%/g, '').replace(/\</g, ''));
+        const barName = StrCast(this._currSelected[this._props.axes[0]].replace(/\$/g, '').replace(/\%/g, '').replace(/\</g, ''));
 
-        const barColors = Cast(this.props.layoutDoc.dataViz_histogram_barColors, listSpec('string'), null);
+        const barColors = Cast(this._props.layoutDoc.dataViz_histogram_barColors, listSpec('string'), null);
         barColors.forEach(each => each.split('::')[0] === barName && barColors.splice(barColors.indexOf(each), 1));
         barColors.push(StrCast(barName + '::' + color));
     };
 
     @action eraseSelectedColor = () => {
-        this.curBarSelected.attr('fill', this.props.layoutDoc.dataViz_histogram_defaultColor);
-        const barName = StrCast(this._currSelected[this.props.axes[0]].replace(/\$/g, '').replace(/\%/g, '').replace(/\</g, ''));
+        this.curBarSelected.attr('fill', this._props.layoutDoc.dataViz_histogram_defaultColor);
+        const barName = StrCast(this._currSelected[this._props.axes[0]].replace(/\$/g, '').replace(/\%/g, '').replace(/\</g, ''));
 
-        const barColors = Cast(this.props.layoutDoc.dataViz_histogram_barColors, listSpec('string'), null);
+        const barColors = Cast(this._props.layoutDoc.dataViz_histogram_barColors, listSpec('string'), null);
         barColors.forEach(each => each.split('::')[0] === barName && barColors.splice(barColors.indexOf(each), 1));
     };
 
@@ -416,7 +422,7 @@ export class Histogram extends React.Component<HistogramProps> {
         if (svg)
             svg.selectAll('rect').attr('fill', (d: any) => {
                 var barColor;
-                const barColors = StrListCast(this.props.layoutDoc.dataViz_histogram_barColors).map(each => each.split('::'));
+                const barColors = StrListCast(this._props.layoutDoc.dataViz_histogram_barColors).map(each => each.split('::'));
                 barColors.forEach(each => {
                     if (d[0] && d[0].toString() && each[0] == d[0].toString()) barColor = each[1];
                     else {
@@ -424,7 +430,7 @@ export class Histogram extends React.Component<HistogramProps> {
                         if (Number(range[0]) <= d[0] && d[0] <= Number(range[1])) barColor = each[1];
                     }
                 });
-                return barColor ? StrCast(barColor) : StrCast(this.props.layoutDoc.dataViz_histogram_defaultColor);
+                return barColor ? StrCast(barColor) : StrCast(this._props.layoutDoc.dataViz_histogram_defaultColor);
             });
     };
 
@@ -433,14 +439,14 @@ export class Histogram extends React.Component<HistogramProps> {
         this._histogramData;
         var curSelectedBarName = '';
         var titleAccessor: any = '';
-        if (this.props.axes.length == 2) titleAccessor = 'dataViz_histogram_title' + this.props.axes[0] + '-' + this.props.axes[1];
-        else if (this.props.axes.length > 0) titleAccessor = 'dataViz_histogram_title' + this.props.axes[0];
-        if (!this.props.layoutDoc[titleAccessor]) this.props.layoutDoc[titleAccessor] = this.defaultGraphTitle;
-        if (!this.props.layoutDoc.dataViz_histogram_defaultColor) this.props.layoutDoc.dataViz_histogram_defaultColor = '#69b3a2';
-        if (!this.props.layoutDoc.dataViz_histogram_barColors) this.props.layoutDoc.dataViz_histogram_barColors = new List<string>();
+        if (this._props.axes.length == 2) titleAccessor = 'dataViz_histogram_title' + this._props.axes[0] + '-' + this._props.axes[1];
+        else if (this._props.axes.length > 0) titleAccessor = 'dataViz_histogram_title' + this._props.axes[0];
+        if (!this._props.layoutDoc[titleAccessor]) this._props.layoutDoc[titleAccessor] = this.defaultGraphTitle;
+        if (!this._props.layoutDoc.dataViz_histogram_defaultColor) this._props.layoutDoc.dataViz_histogram_defaultColor = '#69b3a2';
+        if (!this._props.layoutDoc.dataViz_histogram_barColors) this._props.layoutDoc.dataViz_histogram_barColors = new List<string>();
         var selected = 'none';
         if (this._currSelected) {
-            curSelectedBarName = StrCast(this._currSelected![this.props.axes[0]].replace(/\$/g, '').replace(/\%/g, '').replace(/\</g, ''));
+            curSelectedBarName = StrCast(this._currSelected![this._props.axes[0]].replace(/\$/g, '').replace(/\%/g, '').replace(/\</g, ''));
             selected = '{ ';
             Object.keys(this._currSelected).forEach(key =>
                 key //
@@ -450,17 +456,17 @@ export class Histogram extends React.Component<HistogramProps> {
             selected = selected.substring(0, selected.length - 2) + ' }';
         }
         var selectedBarColor;
-        var barColors = StrListCast(this.props.layoutDoc.histogramBarColors).map(each => each.split('::'));
+        var barColors = StrListCast(this._props.layoutDoc.histogramBarColors).map(each => each.split('::'));
         barColors.forEach(each => each[0] === curSelectedBarName && (selectedBarColor = each[1]));
 
         if (this._histogramData.length > 0 || !this.parentViz) {
-            return this.props.axes.length >= 1 ? (
+            return this._props.axes.length >= 1 ? (
                 <div className="chart-container">
                     <div className="graph-title">
                         <EditableText
-                            val={StrCast(this.props.layoutDoc[titleAccessor])}
+                            val={StrCast(this._props.layoutDoc[titleAccessor])}
                             setVal={undoable(
-                                action(val => (this.props.layoutDoc[titleAccessor] = val as string)),
+                                action(val => (this._props.layoutDoc[titleAccessor] = val as string)),
                                 'Change Graph Title'
                             )}
                             color={'black'}
@@ -472,9 +478,9 @@ export class Histogram extends React.Component<HistogramProps> {
                             tooltip={'Change Default Bar Color'}
                             type={Type.SEC}
                             icon={<FaFillDrip />}
-                            selectedColor={StrCast(this.props.layoutDoc.dataViz_histogram_defaultColor)}
-                            setFinalColor={undoable(color => (this.props.layoutDoc.dataViz_histogram_defaultColor = color), 'Change Default Bar Color')}
-                            setSelectedColor={undoable(color => (this.props.layoutDoc.dataViz_histogram_defaultColor = color), 'Change Default Bar Color')}
+                            selectedColor={StrCast(this._props.layoutDoc.dataViz_histogram_defaultColor)}
+                            setFinalColor={undoable(color => (this._props.layoutDoc.dataViz_histogram_defaultColor = color), 'Change Default Bar Color')}
+                            setSelectedColor={undoable(color => (this._props.layoutDoc.dataViz_histogram_defaultColor = color), 'Change Default Bar Color')}
                             size={Size.XSMALL}
                         />
                     </div>
diff --git a/src/client/views/nodes/DataVizBox/components/LineChart.tsx b/src/client/views/nodes/DataVizBox/components/LineChart.tsx
index 7e0391879..abb95aa4c 100644
--- a/src/client/views/nodes/DataVizBox/components/LineChart.tsx
+++ b/src/client/views/nodes/DataVizBox/components/LineChart.tsx
@@ -1,6 +1,6 @@
 import { EditableText, Size } from 'browndash-components';
 import * as d3 from 'd3';
-import { action, computed, IReactionDisposer, observable, reaction } from 'mobx';
+import { action, computed, IReactionDisposer, makeObservable, observable, reaction } from 'mobx';
 import { observer } from 'mobx-react';
 import * as React from 'react';
 import { Doc, DocListCast, NumListCast, StrListCast } from '../../../../../fields/Doc';
@@ -14,6 +14,7 @@ import { PinProps, PresBox } from '../../trails';
 import { DataVizBox } from '../DataVizBox';
 import { createLineGenerator, drawLine, minMaxRange, scaleCreatorNumerical, xAxisCreator, xGrid, yAxisCreator, yGrid } from '../utils/D3Utils';
 import './Chart.scss';
+import { ObservableReactComponent } from '../../../ObservableReactComponent';
 
 export interface DataPoint {
     x: number;
@@ -40,33 +41,38 @@ export interface LineChartProps {
 }
 
 @observer
-export class LineChart extends React.Component<LineChartProps> {
+export class LineChart extends ObservableReactComponent<LineChartProps> {
     private _disposers: { [key: string]: IReactionDisposer } = {};
     private _lineChartRef: React.RefObject<HTMLDivElement> = React.createRef();
     private _lineChartSvg: d3.Selection<SVGGElement, unknown, null, undefined> | undefined;
     @observable _currSelected: SelectedDataPoint | undefined = undefined;
     // TODO: nda - some sort of mapping that keeps track of the annotated points so we can easily remove when annotations list updates
+    constructor(props:any) {
+        super(props);
+        makeObservable(this);
+    }
+
 
     @computed get _tableDataIds() {
-        return !this.parentViz ? this.props.records.map((rec, i) => i) : NumListCast(this.parentViz.dataViz_selectedRows);
+        return !this.parentViz ? this._props.records.map((rec, i) => i) : NumListCast(this.parentViz.dataViz_selectedRows);
     }
     // returns all the data records that will be rendered by only returning those records that have been selected by the parent visualization (or all records if there is no parent)
     @computed get _tableData() {
-        return !this.parentViz ? this.props.records : this._tableDataIds.map(rowId => this.props.records[rowId]);
+        return !this.parentViz ? this._props.records : this._tableDataIds.map(rowId => this._props.records[rowId]);
     }
     @computed get _lineChartData() {
-        var guids = StrListCast(this.props.layoutDoc.dataViz_rowIds);
-        if (this.props.axes.length <= 1) return [];
-        return this._tableData.map(record => ({ x: Number(record[this.props.axes[0]]), y: Number(record[this.props.axes[1]]) })).sort((a, b) => (a.x < b.x ? -1 : 1));
+        var guids = StrListCast(this._props.layoutDoc.dataViz_rowIds);
+        if (this._props.axes.length <= 1) return [];
+        return this._tableData.map(record => ({ x: Number(record[this._props.axes[0]]), y: Number(record[this._props.axes[1]]) })).sort((a, b) => (a.x < b.x ? -1 : 1));
     }
     @computed get graphTitle() {
-        return this.props.axes[1] + ' vs. ' + this.props.axes[0] + ' Line Chart';
+        return this._props.axes[1] + ' vs. ' + this._props.axes[0] + ' Line Chart';
     }
     @computed get parentViz() {
-        return DocCast(this.props.Document.dataViz_parentViz);
-        // return LinkManager.Instance.getAllRelatedLinks(this.props.Document) // out of all links
+        return DocCast(this._props.Document.dataViz_parentViz);
+        // return LinkManager.Instance.getAllRelatedLinks(this._props.Document) // out of all links
         //     .filter(link => {
-        //         return link.link_anchor_1 == this.props.Document.dataViz_parentViz;
+        //         return link.link_anchor_1 == this._props.Document.dataViz_parentViz;
         //     }) // get links where this chart doc is the target of the link
         //     .map(link => DocCast(link.link_anchor_1)); // then return the source of the link
     }
@@ -94,7 +100,7 @@ export class LineChart extends React.Component<LineChartProps> {
             { fireImmediately: true }
         );
         this._disposers.annos = reaction(
-            () => DocListCast(this.props.dataDoc[this.props.fieldKey + '_annotations']),
+            () => DocListCast(this._props.dataDoc[this._props.fieldKey + '_annotations']),
             annotations => {
                 // modify how d3 renders so that anything in this annotations list would be potentially highlighted in some way
                 // could be blue colored to make it look like anchor
@@ -114,7 +120,7 @@ export class LineChart extends React.Component<LineChartProps> {
                 // redraw annotations when the chart data has changed, or the local or inherited selection has changed
                 this.clearAnnotations();
                 selected && this.drawAnnotations(Number(selected.x), Number(selected.y), true);
-                incomingHighlited?.forEach((record: any) => this.drawAnnotations(Number(record[this.props.axes[0]]), Number(record[this.props.axes[1]])));
+                incomingHighlited?.forEach((record: any) => this.drawAnnotations(Number(record[this._props.axes[0]]), Number(record[this._props.axes[1]])));
             },
             { fireImmediately: true }
         );
@@ -170,23 +176,23 @@ export class LineChart extends React.Component<LineChartProps> {
             //
             title: 'line doc selection' + this._currSelected?.x,
         });
-        PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: pinProps?.pinData }, this.props.Document);
+        PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: pinProps?.pinData }, this._props.Document);
         anchor.config_dataVizSelection = this._currSelected ? new List<number>([this._currSelected.x, this._currSelected.y]) : undefined;
         return anchor;
     };
 
     @computed get height() {
-        return this.props.height - this.props.margin.top - this.props.margin.bottom;
+        return this._props.height - this._props.margin.top - this._props.margin.bottom;
     }
 
     @computed get width() {
-        return this.props.width - this.props.margin.left - this.props.margin.right;
+        return this._props.width - this._props.margin.left - this._props.margin.right;
     }
 
     @computed get defaultGraphTitle() {
-        var ax0 = this.props.axes[0];
-        var ax1 = this.props.axes.length > 1 ? this.props.axes[1] : undefined;
-        if (this.props.axes.length < 2 || !/\d/.test(this.props.records[0][ax0]) || !ax1) {
+        var ax0 = this._props.axes[0];
+        var ax1 = this._props.axes.length > 1 ? this._props.axes[1] : undefined;
+        if (this._props.axes.length < 2 || !/\d/.test(this._props.records[0][ax0]) || !ax1) {
             return ax0 + ' Line Chart';
         } else return ax1 + ' by ' + ax0 + ' Line Chart';
     }
@@ -210,7 +216,7 @@ export class LineChart extends React.Component<LineChartProps> {
         // TODO: nda - get rid of svg element in the list?
         if (this._currSelected && this._currSelected.x == x && this._currSelected.y == y) this._currSelected = undefined;
         else this._currSelected = x !== undefined && y !== undefined ? { x, y } : undefined;
-        this.props.records.forEach(record => record[this.props.axes[0]] === x && record[this.props.axes[1]] === y && (record.selected = true));
+        this._props.records.forEach(record => record[this._props.axes[0]] === x && record[this._props.axes[1]] === y && (record.selected = true));
     }
 
     drawDataPoints(data: DataPoint[], idx: number, xScale: d3.ScaleLinear<number, number, never>, yScale: d3.ScaleLinear<number, number, never>) {
@@ -245,7 +251,7 @@ export class LineChart extends React.Component<LineChartProps> {
         const yScale = scaleCreatorNumerical(0, yMax, height, 0);
 
         // adding svg
-        const margin = this.props.margin;
+        const margin = this._props.margin;
         const svg = (this._lineChartSvg = d3
             .select(this._lineChartRef.current)
             .append('svg')
@@ -317,7 +323,7 @@ export class LineChart extends React.Component<LineChartProps> {
         svg.append('text')
             .attr('transform', 'translate(' + width / 2 + ' ,' + (height + 40) + ')')
             .style('text-anchor', 'middle')
-            .text(this.props.axes[0]);
+            .text(this._props.axes[0]);
         svg.append('text')
             .attr('transform', 'rotate(-90)' + ' ' + 'translate( 0, ' + -10 + ')')
             .attr('x', -(height / 2))
@@ -325,7 +331,7 @@ export class LineChart extends React.Component<LineChartProps> {
             .attr('height', 20)
             .attr('width', 20)
             .style('text-anchor', 'middle')
-            .text(this.props.axes[1]);
+            .text(this._props.axes[1]);
     };
 
     private updateTooltip(
@@ -346,18 +352,18 @@ export class LineChart extends React.Component<LineChartProps> {
 
     render() {
         var titleAccessor: any = '';
-        if (this.props.axes.length == 2) titleAccessor = 'dataViz_lineChart_title' + this.props.axes[0] + '-' + this.props.axes[1];
-        else if (this.props.axes.length > 0) titleAccessor = 'dataViz_lineChart_title' + this.props.axes[0];
-        if (!this.props.layoutDoc[titleAccessor]) this.props.layoutDoc[titleAccessor] = this.defaultGraphTitle;
-        const selectedPt = this._currSelected ? `{ ${this.props.axes[0]}: ${this._currSelected.x} ${this.props.axes[1]}: ${this._currSelected.y} }` : 'none';
+        if (this._props.axes.length == 2) titleAccessor = 'dataViz_lineChart_title' + this._props.axes[0] + '-' + this._props.axes[1];
+        else if (this._props.axes.length > 0) titleAccessor = 'dataViz_lineChart_title' + this._props.axes[0];
+        if (!this._props.layoutDoc[titleAccessor]) this._props.layoutDoc[titleAccessor] = this.defaultGraphTitle;
+        const selectedPt = this._currSelected ? `{ ${this._props.axes[0]}: ${this._currSelected.x} ${this._props.axes[1]}: ${this._currSelected.y} }` : 'none';
         if (this._lineChartData.length > 0 || !this.parentViz || this.parentViz.length == 0) {
-            return this.props.axes.length >= 2 && /\d/.test(this.props.records[0][this.props.axes[0]]) && /\d/.test(this.props.records[0][this.props.axes[1]]) ? (
+            return this._props.axes.length >= 2 && /\d/.test(this._props.records[0][this._props.axes[0]]) && /\d/.test(this._props.records[0][this._props.axes[1]]) ? (
                 <div className="chart-container">
                     <div className="graph-title">
                         <EditableText
-                            val={StrCast(this.props.layoutDoc[titleAccessor])}
+                            val={StrCast(this._props.layoutDoc[titleAccessor])}
                             setVal={undoable(
-                                action(val => (this.props.layoutDoc[titleAccessor] = val as string)),
+                                action(val => (this._props.layoutDoc[titleAccessor] = val as string)),
                                 'Change Graph Title'
                             )}
                             color={'black'}
diff --git a/src/client/views/nodes/DataVizBox/components/PieChart.tsx b/src/client/views/nodes/DataVizBox/components/PieChart.tsx
index c2e03744e..9e7265b26 100644
--- a/src/client/views/nodes/DataVizBox/components/PieChart.tsx
+++ b/src/client/views/nodes/DataVizBox/components/PieChart.tsx
@@ -1,7 +1,7 @@
 import { Checkbox } from '@mui/material';
 import { ColorPicker, EditableText, Size, Type } from 'browndash-components';
 import * as d3 from 'd3';
-import { action, computed, IReactionDisposer, observable, reaction } from 'mobx';
+import { action, computed, IReactionDisposer, makeObservable, observable, reaction } from 'mobx';
 import { observer } from 'mobx-react';
 import * as React from 'react';
 import { FaFillDrip } from 'react-icons/fa';
@@ -13,6 +13,7 @@ import { Docs } from '../../../../documents/Documents';
 import { undoable } from '../../../../util/UndoManager';
 import { PinProps, PresBox } from '../../trails';
 import './Chart.scss';
+import { ObservableReactComponent } from '../../../ObservableReactComponent';
 
 export interface PieChartProps {
     Document: Doc;
@@ -32,7 +33,7 @@ export interface PieChartProps {
 }
 
 @observer
-export class PieChart extends React.Component<PieChartProps> {
+export class PieChart extends ObservableReactComponent<PieChartProps> {
     private _disposers: { [key: string]: IReactionDisposer } = {};
     private _piechartRef: React.RefObject<HTMLDivElement> = React.createRef();
     private _piechartSvg: d3.Selection<SVGGElement, unknown, null, undefined> | undefined;
@@ -41,44 +42,49 @@ export class PieChart extends React.Component<PieChartProps> {
     private hoverOverData: any = undefined; // Selection of slice being hovered over
     @observable _currSelected: any | undefined = undefined; // Object of selected slice
 
+    constructor(props: any) {
+        super(props);
+        makeObservable(this);
+    }
+
     @computed get _tableDataIds() {
-        return !this.parentViz ? this.props.records.map((rec, i) => i) : NumListCast(this.parentViz.dataViz_selectedRows);
+        return !this.parentViz ? this._props.records.map((rec, i) => i) : NumListCast(this.parentViz.dataViz_selectedRows);
     }
     // returns all the data records that will be rendered by only returning those records that have been selected by the parent visualization (or all records if there is no parent)
     @computed get _tableData() {
-        return !this.parentViz ? this.props.records : this._tableDataIds.map(rowId => this.props.records[rowId]);
+        return !this.parentViz ? this._props.records : this._tableDataIds.map(rowId => this._props.records[rowId]);
     }
 
     // organized by specified number percentages/ratios if one column is selected and it contains numbers
     // otherwise, assume data is organized by categories
     @computed get byCategory() {
-        return !/\d/.test(this.props.records[0][this.props.axes[0]]) || this.props.layoutDoc.dataViz_pie_asHistogram;
+        return !/\d/.test(this._props.records[0][this._props.axes[0]]) || this._props.layoutDoc.dataViz_pie_asHistogram;
     }
     // filters all data to just display selected data if brushed (created from an incoming link)
     @computed get _pieChartData() {
-        if (this.props.axes.length < 1) return [];
+        if (this._props.axes.length < 1) return [];
 
-        const ax0 = this.props.axes[0];
-        if (this.props.axes.length < 2) {
-            return this._tableData.map(record => ({ [ax0]: record[this.props.axes[0]] }));
+        const ax0 = this._props.axes[0];
+        if (this._props.axes.length < 2) {
+            return this._tableData.map(record => ({ [ax0]: record[this._props.axes[0]] }));
         }
-        const ax1 = this.props.axes[1];
-        return this._tableData.map(record => ({ [ax0]: record[this.props.axes[0]], [ax1]: record[this.props.axes[1]] }));
+        const ax1 = this._props.axes[1];
+        return this._tableData.map(record => ({ [ax0]: record[this._props.axes[0]], [ax1]: record[this._props.axes[1]] }));
     }
 
     @computed get defaultGraphTitle() {
-        var ax0 = this.props.axes[0];
-        var ax1 = this.props.axes.length > 1 ? this.props.axes[1] : undefined;
-        if (this.props.axes.length < 2 || !/\d/.test(this.props.records[0][ax0]) || !ax1) {
+        var ax0 = this._props.axes[0];
+        var ax1 = this._props.axes.length > 1 ? this._props.axes[1] : undefined;
+        if (this._props.axes.length < 2 || !/\d/.test(this._props.records[0][ax0]) || !ax1) {
             return ax0 + ' Pie Chart';
         }
         return ax1 + ' by ' + ax0 + ' Pie Chart';
     }
 
     @computed get parentViz() {
-        return DocCast(this.props.Document.dataViz_parentViz);
-        // return LinkManager.Instance.getAllRelatedLinks(this.props.Document) // out of all links
-        //     .filter(link => link.link_anchor_1 == this.props.Document.dataViz_parentViz) // get links where this chart doc is the target of the link
+        return DocCast(this._props.Document.dataViz_parentViz);
+        // return LinkManager.Instance.getAllRelatedLinks(this._props.Document) // out of all links
+        //     .filter(link => link.link_anchor_1 == this._props.Document.dataViz_parentViz) // get links where this chart doc is the target of the link
         //     .map(link => DocCast(link.link_anchor_1)); // then return the source of the link
     }
 
@@ -101,16 +107,16 @@ export class PieChart extends React.Component<PieChartProps> {
             //
             title: 'piechart doc selection' + this._currSelected,
         });
-        PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: pinProps?.pinData }, this.props.Document);
+        PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: pinProps?.pinData }, this._props.Document);
         return anchor;
     };
 
     @computed get height() {
-        return this.props.height - this.props.margin.top - this.props.margin.bottom;
+        return this._props.height - this._props.margin.top - this._props.margin.bottom;
     }
 
     @computed get width() {
-        return this.props.width - this.props.margin.left - this.props.margin.right;
+        return this._props.width - this._props.margin.left - this._props.margin.right;
     }
 
     // cleans data by converting numerical data to numbers and taking out empty cells
@@ -181,7 +187,7 @@ export class PieChart extends React.Component<PieChartProps> {
 
         var percentField = Object.keys(dataSet[0])[0];
         var descriptionField = Object.keys(dataSet[0])[1]!;
-        var radius = Math.min(width, height - this.props.margin.top - this.props.margin.bottom) / 2;
+        var radius = Math.min(width, height - this._props.margin.top - this._props.margin.bottom) / 2;
 
         // converts data into Objects
         var data = this.data(dataSet);
@@ -209,10 +215,10 @@ export class PieChart extends React.Component<PieChartProps> {
             .select(this._piechartRef.current)
             .append('svg')
             .attr('class', 'graph')
-            .attr('width', width + this.props.margin.right + this.props.margin.left)
-            .attr('height', height + this.props.margin.top + this.props.margin.bottom)
+            .attr('width', width + this._props.margin.right + this._props.margin.left)
+            .attr('height', height + this._props.margin.top + this._props.margin.bottom)
             .append('g'));
-        let g = svg.append('g').attr('transform', 'translate(' + (width / 2 + this.props.margin.left) + ',' + height / 2 + ')');
+        let g = svg.append('g').attr('transform', 'translate(' + (width / 2 + this._props.margin.left) + ',' + height / 2 + ')');
         var pie = d3.pie();
         var arc = d3.arc().innerRadius(0).outerRadius(radius);
 
@@ -249,7 +255,7 @@ export class PieChart extends React.Component<PieChartProps> {
             } catch (error) {}
             possibleDataPointVals.push(dataPointVal);
         });
-        const sliceColors = StrListCast(this.props.layoutDoc.dataViz_pie_sliceColors).map(each => each.split('::'));
+        const sliceColors = StrListCast(this._props.layoutDoc.dataViz_pie_sliceColors).map(each => each.split('::'));
         arcs.append('path')
             .attr('fill', (d, i) => {
                 var dataPoint;
@@ -261,7 +267,7 @@ export class PieChart extends React.Component<PieChartProps> {
                 }
                 var sliceColor;
                 if (dataPoint) {
-                    const sliceTitle = dataPoint[this.props.axes[0]];
+                    const sliceTitle = dataPoint[this._props.axes[0]];
                     const accessByName = StrCast(sliceTitle) ? StrCast(sliceTitle).replace(/\$/g, '').replace(/\%/g, '').replace(/\#/g, '').replace(/\</g, '') : sliceTitle;
                     sliceColors.forEach(each => each[0] == accessByName && (sliceColor = each[1]));
                 }
@@ -309,10 +315,10 @@ export class PieChart extends React.Component<PieChartProps> {
 
     @action changeSelectedColor = (color: string) => {
         this.curSliceSelected.attr('fill', color);
-        const sliceTitle = this._currSelected[this.props.axes[0]];
+        const sliceTitle = this._currSelected[this._props.axes[0]];
         const sliceName = StrCast(sliceTitle) ? StrCast(sliceTitle).replace(/\$/g, '').replace(/\%/g, '').replace(/\#/g, '').replace(/\</g, '') : sliceTitle;
 
-        const sliceColors = Cast(this.props.layoutDoc.dataViz_pie_sliceColors, listSpec('string'), null);
+        const sliceColors = Cast(this._props.layoutDoc.dataViz_pie_sliceColors, listSpec('string'), null);
         sliceColors.map(each => {
             if (each.split('::')[0] == sliceName) sliceColors.splice(sliceColors.indexOf(each), 1);
         });
@@ -320,20 +326,20 @@ export class PieChart extends React.Component<PieChartProps> {
     };
 
     @action changeHistogramCheckBox = () => {
-        this.props.layoutDoc.dataViz_pie_asHistogram = !this.props.layoutDoc.dataViz_pie_asHistogram;
+        this._props.layoutDoc.dataViz_pie_asHistogram = !this._props.layoutDoc.dataViz_pie_asHistogram;
         this.drawChart(this._pieChartData, this.width, this.height);
     };
 
     render() {
         var titleAccessor: any = '';
-        if (this.props.axes.length == 2) titleAccessor = 'dataViz_pie_title' + this.props.axes[0] + '-' + this.props.axes[1];
-        else if (this.props.axes.length > 0) titleAccessor = 'dataViz_pie_title' + this.props.axes[0];
-        if (!this.props.layoutDoc[titleAccessor]) this.props.layoutDoc[titleAccessor] = this.defaultGraphTitle;
-        if (!this.props.layoutDoc.dataViz_pie_sliceColors) this.props.layoutDoc.dataViz_pie_sliceColors = new List<string>();
+        if (this._props.axes.length == 2) titleAccessor = 'dataViz_pie_title' + this._props.axes[0] + '-' + this._props.axes[1];
+        else if (this._props.axes.length > 0) titleAccessor = 'dataViz_pie_title' + this._props.axes[0];
+        if (!this._props.layoutDoc[titleAccessor]) this._props.layoutDoc[titleAccessor] = this.defaultGraphTitle;
+        if (!this._props.layoutDoc.dataViz_pie_sliceColors) this._props.layoutDoc.dataViz_pie_sliceColors = new List<string>();
         var selected: string;
         var curSelectedSliceName = '';
         if (this._currSelected) {
-            const sliceTitle = this._currSelected[this.props.axes[0]];
+            const sliceTitle = this._currSelected[this._props.axes[0]];
             curSelectedSliceName = StrCast(sliceTitle) ? StrCast(sliceTitle).replace(/\$/g, '').replace(/\%/g, '').replace(/\#/g, '').replace(/\</g, '') : sliceTitle;
             selected = '{ ';
             Object.keys(this._currSelected).map(key => {
@@ -343,19 +349,19 @@ export class PieChart extends React.Component<PieChartProps> {
             selected += ' }';
         } else selected = 'none';
         var selectedSliceColor;
-        var sliceColors = StrListCast(this.props.layoutDoc.dataViz_pie_sliceColors).map(each => each.split('::'));
+        var sliceColors = StrListCast(this._props.layoutDoc.dataViz_pie_sliceColors).map(each => each.split('::'));
         sliceColors.forEach(each => {
             if (each[0] == curSelectedSliceName!) selectedSliceColor = each[1];
         });
 
         if (this._pieChartData.length > 0 || !this.parentViz) {
-            return this.props.axes.length >= 1 ? (
+            return this._props.axes.length >= 1 ? (
                 <div className="chart-container">
                     <div className="graph-title">
                         <EditableText
-                            val={StrCast(this.props.layoutDoc[titleAccessor])}
+                            val={StrCast(this._props.layoutDoc[titleAccessor])}
                             setVal={undoable(
-                                action(val => (this.props.layoutDoc[titleAccessor] = val as string)),
+                                action(val => (this._props.layoutDoc[titleAccessor] = val as string)),
                                 'Change Graph Title'
                             )}
                             color={'black'}
@@ -363,9 +369,9 @@ export class PieChart extends React.Component<PieChartProps> {
                             fillWidth
                         />
                     </div>
-                    {this.props.axes.length === 1 && /\d/.test(this.props.records[0][this.props.axes[0]]) ? (
-                        <div className={'asHistogram-checkBox'} style={{ width: this.props.width }}>
-                            <Checkbox color="primary" onChange={this.changeHistogramCheckBox} checked={this.props.layoutDoc.dataViz_pie_asHistogram as boolean} />
+                    {this._props.axes.length === 1 && /\d/.test(this._props.records[0][this._props.axes[0]]) ? (
+                        <div className={'asHistogram-checkBox'} style={{ width: this._props.width }}>
+                            <Checkbox color="primary" onChange={this.changeHistogramCheckBox} checked={this._props.layoutDoc.dataViz_pie_asHistogram as boolean} />
                             Organize data as histogram
                         </div>
                     ) : null}
diff --git a/src/client/views/nodes/DataVizBox/components/TableBox.tsx b/src/client/views/nodes/DataVizBox/components/TableBox.tsx
index 3e7d3af8c..f77c138df 100644
--- a/src/client/views/nodes/DataVizBox/components/TableBox.tsx
+++ b/src/client/views/nodes/DataVizBox/components/TableBox.tsx
@@ -1,5 +1,5 @@
 import { Button, Type } from 'browndash-components';
-import { action, computed, IReactionDisposer, observable, reaction, trace } from 'mobx';
+import { action, computed, IReactionDisposer, makeObservable, observable, reaction, trace } from 'mobx';
 import { observer } from 'mobx-react';
 import * as React from 'react';
 import { Doc, Field, NumListCast } from '../../../../../fields/Doc';
@@ -11,6 +11,7 @@ import { DragManager } from '../../../../util/DragManager';
 import { DocumentView } from '../../DocumentView';
 import { DataVizView } from '../DataVizBox';
 import './Chart.scss';
+import { ObservableReactComponent } from '../../../ObservableReactComponent';
 const {  default: { DATA_VIZ_TABLE_ROW_HEIGHT } } = require('../../../global/globalCssVariables.module.scss'); // prettier-ignore
 interface TableBoxProps {
     Document: Doc;
@@ -30,13 +31,17 @@ interface TableBoxProps {
 }
 
 @observer
-export class TableBox extends React.Component<TableBoxProps> {
+export class TableBox extends ObservableReactComponent<TableBoxProps> {
     _inputChangedDisposer?: IReactionDisposer;
     _containerRef: HTMLDivElement | null = null;
 
     @observable _scrollTop = -1;
     @observable _tableHeight = 0;
     @observable _tableContainerHeight = 0;
+    constructor(props: any) {
+        super(props);
+        makeObservable(this);
+    }
 
     componentDidMount() {
         // if the tableData changes (ie., when records are selected by the parent (input) visulization),
@@ -48,17 +53,17 @@ export class TableBox extends React.Component<TableBoxProps> {
         this._inputChangedDisposer?.();
     }
     @computed get _tableDataIds() {
-        return !this.parentViz ? this.props.records.map((rec, i) => i) : NumListCast(this.parentViz.dataViz_selectedRows);
+        return !this.parentViz ? this._props.records.map((rec, i) => i) : NumListCast(this.parentViz.dataViz_selectedRows);
     }
     // returns all the data records that will be rendered by only returning those records that have been selected by the parent visualization (or all records if there is no parent)
     @computed get _tableData() {
-        return !this.parentViz ? this.props.records : this._tableDataIds.map(rowId => this.props.records[rowId]);
+        return !this.parentViz ? this._props.records : this._tableDataIds.map(rowId => this._props.records[rowId]);
     }
 
     @computed get parentViz() {
-        return DocCast(this.props.Document.dataViz_parentViz);
-        // return LinkManager.Instance.getAllRelatedLinks(this.props.Document) // out of all links
-        //     .filter(link => link.link_anchor_1 == this.props.Document.dataViz_parentViz) // get links where this chart doc is the target of the link
+        return DocCast(this._props.Document.dataViz_parentViz);
+        // return LinkManager.Instance.getAllRelatedLinks(this._props.Document) // out of all links
+        //     .filter(link => link.link_anchor_1 == this._props.Document.dataViz_parentViz) // get links where this chart doc is the target of the link
         //     .map(link => DocCast(link.link_anchor_1)); // then return the source of the link
     }
 
@@ -68,14 +73,14 @@ export class TableBox extends React.Component<TableBoxProps> {
 
     // updates the 'dataViz_selectedRows' and 'dataViz_highlightedRows' fields to no longer include rows that aren't in the table
     filterSelectedRowsDown = () => {
-        const selected = NumListCast(this.props.layoutDoc.dataViz_selectedRows);
-        this.props.layoutDoc.dataViz_selectedRows = new List<number>(selected.filter(rowId => this._tableDataIds.includes(rowId))); // filters through selected to remove guids that were removed in the incoming data
-        const highlighted = NumListCast(this.props.layoutDoc.dataViz_highlitedRows);
-        this.props.layoutDoc.dataViz_highlitedRows = new List<number>(highlighted.filter(rowId => this._tableDataIds.includes(rowId))); // filters through highlighted to remove guids that were removed in the incoming data
+        const selected = NumListCast(this._props.layoutDoc.dataViz_selectedRows);
+        this._props.layoutDoc.dataViz_selectedRows = new List<number>(selected.filter(rowId => this._tableDataIds.includes(rowId))); // filters through selected to remove guids that were removed in the incoming data
+        const highlighted = NumListCast(this._props.layoutDoc.dataViz_highlitedRows);
+        this._props.layoutDoc.dataViz_highlitedRows = new List<number>(highlighted.filter(rowId => this._tableDataIds.includes(rowId))); // filters through highlighted to remove guids that were removed in the incoming data
     };
 
     @computed get viewScale() {
-        return this.props.docView?.()?._props.ScreenToLocalTransform().Scale || 1;
+        return this._props.docView?.()?._props.ScreenToLocalTransform().Scale || 1;
     }
     @computed get rowHeight() {
         console.log('scale = ' + this.viewScale + '  table = ' + this._tableHeight + ' ids = ' + this._tableDataIds.length);
@@ -89,14 +94,14 @@ export class TableBox extends React.Component<TableBoxProps> {
         return Math.ceil(this.startID + (this._tableContainerHeight * this.viewScale) / (this.rowHeight || 1));
     }
     @action handleScroll = () => {
-        if (!this.props.docView?.()?.ContentDiv?.hidden) {
+        if (!this._props.docView?.()?.ContentDiv?.hidden) {
             this._scrollTop = this._containerRef?.scrollTop ?? 0;
         }
     };
     @action
     tableRowClick = (e: React.MouseEvent, rowId: number) => {
-        const highlited = Cast(this.props.layoutDoc.dataViz_highlitedRows, listSpec('number'), null);
-        const selected = Cast(this.props.layoutDoc.dataViz_selectedRows, listSpec('number'), null);
+        const highlited = Cast(this._props.layoutDoc.dataViz_highlitedRows, listSpec('number'), null);
+        const selected = Cast(this._props.layoutDoc.dataViz_selectedRows, listSpec('number'), null);
         if (e.metaKey) {
             // highlighting a row
             if (highlited?.includes(rowId)) highlited.splice(highlited.indexOf(rowId), 1);
@@ -120,26 +125,26 @@ export class TableBox extends React.Component<TableBoxProps> {
             e,
             e => {
                 // dragging off a column to create a brushed DataVizBox
-                const sourceAnchorCreator = () => this.props.docView?.()!.Document!;
+                const sourceAnchorCreator = () => this._props.docView?.()!.Document!;
                 const targetCreator = (annotationOn: Doc | undefined) => {
-                    const embedding = Doc.MakeEmbedding(this.props.docView?.()!.Document!);
+                    const embedding = Doc.MakeEmbedding(this._props.docView?.()!.Document!);
                     embedding._dataViz = DataVizView.TABLE;
                     embedding._dataViz_axes = new List<string>([col, col]);
-                    embedding._dataViz_parentViz = this.props.Document;
+                    embedding._dataViz_parentViz = this._props.Document;
                     embedding.annotationOn = annotationOn;
-                    embedding.histogramBarColors = Field.Copy(this.props.layoutDoc.histogramBarColors);
-                    embedding.defaultHistogramColor = this.props.layoutDoc.defaultHistogramColor;
-                    embedding.pieSliceColors = Field.Copy(this.props.layoutDoc.pieSliceColors);
+                    embedding.histogramBarColors = Field.Copy(this._props.layoutDoc.histogramBarColors);
+                    embedding.defaultHistogramColor = this._props.layoutDoc.defaultHistogramColor;
+                    embedding.pieSliceColors = Field.Copy(this._props.layoutDoc.pieSliceColors);
                     return embedding;
                 };
-                if (this.props.docView?.() && !Utils.isClick(e.clientX, e.clientY, downX, downY, Date.now())) {
-                    DragManager.StartAnchorAnnoDrag(e.target instanceof HTMLElement ? [e.target] : [], new DragManager.AnchorAnnoDragData(this.props.docView()!, sourceAnchorCreator, targetCreator), downX, downY, {
+                if (this._props.docView?.() && !Utils.isClick(e.clientX, e.clientY, downX, downY, Date.now())) {
+                    DragManager.StartAnchorAnnoDrag(e.target instanceof HTMLElement ? [e.target] : [], new DragManager.AnchorAnnoDragData(this._props.docView()!, sourceAnchorCreator, targetCreator), downX, downY, {
                         dragComplete: e => {
                             if (!e.aborted && e.annoDragData && e.annoDragData.linkSourceDoc && e.annoDragData.dropDocument && e.linkDocument) {
                                 e.linkDocument.link_displayLine = true;
                                 e.linkDocument.link_matchEmbeddings = true;
                                 e.linkDocument.link_displayArrow = true;
-                                // e.annoDragData.linkSourceDoc.followLinkToggle = e.annoDragData.dropDocument.annotationOn === this.props.Document;
+                                // e.annoDragData.linkSourceDoc.followLinkToggle = e.annoDragData.dropDocument.annotationOn === this._props.Document;
                                 // e.annoDragData.linkSourceDoc.followLinkZoom = false;
                             }
                         },
@@ -150,11 +155,11 @@ export class TableBox extends React.Component<TableBoxProps> {
             },
             emptyFunction,
             action(e => {
-                const newAxes = this.props.axes;
+                const newAxes = this._props.axes;
                 if (newAxes.includes(col)) newAxes.splice(newAxes.indexOf(col), 1);
                 else if (newAxes.length > 1) newAxes[1] = col;
                 else newAxes.push(col);
-                this.props.selectAxes(newAxes);
+                this._props.selectAxes(newAxes);
             })
         );
     };
@@ -166,14 +171,14 @@ export class TableBox extends React.Component<TableBoxProps> {
                     className="tableBox"
                     tabIndex={0}
                     onKeyDown={e => {
-                        if (this.props.layoutDoc && e.key === 'a' && (e.ctrlKey || e.metaKey)) {
+                        if (this._props.layoutDoc && e.key === 'a' && (e.ctrlKey || e.metaKey)) {
                             e.stopPropagation();
-                            this.props.layoutDoc.dataViz_selectedRows = new List<number>(this._tableDataIds);
+                            this._props.layoutDoc.dataViz_selectedRows = new List<number>(this._tableDataIds);
                         }
                     }}>
                     <div className="selectAll-buttons">
-                        <Button onClick={action(() => (this.props.layoutDoc.dataViz_selectedRows = new List<number>(this._tableDataIds)))} text="Select All" type={Type.SEC} color={'black'} />
-                        <Button onClick={action(() => (this.props.layoutDoc.dataViz_selectedRows = new List<number>()))} text="Deselect All" type={Type.SEC} color={'black'} />
+                        <Button onClick={action(() => (this._props.layoutDoc.dataViz_selectedRows = new List<number>(this._tableDataIds)))} text="Select All" type={Type.SEC} color={'black'} />
+                        <Button onClick={action(() => (this._props.layoutDoc.dataViz_selectedRows = new List<number>()))} text="Deselect All" type={Type.SEC} color={'black'} />
                     </div>
                     <div
                         className={`tableBox-container ${this.columns[0]}`}
@@ -181,7 +186,7 @@ export class TableBox extends React.Component<TableBoxProps> {
                         onScroll={this.handleScroll}
                         ref={action((r: HTMLDivElement | null) => {
                             this._containerRef = r;
-                            if (!this.props.docView?.()?.ContentDiv?.hidden && r) {
+                            if (!this._props.docView?.()?.ContentDiv?.hidden && r) {
                                 this._tableContainerHeight = r.getBoundingClientRect().height ?? 0;
                                 r.addEventListener(
                                     'wheel', // if scrollTop is 0, then don't let wheel trigger scroll on any container (which it would since onScroll won't be triggered on this)
@@ -196,7 +201,7 @@ export class TableBox extends React.Component<TableBoxProps> {
                         <table
                             className="tableBox-table"
                             ref={action((r: HTMLTableElement | null) => {
-                                if (!this.props.docView?.()?.ContentDiv?.hidden && r) {
+                                if (!this._props.docView?.()?.ContentDiv?.hidden && r) {
                                     this._tableHeight = r?.getBoundingClientRect().height ?? 0;
                                 }
                             })}>
@@ -207,8 +212,8 @@ export class TableBox extends React.Component<TableBoxProps> {
                                         <th
                                             key={this.columns.indexOf(col)}
                                             style={{
-                                                color: this.props.axes.slice().reverse().lastElement() === col ? 'darkgreen' : this.props.axes.lastElement() === col ? 'darkred' : undefined,
-                                                background: this.props.axes.slice().reverse().lastElement() === col ? '#E3fbdb' : this.props.axes.lastElement() === col ? '#Fbdbdb' : undefined,
+                                                color: this._props.axes.slice().reverse().lastElement() === col ? 'darkgreen' : this._props.axes.lastElement() === col ? 'darkred' : undefined,
+                                                background: this._props.axes.slice().reverse().lastElement() === col ? '#E3fbdb' : this._props.axes.lastElement() === col ? '#Fbdbdb' : undefined,
                                                 fontWeight: 'bolder',
                                                 border: '3px solid black',
                                             }}
@@ -227,13 +232,13 @@ export class TableBox extends React.Component<TableBoxProps> {
                                             className={`tableBox-row ${this.columns[0]}`}
                                             onClick={e => this.tableRowClick(e, rowId)}
                                             style={{
-                                                background: NumListCast(this.props.layoutDoc.dataViz_highlitedRows).includes(rowId) ? 'lightYellow' : NumListCast(this.props.layoutDoc.dataViz_selectedRows).includes(rowId) ? 'lightgrey' : '',
+                                                background: NumListCast(this._props.layoutDoc.dataViz_highlitedRows).includes(rowId) ? 'lightYellow' : NumListCast(this._props.layoutDoc.dataViz_selectedRows).includes(rowId) ? 'lightgrey' : '',
                                             }}>
                                             {this.columns.map(col => {
-                                                const colSelected = this.props.axes.length > 1 ? this.props.axes[0] == col || this.props.axes[1] == col : this.props.axes.length > 0 ? this.props.axes[0] == col : false;
+                                                const colSelected = this._props.axes.length > 1 ? this._props.axes[0] == col || this._props.axes[1] == col : this._props.axes.length > 0 ? this._props.axes[0] == col : false;
                                                 return (
                                                     <td key={this.columns.indexOf(col)} style={{ border: colSelected ? '3px solid black' : '1px solid black', fontWeight: colSelected ? 'bolder' : 'normal' }}>
-                                                        <div className="tableBox-cell">{this.props.records[rowId][col]}</div>
+                                                        <div className="tableBox-cell">{this._props.records[rowId][col]}</div>
                                                     </td>
                                                 );
                                             })}
diff --git a/src/client/views/nodes/MapBox/AnimationUtility.ts b/src/client/views/nodes/MapBox/AnimationUtility.ts
index 256acbf13..13ce5b7e2 100644
--- a/src/client/views/nodes/MapBox/AnimationUtility.ts
+++ b/src/client/views/nodes/MapBox/AnimationUtility.ts
@@ -1,13 +1,13 @@
-import mapboxgl from "mapbox-gl";
-import { MercatorCoordinate } from "mapbox-gl";
-import { MapRef } from "react-map-gl";
+import mapboxgl from 'mapbox-gl';
+import { MercatorCoordinate } from 'mapbox-gl';
+import { MapRef } from 'react-map-gl';
 import * as React from 'react';
-import * as d3 from "d3";
+import * as d3 from 'd3';
 import * as turf from '@turf/turf';
-import { Position } from "@turf/turf";
-import { Feature, FeatureCollection, GeoJsonProperties, Geometry } from "geojson";
-import { observer } from "mobx-react";
-import { action, computed, observable } from "mobx";
+import { Position } from '@turf/turf';
+import { Feature, FeatureCollection, GeoJsonProperties, Geometry } from 'geojson';
+import { observer } from 'mobx-react';
+import { action, computed, observable } from 'mobx';
 
 export enum AnimationStatus {
     START = 'start',
@@ -21,37 +21,35 @@ export enum AnimationSpeed {
     FAST = '3x',
 }
 
-@observer
 export class AnimationUtility {
-    private SMOOTH_FACTOR = 0.95
-    private ROUTE_COORDINATES: Position[] = []; 
+    private SMOOTH_FACTOR = 0.95;
+    private ROUTE_COORDINATES: Position[] = [];
     private PATH: turf.helpers.Feature<turf.helpers.LineString, turf.helpers.Properties>;
     private FLY_IN_START_PITCH = 40;
-    private FIRST_LNG_LAT: {lng: number, lat: number};
+    private FIRST_LNG_LAT: { lng: number; lat: number };
     private START_ALTITUDE = 3_000_000;
 
     @observable private isStreetViewAnimation: boolean;
     @observable private animationSpeed: AnimationSpeed;
 
-    
-    private previousLngLat: {lng: number, lat: number};
+    private previousLngLat: { lng: number; lat: number };
 
     private currentStreetViewBearing: number = 0;
 
     @computed get flyInEndBearing() {
-        return this.isStreetViewAnimation ? 
-            this.calculateBearing(
-                {
-                    lng: this.ROUTE_COORDINATES[0][0],
-                    lat: this.ROUTE_COORDINATES[0][1]
-                },
-                {
-                    lng: this.ROUTE_COORDINATES[1][0],
-                    lat: this.ROUTE_COORDINATES[1][1]
-                }
-            )
+        return this.isStreetViewAnimation
+            ? this.calculateBearing(
+                  {
+                      lng: this.ROUTE_COORDINATES[0][0],
+                      lat: this.ROUTE_COORDINATES[0][1],
+                  },
+                  {
+                      lng: this.ROUTE_COORDINATES[1][0],
+                      lat: this.ROUTE_COORDINATES[1][1],
+                  }
+              )
             : -20;
-        }
+    }
 
     @computed get flyInStartBearing() {
         return Math.max(0, Math.min(this.flyInEndBearing + 20, 360)); // between 0 and 360
@@ -80,8 +78,8 @@ export class AnimationUtility {
 
     @computed get animationDuration(): number {
         return 20_000;
-        // compute path distance for a standard speed 
-        // get animation speed 
+        // compute path distance for a standard speed
+        // get animation speed
         // get isStreetViewAnimation (should be slower if so)
     }
 
@@ -90,19 +88,13 @@ export class AnimationUtility {
         // calculate new flyToDuration and animationDuration
         this.animationSpeed = speed;
     }
-    
+
     @action
     public updateIsStreetViewAnimation(isStreetViewAnimation: boolean) {
         this.isStreetViewAnimation = isStreetViewAnimation;
     }
 
-
-    constructor(
-        firstLngLat: {lng: number, lat: number},
-        routeCoordinates: Position[],
-        isStreetViewAnimation: boolean,
-        animationSpeed: AnimationSpeed
-    ) {
+    constructor(firstLngLat: { lng: number; lat: number }, routeCoordinates: Position[], isStreetViewAnimation: boolean, animationSpeed: AnimationSpeed) {
         this.FIRST_LNG_LAT = firstLngLat;
         this.previousLngLat = firstLngLat;
         this.ROUTE_COORDINATES = routeCoordinates;
@@ -111,11 +103,11 @@ export class AnimationUtility {
         const bearing = this.calculateBearing(
             {
                 lng: routeCoordinates[0][0],
-                lat: routeCoordinates[0][1]
+                lat: routeCoordinates[0][1],
             },
             {
                 lng: routeCoordinates[1][0],
-                lat: routeCoordinates[1][1]
+                lat: routeCoordinates[1][1],
             }
         );
         this.currentStreetViewBearing = bearing;
@@ -137,293 +129,245 @@ export class AnimationUtility {
         currentAnimationPhase,
         updateAnimationPhase,
         updateFrameId,
-      }: {
-        map: MapRef,
+    }: {
+        map: MapRef;
         // path: turf.helpers.Feature<turf.helpers.LineString, turf.helpers.Properties>,
         // startBearing: number,
         // startAltitude: number,
         // pitch: number,
-        currentAnimationPhase: number,
-        updateAnimationPhase: ( 
-            newAnimationPhase: number,
-            ) => void,
+        currentAnimationPhase: number;
+        updateAnimationPhase: (newAnimationPhase: number) => void;
         updateFrameId: (newFrameId: number) => void;
+    }) => {
+        return new Promise<void>(async resolve => {
+            const pathDistance = turf.lineDistance(this.PATH);
+            console.log('PATH DISTANCE: ', pathDistance);
+            let startTime: number | null = null;
+
+            const frame = async (currentTime: number) => {
+                if (!startTime) startTime = currentTime;
+                const elapsedSinceLastFrame = currentTime - startTime;
+                const phaseIncrement = elapsedSinceLastFrame / this.animationDuration;
+                const animationPhase = currentAnimationPhase + phaseIncrement;
+
+                // when the duration is complete, resolve the promise and stop iterating
+                if (animationPhase > 1) {
+                    resolve();
+                    return;
+                }
 
-      }) => {
-        return new Promise<void>(async (resolve) => {
-          const pathDistance = turf.lineDistance(this.PATH);
-          console.log("PATH DISTANCE: ", pathDistance);
-          let startTime: number | null = null;
-      
-          const frame = async (currentTime: number) => {
-            if (!startTime) startTime = currentTime;
-            const elapsedSinceLastFrame = currentTime - startTime;
-            const phaseIncrement = elapsedSinceLastFrame / this.animationDuration;
-            const animationPhase = currentAnimationPhase + phaseIncrement;
-      
-            // when the duration is complete, resolve the promise and stop iterating
-            if (animationPhase > 1) {
-              resolve();
-              return;
-            }
+                // calculate the distance along the path based on the animationPhase
+                const alongPath = turf.along(this.PATH, pathDistance * animationPhase).geometry.coordinates;
+
+                const lngLat = {
+                    lng: alongPath[0],
+                    lat: alongPath[1],
+                };
+
+                let bearing: number;
+                if (this.isStreetViewAnimation) {
+                    bearing = this.lerp(
+                        this.currentStreetViewBearing,
+                        this.calculateBearing(this.previousLngLat, lngLat),
+                        0.028 // Adjust the transition speed as needed
+                    );
+                    this.currentStreetViewBearing = bearing;
+                    // bearing = this.calculateBearing(this.previousLngLat, lngLat); // TODO: Calculate actual bearing
+                } else {
+                    // slowly rotate the map at a constant rate
+                    bearing = this.flyInEndBearing - animationPhase * 200.0;
+                    // bearing = startBearing - animationPhase * 200.0;
+                }
+
+                this.previousLngLat = lngLat;
+
+                updateAnimationPhase(animationPhase);
+
+                // compute corrected camera ground position, so that he leading edge of the path is in view
+                var correctedPosition = this.computeCameraPosition(
+                    this.isStreetViewAnimation,
+                    this.flyInEndPitch,
+                    bearing,
+                    lngLat,
+                    this.flyInEndAltitude,
+                    true // smooth
+                );
+
+                // set the pitch and bearing of the camera
+                const camera = map.getFreeCameraOptions();
+                camera.setPitchBearing(this.flyInEndPitch, bearing);
+
+                console.log('Corrected pos: ', correctedPosition);
+                console.log('Start altitude: ', this.flyInEndAltitude);
+                // set the position and altitude of the camera
+                camera.position = MercatorCoordinate.fromLngLat(correctedPosition, this.flyInEndAltitude);
+
+                // apply the new camera options
+                map.setFreeCameraOptions(camera);
 
-      
-            // calculate the distance along the path based on the animationPhase
-            const alongPath = turf.along(this.PATH, pathDistance * animationPhase).geometry
-              .coordinates;
-      
-            const lngLat = {
-              lng: alongPath[0],
-              lat: alongPath[1],
+                // repeat!
+                const innerFrameId = await window.requestAnimationFrame(frame);
+                updateFrameId(innerFrameId);
             };
-      
-            let bearing: number;
-            if (this.isStreetViewAnimation){
-                bearing = this.lerp(
-                    this.currentStreetViewBearing,
-                    this.calculateBearing(this.previousLngLat, lngLat),
-                    0.028 // Adjust the transition speed as needed
-                  );
-                  this.currentStreetViewBearing = bearing;
-                // bearing = this.calculateBearing(this.previousLngLat, lngLat); // TODO: Calculate actual bearing
-            } else {
-                // slowly rotate the map at a constant rate
-                bearing = this.flyInEndBearing - animationPhase * 200.0;
-                // bearing = startBearing - animationPhase * 200.0;
-            }
 
-            this.previousLngLat = lngLat;
-            
-            updateAnimationPhase(animationPhase);
-      
-            // compute corrected camera ground position, so that he leading edge of the path is in view
-            var correctedPosition = this.computeCameraPosition(
-              this.isStreetViewAnimation,
-              this.flyInEndPitch,
-              bearing,
-              lngLat,
-              this.flyInEndAltitude,
-              true // smooth
-            );
-      
-            // set the pitch and bearing of the camera
-            const camera = map.getFreeCameraOptions();
-            camera.setPitchBearing(this.flyInEndPitch, bearing);
-      
-            console.log("Corrected pos: ", correctedPosition);
-            console.log("Start altitude: ", this.flyInEndAltitude);
-            // set the position and altitude of the camera
-            camera.position = MercatorCoordinate.fromLngLat(
-              correctedPosition,
-              this.flyInEndAltitude
-            );
-
-      
-            // apply the new camera options
-            map.setFreeCameraOptions(camera);
-      
-            // repeat!
-            const innerFrameId = await window.requestAnimationFrame(frame);
-            updateFrameId(innerFrameId);
-          };
-      
-          const outerFrameId = await window.requestAnimationFrame(frame);
-          updateFrameId(outerFrameId);
+            const outerFrameId = await window.requestAnimationFrame(frame);
+            updateFrameId(outerFrameId);
         });
-      };
+    };
 
-    public flyInAndRotate = async ({
-        map,
-        updateFrameId
-      }:
-      {
-        map: MapRef,
-        updateFrameId: (newFrameId: number) => void
-      }
-      ) => {
-        return new Promise<{bearing: number, altitude: number}>(async (resolve) => {
-          let start: number | null;
-      
-          var currentAltitude;
-          var currentBearing;
-          var currentPitch;
-      
-          // the animation frame will run as many times as necessary until the duration has been reached
-          const frame = async (time: number) => {
-            if (!start) {
-              start = time;
-            }
-      
-            // otherwise, use the current time to determine how far along in the duration we are
-            let animationPhase = (time - start) / this.flyToDuration;
-      
-            // because the phase calculation is imprecise, the final zoom can vary
-            // if it ended up greater than 1, set it to 1 so that we get the exact endAltitude that was requested
-            if (animationPhase > 1) {
-              animationPhase = 1;
-            }
-      
-            currentAltitude = this.START_ALTITUDE + (this.flyInEndAltitude - this.START_ALTITUDE) * d3.easeCubicOut(animationPhase)
-            // rotate the camera between startBearing and endBearing
-            currentBearing = this.flyInStartBearing + (this.flyInEndBearing - this.flyInStartBearing) * d3.easeCubicOut(animationPhase)
-      
-            currentPitch = this.FLY_IN_START_PITCH + (this.flyInEndPitch - this.FLY_IN_START_PITCH) * d3.easeCubicOut(animationPhase)
-      
-            // compute corrected camera ground position, so the start of the path is always in view
-            var correctedPosition = this.computeCameraPosition(
-              false,
-              currentPitch,
-              currentBearing,
-              this.FIRST_LNG_LAT,
-              currentAltitude
-            );
-      
-            // set the pitch and bearing of the camera
-            const camera = map.getFreeCameraOptions();
-            camera.setPitchBearing(currentPitch, currentBearing);
-      
-            // set the position and altitude of the camera
-            camera.position = MercatorCoordinate.fromLngLat(
-              correctedPosition,
-              currentAltitude
-            );
-      
-            // apply the new camera options
-            map.setFreeCameraOptions(camera);
-      
-            // when the animationPhase is done, resolve the promise so the parent function can move on to the next step in the sequence
-            if (animationPhase === 1) {
-              resolve({
-                bearing: currentBearing,
-                altitude: currentAltitude,
-              });
-      
-              // return so there are no further iterations of this frame
-              return;
-            }
-      
-            const innerFrameId = await window.requestAnimationFrame(frame);
-            updateFrameId(innerFrameId);
-            
-          };
-      
-         const outerFrameId = await window.requestAnimationFrame(frame);
-         updateFrameId(outerFrameId);
+    public flyInAndRotate = async ({ map, updateFrameId }: { map: MapRef; updateFrameId: (newFrameId: number) => void }) => {
+        return new Promise<{ bearing: number; altitude: number }>(async resolve => {
+            let start: number | null;
+
+            var currentAltitude;
+            var currentBearing;
+            var currentPitch;
+
+            // the animation frame will run as many times as necessary until the duration has been reached
+            const frame = async (time: number) => {
+                if (!start) {
+                    start = time;
+                }
+
+                // otherwise, use the current time to determine how far along in the duration we are
+                let animationPhase = (time - start) / this.flyToDuration;
+
+                // because the phase calculation is imprecise, the final zoom can vary
+                // if it ended up greater than 1, set it to 1 so that we get the exact endAltitude that was requested
+                if (animationPhase > 1) {
+                    animationPhase = 1;
+                }
+
+                currentAltitude = this.START_ALTITUDE + (this.flyInEndAltitude - this.START_ALTITUDE) * d3.easeCubicOut(animationPhase);
+                // rotate the camera between startBearing and endBearing
+                currentBearing = this.flyInStartBearing + (this.flyInEndBearing - this.flyInStartBearing) * d3.easeCubicOut(animationPhase);
+
+                currentPitch = this.FLY_IN_START_PITCH + (this.flyInEndPitch - this.FLY_IN_START_PITCH) * d3.easeCubicOut(animationPhase);
+
+                // compute corrected camera ground position, so the start of the path is always in view
+                var correctedPosition = this.computeCameraPosition(false, currentPitch, currentBearing, this.FIRST_LNG_LAT, currentAltitude);
+
+                // set the pitch and bearing of the camera
+                const camera = map.getFreeCameraOptions();
+                camera.setPitchBearing(currentPitch, currentBearing);
+
+                // set the position and altitude of the camera
+                camera.position = MercatorCoordinate.fromLngLat(correctedPosition, currentAltitude);
+
+                // apply the new camera options
+                map.setFreeCameraOptions(camera);
+
+                // when the animationPhase is done, resolve the promise so the parent function can move on to the next step in the sequence
+                if (animationPhase === 1) {
+                    resolve({
+                        bearing: currentBearing,
+                        altitude: currentAltitude,
+                    });
+
+                    // return so there are no further iterations of this frame
+                    return;
+                }
+
+                const innerFrameId = await window.requestAnimationFrame(frame);
+                updateFrameId(innerFrameId);
+            };
+
+            const outerFrameId = await window.requestAnimationFrame(frame);
+            updateFrameId(outerFrameId);
         });
-      };
+    };
 
-      previousCameraPosition: {lng: number, lat: number} | null = null;
+    previousCameraPosition: { lng: number; lat: number } | null = null;
 
-      lerp = (start: number, end: number, amt: number) => {
+    lerp = (start: number, end: number, amt: number) => {
         return (1 - amt) * start + amt * end;
-      }
-
-      computeCameraPosition = (
-        isStreetViewAnimation: boolean,
-        pitch: number,
-        bearing: number,
-        targetPosition: {lng: number, lat: number},
-        altitude: number,
-        smooth = false
-      ) => {
+    };
+
+    computeCameraPosition = (isStreetViewAnimation: boolean, pitch: number, bearing: number, targetPosition: { lng: number; lat: number }, altitude: number, smooth = false) => {
         const bearingInRadian = (bearing * Math.PI) / 180;
-        const pitchInRadian = ((90 - pitch)* Math.PI) / 180;
+        const pitchInRadian = ((90 - pitch) * Math.PI) / 180;
 
         let correctedLng = targetPosition.lng;
         let correctedLat = targetPosition.lat;
 
         if (!isStreetViewAnimation) {
-            const lngDiff =
-                ((altitude / Math.tan(pitchInRadian)) *
-                Math.sin(-bearingInRadian)) /
-                70000; // ~70km/degree longitude
-            const latDiff =
-                ((altitude / Math.tan(pitchInRadian)) *
-                Math.cos(-bearingInRadian)) /
-                110000 // 110km/degree latitude
+            const lngDiff = ((altitude / Math.tan(pitchInRadian)) * Math.sin(-bearingInRadian)) / 70000; // ~70km/degree longitude
+            const latDiff = ((altitude / Math.tan(pitchInRadian)) * Math.cos(-bearingInRadian)) / 110000; // 110km/degree latitude
 
             correctedLng = targetPosition.lng + lngDiff;
             correctedLat = targetPosition.lat - latDiff;
-
         }
-        
+
         const newCameraPosition = {
-          lng: correctedLng,
-          lat: correctedLat
+            lng: correctedLng,
+            lat: correctedLat,
         };
-      
+
         if (smooth) {
-          if (this.previousCameraPosition) {
-            newCameraPosition.lng = this.lerp(newCameraPosition.lng, this.previousCameraPosition.lng, this.SMOOTH_FACTOR);
-            newCameraPosition.lat = this.lerp(newCameraPosition.lat, this.previousCameraPosition.lat, this.SMOOTH_FACTOR);
-          }
+            if (this.previousCameraPosition) {
+                newCameraPosition.lng = this.lerp(newCameraPosition.lng, this.previousCameraPosition.lng, this.SMOOTH_FACTOR);
+                newCameraPosition.lat = this.lerp(newCameraPosition.lat, this.previousCameraPosition.lat, this.SMOOTH_FACTOR);
+            }
         }
-      
-        this.previousCameraPosition = newCameraPosition
-      
+
+        this.previousCameraPosition = newCameraPosition;
+
         return newCameraPosition;
-      };
-      
-      public static createGeoJSONCircle = (center: number[], radiusInKm: number, points = 64): Feature<Geometry, GeoJsonProperties>=> {
+    };
+
+    public static createGeoJSONCircle = (center: number[], radiusInKm: number, points = 64): Feature<Geometry, GeoJsonProperties> => {
         const coords = {
-          latitude: center[1],
-          longitude: center[0],
+            latitude: center[1],
+            longitude: center[0],
         };
         const km = radiusInKm;
         const ret = [];
-        const distanceX = km / (111.320 * Math.cos((coords.latitude * Math.PI) / 180));
+        const distanceX = km / (111.32 * Math.cos((coords.latitude * Math.PI) / 180));
         const distanceY = km / 110.574;
         let theta;
         let x;
         let y;
         for (let i = 0; i < points; i += 1) {
-          theta = (i / points) * (2 * Math.PI);
-          x = distanceX * Math.cos(theta);
-          y = distanceY * Math.sin(theta);
-          ret.push([coords.longitude + x, coords.latitude + y]);
+            theta = (i / points) * (2 * Math.PI);
+            x = distanceX * Math.cos(theta);
+            y = distanceY * Math.sin(theta);
+            ret.push([coords.longitude + x, coords.latitude + y]);
         }
         ret.push(ret[0]);
         return {
-          type: 'Feature',
-          geometry: {
-            type: 'Polygon',
-            coordinates: [ret],
-          },
-          properties: {}
+            type: 'Feature',
+            geometry: {
+                type: 'Polygon',
+                coordinates: [ret],
+            },
+            properties: {},
         };
-      }
+    };
 
-      private calculateBearing(
-        from: { lng: number; lat: number },
-        to: { lng: number; lat: number }
-      ): number {
+    private calculateBearing(from: { lng: number; lat: number }, to: { lng: number; lat: number }): number {
         const lon1 = from.lng;
         const lat1 = from.lat;
         const lon2 = to.lng;
         const lat2 = to.lat;
-      
+
         const lon1Rad = (lon1 * Math.PI) / 180;
         const lon2Rad = (lon2 * Math.PI) / 180;
         const lat1Rad = (lat1 * Math.PI) / 180;
         const lat2Rad = (lat2 * Math.PI) / 180;
-      
+
         const y = Math.sin(lon2Rad - lon1Rad) * Math.cos(lat2Rad);
-        const x =
-          Math.cos(lat1Rad) * Math.sin(lat2Rad) -
-          Math.sin(lat1Rad) * Math.cos(lat2Rad) * Math.cos(lon2Rad - lon1Rad);
-      
-        let bearing = Math.atan2(y,x);
-      
+        const x = Math.cos(lat1Rad) * Math.sin(lat2Rad) - Math.sin(lat1Rad) * Math.cos(lat2Rad) * Math.cos(lon2Rad - lon1Rad);
+
+        let bearing = Math.atan2(y, x);
+
         // Convert bearing from radians to degrees
         bearing = (bearing * 180) / Math.PI;
-      
+
         // Ensure the bearing is within [0, 360)
         if (bearing < 0) {
-          bearing += 360;
+            bearing += 360;
         }
-      
-        return bearing;
-      }
-
 
-}
\ No newline at end of file
+        return bearing;
+    }
+}
diff --git a/src/client/views/nodes/MapBox/DirectionsAnchorMenu.tsx b/src/client/views/nodes/MapBox/DirectionsAnchorMenu.tsx
index bf4028f01..f9607becf 100644
--- a/src/client/views/nodes/MapBox/DirectionsAnchorMenu.tsx
+++ b/src/client/views/nodes/MapBox/DirectionsAnchorMenu.tsx
@@ -1,15 +1,15 @@
-import React = require('react');
-import { observer } from "mobx-react";
-import { AntimodeMenu, AntimodeMenuProps } from "../../AntimodeMenu";
-import { IReactionDisposer, ObservableMap, reaction } from "mobx";
-import { Doc, Opt } from "../../../../fields/Doc";
-import { returnFalse, unimplementedFunction } from "../../../../Utils";
-import { NumCast, StrCast } from "../../../../fields/Types";
-import { SelectionManager } from "../../../util/SelectionManager";
-import { IconButton } from "browndash-components";
-import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-import { SettingsManager } from "../../../util/SettingsManager";
-import { IconLookup, faAdd, faCalendarDays, faRoute } from "@fortawesome/free-solid-svg-icons";
+import * as React from 'react';
+import { observer } from 'mobx-react';
+import { AntimodeMenu, AntimodeMenuProps } from '../../AntimodeMenu';
+import { IReactionDisposer, ObservableMap, reaction } from 'mobx';
+import { Doc, Opt } from '../../../../fields/Doc';
+import { returnFalse, unimplementedFunction } from '../../../../Utils';
+import { NumCast, StrCast } from '../../../../fields/Types';
+import { SelectionManager } from '../../../util/SelectionManager';
+import { IconButton } from 'browndash-components';
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import { SettingsManager } from '../../../util/SettingsManager';
+import { IconLookup, faAdd, faCalendarDays, faRoute } from '@fortawesome/free-solid-svg-icons';
 
 @observer
 export class DirectionsAnchorMenu extends AntimodeMenu<AntimodeMenuProps> {
@@ -32,9 +32,9 @@ export class DirectionsAnchorMenu extends AntimodeMenu<AntimodeMenuProps> {
 
     private title: string | undefined = undefined;
 
-    public setPinDoc(pinDoc: Doc){
-        this.title = StrCast(pinDoc.title ? pinDoc.title : `${NumCast(pinDoc.longitude)}, ${NumCast(pinDoc.latitude)}`) ;
-        console.log("Title: ", this.title)
+    public setPinDoc(pinDoc: Doc) {
+        this.title = StrCast(pinDoc.title ? pinDoc.title : `${NumCast(pinDoc.longitude)}, ${NumCast(pinDoc.latitude)}`);
+        console.log('Title: ', this.title);
     }
 
     public get Active() {
@@ -54,7 +54,7 @@ export class DirectionsAnchorMenu extends AntimodeMenu<AntimodeMenuProps> {
 
     componentDidMount() {
         this._disposer = reaction(
-            () => SelectionManager.Views().slice(),
+            () => SelectionManager.Views.slice(),
             sel => DirectionsAnchorMenu.Instance.fadeOut(true)
         );
     }
@@ -95,43 +95,28 @@ export class DirectionsAnchorMenu extends AntimodeMenu<AntimodeMenuProps> {
 
     render() {
         const buttons = (
-            <div className='directions-menu-buttons' style={{display: 'flex'}}>
+            <div className="directions-menu-buttons" style={{ display: 'flex' }}>
                 <IconButton
                     tooltip="Add route" //
                     onPointerDown={this.Delete}
                     icon={<FontAwesomeIcon icon={faAdd as IconLookup} />}
                     color={SettingsManager.userColor}
                 />
-            
-            
-                <IconButton
-                    tooltip='Animate route'
-                    onPointerDown={this.Delete} /**TODO: fix */
-                    icon={<FontAwesomeIcon icon={faRoute as IconLookup}/>}
-                    color={SettingsManager.userColor}
-                />
-                <IconButton
-                    tooltip='Add to calendar'
-                    onPointerDown={this.Delete} /**TODO: fix */
-                    icon={<FontAwesomeIcon icon={faCalendarDays as IconLookup}/>}
-                    color={SettingsManager.userColor}
-                />
+
+                <IconButton tooltip="Animate route" onPointerDown={this.Delete} /**TODO: fix */ icon={<FontAwesomeIcon icon={faRoute as IconLookup} />} color={SettingsManager.userColor} />
+                <IconButton tooltip="Add to calendar" onPointerDown={this.Delete} /**TODO: fix */ icon={<FontAwesomeIcon icon={faCalendarDays as IconLookup} />} color={SettingsManager.userColor} />
             </div>
-        )
+        );
 
         return this.getElement(
-            <div ref={DirectionsAnchorMenu.top} style={{ height: 'max-content' , width: '100%', display: 'flex', flexDirection: 'column' }}>
+            <div ref={DirectionsAnchorMenu.top} style={{ height: 'max-content', width: '100%', display: 'flex', flexDirection: 'column' }}>
                 <div>{this.title}</div>
-                <div className='direction-inputs' style={{display: 'flex', flexDirection: 'column'}}>
-                    <input
-                        placeholder="Origin"
-                    />
-                    <input
-                        placeholder="Destination"
-                    />
+                <div className="direction-inputs" style={{ display: 'flex', flexDirection: 'column' }}>
+                    <input placeholder="Origin" />
+                    <input placeholder="Destination" />
                 </div>
                 {buttons}
             </div>
-        )
+        );
     }
-}
\ No newline at end of file
+}
diff --git a/src/client/views/nodes/MapboxMapBox/MapboxContainer.tsx b/src/client/views/nodes/MapboxMapBox/MapboxContainer.tsx
index a6182991d..6a14427c0 100644
--- a/src/client/views/nodes/MapboxMapBox/MapboxContainer.tsx
+++ b/src/client/views/nodes/MapboxMapBox/MapboxContainer.tsx
@@ -43,7 +43,7 @@ import { MapProvider, Map as MapboxMap } from 'react-map-gl';
  * A map marker is considered a document that contains a collection with stacking view of documents, it has a lat, lng location, which is passed to Maps API's custom marker (red pin) to be rendered on the google maps
  */
 
-const mapboxApiKey = "pk.eyJ1IjoiemF1bHRhdmFuZ2FyIiwiYSI6ImNsbnc2eHJpbTA1ZTUyam85aGx4Z2FhbGwifQ.2Kqw9mk-9wAAg9kmHmKzcg";
+const mapboxApiKey = 'pk.eyJ1IjoiemF1bHRhdmFuZ2FyIiwiYSI6ImNsbnc2eHJpbTA1ZTUyam85aGx4Z2FhbGwifQ.2Kqw9mk-9wAAg9kmHmKzcg';
 const bingApiKey = process.env.BING_MAPS; // if you're running local, get a Bing Maps api key here: https://www.bingmapsportal.com/  and then add it to the .env file in the Dash-Web root directory as: _CLIENT_BING_MAPS=<your apikey>
 
 /**
@@ -198,7 +198,7 @@ export class MapBoxContainer extends ViewBoxAnnotatableComponent<ViewBoxAnnotata
                 title="Toggle Sidebar"
                 style={{
                     display: !this.props.isContentActive() ? 'none' : undefined,
-                    top: StrCast(this.rootDoc._layout_showTitle) === 'title' ? 20 : 5,
+                    top: StrCast(this.Document._layout_showTitle) === 'title' ? 20 : 5,
                     backgroundColor: this.SidebarShown ? Colors.MEDIUM_BLUE : Colors.BLACK,
                 }}
                 onPointerDown={this.sidebarBtnDown}>
@@ -230,8 +230,8 @@ export class MapBoxContainer extends ViewBoxAnnotatableComponent<ViewBoxAnnotata
         });
 
         const targetCreator = (annotationOn: Doc | undefined) => {
-            const target = DocUtils.GetNewTextDoc('Note linked to ' + this.rootDoc.title, 0, 0, 100, 100, undefined, annotationOn, undefined, 'yellow');
-            FormattedTextBox.SelectOnLoad = target[Id];
+            const target = DocUtils.GetNewTextDoc('Note linked to ' + this.Document.title, 0, 0, 100, 100, undefined, annotationOn, undefined, 'yellow');
+            FormattedTextBox.SetSelectOnLoad(target);
             return target;
         };
         const docView = this.props.DocumentView?.();
@@ -324,7 +324,7 @@ export class MapBoxContainer extends ViewBoxAnnotatableComponent<ViewBoxAnnotata
     };
 
     @observable
-    bingSearchBarContents: any = this.rootDoc.map; // For Bing Maps: The contents of the Bing search bar (string)
+    bingSearchBarContents: any = this.Document.map; // For Bing Maps: The contents of the Bing search bar (string)
 
     geoDataRequestOptions = {
         entityType: 'PopulatedPlace',
@@ -357,9 +357,9 @@ export class MapBoxContainer extends ViewBoxAnnotatableComponent<ViewBoxAnnotata
     deselectPin = () => {
         if (this.selectedPin) {
             // Removes filter
-            Doc.setDocFilter(this.rootDoc, 'latitude', this.selectedPin.latitude, 'remove');
-            Doc.setDocFilter(this.rootDoc, 'longitude', this.selectedPin.longitude, 'remove');
-            Doc.setDocFilter(this.rootDoc, LinkedTo, `mapPin=${Field.toScriptString(DocCast(this.selectedPin))}`, 'remove');
+            Doc.setDocFilter(this.Document, 'latitude', this.selectedPin.latitude, 'remove');
+            Doc.setDocFilter(this.Document, 'longitude', this.selectedPin.longitude, 'remove');
+            Doc.setDocFilter(this.Document, LinkedTo, `mapPin=${Field.toScriptString(DocCast(this.selectedPin))}`, 'remove');
 
             const temp = this.selectedPin;
             if (!this._unmounting) {
@@ -372,7 +372,7 @@ export class MapBoxContainer extends ViewBoxAnnotatableComponent<ViewBoxAnnotata
             }
             this.map_docToPinMap.set(temp, newpin);
             this.selectedPin = undefined;
-            this.bingSearchBarContents = this.rootDoc.map;
+            this.bingSearchBarContents = this.Document.map;
         }
     };
 
@@ -389,9 +389,9 @@ export class MapBoxContainer extends ViewBoxAnnotatableComponent<ViewBoxAnnotata
         this.selectedPin = pinDoc;
         this.bingSearchBarContents = pinDoc.map;
 
-        // Doc.setDocFilter(this.rootDoc, 'latitude', this.selectedPin.latitude, 'match');
-        // Doc.setDocFilter(this.rootDoc, 'longitude', this.selectedPin.longitude, 'match');
-        Doc.setDocFilter(this.rootDoc, LinkedTo, `mapPin=${Field.toScriptString(this.selectedPin)}`, 'check');
+        // Doc.setDocFilter(this.Document, 'latitude', this.selectedPin.latitude, 'match');
+        // Doc.setDocFilter(this.Document, 'longitude', this.selectedPin.longitude, 'match');
+        Doc.setDocFilter(this.Document, LinkedTo, `mapPin=${Field.toScriptString(this.selectedPin)}`, 'check');
 
         this.recolorPin(this.selectedPin, 'green');
 
@@ -460,8 +460,8 @@ export class MapBoxContainer extends ViewBoxAnnotatableComponent<ViewBoxAnnotata
     getAnchor = (addAsAnnotation: boolean, pinProps?: PinProps, existingPin?: Doc) => {
         /// this should use SELECTED pushpin for lat/long  if there is a selection, otherwise CENTER
         const anchor = Docs.Create.ConfigDocument({
-            title: 'MapAnchor:' + this.rootDoc.title,
-            text: StrCast(this.selectedPin?.map) || StrCast(this.rootDoc.map) || 'map location',
+            title: 'MapAnchor:' + this.Document.title,
+            text: StrCast(this.selectedPin?.map) || StrCast(this.Document.map) || 'map location',
             config_latitude: NumCast((existingPin ?? this.selectedPin)?.latitude ?? this.dataDoc.latitude),
             config_longitude: NumCast((existingPin ?? this.selectedPin)?.longitude ?? this.dataDoc.longitude),
             config_map_zoom: NumCast(this.dataDoc.map_zoom),
@@ -469,15 +469,15 @@ export class MapBoxContainer extends ViewBoxAnnotatableComponent<ViewBoxAnnotata
             config_map: StrCast((existingPin ?? this.selectedPin)?.map) || StrCast(this.dataDoc.map),
             layout_unrendered: true,
             mapPin: existingPin ?? this.selectedPin,
-            annotationOn: this.rootDoc,
+            annotationOn: this.Document,
         });
         if (anchor) {
             if (!addAsAnnotation) anchor.backgroundColor = 'transparent';
             addAsAnnotation && this.addDocument(anchor);
-            PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: { ...(pinProps?.pinData ?? {}), map: true } }, this.rootDoc);
+            PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: { ...(pinProps?.pinData ?? {}), map: true } }, this.Document);
             return anchor;
         }
-        return this.rootDoc;
+        return this.Document;
     };
 
     map_docToPinMap = new Map<Doc, any>();
@@ -524,9 +524,9 @@ export class MapBoxContainer extends ViewBoxAnnotatableComponent<ViewBoxAnnotata
     deleteSelectedPin = undoable(() => {
         if (this.selectedPin) {
             // Removes filter
-            Doc.setDocFilter(this.rootDoc, 'latitude', this.selectedPin.latitude, 'remove');
-            Doc.setDocFilter(this.rootDoc, 'longitude', this.selectedPin.longitude, 'remove');
-            Doc.setDocFilter(this.rootDoc, LinkedTo, `mapPin=${Field.toScriptString(DocCast(this.selectedPin))}`, 'remove');
+            Doc.setDocFilter(this.Document, 'latitude', this.selectedPin.latitude, 'remove');
+            Doc.setDocFilter(this.Document, 'longitude', this.selectedPin.longitude, 'remove');
+            Doc.setDocFilter(this.Document, LinkedTo, `mapPin=${Field.toScriptString(DocCast(this.selectedPin))}`, 'remove');
 
             this.removePushpin(this.selectedPin);
         }
@@ -614,7 +614,7 @@ export class MapBoxContainer extends ViewBoxAnnotatableComponent<ViewBoxAnnotata
         this.MicrosoftMaps.Events.addHandler(this._bingMap.current, 'maptypechanged', undoable(this.updateMapType, 'Map ViewType Change'));
 
         this._disposers.mapLocation = reaction(
-            () => this.rootDoc.map,
+            () => this.Document.map,
             mapLoc => (this.bingSearchBarContents = mapLoc),
             { fireImmediately: true }
         );
@@ -639,7 +639,7 @@ export class MapBoxContainer extends ViewBoxAnnotatableComponent<ViewBoxAnnotata
         );
 
         this._disposers.location = reaction(
-            () => ({ lat: this.rootDoc.latitude, lng: this.rootDoc.longitude, zoom: this.rootDoc.map_zoom, mapType: this.rootDoc.map_type }),
+            () => ({ lat: this.Document.latitude, lng: this.Document.longitude, zoom: this.Document.map_zoom, mapType: this.Document.map_type }),
             locationObject => {
                 // if (this._bingMap.current)
                 try {
@@ -690,7 +690,7 @@ export class MapBoxContainer extends ViewBoxAnnotatableComponent<ViewBoxAnnotata
                 }
             },
             e => {
-                const createPin = () => this.createPushpin(this.rootDoc.latitude, this.rootDoc.longitude, this.rootDoc.map);
+                const createPin = () => this.createPushpin(this.Document.latitude, this.Document.longitude, this.Document.map);
                 if (this.bingSearchBarContents) {
                     this.bingSearch().then(createPin);
                 } else createPin();
@@ -706,7 +706,7 @@ export class MapBoxContainer extends ViewBoxAnnotatableComponent<ViewBoxAnnotata
     render() {
         // bcz:  no idea what's going on here, but bings maps have some kind of bug
         // such that we need to delay rendering a second map on startup until the first map is rendered.
-        this.rootDoc[DocCss];
+        this.Document[DocCss];
         if (MapBoxContainer._rerenderDelay) {
             // prettier-ignore
             this._rerenderTimeout = this._rerenderTimeout ??
@@ -715,7 +715,7 @@ export class MapBoxContainer extends ViewBoxAnnotatableComponent<ViewBoxAnnotata
                         MapBoxContainer._rerenderDelay = 0;
                     }
                     this._rerenderTimeout = undefined;
-                    this.rootDoc[DocCss] = this.rootDoc[DocCss] + 1;
+                    this.Document[DocCss] = this.Document[DocCss] + 1;
                 }), MapBoxContainer._rerenderDelay);
             return null;
         }
@@ -732,7 +732,7 @@ export class MapBoxContainer extends ViewBoxAnnotatableComponent<ViewBoxAnnotata
                     style={{ width: `calc(100% - ${this.sidebarWidthPercent})`, pointerEvents: this.pointerEvents() }}>
                     <div style={{ mixBlendMode: 'multiply' }}>{renderAnnotations(this.transparentFilter)}</div>
                     {renderAnnotations(this.opaqueFilter)}
-                    {SnappingManager.GetIsDragging() ? null : renderAnnotations()}
+                    {SnappingManager.IsDragging ? null : renderAnnotations()}
 
                     <div className="mapBox-searchbar">
                         <EditableText
@@ -758,15 +758,10 @@ export class MapBoxContainer extends ViewBoxAnnotatableComponent<ViewBoxAnnotata
                         </div>
                     </div>
                     <MapProvider>
-                        <MapboxMap
-                            id="mabox-map"
-                            mapStyle={`mapbox://styles/mapbox/streets-v9`}
-                            mapboxAccessToken={mapboxApiKey}
-                        />
+                        <MapboxMap id="mabox-map" mapStyle={`mapbox://styles/mapbox/streets-v9`} mapboxAccessToken={mapboxApiKey} />
                     </MapProvider>
-                    
-  
-{/* 
+
+                    {/* 
                     <BingMapsReact
                         onMapReady={this.bingMapReady} //
                         bingMapsKey={bingApiKey}
@@ -786,7 +781,6 @@ export class MapBoxContainer extends ViewBoxAnnotatableComponent<ViewBoxAnnotata
                                           {...this.props}
                                           renderDepth={this.props.renderDepth + 1}
                                           Document={pushpin}
-                                          DataDoc={undefined}
                                           PanelWidth={returnOne}
                                           PanelHeight={returnOne}
                                           NativeWidth={returnOne}
@@ -824,7 +818,7 @@ export class MapBoxContainer extends ViewBoxAnnotatableComponent<ViewBoxAnnotata
                         ref={this._sidebarRef}
                         {...this.props}
                         fieldKey={this.fieldKey}
-                        rootDoc={this.rootDoc}
+                        Document={this.Document}
                         layoutDoc={this.layoutDoc}
                         dataDoc={this.dataDoc}
                         usePanelWidth={true}
diff --git a/webpack.config.js b/webpack.config.js
index a153616b8..d92086bc2 100644
--- a/webpack.config.js
+++ b/webpack.config.js
@@ -12,7 +12,7 @@ const plugins = [
     // new ForkTsCheckerWebpackPlugin({
     //     typescript: {
     //         // useTypescriptIncrementalApi: true,
-    //         eslint: true,
+    //         // eslint: true,
     //         memoryLimit: 8192,
     //     },
     //     // tslint: true,
-- 
cgit v1.2.3-70-g09d2

