From 65ab8c985a86f18ebb51a269f20d7865dcfc6589 Mon Sep 17 00:00:00 2001 From: srichman333 Date: Tue, 18 Jul 2023 10:50:16 -0400 Subject: click on histograms --- src/client/views/nodes/DataVizBox/components/TableBox.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'src/client/views/nodes/DataVizBox/components/TableBox.tsx') diff --git a/src/client/views/nodes/DataVizBox/components/TableBox.tsx b/src/client/views/nodes/DataVizBox/components/TableBox.tsx index d84e34d52..8c8264861 100644 --- a/src/client/views/nodes/DataVizBox/components/TableBox.tsx +++ b/src/client/views/nodes/DataVizBox/components/TableBox.tsx @@ -33,6 +33,7 @@ export class TableBox extends React.Component { const header = React.createRef(); return ( { {this.props.pairs?.map((p, i) => { return ( - (p['select' + this.props.docView?.()?.rootDoc![Id]] = !p['select' + this.props.docView?.()?.rootDoc![Id]]))}> + (p['select' + this.props.docView?.()?.rootDoc![Id]] = !p['select' + this.props.docView?.()?.rootDoc![Id]]))}> {this.columns.map(col => ( - {p[col]} + {p[col]} ))} ); -- cgit v1.2.3-70-g09d2 From 900efdb5c08397e53e1d00555fc6eac208eff5a1 Mon Sep 17 00:00:00 2001 From: srichman333 Date: Tue, 18 Jul 2023 16:24:57 -0400 Subject: brushed graph has can have multiple links + still link to the correct graph for data --- src/client/views/nodes/DataVizBox/DataVizBox.scss | 1 + src/client/views/nodes/DataVizBox/components/LineChart.tsx | 4 ++-- src/client/views/nodes/DataVizBox/components/TableBox.tsx | 1 + 3 files changed, 4 insertions(+), 2 deletions(-) (limited to 'src/client/views/nodes/DataVizBox/components/TableBox.tsx') diff --git a/src/client/views/nodes/DataVizBox/DataVizBox.scss b/src/client/views/nodes/DataVizBox/DataVizBox.scss index b3cbc89aa..5e7230271 100644 --- a/src/client/views/nodes/DataVizBox/DataVizBox.scss +++ b/src/client/views/nodes/DataVizBox/DataVizBox.scss @@ -1,6 +1,7 @@ .dataviz { overflow: hidden; height: 100%; + width: 100%; .datatype-button{ margin: 0; diff --git a/src/client/views/nodes/DataVizBox/components/LineChart.tsx b/src/client/views/nodes/DataVizBox/components/LineChart.tsx index cb6ba6fe7..637ed0ead 100644 --- a/src/client/views/nodes/DataVizBox/components/LineChart.tsx +++ b/src/client/views/nodes/DataVizBox/components/LineChart.tsx @@ -1,7 +1,6 @@ import { action, computed, IReactionDisposer, observable, reaction } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; -// import d3 import * as d3 from 'd3'; import { Doc, DocListCast } from '../../../../../fields/Doc'; import { Id } from '../../../../../fields/FieldSymbols'; @@ -56,7 +55,8 @@ export class LineChart extends React.Component { } @computed get incomingLinks() { return LinkManager.Instance.getAllRelatedLinks(this.props.rootDoc) // out of all links - .filter(link => link.link_anchor_1 !== this.props.rootDoc) // get links where this chart doc is the target of the link + .filter(link => { + return link.link_anchor_1 == this.props.rootDoc.draggedFrom}) // 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 } @computed get incomingSelected() { diff --git a/src/client/views/nodes/DataVizBox/components/TableBox.tsx b/src/client/views/nodes/DataVizBox/components/TableBox.tsx index 8c8264861..ff43f67d9 100644 --- a/src/client/views/nodes/DataVizBox/components/TableBox.tsx +++ b/src/client/views/nodes/DataVizBox/components/TableBox.tsx @@ -51,6 +51,7 @@ export class TableBox extends React.Component { const embedding = Doc.MakeEmbedding(this.props.docView?.()!.rootDoc!); embedding._dataVizView = DataVizView.LINECHART; embedding._data_vizAxes = new List([col, col]); + embedding._draggedFrom = this.props.docView?.()!.rootDoc!; embedding.annotationOn = annotationOn; //this.props.docView?.()!.rootDoc!; return embedding; }; -- cgit v1.2.3-70-g09d2 From 27441b60e7af8ea93f277ab3bdc2990ad25ea326 Mon Sep 17 00:00:00 2001 From: bobzel Date: Wed, 19 Jul 2023 19:03:59 -0400 Subject: fixed showing of link lines for data visualization views. --- src/client/views/nodes/DataVizBox/components/TableBox.tsx | 5 ++++- src/client/views/nodes/DocumentView.tsx | 8 ++++---- 2 files changed, 8 insertions(+), 5 deletions(-) (limited to 'src/client/views/nodes/DataVizBox/components/TableBox.tsx') diff --git a/src/client/views/nodes/DataVizBox/components/TableBox.tsx b/src/client/views/nodes/DataVizBox/components/TableBox.tsx index ff43f67d9..ca888e13f 100644 --- a/src/client/views/nodes/DataVizBox/components/TableBox.tsx +++ b/src/client/views/nodes/DataVizBox/components/TableBox.tsx @@ -60,6 +60,7 @@ export class TableBox extends React.Component { 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.annoDragData.linkSourceDoc.followLinkToggle = e.annoDragData.dropDocument.annotationOn === this.props.rootDoc; // e.annoDragData.linkSourceDoc.followLinkZoom = false; } @@ -94,7 +95,9 @@ export class TableBox extends React.Component { return ( (p['select' + this.props.docView?.()?.rootDoc![Id]] = !p['select' + this.props.docView?.()?.rootDoc![Id]]))}> {this.columns.map(col => ( - {p[col]} + + {p[col]} + ))} ); diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index d7b4ca317..4211b8a81 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -975,8 +975,8 @@ export class DocumentViewInternal extends DocComponent - Doc.AreProtosEqual(link.link_anchor_1 as Doc, this.rootDoc) || - Doc.AreProtosEqual(link.link_anchor_2 as Doc, this.rootDoc) || + (link.link_matchEmbeddings ? link.link_anchor_1 === this.rootDoc : Doc.AreProtosEqual(link.link_anchor_1 as Doc, this.rootDoc)) || + (link.link_matchEmbeddings ? link.link_anchor_2 === this.rootDoc : Doc.AreProtosEqual(link.link_anchor_2 as Doc, this.rootDoc)) || ((link.link_anchor_1 as Doc)?.layout_unrendered && Doc.AreProtosEqual((link.link_anchor_1 as Doc)?.annotationOn as Doc, this.rootDoc)) || ((link.link_anchor_2 as Doc)?.layout_unrendered && Doc.AreProtosEqual((link.link_anchor_2 as Doc)?.annotationOn as Doc, this.rootDoc)) ); @@ -1237,7 +1237,7 @@ export class DocumentViewInternal extends DocComponent { return this.docView?._componentView; } get allLinks() { - return this.docView?.allLinks || []; + return (this.docView?.allLinks || []).filter(link => !link.link_matchEmbeddings || link.link_anchor_1 === this.rootDoc || link.link_anchor_2 === this.rootDoc); } get LayoutFieldKey() { return this.docView?.LayoutFieldKey || 'layout'; -- cgit v1.2.3-70-g09d2 From 371f0309ec6b10a86b4a456d233be5b53cf93356 Mon Sep 17 00:00:00 2001 From: srichman333 Date: Thu, 20 Jul 2023 17:58:24 -0400 Subject: components + links + brushed TableBox --- src/client/views/nodes/DataVizBox/DataVizBox.scss | 4 ++-- src/client/views/nodes/DataVizBox/DataVizBox.tsx | 26 +++++++++++++++++----- .../nodes/DataVizBox/components/Histogram.tsx | 3 ++- .../views/nodes/DataVizBox/components/PieChart.tsx | 4 ++-- .../views/nodes/DataVizBox/components/TableBox.tsx | 22 ++++++++++++++++-- 5 files changed, 46 insertions(+), 13 deletions(-) (limited to 'src/client/views/nodes/DataVizBox/components/TableBox.tsx') diff --git a/src/client/views/nodes/DataVizBox/DataVizBox.scss b/src/client/views/nodes/DataVizBox/DataVizBox.scss index 5e7230271..32c0bbfc1 100644 --- a/src/client/views/nodes/DataVizBox/DataVizBox.scss +++ b/src/client/views/nodes/DataVizBox/DataVizBox.scss @@ -4,7 +4,7 @@ width: 100%; .datatype-button{ - margin: 0; - border: 1px solid white; + display: flex; + flex-direction: row; } } diff --git a/src/client/views/nodes/DataVizBox/DataVizBox.tsx b/src/client/views/nodes/DataVizBox/DataVizBox.tsx index 25098baf1..4ddebb833 100644 --- a/src/client/views/nodes/DataVizBox/DataVizBox.tsx +++ b/src/client/views/nodes/DataVizBox/DataVizBox.tsx @@ -14,6 +14,7 @@ import { TableBox } from './components/TableBox'; import './DataVizBox.scss'; import { Histogram } from './components/Histogram'; import { PieChart } from './components/PieChart'; +import { Toggle, ToggleType } from 'browndash-components'; export enum DataVizView { TABLE = 'table', @@ -103,7 +104,7 @@ export class DataVizBox extends ViewBoxAnnotatableComponent() { if (!this.pairs) return 'no data'; // prettier-ignore switch (this.dataVizView) { - case DataVizView.TABLE: return ; + case DataVizView.TABLE: return ; case DataVizView.LINECHART: return (this._chartRenderer = r ?? undefined)} height={height} width={width} fieldKey={this.fieldKey} margin={margin} rootDoc={this.rootDoc} axes={this.axes} pairs={this.pairs} dataDoc={this.dataDoc} />; case DataVizView.HISTOGRAM: return ; case DataVizView.PIECHART: return ; @@ -150,11 +151,24 @@ export class DataVizBox extends ViewBoxAnnotatableComponent() { { passive: false } ) }> - {/* */} - - - - +
+ this.layoutDoc._dataVizView = DataVizView.TABLE} + toggleStatus={this.layoutDoc._dataVizView == DataVizView.TABLE} + /> + this.layoutDoc._dataVizView = DataVizView.LINECHART} + toggleStatus={this.layoutDoc._dataVizView == DataVizView.LINECHART} + /> + this.layoutDoc._dataVizView = DataVizView.HISTOGRAM} + toggleStatus={this.layoutDoc._dataVizView == DataVizView.HISTOGRAM} + /> + this.layoutDoc._dataVizView = DataVizView.PIECHART} + toggleStatus={this.layoutDoc._dataVizView == DataVizView.PIECHART} + /> +
{this.selectView} ); diff --git a/src/client/views/nodes/DataVizBox/components/Histogram.tsx b/src/client/views/nodes/DataVizBox/components/Histogram.tsx index b8be9bd13..01e6709fa 100644 --- a/src/client/views/nodes/DataVizBox/components/Histogram.tsx +++ b/src/client/views/nodes/DataVizBox/components/Histogram.tsx @@ -65,7 +65,8 @@ export class Histogram extends React.Component { } @computed get incomingLinks() { return LinkManager.Instance.getAllRelatedLinks(this.props.rootDoc) // out of all links - .filter(link => link.link_anchor_1 !== this.props.rootDoc) // get links where this chart doc is the target of the link + .filter(link => { + return link.link_anchor_1 == this.props.rootDoc.draggedFrom}) // 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 } @computed get incomingSelected() { diff --git a/src/client/views/nodes/DataVizBox/components/PieChart.tsx b/src/client/views/nodes/DataVizBox/components/PieChart.tsx index 6241e6221..05a2f1588 100644 --- a/src/client/views/nodes/DataVizBox/components/PieChart.tsx +++ b/src/client/views/nodes/DataVizBox/components/PieChart.tsx @@ -65,7 +65,8 @@ export class PieChart extends React.Component { } @computed get incomingLinks() { return LinkManager.Instance.getAllRelatedLinks(this.props.rootDoc) // out of all links - .filter(link => link.link_anchor_1 !== this.props.rootDoc) // get links where this chart doc is the target of the link + .filter(link => { + return link.link_anchor_1 == this.props.rootDoc.draggedFrom}) // 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 } @computed get incomingSelected() { @@ -359,7 +360,6 @@ export class PieChart extends React.Component { }; render() { - var selected: string; if (this._currSelected){ selected = '{ '; diff --git a/src/client/views/nodes/DataVizBox/components/TableBox.tsx b/src/client/views/nodes/DataVizBox/components/TableBox.tsx index ca888e13f..500e7b639 100644 --- a/src/client/views/nodes/DataVizBox/components/TableBox.tsx +++ b/src/client/views/nodes/DataVizBox/components/TableBox.tsx @@ -8,8 +8,11 @@ import { emptyFunction, returnFalse, setupMoveUpEvents, Utils } from '../../../. import { DragManager } from '../../../../util/DragManager'; import { DocumentView } from '../../DocumentView'; import { DataVizView } from '../DataVizBox'; +import { LinkManager } from '../../../../util/LinkManager'; +import { DocCast } from '../../../../../fields/Types'; interface TableBoxProps { + rootDoc: Doc; pairs: { [key: string]: any }[]; selectAxes: (axes: string[]) => void; axes: string[]; @@ -18,9 +21,24 @@ interface TableBoxProps { @observer export class TableBox extends React.Component { + + @computed get _tableData() { + if (this.incomingLinks.length! <= 0) return this.props.pairs; + return this.props.pairs?.filter(pair => (Array.from(Object.keys(pair)).some(key => pair[key] && key.startsWith('select')))) + } + + @computed get incomingLinks() { + return LinkManager.Instance.getAllRelatedLinks(this.props.rootDoc) // out of all links + .filter(link => { + return link.link_anchor_1 == this.props.rootDoc.draggedFrom}) // 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 + } + @computed get columns() { - return this.props.pairs.length ? Array.from(Object.keys(this.props.pairs[0])) : []; + // return this.props.pairs.length ? Array.from(Object.keys(this.props.pairs[0])) : []; + return this._tableData.length ? Array.from(Object.keys(this._tableData[0])) : []; } + render() { return (
@@ -91,7 +109,7 @@ export class TableBox extends React.Component { - {this.props.pairs?.map((p, i) => { + {this._tableData?.map((p, i) => { return ( (p['select' + this.props.docView?.()?.rootDoc![Id]] = !p['select' + this.props.docView?.()?.rootDoc![Id]]))}> {this.columns.map(col => ( -- cgit v1.2.3-70-g09d2 From 710cb3aa93ea30799479ca7c79444f05aeab2209 Mon Sep 17 00:00:00 2001 From: srichman333 Date: Mon, 31 Jul 2023 18:49:44 -0400 Subject: TableBox editable headers start --- .../nodes/DataVizBox/components/Histogram.tsx | 23 ++--- .../views/nodes/DataVizBox/components/PieChart.tsx | 24 ++--- .../views/nodes/DataVizBox/components/TableBox.tsx | 108 ++++++++++++++++++++- 3 files changed, 125 insertions(+), 30 deletions(-) (limited to 'src/client/views/nodes/DataVizBox/components/TableBox.tsx') diff --git a/src/client/views/nodes/DataVizBox/components/Histogram.tsx b/src/client/views/nodes/DataVizBox/components/Histogram.tsx index 6d0a8bf75..64e61fca8 100644 --- a/src/client/views/nodes/DataVizBox/components/Histogram.tsx +++ b/src/client/views/nodes/DataVizBox/components/Histogram.tsx @@ -443,21 +443,8 @@ export class Histogram extends React.Component { this.defaultBarColor = color; }; - @computed get editableTitle() { - const title = this.graphTitle; - return ( - this.graphTitle = val as string)} - color={"black"} - size={Size.LARGE} - fillWidth - /> - ); - } - render() { - + const title = this.graphTitle; var selected: string; if (this._currSelected){ selected = '{ '; @@ -472,7 +459,13 @@ export class Histogram extends React.Component { this.props.axes.length >= 1 ? (
- {this.editableTitle} + this.graphTitle = val as string)} + color={"black"} + size={Size.LARGE} + fillWidth + />     { this.sliceColors[this._currSelected[this.props.axes[0]].replace(/\$/g, '').replace(/\%/g, '').replace(/\ this.graphTitle = val as string)} - color={"black"} - size={Size.LARGE} - fillWidth - /> - ); - } - render() { + const title = this.graphTitle; var selected: string; if (this._currSelected){ selected = '{ '; @@ -409,7 +397,15 @@ export class PieChart extends React.Component { return ( this.props.axes.length >= 1 ? (
-
{this.editableTitle}
+
+ this.graphTitle = val as string)} + color={"black"} + size={Size.LARGE} + fillWidth + /> +
{selected != 'none' ?
Selected: {selected} diff --git a/src/client/views/nodes/DataVizBox/components/TableBox.tsx b/src/client/views/nodes/DataVizBox/components/TableBox.tsx index 500e7b639..aaedba202 100644 --- a/src/client/views/nodes/DataVizBox/components/TableBox.tsx +++ b/src/client/views/nodes/DataVizBox/components/TableBox.tsx @@ -1,4 +1,4 @@ -import { action, computed } from 'mobx'; +import { action, computed, observable } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; import { Doc } from '../../../../../fields/Doc'; @@ -10,6 +10,7 @@ import { DocumentView } from '../../DocumentView'; import { DataVizView } from '../DataVizBox'; import { LinkManager } from '../../../../util/LinkManager'; import { DocCast } from '../../../../../fields/Types'; +import { EditableText, Size, Type } from 'browndash-components'; interface TableBoxProps { rootDoc: Doc; @@ -21,6 +22,8 @@ interface TableBoxProps { @observer export class TableBox extends React.Component { + @observable editableHeaders = this.columns; + @observable editableCells = this._tableData; @computed get _tableData() { if (this.incomingLinks.length! <= 0) return this.props.pairs; @@ -39,6 +42,106 @@ export class TableBox extends React.Component { return this._tableData.length ? Array.from(Object.keys(this._tableData[0])) : []; } + // render() { + // return ( + //
+ // + // + // + // {this.editableHeaders + // .filter(col => !col.startsWith('select')) + // .map(col => { + // const header = React.createRef(); + // const displayColName = col; + // return ( + // + // ); + // })} + // + // + // + // {this._tableData?.map((p, i) => { + // return ( + // (p['select' + this.props.docView?.()?.rootDoc![Id]] = !p['select' + this.props.docView?.()?.rootDoc![Id]]))}> + // {this.editableHeaders.map(col => ( + // + // ))} + // + // ); + // })} + // + //
{ + // const downX = e.clientX; + // const downY = e.clientY; + // setupMoveUpEvents( + // {}, + // e, + // e => { + // const sourceAnchorCreator = () => this.props.docView?.()!.rootDoc!; + // const targetCreator = (annotationOn: Doc | undefined) => { + // const embedding = Doc.MakeEmbedding(this.props.docView?.()!.rootDoc!); + // embedding._dataVizView = DataVizView.LINECHART; + // embedding._data_vizAxes = new List([col, col]); + // embedding._draggedFrom = this.props.docView?.()!.rootDoc!; + // embedding.annotationOn = annotationOn; //this.props.docView?.()!.rootDoc!; + // return embedding; + // }; + // if (this.props.docView?.() && !Utils.isClick(e.clientX, e.clientY, downX, downY, Date.now())) { + // DragManager.StartAnchorAnnoDrag([header.current!], 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.annoDragData.linkSourceDoc.followLinkToggle = e.annoDragData.dropDocument.annotationOn === this.props.rootDoc; + // // e.annoDragData.linkSourceDoc.followLinkZoom = false; + // } + // }, + // }); + // return true; + // } + // return false; + // }, + // emptyFunction, + // action(e => { + // 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[0] = col; + // } + // this.props.selectAxes(newAxes); + // }) + // ); + // }}> + // { + // this.editableHeaders[this.editableHeaders.indexOf(col)] = val as string + // this.props.pairs.map(pair => { + // pair[val as string] = pair[col]; + // delete pair[col] + // }) + // })} + // color={"black"} + // size={Size.LARGE} + // /> + //
+ // {p[col]} + //
+ //
+ // ); + // } + + render() { return (
@@ -125,4 +228,7 @@ export class TableBox extends React.Component {
); } + + + } -- cgit v1.2.3-70-g09d2 From 591533a40c847f84e23428ab757b8822edbc2a61 Mon Sep 17 00:00:00 2001 From: srichman333 Date: Tue, 1 Aug 2023 17:41:09 -0400 Subject: things save: editable title for all 3 + color for histogram --- src/client/views/nodes/DataVizBox/DataVizBox.tsx | 42 ++++++---------------- .../views/nodes/DataVizBox/components/Chart.scss | 3 ++ .../nodes/DataVizBox/components/Histogram.tsx | 37 ++++++++++--------- .../nodes/DataVizBox/components/LineChart.tsx | 28 +++++++++++++-- .../views/nodes/DataVizBox/components/PieChart.tsx | 20 ++++++----- .../views/nodes/DataVizBox/components/TableBox.tsx | 26 +++++++++++--- 6 files changed, 95 insertions(+), 61 deletions(-) (limited to 'src/client/views/nodes/DataVizBox/components/TableBox.tsx') diff --git a/src/client/views/nodes/DataVizBox/DataVizBox.tsx b/src/client/views/nodes/DataVizBox/DataVizBox.tsx index 12aa2ae34..710c049a2 100644 --- a/src/client/views/nodes/DataVizBox/DataVizBox.tsx +++ b/src/client/views/nodes/DataVizBox/DataVizBox.tsx @@ -14,7 +14,7 @@ import { TableBox } from './components/TableBox'; import './DataVizBox.scss'; import { Histogram } from './components/Histogram'; import { PieChart } from './components/PieChart'; -import { Toggle, ToggleType } from 'browndash-components'; +import { Toggle, ToggleType, Type } from 'browndash-components'; export enum DataVizView { TABLE = 'table', @@ -25,6 +25,7 @@ export enum DataVizView { @observer export class DataVizBox extends ViewBoxAnnotatableComponent() { + public static LayoutString(fieldKey: string) { return FieldView.LayoutString(DataVizBox, fieldKey); } @@ -97,37 +98,16 @@ export class DataVizBox extends ViewBoxAnnotatableComponent() { } selectAxes = (axes: string[]) => (this.layoutDoc.data_vizAxes = new List(axes)); - @computed get table(){ - if (!this.pairs) return 'no data'; - return ; - } - @computed get lineChart(){ - const width = this.props.PanelWidth() * 0.9; - const height = (this.props.PanelHeight() - 32) /* height of 'change view' button */ * 0.9; - const margin = { top: 10, right: 25, bottom: 50, left: 25 }; - if (!this.pairs) return 'no data'; - return (this._chartRenderer = r ?? undefined)} height={height} width={width} fieldKey={this.fieldKey} margin={margin} rootDoc={this.rootDoc} axes={this.axes} pairs={this.pairs} dataDoc={this.dataDoc} />; - } - @computed get histogram(){ - const width = this.props.PanelWidth() * 0.9; - const height = (this.props.PanelHeight() - 32) /* height of 'change view' button */ * 0.9; - const margin = { top: 10, right: 25, bottom: 50, left: 25 }; - if (!this.pairs) return 'no data'; - return ; - } - @computed get pieChart(){ + @computed get selectView() { const width = this.props.PanelWidth() * 0.9; const height = (this.props.PanelHeight() - 32) /* height of 'change view' button */ * 0.9; const margin = { top: 10, right: 25, bottom: 50, left: 25 }; if (!this.pairs) return 'no data'; - return ; - } - @computed get selectView() { switch (this.dataVizView) { - case DataVizView.TABLE: return this.table; - case DataVizView.LINECHART: return this.lineChart; - case DataVizView.HISTOGRAM: return this.histogram; - case DataVizView.PIECHART: return this.pieChart; + case DataVizView.TABLE: return ; + case DataVizView.LINECHART: return (this._chartRenderer = r ?? undefined)} height={height} width={width} fieldKey={this.fieldKey} margin={margin} rootDoc={this.rootDoc} axes={this.axes} pairs={this.pairs} dataDoc={this.dataDoc} />; + case DataVizView.HISTOGRAM: return ; + case DataVizView.PIECHART: return ; } } @computed get dataUrl() { @@ -176,19 +156,19 @@ export class DataVizBox extends ViewBoxAnnotatableComponent() { ) }>
- this.layoutDoc._dataVizView = DataVizView.TABLE} toggleStatus={this.layoutDoc._dataVizView == DataVizView.TABLE} /> - this.layoutDoc._dataVizView = DataVizView.LINECHART} toggleStatus={this.layoutDoc._dataVizView == DataVizView.LINECHART} /> - this.layoutDoc._dataVizView = DataVizView.HISTOGRAM} toggleStatus={this.layoutDoc._dataVizView == DataVizView.HISTOGRAM} /> - this.layoutDoc._dataVizView = DataVizView.PIECHART} toggleStatus={this.layoutDoc._dataVizView == DataVizView.PIECHART} /> diff --git a/src/client/views/nodes/DataVizBox/components/Chart.scss b/src/client/views/nodes/DataVizBox/components/Chart.scss index fc0c4cea3..6c87241b8 100644 --- a/src/client/views/nodes/DataVizBox/components/Chart.scss +++ b/src/client/views/nodes/DataVizBox/components/Chart.scss @@ -75,3 +75,6 @@ fill: red; } } +.table-container{ + overflow: scroll; +} \ No newline at end of file diff --git a/src/client/views/nodes/DataVizBox/components/Histogram.tsx b/src/client/views/nodes/DataVizBox/components/Histogram.tsx index 64e61fca8..740ee6e3a 100644 --- a/src/client/views/nodes/DataVizBox/components/Histogram.tsx +++ b/src/client/views/nodes/DataVizBox/components/Histogram.tsx @@ -1,10 +1,10 @@ import { observer } from "mobx-react"; -import { Doc, DocListCast } from "../../../../../fields/Doc"; +import { Doc, DocListCast, FieldResult } from "../../../../../fields/Doc"; import * as React from 'react'; import * as d3 from 'd3'; import { IReactionDisposer, action, computed, observable, reaction } from "mobx"; import { LinkManager } from "../../../../util/LinkManager"; -import { Cast, DocCast} from "../../../../../fields/Types"; +import { Cast, DocCast, StrCast} from "../../../../../fields/Types"; import { DataPoint, SelectedDataPoint } from "./LineChart"; import { DocumentManager } from "../../../../util/DocumentManager"; import { Id } from "../../../../../fields/FieldSymbols"; @@ -19,6 +19,7 @@ import { FaFillDrip } from "react-icons/fa"; export interface HistogramProps { rootDoc: Doc; + layoutDoc: Doc; axes: string[]; pairs: { [key: string]: any }[]; width: number; @@ -44,9 +45,6 @@ export class Histogram extends React.Component { private maxBins = 15; // maximum number of bins that is readable on a normal sized doc @observable _currSelected: any | undefined = undefined; private curBarSelected: any = undefined; - private barColors: any = {}; - private defaultBarColor: string = '#69b3a2'; - @observable graphTitle: string = this.defaultGraphTitle; // TODO: nda - some sort of mapping that keeps track of the annotated points so we can easily remove when annotations list updates @computed get _histogramData() { @@ -75,7 +73,7 @@ export class Histogram extends React.Component { @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.pairs[0][ax0]) || !ax1){ + if (this.props.axes.length<2 || !/\d/.test(this.props.pairs[0][ax0]) || !ax1 || !this.numericalYData){ return ax0 + " Histogram"; } else return ax1 + " by " + ax0 + " Histogram"; @@ -285,8 +283,8 @@ export class Histogram extends React.Component { histStringDataSet.push({[yAxisTitle]: 0, [xAxisTitle]: uniqueArr[i]}) } for (let i=0; i each[xAxisTitle]==data[i]) - sliceData[0][yAxisTitle] = sliceData[0][yAxisTitle] + 1; + let barData = histStringDataSet.filter(each => each[xAxisTitle]==data[i]) + barData[0][yAxisTitle] = barData[0][yAxisTitle] + 1; } } histDataSet = histStringDataSet @@ -426,27 +424,33 @@ export class Histogram extends React.Component { return height - y(d.length)}) .attr("width", eachRectWidth) .attr("class", 'histogram-bar') - .attr("fill", (d)=>{ return this.barColors[d[0]]? this.barColors[d[0]] : this.defaultBarColor}) + .attr("fill", (d)=>{ return this.props.layoutDoc['histogramBarColors-'+d[0]]? StrCast(this.props.layoutDoc['histogramBarColors-'+d[0]]) : this.props.layoutDoc.defaultHistogramColor? StrCast(this.props.layoutDoc.defaultHistogramColor): '#69b3a2'}) }; @action changeSelectedColor = (color: string) => { this.curBarSelected.attr("fill", color); - this.barColors[this._currSelected[this.props.axes[0]].replace(/\$/g, '').replace(/\%/g, '').replace(/\ { const defaultColorBars = this._histogramSvg!.selectAll('.histogram-bar').filter((d: any) => { - if (this.barColors[d[0]]) return false; + if (this.props.layoutDoc['histogramBarColors-'+d[0]]) return false; else return true; }) defaultColorBars.attr("fill", color); - this.defaultBarColor = color; + this.props.layoutDoc.defaultHistogramColor = color; }; render() { - const title = this.graphTitle; + var curSelectedBarName; + var titleAccessor: any=''; + if (this.props.axes.length==2) titleAccessor = StrCast(this.props.layoutDoc['histogram-title-'+this.props.axes[0]+'-'+this.props.axes[1]]); + else if (this.props.axes.length>0) titleAccessor = StrCast(this.props.layoutDoc['histogram-title-'+this.props.axes[0]]); + const title = titleAccessor? titleAccessor : this.defaultGraphTitle; var selected: string; if (this._currSelected){ + curSelectedBarName = StrCast(this._currSelected![this.props.axes[0]].replace(/\$/g, '').replace(/\%/g, '').replace(/\ { key!=''? selected += key + ': ' + this._currSelected[key] + ', ': ''; @@ -461,7 +465,8 @@ export class Histogram extends React.Component {
this.graphTitle = val as string)} + setVal={action(val => {this.props.axes.length>1? this.props.layoutDoc['histogram-title-'+this.props.axes[0]+"-"+this.props.axes[1]] = val as string + : this.props.layoutDoc['histogram-title-'+this.props.axes[0]] = val as string})} color={"black"} size={Size.LARGE} fillWidth @@ -471,7 +476,7 @@ export class Histogram extends React.Component { tooltip={'Change Default Bar Color'} type={Type.SEC} icon={} - selectedColor={this.defaultBarColor} + selectedColor={this.props.layoutDoc.defaultHistogramColor? StrCast(this.props.layoutDoc.defaultHistogramColor): '#69b3a2'} setSelectedColor={color => this.changeDefaultColor(color)} size={Size.XSMALL} /> @@ -484,7 +489,7 @@ export class Histogram extends React.Component { tooltip={'Change Slice Color'} type={Type.SEC} icon={} - selectedColor={this.curBarSelected.attr("fill")} + selectedColor={this.props.layoutDoc['histogramBarColors-'+curSelectedBarName]? this.props.layoutDoc['histogramBarColors-'+curSelectedBarName] : this.curBarSelected.attr("fill")} setSelectedColor={color => this.changeSelectedColor(color)} size={Size.XSMALL} /> diff --git a/src/client/views/nodes/DataVizBox/components/LineChart.tsx b/src/client/views/nodes/DataVizBox/components/LineChart.tsx index da79df476..0142e96ad 100644 --- a/src/client/views/nodes/DataVizBox/components/LineChart.tsx +++ b/src/client/views/nodes/DataVizBox/components/LineChart.tsx @@ -6,7 +6,7 @@ import { Doc, DocListCast } from '../../../../../fields/Doc'; import { Id } from '../../../../../fields/FieldSymbols'; import { List } from '../../../../../fields/List'; import { listSpec } from '../../../../../fields/Schema'; -import { Cast, DocCast } from '../../../../../fields/Types'; +import { Cast, DocCast, StrCast } from '../../../../../fields/Types'; import { Docs } from '../../../../documents/Documents'; import { DocumentManager } from '../../../../util/DocumentManager'; import { LinkManager } from '../../../../util/LinkManager'; @@ -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 { EditableText, Size } from 'browndash-components'; export interface DataPoint { x: number; @@ -24,6 +25,7 @@ export interface SelectedDataPoint extends DataPoint { } export interface LineChartProps { rootDoc: Doc; + layoutDoc: Doc; axes: string[]; pairs: { [key: string]: any }[]; width: number; @@ -185,6 +187,15 @@ export class LineChart extends React.Component { 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.pairs[0][ax0]) || !ax1){ + return ax0 + " Line Chart"; + } + else return ax1 + " by " + ax0 + " Line Chart"; + } + setupTooltip() { return d3 .select(this._lineChartRef.current) @@ -339,11 +350,24 @@ export class LineChart extends React.Component { } render() { + var titleAccessor:any = ''; + if (this.props.axes.length==2) titleAccessor = StrCast(this.props.layoutDoc['lineChart-title-'+this.props.axes[0]+'-'+this.props.axes[1]]); + else if (this.props.axes.length>0) titleAccessor = StrCast(this.props.layoutDoc['lineChart-title-'+this.props.axes[0]]); + const title = titleAccessor? titleAccessor : this.defaultGraphTitle; const selectedPt = this._currSelected ? `x: ${this._currSelected.x} y: ${this._currSelected.y}` : 'none'; return ( this.props.axes.length >= 2 ? (
-
{this.graphTitle}
+
+ {this.props.axes.length>1? this.props.layoutDoc['lineChart-title-'+this.props.axes[0]+"-"+this.props.axes[1]] = val as string + : this.props.layoutDoc['lineChart-title-'+this.props.axes[0]] = val as string})} + color={"black"} + size={Size.LARGE} + fillWidth + /> +
{`Selected: ${selectedPt}`}
diff --git a/src/client/views/nodes/DataVizBox/components/PieChart.tsx b/src/client/views/nodes/DataVizBox/components/PieChart.tsx index 47d4fb23e..f0c27866d 100644 --- a/src/client/views/nodes/DataVizBox/components/PieChart.tsx +++ b/src/client/views/nodes/DataVizBox/components/PieChart.tsx @@ -4,7 +4,7 @@ import * as React from 'react'; import * as d3 from 'd3'; import { IReactionDisposer, action, computed, observable, reaction } from "mobx"; import { LinkManager } from "../../../../util/LinkManager"; -import { Cast, DocCast} from "../../../../../fields/Types"; +import { Cast, DocCast, StrCast} from "../../../../../fields/Types"; import { DataPoint, SelectedDataPoint } from "./LineChart"; import { DocumentManager } from "../../../../util/DocumentManager"; import { Id } from "../../../../../fields/FieldSymbols"; @@ -19,6 +19,7 @@ import { FaFillDrip } from "react-icons/fa"; export interface PieChartProps { rootDoc: Doc; + layoutDoc: Doc; axes: string[]; pairs: { [key: string]: any }[]; width: number; @@ -42,8 +43,6 @@ export class PieChart extends React.Component { private byCategory: boolean = true; // whether the data is organized by category or by specified number percentages/ratios @observable _currSelected: any | undefined = undefined; private curSliceSelected: any = undefined; - private sliceColors: any = {}; - @observable graphTitle: string = this.defaultGraphTitle; // TODO: nda - some sort of mapping that keeps track of the annotated points so we can easily remove when annotations list updates @computed get _piechartData() { @@ -254,7 +253,7 @@ export class PieChart extends React.Component { var percentField = Object.keys(dataSet[0])[0] var descriptionField = Object.keys(dataSet[0])[1]! - var radius = Math.min(width, height) / 2 - Math.max(this.props.margin.top, this.props.margin.bottom, this.props.margin.left, this.props.margin.right) + var radius = Math.min(width, height-this.props.margin.top-this.props.margin.bottom) /2 var svg = (this._piechartSvg = d3 .select(this._piechartRef.current) .append("svg") @@ -349,7 +348,7 @@ export class PieChart extends React.Component { .enter() .append("g") arcs.append("path") - .attr("fill", (data, i)=>{ return this.sliceColors[data.data.valueOf()]? this.sliceColors[data.data.valueOf()] : d3.schemeSet3[i]? d3.schemeSet3[i]: d3.schemeSet3[i%12] }) + .attr("fill", (data, i)=>{ return this.props.layoutDoc['pieSliceColors-'+data.data.valueOf()]? StrCast(this.props.layoutDoc['pieSliceColors-'+data.data.valueOf()]) : d3.schemeSet3[i]? d3.schemeSet3[i]: d3.schemeSet3[i%12] }) .attr("class", 'slice') .attr("d", arc) .on('click', onPointClick) @@ -379,11 +378,15 @@ export class PieChart extends React.Component { @action changeSelectedColor = (color: string) => { this.curSliceSelected.attr("fill", color); - this.sliceColors[this._currSelected[this.props.axes[0]].replace(/\$/g, '').replace(/\%/g, '').replace(/\0) titleAccessor = StrCast(this.props.layoutDoc['pieChart-title-'+this.props.axes[0]]); + const title = titleAccessor? titleAccessor : this.defaultGraphTitle; var selected: string; if (this._currSelected){ selected = '{ '; @@ -400,7 +403,8 @@ export class PieChart extends React.Component {
this.graphTitle = val as string)} + setVal={action(val => {this.props.axes.length>1? this.props.layoutDoc['pieChart-title-'+this.props.axes[0]+"-"+this.props.axes[1]] = val as string + : this.props.layoutDoc['pieChart-title-'+this.props.axes[0]] = val as string})} color={"black"} size={Size.LARGE} fillWidth diff --git a/src/client/views/nodes/DataVizBox/components/TableBox.tsx b/src/client/views/nodes/DataVizBox/components/TableBox.tsx index aaedba202..64c6dc940 100644 --- a/src/client/views/nodes/DataVizBox/components/TableBox.tsx +++ b/src/client/views/nodes/DataVizBox/components/TableBox.tsx @@ -9,14 +9,24 @@ import { DragManager } from '../../../../util/DragManager'; import { DocumentView } from '../../DocumentView'; import { DataVizView } from '../DataVizBox'; import { LinkManager } from '../../../../util/LinkManager'; -import { DocCast } from '../../../../../fields/Types'; +import { Cast, DocCast } from '../../../../../fields/Types'; import { EditableText, Size, Type } from 'browndash-components'; +import './Chart.scss'; +import { listSpec } from '../../../../../fields/Schema'; interface TableBoxProps { rootDoc: Doc; pairs: { [key: string]: any }[]; selectAxes: (axes: string[]) => void; axes: string[]; + width: number; + height: number; + margin: { + top: number; + right: number; + bottom: number; + left: number; + }; docView?: () => DocumentView | undefined; } @@ -27,6 +37,7 @@ export class TableBox extends React.Component { @computed get _tableData() { if (this.incomingLinks.length! <= 0) return this.props.pairs; + /// StrListCast(this.incomingLinks[0].anchor_1.selected) ==> list of guids that the parent has selected return this.props.pairs?.filter(pair => (Array.from(Object.keys(pair)).some(key => pair[key] && key.startsWith('select')))) } @@ -44,7 +55,7 @@ export class TableBox extends React.Component { // render() { // return ( - //
+ //
// // // @@ -144,7 +155,7 @@ export class TableBox extends React.Component { render() { return ( -
+
@@ -214,7 +225,14 @@ export class TableBox extends React.Component { {this._tableData?.map((p, i) => { return ( - (p['select' + this.props.docView?.()?.rootDoc![Id]] = !p['select' + this.props.docView?.()?.rootDoc![Id]]))}> + { + // if (!this.props.docView?.()!.layoutDoc.selected) + // this.props.docView!.()!.layoutDoc.selected = new List(); + // const selected = Cast(this.props.docView?.()!.layoutDoc.selected, listSpec("string"), null); + // // StrListCast(this.props.docView?.()!.layoutDoc.selected) + // selected.push(p.guid); + (p['select' + this.props.docView?.()?.rootDoc![Id]] = !p['select' + this.props.docView?.()?.rootDoc![Id]]) + })}> {this.columns.map(col => ( {this._tableData?.map((p, i) => { - return ( - { - if (!this.props.layoutDoc.selected) this.props.layoutDoc.selected = new List(); - const selected = Cast(this.props.layoutDoc.selected, listSpec("string"), null); - if (selected.includes(p.guid)) selected.splice(selected.indexOf(p.guid), 1); - else { - selected.push(p.guid)}; - })} style={ - { fontWeight: StrListCast(this.props.layoutDoc.selected).includes(p.guid) ? 'bold' : '' , width: '110%', - background: StrListCast(this.props.layoutDoc.selected).includes(p.guid) ? 'lightgrey' : '' }}> - {this.columns.map(col => ( - (this.props.layoutDoc.selected)? - - : - ))} - - ); + var containsData = false; + this.columns.map(col => {if (p[col]!='' && p[col]!=null && p[col]!=undefined) containsData = true}) + if (containsData){ + return ( + { + if (!this.props.layoutDoc.selected) this.props.layoutDoc.selected = new List(); + const selected = Cast(this.props.layoutDoc.selected, listSpec("string"), null); + if (selected.includes(p.guid)) selected.splice(selected.indexOf(p.guid), 1); + else { + selected.push(p.guid)}; + })} style={ + { fontWeight: StrListCast(this.props.layoutDoc.selected).includes(p.guid) ? 'bold' : '' , width: '110%', + background: StrListCast(this.props.layoutDoc.selected).includes(p.guid) ? 'lightgrey' : '' }}> + {this.columns.map(col => ( + (this.props.layoutDoc.selected)? + + : + ))} + + ); + } })}
{p[col]} -- cgit v1.2.3-70-g09d2 From 23e0ee2dcad8df2bc3467647e05c433f27787d54 Mon Sep 17 00:00:00 2001 From: srichman333 Date: Thu, 3 Aug 2023 14:38:47 -0400 Subject: table fixes (selected by guid not extra row + ui changes) --- src/client/views/nodes/DataVizBox/DataVizBox.tsx | 17 +- .../views/nodes/DataVizBox/components/Chart.scss | 1 + .../nodes/DataVizBox/components/Histogram.tsx | 56 +--- .../nodes/DataVizBox/components/LineChart.tsx | 4 +- .../views/nodes/DataVizBox/components/PieChart.tsx | 47 +--- .../views/nodes/DataVizBox/components/TableBox.tsx | 310 +++++++-------------- 6 files changed, 135 insertions(+), 300 deletions(-) (limited to 'src/client/views/nodes/DataVizBox/components/TableBox.tsx') diff --git a/src/client/views/nodes/DataVizBox/DataVizBox.tsx b/src/client/views/nodes/DataVizBox/DataVizBox.tsx index 9a4de3c36..80586d7c7 100644 --- a/src/client/views/nodes/DataVizBox/DataVizBox.tsx +++ b/src/client/views/nodes/DataVizBox/DataVizBox.tsx @@ -1,9 +1,9 @@ -import { action, computed, observable, ObservableMap, ObservableSet } from 'mobx'; +import { action, computed, ObservableMap, ObservableSet } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; import { Doc, StrListCast } from '../../../../fields/Doc'; import { List } from '../../../../fields/List'; -import { Cast, CsvCast, NumCast, StrCast } from '../../../../fields/Types'; +import { Cast, CsvCast, StrCast } from '../../../../fields/Types'; import { CsvField } from '../../../../fields/URLField'; import { Docs } from '../../../documents/Documents'; import { ViewBoxAnnotatableComponent } from '../../DocComponent'; @@ -15,6 +15,7 @@ import './DataVizBox.scss'; import { Histogram } from './components/Histogram'; import { PieChart } from './components/PieChart'; import { Toggle, ToggleType, Type } from 'browndash-components'; +import { Utils } from '../../../../Utils'; export enum DataVizView { TABLE = 'table', @@ -35,9 +36,11 @@ export class DataVizBox extends ViewBoxAnnotatableComponent() { // @observable private pairs: { [key: string]: FieldResult }[] = []; static pairSet = new ObservableMap(); @computed.struct get pairs() { - return DataVizBox.pairSet.get(CsvCast(this.rootDoc[this.fieldKey]).url.href); + var pairs = DataVizBox.pairSet.get(CsvCast(this.rootDoc[this.fieldKey]).url.href); + pairs?.map(pair => {if (!pair.guid) pair.guid = Utils.GenerateGuid()}) + return pairs; } - private _chartRenderer: LineChart | undefined; + private _chartRenderer: LineChart | Histogram | PieChart | undefined; // // another way would be store a schema that defines the type of data we are expecting from an imported doc // method1() { @@ -116,10 +119,10 @@ export class DataVizBox extends ViewBoxAnnotatableComponent() { const margin = { top: 10, right: 25, bottom: 50, left: 25 }; if (!this.pairs) return 'no data'; switch (this.dataVizView) { - case DataVizView.TABLE: return ; + case DataVizView.TABLE: return ; case DataVizView.LINECHART: return (this._chartRenderer = r ?? undefined)} height={height} width={width} fieldKey={this.fieldKey} margin={margin} rootDoc={this.rootDoc} axes={this.axes} pairs={this.pairs} dataDoc={this.dataDoc} />; - case DataVizView.HISTOGRAM: return ; - case DataVizView.PIECHART: return ; + case DataVizView.HISTOGRAM: return (this._chartRenderer = r ?? undefined)} height={height} width={width} fieldKey={this.fieldKey} margin={margin} rootDoc={this.rootDoc} axes={this.axes} pairs={this.pairs} dataDoc={this.dataDoc} />; + case DataVizView.PIECHART: return (this._chartRenderer = r ?? undefined)} height={height} width={width} fieldKey={this.fieldKey} margin={margin} rootDoc={this.rootDoc} axes={this.axes} pairs={this.pairs} dataDoc={this.dataDoc} />; } } @computed get dataUrl() { diff --git a/src/client/views/nodes/DataVizBox/components/Chart.scss b/src/client/views/nodes/DataVizBox/components/Chart.scss index 6c87241b8..996183cb8 100644 --- a/src/client/views/nodes/DataVizBox/components/Chart.scss +++ b/src/client/views/nodes/DataVizBox/components/Chart.scss @@ -77,4 +77,5 @@ } .table-container{ overflow: scroll; + margin: 10px; } \ No newline at end of file diff --git a/src/client/views/nodes/DataVizBox/components/Histogram.tsx b/src/client/views/nodes/DataVizBox/components/Histogram.tsx index 89dcf87db..efe17297b 100644 --- a/src/client/views/nodes/DataVizBox/components/Histogram.tsx +++ b/src/client/views/nodes/DataVizBox/components/Histogram.tsx @@ -1,15 +1,13 @@ import { observer } from "mobx-react"; -import { Doc, DocListCast, FieldResult } from "../../../../../fields/Doc"; +import { Doc, DocListCast, StrListCast } from "../../../../../fields/Doc"; import * as React from 'react'; import * as d3 from 'd3'; import { IReactionDisposer, action, computed, observable, reaction } from "mobx"; import { LinkManager } from "../../../../util/LinkManager"; -import { Cast, DocCast, StrCast} from "../../../../../fields/Types"; -import { DataPoint, SelectedDataPoint } from "./LineChart"; +import { DocCast, StrCast} from "../../../../../fields/Types"; import { DocumentManager } from "../../../../util/DocumentManager"; import { Id } from "../../../../../fields/FieldSymbols"; import { DataVizBox } from "../DataVizBox"; -import { listSpec } from "../../../../../fields/Schema"; import { PinProps, PresBox } from "../../trails"; import { Docs } from "../../../../documents/Documents"; import { List } from "../../../../../fields/List"; @@ -54,7 +52,7 @@ export class Histogram extends React.Component { var ax0 = this.props.axes[0]; if (/\d/.test(this.props.pairs[0][ax0])){ this.numericalXData = true } return this.props.pairs - ?.filter(pair => (!this.incomingLinks.length ? true : Array.from(Object.keys(pair)).some(key => pair[key] && key.startsWith('select')))) + ?.filter(pair => (!this.incomingLinks.length ? true : this.incomingLinks[0]!.selected && StrListCast(this.incomingLinks[0].selected).includes(pair.guid))) .map(pair => ({ [ax0]: (pair[this.props.axes[0]])})) }; @@ -63,13 +61,8 @@ export class Histogram extends React.Component { if (/\d/.test(this.props.pairs[0][ax0])) { this.numericalXData = true;} if (/\d/.test(this.props.pairs[0][ax1]) && this.props.pairs.length < this.maxBins) { this.numericalYData = true;} return this.props.pairs - ?.filter(pair => (!this.incomingLinks.length ? true : Array.from(Object.keys(pair)).some(key => pair[key] && key.startsWith('select')))) + ?.filter(pair => (!this.incomingLinks.length ? true : this.incomingLinks[0]!.selected && StrListCast(this.incomingLinks[0].selected).includes(pair.guid))) .map(pair => ({ [ax0]: (pair[this.props.axes[0]]), [ax1]: (pair[this.props.axes[1]]) })) - // .sort((a, b) => (a[ax0] < b[ax0] ? -1 : 1)); - return this.props.pairs - ?.filter(pair => (!this.incomingLinks.length ? true : Array.from(Object.keys(pair)).some(key => pair[key] && key.startsWith('select')))) - .map(pair => ({ x: Number(pair[this.props.axes[0]]), y: Number(pair[this.props.axes[1]]) })) - .sort((a, b) => (a.x < b.x ? -1 : 1)); } @computed get defaultGraphTitle(){ var ax0 = this.props.axes[0]; @@ -181,27 +174,16 @@ export class Histogram extends React.Component { } @action - restoreView = (data: Doc) => { - const coords = Cast(data.presDataVizSelection, listSpec('number'), null); - if (coords?.length > 1 && (this._currSelected?.x !== coords[0] || this._currSelected?.y !== coords[1])) { - this.setCurrSelected(coords[0], coords[1]); - return true; - } - if (this._currSelected) { - this.setCurrSelected(); - return true; - } - return false; - }; + restoreView = (data: Doc) => {}; // create a document anchor that stores whatever is needed to reconstruct the viewing state (selection,zoom,etc) getAnchor = (pinProps?: PinProps) => { const anchor = Docs.Create.ConfigDocument({ // - title: 'histogram doc selection' + this._currSelected?.x, + title: 'histogram doc selection' + this._currSelected, }); PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: pinProps?.pinData }, this.props.dataDoc); - anchor.presDataVizSelection = this._currSelected ? new List([this._currSelected.x, this._currSelected.y]) : undefined; + anchor.presDataVizSelection = this._currSelected ? new List([this._currSelected]) : undefined; return anchor; }; @@ -213,28 +195,6 @@ export class Histogram extends React.Component { return this.props.width - this.props.margin.left - this.props.margin.right; } - setupTooltip() { - return d3 - .select(this._histogramRef.current) - .append('div') - .attr('class', 'tooltip') - .style('opacity', 0) - .style('background', '#fff') - .style('border', '1px solid #ccc') - .style('padding', '5px') - .style('position', 'absolute') - .style('font-size', '12px'); - } - - // TODO: nda - use this everyewhere we update currSelected? - @action - setCurrSelected(x?: number, y?: number) { - // TODO: nda - get rid of svg element in the list? - this._currSelected = x !== undefined && y !== undefined ? { x, y } : undefined; - this.props.pairs.forEach(pair => pair[this.props.axes[0]] === x && pair[this.props.axes[1]] === y && (pair.selected = true)); - this.props.pairs.forEach(pair => (pair.selected = pair[this.props.axes[0]] === x && pair[this.props.axes[1]] === y ? true : undefined)); - } - data = (dataSet: any) => { var validData = dataSet.filter((d: { [x: string]: unknown; }) => { var valid = true; @@ -364,7 +324,7 @@ export class Histogram extends React.Component { const selected = svg.selectAll('.histogram-bar').filter((d: any) => { barCounter++; if ((barCounter*eachRectWidth ) <= pointerX && pointerX <= ((barCounter+1)*eachRectWidth)){ - var showSelected = this.numericalYData? this.props.pairs.filter((data: { [x: string]: any; }) => data[xAxisTitle].replace(/\$/g, '').replace(/\%/g, '').replace(/\ data[xAxisTitle].replace(/\$/g, '').replace(/\%/g, '').replace(/\ data[xAxisTitle].replace(/\$/g, '').replace(/\%/g, '').replace(/\ { @computed get _lineChartData() { if (this.props.axes.length <= 1) return []; return this.props.pairs - ?.filter(pair => (!this.incomingLinks.length ? true : Array.from(Object.keys(pair)).some(key => pair[key] && key.startsWith('select')))) + ?.filter(pair => (!this.incomingLinks.length ? true : this.incomingLinks[0]!.selected && StrListCast(this.incomingLinks[0].selected).includes(pair.guid))) .map(pair => ({ x: Number(pair[this.props.axes[0]]), y: Number(pair[this.props.axes[1]]) })) .sort((a, b) => (a.x < b.x ? -1 : 1)); } diff --git a/src/client/views/nodes/DataVizBox/components/PieChart.tsx b/src/client/views/nodes/DataVizBox/components/PieChart.tsx index d01d4429f..f3a72a53b 100644 --- a/src/client/views/nodes/DataVizBox/components/PieChart.tsx +++ b/src/client/views/nodes/DataVizBox/components/PieChart.tsx @@ -1,15 +1,13 @@ import { observer } from "mobx-react"; -import { Doc, DocListCast } from "../../../../../fields/Doc"; +import { Doc, DocListCast, StrListCast } from "../../../../../fields/Doc"; import * as React from 'react'; import * as d3 from 'd3'; import { IReactionDisposer, action, computed, observable, reaction } from "mobx"; import { LinkManager } from "../../../../util/LinkManager"; -import { Cast, DocCast, StrCast} from "../../../../../fields/Types"; -import { DataPoint, SelectedDataPoint } from "./LineChart"; +import { DocCast, StrCast} from "../../../../../fields/Types"; import { DocumentManager } from "../../../../util/DocumentManager"; import { Id } from "../../../../../fields/FieldSymbols"; import { DataVizBox } from "../DataVizBox"; -import { listSpec } from "../../../../../fields/Schema"; import { PinProps, PresBox } from "../../trails"; import { Docs } from "../../../../documents/Documents"; import { List } from "../../../../../fields/List"; @@ -52,7 +50,7 @@ export class PieChart extends React.Component { var ax0 = this.props.axes[0]; if (/\d/.test(this.props.pairs[0][ax0])){ this.byCategory = false } return this.props.pairs - ?.filter(pair => (!this.incomingLinks.length ? true : Array.from(Object.keys(pair)).some(key => pair[key] && key.startsWith('select')))) + ?.filter(pair => (!this.incomingLinks.length ? true : this.incomingLinks[0]!.selected && StrListCast(this.incomingLinks[0].selected).includes(pair.guid))) .map(pair => ({ [ax0]: (pair[this.props.axes[0]])})) }; @@ -60,13 +58,8 @@ export class PieChart extends React.Component { var ax1 = this.props.axes[1]; if (/\d/.test(this.props.pairs[0][ax0])) { this.byCategory = false; } return this.props.pairs - ?.filter(pair => (!this.incomingLinks.length ? true : Array.from(Object.keys(pair)).some(key => pair[key] && key.startsWith('select')))) + ?.filter(pair => (!this.incomingLinks.length ? true : this.incomingLinks[0]!.selected && StrListCast(this.incomingLinks[0].selected).includes(pair.guid))) .map(pair => ({ [ax0]: (pair[this.props.axes[0]]), [ax1]: (pair[this.props.axes[1]]) })) - // .sort((a, b) => (a[ax0] < b[ax0] ? -1 : 1)); - return this.props.pairs - ?.filter(pair => (!this.incomingLinks.length ? true : Array.from(Object.keys(pair)).some(key => pair[key] && key.startsWith('select')))) - .map(pair => ({ x: Number(pair[this.props.axes[0]]), y: Number(pair[this.props.axes[1]]) })) - .sort((a, b) => (a.x < b.x ? -1 : 1)); } @computed get defaultGraphTitle(){ var ax0 = this.props.axes[0]; @@ -178,27 +171,16 @@ export class PieChart extends React.Component { } @action - restoreView = (data: Doc) => { - const coords = Cast(data.presDataVizSelection, listSpec('number'), null); - if (coords?.length > 1 && (this._currSelected?.x !== coords[0] || this._currSelected?.y !== coords[1])) { - this.setCurrSelected(coords[0], coords[1]); - return true; - } - if (this._currSelected) { - this.setCurrSelected(); - return true; - } - return false; - }; + restoreView = (data: Doc) => {}; // create a document anchor that stores whatever is needed to reconstruct the viewing state (selection,zoom,etc) getAnchor = (pinProps?: PinProps) => { const anchor = Docs.Create.ConfigDocument({ // - title: 'piechart doc selection' + this._currSelected?.x, + title: 'piechart doc selection' + this._currSelected, }); PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: pinProps?.pinData }, this.props.dataDoc); - anchor.presDataVizSelection = this._currSelected ? new List([this._currSelected.x, this._currSelected.y]) : undefined; + anchor.presDataVizSelection = this._currSelected ? new List([this._currSelected]) : undefined; return anchor; }; @@ -210,19 +192,6 @@ export class PieChart extends React.Component { return this.props.width - this.props.margin.left - this.props.margin.right; } - setupTooltip() { - return d3 - .select(this._piechartRef.current) - .append('div') - .attr('class', 'tooltip') - .style('opacity', 0) - .style('background', '#fff') - .style('border', '1px solid #ccc') - .style('padding', '5px') - .style('position', 'absolute') - .style('font-size', '12px'); - } - // TODO: nda - use this everyewhere we update currSelected? @action setCurrSelected(x?: number, y?: number) { @@ -322,7 +291,7 @@ export class PieChart extends React.Component { if (Math.min(p4[1], p1[1])<=pointer[1] && pointer[1]<=Math.max(p4[1], p1[1])){ if (pointer[0] <= (pointer[1]-p4[1])*(p1[0]-p4[0])/(p1[1]-p4[1])+p4[0]) lineCrossCount++; } if (lineCrossCount % 2 != 0) { - var showSelected = this.byCategory? pieDataSet[index] : this.props.pairs[index]; + var showSelected = this.byCategory? pieDataSet[index] : this._piechartData[index]; sameAsCurrent = (this.byCategory && this._currSelected)? (showSelected[Object.keys(showSelected)[0]]==this._currSelected![Object.keys(showSelected)[0]] && showSelected[Object.keys(showSelected)[1]]==this._currSelected![Object.keys(showSelected)[1]]) diff --git a/src/client/views/nodes/DataVizBox/components/TableBox.tsx b/src/client/views/nodes/DataVizBox/components/TableBox.tsx index 64c6dc940..5653adbce 100644 --- a/src/client/views/nodes/DataVizBox/components/TableBox.tsx +++ b/src/client/views/nodes/DataVizBox/components/TableBox.tsx @@ -1,21 +1,20 @@ -import { action, computed, observable } from 'mobx'; +import { action, computed, } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; -import { Doc } from '../../../../../fields/Doc'; -import { Id } from '../../../../../fields/FieldSymbols'; +import { Doc, StrListCast } from '../../../../../fields/Doc'; import { List } from '../../../../../fields/List'; -import { emptyFunction, returnFalse, setupMoveUpEvents, Utils } from '../../../../../Utils'; +import { emptyFunction, setupMoveUpEvents, Utils } from '../../../../../Utils'; import { DragManager } from '../../../../util/DragManager'; import { DocumentView } from '../../DocumentView'; import { DataVizView } from '../DataVizBox'; import { LinkManager } from '../../../../util/LinkManager'; import { Cast, DocCast } from '../../../../../fields/Types'; -import { EditableText, Size, Type } from 'browndash-components'; import './Chart.scss'; import { listSpec } from '../../../../../fields/Schema'; interface TableBoxProps { rootDoc: Doc; + layoutDoc: Doc; pairs: { [key: string]: any }[]; selectAxes: (axes: string[]) => void; axes: string[]; @@ -32,13 +31,10 @@ interface TableBoxProps { @observer export class TableBox extends React.Component { - @observable editableHeaders = this.columns; - @observable editableCells = this._tableData; @computed get _tableData() { if (this.incomingLinks.length! <= 0) return this.props.pairs; - /// StrListCast(this.incomingLinks[0].anchor_1.selected) ==> list of guids that the parent has selected - return this.props.pairs?.filter(pair => (Array.from(Object.keys(pair)).some(key => pair[key] && key.startsWith('select')))) + return this.props.pairs?.filter(pair => this.incomingLinks[0]!.selected && StrListCast(this.incomingLinks[0].selected).includes(pair.guid)) } @computed get incomingLinks() { @@ -49,204 +45,110 @@ export class TableBox extends React.Component { } @computed get columns() { - // return this.props.pairs.length ? Array.from(Object.keys(this.props.pairs[0])) : []; - return this._tableData.length ? Array.from(Object.keys(this._tableData[0])) : []; + return this._tableData.length ? Array.from(Object.keys(this._tableData[0])).filter(header => header!='guid' && header!='') : []; } - // render() { - // return ( - //
- // - // - // - // {this.editableHeaders - // .filter(col => !col.startsWith('select')) - // .map(col => { - // const header = React.createRef(); - // const displayColName = col; - // return ( - // - // ); - // })} - // - // - // - // {this._tableData?.map((p, i) => { - // return ( - // (p['select' + this.props.docView?.()?.rootDoc![Id]] = !p['select' + this.props.docView?.()?.rootDoc![Id]]))}> - // {this.editableHeaders.map(col => ( - // - // ))} - // - // ); - // })} - // - //
{ - // const downX = e.clientX; - // const downY = e.clientY; - // setupMoveUpEvents( - // {}, - // e, - // e => { - // const sourceAnchorCreator = () => this.props.docView?.()!.rootDoc!; - // const targetCreator = (annotationOn: Doc | undefined) => { - // const embedding = Doc.MakeEmbedding(this.props.docView?.()!.rootDoc!); - // embedding._dataVizView = DataVizView.LINECHART; - // embedding._data_vizAxes = new List([col, col]); - // embedding._draggedFrom = this.props.docView?.()!.rootDoc!; - // embedding.annotationOn = annotationOn; //this.props.docView?.()!.rootDoc!; - // return embedding; - // }; - // if (this.props.docView?.() && !Utils.isClick(e.clientX, e.clientY, downX, downY, Date.now())) { - // DragManager.StartAnchorAnnoDrag([header.current!], 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.annoDragData.linkSourceDoc.followLinkToggle = e.annoDragData.dropDocument.annotationOn === this.props.rootDoc; - // // e.annoDragData.linkSourceDoc.followLinkZoom = false; - // } - // }, - // }); - // return true; - // } - // return false; - // }, - // emptyFunction, - // action(e => { - // 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[0] = col; - // } - // this.props.selectAxes(newAxes); - // }) - // ); - // }}> - // { - // this.editableHeaders[this.editableHeaders.indexOf(col)] = val as string - // this.props.pairs.map(pair => { - // pair[val as string] = pair[col]; - // delete pair[col] - // }) - // })} - // color={"black"} - // size={Size.LARGE} - // /> - //
- // {p[col]} - //
- //
- // ); - // } - - render() { - return ( -
- - - - {this.columns - .filter(col => !col.startsWith('select')) - .map(col => { - const header = React.createRef(); - return ( - - ); - })} - - - - {this._tableData?.map((p, i) => { - return ( - { - // if (!this.props.docView?.()!.layoutDoc.selected) - // this.props.docView!.()!.layoutDoc.selected = new List(); - // const selected = Cast(this.props.docView?.()!.layoutDoc.selected, listSpec("string"), null); - // // StrListCast(this.props.docView?.()!.layoutDoc.selected) - // selected.push(p.guid); - (p['select' + this.props.docView?.()?.rootDoc![Id]] = !p['select' + this.props.docView?.()?.rootDoc![Id]]) - })}> - {this.columns.map(col => ( - - ))} - - ); - })} - -
{ - const downX = e.clientX; - const downY = e.clientY; - setupMoveUpEvents( - {}, - e, - e => { - const sourceAnchorCreator = () => this.props.docView?.()!.rootDoc!; - const targetCreator = (annotationOn: Doc | undefined) => { - const embedding = Doc.MakeEmbedding(this.props.docView?.()!.rootDoc!); - embedding._dataVizView = DataVizView.LINECHART; - embedding._data_vizAxes = new List([col, col]); - embedding._draggedFrom = this.props.docView?.()!.rootDoc!; - embedding.annotationOn = annotationOn; //this.props.docView?.()!.rootDoc!; - return embedding; - }; - if (this.props.docView?.() && !Utils.isClick(e.clientX, e.clientY, downX, downY, Date.now())) { - DragManager.StartAnchorAnnoDrag([header.current!], 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.annoDragData.linkSourceDoc.followLinkToggle = e.annoDragData.dropDocument.annotationOn === this.props.rootDoc; - // e.annoDragData.linkSourceDoc.followLinkZoom = false; - } - }, - }); - return true; - } - return false; - }, - emptyFunction, - action(e => { - 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[0] = col; - } - this.props.selectAxes(newAxes); - }) - ); - }}> - {col} -
- {p[col]} -
+ if (this._tableData.length>0){ + return ( +
+ + + + {this.columns + .filter(col => !col.startsWith('select')) + .map(col => { + const header = React.createRef(); + return ( + + ); + })} + + + + {this._tableData?.map((p, i) => { + return ( + { + if (!this.props.layoutDoc.selected) this.props.layoutDoc.selected = new List(); + const selected = Cast(this.props.layoutDoc.selected, listSpec("string"), null); + if (selected.includes(p.guid)) selected.splice(selected.indexOf(p.guid), 1); + else { + selected.push(p.guid)}; + })} style={ + { fontWeight: StrListCast(this.props.layoutDoc.selected).includes(p.guid) ? 'bold' : '' , width: '110%', + background: StrListCast(this.props.layoutDoc.selected).includes(p.guid) ? 'lightgrey' : '' }}> + {this.columns.map(col => ( + (this.props.layoutDoc.selected)? + + : + ))} + + ); + })} + +
{ + const downX = e.clientX; + const downY = e.clientY; + setupMoveUpEvents( + {}, + e, + e => { + const sourceAnchorCreator = () => this.props.docView?.()!.rootDoc!; + const targetCreator = (annotationOn: Doc | undefined) => { + const embedding = Doc.MakeEmbedding(this.props.docView?.()!.rootDoc!); + embedding._dataVizView = DataVizView.TABLE; + embedding._data_vizAxes = new List([col, col]); + embedding._draggedFrom = this.props.docView?.()!.rootDoc!; + embedding.annotationOn = annotationOn; //this.props.docView?.()!.rootDoc!; + return embedding; + }; + if (this.props.docView?.() && !Utils.isClick(e.clientX, e.clientY, downX, downY, Date.now())) { + DragManager.StartAnchorAnnoDrag([header.current!], 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.annoDragData.linkSourceDoc.followLinkToggle = e.annoDragData.dropDocument.annotationOn === this.props.rootDoc; + // e.annoDragData.linkSourceDoc.followLinkZoom = false; + } + }, + }); + return true; + } + return false; + }, + emptyFunction, + action(e => { + 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[0] = col; + } + this.props.selectAxes(newAxes); + }) + ); + }}> + {col} +
+ {p[col]} + {p[col]}
+
+ ); + } + else return ( +
+ Selected rows of data from the incoming DataVizBox to display.
- ); + ) } - - - } -- cgit v1.2.3-70-g09d2 From 8bdae208c4ae44766241c285f2f7234027b9b80f Mon Sep 17 00:00:00 2001 From: srichman333 Date: Thu, 3 Aug 2023 15:56:11 -0400 Subject: histogram small data fix --- .../nodes/DataVizBox/components/Histogram.tsx | 6 ++-- .../views/nodes/DataVizBox/components/TableBox.tsx | 42 ++++++++++++---------- 2 files changed, 26 insertions(+), 22 deletions(-) (limited to 'src/client/views/nodes/DataVizBox/components/TableBox.tsx') diff --git a/src/client/views/nodes/DataVizBox/components/Histogram.tsx b/src/client/views/nodes/DataVizBox/components/Histogram.tsx index efe17297b..1077df844 100644 --- a/src/client/views/nodes/DataVizBox/components/Histogram.tsx +++ b/src/client/views/nodes/DataVizBox/components/Histogram.tsx @@ -267,10 +267,10 @@ export class Histogram extends React.Component { var histogram = d3.histogram() .value(function(d) {return d}) .domain([startingPoint!, endingPoint!]) - .thresholds(x.ticks(numBins-1)) + .thresholds(x.ticks(numBins)) var bins = histogram(data) var eachRectWidth = width/(bins.length) - var graphStartingPoint = bins[0].x1? bins[0].x1! - (bins[1].x1! - bins[1].x0!) : 0; + var graphStartingPoint = (bins[0].x1 && bins[1])? bins[0].x1! - (bins[1].x1! - bins[1].x0!) : 0; bins[0].x0 = graphStartingPoint; x = x.domain([graphStartingPoint, endingPoint]) .range([0, Number.isInteger(this.rangeVals.xMin!)? (width-eachRectWidth) : width ]) @@ -286,7 +286,7 @@ export class Histogram extends React.Component { index = j; } } - bins[index].push(data[i]) + if (bins[index]) bins[index].push(data[i]) } bins.pop(); eachRectWidth = width/(bins.length) diff --git a/src/client/views/nodes/DataVizBox/components/TableBox.tsx b/src/client/views/nodes/DataVizBox/components/TableBox.tsx index 5653adbce..f244502a4 100644 --- a/src/client/views/nodes/DataVizBox/components/TableBox.tsx +++ b/src/client/views/nodes/DataVizBox/components/TableBox.tsx @@ -120,25 +120,29 @@ export class TableBox extends React.Component {
- {p[col]} - {p[col]}
+ {p[col]} + {p[col]}
-- cgit v1.2.3-70-g09d2 From bee66361d878c366e8c753ca844abc2f78fbf7f3 Mon Sep 17 00:00:00 2001 From: srichman333 Date: Fri, 4 Aug 2023 14:52:35 -0400 Subject: better row guids so selected rows stay on refresh --- src/client/views/nodes/DataVizBox/DataVizBox.tsx | 5 +---- .../views/nodes/DataVizBox/components/Histogram.tsx | 5 +++-- .../views/nodes/DataVizBox/components/LineChart.tsx | 3 ++- .../views/nodes/DataVizBox/components/PieChart.tsx | 5 +++-- .../views/nodes/DataVizBox/components/TableBox.tsx | 17 +++++++++++------ 5 files changed, 20 insertions(+), 15 deletions(-) (limited to 'src/client/views/nodes/DataVizBox/components/TableBox.tsx') diff --git a/src/client/views/nodes/DataVizBox/DataVizBox.tsx b/src/client/views/nodes/DataVizBox/DataVizBox.tsx index a92fc1eb9..8b951a002 100644 --- a/src/client/views/nodes/DataVizBox/DataVizBox.tsx +++ b/src/client/views/nodes/DataVizBox/DataVizBox.tsx @@ -15,7 +15,6 @@ import './DataVizBox.scss'; import { Histogram } from './components/Histogram'; import { PieChart } from './components/PieChart'; import { Toggle, ToggleType, Type } from 'browndash-components'; -import { Utils } from '../../../../Utils'; export enum DataVizView { TABLE = 'table', @@ -36,9 +35,7 @@ export class DataVizBox extends ViewBoxAnnotatableComponent() { // @observable private pairs: { [key: string]: FieldResult }[] = []; static pairSet = new ObservableMap(); @computed.struct get pairs() { - var pairs = DataVizBox.pairSet.get(CsvCast(this.rootDoc[this.fieldKey]).url.href); - pairs?.map(pair => {if (!pair.guid) pair.guid = Utils.GenerateGuid()}) - return pairs; + return DataVizBox.pairSet.get(CsvCast(this.rootDoc[this.fieldKey]).url.href); } private _chartRenderer: LineChart | Histogram | PieChart | undefined; // // another way would be store a schema that defines the type of data we are expecting from an imported doc diff --git a/src/client/views/nodes/DataVizBox/components/Histogram.tsx b/src/client/views/nodes/DataVizBox/components/Histogram.tsx index 02f1ddbbb..a9be151bc 100644 --- a/src/client/views/nodes/DataVizBox/components/Histogram.tsx +++ b/src/client/views/nodes/DataVizBox/components/Histogram.tsx @@ -49,12 +49,13 @@ export class Histogram extends React.Component { // TODO: nda - some sort of mapping that keeps track of the annotated points so we can easily remove when annotations list updates @computed get _histogramData() { + var guids = StrListCast(this.props.layoutDoc.rowGuids); if (this.props.axes.length < 1) return []; if (this.props.axes.length < 2) { var ax0 = this.props.axes[0]; if (/\d/.test(this.props.pairs[0][ax0])){ this.numericalXData = true } return this.props.pairs - ?.filter(pair => (!this.incomingLinks.length ? true : this.incomingLinks[0]!.selected && StrListCast(this.incomingLinks[0].selected).includes(pair.guid))) + ?.filter(pair => (!this.incomingLinks.length ? true : this.incomingLinks[0]!.selected && StrListCast(this.incomingLinks[0].selected).includes(guids[this.props.pairs.indexOf(pair)]))) .map(pair => ({ [ax0]: (pair[this.props.axes[0]])})) }; @@ -63,7 +64,7 @@ export class Histogram extends React.Component { if (/\d/.test(this.props.pairs[0][ax0])) { this.numericalXData = true;} if (/\d/.test(this.props.pairs[0][ax1]) && this.props.pairs.length < this.maxBins) { this.numericalYData = true;} return this.props.pairs - ?.filter(pair => (!this.incomingLinks.length ? true : this.incomingLinks[0]!.selected && StrListCast(this.incomingLinks[0].selected).includes(pair.guid))) + ?.filter(pair => (!this.incomingLinks.length ? true : this.incomingLinks[0]!.selected && StrListCast(this.incomingLinks[0].selected).includes(guids[this.props.pairs.indexOf(pair)]))) .map(pair => ({ [ax0]: (pair[this.props.axes[0]]), [ax1]: (pair[this.props.axes[1]]) })) } @computed get defaultGraphTitle(){ diff --git a/src/client/views/nodes/DataVizBox/components/LineChart.tsx b/src/client/views/nodes/DataVizBox/components/LineChart.tsx index da5f7dbbb..77b3acf47 100644 --- a/src/client/views/nodes/DataVizBox/components/LineChart.tsx +++ b/src/client/views/nodes/DataVizBox/components/LineChart.tsx @@ -49,9 +49,10 @@ export class LineChart extends React.Component { // TODO: nda - some sort of mapping that keeps track of the annotated points so we can easily remove when annotations list updates @computed get _lineChartData() { + var guids = StrListCast(this.props.layoutDoc.rowGuids); if (this.props.axes.length <= 1) return []; return this.props.pairs - ?.filter(pair => (!this.incomingLinks.length ? true : this.incomingLinks[0]!.selected && StrListCast(this.incomingLinks[0].selected).includes(pair.guid))) + ?.filter(pair => (!this.incomingLinks.length ? true : this.incomingLinks[0]!.selected && StrListCast(this.incomingLinks[0].selected).includes(guids[this.props.pairs.indexOf(pair)]))) .map(pair => ({ x: Number(pair[this.props.axes[0]]), y: Number(pair[this.props.axes[1]]) })) .sort((a, b) => (a.x < b.x ? -1 : 1)); } diff --git a/src/client/views/nodes/DataVizBox/components/PieChart.tsx b/src/client/views/nodes/DataVizBox/components/PieChart.tsx index 8fdead3d7..cc5cc231b 100644 --- a/src/client/views/nodes/DataVizBox/components/PieChart.tsx +++ b/src/client/views/nodes/DataVizBox/components/PieChart.tsx @@ -46,12 +46,13 @@ export class PieChart extends React.Component { // TODO: nda - some sort of mapping that keeps track of the annotated points so we can easily remove when annotations list updates @computed get _piechartData() { + var guids = StrListCast(this.props.layoutDoc.rowGuids); if (this.props.axes.length < 1) return []; if (this.props.axes.length < 2) { var ax0 = this.props.axes[0]; if (/\d/.test(this.props.pairs[0][ax0])){ this.byCategory = false } return this.props.pairs - ?.filter(pair => (!this.incomingLinks.length ? true : this.incomingLinks[0]!.selected && StrListCast(this.incomingLinks[0].selected).includes(pair.guid))) + ?.filter(pair => (!this.incomingLinks.length ? true : this.incomingLinks[0]!.selected && StrListCast(this.incomingLinks[0].selected).includes(guids[this.props.pairs.indexOf(pair)]))) .map(pair => ({ [ax0]: (pair[this.props.axes[0]])})) }; @@ -59,7 +60,7 @@ export class PieChart extends React.Component { var ax1 = this.props.axes[1]; if (/\d/.test(this.props.pairs[0][ax0])) { this.byCategory = false; } return this.props.pairs - ?.filter(pair => (!this.incomingLinks.length ? true : this.incomingLinks[0]!.selected && StrListCast(this.incomingLinks[0].selected).includes(pair.guid))) + ?.filter(pair => (!this.incomingLinks.length ? true : this.incomingLinks[0]!.selected && StrListCast(this.incomingLinks[0].selected).includes(guids[this.props.pairs.indexOf(pair)]))) .map(pair => ({ [ax0]: (pair[this.props.axes[0]]), [ax1]: (pair[this.props.axes[1]]) })) } @computed get defaultGraphTitle(){ diff --git a/src/client/views/nodes/DataVizBox/components/TableBox.tsx b/src/client/views/nodes/DataVizBox/components/TableBox.tsx index f244502a4..7d6f934b9 100644 --- a/src/client/views/nodes/DataVizBox/components/TableBox.tsx +++ b/src/client/views/nodes/DataVizBox/components/TableBox.tsx @@ -34,7 +34,8 @@ export class TableBox extends React.Component { @computed get _tableData() { if (this.incomingLinks.length! <= 0) return this.props.pairs; - return this.props.pairs?.filter(pair => this.incomingLinks[0]!.selected && StrListCast(this.incomingLinks[0].selected).includes(pair.guid)) + var guids = StrListCast(this.props.layoutDoc.rowGuids); + return this.props.pairs?.filter(pair => this.incomingLinks[0]!.selected && StrListCast(this.incomingLinks[0].selected).includes(guids[this.props.pairs.indexOf(pair)])) } @computed get incomingLinks() { @@ -45,7 +46,10 @@ export class TableBox extends React.Component { } @computed get columns() { - return this._tableData.length ? Array.from(Object.keys(this._tableData[0])).filter(header => header!='guid' && header!='') : []; + if (!this.props.layoutDoc.rowGuids) this.props.layoutDoc.rowGuids = new List(); + const guids = Cast(this.props.layoutDoc.rowGuids, listSpec("string"), null); + if (guids.length==0) this.props.pairs.map(row => guids.push(Utils.GenerateGuid())); + return this._tableData.length ? Array.from(Object.keys(this._tableData[0])).filter(header => header!='') : []; } render() { @@ -121,18 +125,19 @@ export class TableBox extends React.Component { {this._tableData?.map((p, i) => { var containsData = false; + var guid = StrListCast(this.props.layoutDoc.rowGuids)![this.props.pairs.indexOf(p)] this.columns.map(col => {if (p[col]!='' && p[col]!=null && p[col]!=undefined) containsData = true}) if (containsData){ return ( { if (!this.props.layoutDoc.selected) this.props.layoutDoc.selected = new List(); const selected = Cast(this.props.layoutDoc.selected, listSpec("string"), null); - if (selected.includes(p.guid)) selected.splice(selected.indexOf(p.guid), 1); + if (selected.includes(guid)) selected.splice(selected.indexOf(guid), 1); else { - selected.push(p.guid)}; + selected.push(guid)}; })} style={ - { fontWeight: StrListCast(this.props.layoutDoc.selected).includes(p.guid) ? 'bold' : '' , width: '110%', - background: StrListCast(this.props.layoutDoc.selected).includes(p.guid) ? 'lightgrey' : '' }}> + { fontWeight: StrListCast(this.props.layoutDoc.selected).includes(guid) ? 'bold' : '' , width: '110%', + background: StrListCast(this.props.layoutDoc.selected).includes(guid) ? 'lightgrey' : '' }}> {this.columns.map(col => ( (this.props.layoutDoc.selected)? -- cgit v1.2.3-70-g09d2 From 8cbfb72751a3f8814c0dbda54c8ed22c8bb58783 Mon Sep 17 00:00:00 2001 From: srichman333 Date: Fri, 4 Aug 2023 15:17:25 -0400 Subject: color stays on dragged charts + erase bar color is on individual bars --- .../nodes/DataVizBox/components/Histogram.tsx | 28 ++++++++++++++-------- .../views/nodes/DataVizBox/components/TableBox.tsx | 5 +++- 2 files changed, 22 insertions(+), 11 deletions(-) (limited to 'src/client/views/nodes/DataVizBox/components/TableBox.tsx') diff --git a/src/client/views/nodes/DataVizBox/components/Histogram.tsx b/src/client/views/nodes/DataVizBox/components/Histogram.tsx index a9be151bc..2a47abf32 100644 --- a/src/client/views/nodes/DataVizBox/components/Histogram.tsx +++ b/src/client/views/nodes/DataVizBox/components/Histogram.tsx @@ -400,6 +400,14 @@ export class Histogram extends React.Component { barColors.map(each => { if (each.split('::')[0] == barName) barColors.splice(barColors.indexOf(each), 1) }); barColors.push(StrCast(barName + '::' + color)); }; + + @action eraseSelectedColor= () => { + this.curBarSelected.attr("fill", this.props.layoutDoc.defaultHistogramColor); + var barName = StrCast(this._currSelected[this.props.axes[0]].replace(/\$/g, '').replace(/\%/g, '').replace(/\ { if (each.split('::')[0] == barName) barColors.splice(barColors.indexOf(each), 1) }); + }; render() { var curSelectedBarName; @@ -445,28 +453,28 @@ export class Histogram extends React.Component { setSelectedColor={color => this.props.layoutDoc.defaultHistogramColor = color} size={Size.XSMALL} /> -   - } - size={Size.XSMALL} - color={'black'} - type={Type.SEC} - tooltip={'Revert all bars to the default color'} - onClick={action(() => {this.props.layoutDoc.histogramBarColors = new List()})} - />
{selected != 'none' ?
Selected: {selected}     } selectedColor={selectedBarColor? selectedBarColor : this.curBarSelected.attr("fill")} setSelectedColor={color => this.changeSelectedColor(color)} size={Size.XSMALL} /> +   + } + size={Size.XSMALL} + color={'black'} + type={Type.SEC} + tooltip={'Revert to the default bar color'} + onClick={action(() => this.eraseSelectedColor())} + />
: null}
diff --git a/src/client/views/nodes/DataVizBox/components/TableBox.tsx b/src/client/views/nodes/DataVizBox/components/TableBox.tsx index 7d6f934b9..8a99d332f 100644 --- a/src/client/views/nodes/DataVizBox/components/TableBox.tsx +++ b/src/client/views/nodes/DataVizBox/components/TableBox.tsx @@ -1,7 +1,7 @@ import { action, computed, } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; -import { Doc, StrListCast } from '../../../../../fields/Doc'; +import { Doc, Field, StrListCast } from '../../../../../fields/Doc'; import { List } from '../../../../../fields/List'; import { emptyFunction, setupMoveUpEvents, Utils } from '../../../../../Utils'; import { DragManager } from '../../../../util/DragManager'; @@ -85,6 +85,9 @@ export class TableBox extends React.Component { embedding._data_vizAxes = new List([col, col]); embedding._draggedFrom = this.props.docView?.()!.rootDoc!; embedding.annotationOn = annotationOn; //this.props.docView?.()!.rootDoc!; + 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())) { -- cgit v1.2.3-70-g09d2 From 1bfa61ae441458cdcd860eb39e617417d013f1fa Mon Sep 17 00:00:00 2001 From: srichman333 Date: Mon, 7 Aug 2023 10:53:09 -0400 Subject: Issues when you remove a highlighted row more than 1 chart up the tree fixed --- src/client/views/nodes/DataVizBox/components/TableBox.tsx | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'src/client/views/nodes/DataVizBox/components/TableBox.tsx') diff --git a/src/client/views/nodes/DataVizBox/components/TableBox.tsx b/src/client/views/nodes/DataVizBox/components/TableBox.tsx index 8a99d332f..a7cc3f2fb 100644 --- a/src/client/views/nodes/DataVizBox/components/TableBox.tsx +++ b/src/client/views/nodes/DataVizBox/components/TableBox.tsx @@ -52,7 +52,18 @@ export class TableBox extends React.Component { return this._tableData.length ? Array.from(Object.keys(this._tableData[0])).filter(header => header!='') : []; } + filterSelectedRowsDown() { + if (!this.props.layoutDoc.selected) this.props.layoutDoc.selected = new List(); + const selected = Cast(this.props.layoutDoc.selected, listSpec("string"), null); + const incomingSelected = this.incomingLinks.length? StrListCast(this.incomingLinks[0].selected) : undefined; + if (incomingSelected){ + selected.map(guid => { + if (!incomingSelected.includes(guid)) selected.splice(selected.indexOf(guid), 1)}); // filters through selected to remove guids that were removed in the incoming data + } + } + render() { + this.filterSelectedRowsDown(); if (this._tableData.length>0){ return (
@@ -133,7 +144,6 @@ export class TableBox extends React.Component { if (containsData){ return ( { - if (!this.props.layoutDoc.selected) this.props.layoutDoc.selected = new List(); const selected = Cast(this.props.layoutDoc.selected, listSpec("string"), null); if (selected.includes(guid)) selected.splice(selected.indexOf(guid), 1); else { -- cgit v1.2.3-70-g09d2 From 85f91733a21c7b41829eb9280ce33e90783c926d Mon Sep 17 00:00:00 2001 From: srichman333 Date: Mon, 7 Aug 2023 13:30:40 -0400 Subject: selected data at bottom of graph --- src/client/views/nodes/DataVizBox/DataVizBox.scss | 2 +- src/client/views/nodes/DataVizBox/DataVizBox.tsx | 2 +- src/client/views/nodes/DataVizBox/components/Chart.scss | 7 +++++-- src/client/views/nodes/DataVizBox/components/Histogram.tsx | 2 +- src/client/views/nodes/DataVizBox/components/LineChart.tsx | 5 +++-- src/client/views/nodes/DataVizBox/components/PieChart.tsx | 2 +- src/client/views/nodes/DataVizBox/components/TableBox.tsx | 4 ++-- 7 files changed, 14 insertions(+), 10 deletions(-) (limited to 'src/client/views/nodes/DataVizBox/components/TableBox.tsx') diff --git a/src/client/views/nodes/DataVizBox/DataVizBox.scss b/src/client/views/nodes/DataVizBox/DataVizBox.scss index ab2f19726..a69881b7c 100644 --- a/src/client/views/nodes/DataVizBox/DataVizBox.scss +++ b/src/client/views/nodes/DataVizBox/DataVizBox.scss @@ -1,5 +1,5 @@ .dataviz { - overflow: hidden; + overflow: scroll; height: 100%; width: 100%; diff --git a/src/client/views/nodes/DataVizBox/DataVizBox.tsx b/src/client/views/nodes/DataVizBox/DataVizBox.tsx index 8b951a002..9a4546900 100644 --- a/src/client/views/nodes/DataVizBox/DataVizBox.tsx +++ b/src/client/views/nodes/DataVizBox/DataVizBox.tsx @@ -116,7 +116,7 @@ export class DataVizBox extends ViewBoxAnnotatableComponent() { @computed get selectView() { const width = this.props.PanelWidth() * 0.9; const height = (this.props.PanelHeight() - 32) /* height of 'change view' button */ * 0.9; - const margin = { top: 10, right: 25, bottom: 50, left: 25 }; + const margin = { top: 10, right: 25, bottom: 75, left: 45 }; if (!this.pairs) return 'no data'; switch (this.dataVizView) { case DataVizView.TABLE: return ; diff --git a/src/client/views/nodes/DataVizBox/components/Chart.scss b/src/client/views/nodes/DataVizBox/components/Chart.scss index 996183cb8..35e5187b2 100644 --- a/src/client/views/nodes/DataVizBox/components/Chart.scss +++ b/src/client/views/nodes/DataVizBox/components/Chart.scss @@ -4,6 +4,7 @@ align-items: center; cursor: default; margin-top: 10px; + overflow-y: visible; .graph{ overflow: visible; @@ -22,8 +23,8 @@ display: flex; flex-direction: row; margin: 10px; - margin-top: 0px; - margin-bottom: -5px; + margin-top: -25px; + margin-bottom: 5px; } .slice { &.hover { @@ -78,4 +79,6 @@ .table-container{ overflow: scroll; margin: 10px; + margin-left: 25px; + margin-top: 25px; } \ No newline at end of file diff --git a/src/client/views/nodes/DataVizBox/components/Histogram.tsx b/src/client/views/nodes/DataVizBox/components/Histogram.tsx index 2a47abf32..cb882cf4a 100644 --- a/src/client/views/nodes/DataVizBox/components/Histogram.tsx +++ b/src/client/views/nodes/DataVizBox/components/Histogram.tsx @@ -454,6 +454,7 @@ export class Histogram extends React.Component { size={Size.XSMALL} />
+
{selected != 'none' ?
Selected: {selected} @@ -477,7 +478,6 @@ export class Histogram extends React.Component { />
: null} -
) : {'first use table view to select a column to graph'} ); diff --git a/src/client/views/nodes/DataVizBox/components/LineChart.tsx b/src/client/views/nodes/DataVizBox/components/LineChart.tsx index 77b3acf47..3a416c401 100644 --- a/src/client/views/nodes/DataVizBox/components/LineChart.tsx +++ b/src/client/views/nodes/DataVizBox/components/LineChart.tsx @@ -216,7 +216,6 @@ export class LineChart extends React.Component { // TODO: nda - get rid of svg element in the list? this._currSelected = x !== undefined && y !== undefined ? { x, y } : undefined; this.props.pairs.forEach(pair => pair[this.props.axes[0]] === x && pair[this.props.axes[1]] === y && (pair.selected = true)); - this.props.pairs.forEach(pair => (pair.selected = pair[this.props.axes[0]] === x && pair[this.props.axes[1]] === y ? true : undefined)); } drawDataPoints(data: DataPoint[], idx: number, xScale: d3.ScaleLinear, yScale: d3.ScaleLinear) { @@ -369,8 +368,10 @@ export class LineChart extends React.Component { fillWidth />
-
{`Selected: ${selectedPt}`}
+ {selectedPt!='none'? +
{`Selected: ${selectedPt}`}
+ : null}
) : {'first use table view to select two axes to plot'} ); diff --git a/src/client/views/nodes/DataVizBox/components/PieChart.tsx b/src/client/views/nodes/DataVizBox/components/PieChart.tsx index cc5cc231b..ca93a2942 100644 --- a/src/client/views/nodes/DataVizBox/components/PieChart.tsx +++ b/src/client/views/nodes/DataVizBox/components/PieChart.tsx @@ -410,6 +410,7 @@ export class PieChart extends React.Component { fillWidth />
+
{selected != 'none' ?
Selected: {selected} @@ -424,7 +425,6 @@ export class PieChart extends React.Component { />
: null} -
) : {'first use table view to select a column to graph'} ); diff --git a/src/client/views/nodes/DataVizBox/components/TableBox.tsx b/src/client/views/nodes/DataVizBox/components/TableBox.tsx index a7cc3f2fb..38dd62d8d 100644 --- a/src/client/views/nodes/DataVizBox/components/TableBox.tsx +++ b/src/client/views/nodes/DataVizBox/components/TableBox.tsx @@ -49,7 +49,7 @@ export class TableBox extends React.Component { if (!this.props.layoutDoc.rowGuids) this.props.layoutDoc.rowGuids = new List(); const guids = Cast(this.props.layoutDoc.rowGuids, listSpec("string"), null); if (guids.length==0) this.props.pairs.map(row => guids.push(Utils.GenerateGuid())); - return this._tableData.length ? Array.from(Object.keys(this._tableData[0])).filter(header => header!='') : []; + return this._tableData.length ? Array.from(Object.keys(this._tableData[0])).filter(header => header!='' && header!=undefined) : []; } filterSelectedRowsDown() { @@ -66,7 +66,7 @@ export class TableBox extends React.Component { this.filterSelectedRowsDown(); if (this._tableData.length>0){ return ( -
+
-- cgit v1.2.3-70-g09d2 From 318d56e1dff94204b100f5636e1a3288724aaffc Mon Sep 17 00:00:00 2001 From: srichman333 Date: Tue, 8 Aug 2023 16:15:36 -0400 Subject: comments + cleanups --- src/client/views/nodes/DataVizBox/DataVizBox.tsx | 47 +------ .../nodes/DataVizBox/components/Histogram.tsx | 120 ++++------------ .../views/nodes/DataVizBox/components/PieChart.tsx | 155 +++++---------------- .../views/nodes/DataVizBox/components/TableBox.tsx | 7 +- src/client/views/nodes/DataVizBox/utils/D3Utils.ts | 1 - 5 files changed, 78 insertions(+), 252 deletions(-) (limited to 'src/client/views/nodes/DataVizBox/components/TableBox.tsx') diff --git a/src/client/views/nodes/DataVizBox/DataVizBox.tsx b/src/client/views/nodes/DataVizBox/DataVizBox.tsx index 9a4546900..e71739231 100644 --- a/src/client/views/nodes/DataVizBox/DataVizBox.tsx +++ b/src/client/views/nodes/DataVizBox/DataVizBox.tsx @@ -26,45 +26,20 @@ export enum DataVizView { @observer export class DataVizBox extends ViewBoxAnnotatableComponent() { - public static LayoutString(fieldKey: string) { - return FieldView.LayoutString(DataVizBox, fieldKey); - } - // says we have an object and any string - // 2 ways of doing it - // @observable private pairs: { [key: string]: number | string | undefined }[] = []; - // @observable private pairs: { [key: string]: FieldResult }[] = []; + // all data static pairSet = new ObservableMap(); @computed.struct get pairs() { return DataVizBox.pairSet.get(CsvCast(this.rootDoc[this.fieldKey]).url.href); } - private _chartRenderer: LineChart | Histogram | PieChart | undefined; - // // another way would be store a schema that defines the type of data we are expecting from an imported doc - - // method1() { - // this.pairs[0].x = 3; - // } - - // method() { - // // this.pairs[0].x = 3; - // // go through the pairs - // const x = this.pairs[0].x; - // if (typeof x == 'number') { - // let x1 = Number(x); - // // let x1 = NumCast(x); - // } - // } - // could use field result - // [key: string]: FieldResult; - // instead of numeric x,y in there, - - // TODO: nda - use onmousedown and onmouseup when dragging and changing height and width to update the height and width props only when dragging stops + private _chartRenderer: LineChart | Histogram | PieChart | undefined; + // current displayed chart type @computed get dataVizView(): DataVizView { return StrCast(this.layoutDoc._dataVizView, 'table') as DataVizView; } - @action + @action // pinned / linked anchor doc includes selected rows, graph titles, and graph colors restoreView = (data: Doc) => { const changedView = this.dataVizView !== data.presDataVizView && (this.layoutDoc._dataVizView = data.presDataVizView); const changedAxes = this.axes.join('') !== StrListCast(data.presDataVizAxes).join('') && (this.layoutDoc._data_vizAxes = new List(StrListCast(data.presDataVizAxes))); @@ -75,7 +50,6 @@ export class DataVizBox extends ViewBoxAnnotatableComponent() { Object.keys(this.layoutDoc).map(key => { if (key.startsWith('histogram-title') || key.startsWith('lineChart-title') || key.startsWith('pieChart-title')){ this.layoutDoc['_'+key] = data[key]; } }) - const func = () => this._chartRenderer?.restoreView(data); if (changedView || changedAxes) { setTimeout(func, 100); @@ -83,7 +57,6 @@ export class DataVizBox extends ViewBoxAnnotatableComponent() { } return func() ?? false; }; - getAnchor = (addAsAnnotation?: boolean, pinProps?: PinProps) => { const anchor = !pinProps ? this.rootDoc @@ -93,7 +66,6 @@ export class DataVizBox extends ViewBoxAnnotatableComponent() { // this is for when we want the whole doc (so when the chartBox getAnchor returns without a marker) /*put in some options*/ }); - anchor.presDataVizView = this.dataVizView; anchor.presDataVizAxes = this.axes.length ? new List(this.axes) : undefined; anchor.selected = Field.Copy(this.layoutDoc.selected); @@ -103,7 +75,6 @@ export class DataVizBox extends ViewBoxAnnotatableComponent() { Object.keys(this.layoutDoc).map(key => { if (key.startsWith('histogram-title') || key.startsWith('lineChart-title') || key.startsWith('pieChart-title')){ anchor[key] = this.layoutDoc[key]; } }) - this.addDocument(anchor); return anchor; }; @@ -113,6 +84,7 @@ export class DataVizBox extends ViewBoxAnnotatableComponent() { } selectAxes = (axes: string[]) => (this.layoutDoc.data_vizAxes = new List(axes)); + // toggles for user to decide which chart type to view the data in @computed get selectView() { const width = this.props.PanelWidth() * 0.9; const height = (this.props.PanelHeight() - 32) /* height of 'change view' button */ * 0.9; @@ -125,6 +97,7 @@ export class DataVizBox extends ViewBoxAnnotatableComponent() { case DataVizView.PIECHART: return (this._chartRenderer = r ?? undefined)} height={height} width={width} fieldKey={this.fieldKey} margin={margin} rootDoc={this.rootDoc} axes={this.axes} pairs={this.pairs} dataDoc={this.dataDoc} />; } } + @computed get dataUrl() { return Cast(this.dataDoc[this.fieldKey], CsvField); } @@ -141,16 +114,10 @@ export class DataVizBox extends ViewBoxAnnotatableComponent() { .then(res => res.json().then(action(res => !res.errno && DataVizBox.pairSet.set(CsvCast(this.rootDoc[this.fieldKey]).url.href, res)))); } - // handle changing the view using a button - @action changeViewHandler(e: React.MouseEvent) { - e.preventDefault(); - e.stopPropagation(); - this.layoutDoc._dataVizView = this.dataVizView === DataVizView.TABLE ? DataVizView.LINECHART : DataVizView.TABLE; - } - render() { if (!this.layoutDoc._dataVizView) this.layoutDoc._dataVizView = this.dataVizView; return !this.pairs?.length ? ( + // displays how to get data into the DataVizBox if its empty
To create a DataViz box, either import / drag a CSV file into your canvas or copy a data table and use the command 'ctrl + t' to bring the data table diff --git a/src/client/views/nodes/DataVizBox/components/Histogram.tsx b/src/client/views/nodes/DataVizBox/components/Histogram.tsx index 26c40045c..0b35f2856 100644 --- a/src/client/views/nodes/DataVizBox/components/Histogram.tsx +++ b/src/client/views/nodes/DataVizBox/components/Histogram.tsx @@ -44,12 +44,12 @@ export class Histogram extends React.Component { private numericalXData: boolean = false; // whether the data is organized by numbers rather than categoreis private numericalYData: boolean = false; // whether the y axis is controlled by provided data rather than frequency private maxBins = 15; // maximum number of bins that is readable on a normal sized doc - @observable _currSelected: any | undefined = undefined; - private curBarSelected: any = undefined; - private selectedData: any = undefined; - private hoverOverData: any = undefined; - // TODO: nda - some sort of mapping that keeps track of the annotated points so we can easily remove when annotations list updates + @observable _currSelected: any | undefined = undefined; // Object of selected bar + private curBarSelected: any = undefined; // histogram bin of selected bar + private selectedData: any = undefined; // Selection of selected bar + private hoverOverData: any = undefined; // Selection of bar being hovered over + // filters all data to just display selected data if brushed (created from an incoming link) @computed get _histogramData() { var guids = StrListCast(this.props.layoutDoc.rowGuids); if (this.props.axes.length < 1) return []; @@ -60,7 +60,6 @@ export class Histogram extends React.Component { ?.filter(pair => (!this.incomingLinks.length ? true : this.incomingLinks[0]!.selected && StrListCast(this.incomingLinks[0].selected).includes(guids[this.props.pairs.indexOf(pair)]))) .map(pair => ({ [ax0]: (pair[this.props.axes[0]])})) }; - var ax0 = this.props.axes[0]; var ax1 = this.props.axes[1]; if (/\d/.test(this.props.pairs[0][ax0])) { this.numericalXData = true;} @@ -69,6 +68,7 @@ export class Histogram extends React.Component { ?.filter(pair => (!this.incomingLinks.length ? true : this.incomingLinks[0]!.selected && StrListCast(this.incomingLinks[0].selected).includes(guids[this.props.pairs.indexOf(pair)]))) .map(pair => ({ [ax0]: (pair[this.props.axes[0]]), [ax1]: (pair[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; @@ -77,21 +77,13 @@ export class Histogram extends React.Component { } else return ax1 + " by " + ax0 + " Histogram"; } + @computed get incomingLinks() { return LinkManager.Instance.getAllRelatedLinks(this.props.rootDoc) // out of all links - .filter(link => { - return link.link_anchor_1 == this.props.rootDoc.draggedFrom}) // get links where this chart doc is the target of the link + .filter(link => link.link_anchor_1 == this.props.rootDoc.draggedFrom) // 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 } - @computed get incomingSelected() { - // return selected x and y axes - // otherwise, use the selection of whatever is linked to us - return this.incomingLinks // all links that are pointing to this node - .map(anchor => DocumentManager.Instance.getFirstDocumentView(anchor)?.ComponentView as DataVizBox) // get their data viz boxes - .filter(dvb => dvb) - .map(dvb => dvb.pairs?.filter((pair: { [x: string]: any; }) => pair['select' + dvb.rootDoc[Id]])) // get all the datapoints they have selected field set by incoming anchor - .lastElement(); - } + @computed get rangeVals(): { xMin?: number; xMax?: number; yMin?: number; yMax?: number } { if (this.numericalXData){ const data = this.data(this._histogramData); @@ -99,6 +91,7 @@ export class Histogram extends React.Component { } return {xMin:0, xMax:0, yMin:0, yMax:0} } + componentWillUnmount() { Array.from(Object.keys(this._disposers)).forEach(key => this._disposers[key]()); } @@ -108,79 +101,14 @@ export class Histogram extends React.Component { ({ dataSet, w, h }) => { if (dataSet!.length>0) { this.drawChart(dataSet, w, h); - - // redraw annotations when the chart data has changed, or the local or inherited selection has changed - this.clearAnnotations(); - this._currSelected && this.drawAnnotations(Number(this._currSelected.x), Number(this._currSelected.y), true); - this.incomingSelected?.forEach((pair: any) => this.drawAnnotations(Number(pair[this.props.axes[0]]), Number(pair[this.props.axes[1]]))); } }, { fireImmediately: true } ); - this._disposers.annos = reaction( - () => 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 - // this.drawAnnotations() - // loop through annotations and draw them - annotations.forEach(a => this.drawAnnotations(Number(a.x), Number(a.y))); - // this.drawAnnotations(annotations.x, annotations.y); - }, - { fireImmediately: true } - ); - this._disposers.highlights = reaction( - () => ({ - selected: this._currSelected, - incomingSelected: this.incomingSelected, - }), - ({ selected, incomingSelected }) => { - // 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); - incomingSelected?.forEach((pair: any) => this.drawAnnotations(Number(pair[this.props.axes[0]]), Number(pair[this.props.axes[1]]))); - }, - { fireImmediately: true } - ); }; - // anything that doesn't need to be recalculated should just be stored as drawCharts (i.e. computed values) and drawChart is gonna iterate over these observables and generate svgs based on that - - clearAnnotations = () => { - const elements = document.querySelectorAll('.datapoint'); - for (let i = 0; i < elements.length; i++) { - const element = elements[i]; - element.classList.remove('brushed'); - element.classList.remove('selected'); - } - }; - // gets called whenever the "data_annotations" fields gets updated - drawAnnotations = (dataX: number, dataY: number, selected?: boolean) => { - // TODO: nda - can optimize this by having some sort of mapping of the x and y values to the individual circle elements - // loop through all html elements with class .circle-d1 and find the one that has "data-x" and "data-y" attributes that match the dataX and dataY - // if it exists, then highlight it - // if it doesn't exist, then remove the highlight - const elements = document.querySelectorAll('.datapoint'); - for (let i = 0; i < elements.length; i++) { - const element = elements[i]; - const x = element.getAttribute('data-x'); - const y = element.getAttribute('data-y'); - if (x === dataX.toString() && y === dataY.toString()) { - element.classList.add(selected ? 'selected' : 'brushed'); - } - // TODO: nda - this remove highlight code should go where we remove the links - // } else { - // } - } - }; - - removeAnnotations(dataX: number, dataY: number) { - // loop through and remove any annotations that no longer exist - } - @action restoreView = (data: Doc) => {}; - // create a document anchor that stores whatever is needed to reconstruct the viewing state (selection,zoom,etc) getAnchor = (pinProps?: PinProps) => { const anchor = Docs.Create.ConfigDocument({ @@ -188,7 +116,6 @@ export class Histogram extends React.Component { title: 'histogram doc selection' + this._currSelected, }); PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: pinProps?.pinData }, this.props.dataDoc); - // anchor.presDataVizSelection = this._currSelected ? new List([this._currSelected]) : undefined; return anchor; }; @@ -200,6 +127,7 @@ export class Histogram extends React.Component { 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 data = (dataSet: any) => { var validData = dataSet.filter((d: { [x: string]: unknown; }) => { var valid = true; @@ -216,21 +144,24 @@ export class Histogram extends React.Component { return data; } + // outlines the bar selected / hovered over highlightSelectedBar = (changeSelectedVariables: boolean, svg: any, eachRectWidth: any, pointerX: any, xAxisTitle: any, yAxisTitle: any, histDataSet: any) => { var sameAsCurrent: boolean; var barCounter = -1; const selected = svg.selectAll('.histogram-bar').filter((d: any) => { - barCounter++; + barCounter++; // uses the order of bars and width of each bar to find which one the pointer is over if ((barCounter*eachRectWidth ) <= pointerX && pointerX <= ((barCounter+1)*eachRectWidth)){ var showSelected = this.numericalYData? this._histogramData.filter((data: { [x: string]: any; }) => data[xAxisTitle].replace(/\$/g, '').replace(/\%/g, '').replace(/\ data[xAxisTitle].replace(/\$/g, '').replace(/\%/g, '').replace(/\ { } } + // draws the histogram drawChart = (dataSet: any, width: number, height: number) => { d3.select(this._histogramRef.current).select('svg').remove(); d3.select(this._histogramRef.current).select('.tooltip').remove(); var data = this.data(dataSet); - var xAxisTitle = Object.keys(dataSet[0])[0] var yAxisTitle = this.numericalYData ? Object.keys(dataSet[0])[1] : 'frequency'; let uniqueArr: unknown[] = [...new Set(data)] @@ -263,6 +194,8 @@ export class Histogram extends React.Component { if (numBins>this.maxBins) numBins = this.maxBins; var startingPoint = this.numericalXData? this.rangeVals.xMin! : 0; var endingPoint = this.numericalXData? this.rangeVals.xMax! : numBins; + + // converts data into Objects var histDataSet = dataSet.filter((d: { [x: string]: unknown; }) => { var valid = true; Object.keys(dataSet[0]).map(key => { @@ -289,6 +222,7 @@ export class Histogram extends React.Component { histDataSet = histStringDataSet } + // initial graph and binning data for histogram var svg = (this._histogramSvg = d3 .select(this._histogramRef.current) .append("svg") @@ -298,7 +232,6 @@ export class Histogram extends React.Component { .append("g") .attr("transform", "translate(" + this.props.margin.left + "," + this.props.margin.top + ")")); - var x = d3.scaleLinear() .domain(this.numericalXData? [startingPoint!, endingPoint!] : [0, numBins]) .range([0, width ]); @@ -314,6 +247,8 @@ export class Histogram extends React.Component { .range([0, Number.isInteger(this.rangeVals.xMin!)? (width-eachRectWidth) : width ]) var xAxis; + // more calculations based on bins + // x-axis if (!this.numericalXData) { // reorganize if the data is strings rather than numbers // uniqueArr.sort() histDataSet.sort() @@ -331,7 +266,7 @@ export class Histogram extends React.Component { bins.forEach(d => d.x0 = d.x0!) xAxis = d3.axisBottom(x) .ticks(bins.length-1) - .tickFormat( i => uniqueArr[i]) + .tickFormat( i => uniqueArr[i.valueOf()] as string) .tickPadding(10) x.range([0, width-eachRectWidth]) x.domain([0, bins.length-1]) @@ -343,10 +278,10 @@ export class Histogram extends React.Component { xAxis = d3.axisBottom(x) .ticks(numBins-1) } + // y-axis const maxFrequency = this.numericalYData? d3.max(histDataSet, function(d: any) { return Number(d[yAxisTitle]!.replace(/\$/g, '').replace(/\%/g, '').replace(/\ { svg.append("g") .attr("transform", "translate(" + translateXAxis + ", " + height + ")") .call(xAxis) - + + // click/hover const onPointClick = action((e: any) => this.highlightSelectedBar(true, svg, eachRectWidth, d3.pointer(e)[0], xAxisTitle, yAxisTitle, histDataSet)); const onHover = action((e: any) => { const selected = this.highlightSelectedBar(false, svg, eachRectWidth, d3.pointer(e)[0], xAxisTitle, yAxisTitle, histDataSet) @@ -378,12 +314,11 @@ export class Histogram extends React.Component { const selectedData = this.selectedData; svg.selectAll('rect').attr("class", function(d: any) { return ((hoverOverBar && hoverOverBar[0]==d[0]) || selectedData && selectedData[0]==d[0])? 'histogram-bar hover' : 'histogram-bar'; }) } - svg.on('click', onPointClick) .on('mouseover', onHover) .on('mouseout', mouseOut) - var selected = this.selectedData; + // axis titles svg.append("text") .attr("transform", "translate(" + (width/2) + " ," + (height+40) + ")") .style("text-anchor", "middle") @@ -395,6 +330,9 @@ export class Histogram extends React.Component { .style("text-anchor", "middle") .text(yAxisTitle); d3.format('.0f') + + // draw bars + var selected = this.selectedData; svg.selectAll("rect") .data(bins) .enter() diff --git a/src/client/views/nodes/DataVizBox/components/PieChart.tsx b/src/client/views/nodes/DataVizBox/components/PieChart.tsx index 0fd4f6b54..d4570dee2 100644 --- a/src/client/views/nodes/DataVizBox/components/PieChart.tsx +++ b/src/client/views/nodes/DataVizBox/components/PieChart.tsx @@ -40,12 +40,12 @@ export class PieChart extends React.Component { private _piechartRef: React.RefObject = React.createRef(); private _piechartSvg: d3.Selection | undefined; private byCategory: boolean = true; // whether the data is organized by category or by specified number percentages/ratios - @observable _currSelected: any | undefined = undefined; - private curSliceSelected: any = undefined; - private selectedData: any = undefined; - private hoverOverData: any = undefined; - // TODO: nda - some sort of mapping that keeps track of the annotated points so we can easily remove when annotations list updates + @observable _currSelected: any | undefined = undefined; // Object of selected slice + private curSliceSelected: any = undefined; // d3 data of selected slice + private selectedData: any = undefined; // Selection of selected slice + private hoverOverData: any = undefined; // Selection of slice being hovered over + // filters all data to just display selected data if brushed (created from an incoming link) @computed get _piechartData() { var guids = StrListCast(this.props.layoutDoc.rowGuids); if (this.props.axes.length < 1) return []; @@ -56,7 +56,6 @@ export class PieChart extends React.Component { ?.filter(pair => (!this.incomingLinks.length ? true : this.incomingLinks[0]!.selected && StrListCast(this.incomingLinks[0].selected).includes(guids[this.props.pairs.indexOf(pair)]))) .map(pair => ({ [ax0]: (pair[this.props.axes[0]])})) }; - var ax0 = this.props.axes[0]; var ax1 = this.props.axes[1]; if (/\d/.test(this.props.pairs[0][ax0])) { this.byCategory = false; } @@ -64,6 +63,7 @@ export class PieChart extends React.Component { ?.filter(pair => (!this.incomingLinks.length ? true : this.incomingLinks[0]!.selected && StrListCast(this.incomingLinks[0].selected).includes(guids[this.props.pairs.indexOf(pair)]))) .map(pair => ({ [ax0]: (pair[this.props.axes[0]]), [ax1]: (pair[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; @@ -72,28 +72,13 @@ export class PieChart extends React.Component { } else return ax1 + " by " + ax0 + " Pie Chart"; } + @computed get incomingLinks() { return LinkManager.Instance.getAllRelatedLinks(this.props.rootDoc) // out of all links - .filter(link => { - return link.link_anchor_1 == this.props.rootDoc.draggedFrom}) // get links where this chart doc is the target of the link + .filter(link => link.link_anchor_1 == this.props.rootDoc.draggedFrom) // 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 } - @computed get incomingSelected() { - // return selected x and y axes - // otherwise, use the selection of whatever is linked to us - return this.incomingLinks // all links that are pointing to this node - .map(anchor => DocumentManager.Instance.getFirstDocumentView(anchor)?.ComponentView as DataVizBox) // get their data viz boxes - .filter(dvb => dvb) - .map(dvb => dvb.pairs?.filter((pair: { [x: string]: any; }) => pair['select' + dvb.rootDoc[Id]])) // get all the datapoints they have selected field set by incoming anchor - .lastElement(); - } - @computed get rangeVals(): { xMin?: number; xMax?: number; yMin?: number; yMax?: number } { - if (!this.byCategory){ - const data = this.data(this._piechartData); - return {xMin: Math.min.apply(null, data), xMax: Math.max.apply(null, data), yMin:0, yMax:0} - } - return {xMin:0, xMax:0, yMin:0, yMax:0} - } + componentWillUnmount() { Array.from(Object.keys(this._disposers)).forEach(key => this._disposers[key]()); } @@ -103,79 +88,14 @@ export class PieChart extends React.Component { ({ dataSet, w, h }) => { if (dataSet!.length>0) { this.drawChart(dataSet, w, h); - - // redraw annotations when the chart data has changed, or the local or inherited selection has changed - this.clearAnnotations(); - this._currSelected && this.drawAnnotations(Number(this._currSelected.x), Number(this._currSelected.y), true); - this.incomingSelected?.forEach((pair: any) => this.drawAnnotations(Number(pair[this.props.axes[0]]), Number(pair[this.props.axes[1]]))); } }, { fireImmediately: true } ); - this._disposers.annos = reaction( - () => 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 - // this.drawAnnotations() - // loop through annotations and draw them - annotations.forEach(a => this.drawAnnotations(Number(a.x), Number(a.y))); - // this.drawAnnotations(annotations.x, annotations.y); - }, - { fireImmediately: true } - ); - this._disposers.highlights = reaction( - () => ({ - selected: this._currSelected, - incomingSelected: this.incomingSelected, - }), - ({ selected, incomingSelected }) => { - // 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); - incomingSelected?.forEach((pair: any) => this.drawAnnotations(Number(pair[this.props.axes[0]]), Number(pair[this.props.axes[1]]))); - }, - { fireImmediately: true } - ); - }; - - // anything that doesn't need to be recalculated should just be stored as drawCharts (i.e. computed values) and drawChart is gonna iterate over these observables and generate svgs based on that - - clearAnnotations = () => { - const elements = document.querySelectorAll('.datapoint'); - for (let i = 0; i < elements.length; i++) { - const element = elements[i]; - element.classList.remove('brushed'); - element.classList.remove('selected'); - } - }; - // gets called whenever the "data_annotations" fields gets updated - drawAnnotations = (dataX: number, dataY: number, selected?: boolean) => { - // TODO: nda - can optimize this by having some sort of mapping of the x and y values to the individual circle elements - // loop through all html elements with class .circle-d1 and find the one that has "data-x" and "data-y" attributes that match the dataX and dataY - // if it exists, then highlight it - // if it doesn't exist, then remove the highlight - const elements = document.querySelectorAll('.datapoint'); - for (let i = 0; i < elements.length; i++) { - const element = elements[i]; - const x = element.getAttribute('data-x'); - const y = element.getAttribute('data-y'); - if (x === dataX.toString() && y === dataY.toString()) { - element.classList.add(selected ? 'selected' : 'brushed'); - } - // TODO: nda - this remove highlight code should go where we remove the links - // } else { - // } - } }; - removeAnnotations(dataX: number, dataY: number) { - // loop through and remove any annotations that no longer exist - } - @action restoreView = (data: Doc) => {}; - // create a document anchor that stores whatever is needed to reconstruct the viewing state (selection,zoom,etc) getAnchor = (pinProps?: PinProps) => { const anchor = Docs.Create.ConfigDocument({ @@ -183,7 +103,6 @@ export class PieChart extends React.Component { title: 'piechart doc selection' + this._currSelected, }); PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: pinProps?.pinData }, this.props.dataDoc); - // anchor.presDataVizSelection = this._currSelected ? new List([this._currSelected]) : undefined; return anchor; }; @@ -195,15 +114,7 @@ export class PieChart extends React.Component { return this.props.width - this.props.margin.left - this.props.margin.right; } - // TODO: nda - use this everyewhere we update currSelected? - @action - setCurrSelected(x?: number, y?: number) { - // TODO: nda - get rid of svg element in the list? - this._currSelected = x !== undefined && y !== undefined ? { x, y } : undefined; - this.props.pairs.forEach(pair => pair[this.props.axes[0]] === x && pair[this.props.axes[1]] === y && (pair.selected = true)); - this.props.pairs.forEach(pair => (pair.selected = pair[this.props.axes[0]] === x && pair[this.props.axes[1]] === y ? true : undefined)); - } - + // cleans data by converting numerical data to numbers and taking out empty cells data = (dataSet: any) => { var validData = dataSet.filter((d: { [x: string]: unknown; }) => { var valid = true; @@ -220,15 +131,16 @@ export class PieChart extends React.Component { return data; } + // outlines the slice selected / hovered over highlightSelectedSlice = (changeSelectedVariables: boolean, svg: any, arc: any, radius: any, pointer: any, pieDataSet: any) => { var index = -1; var sameAsCurrent: boolean; const selected = svg.selectAll('.slice').filter((d: any) => { index++; - var p1 = [0,0]; - var p3 = [arc.centroid(d)[0]*2, arc.centroid(d)[1]*2]; - var p2 = [radius*Math.sin(d.startAngle), -radius*Math.cos(d.startAngle)]; - var p4 = [radius*Math.sin(d.endAngle), -radius*Math.cos(d.endAngle)]; + var p1 = [0,0]; // center of pie + var p3 = [arc.centroid(d)[0]*2, arc.centroid(d)[1]*2]; // outward peak of arc + var p2 = [radius*Math.sin(d.startAngle), -radius*Math.cos(d.startAngle)]; // start of arc + var p4 = [radius*Math.sin(d.endAngle), -radius*Math.cos(d.endAngle)]; // end of arc // draw an imaginary horizontal line from the pointer to see how many times it crosses a slice edge var lineCrossCount = 0; @@ -241,10 +153,10 @@ export class PieChart extends React.Component { if (pointer[0] <= (pointer[1]-p3[1])*(p4[0]-p3[0])/(p4[1]-p3[1])+p3[0]) lineCrossCount++; } if (Math.min(p4[1], p1[1])<=pointer[1] && pointer[1]<=Math.max(p4[1], p1[1])){ if (pointer[0] <= (pointer[1]-p4[1])*(p1[0]-p4[0])/(p1[1]-p4[1])+p4[0]) lineCrossCount++; } - if (lineCrossCount % 2 != 0) { + if (lineCrossCount % 2 != 0) { // inside the slice of it crosses an odd number of edges var showSelected = this.byCategory? pieDataSet[index] : this._piechartData[index]; - if (changeSelectedVariables){ + // for when a bar is selected - not just hovered over sameAsCurrent = (this._currSelected)? (showSelected[Object.keys(showSelected)[0]]==this._currSelected![Object.keys(showSelected)[0]] && showSelected[Object.keys(showSelected)[1]]==this._currSelected![Object.keys(showSelected)[1]]) @@ -264,6 +176,7 @@ export class PieChart extends React.Component { } } + // draws the pie chart drawChart = (dataSet: any, width: number, height: number) => { d3.select(this._piechartRef.current).select('svg').remove(); d3.select(this._piechartRef.current).select('.tooltip').remove(); @@ -271,18 +184,8 @@ export class PieChart extends React.Component { 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 svg = (this._piechartSvg = d3 - .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) - .append("g")); - - let g = svg.append("g") - .attr("transform", - "translate(" + (width/2 + this.props.margin.left) + "," + height/2 + ")"); + // converts data into Objects var data = this.data(dataSet); var pieDataSet = dataSet.filter((d: { [x: string]: unknown; }) => { var valid = true; @@ -293,12 +196,12 @@ export class PieChart extends React.Component { }); if (this.byCategory){ let uniqueCategories = [...new Set(data)] - var pieStringDataSet: { frequency: number, [percentField]: string }[] = []; + var pieStringDataSet: { frequency: number }[] = []; for (let i=0; i each[percentField]==data[i]) + let sliceData = pieStringDataSet.filter((each: any) => each[percentField]==data[i]) sliceData[0].frequency = sliceData[0].frequency + 1; } pieDataSet = pieStringDataSet @@ -309,11 +212,23 @@ export class PieChart extends React.Component { var trackDuplicates : {[key: string]: any} = {}; data.forEach((eachData: any) => !trackDuplicates[eachData]? trackDuplicates[eachData] = 0: null) + // initial chart + var svg = (this._piechartSvg = d3 + .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) + .append("g")); + 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); + // click/hover const onPointClick = action((e: any) => this.highlightSelectedSlice(true, svg, arc, radius, d3.pointer(e), pieDataSet)); const onHover = action((e: any) => { const selected = this.highlightSelectedSlice(false, svg, arc, radius, d3.pointer(e), pieDataSet) @@ -331,6 +246,7 @@ export class PieChart extends React.Component { || ((hoverOverSlice && d.startAngle==hoverOverSlice.startAngle && d.endAngle==hoverOverSlice.endAngle)))? 'slice hover' : 'slice'; }) } + // drawing the slices var selected = this.selectedData; var arcs = g.selectAll("arc") .data(pie(data)) @@ -359,11 +275,12 @@ export class PieChart extends React.Component { function(d) { return (selected && d.startAngle==selected.startAngle && d.endAngle==selected.endAngle)? 'slice hover' : 'slice'; }: function(d) {return 'slice'}) - .attr("d", arc) + .attr('d', arc) .on('click', onPointClick) .on('mouseover', onHover) .on('mouseout', mouseOut); + // adding labels trackDuplicates = {}; data.forEach((eachData: any) => !trackDuplicates[eachData]? trackDuplicates[eachData] = 0: null) arcs.append("text") diff --git a/src/client/views/nodes/DataVizBox/components/TableBox.tsx b/src/client/views/nodes/DataVizBox/components/TableBox.tsx index 38dd62d8d..277ee83ec 100644 --- a/src/client/views/nodes/DataVizBox/components/TableBox.tsx +++ b/src/client/views/nodes/DataVizBox/components/TableBox.tsx @@ -32,6 +32,7 @@ interface TableBoxProps { @observer export class TableBox extends React.Component { + // filters all data to just display selected data if brushed (created from an incoming link) @computed get _tableData() { if (this.incomingLinks.length! <= 0) return this.props.pairs; var guids = StrListCast(this.props.layoutDoc.rowGuids); @@ -52,6 +53,7 @@ export class TableBox extends React.Component { return this._tableData.length ? Array.from(Object.keys(this._tableData[0])).filter(header => header!='' && header!=undefined) : []; } + // updates the 'selected' field to no longer include rows that aren't in the table filterSelectedRowsDown() { if (!this.props.layoutDoc.selected) this.props.layoutDoc.selected = new List(); const selected = Cast(this.props.layoutDoc.selected, listSpec("string"), null); @@ -88,7 +90,7 @@ export class TableBox extends React.Component { setupMoveUpEvents( {}, e, - e => { + e => { // dragging off a column to create a brushed DataVizBox const sourceAnchorCreator = () => this.props.docView?.()!.rootDoc!; const targetCreator = (annotationOn: Doc | undefined) => { const embedding = Doc.MakeEmbedding(this.props.docView?.()!.rootDoc!); @@ -144,6 +146,7 @@ export class TableBox extends React.Component { if (containsData){ return (
{ + // selecting a row const selected = Cast(this.props.layoutDoc.selected, listSpec("string"), null); if (selected.includes(guid)) selected.splice(selected.indexOf(guid), 1); else { @@ -153,6 +156,7 @@ export class TableBox extends React.Component { background: StrListCast(this.props.layoutDoc.selected).includes(guid) ? 'lightgrey' : '' }}> {this.columns.map(col => ( (this.props.layoutDoc.selected)? + // each cell @@ -168,6 +172,7 @@ export class TableBox extends React.Component { ); } else return ( + // when it is a brushed table and the incoming table doesn't have any rows selected
Selected rows of data from the incoming DataVizBox to display.
diff --git a/src/client/views/nodes/DataVizBox/utils/D3Utils.ts b/src/client/views/nodes/DataVizBox/utils/D3Utils.ts index e1ff6f8eb..10bfb0c64 100644 --- a/src/client/views/nodes/DataVizBox/utils/D3Utils.ts +++ b/src/client/views/nodes/DataVizBox/utils/D3Utils.ts @@ -34,7 +34,6 @@ export const createLineGenerator = (xScale: d3.ScaleLinear, height: number, xScale: d3.ScaleLinear) => { - console.log('x axis creator being called'); g.attr('class', 'x-axis').attr('transform', `translate(0,${height})`).call(d3.axisBottom(xScale).tickSize(15)); }; -- cgit v1.2.3-70-g09d2 From 481a847b1074c9544e947e409b96778ac4d4f852 Mon Sep 17 00:00:00 2001 From: srichman333 Date: Wed, 9 Aug 2023 15:24:03 -0400 Subject: numerical y axis data fix --- .../views/nodes/DataVizBox/components/Histogram.tsx | 11 ++++------- .../views/nodes/DataVizBox/components/PieChart.tsx | 21 +++++++++------------ .../views/nodes/DataVizBox/components/TableBox.tsx | 4 ++-- 3 files changed, 15 insertions(+), 21 deletions(-) (limited to 'src/client/views/nodes/DataVizBox/components/TableBox.tsx') diff --git a/src/client/views/nodes/DataVizBox/components/Histogram.tsx b/src/client/views/nodes/DataVizBox/components/Histogram.tsx index e04d37094..ed663006f 100644 --- a/src/client/views/nodes/DataVizBox/components/Histogram.tsx +++ b/src/client/views/nodes/DataVizBox/components/Histogram.tsx @@ -1,13 +1,10 @@ import { observer } from "mobx-react"; -import { Doc, DocListCast, StrListCast } from "../../../../../fields/Doc"; +import { Doc, StrListCast } from "../../../../../fields/Doc"; import * as React from 'react'; import * as d3 from 'd3'; import { IReactionDisposer, action, computed, observable, reaction } from "mobx"; import { LinkManager } from "../../../../util/LinkManager"; import { Cast, DocCast, StrCast} from "../../../../../fields/Types"; -import { DocumentManager } from "../../../../util/DocumentManager"; -import { Id } from "../../../../../fields/FieldSymbols"; -import { DataVizBox } from "../DataVizBox"; import { PinProps, PresBox } from "../../trails"; import { Docs } from "../../../../documents/Documents"; import { List } from "../../../../../fields/List"; @@ -299,7 +296,7 @@ export class Histogram extends React.Component { } // y-axis const maxFrequency = this.numericalYData? d3.max(histDataSet, function(d: any) { - return Number(d[yAxisTitle]!.replace(/\$/g, '').replace(/\%/g, '').replace(/\ { .attr("transform", this.numericalYData? function (d) { var eachData = histDataSet.filter((data: { [x: string]: number; }) => {return data[xAxisTitle]==d[0]}) - var length = eachData[0][yAxisTitle].replace(/\$/g, '').replace(/\%/g, '').replace(/\ {return data[xAxisTitle]==d[0]}) - var length = eachData[0][yAxisTitle].replace(/\$/g, '').replace(/\%/g, '').replace(/\ { .attr("fill", (d, i)=>{ var possibleDataPoints = pieDataSet.filter((each: { [x: string]: any | { valueOf(): number; }; }) => { try { - return each[percentField].replace(/[^0-9]/g,"")==d.data.toString().replace(/[^0-9]/g,"") + return Number(each[percentField].replace(/\$/g, '').replace(/\%/g, '').replace(/\ { dataPoint = possibleDataPoints[trackDuplicates[d.data.toString()]] trackDuplicates[d.data.toString()] = trackDuplicates[d.data.toString()] + 1; } - var accessByName = descriptionField? dataPoint[descriptionField] : dataPoint[percentField]; var sliceColor; - var sliceColors = StrListCast(this.props.layoutDoc.pieSliceColors).map(each => each.split('::')); - sliceColors.map(each => {if (each[0]==StrCast(accessByName)) sliceColor = each[1]}); + if (dataPoint){ + var accessByName = descriptionField? dataPoint[descriptionField] : dataPoint[percentField]; + var sliceColors = StrListCast(this.props.layoutDoc.pieSliceColors).map(each => each.split('::')); + sliceColors.map(each => {if (each[0]==StrCast(accessByName)) sliceColor = each[1]}); + } return sliceColor? StrCast(sliceColor) : d3.schemeSet3[i]? d3.schemeSet3[i]: d3.schemeSet3[i%(d3.schemeSet3.length)] }) .attr("class", selected? function(d) { @@ -292,7 +291,7 @@ export class PieChart extends React.Component { .text(function(d){ var possibleDataPoints = pieDataSet.filter((each: { [x: string]: any | { valueOf(): number; }; }) => { try { - return each[percentField].replace(/[^0-9]/g,"")==d.data.toString().replace(/[^0-9]/g,"") + return Number(each[percentField].replace(/\$/g, '').replace(/\%/g, '').replace(/\ { dataPoint = possibleDataPoints[trackDuplicates[d.data.toString()]] trackDuplicates[d.data.toString()] = trackDuplicates[d.data.toString()] + 1; } - return dataPoint[percentField]! - + (!descriptionField? '' : (' - ' + dataPoint[descriptionField]))!}) - + return dataPoint? dataPoint[percentField]! + (!descriptionField? '' : (' - ' + dataPoint[descriptionField]))! : ''}) }; @action changeSelectedColor = (color: string) => { diff --git a/src/client/views/nodes/DataVizBox/components/TableBox.tsx b/src/client/views/nodes/DataVizBox/components/TableBox.tsx index 277ee83ec..f80cbdf99 100644 --- a/src/client/views/nodes/DataVizBox/components/TableBox.tsx +++ b/src/client/views/nodes/DataVizBox/components/TableBox.tsx @@ -123,10 +123,10 @@ export class TableBox extends React.Component { const newAxes = this.props.axes; if (newAxes.includes(col)) { newAxes.splice(newAxes.indexOf(col), 1); - } else if (newAxes.length >= 1) { + } else if (newAxes.length > 1) { newAxes[1] = col; } else { - newAxes[0] = col; + newAxes.push(col); } this.props.selectAxes(newAxes); }) -- cgit v1.2.3-70-g09d2 From da893c2739c9589bac04c00df3d22ebbfd78c09d Mon Sep 17 00:00:00 2001 From: srichman333 Date: Sun, 13 Aug 2023 17:13:31 -0400 Subject: LineChart ui fixes + selected columns bolded --- .../views/nodes/DataVizBox/components/LineChart.tsx | 4 ++-- .../views/nodes/DataVizBox/components/TableBox.tsx | 17 ++++++++--------- 2 files changed, 10 insertions(+), 11 deletions(-) (limited to 'src/client/views/nodes/DataVizBox/components/TableBox.tsx') diff --git a/src/client/views/nodes/DataVizBox/components/LineChart.tsx b/src/client/views/nodes/DataVizBox/components/LineChart.tsx index 49ef577e4..d27aaafbc 100644 --- a/src/client/views/nodes/DataVizBox/components/LineChart.tsx +++ b/src/client/views/nodes/DataVizBox/components/LineChart.tsx @@ -348,7 +348,7 @@ export class LineChart extends React.Component { tooltip .html(() => `(${d0.x},${d0.y})`) // text content for tooltip .style('pointer-events', 'none') - .style('transform', `translate(${xScale(d0.x) - this.width / 2}px,${yScale(d0.y) - 30}px)`); + .style('transform', `translate(${xScale(d0.x)-this.width}px,${yScale(d0.y)}px)`); } render() { @@ -357,7 +357,7 @@ export class LineChart extends React.Component { if (this.props.axes.length==2) titleAccessor = 'lineChart-title-'+this.props.axes[0]+'-'+this.props.axes[1]; else if (this.props.axes.length>0) titleAccessor = 'lineChart-title-'+this.props.axes[0]; if (!this.props.layoutDoc[titleAccessor]) this.props.layoutDoc[titleAccessor] = this.defaultGraphTitle; - const selectedPt = this._currSelected ? `x: ${this._currSelected.x} y: ${this._currSelected.y}` : 'none'; + const selectedPt = this._currSelected ? `{ ${this.props.axes[0]}: ${this._currSelected.x} ${this.props.axes[1]}: ${this._currSelected.y} }` : 'none'; return ( this.props.axes.length>=2 && /\d/.test(this.props.pairs[0][this.props.axes[0]]) && /\d/.test(this.props.pairs[0][this.props.axes[1]]) ? (
diff --git a/src/client/views/nodes/DataVizBox/components/TableBox.tsx b/src/client/views/nodes/DataVizBox/components/TableBox.tsx index f80cbdf99..f56d34fa6 100644 --- a/src/client/views/nodes/DataVizBox/components/TableBox.tsx +++ b/src/client/views/nodes/DataVizBox/components/TableBox.tsx @@ -81,7 +81,8 @@ export class TableBox extends React.Component { key={this.columns.indexOf(col)} ref={header as any} style={{ - color: this.props.axes.slice().reverse().lastElement() === col ? 'green' : this.props.axes.lastElement() === col ? 'red' : 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' }} onPointerDown={e => { @@ -151,17 +152,15 @@ export class TableBox extends React.Component { if (selected.includes(guid)) selected.splice(selected.indexOf(guid), 1); else { selected.push(guid)}; - })} style={ - { fontWeight: StrListCast(this.props.layoutDoc.selected).includes(guid) ? 'bold' : '' , width: '110%', - background: StrListCast(this.props.layoutDoc.selected).includes(guid) ? 'lightgrey' : '' }}> - {this.columns.map(col => ( - (this.props.layoutDoc.selected)? + })} style={{ background: StrListCast(this.props.layoutDoc.selected).includes(guid) ? 'lightgrey' : '', width: '110%' }}> + {this.columns.map(col => { // each cell -
- : - ))} + )})} ); } -- cgit v1.2.3-70-g09d2 From 0eb9d37a9dd1a6539f331f953d5f20c761d5f940 Mon Sep 17 00:00:00 2001 From: bobzel Date: Thu, 17 Aug 2023 10:00:10 -0400 Subject: fixed brushing of pinned viewports for chrome to not flash. converted pres to config_ and treeView to treeView_Property. fixed text toolbar to show/set text properties based on insertion point. --- src/client/documents/Documents.ts | 101 ++-- src/client/util/CurrentUserUtils.ts | 38 +- src/client/util/DocumentManager.ts | 6 +- src/client/views/DashboardView.tsx | 15 +- src/client/views/DocumentButtonBar.tsx | 6 +- src/client/views/InkStroke.scss | 1 + src/client/views/InkingStroke.tsx | 6 +- src/client/views/MainView.tsx | 4 +- src/client/views/MarqueeAnnotator.tsx | 2 +- src/client/views/PropertiesView.scss | 88 ++-- src/client/views/PropertiesView.tsx | 32 +- src/client/views/StyleProvider.tsx | 8 +- src/client/views/TemplateMenu.tsx | 2 +- .../views/collections/CollectionTimeView.tsx | 6 +- .../views/collections/CollectionTreeView.tsx | 22 +- src/client/views/collections/CollectionView.tsx | 2 +- src/client/views/collections/TabDocView.tsx | 45 +- src/client/views/collections/TreeView.tsx | 90 ++-- .../collectionFreeForm/CollectionFreeFormView.scss | 7 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 46 +- src/client/views/linking/LinkMenuItem.tsx | 2 +- src/client/views/nodes/DataVizBox/DataVizBox.tsx | 111 ++-- .../nodes/DataVizBox/components/Histogram.tsx | 534 ++++++++++--------- .../nodes/DataVizBox/components/LineChart.tsx | 105 ++-- .../views/nodes/DataVizBox/components/PieChart.tsx | 401 ++++++++------- .../views/nodes/DataVizBox/components/TableBox.tsx | 87 ++-- src/client/views/nodes/DocumentView.tsx | 17 +- src/client/views/nodes/FontIconBox/FontIconBox.tsx | 4 +- src/client/views/nodes/FunctionPlotBox.tsx | 4 +- src/client/views/nodes/ImageBox.tsx | 14 +- src/client/views/nodes/KeyValueBox.tsx | 17 +- src/client/views/nodes/LinkBox.tsx | 2 +- src/client/views/nodes/MapBox/MapBox.tsx | 2 +- src/client/views/nodes/MapBox/MapBox2.tsx | 2 +- src/client/views/nodes/PDFBox.tsx | 6 +- src/client/views/nodes/WebBox.tsx | 16 +- .../views/nodes/formattedText/FormattedTextBox.tsx | 29 +- .../formattedText/ProsemirrorExampleTransfer.ts | 2 +- .../views/nodes/formattedText/RichTextMenu.tsx | 2 +- src/client/views/nodes/trails/PresBox.tsx | 567 +++++++++++---------- src/client/views/nodes/trails/PresElementBox.tsx | 50 +- src/client/views/pdf/Annotation.tsx | 4 +- src/client/views/pdf/PDFViewer.tsx | 8 +- src/fields/Doc.ts | 8 +- src/fields/documentSchemas.ts | 10 +- 45 files changed, 1334 insertions(+), 1197 deletions(-) (limited to 'src/client/views/nodes/DataVizBox/components/TableBox.tsx') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 5c33e319d..96a983153 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -288,12 +288,12 @@ export class DocumentOptions { _isTimelineLabel?: BOOLt = new BoolInfo('is document a timeline label'); _isLightbox?: BOOLt = new BoolInfo('whether a collection acts as a lightbox by opening lightbox links by hiding all other documents in collection besides link target'); - presPanX?: NUMt = new NumInfo('panX saved as a view spec'); - presPanY?: NUMt = new NumInfo('panY saved as a view spec'); - presViewScale?: NUMt = new NumInfo('viewScale saved as a view Spec'); - presTransition?: NUMt = new NumInfo('the time taken for the transition TO a document'); - presDuration?: NUMt = new NumInfo('the duration of the slide in presentation view'); - presZoomText?: BOOLt = new BoolInfo('whether text anchors should shown in a larger box when following links to make them stand out'); + config_panX?: NUMt = new NumInfo('panX saved as a view spec'); + config_panY?: NUMt = new NumInfo('panY saved as a view spec'); + config_viewScale?: NUMt = new NumInfo('viewScale saved as a view Spec'); + presentation_transition?: NUMt = new NumInfo('the time taken for the transition TO a document'); + presentation_duration?: NUMt = new NumInfo('the duration of the slide in presentation view'); + presentation_zoomText?: BOOLt = new BoolInfo('whether text anchors should shown in a larger box when following links to make them stand out'); data?: any; data_useCors?: BOOLt = new BoolInfo('whether CORS protocol should be used for web page'); @@ -378,21 +378,21 @@ export class DocumentOptions { onDragStart?: ScriptField; //script to execute at start of drag operation -- e.g., when a "creator" button is dragged this script generates a different document to drop target?: Doc; // available for use in scripts. used to provide a document parameter to the script (Note, this is a convenience entry since any field could be used for parameterizing a script) - treeViewHideTitle?: BOOLt = new BoolInfo('whether to hide the top document title of a tree view'); - treeViewHideUnrendered?: BOOLt = new BoolInfo("tells tree view not to display documents that have an 'layout_unrendered' tag unless they also have a treeViewFieldKey tag (presBox)"); - treeViewHideHeaderIfTemplate?: BOOLt = new BoolInfo('whether to hide the header for a document in a tree view only if a childLayoutTemplate is provided (presBox)'); - treeViewHideHeader?: BOOLt = new BoolInfo('whether to hide the header for a document in a tree view'); - treeViewHideHeaderFields?: BOOLt = new BoolInfo('whether to hide the drop down options for tree view items.'); - treeViewChildDoubleClick?: ScriptField; // - treeViewOpenIsTransient?: BOOLt = new BoolInfo("ignores the treeViewOpen Doc flag, allowing a treeViewItem's expand/collapse state to be independent of other views of the same document in the same or any other tree view"); - treeViewOpen?: BOOLt = new BoolInfo('whether this document is expanded in a tree view'); - treeViewExpandedView?: string; // which field/thing is displayed when this item is opened in tree view - treeViewExpandedViewLock?: BOOLt = new BoolInfo('whether the expanded view can be changed'); - treeViewChecked?: ScriptField; // script to call when a tree view checkbox is checked - treeViewTruncateTitleWidth?: NUMt = new NumInfo('maximum width of a treew view title before truncation'); - treeViewHasOverlay?: BOOLt = new BoolInfo('whether the treeview has an overlay for freeform annotations'); - treeViewType?: string; // whether treeview is a Slide, file system, or (default) collection hierarchy - treeViewFreezeChildren?: STRt = new StrInfo('set (add, remove, add|remove) to disable adding, removing or both from collection'); + treeView_HideTitle?: BOOLt = new BoolInfo('whether to hide the top document title of a tree view'); + treeView_HideUnrendered?: BOOLt = new BoolInfo("tells tree view not to display documents that have an 'layout_unrendered' tag unless they also have a treeView_FieldKey tag (presBox)"); + treeView_HideHeaderIfTemplate?: BOOLt = new BoolInfo('whether to hide the header for a document in a tree view only if a childLayoutTemplate is provided (presBox)'); + treeView_HideHeader?: BOOLt = new BoolInfo('whether to hide the header for a document in a tree view'); + treeView_HideHeaderFields?: BOOLt = new BoolInfo('whether to hide the drop down options for tree view items.'); + treeView_ChildDoubleClick?: ScriptField; // + treeView_OpenIsTransient?: BOOLt = new BoolInfo("ignores the treeView_Open Doc flag, allowing a treeView_Item's expand/collapse state to be independent of other views of the same document in the same or any other tree view"); + treeView_Open?: BOOLt = new BoolInfo('whether this document is expanded in a tree view'); + treeView_ExpandedView?: string; // which field/thing is displayed when this item is opened in tree view + treeView_ExpandedViewLock?: BOOLt = new BoolInfo('whether the expanded view can be changed'); + treeView_Checked?: ScriptField; // script to call when a tree view checkbox is checked + treeView_TruncateTitleWidth?: NUMt = new NumInfo('maximum width of a treew view title before truncation'); + treeView_HasOverlay?: BOOLt = new BoolInfo('whether the treeview has an overlay for freeform annotations'); + treeView_Type?: string; // whether treeview is a Slide, file system, or (default) collection hierarchy + treeView_FreezeChildren?: STRt = new StrInfo('set (add, remove, add|remove) to disable adding, removing or both from collection'); sidebar_color?: string; // background color of text sidebar sidebar_collectionType?: string; // collection type of text sidebar @@ -635,7 +635,7 @@ export namespace Docs { DocumentType.CONFIG, { layout: { view: CollectionView, dataField: defaultDataKey }, - options: { layout_hideLinkButton: true, layout_unrendered: true }, + options: { config: '', layout_hideLinkButton: true, layout_unrendered: true }, }, ], [ @@ -679,7 +679,7 @@ export namespace Docs { DocumentType.DATAVIZ, { layout: { view: DataVizBox, dataField: defaultDataKey }, - options: { _layout_fitWidth: true, nativeDimModifiable: true }, + options: { dataViz_title: '', _layout_fitWidth: true, nativeDimModifiable: true }, }, ], [ @@ -845,7 +845,7 @@ export namespace Docs { * only when creating a DockDocument from the current user's already existing * main document. */ - function InstanceFromProto(proto: Doc, data: Field | undefined, options: DocumentOptions, delegId?: string, fieldKey: string = 'data', protoId?: string, placeholderDoc?: Doc) { + function InstanceFromProto(proto: Doc, data: Field | undefined, options: DocumentOptions, delegId?: string, fieldKey: string = 'data', protoId?: string, placeholderDoc?: Doc, noView?: boolean) { const viewKeys = ['x', 'y', 'isSystem']; // keys that should be addded to the view document even though they don't begin with an "_" const { omit: dataProps, extract: viewProps } = OmitKeys(options, viewKeys, '^_'); @@ -872,29 +872,34 @@ export namespace Docs { dataDoc.proto = proto; } - const viewFirstProps: { [id: string]: any } = { author: Doc.CurrentUserEmail }; - viewFirstProps['acl-Guest'] = options['_acl-Guest'] ?? (Doc.defaultAclPrivate ? SharingPermissions.None : SharingPermissions.View); - let viewDoc: Doc; - // determines whether viewDoc should be created using placeholder Doc or default - if (placeholderDoc) { - placeholderDoc._height = options._height !== undefined ? Number(options._height) : undefined; - placeholderDoc._width = options._width !== undefined ? Number(options._width) : undefined; - viewDoc = Doc.assign(placeholderDoc, viewFirstProps, true, true); - Array.from(Object.keys(placeholderDoc)) - .filter(key => key.startsWith('acl')) - .forEach(key => (dataDoc[key] = viewDoc[key] = placeholderDoc[key])); - } else { - viewDoc = Doc.assign(Doc.MakeDelegate(dataDoc, delegId), viewFirstProps, true, true); - } - Doc.assign(viewDoc, viewProps, true, true); - if (![DocumentType.LINK, DocumentType.CONFIG, DocumentType.LABEL].includes(viewDoc.type as any)) { - DocUtils.MakeLinkToActiveAudio(() => viewDoc); + if (!noView) { + const viewFirstProps: { [id: string]: any } = { author: Doc.CurrentUserEmail }; + viewFirstProps['acl-Guest'] = options['_acl-Guest'] ?? (Doc.defaultAclPrivate ? SharingPermissions.None : SharingPermissions.View); + let viewDoc: Doc; + // determines whether viewDoc should be created using placeholder Doc or default + if (placeholderDoc) { + placeholderDoc._height = options._height !== undefined ? Number(options._height) : undefined; + placeholderDoc._width = options._width !== undefined ? Number(options._width) : undefined; + viewDoc = Doc.assign(placeholderDoc, viewFirstProps, true, true); + Array.from(Object.keys(placeholderDoc)) + .filter(key => key.startsWith('acl')) + .forEach(key => (dataDoc[key] = viewDoc[key] = placeholderDoc[key])); + } else { + viewDoc = Doc.assign(Doc.MakeDelegate(dataDoc, delegId), viewFirstProps, true, true); + } + Doc.assign(viewDoc, viewProps, true, true); + if (![DocumentType.LINK, DocumentType.CONFIG, DocumentType.LABEL].includes(viewDoc.type as any)) { + DocUtils.MakeLinkToActiveAudio(() => viewDoc); + } + updateCachedAcls(dataDoc); + updateCachedAcls(viewDoc); + + return viewDoc; } updateCachedAcls(dataDoc); - updateCachedAcls(viewDoc); - return viewDoc; + return dataDoc; } export function ImageDocument(url: string | ImageField, options: DocumentOptions = {}, overwriteDoc?: Doc) { @@ -1065,7 +1070,7 @@ export namespace Docs { } export function ConfigDocument(options: DocumentOptions, id?: string) { - return InstanceFromProto(Prototypes.get(DocumentType.CONFIG), options?.data, options, id); + return InstanceFromProto(Prototypes.get(DocumentType.CONFIG), options?.data, options, id, '', undefined, undefined, true); } export function HTMLMarkerDocument(documents: Array, options: DocumentOptions, id?: string) { @@ -1105,7 +1110,9 @@ export namespace Docs { } export function TreeDocument(documents: Array, options: DocumentOptions, id?: string, protoId?: string) { - return InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { _xMargin: 5, _yMargin: 5, ...options, _type_collection: CollectionViewType.Tree }, id, undefined, protoId); + const doc = InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { _xMargin: 5, _yMargin: 5, ...options, _type_collection: CollectionViewType.Tree }, id, undefined, protoId); + Doc.GetProto(doc).treeView = ''; /// not really needed, but makes keyvalue pane look better + return doc; } export function StackingDocument(documents: Array, options: DocumentOptions, id?: string, protoId?: string) { @@ -1163,11 +1170,11 @@ export namespace Docs { } export function DataVizDocument(url: string, options?: DocumentOptions, overwriteDoc?: Doc) { - return InstanceFromProto(Prototypes.get(DocumentType.DATAVIZ), new CsvField(url), { title: 'Data Viz', type: 'dataviz', ...options }, undefined, undefined, undefined, overwriteDoc); + return InstanceFromProto(Prototypes.get(DocumentType.DATAVIZ), new CsvField(url), { title: 'Data Viz', type: 'dataviz', ...options }, undefined, undefined, undefined, overwriteDoc); } export function DockDocument(documents: Array, config: string, options: DocumentOptions, id?: string) { - const ret = InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { treeViewFreezeChildren: 'remove|add', ...options, type_collection: CollectionViewType.Docking, dockingConfig: config }, id); + const ret = InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { treeView_FreezeChildren: 'remove|add', ...options, type_collection: CollectionViewType.Docking, dockingConfig: config }, id); documents.map(c => Doc.SetContainer(c, ret)); return ret; } diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index 47cd866cb..af43ef16a 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -278,12 +278,12 @@ export class CurrentUserUtils { {key: "Button", creator: Docs.Create.ButtonDocument, opts: { _width: 150, _height: 50, _xPadding: 10, _yPadding: 10}, scripts: {onClick: FollowLinkScript()?.script.originalScript ?? ""}}, {key: "Script", creator: opts => Docs.Create.ScriptingDocument(null, opts), opts: { _width: 200, _height: 250, }}, {key: "DataViz", creator: opts => Docs.Create.DataVizDocument("/users/rz/Downloads/addresses.csv", opts), opts: { _width: 300, _height: 300 }}, - {key: "Header", creator: headerTemplate, opts: { _width: 300, _height: 70, _headerPointerEvents: "all", _headerHeight: 12, _headerFontSize: 9, _layout_autoHeight: true, treeViewHideUnrendered: true}}, - {key: "Trail", creator: Docs.Create.PresDocument, opts: { _width: 400, _height: 30, _type_collection: CollectionViewType.Stacking, dropAction: "embed" as dropActionType, treeViewHideTitle: true, _layout_fitWidth:true, _chromeHidden: true, layout_boxShadow: "0 0" }}, + {key: "Header", creator: headerTemplate, opts: { _width: 300, _height: 70, _headerPointerEvents: "all", _headerHeight: 12, _headerFontSize: 9, _layout_autoHeight: true, treeView_HideUnrendered: true}}, + {key: "Trail", creator: Docs.Create.PresDocument, opts: { _width: 400, _height: 30, _type_collection: CollectionViewType.Stacking, dropAction: "embed" as dropActionType, treeView_HideTitle: true, _layout_fitWidth:true, _chromeHidden: true, layout_boxShadow: "0 0" }}, {key: "Tab", creator: opts => Docs.Create.FreeformDocument([], opts), opts: { _width: 500, _height: 800, _layout_fitWidth: true, _freeform_backgroundGrid: true, }}, {key: "Slide", creator: opts => Docs.Create.TreeDocument([], opts), opts: { _width: 300, _height: 200, _type_collection: CollectionViewType.Tree, - treeViewHasOverlay: true, _text_fontSize: "20px", _layout_autoHeight: true, - dropAction:'move', treeViewType: TreeViewType.outline, + treeView_HasOverlay: true, _text_fontSize: "20px", _layout_autoHeight: true, + dropAction:'move', treeView_Type: TreeViewType.outline, backgroundColor: "white", _xMargin: 0, _yMargin: 0, _createDocOnCR: true }, funcs: {title: 'self.text?.Text'}}, ]; @@ -493,8 +493,8 @@ export class CurrentUserUtils { const childContextMenuLabels = ["Toggle Dark Theme", "Toggle Comic Mode", "Snapshot Dashboard", "Share Dashboard", "Remove Dashboard", "Reset Dashboard"];// entries must be kept in synch with childContextMenuScripts, childContextMenuIcons, and childContextMenuFilters const childContextMenuIcons = ["chalkboard", "tv", "camera", "users", "times", "trash"]; // entries must be kept in synch with childContextMenuScripts, childContextMenuLabels, and childContextMenuFilters const reqdOpts:DocumentOptions = { - title: "My Dashboards", childHideLinkButton: true, treeViewFreezeChildren: "remove|add", treeViewHideTitle: true, layout_boxShadow: "0 0", childDontRegisterViews: true, - dropAction: "same", treeViewType: TreeViewType.fileSystem, isFolder: true, isSystem: true, treeViewTruncateTitleWidth: 350, ignoreClick: true, + title: "My Dashboards", childHideLinkButton: true, treeView_FreezeChildren: "remove|add", treeView_HideTitle: true, layout_boxShadow: "0 0", childDontRegisterViews: true, + dropAction: "same", treeView_Type: TreeViewType.fileSystem, isFolder: true, isSystem: true, treeView_TruncateTitleWidth: 350, ignoreClick: true, layout_headerButton: newDashboardButton, childDragAction: "none", _layout_showTitle: "title", _height: 400, _gridGap: 5, _forceActive: true, _lockedPosition: true, contextMenuLabels:new List(contextMenuLabels), @@ -522,16 +522,16 @@ export class CurrentUserUtils { const newFolder = `TreeView_addNewFolder()`; const newFolderOpts: DocumentOptions = { - _forceActive: true, _dragOnlyWithinContainer: true, _layout_hideContextMenu: true, _width: 30, _height: 30, undoIgnoreFields:new List(['treeViewSortCriterion']), + _forceActive: true, _dragOnlyWithinContainer: true, _layout_hideContextMenu: true, _width: 30, _height: 30, undoIgnoreFields:new List(['treeView_SortCriterion']), title: "New folder", color: Colors.BLACK, btnType: ButtonType.ClickButton, toolTip: "Create new folder", buttonText: "New folder", icon: "folder-plus", isSystem: true }; const newFolderScript = { onClick: newFolder}; const newFolderButton = DocUtils.AssignScripts(DocUtils.AssignOpts(DocCast(myFilesystem?.layout_headerButton), newFolderOpts) ?? Docs.Create.FontIconDocument(newFolderOpts), newFolderScript); const reqdOpts:DocumentOptions = { _layout_showTitle: "title", _height: 100, _gridGap: 5, _forceActive: true, _lockedPosition: true, - title: "My Documents", layout_headerButton: newFolderButton, treeViewHideTitle: true, dropAction: 'add', isSystem: true, - isFolder: true, treeViewType: TreeViewType.fileSystem, childHideLinkButton: true, layout_boxShadow: "0 0", childDontRegisterViews: true, - treeViewTruncateTitleWidth: 350, ignoreClick: true, childDragAction: "embed", + title: "My Documents", layout_headerButton: newFolderButton, treeView_HideTitle: true, dropAction: 'add', isSystem: true, + isFolder: true, treeView_Type: TreeViewType.fileSystem, childHideLinkButton: true, layout_boxShadow: "0 0", childDontRegisterViews: true, + treeView_TruncateTitleWidth: 350, ignoreClick: true, childDragAction: "embed", childContextMenuLabels: new List(["Create new folder"]), childContextMenuIcons: new List(["plus"]), layout_explainer: "This is your file manager where you can create folders to keep track of documents independently of your dashboard." @@ -548,8 +548,8 @@ export class CurrentUserUtils { /// initializes the panel displaying docs that have been recently closed static setupRecentlyClosed(doc: Doc, field:string) { const reqdOpts:DocumentOptions = { _layout_showTitle: "title", _lockedPosition: true, _gridGap: 5, _forceActive: true, isFolder: true, - title: "My Recently Closed", childHideLinkButton: true, treeViewHideTitle: true, childDragAction: "move", isSystem: true, - treeViewTruncateTitleWidth: 350, ignoreClick: true, layout_boxShadow: "0 0", childDontRegisterViews: true, dropAction: "same", + title: "My Recently Closed", childHideLinkButton: true, treeView_HideTitle: true, childDragAction: "move", isSystem: true, + treeView_TruncateTitleWidth: 350, ignoreClick: true, layout_boxShadow: "0 0", childDontRegisterViews: true, dropAction: "same", contextMenuLabels: new List(["Empty recently closed"]), contextMenuIcons:new List(["trash"]), layout_explainer: "Recently closed documents appear in this menu. They will only be deleted if you explicity empty this list." @@ -573,9 +573,9 @@ export class CurrentUserUtils { const reqdOpts:DocumentOptions = { _lockedPosition: true, _gridGap: 5, _forceActive: true, title: Doc.CurrentUserEmail +"-view", layout_boxShadow: "0 0", childDontRegisterViews: true, dropAction: "same", ignoreClick: true, isSystem: true, - treeViewHideTitle: true, treeViewTruncateTitleWidth: 350 + treeView_HideTitle: true, treeView_TruncateTitleWidth: 350 }; - if (!doc[field]) DocUtils.AssignOpts(doc, {treeViewOpen: true, treeViewExpandedView: "fields" }); + if (!doc[field]) DocUtils.AssignOpts(doc, {treeView_Open: true, treeView_ExpandedView: "fields" }); return DocUtils.AssignDocField(doc, field, (opts, items) => Docs.Create.TreeDocument(items??[], opts), reqdOpts, [doc]); } @@ -789,19 +789,19 @@ export class CurrentUserUtils { static setupSharedDocs(doc: Doc, sharingDocumentId: string) { const dblClkScript = "{scriptContext.openLevel(documentView); addDocToList(scriptContext.props.treeView.props.Document, 'viewed', documentView.rootDoc);}"; - const sharedScripts = { treeViewChildDoubleClick: dblClkScript, } + const sharedScripts = { treeView_ChildDoubleClick: dblClkScript, } const sharedDocOpts:DocumentOptions = { title: "My Shared Docs", userColor: "rgb(202, 202, 202)", - isFolder:true, undoIgnoreFields:new List(['treeViewSortCriterion']), + isFolder:true, undoIgnoreFields:new List(['treeView_SortCriterion']), // childContextMenuFilters: new List([dashboardFilter!,]), // childContextMenuScripts: new List([addToDashboards!,]), // childContextMenuLabels: new List(["Add to Dashboards",]), // childContextMenuIcons: new List(["user-plus",]), "acl-Guest": SharingPermissions.Augment, "_acl-Guest": SharingPermissions.Augment, childDragAction: "embed", isSystem: true, contentPointerEvents: "all", childLimitHeight: 0, _yMargin: 0, _gridGap: 15, childDontRegisterViews:true, - // NOTE: treeViewHideTitle & _layout_showTitle is for a TreeView's editable title, _layout_showTitle is for DocumentViews title bar - _layout_showTitle: "title", treeViewHideTitle: true, ignoreClick: true, _lockedPosition: true, layout_boxShadow: "0 0", _chromeHidden: true, dontRegisterView: true, + // NOTE: treeView_HideTitle & _layout_showTitle is for a TreeView's editable title, _layout_showTitle is for DocumentViews title bar + _layout_showTitle: "title", treeView_HideTitle: true, ignoreClick: true, _lockedPosition: true, layout_boxShadow: "0 0", _chromeHidden: true, dontRegisterView: true, layout_explainer: "This is where documents or dashboards that other users have shared with you will appear. To share a document or dashboard right click and select 'Share'" }; @@ -864,7 +864,7 @@ export class CurrentUserUtils { doc.userColor ?? (doc.userColor = Colors.LIGHT_GRAY); doc.userTheme ?? (doc.userTheme = ColorScheme.Dark); doc.filterDocCount = 0; - doc.treeViewFreezeChildren = "remove|add"; + doc.treeView_FreezeChildren = "remove|add"; doc.activePage = doc.activeDashboard === undefined ? 'home': doc.activePage; this.setupLinkDocs(doc, linkDatabaseId); this.setupSharedDocs(doc, sharingDocumentId); // sets up the right sidebar collection for mobile upload documents and sharing diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts index 42132c2d7..9779639f4 100644 --- a/src/client/util/DocumentManager.ts +++ b/src/client/util/DocumentManager.ts @@ -315,10 +315,10 @@ export class DocumentManager { if (options.toggleTarget && (!options.didMove || docView.rootDoc.hidden)) docView.rootDoc.hidden = !docView.rootDoc.hidden; if (options.effect) docView.rootDoc[Animation] = options.effect; - if (options.zoomTextSelections && Doc.UnhighlightTimer && contextView && viewSpec.textHtml) { + if (options.zoomTextSelections && Doc.UnhighlightTimer && contextView && viewSpec.text_html) { // if the docView is a text anchor, the contextView is the PDF/Web/Text doc - contextView.htmlOverlayEffect = StrCast(options?.effect?.presEffect, StrCast(options?.effect?.followLinkAnimEffect)); - contextView.textHtmlOverlay = StrCast(targetDoc.textHtml); + contextView.htmlOverlayEffect = StrCast(options?.effect?.presentation_effect, StrCast(options?.effect?.followLinkAnimEffect)); + contextView.textHtmlOverlay = StrCast(targetDoc.text_html); DocumentManager._overlayViews.add(contextView); } Doc.AddUnHighlightWatcher(() => { diff --git a/src/client/views/DashboardView.tsx b/src/client/views/DashboardView.tsx index 21808d6e0..3e4827c83 100644 --- a/src/client/views/DashboardView.tsx +++ b/src/client/views/DashboardView.tsx @@ -108,7 +108,14 @@ export class DashboardView extends React.Component { }}>
Create New Dashboard
this.setNewDashboardName(val as string)} fillWidth /> - +
{!selectedItem ? null : ( -
-
(this.openPresTransitions = !this.openPresTransitions))} style={{ backgroundColor: this.openPresTransitions ? 'black' : '' }}> +
+
(this.openPresTransitions = !this.openPresTransitions))} style={{ backgroundColor: this.openPresTransitions ? 'black' : '' }}>     Transitions -
+
- {this.openPresTransitions ?
{PresBox.Instance.transitionDropdown}
: null} + {this.openPresTransitions ?
{PresBox.Instance.transitionDropdown}
: null}
)} {!selectedItem ? null : ( -
+
(this.openPresVisibilityAndDuration = !this.openPresVisibilityAndDuration))} style={{ backgroundColor: this.openPresTransitions ? 'black' : '' }}>     Visibilty -
+
- {this.openPresVisibilityAndDuration ?
{PresBox.Instance.visibiltyDurationDropdown}
: null} + {this.openPresVisibilityAndDuration ?
{PresBox.Instance.visibiltyDurationDropdown}
: null}
)} {!selectedItem ? null : ( -
-
(this.openPresProgressivize = !this.openPresProgressivize))} style={{ backgroundColor: this.openPresTransitions ? 'black' : '' }}> +
+
(this.openPresProgressivize = !this.openPresProgressivize))} style={{ backgroundColor: this.openPresTransitions ? 'black' : '' }}>     Progressivize -
+
- {this.openPresProgressivize ?
{PresBox.Instance.progressivizeDropdown}
: null} + {this.openPresProgressivize ?
{PresBox.Instance.progressivizeDropdown}
: null}
)} {!selectedItem || (type !== DocumentType.VID && type !== DocumentType.AUDIO) ? null : ( -
-
(this.openSlideOptions = !this.openSlideOptions))} style={{ backgroundColor: this.openSlideOptions ? 'black' : '' }}> +
+
(this.openSlideOptions = !this.openSlideOptions))} style={{ backgroundColor: this.openSlideOptions ? 'black' : '' }}>     {type === DocumentType.AUDIO ? 'Audio Options' : 'Video Options'} -
+
- {this.openSlideOptions ?
{PresBox.Instance.mediaOptionsDropdown}
: null} + {this.openSlideOptions ?
{PresBox.Instance.mediaOptionsDropdown}
: null}
)}
diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx index 63ff348e3..a757a0715 100644 --- a/src/client/views/StyleProvider.tsx +++ b/src/client/views/StyleProvider.tsx @@ -27,8 +27,8 @@ import './StyleProvider.scss'; import React = require('react'); export enum StyleProp { - TreeViewIcon = 'treeViewIcon', - TreeViewSortings = 'treeViewSortings', // options for how to sort tree view items + TreeViewIcon = 'treeView_Icon', + TreeViewSortings = 'treeView_Sortings', // options for how to sort tree view items DocContents = 'docContents', // when specified, the JSX returned will replace the normal rendering of the document view Opacity = 'opacity', // opacity of the document view BoxShadow = 'boxShadow', // box shadow - used for making collections standout and for showing clusters in free form views @@ -133,7 +133,7 @@ export function DefaultStyleProvider(doc: Opt, props: Opt, props: Opt { const templateMenu: Array = []; this.props.templates?.forEach((checked, template) => templateMenu.push()); templateMenu.push(); - addedTypes.concat(noteTypes).map(template => (template.treeViewChecked = this.templateIsUsed(firstDoc, template))); + addedTypes.concat(noteTypes).map(template => (template.treeView_Checked = this.templateIsUsed(firstDoc, template))); this._addedKeys && Array.from(this._addedKeys) .filter(key => !noteTypes.some(nt => nt.title === key)) diff --git a/src/client/views/collections/CollectionTimeView.tsx b/src/client/views/collections/CollectionTimeView.tsx index 192d48c64..a8f5345b7 100644 --- a/src/client/views/collections/CollectionTimeView.tsx +++ b/src/client/views/collections/CollectionTimeView.tsx @@ -65,9 +65,9 @@ export class CollectionTimeView extends CollectionSubView() { @action scrollPreview = (docView: DocumentView, anchor: Doc, focusSpeed: number, options: DocFocusOptions) => { // if in preview, then override document's fields with view spec - this._focusFilters = StrListCast(anchor.presDocFilters); - this._focusRangeFilters = StrListCast(anchor.presPinDocRangeFilters); - this._focusPivotField = StrCast(anchor.presPivotField); + this._focusFilters = StrListCast(anchor.config_docFilters); + this._focusRangeFilters = StrListCast(anchor.config_docRangeFilters); + this._focusPivotField = StrCast(anchor.config_pivotField); return undefined; }; diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index ea3b5065f..b5c7d3f5d 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -66,17 +66,17 @@ export class CollectionTreeView extends CollectionSubView (this.doc.treeViewOpenIsTransient = !this.doc.treeViewOpenIsTransient), icon: 'paint-brush' }); - layoutItems.push({ description: (this.doc.treeViewHideHeaderFields ? 'Show' : 'Hide') + ' Header Fields', event: () => (this.doc.treeViewHideHeaderFields = !this.doc.treeViewHideHeaderFields), icon: 'paint-brush' }); - layoutItems.push({ description: (this.doc.treeViewHideTitle ? 'Show' : 'Hide') + ' Title', event: () => (this.doc.treeViewHideTitle = !this.doc.treeViewHideTitle), icon: 'paint-brush' }); + layoutItems.push({ description: 'Make tree state ' + (this.doc.treeView_OpenIsTransient ? 'persistent' : 'transient'), event: () => (this.doc.treeView_OpenIsTransient = !this.doc.treeView_OpenIsTransient), icon: 'paint-brush' }); + layoutItems.push({ description: (this.doc.treeView_HideHeaderFields ? 'Show' : 'Hide') + ' Header Fields', event: () => (this.doc.treeView_HideHeaderFields = !this.doc.treeView_HideHeaderFields), icon: 'paint-brush' }); + layoutItems.push({ description: (this.doc.treeView_HideTitle ? 'Show' : 'Hide') + ' Title', event: () => (this.doc.treeView_HideTitle = !this.doc.treeView_HideTitle), icon: 'paint-brush' }); ContextMenu.Instance.addItem({ description: 'Options...', subitems: layoutItems, icon: 'eye' }); const existingOnClick = ContextMenu.Instance.findByDescription('OnClick...'); const onClicks: ContextMenuProps[] = existingOnClick && 'subitems' in existingOnClick ? existingOnClick.subitems : []; @@ -215,7 +215,7 @@ export class CollectionTreeView extends CollectionSubView StrCast(this.dataDoc.title)} SetValue={undoBatch((value: string, shift: boolean, enter: boolean) => { - if (enter && this.props.Document.treeViewType === TreeViewType.outline) this.makeTextCollection(this.treeChildren); + if (enter && this.props.Document.treeView_Type === TreeViewType.outline) this.makeTextCollection(this.treeChildren); this.dataDoc.title = value; return true; })} @@ -261,7 +261,7 @@ export class CollectionTreeView extends CollectionSubView ({ script: customScripts[i], filter: customFilters[i], icon: icons[i], label })); }; - headerFields = () => this.props.treeViewHideHeaderFields || BoolCast(this.doc.treeViewHideHeaderFields); + headerFields = () => this.props.treeViewHideHeaderFields || BoolCast(this.doc.treeView_HideHeaderFields); @observable _renderCount = 1; @computed get treeViewElements() { TraceMobx(); @@ -389,7 +389,7 @@ export class CollectionTreeView extends CollectionSubView this.props.styleProvider?.(this.doc, this.props, StyleProp.BackgroundColor); const color = () => this.props.styleProvider?.(this.doc, this.props, StyleProp.Color); const pointerEvents = () => (this.props.isContentActive() === false ? 'none' : undefined); - const titleBar = this.props.treeViewHideTitle || this.doc.treeViewHideTitle ? null : this.titleBar; + const titleBar = this.props.treeViewHideTitle || this.doc.treeView_HideTitle ? null : this.titleBar; return (
{!this.buttonMenu && !this.noviceExplainer ? null : ( @@ -401,7 +401,7 @@ export class CollectionTreeView extends CollectionSubView !this.doc.treeViewHasOverlay && r && this.createTreeDropTarget(r)} + ref={r => !this.doc.treeView_HasOverlay && r && this.createTreeDropTarget(r)} style={{ ...(!titleBar ? { marginLeft: this.marginX(), paddingTop: this.marginTop() } : {}), color: color(), @@ -440,7 +440,7 @@ export class CollectionTreeView extends CollectionSubView - {!(this.doc instanceof Doc) || !this.treeChildren ? null : this.doc.treeViewHasOverlay ? ( + {!(this.doc instanceof Doc) || !this.treeChildren ? null : this.doc.treeView_HasOverlay ? ( string; setPreviewCursor?: (func: (x: number, y: number, drag: boolean, hide: boolean) => void) => void; - setBrushViewer?: (func?: (view: { width: number; height: number; panX: number; panY: number }) => void) => void; + setBrushViewer?: (func?: (view: { width: number; height: number; panX: number; panY: number }, transTime: number) => void) => void; ignoreUnrendered?: boolean; // property overrides for child documents diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx index d787f5262..ea473d5cf 100644 --- a/src/client/views/collections/TabDocView.tsx +++ b/src/client/views/collections/TabDocView.tsx @@ -256,46 +256,47 @@ export class TabDocView extends React.Component { return; } const anchorDoc = DocumentManager.Instance.getDocumentView(doc)?.ComponentView?.getAnchor?.(false, pinProps); - const pinDoc = Doc.MakeDelegate(anchorDoc && anchorDoc !== doc ? anchorDoc : doc); - pinDoc.presentationTargetDoc = anchorDoc ?? doc; + const pinDoc = anchorDoc?.type === DocumentType.CONFIG ? anchorDoc : Doc.MakeDelegate(anchorDoc && anchorDoc !== doc ? anchorDoc : doc); + pinDoc.presentation_targetDoc = anchorDoc ?? doc; pinDoc.title = doc.title + ' - Slide'; pinDoc.data = new List(); // the children of the embedding's layout are the presentation slide children. the embedding's data field might be children of a collection, PDF data, etc -- in any case we don't want the tree view to "see" this data - pinDoc.presMovement = doc.type === DocumentType.SCRIPTING || pinProps?.pinDocLayout ? PresMovement.None : PresMovement.Zoom; - pinDoc.presDuration = pinDoc.presDuration ?? 1000; - pinDoc.groupWithUp = false; + pinDoc.presentation_movement = doc.type === DocumentType.SCRIPTING || pinProps?.pinDocLayout ? PresMovement.None : PresMovement.Zoom; + pinDoc.presentation_duration = pinDoc.presentation_duration ?? 1000; + pinDoc.presentation_groupWithUp = false; Doc.SetContainer(pinDoc, curPres); // these should potentially all be props passed down by the CollectionTreeView to the TreeView elements. That way the PresBox could configure all of its children at render time - pinDoc.treeViewRenderAsBulletHeader = true; // forces a tree view to render the document next to the bullet in the header area - pinDoc.treeViewHeaderWidth = '100%'; // forces the header to grow to be the same size as its largest sibling. - pinDoc.treeViewChildrenOnRoot = true; // tree view will look for hierarchical children on the root doc, not the data doc. - pinDoc.treeViewFieldKey = 'data'; // tree view will treat the 'data' field as the field where the hierarchical children are located instead of using the document's layout string field - pinDoc.treeViewExpandedView = 'data'; // in case the data doc has an expandedView set, this will mask that field and use the 'data' field when expanding the tree view - pinDoc.treeViewHideHeaderIfTemplate = true; // this will force the document to render itself as the tree view header + pinDoc.treeView = ''; // not really needed, but makes key value pane look better + pinDoc.treeView_RenderAsBulletHeader = true; // forces a tree view to render the document next to the bullet in the header area + pinDoc.treeView_HeaderWidth = '100%'; // forces the header to grow to be the same size as its largest sibling. + pinDoc.treeView_ChildrenOnRoot = true; // tree view will look for hierarchical children on the root doc, not the data doc. + pinDoc.treeView_FieldKey = 'data'; // tree view will treat the 'data' field as the field where the hierarchical children are located instead of using the document's layout string field + pinDoc.treeView_ExpandedView = 'data'; // in case the data doc has an expandedView set, this will mask that field and use the 'data' field when expanding the tree view + pinDoc.treeView_HideHeaderIfTemplate = true; // this will force the document to render itself as the tree view header const duration = NumCast(doc[`${Doc.LayoutFieldKey(pinDoc)}_duration`], null); if (pinProps.pinViewport) PresBox.pinDocView(pinDoc, pinProps, anchorDoc ?? doc); if (!pinProps?.audioRange && duration !== undefined) { pinDoc.mediaStart = 'manual'; pinDoc.mediaStop = 'manual'; - pinDoc.presStartTime = NumCast(doc.clipStart); - pinDoc.presEndTime = NumCast(doc.clipEnd, duration); + pinDoc.config_clipStart = NumCast(doc.clipStart); + pinDoc.config_clipEnd = NumCast(doc.clipEnd, duration); } if (pinProps?.activeFrame !== undefined) { - pinDoc.presActiveFrame = pinProps?.activeFrame; + pinDoc.config_activeFrame = pinProps?.activeFrame; pinDoc.title = doc.title + ' (move)'; - pinDoc.presMovement = PresMovement.Pan; + pinDoc.presentation_movement = PresMovement.Pan; } if (pinProps?.currentFrame !== undefined) { - pinDoc.presCurrentFrame = pinProps?.currentFrame; + pinDoc.config_currentFrame = pinProps?.currentFrame; pinDoc.title = doc.title + ' (move)'; - pinDoc.presMovement = PresMovement.Pan; + pinDoc.presentation_movement = PresMovement.Pan; } if (pinDoc.stroke_isInkMask) { - pinDoc.presHideAfter = true; - pinDoc.presHideBefore = true; - pinDoc.presMovement = PresMovement.None; + pinDoc.presentation_hideAfter = true; + pinDoc.presentation_hideBefore = true; + pinDoc.presentation_movement = PresMovement.None; } - if (curPres.expandBoolean) pinDoc.presExpandInlineButton = true; + if (curPres.expandBoolean) pinDoc.presentation_expandInlineButton = true; Doc.AddDocToList(curPres, 'data', pinDoc, PresBox.Instance?.sortArray()?.lastElement()); PresBox.Instance?.clearSelectedArray(); pinDoc && PresBox.Instance?.addToSelectedArray(pinDoc); //Update selected array @@ -393,7 +394,7 @@ export class TabDocView extends React.Component { }; getCurrentFrame = () => { - return NumCast(Cast(PresBox.Instance.activeItem.presentationTargetDoc, Doc, null)._currentFrame); + return NumCast(Cast(PresBox.Instance.activeItem.presentation_targetDoc, Doc, null)._currentFrame); }; static Activate = (tabDoc: Doc) => { const tab = Array.from(CollectionDockingView.Instance?.tabMap!).find(tab => tab.DashDoc === tabDoc && !tab.contentItem.config.props.keyValue); diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx index 25a547066..27f9ebc49 100644 --- a/src/client/views/collections/TreeView.tsx +++ b/src/client/views/collections/TreeView.tsx @@ -87,8 +87,8 @@ export enum TreeSort { * Renders a treeView of a collection of documents * * special fields: - * treeViewOpen : flag denoting whether the documents sub-tree (contents) is visible or hidden - * treeViewExpandedView : name of field whose contents are being displayed as the document's subtree + * treeView_Open : flag denoting whether the documents sub-tree (contents) is visible or hidden + * treeView_ExpandedView : name of field whose contents are being displayed as the document's subtree */ @observer export class TreeView extends React.Component { @@ -104,16 +104,16 @@ export class TreeView extends React.Component { private _treedropDisposer?: DragManager.DragDropDisposer; get treeViewOpenIsTransient() { - return this.props.treeView.doc.treeViewOpenIsTransient || Doc.IsDataProto(this.doc); + return this.props.treeView.doc.treeView_OpenIsTransient || Doc.IsDataProto(this.doc); } set treeViewOpen(c: boolean) { if (this.treeViewOpenIsTransient) this._transientOpenState = c; else { - this.doc.treeViewOpen = c; + this.doc.treeView_Open = c; this._transientOpenState = false; } } - @observable _transientOpenState = false; // override of the treeViewOpen field allowing the display state to be independent of the document's state + @observable _transientOpenState = false; // override of the treeView_Open field allowing the display state to be independent of the document's state @observable _editTitle: boolean = false; @observable _dref: DocumentView | undefined | null; get displayName() { @@ -132,29 +132,29 @@ export class TreeView extends React.Component { ? this.fieldKey : Doc.noviceMode ? 'layout' - : StrCast(this.props.treeView.doc.treeViewExpandedView, 'fields'); + : StrCast(this.props.treeView.doc.treeView_ExpandedView, 'fields'); } @computed get doc() { return this.props.document; } @computed get treeViewOpen() { - return (!this.treeViewOpenIsTransient && Doc.GetT(this.doc, 'treeViewOpen', 'boolean', true)) || this._transientOpenState; + return (!this.treeViewOpenIsTransient && Doc.GetT(this.doc, 'treeView_Open', 'boolean', true)) || this._transientOpenState; } @computed get treeViewExpandedView() { - return this.validExpandViewTypes.includes(StrCast(this.doc.treeViewExpandedView)) ? StrCast(this.doc.treeViewExpandedView) : this.defaultExpandedView; + return this.validExpandViewTypes.includes(StrCast(this.doc.treeView_ExpandedView)) ? StrCast(this.doc.treeView_ExpandedView) : this.defaultExpandedView; } @computed get MAX_EMBED_HEIGHT() { return NumCast(this.props.treeViewParent.maxEmbedHeight, 200); } @computed get dataDoc() { - return this.props.document.treeViewChildrenOnRoot ? this.doc : this.doc[DocData]; + return this.props.document.treeView_ChildrenOnRoot ? this.doc : this.doc[DocData]; } @computed get layoutDoc() { return Doc.Layout(this.doc); } @computed get fieldKey() { - return StrCast(this.doc._treeViewFieldKey, Doc.LayoutFieldKey(this.doc)); + return StrCast(this.doc._treeView_FieldKey, Doc.LayoutFieldKey(this.doc)); } @computed get childDocs() { return this.childDocList(this.fieldKey); @@ -308,13 +308,13 @@ export class TreeView extends React.Component { const bullet = Docs.Create.TextDocument('', { layout: CollectionView.LayoutString('data'), title: '-title-', - treeViewExpandedViewLock: true, - treeViewExpandedView: 'data', + treeView_ExpandedViewLock: true, + treeView_ExpandedView: 'data', _type_collection: CollectionViewType.Tree, layout_hideLinkButton: true, _layout_showSidebar: true, _layout_fitWidth: true, - treeViewType: TreeViewType.outline, + treeView_Type: TreeViewType.outline, x: 0, y: 0, _xMargin: 0, @@ -395,7 +395,7 @@ export class TreeView extends React.Component { }; const addDoc = inside ? localAdd : parentAddDoc; const move = (!dropAction || dropAction === 'proto' || dropAction === 'move' || dropAction === 'same') && moveDocument; - const canAdd = (!this.props.treeView.outlineMode && !StrCast((inside ? this.props.document : this.props.treeViewParent)?.treeViewFreezeChildren).includes('add')) || forceAdd; + const canAdd = (!this.props.treeView.outlineMode && !StrCast((inside ? this.props.document : this.props.treeViewParent)?.treeView_FreezeChildren).includes('add')) || forceAdd; if (canAdd) { this.props.parentTreeView instanceof TreeView && (this.props.parentTreeView.dropping = true); const res = droppedDocuments.reduce((added, d) => (move ? move(d, undefined, addDoc) || (dropAction === 'proto' ? addDoc(d) : false) : addDoc(d)) || added, false); @@ -438,7 +438,7 @@ export class TreeView extends React.Component { doc && Object.keys(doc).forEach(key => !(key in ids) && doc[key] !== ComputedField.undefined && (ids[key] = key)); for (const key of Object.keys(ids).slice().sort()) { - if (this.props.skipFields?.includes(key) || key === 'title' || key === 'treeViewOpen') continue; + if (this.props.skipFields?.includes(key) || key === 'title' || key === 'treeView_Open') continue; const contents = doc[key]; let contentElement: (JSX.Element | null)[] | JSX.Element = []; @@ -538,7 +538,7 @@ export class TreeView extends React.Component { const expandKey = this.treeViewExpandedView; const sortings = (this.props.styleProvider?.(this.doc, this.props.treeView.props, StyleProp.TreeViewSortings) as { [key: string]: { color: string; icon: JSX.Element | string } }) ?? {}; if (['links', 'annotations', 'embeddings', this.fieldKey].includes(expandKey)) { - const sorting = StrCast(this.doc.treeViewSortCriterion, TreeSort.None); + const sorting = StrCast(this.doc.treeView_SortCriterion, TreeSort.None); const sortKeys = Object.keys(sortings); const curSortIndex = Math.max( 0, @@ -550,7 +550,7 @@ export class TreeView extends React.Component { const localAdd = (doc: Doc, addBefore?: Doc, before?: boolean) => { // if there's a sort ordering specified that can be modified on drop (eg, zorder can be modified, alphabetical can't), // then the modification would be done here - const ordering = StrCast(this.doc.treeViewSortCriterion); + const ordering = StrCast(this.doc.treeView_SortCriterion); if (ordering === TreeSort.Zindex) { const docs = TreeView.sortDocs(this.childDocs || ([] as Doc[]), ordering); doc.zIndex = addBefore ? NumCast(addBefore.zIndex) + (before ? -0.5 : 0.5) : 1000; @@ -590,7 +590,7 @@ export class TreeView extends React.Component { }} onClick={undoable(e => { if (this.props.isContentActive() && Math.abs(e.clientX - downX) < 3 && Math.abs(e.clientY - downY) < 3) { - !this.props.treeView.outlineMode && (this.doc.treeViewSortCriterion = sortKeys[(curSortIndex + 1) % sortKeys.length]); + !this.props.treeView.outlineMode && (this.doc.treeView_SortCriterion = sortKeys[(curSortIndex + 1) % sortKeys.length]); e.stopPropagation(); } }, 'sort order')} @@ -601,7 +601,7 @@ export class TreeView extends React.Component { style={{ cursor: 'inherit' }} key={expandKey + 'more'} title="click to change sort order" - className={''} //this.doc.treeViewHideTitle ? 'no-indent' : ''} + className={''} //this.doc.treeView_HideTitle ? 'no-indent' : ''} onPointerDown={e => { downX = e.clientX; downY = e.clientY; @@ -609,7 +609,7 @@ export class TreeView extends React.Component { }} onClick={undoable(e => { if (this.props.isContentActive() && Math.abs(e.clientX - downX) < 3 && Math.abs(e.clientY - downY) < 3) { - !this.props.treeView.outlineMode && (this.doc.treeViewSortCriterion = sortKeys[(curSortIndex + 1) % sortKeys.length]); + !this.props.treeView.outlineMode && (this.doc.treeView_SortCriterion = sortKeys[(curSortIndex + 1) % sortKeys.length]); e.stopPropagation(); } }, 'sort order')}> @@ -683,7 +683,7 @@ export class TreeView extends React.Component { { this: this.doc.isTemplateForField && this.props.dataDoc ? this.props.dataDoc : this.doc, heading: this.props.treeViewParent.title, - checked: this.doc.treeViewChecked === 'check' ? 'x' : this.doc.treeViewChecked === 'x' ? 'remove' : 'check', + checked: this.doc.treeView_Checked === 'check' ? 'x' : this.doc.treeView_Checked === 'x' ? 'remove' : 'check', containingTreeView: this.props.treeView.props.Document, }, console.log @@ -698,7 +698,7 @@ export class TreeView extends React.Component { TraceMobx(); const iconType = this.props.treeView.props.styleProvider?.(this.doc, this.props.treeView.props, StyleProp.TreeViewIcon + (this.treeViewOpen ? ':open' : !this.childDocs.length ? ':empty' : '')) || 'question'; const color = StrCast(Doc.UserDoc().userColor); - const checked = this.onCheckedClick ? this.doc.treeViewChecked ?? 'unchecked' : undefined; + const checked = this.onCheckedClick ? this.doc.treeView_Checked ?? 'unchecked' : undefined; return (
{ } @action expandNextviewType = () => { - if (this.treeViewOpen && !this.doc.isFolder && !this.props.treeView.outlineMode && !this.doc.treeViewExpandedViewLock) { + if (this.treeViewOpen && !this.doc.isFolder && !this.props.treeView.outlineMode && !this.doc.treeView_ExpandedViewLock) { const next = (modes: any[]) => modes[(modes.indexOf(StrCast(this.treeViewExpandedView)) + 1) % modes.length]; - this.doc.treeViewExpandedView = next(this.validExpandViewTypes); + this.doc.treeView_ExpandedView = next(this.validExpandViewTypes); } this.treeViewOpen = true; }; @@ -759,7 +759,7 @@ export class TreeView extends React.Component { @computed get titleButtons() { const customHeaderButtons = this.props.styleProvider?.(this.doc, this.props.treeView.props, StyleProp.Decorations); const color = StrCast(Doc.UserDoc().userColor); - return this.props.treeViewHideHeaderFields() || this.doc.treeViewHideHeaderFields ? null : ( + return this.props.treeViewHideHeaderFields() || this.doc.treeView_HideHeaderFields ? null : ( <> {customHeaderButtons} {/* e.g.,. hide button is set by dashboardStyleProvider */} { e.stopPropagation(); }} /> - {Doc.noviceMode ? null : this.doc.treeViewExpandedViewLock || Doc.IsSystem(this.doc) ? null : ( + {Doc.noviceMode ? null : this.doc.treeView_ExpandedViewLock || Doc.IsSystem(this.doc) ? null : ( {this.treeViewExpandedView} @@ -815,7 +815,7 @@ export class TreeView extends React.Component { onChildClick = () => this.props.onChildClick?.() ?? (this._editTitleScript?.() || ScriptField.MakeFunction(`DocFocusOrOpen(self)`)!); - onChildDoubleClick = () => ScriptCast(this.props.treeView.Document.treeViewChildDoubleClick, !this.props.treeView.outlineMode ? this._openScript?.() : null); + onChildDoubleClick = () => ScriptCast(this.props.treeView.Document.treeView_ChildDoubleClick, !this.props.treeView.outlineMode ? this._openScript?.() : null); refocus = () => this.props.treeView.props.focus(this.props.treeView.props.Document, {}); ignoreEvent = (e: any) => { @@ -861,7 +861,7 @@ export class TreeView extends React.Component { return this.props?.treeView?.props.styleProvider?.(doc, props, property); // properties are inherited from the CollectionTreeView, not the hierarchical parent in the treeView }; onKeyDown = (e: React.KeyboardEvent, fieldProps: FieldViewProps) => { - if (this.doc.treeViewHideHeader || (this.doc.treeViewHideHeaderIfTemplate && this.props.treeView.props.childLayoutTemplate?.()) || this.props.treeView.outlineMode) { + if (this.doc.treeView_HideHeader || (this.doc.treeView_HideHeaderIfTemplate && this.props.treeView.props.childLayoutTemplate?.()) || this.props.treeView.outlineMode) { switch (e.key) { case 'Tab': e.stopPropagation?.(); @@ -1068,7 +1068,7 @@ export class TreeView extends React.Component { // renders the text version of a document as the header. This is used in the file system mode and in other vanilla tree views. @computed get renderTitleAsHeader() { - return this.props.treeView.Document.treeViewHideUnrendered && this.doc.layout_unrendered && !this.doc.treeViewFieldKey ? ( + return this.props.treeView.Document.treeView_HideUnrendered && this.doc.layout_unrendered && !this.doc.treeView_FieldKey ? (
) : ( <> @@ -1089,7 +1089,7 @@ export class TreeView extends React.Component { }; @computed get renderBorder() { - const sorting = StrCast(this.doc.treeViewSortCriterion, TreeSort.None); + const sorting = StrCast(this.doc.treeView_SortCriterion, TreeSort.None); const sortings = (this.props.styleProvider?.(this.doc, this.props.treeView.props, StyleProp.TreeViewSortings) ?? {}) as { [key: string]: { color: string; label: string } }; return (
@@ -1109,7 +1109,7 @@ export class TreeView extends React.Component { render() { TraceMobx(); - const hideTitle = this.doc.treeViewHideHeader || (this.doc.treeViewHideHeaderIfTemplate && this.props.treeView.props.childLayoutTemplate?.()) || this.props.treeView.outlineMode; + const hideTitle = this.doc.treeView_HideHeader || (this.doc.treeView_HideHeaderIfTemplate && this.props.treeView.props.childLayoutTemplate?.()) || this.props.treeView.outlineMode; return this.props.renderedIds?.indexOf(this.doc[Id]) !== -1 ? ( '<' + this.doc.title + '>' // just print the title of documents we've previously rendered in this hierarchical path to avoid cycles ) : ( @@ -1121,9 +1121,9 @@ export class TreeView extends React.Component { // onKeyDown={this.onKeyDown} >
  • - {hideTitle && this.doc.type !== DocumentType.RTF && !this.doc.treeViewRenderAsBulletHeader // should test for prop 'treeViewRenderDocWithBulletAsHeader" + {hideTitle && this.doc.type !== DocumentType.RTF && !this.doc.treeView_RenderAsBulletHeader // should test for prop 'treeView_RenderDocWithBulletAsHeader" ? this.renderEmbeddedDocument(false, returnFalse) - : this.renderBulletHeader(hideTitle ? this.renderDocumentAsHeader(!this.doc.treeViewRenderAsBulletHeader) : this.renderTitleAsHeader, this._editTitle)} + : this.renderBulletHeader(hideTitle ? this.renderDocumentAsHeader(!this.doc.treeView_RenderAsBulletHeader) : this.renderTitleAsHeader, this._editTitle)}
  • ); @@ -1162,7 +1162,7 @@ export class TreeView extends React.Component { childDocs: Doc[], treeView: CollectionTreeView, parentTreeView: CollectionTreeView | TreeView | undefined, - treeViewParent: Doc, + treeView_Parent: Doc, dataDoc: Doc | undefined, parentCollectionDoc: Doc | undefined, containerPrevSibling: Doc | undefined, @@ -1176,7 +1176,7 @@ export class TreeView extends React.Component { isContentActive: (outsideReaction?: boolean) => boolean, panelWidth: () => number, renderDepth: number, - treeViewHideHeaderFields: () => boolean, + treeView_HideHeaderFields: () => boolean, renderedIds: string[], onCheckedClick: undefined | (() => ScriptField), onChildClick: undefined | (() => ScriptField), @@ -1193,19 +1193,19 @@ export class TreeView extends React.Component { hierarchyIndex?: number[], renderCount?: number ) { - const viewSpecScript = Cast(treeViewParent.viewSpecScript, ScriptField); + const viewSpecScript = Cast(treeView_Parent.viewSpecScript, ScriptField); if (viewSpecScript) { childDocs = childDocs.filter(d => viewSpecScript.script.run({ doc: d }, console.log).result); } - const docs = TreeView.sortDocs(childDocs, StrCast(treeViewParent.treeViewSortCriterion, TreeSort.None)); + const docs = TreeView.sortDocs(childDocs, StrCast(treeView_Parent.treeView_SortCriterion, TreeSort.None)); const rowWidth = () => panelWidth() - treeBulletWidth() * (treeView.props.NativeDimScaling?.() || 1); - const treeViewRefs = new Map(); + const treeView_Refs = new Map(); return docs .filter(child => child instanceof Doc) .map((child, i) => { if (renderCount && i > renderCount) return null; - const pair = Doc.GetLayoutDataDocPair(treeViewParent, dataDoc, child); + const pair = Doc.GetLayoutDataDocPair(treeView_Parent, dataDoc, child); if (!pair.layout || pair.data instanceof Promise) { return null; } @@ -1218,11 +1218,11 @@ export class TreeView extends React.Component { FormattedTextBox.SelectOnLoad = child[Id]; TreeView._editTitleOnLoad = editTitle ? { id: child[Id], parent } : undefined; Doc.AddDocToList(newParent, fieldKey, child, addAfter, false); - newParent.treeViewOpen = true; + newParent.treeView_Open = true; Doc.SetContainer(child, treeView.Document); } }; - const indent = i === 0 ? undefined : (editTitle: boolean) => dentDoc(editTitle, docs[i - 1], undefined, treeViewRefs.get(docs[i - 1])); + const indent = i === 0 ? undefined : (editTitle: boolean) => dentDoc(editTitle, docs[i - 1], undefined, treeView_Refs.get(docs[i - 1])); const outdent = !parentCollectionDoc ? undefined : (editTitle: boolean) => dentDoc(editTitle, parentCollectionDoc, containerPrevSibling, parentTreeView instanceof TreeView ? parentTreeView.props.parentTreeView : undefined); const addDocument = (doc: Doc | Doc[], annotationKey?: string, relativeTo?: Doc, before?: boolean) => add(doc, relativeTo ?? docs[i], before !== undefined ? before : false); const childLayout = Doc.Layout(pair.layout); @@ -1233,10 +1233,10 @@ export class TreeView extends React.Component { return ( treeViewRefs.set(child, r ? r : undefined)} + ref={r => treeView_Refs.set(child, r ? r : undefined)} document={pair.layout} dataDoc={pair.data} - treeViewParent={treeViewParent} + treeViewParent={treeView_Parent} prevSibling={docs[i]} // TODO: [AL] add these hierarchyIndex={hierarchyIndex ? [...hierarchyIndex, i + 1] : undefined} @@ -1248,7 +1248,7 @@ export class TreeView extends React.Component { onCheckedClick={onCheckedClick} onChildClick={onChildClick} renderDepth={renderDepth} - removeDoc={StrCast(treeViewParent.treeViewFreezeChildren).includes('remove') ? undefined : remove} + removeDoc={StrCast(treeView_Parent.treeView_FreezeChildren).includes('remove') ? undefined : remove} addDocument={addDocument} styleProvider={styleProvider} panelWidth={rowWidth} @@ -1259,7 +1259,7 @@ export class TreeView extends React.Component { addDocTab={addDocTab} ScreenToLocalTransform={screenToLocalXf} isContentActive={isContentActive} - treeViewHideHeaderFields={treeViewHideHeaderFields} + treeViewHideHeaderFields={treeView_HideHeaderFields} renderedIds={renderedIds} skipFields={skipFields} firstLevel={firstLevel} diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss index c6419885b..e4ae251c8 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss @@ -153,7 +153,12 @@ overflow-y: auto; overflow-x: hidden; } - +.collectionFreeFormView-brushView { + pointer-events: none; + position: absolute; + transition: opacity 0.5s; + z-index: 1000; +} .collectionfreeformview-container { // touch action none means that the browser will handle none of the touch actions. this allows us to implement our own actions. touch-action: none; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index e1455525e..ffcf0999c 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -319,7 +319,7 @@ export class CollectionFreeFormView extends CollectionSubView { if (this.Document._isGroup || !this.isContentActive()) return; // group style collections neither pan nor zoom PresBox.Instance?.pauseAutoPres(); - if (this.layoutDoc._Transform || this.props.Document.treeViewOutlineMode === TreeViewType.outline) return; + if (this.layoutDoc._Transform || this.props.Document.treeView_OutlineMode === TreeViewType.outline) return; e.stopPropagation(); const docHeight = NumCast(this.rootDoc[Doc.LayoutFieldKey(this.rootDoc) + '_nativeHeight'], this.nativeHeight); const scrollable = NumCast(this.layoutDoc[this.scaleFieldKey], 1) === 1 && docHeight > this.props.PanelHeight() / this.nativeDimScaling + 1e-4; @@ -1318,7 +1319,7 @@ export class CollectionFreeFormView extends CollectionSubView ); } @@ -1537,7 +1538,7 @@ export class CollectionFreeFormView extends CollectionSubView { // create an anchor that saves information about the current state of the freeform view (pan, zoom, view type) - const anchor = Docs.Create.ConfigDocument({ title: 'ViewSpec - ' + StrCast(this.layoutDoc._type_collection), layout_unrendered: true, presTransition: 500, annotationOn: this.rootDoc }); + const anchor = Docs.Create.ConfigDocument({ title: 'ViewSpec - ' + StrCast(this.layoutDoc._type_collection), layout_unrendered: true, presentation_transition: 500, annotationOn: this.rootDoc }); PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: { ...(pinProps?.pinData ?? {}), pannable: !this.Document._isGroup, type_collection: true, filters: true } }, this.rootDoc); if (addAsAnnotation) { @@ -1866,6 +1867,7 @@ export class CollectionFreeFormView extends CollectionSubView (CollectionFreeFormView.ShowPresPaths ? PresBox.Instance.getPaths(this.rootDoc) : null); + brushedView = () => this._brushedView; @computed get marqueeView() { TraceMobx(); return ( @@ -1908,13 +1910,13 @@ export class CollectionFreeFormView extends CollectionSubView ) : null} {this.children} @@ -1945,19 +1947,19 @@ export class CollectionFreeFormView extends CollectionSubView { - this._brushedView = { ...viewport, panX: viewport.panX - viewport.width / 2, panY: viewport.panY - viewport.height / 2, opacity: 1 }; + brushView = (viewport: { width: number; height: number; panX: number; panY: number }, transTime: number) => { this._brushtimer1 && clearTimeout(this._brushtimer1); this._brushtimer && clearTimeout(this._brushtimer); + this._brushedView = { width: 0, height: 0, panX: 0, panY: 0, opacity: 0 }; this._brushtimer1 = setTimeout( action(() => { - this._brushedView.opacity = 0; + this._brushedView = { ...viewport, panX: viewport.panX - viewport.width / 2, panY: viewport.panY - viewport.height / 2, opacity: 1 }; this._brushtimer = setTimeout( - action(() => (this._brushedView = { width: 0, height: 0, panX: 0, panY: 0, opacity: 0 })), - 500 + action(() => (this._brushedView.opacity = 0)), + 2500 ); }), - 1000 + transTime + 1 ); }; lightboxPanelWidth = () => Math.max(0, this.props.PanelWidth() - 30); @@ -2084,7 +2086,7 @@ interface CollectionFreeFormViewPannableContentsProps { presPinView?: boolean; isAnnotationOverlay: boolean | undefined; isAnnotationOverlayScrollable: boolean | undefined; - brushView: { panX: number; panY: number; width: number; height: number; opacity: number }; + brushedView: () => { panX: number; panY: number; width: number; height: number; opacity: number }; } @observer @@ -2156,6 +2158,7 @@ class CollectionFreeFormViewPannableContents extends React.Component {this.props.children} - {!this.props.brushView.width ? null : ( + {
    - )} + } {this.presPaths}
    ); diff --git a/src/client/views/linking/LinkMenuItem.tsx b/src/client/views/linking/LinkMenuItem.tsx index 737d675aa..a81707ea4 100644 --- a/src/client/views/linking/LinkMenuItem.tsx +++ b/src/client/views/linking/LinkMenuItem.tsx @@ -84,7 +84,7 @@ export class LinkMenuItem extends React.Component { }, emptyFunction, action(() => { - const trail = DocCast(this.props.docView.rootDoc.presTrail); + const trail = DocCast(this.props.docView.rootDoc.presentationTrail); if (trail) { Doc.ActivePresentation = trail; DocumentViewInternal.addDocTabFunc(trail, OpenWhere.replaceRight); diff --git a/src/client/views/nodes/DataVizBox/DataVizBox.tsx b/src/client/views/nodes/DataVizBox/DataVizBox.tsx index 0cc73f32f..059c39c68 100644 --- a/src/client/views/nodes/DataVizBox/DataVizBox.tsx +++ b/src/client/views/nodes/DataVizBox/DataVizBox.tsx @@ -20,7 +20,7 @@ export enum DataVizView { TABLE = 'table', LINECHART = 'lineChart', HISTOGRAM = 'histogram', - PIECHART = 'pieChart' + PIECHART = 'pieChart', } @observer @@ -39,20 +39,22 @@ export class DataVizBox extends ViewBoxAnnotatableComponent() { // current displayed chart type @computed get dataVizView(): DataVizView { - return StrCast(this.layoutDoc._dataVizView, 'table') as DataVizView; + return StrCast(this.layoutDoc._dataViz, 'table') as DataVizView; } @action // pinned / linked anchor doc includes selected rows, graph titles, and graph colors restoreView = (data: Doc) => { - const changedView = this.dataVizView !== data.presDataVizView && (this.layoutDoc._dataVizView = data.presDataVizView); - const changedAxes = this.axes.join('') !== StrListCast(data.presDataVizAxes).join('') && (this.layoutDoc._data_vizAxes = new List(StrListCast(data.presDataVizAxes))); - this.layoutDoc.selected = Field.Copy(data.selected); + const changedView = this.dataVizView !== data.config_dataViz && (this.layoutDoc._dataViz = data.config_dataViz); + const changedAxes = this.axes.join('') !== StrListCast(data.config_dataVizAxes).join('') && (this.layoutDoc._dataViz_axes = new List(StrListCast(data.config_dataVizAxes))); + this.layoutDoc.dataViz_selectedRows = Field.Copy(data.dataViz_selectedRows); this.layoutDoc.histogramBarColors = Field.Copy(data.histogramBarColors); this.layoutDoc.defaultHistogramColor = data.defaultHistogramColor; this.layoutDoc.pieSliceColors = Field.Copy(data.pieSliceColors); Object.keys(this.layoutDoc).map(key => { - if (key.startsWith('histogram-title') || key.startsWith('lineChart-title') || key.startsWith('pieChart-title')){ this.layoutDoc['_'+key] = data[key]; } - }) + if (key.startsWith('histogram_title') || key.startsWith('lineChart_title') || key.startsWith('pieChart_title')) { + this.layoutDoc['_' + key] = data[key]; + } + }); const func = () => this._chartRenderer?.restoreView(data); if (changedView || changedAxes) { setTimeout(func, 100); @@ -69,23 +71,25 @@ export class DataVizBox extends ViewBoxAnnotatableComponent() { // this is for when we want the whole doc (so when the chartBox getAnchor returns without a marker) /*put in some options*/ }); - anchor.presDataVizView = this.dataVizView; - anchor.presDataVizAxes = this.axes.length ? new List(this.axes) : undefined; - anchor.selected = Field.Copy(this.layoutDoc.selected); + anchor.config_dataViz = this.dataVizView; + anchor.config_dataVizAxes = this.axes.length ? new List(this.axes) : undefined; + anchor.dataViz_selectedRows = Field.Copy(this.layoutDoc.dataViz_selectedRows); anchor.histogramBarColors = Field.Copy(this.layoutDoc.histogramBarColors); anchor.defaultHistogramColor = this.layoutDoc.defaultHistogramColor; anchor.pieSliceColors = Field.Copy(this.layoutDoc.pieSliceColors); Object.keys(this.layoutDoc).map(key => { - if (key.startsWith('histogram-title') || key.startsWith('lineChart-title') || key.startsWith('pieChart-title')){ anchor[key] = this.layoutDoc[key]; } - }) + if (key.startsWith('histogram_title') || key.startsWith('lineChart_title') || key.startsWith('pieChart_title')) { + anchor[key] = this.layoutDoc[key]; + } + }); this.addDocument(anchor); return anchor; }; @computed.struct get axes() { - return StrListCast(this.layoutDoc.data_vizAxes); + return StrListCast(this.layoutDoc.dataViz_axes); } - selectAxes = (axes: string[]) => (this.layoutDoc.data_vizAxes = new List(axes)); + selectAxes = (axes: string[]) => (this.layoutDoc.dataViz_axes = new List(axes)); // toggles for user to decide which chart type to view the data in @computed get selectView() { @@ -94,10 +98,53 @@ export class DataVizBox extends ViewBoxAnnotatableComponent() { const margin = { top: 10, right: 25, bottom: 75, left: 45 }; if (!this.pairs) return 'no data'; switch (this.dataVizView) { - case DataVizView.TABLE: return ; - case DataVizView.LINECHART: return (this._chartRenderer = r ?? undefined)} height={height} width={width} fieldKey={this.fieldKey} margin={margin} rootDoc={this.rootDoc} axes={this.axes} pairs={this.pairs} dataDoc={this.dataDoc} />; - case DataVizView.HISTOGRAM: return (this._chartRenderer = r ?? undefined)} height={height} width={width} fieldKey={this.fieldKey} margin={margin} rootDoc={this.rootDoc} axes={this.axes} pairs={this.pairs} dataDoc={this.dataDoc} />; - case DataVizView.PIECHART: return (this._chartRenderer = r ?? undefined)} height={height} width={width} fieldKey={this.fieldKey} margin={margin} rootDoc={this.rootDoc} axes={this.axes} pairs={this.pairs} dataDoc={this.dataDoc} />; + case DataVizView.TABLE: + return ; + case DataVizView.LINECHART: + return ( + (this._chartRenderer = r ?? undefined)} + height={height} + width={width} + fieldKey={this.fieldKey} + margin={margin} + rootDoc={this.rootDoc} + axes={this.axes} + pairs={this.pairs} + dataDoc={this.dataDoc} + /> + ); + case DataVizView.HISTOGRAM: + return ( + (this._chartRenderer = r ?? undefined)} + height={height} + width={width} + fieldKey={this.fieldKey} + margin={margin} + rootDoc={this.rootDoc} + axes={this.axes} + pairs={this.pairs} + dataDoc={this.dataDoc} + /> + ); + case DataVizView.PIECHART: + return ( + (this._chartRenderer = r ?? undefined)} + height={height} + width={width} + fieldKey={this.fieldKey} + margin={margin} + rootDoc={this.rootDoc} + axes={this.axes} + pairs={this.pairs} + dataDoc={this.dataDoc} + /> + ); } } @@ -118,14 +165,10 @@ export class DataVizBox extends ViewBoxAnnotatableComponent() { } render() { - if (!this.layoutDoc._dataVizView) this.layoutDoc._dataVizView = this.dataVizView; + if (!this.layoutDoc._dataViz) this.layoutDoc._dataViz = this.dataVizView; return !this.pairs?.length ? ( // displays how to get data into the DataVizBox if its empty -
    - 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. -
    +
    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.
    ) : (
    () { ) }>
    - this.layoutDoc._dataVizView = DataVizView.TABLE} - toggleStatus={this.layoutDoc._dataVizView == DataVizView.TABLE} - /> - this.layoutDoc._dataVizView = DataVizView.LINECHART} - toggleStatus={this.layoutDoc._dataVizView == DataVizView.LINECHART} - /> - this.layoutDoc._dataVizView = DataVizView.HISTOGRAM} - toggleStatus={this.layoutDoc._dataVizView == DataVizView.HISTOGRAM} - /> - this.layoutDoc._dataVizView = DataVizView.PIECHART} - toggleStatus={this.layoutDoc._dataVizView == DataVizView.PIECHART} - /> + (this.layoutDoc._dataViz = DataVizView.TABLE)} toggleStatus={this.layoutDoc._dataViz == DataVizView.TABLE} /> + (this.layoutDoc._dataViz = DataVizView.LINECHART)} toggleStatus={this.layoutDoc._dataViz == DataVizView.LINECHART} /> + (this.layoutDoc._dataViz = DataVizView.HISTOGRAM)} toggleStatus={this.layoutDoc._dataViz == DataVizView.HISTOGRAM} /> + (this.layoutDoc._dataViz = DataVizView.PIECHART)} toggleStatus={this.layoutDoc._dataViz == DataVizView.PIECHART} />
    {this.selectView}
    diff --git a/src/client/views/nodes/DataVizBox/components/Histogram.tsx b/src/client/views/nodes/DataVizBox/components/Histogram.tsx index df6aac6bc..086db2a47 100644 --- a/src/client/views/nodes/DataVizBox/components/Histogram.tsx +++ b/src/client/views/nodes/DataVizBox/components/Histogram.tsx @@ -1,20 +1,20 @@ -import { observer } from "mobx-react"; -import { Doc, StrListCast } from "../../../../../fields/Doc"; +import { observer } from 'mobx-react'; +import { Doc, StrListCast } from '../../../../../fields/Doc'; import * as React from 'react'; import * as d3 from 'd3'; -import { IReactionDisposer, action, computed, observable, reaction } from "mobx"; -import { LinkManager } from "../../../../util/LinkManager"; -import { Cast, DocCast, StrCast} from "../../../../../fields/Types"; -import { PinProps, PresBox } from "../../trails"; -import { Docs } from "../../../../documents/Documents"; -import { List } from "../../../../../fields/List"; +import { IReactionDisposer, action, computed, observable, reaction } from 'mobx'; +import { LinkManager } from '../../../../util/LinkManager'; +import { Cast, DocCast, StrCast } from '../../../../../fields/Types'; +import { PinProps, PresBox } from '../../trails'; +import { Docs } from '../../../../documents/Documents'; +import { List } from '../../../../../fields/List'; import './Chart.scss'; -import { ColorPicker, EditableText, IconButton, Size, Type } from "browndash-components"; -import { FaFillDrip } from "react-icons/fa"; -import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { listSpec } from "../../../../../fields/Schema"; -import { scaleCreatorNumerical, yAxisCreator } from "../utils/D3Utils"; -import { undoBatch, undoable } from "../../../../util/UndoManager"; +import { ColorPicker, EditableText, IconButton, Size, Type } from 'browndash-components'; +import { FaFillDrip } from 'react-icons/fa'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { listSpec } from '../../../../../fields/Schema'; +import { scaleCreatorNumerical, yAxisCreator } from '../utils/D3Utils'; +import { undoBatch, undoable } from '../../../../util/UndoManager'; export interface HistogramProps { rootDoc: Doc; @@ -35,7 +35,6 @@ export interface HistogramProps { @observer export class Histogram extends React.Component { - private _disposers: { [key: string]: IReactionDisposer } = {}; private _histogramRef: React.RefObject = React.createRef(); private _histogramSvg: d3.Selection | undefined; @@ -49,32 +48,37 @@ export class Histogram extends React.Component { // filters all data to just display selected data if brushed (created from an incoming link) @computed get _histogramData() { - var guids = StrListCast(this.props.layoutDoc.rowGuids); + var guids = StrListCast(this.props.layoutDoc.dataViz_rowGuids); if (this.props.axes.length < 1) return []; if (this.props.axes.length < 2) { var ax0 = this.props.axes[0]; - if (/\d/.test(this.props.pairs[0][ax0])){ this.numericalXData = true } + if (/\d/.test(this.props.pairs[0][ax0])) { + this.numericalXData = true; + } return this.props.pairs - ?.filter(pair => (!this.incomingLinks.length ? true : this.incomingLinks[0]!.selected && StrListCast(this.incomingLinks[0].selected).includes(guids[this.props.pairs.indexOf(pair)]))) - .map(pair => ({ [ax0]: (pair[this.props.axes[0]])})) - }; + ?.filter(pair => (!this.incomingLinks.length ? true : this.incomingLinks[0]!.dataViz_selectedRows && StrListCast(this.incomingLinks[0].dataViz_selectedRows).includes(guids[this.props.pairs.indexOf(pair)]))) + .map(pair => ({ [ax0]: pair[this.props.axes[0]] })); + } var ax0 = this.props.axes[0]; var ax1 = this.props.axes[1]; - if (/\d/.test(this.props.pairs[0][ax0])) { this.numericalXData = true;} - if (/\d/.test(this.props.pairs[0][ax1]) ) { this.numericalYData = true;} + if (/\d/.test(this.props.pairs[0][ax0])) { + this.numericalXData = true; + } + if (/\d/.test(this.props.pairs[0][ax1])) { + this.numericalYData = true; + } return this.props.pairs - ?.filter(pair => (!this.incomingLinks.length ? true : this.incomingLinks[0]!.selected && StrListCast(this.incomingLinks[0].selected).includes(guids[this.props.pairs.indexOf(pair)]))) - .map(pair => ({ [ax0]: (pair[this.props.axes[0]]), [ax1]: (pair[this.props.axes[1]]) })) + ?.filter(pair => (!this.incomingLinks.length ? true : this.incomingLinks[0]!.dataViz_selectedRows && StrListCast(this.incomingLinks[0].dataViz_selectedRows).includes(guids[this.props.pairs.indexOf(pair)]))) + .map(pair => ({ [ax0]: pair[this.props.axes[0]], [ax1]: pair[this.props.axes[1]] })); } - @computed get defaultGraphTitle(){ + @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.pairs[0][ax1]) || !this.numericalYData){ - return ax0 + " Histogram"; - } - else return ax0 + " by " + ax1 + " Histogram"; - } + var ax1 = this.props.axes.length > 1 ? this.props.axes[1] : undefined; + if (this.props.axes.length < 2 || !ax1 || !/\d/.test(this.props.pairs[0][ax1]) || !this.numericalYData) { + return ax0 + ' Histogram'; + } else return ax0 + ' by ' + ax1 + ' Histogram'; + } @computed get incomingLinks() { return LinkManager.Instance.getAllRelatedLinks(this.props.rootDoc) // out of all links @@ -83,11 +87,11 @@ export class Histogram extends React.Component { } @computed get rangeVals(): { xMin?: number; xMax?: number; yMin?: number; yMax?: number } { - if (this.numericalXData){ + if (this.numericalXData) { const data = this.data(this._histogramData); - return {xMin: Math.min.apply(null, data), xMax: Math.max.apply(null, data), yMin:0, yMax:0} + return { xMin: Math.min.apply(null, data), xMax: Math.max.apply(null, data), yMin: 0, yMax: 0 }; } - return {xMin:0, xMax:0, yMin:0, yMax:0} + return { xMin: 0, xMax: 0, yMin: 0, yMax: 0 }; } componentWillUnmount() { @@ -97,7 +101,7 @@ export class Histogram extends React.Component { this._disposers.chartData = reaction( () => ({ dataSet: this._histogramData, w: this.width, h: this.height }), ({ dataSet, w, h }) => { - if (dataSet!.length>0) { + if (dataSet!.length > 0) { this.drawChart(dataSet, w, h); } }, @@ -113,7 +117,7 @@ export class Histogram extends React.Component { // title: 'histogram doc selection' + this._currSelected, }); - PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: pinProps?.pinData }, this.props.dataDoc); + PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: pinProps?.pinData }, this.props.rootDoc); return anchor; }; @@ -127,20 +131,22 @@ export class Histogram extends React.Component { // cleans data by converting numerical data to numbers and taking out empty cells data = (dataSet: any) => { - var validData = dataSet.filter((d: { [x: string]: unknown; }) => { + var validData = dataSet.filter((d: { [x: string]: unknown }) => { var valid = true; Object.keys(dataSet[0]).map(key => { if (!d[key] || Number.isNaN(d[key])) valid = false; - }) + }); return valid; - }) - var field = dataSet[0]? Object.keys(dataSet[0])[0] : undefined; - const data = validData.map((d: { [x: string]: any; }) => { - if (this.numericalXData) { return +d[field!].replace(/\$/g, '').replace(/\%/g, '').replace(/\ { + if (this.numericalXData) { + return +d[field!].replace(/\$/g, '').replace(/\%/g, '').replace(/\ { @@ -148,35 +154,31 @@ export class Histogram extends React.Component { var barCounter = -1; const selected = svg.selectAll('.histogram-bar').filter((d: any) => { barCounter++; // uses the order of bars and width of each bar to find which one the pointer is over - if ((barCounter*eachRectWidth ) <= pointerX && pointerX <= ((barCounter+1)*eachRectWidth)){ - var showSelected = this.numericalYData? this._histogramData.filter((data: { [x: string]: any; }) => StrCast(data[xAxisTitle]).replace(/\$/g, '').replace(/\%/g, '').replace(/\ data[xAxisTitle].replace(/\$/g, '').replace(/\%/g, '').replace(/\ StrCast(data[xAxisTitle]).replace(/\$/g, '').replace(/\%/g, '').replace(/\ data[xAxisTitle].replace(/\$/g, '').replace(/\%/g, '').replace(/\ { @@ -184,306 +186,338 @@ export class Histogram extends React.Component { d3.select(this._histogramRef.current).select('.tooltip').remove(); var data = this.data(dataSet); - var xAxisTitle = Object.keys(dataSet[0])[0] + var xAxisTitle = Object.keys(dataSet[0])[0]; var yAxisTitle = this.numericalYData ? Object.keys(dataSet[0])[1] : 'frequency'; - let uniqueArr: unknown[] = [...new Set(data)] - var numBins = (this.numericalXData && Number.isInteger(data[0]))? (this.rangeVals.xMax! - this.rangeVals.xMin! ) : uniqueArr.length - var translateXAxis = !this.numericalXData || numBinsthis.maxBins) numBins = this.maxBins; - var startingPoint = this.numericalXData? this.rangeVals.xMin! : 0; - var endingPoint = this.numericalXData? this.rangeVals.xMax! : numBins; + let uniqueArr: unknown[] = [...new Set(data)]; + var numBins = this.numericalXData && Number.isInteger(data[0]) ? this.rangeVals.xMax! - this.rangeVals.xMin! : uniqueArr.length; + var translateXAxis = !this.numericalXData || numBins < this.maxBins ? width / (numBins + 1) / 2 : 0; + if (numBins > this.maxBins) numBins = this.maxBins; + var startingPoint = this.numericalXData ? this.rangeVals.xMin! : 0; + var endingPoint = this.numericalXData ? this.rangeVals.xMax! : numBins; // converts data into Objects - var histDataSet = dataSet.filter((d: { [x: string]: unknown; }) => { + var histDataSet = dataSet.filter((d: { [x: string]: unknown }) => { var valid = true; Object.keys(dataSet[0]).map(key => { if (!d[key] || Number.isNaN(d[key])) valid = false; - }) + }); return valid; }); if (!this.numericalXData) { - var histStringDataSet: { [x: string]: unknown; }[] = []; - if (this.numericalYData){ - for (let i=0; i each[xAxisTitle]==data[i]) - histStringDataSet.filter(each => each[xAxisTitle]==data[i])[0][yAxisTitle] = Number(barData[0][yAxisTitle]) + 1; + for (let i = 0; i < data.length; i++) { + let barData = histStringDataSet.filter(each => each[xAxisTitle] == data[i]); + histStringDataSet.filter(each => each[xAxisTitle] == data[i])[0][yAxisTitle] = Number(barData[0][yAxisTitle]) + 1; } } - histDataSet = histStringDataSet + histDataSet = histStringDataSet; } // initial graph and binning data for histogram var svg = (this._histogramSvg = d3 .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) - .append("g") - .attr("transform", - "translate(" + this.props.margin.left + "," + this.props.margin.top + ")")); - var x = d3.scaleLinear() - .domain(this.numericalXData? [startingPoint!, endingPoint!] : [0, numBins]) - .range([0, width ]); - var histogram = d3.histogram() - .value(function(d) {return d}) + .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) + .append('g') + .attr('transform', 'translate(' + this.props.margin.left + ',' + this.props.margin.top + ')')); + var x = d3 + .scaleLinear() + .domain(this.numericalXData ? [startingPoint!, endingPoint!] : [0, numBins]) + .range([0, width]); + var histogram = d3 + .histogram() + .value(function (d) { + return d; + }) .domain([startingPoint!, endingPoint!]) - .thresholds(x.ticks(numBins)) - var bins = histogram(data) - var eachRectWidth = width/(bins.length) - var graphStartingPoint = (bins[0].x1 && bins[1])? bins[0].x1! - (bins[1].x1! - bins[1].x0!) : 0; + .thresholds(x.ticks(numBins)); + var bins = histogram(data); + var eachRectWidth = width / bins.length; + var graphStartingPoint = bins[0].x1 && bins[1] ? bins[0].x1! - (bins[1].x1! - bins[1].x0!) : 0; bins[0].x0 = graphStartingPoint; - x = x.domain([graphStartingPoint, endingPoint]) - .range([0, Number.isInteger(this.rangeVals.xMin!)? (width-eachRectWidth) : width ]) + x = x.domain([graphStartingPoint, endingPoint]).range([0, Number.isInteger(this.rangeVals.xMin!) ? width - eachRectWidth : width]); var xAxis; // more calculations based on bins // x-axis - if (!this.numericalXData) { // reorganize to match data if the data is strings rather than numbers + if (!this.numericalXData) { + // reorganize to match data if the data is strings rather than numbers // uniqueArr.sort() - histDataSet.sort() - for (let i=0; i d.x0 = d.x0!) - xAxis = d3.axisBottom(x) - .ticks(bins.length>1? bins.length-1: 1) - .tickFormat( i => uniqueArr[i.valueOf()] as string) - .tickPadding(10) - x.range([0, width-eachRectWidth]) - x.domain([0, bins.length-1]) + eachRectWidth = width / bins.length; + bins.forEach(d => (d.x0 = d.x0!)); + xAxis = d3 + .axisBottom(x) + .ticks(bins.length > 1 ? bins.length - 1 : 1) + .tickFormat(i => uniqueArr[i.valueOf()] as string) + .tickPadding(10); + x.range([0, width - eachRectWidth]); + x.domain([0, bins.length - 1]); translateXAxis = eachRectWidth / 2; - } - else { + } else { var allSame = true; - for (var i=0; i=2? (bins[bins.length-2].x1!-bins[bins.length-2].x0!): 0) + eachRectWidth = width / bins.length; + } else { + eachRectWidth = width / (bins.length + 1); + var tickDiff = bins.length >= 2 ? bins[bins.length - 2].x1! - bins[bins.length - 2].x0! : 0; var curDomain = x.domain(); - x.domain([curDomain[0], curDomain[0] + tickDiff*bins.length]) + x.domain([curDomain[0], curDomain[0] + tickDiff * bins.length]); } - xAxis = d3.axisBottom(x) - .ticks(bins.length-1) - x.range([0, width-eachRectWidth]) + xAxis = d3.axisBottom(x).ticks(bins.length - 1); + x.range([0, width - eachRectWidth]); } // y-axis - const maxFrequency = this.numericalYData? d3.max(histDataSet, function(d: any) { - return d[yAxisTitle]? Number(d[yAxisTitle]!.replace(/\$/g, '').replace(/\%/g, '').replace(/\ this.highlightSelectedBar(true, svg, eachRectWidth, d3.pointer(e)[0], xAxisTitle, yAxisTitle, histDataSet)); const onHover = action((e: any) => { - const selected = this.highlightSelectedBar(false, svg, eachRectWidth, d3.pointer(e)[0], xAxisTitle, yAxisTitle, histDataSet) + const selected = this.highlightSelectedBar(false, svg, eachRectWidth, d3.pointer(e)[0], xAxisTitle, yAxisTitle, histDataSet); updateHighlights(); - }) + }); const mouseOut = action((e: any) => { this.hoverOverData = undefined; updateHighlights(); - }) + }); const updateHighlights = () => { const hoverOverBar = this.hoverOverData; const selectedData = this.selectedData; - svg.selectAll('rect').attr("class", function(d: any) { return ((hoverOverBar && hoverOverBar[0]==d[0]) || selectedData && selectedData[0]==d[0])? 'histogram-bar hover' : 'histogram-bar'; }) - } - svg.on('click', onPointClick) - .on('mouseover', onHover) - .on('mouseout', mouseOut) + svg.selectAll('rect').attr('class', function (d: any) { + return (hoverOverBar && hoverOverBar[0] == d[0]) || (selectedData && selectedData[0] == d[0]) ? 'histogram-bar hover' : 'histogram-bar'; + }); + }; + svg.on('click', onPointClick).on('mouseover', onHover).on('mouseout', mouseOut); // axis titles - svg.append("text") - .attr("transform", "translate(" + (width/2) + " ," + (height+40) + ")") - .style("text-anchor", "middle") + svg.append('text') + .attr('transform', 'translate(' + width / 2 + ' ,' + (height + 40) + ')') + .style('text-anchor', 'middle') .text(xAxisTitle); - svg.append("text") - .attr("transform", "rotate(-90)" + " " + "translate( 0, " + -10 + ")") - .attr("x", -(height/2)) - .attr("y", -20) - .style("text-anchor", "middle") + svg.append('text') + .attr('transform', 'rotate(-90)' + ' ' + 'translate( 0, ' + -10 + ')') + .attr('x', -(height / 2)) + .attr('y', -20) + .style('text-anchor', 'middle') .text(yAxisTitle); - d3.format('.0f') + d3.format('.0f'); // draw bars var selected = this.selectedData; - svg.selectAll("rect") + svg.selectAll('rect') .data(bins) .enter() - .append("rect") - .attr("transform", this.numericalYData? - function (d) { - var eachData = histDataSet.filter((data: { [x: string]: number; }) => {return data[xAxisTitle]==d[0]}) - var length = eachData.length? eachData[0][yAxisTitle].replace(/\$/g, '').replace(/\%/g, '').replace(/\ {return data[xAxisTitle]==d[0]}) - var length = eachData.length? eachData[0][yAxisTitle].replace(/\$/g, '').replace(/\%/g, '').replace(/\{ + .append('rect') + .attr( + 'transform', + this.numericalYData + ? function (d) { + var eachData = histDataSet.filter((data: { [x: string]: number }) => { + return data[xAxisTitle] == d[0]; + }); + var length = eachData.length ? eachData[0][yAxisTitle].replace(/\$/g, '').replace(/\%/g, '').replace(/\ { + return data[xAxisTitle] == d[0]; + }); + var length = eachData.length ? eachData[0][yAxisTitle].replace(/\$/g, '').replace(/\%/g, '').replace(/\ { var barColor; var barColors = StrListCast(this.props.layoutDoc.histogramBarColors).map(each => each.split('::')); - barColors.map(each => { - if (d[0] && d[0].toString() && each[0]==d[0].toString()) barColor = each[1]; + barColors.map(each => { + if (d[0] && d[0].toString() && each[0] == d[0].toString()) barColor = each[1]; else { - var range = StrCast(each[0]).split(" to "); - if (Number(range[0])<=d[0] && d[0]<=Number(range[1])) barColor = each[1]; + var range = StrCast(each[0]).split(' to '); + if (Number(range[0]) <= d[0] && d[0] <= Number(range[1])) barColor = each[1]; } }); - return barColor? StrCast(barColor) : StrCast(this.props.layoutDoc.defaultHistogramColor)}) + return barColor ? StrCast(barColor) : StrCast(this.props.layoutDoc.defaultHistogramColor); + }); }; @action changeSelectedColor = (color: string) => { - this.curBarSelected.attr("fill", color); - var barName = StrCast(this._currSelected[this.props.axes[0]].replace(/\$/g, '').replace(/\%/g, '').replace(/\ { if (each.split('::')[0] == barName) barColors.splice(barColors.indexOf(each), 1) }); + const barColors = Cast(this.props.layoutDoc.histogramBarColors, listSpec('string'), null); + barColors.map(each => { + if (each.split('::')[0] == barName) barColors.splice(barColors.indexOf(each), 1); + }); barColors.push(StrCast(barName + '::' + color)); }; - - @action eraseSelectedColor= () => { - this.curBarSelected.attr("fill", this.props.layoutDoc.defaultHistogramColor); - var barName = StrCast(this._currSelected[this.props.axes[0]].replace(/\$/g, '').replace(/\%/g, '').replace(/\ { if (each.split('::')[0] == barName) barColors.splice(barColors.indexOf(each), 1) }); + @action eraseSelectedColor = () => { + this.curBarSelected.attr('fill', this.props.layoutDoc.defaultHistogramColor); + var barName = StrCast(this._currSelected[this.props.axes[0]].replace(/\$/g, '').replace(/\%/g, '').replace(/\ { + if (each.split('::')[0] == barName) barColors.splice(barColors.indexOf(each), 1); + }); }; render() { - this._histogramData - var curSelectedBarName; - var titleAccessor: any=''; - if (this.props.axes.length==2) titleAccessor = 'histogram-title-'+this.props.axes[0]+'-'+this.props.axes[1]; - else if (this.props.axes.length>0) titleAccessor = 'histogram-title-'+this.props.axes[0]; + this._histogramData; + var curSelectedBarName = ''; + var titleAccessor: any = ''; + if (this.props.axes.length == 2) titleAccessor = 'dataViz_title_histogram_' + this.props.axes[0] + '-' + this.props.axes[1]; + else if (this.props.axes.length > 0) titleAccessor = 'dataViz_title_histogram_' + this.props.axes[0]; if (!this.props.layoutDoc[titleAccessor]) this.props.layoutDoc[titleAccessor] = this.defaultGraphTitle; if (!this.props.layoutDoc.defaultHistogramColor) this.props.layoutDoc.defaultHistogramColor = '#69b3a2'; if (!this.props.layoutDoc.histogramBarColors) this.props.layoutDoc.histogramBarColors = new List(); var selected: string; - if (this._currSelected){ - curSelectedBarName = StrCast(this._currSelected![this.props.axes[0]].replace(/\$/g, '').replace(/\%/g, '').replace(/\ { - key!=''? selected += key + ': ' + this._currSelected[key] + ', ': ''; - }) - selected = selected.substring(0, selected.length-2); + key != '' ? (selected += key + ': ' + this._currSelected[key] + ', ') : ''; + }); + selected = selected.substring(0, selected.length - 2); selected += ' }'; - } - else selected = 'none'; + } else selected = 'none'; var selectedBarColor; var barColors = StrListCast(this.props.layoutDoc.histogramBarColors).map(each => each.split('::')); - barColors.map(each => {if (each[0]==curSelectedBarName!) selectedBarColor = each[1]}); + barColors.map(each => { + if (each[0] == curSelectedBarName!) selectedBarColor = each[1]; + }); this.componentDidMount(); - if (this._histogramData.length>0){ - return ( - this.props.axes.length >= 1 ? ( -
    -
    + if (this._histogramData.length > 0) { + return this.props.axes.length >= 1 ? ( +
    +
    this.props.layoutDoc[titleAccessor] = val as string), "Change Graph Title")} - color={"black"} + setVal={undoable( + action(val => (this.props.layoutDoc[titleAccessor] = val as string)), + 'Change Graph Title' + )} + color={'black'} size={Size.LARGE} fillWidth /> -     +     } + tooltip={'Change Default Bar Color'} + type={Type.SEC} + icon={} selectedColor={StrCast(this.props.layoutDoc.defaultHistogramColor)} - setSelectedColor={undoable (color => this.props.layoutDoc.defaultHistogramColor = color, "Change Default Bar Color")} + setFinalColor={undoable(color => (this.props.layoutDoc.defaultHistogramColor = color), 'Change Default Bar Color')} + setSelectedColor={undoable(color => (this.props.layoutDoc.defaultHistogramColor = color), 'Change Default Bar Color')} size={Size.XSMALL} />
    - {selected != 'none' ? + {selected != 'none' ? (
    Selected: {selected}     } - selectedColor={selectedBarColor? selectedBarColor : this.curBarSelected.attr("fill")} - setSelectedColor={undoable (color => this.changeSelectedColor(color), "Change Selected Bar Color")} + tooltip={'Change Bar Color'} + type={Type.SEC} + icon={} + selectedColor={selectedBarColor ? selectedBarColor : this.curBarSelected.attr('fill')} + setFinalColor={undoable(color => this.changeSelectedColor(color), 'Change Selected Bar Color')} + setSelectedColor={undoable(color => this.changeSelectedColor(color), 'Change Selected Bar Color')} size={Size.XSMALL} />   } - size={Size.XSMALL} - color={'black'} + icon={} + size={Size.XSMALL} + color={'black'} type={Type.SEC} tooltip={'Revert to the default bar color'} - onClick={undoable (action(() => this.eraseSelectedColor()), "Change Selected Bar Color")} + onClick={undoable( + action(() => this.eraseSelectedColor()), + 'Change Selected Bar Color' + )} />
    - : null} + ) : null}
    - ) : {'first use table view to select a column to graph'} + ) : ( + {'first use table view to select a column to graph'} + ); + } else + return ( + // when it is a brushed table and the incoming table doesn't have any rows selected +
    Selected rows of data from the incoming DataVizBox to display.
    ); - } - else return ( - // when it is a brushed table and the incoming table doesn't have any rows selected -
    - Selected rows of data from the incoming DataVizBox to display. -
    - ) } -} \ No newline at end of file +} diff --git a/src/client/views/nodes/DataVizBox/components/LineChart.tsx b/src/client/views/nodes/DataVizBox/components/LineChart.tsx index 8bace941f..8e549adbe 100644 --- a/src/client/views/nodes/DataVizBox/components/LineChart.tsx +++ b/src/client/views/nodes/DataVizBox/components/LineChart.tsx @@ -50,20 +50,21 @@ export class LineChart extends React.Component { // TODO: nda - some sort of mapping that keeps track of the annotated points so we can easily remove when annotations list updates @computed get _lineChartData() { - var guids = StrListCast(this.props.layoutDoc.rowGuids); + var guids = StrListCast(this.props.layoutDoc.dataViz_rowGuids); if (this.props.axes.length <= 1) return []; return this.props.pairs - ?.filter(pair => (!this.incomingLinks.length ? true : this.incomingLinks[0]!.selected && StrListCast(this.incomingLinks[0].selected).includes(guids[this.props.pairs.indexOf(pair)]))) + ?.filter(pair => (!this.incomingLinks.length ? true : this.incomingLinks[0]!.dataViz_selectedRows && StrListCast(this.incomingLinks[0].dataViz_selectedRows).includes(guids[this.props.pairs.indexOf(pair)]))) .map(pair => ({ x: Number(pair[this.props.axes[0]]), y: Number(pair[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"; - } + @computed get graphTitle() { + return this.props.axes[1] + ' vs. ' + this.props.axes[0] + ' Line Chart'; + } @computed get incomingLinks() { return LinkManager.Instance.getAllRelatedLinks(this.props.rootDoc) // out of all links .filter(link => { - return link.link_anchor_1 == this.props.rootDoc.draggedFrom}) // get links where this chart doc is the target of the link + return link.link_anchor_1 == this.props.rootDoc.draggedFrom; + }) // 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 } @computed get incomingSelected() { @@ -158,7 +159,7 @@ export class LineChart extends React.Component { @action restoreView = (data: Doc) => { - const coords = Cast(data.presDataVizSelection, listSpec('number'), null); + const coords = Cast(data.config_dataVizSelection, listSpec('number'), null); if (coords?.length > 1 && (this._currSelected?.x !== coords[0] || this._currSelected?.y !== coords[1])) { this.setCurrSelected(coords[0], coords[1]); return true; @@ -176,8 +177,8 @@ export class LineChart extends React.Component { // title: 'line doc selection' + this._currSelected?.x, }); - PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: pinProps?.pinData }, this.props.dataDoc); - anchor.presDataVizSelection = this._currSelected ? new List([this._currSelected.x, this._currSelected.y]) : undefined; + PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: pinProps?.pinData }, this.props.rootDoc); + anchor.config_dataVizSelection = this._currSelected ? new List([this._currSelected.x, this._currSelected.y]) : undefined; return anchor; }; @@ -189,14 +190,13 @@ export class LineChart extends React.Component { return this.props.width - this.props.margin.left - this.props.margin.right; } - @computed get defaultGraphTitle(){ + @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.pairs[0][ax0]) || !ax1){ - return ax0 + " Line Chart"; - } - else return ax1 + " by " + ax0 + " Line Chart"; - } + var ax1 = this.props.axes.length > 1 ? this.props.axes[1] : undefined; + if (this.props.axes.length < 2 || !/\d/.test(this.props.pairs[0][ax0]) || !ax1) { + return ax0 + ' Line Chart'; + } else return ax1 + ' by ' + ax0 + ' Line Chart'; + } setupTooltip() { return d3 @@ -215,7 +215,7 @@ export class LineChart extends React.Component { @action setCurrSelected(x?: number, y?: number) { // TODO: nda - get rid of svg element in the list? - if (this._currSelected && this._currSelected.x==x && this._currSelected.y==y) this._currSelected = undefined; + 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.pairs.forEach(pair => pair[this.props.axes[0]] === x && pair[this.props.axes[1]] === y && (pair.selected = true)); } @@ -256,7 +256,7 @@ export class LineChart extends React.Component { const svg = (this._lineChartSvg = d3 .select(this._lineChartRef.current) .append('svg') - .attr("class", "graph") + .attr('class', 'graph') .attr('width', `${width + margin.left + margin.right}`) .attr('height', `${height + margin.top + margin.bottom}`) .append('g') @@ -271,13 +271,13 @@ export class LineChart extends React.Component { // get valid data points const data = dataSet[0]; const lineGen = createLineGenerator(xScale, yScale); - var validData = data.filter((d => { + var validData = data.filter(d => { var valid = true; Object.keys(data[0]).map(key => { if (!d[key] || Number.isNaN(d[key])) valid = false; - }) + }); return valid; - })) + }); // draw the plot line drawLine(svg.append('path'), validData, lineGen); // draw the datapoint circle @@ -321,17 +321,17 @@ export class LineChart extends React.Component { .on('click', onPointClick); // axis titles - svg.append("text") - .attr("transform", "translate(" + (width/2) + " ," + (height+40) + ")") - .style("text-anchor", "middle") + svg.append('text') + .attr('transform', 'translate(' + width / 2 + ' ,' + (height + 40) + ')') + .style('text-anchor', 'middle') .text(this.props.axes[0]); - svg.append("text") - .attr("transform", "rotate(-90)" + " " + "translate( 0, " + -10 + ")") - .attr("x", -(height/2)) - .attr("y", -20) - .attr("height", 20) - .attr("width", 20) - .style("text-anchor", "middle") + svg.append('text') + .attr('transform', 'rotate(-90)' + ' ' + 'translate( 0, ' + -10 + ')') + .attr('x', -(height / 2)) + .attr('y', -20) + .attr('height', 20) + .attr('width', 20) + .style('text-anchor', 'middle') .text(this.props.axes[1]); }; @@ -348,42 +348,41 @@ export class LineChart extends React.Component { tooltip .html(() => `(${d0.x},${d0.y})`) // text content for tooltip .style('pointer-events', 'none') - .style('transform', `translate(${xScale(d0.x)-this.width}px,${yScale(d0.y)}px)`); + .style('transform', `translate(${xScale(d0.x) - this.width}px,${yScale(d0.y)}px)`); } render() { this.componentDidMount(); - var titleAccessor:any = ''; - if (this.props.axes.length==2) titleAccessor = 'lineChart-title-'+this.props.axes[0]+'-'+this.props.axes[1]; - else if (this.props.axes.length>0) titleAccessor = 'lineChart-title-'+this.props.axes[0]; + var titleAccessor: any = ''; + if (this.props.axes.length == 2) titleAccessor = 'dataViz_title_lineChart_' + this.props.axes[0] + '-' + this.props.axes[1]; + else if (this.props.axes.length > 0) titleAccessor = 'dataViz_title_lineChart_' + 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){ - return ( - this.props.axes.length>=2 && /\d/.test(this.props.pairs[0][this.props.axes[0]]) && /\d/.test(this.props.pairs[0][this.props.axes[1]]) ? ( -
    -
    + if (this._lineChartData.length > 0) { + return this.props.axes.length >= 2 && /\d/.test(this.props.pairs[0][this.props.axes[0]]) && /\d/.test(this.props.pairs[0][this.props.axes[1]]) ? ( +
    +
    this.props.layoutDoc[titleAccessor] = val as string), "Change Graph Title")} - color={"black"} + setVal={undoable( + action(val => (this.props.layoutDoc[titleAccessor] = val as string)), + 'Change Graph Title' + )} + color={'black'} size={Size.LARGE} fillWidth />
    - {selectedPt!='none'? -
    {`Selected: ${selectedPt}`}
    - : null} + {selectedPt != 'none' ?
    {`Selected: ${selectedPt}`}
    : null}
    - ) : {'first use table view to select two numerical axes to plot'} + ) : ( + {'first use table view to select two numerical axes to plot'} + ); + } else + return ( + // when it is a brushed table and the incoming table doesn't have any rows selected +
    Selected rows of data from the incoming DataVizBox to display.
    ); - } - else return ( - // when it is a brushed table and the incoming table doesn't have any rows selected -
    - Selected rows of data from the incoming DataVizBox to display. -
    - ) } } diff --git a/src/client/views/nodes/DataVizBox/components/PieChart.tsx b/src/client/views/nodes/DataVizBox/components/PieChart.tsx index 0c54d0a4e..fe77293f0 100644 --- a/src/client/views/nodes/DataVizBox/components/PieChart.tsx +++ b/src/client/views/nodes/DataVizBox/components/PieChart.tsx @@ -1,18 +1,18 @@ -import { observer } from "mobx-react"; -import { Doc, StrListCast } from "../../../../../fields/Doc"; +import { observer } from 'mobx-react'; +import { Doc, StrListCast } from '../../../../../fields/Doc'; import * as React from 'react'; import * as d3 from 'd3'; -import { IReactionDisposer, action, computed, observable, reaction } from "mobx"; -import { LinkManager } from "../../../../util/LinkManager"; -import { Cast, DocCast, StrCast} from "../../../../../fields/Types"; -import { PinProps, PresBox } from "../../trails"; -import { Docs } from "../../../../documents/Documents"; -import { List } from "../../../../../fields/List"; +import { IReactionDisposer, action, computed, observable, reaction } from 'mobx'; +import { LinkManager } from '../../../../util/LinkManager'; +import { Cast, DocCast, StrCast } from '../../../../../fields/Types'; +import { PinProps, PresBox } from '../../trails'; +import { Docs } from '../../../../documents/Documents'; +import { List } from '../../../../../fields/List'; import './Chart.scss'; -import { ColorPicker, EditableText, Size, Type } from "browndash-components"; -import { FaFillDrip } from "react-icons/fa"; -import { listSpec } from "../../../../../fields/Schema"; -import { undoable } from "../../../../util/UndoManager"; +import { ColorPicker, EditableText, Size, Type } from 'browndash-components'; +import { FaFillDrip } from 'react-icons/fa'; +import { listSpec } from '../../../../../fields/Schema'; +import { undoable } from '../../../../util/UndoManager'; export interface PieChartProps { rootDoc: Doc; @@ -33,7 +33,6 @@ export interface PieChartProps { @observer export class PieChart extends React.Component { - private _disposers: { [key: string]: IReactionDisposer } = {}; private _piechartRef: React.RefObject = React.createRef(); private _piechartSvg: d3.Selection | undefined; @@ -45,31 +44,34 @@ export class PieChart extends React.Component { // filters all data to just display selected data if brushed (created from an incoming link) @computed get _piechartData() { - var guids = StrListCast(this.props.layoutDoc.rowGuids); + var guids = StrListCast(this.props.layoutDoc.dataViz_rowGuids); if (this.props.axes.length < 1) return []; if (this.props.axes.length < 2) { var ax0 = this.props.axes[0]; - if (/\d/.test(this.props.pairs[0][ax0])){ this.byCategory = false } + if (/\d/.test(this.props.pairs[0][ax0])) { + this.byCategory = false; + } return this.props.pairs - ?.filter(pair => (!this.incomingLinks.length ? true : this.incomingLinks[0]!.selected && StrListCast(this.incomingLinks[0].selected).includes(guids[this.props.pairs.indexOf(pair)]))) - .map(pair => ({ [ax0]: (pair[this.props.axes[0]])})) - }; + ?.filter(pair => (!this.incomingLinks.length ? true : this.incomingLinks[0]!.dataViz_selectedRows && StrListCast(this.incomingLinks[0].dataViz_selectedRows).includes(guids[this.props.pairs.indexOf(pair)]))) + .map(pair => ({ [ax0]: pair[this.props.axes[0]] })); + } var ax0 = this.props.axes[0]; var ax1 = this.props.axes[1]; - if (/\d/.test(this.props.pairs[0][ax0])) { this.byCategory = false; } + if (/\d/.test(this.props.pairs[0][ax0])) { + this.byCategory = false; + } return this.props.pairs - ?.filter(pair => (!this.incomingLinks.length ? true : this.incomingLinks[0]!.selected && StrListCast(this.incomingLinks[0].selected).includes(guids[this.props.pairs.indexOf(pair)]))) - .map(pair => ({ [ax0]: (pair[this.props.axes[0]]), [ax1]: (pair[this.props.axes[1]]) })) + ?.filter(pair => (!this.incomingLinks.length ? true : this.incomingLinks[0]!.dataViz_selectedRows && StrListCast(this.incomingLinks[0].dataViz_selectedRows).includes(guids[this.props.pairs.indexOf(pair)]))) + .map(pair => ({ [ax0]: pair[this.props.axes[0]], [ax1]: pair[this.props.axes[1]] })); } - @computed get defaultGraphTitle(){ + @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.pairs[0][ax0]) || !ax1){ - return ax0 + " Pie Chart"; - } - else return ax1 + " by " + ax0 + " Pie Chart"; - } + var ax1 = this.props.axes.length > 1 ? this.props.axes[1] : undefined; + if (this.props.axes.length < 2 || !/\d/.test(this.props.pairs[0][ax0]) || !ax1) { + return ax0 + ' Pie Chart'; + } else return ax1 + ' by ' + ax0 + ' Pie Chart'; + } @computed get incomingLinks() { return LinkManager.Instance.getAllRelatedLinks(this.props.rootDoc) // out of all links @@ -84,7 +86,7 @@ export class PieChart extends React.Component { this._disposers.chartData = reaction( () => ({ dataSet: this._piechartData, w: this.width, h: this.height }), ({ dataSet, w, h }) => { - if (dataSet!.length>0) { + if (dataSet!.length > 0) { this.drawChart(dataSet, w, h); } }, @@ -100,7 +102,7 @@ export class PieChart extends React.Component { // title: 'piechart doc selection' + this._currSelected, }); - PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: pinProps?.pinData }, this.props.dataDoc); + PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: pinProps?.pinData }, this.props.rootDoc); return anchor; }; @@ -114,167 +116,177 @@ export class PieChart extends React.Component { // cleans data by converting numerical data to numbers and taking out empty cells data = (dataSet: any) => { - var validData = dataSet.filter((d: { [x: string]: unknown; }) => { + var validData = dataSet.filter((d: { [x: string]: unknown }) => { var valid = true; Object.keys(dataSet[0]).map(key => { if (!d[key] || Number.isNaN(d[key])) valid = false; - }) + }); return valid; - }) - var field = dataSet[0]? Object.keys(dataSet[0])[0] : undefined; - const data = validData.map((d: { [x: string]: any; }) => { - if (!this.byCategory) { return +d[field!].replace(/\$/g, '').replace(/\%/g, '').replace(/\ { + if (!this.byCategory) { + return +d[field!].replace(/\$/g, '').replace(/\%/g, '').replace(/\ { - var index = -1; - var sameAsCurrent: boolean; - const selected = svg.selectAll('.slice').filter((d: any) => { - index++; - var p1 = [0,0]; // center of pie - var p3 = [arc.centroid(d)[0]*2, arc.centroid(d)[1]*2]; // outward peak of arc - var p2 = [radius*Math.sin(d.startAngle), -radius*Math.cos(d.startAngle)]; // start of arc - var p4 = [radius*Math.sin(d.endAngle), -radius*Math.cos(d.endAngle)]; // end of arc + var index = -1; + var sameAsCurrent: boolean; + const selected = svg.selectAll('.slice').filter((d: any) => { + index++; + var p1 = [0, 0]; // center of pie + var p3 = [arc.centroid(d)[0] * 2, arc.centroid(d)[1] * 2]; // outward peak of arc + var p2 = [radius * Math.sin(d.startAngle), -radius * Math.cos(d.startAngle)]; // start of arc + var p4 = [radius * Math.sin(d.endAngle), -radius * Math.cos(d.endAngle)]; // end of arc - // draw an imaginary horizontal line from the pointer to see how many times it crosses a slice edge - var lineCrossCount = 0; - // if for all 4 lines - if (Math.min(p1[1], p2[1])<=pointer[1] && pointer[1]<=Math.max(p1[1], p2[1])){ // within y bounds - if (pointer[0] <= (pointer[1]-p1[1])*(p2[0]-p1[0])/(p2[1]-p1[1])+p1[0]) lineCrossCount++; } // intercepts x - if (Math.min(p2[1], p3[1])<=pointer[1] && pointer[1]<=Math.max(p2[1], p3[1])){ - if (pointer[0] <= (pointer[1]-p2[1])*(p3[0]-p2[0])/(p3[1]-p2[1])+p2[0]) lineCrossCount++; } - if (Math.min(p3[1], p4[1])<=pointer[1] && pointer[1]<=Math.max(p3[1], p4[1])){ - if (pointer[0] <= (pointer[1]-p3[1])*(p4[0]-p3[0])/(p4[1]-p3[1])+p3[0]) lineCrossCount++; } - if (Math.min(p4[1], p1[1])<=pointer[1] && pointer[1]<=Math.max(p4[1], p1[1])){ - if (pointer[0] <= (pointer[1]-p4[1])*(p1[0]-p4[0])/(p1[1]-p4[1])+p4[0]) lineCrossCount++; } - if (lineCrossCount % 2 != 0) { // inside the slice of it crosses an odd number of edges - var showSelected = this.byCategory? pieDataSet[index] : this._piechartData[index]; - if (changeSelectedVariables){ - // for when a bar is selected - not just hovered over - sameAsCurrent = (this._currSelected)? - (showSelected[Object.keys(showSelected)[0]]==this._currSelected![Object.keys(showSelected)[0]] - && showSelected[Object.keys(showSelected)[1]]==this._currSelected![Object.keys(showSelected)[1]]) - : - this._currSelected===showSelected; - this._currSelected = sameAsCurrent? undefined: showSelected; - this.selectedData = sameAsCurrent? undefined: d; - } - else this.hoverOverData = d; - return true; - } - return false; - }); - if (changeSelectedVariables){ - if (sameAsCurrent!) this.curSliceSelected = undefined; - else this.curSliceSelected = selected; + // draw an imaginary horizontal line from the pointer to see how many times it crosses a slice edge + var lineCrossCount = 0; + // if for all 4 lines + if (Math.min(p1[1], p2[1]) <= pointer[1] && pointer[1] <= Math.max(p1[1], p2[1])) { + // within y bounds + if (pointer[0] <= ((pointer[1] - p1[1]) * (p2[0] - p1[0])) / (p2[1] - p1[1]) + p1[0]) lineCrossCount++; + } // intercepts x + if (Math.min(p2[1], p3[1]) <= pointer[1] && pointer[1] <= Math.max(p2[1], p3[1])) { + if (pointer[0] <= ((pointer[1] - p2[1]) * (p3[0] - p2[0])) / (p3[1] - p2[1]) + p2[0]) lineCrossCount++; } - } + if (Math.min(p3[1], p4[1]) <= pointer[1] && pointer[1] <= Math.max(p3[1], p4[1])) { + if (pointer[0] <= ((pointer[1] - p3[1]) * (p4[0] - p3[0])) / (p4[1] - p3[1]) + p3[0]) lineCrossCount++; + } + if (Math.min(p4[1], p1[1]) <= pointer[1] && pointer[1] <= Math.max(p4[1], p1[1])) { + if (pointer[0] <= ((pointer[1] - p4[1]) * (p1[0] - p4[0])) / (p1[1] - p4[1]) + p4[0]) lineCrossCount++; + } + if (lineCrossCount % 2 != 0) { + // inside the slice of it crosses an odd number of edges + var showSelected = this.byCategory ? pieDataSet[index] : this._piechartData[index]; + if (changeSelectedVariables) { + // for when a bar is selected - not just hovered over + sameAsCurrent = this._currSelected + ? showSelected[Object.keys(showSelected)[0]] == this._currSelected![Object.keys(showSelected)[0]] && showSelected[Object.keys(showSelected)[1]] == this._currSelected![Object.keys(showSelected)[1]] + : this._currSelected === showSelected; + this._currSelected = sameAsCurrent ? undefined : showSelected; + this.selectedData = sameAsCurrent ? undefined : d; + } else this.hoverOverData = d; + return true; + } + return false; + }); + if (changeSelectedVariables) { + if (sameAsCurrent!) this.curSliceSelected = undefined; + else this.curSliceSelected = selected; + } + }; // draws the pie chart drawChart = (dataSet: any, width: number, height: number) => { d3.select(this._piechartRef.current).select('svg').remove(); d3.select(this._piechartRef.current).select('.tooltip').remove(); - - 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 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; // converts data into Objects var data = this.data(dataSet); - var pieDataSet = dataSet.filter((d: { [x: string]: unknown; }) => { + var pieDataSet = dataSet.filter((d: { [x: string]: unknown }) => { var valid = true; Object.keys(dataSet[0]).map(key => { if (!d[key] || Number.isNaN(d[key])) valid = false; - }) + }); return valid; }); - if (this.byCategory){ - let uniqueCategories = [...new Set(data)] + if (this.byCategory) { + let uniqueCategories = [...new Set(data)]; var pieStringDataSet: { frequency: number }[] = []; - for (let i=0; i each[percentField]==data[i]) + for (let i = 0; i < data.length; i++) { + let sliceData = pieStringDataSet.filter((each: any) => each[percentField] == data[i]); sliceData[0].frequency = sliceData[0].frequency + 1; } - pieDataSet = pieStringDataSet - percentField = Object.keys(pieDataSet[0])[0] - descriptionField = Object.keys(pieDataSet[0])[1]! - data = this.data(pieStringDataSet) + pieDataSet = pieStringDataSet; + percentField = Object.keys(pieDataSet[0])[0]; + descriptionField = Object.keys(pieDataSet[0])[1]!; + data = this.data(pieStringDataSet); } - var trackDuplicates : {[key: string]: any} = {}; - data.forEach((eachData: any) => !trackDuplicates[eachData]? trackDuplicates[eachData] = 0: null) + var trackDuplicates: { [key: string]: any } = {}; + data.forEach((eachData: any) => (!trackDuplicates[eachData] ? (trackDuplicates[eachData] = 0) : null)); // initial chart var svg = (this._piechartSvg = d3 .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) - .append("g")); - let g = svg.append("g") - .attr("transform", - "translate(" + (width/2 + this.props.margin.left) + "," + height/2 + ")"); + .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) + .append('g')); + 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); + var arc = d3.arc().innerRadius(0).outerRadius(radius); // click/hover const onPointClick = action((e: any) => this.highlightSelectedSlice(true, svg, arc, radius, d3.pointer(e), pieDataSet)); const onHover = action((e: any) => { - const selected = this.highlightSelectedSlice(false, svg, arc, radius, d3.pointer(e), pieDataSet) + const selected = this.highlightSelectedSlice(false, svg, arc, radius, d3.pointer(e), pieDataSet); updateHighlights(); - }) + }); const mouseOut = action((e: any) => { this.hoverOverData = undefined; updateHighlights(); - }) + }); const updateHighlights = () => { const hoverOverSlice = this.hoverOverData; const selectedData = this.selectedData; - svg.selectAll('path').attr("class", function(d: any) { - return ((selectedData && d.startAngle==selectedData.startAngle && d.endAngle==selectedData.endAngle) - || ((hoverOverSlice && d.startAngle==hoverOverSlice.startAngle && d.endAngle==hoverOverSlice.endAngle)))? 'slice hover' : 'slice'; }) - } + svg.selectAll('path').attr('class', function (d: any) { + return (selectedData && d.startAngle == selectedData.startAngle && d.endAngle == selectedData.endAngle) || (hoverOverSlice && d.startAngle == hoverOverSlice.startAngle && d.endAngle == hoverOverSlice.endAngle) + ? 'slice hover' + : 'slice'; + }); + }; // drawing the slices var selected = this.selectedData; - var arcs = g.selectAll("arc") - .data(pie(data)) - .enter() - .append("g") - arcs.append("path") - .attr("fill", (d, i)=>{ - var possibleDataPoints = pieDataSet.filter((each: { [x: string]: any | { valueOf(): number; }; }) => { + var arcs = g.selectAll('arc').data(pie(data)).enter().append('g'); + arcs.append('path') + .attr('fill', (d, i) => { + var possibleDataPoints = pieDataSet.filter((each: { [x: string]: any | { valueOf(): number } }) => { try { - return Number(each[percentField].replace(/\$/g, '').replace(/\%/g, '').replace(/\ each.split('::')); - sliceColors.map(each => {if (each[0]==StrCast(accessByName)) sliceColor = each[1]}); + sliceColors.map(each => { + if (each[0] == StrCast(accessByName)) sliceColor = each[1]; + }); } - return sliceColor? StrCast(sliceColor) : d3.schemeSet3[i]? d3.schemeSet3[i]: d3.schemeSet3[i%(d3.schemeSet3.length)] }) - .attr("class", selected? - function(d) { - return (selected && d.startAngle==selected.startAngle && d.endAngle==selected.endAngle)? 'slice hover' : 'slice'; - }: function(d) {return 'slice'}) + return sliceColor ? StrCast(sliceColor) : d3.schemeSet3[i] ? d3.schemeSet3[i] : d3.schemeSet3[i % d3.schemeSet3.length]; + }) + .attr( + 'class', + selected + ? function (d) { + return selected && d.startAngle == selected.startAngle && d.endAngle == selected.endAngle ? 'slice hover' : 'slice'; + } + : function (d) { + return 'slice'; + } + ) .attr('d', arc) .on('click', onPointClick) .on('mouseover', onHover) @@ -282,99 +294,106 @@ export class PieChart extends React.Component { // adding labels trackDuplicates = {}; - data.forEach((eachData: any) => !trackDuplicates[eachData]? trackDuplicates[eachData] = 0: null) - arcs.append("text") - .attr("transform",function(d){ - var centroid = arc.centroid(d as unknown as d3.DefaultArcObject) - var heightOffset = (centroid[1]/radius) * Math.abs(centroid[1]) - return "translate("+ (centroid[0]+centroid[0]/(radius*.02)) + "," + (centroid[1]+heightOffset) + ")"; }) - .attr("text-anchor", "middle") - .text(function(d){ - var possibleDataPoints = pieDataSet.filter((each: { [x: string]: any | { valueOf(): number; }; }) => { + data.forEach((eachData: any) => (!trackDuplicates[eachData] ? (trackDuplicates[eachData] = 0) : null)); + arcs.append('text') + .attr('transform', function (d) { + var centroid = arc.centroid(d as unknown as d3.DefaultArcObject); + var heightOffset = (centroid[1] / radius) * Math.abs(centroid[1]); + return 'translate(' + (centroid[0] + centroid[0] / (radius * 0.02)) + ',' + (centroid[1] + heightOffset) + ')'; + }) + .attr('text-anchor', 'middle') + .text(function (d) { + var possibleDataPoints = pieDataSet.filter((each: { [x: string]: any | { valueOf(): number } }) => { try { - return Number(each[percentField].replace(/\$/g, '').replace(/\%/g, '').replace(/\ { - this.curSliceSelected.attr("fill", color); - var sliceName = this._currSelected[this.props.axes[0]].replace(/\$/g, '').replace(/\%/g, '').replace(/\ { if (each.split('::')[0] == sliceName) sliceColors.splice(sliceColors.indexOf(each), 1) }); + this.curSliceSelected.attr('fill', color); + var sliceName = this._currSelected[this.props.axes[0]].replace(/\$/g, '').replace(/\%/g, '').replace(/\ { + if (each.split('::')[0] == sliceName) sliceColors.splice(sliceColors.indexOf(each), 1); + }); sliceColors.push(StrCast(sliceName + '::' + color)); }; render() { this.componentDidMount(); - var titleAccessor: any=''; - if (this.props.axes.length==2) titleAccessor = 'pieChart-title-'+this.props.axes[0]+'-'+this.props.axes[1]; - else if (this.props.axes.length>0) titleAccessor = 'pieChart-title-'+this.props.axes[0]; + var titleAccessor: any = ''; + if (this.props.axes.length == 2) titleAccessor = 'dataViz_title_pieChart_' + this.props.axes[0] + '-' + this.props.axes[1]; + else if (this.props.axes.length > 0) titleAccessor = 'dataViz_title_pieChart_' + this.props.axes[0]; if (!this.props.layoutDoc[titleAccessor]) this.props.layoutDoc[titleAccessor] = this.defaultGraphTitle; if (!this.props.layoutDoc.pieSliceColors) this.props.layoutDoc.pieSliceColors = new List(); var selected: string; - var curSelectedSliceName; - if (this._currSelected){ - curSelectedSliceName = StrCast(this._currSelected![this.props.axes[0]].replace(/\$/g, '').replace(/\%/g, '').replace(/\ { - key!=''? selected += key + ': ' + this._currSelected[key] + ', ': ''; - }) - selected = selected.substring(0, selected.length-2); + key != '' ? (selected += key + ': ' + this._currSelected[key] + ', ') : ''; + }); + selected = selected.substring(0, selected.length - 2); selected += ' }'; - } - else selected = 'none'; + } else selected = 'none'; var selectedSliceColor; var sliceColors = StrListCast(this.props.layoutDoc.pieSliceColors).map(each => each.split('::')); - sliceColors.map(each => {if (each[0]==curSelectedSliceName!) selectedSliceColor = each[1]}); + sliceColors.map(each => { + if (each[0] == curSelectedSliceName!) selectedSliceColor = each[1]; + }); - if (this._piechartData.length>0){ - return ( - this.props.axes.length >= 1 ? ( + if (this._piechartData.length > 0) { + return this.props.axes.length >= 1 ? (
    -
    +
    this.props.layoutDoc[titleAccessor] = val as string), "Change Graph Title")} - color={"black"} + setVal={undoable( + action(val => (this.props.layoutDoc[titleAccessor] = val as string)), + 'Change Graph Title' + )} + color={'black'} size={Size.LARGE} fillWidth />
    - {selected != 'none' ? + {selected != 'none' ? (
    Selected: {selected}     } - selectedColor={selectedSliceColor? selectedSliceColor : this.curSliceSelected.attr("fill")} - setSelectedColor={undoable (color => this.changeSelectedColor(color), "Change Selected Slice Color")} + tooltip={'Change Slice Color'} + type={Type.SEC} + icon={} + selectedColor={selectedSliceColor ? selectedSliceColor : this.curSliceSelected.attr('fill')} + setFinalColor={undoable(color => this.changeSelectedColor(color), 'Change Selected Slice Color')} + setSelectedColor={undoable(color => this.changeSelectedColor(color), 'Change Selected Slice Color')} size={Size.XSMALL} />
    - : null} + ) : null}
    - ) : {'first use table view to select a column to graph'} + ) : ( + {'first use table view to select a column to graph'} + ); + } else + return ( + // when it is a brushed table and the incoming table doesn't have any rows selected +
    Selected rows of data from the incoming DataVizBox to display.
    ); - } - else return ( - // when it is a brushed table and the incoming table doesn't have any rows selected -
    - Selected rows of data from the incoming DataVizBox to display. -
    - ) } - -} \ No newline at end of file +} diff --git a/src/client/views/nodes/DataVizBox/components/TableBox.tsx b/src/client/views/nodes/DataVizBox/components/TableBox.tsx index f56d34fa6..5579d6d80 100644 --- a/src/client/views/nodes/DataVizBox/components/TableBox.tsx +++ b/src/client/views/nodes/DataVizBox/components/TableBox.tsx @@ -1,4 +1,4 @@ -import { action, computed, } from 'mobx'; +import { action, computed } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; import { Doc, Field, StrListCast } from '../../../../../fields/Doc'; @@ -31,44 +31,45 @@ interface TableBoxProps { @observer export class TableBox extends React.Component { - // filters all data to just display selected data if brushed (created from an incoming link) @computed get _tableData() { if (this.incomingLinks.length! <= 0) return this.props.pairs; - var guids = StrListCast(this.props.layoutDoc.rowGuids); - return this.props.pairs?.filter(pair => this.incomingLinks[0]!.selected && StrListCast(this.incomingLinks[0].selected).includes(guids[this.props.pairs.indexOf(pair)])) + var guids = StrListCast(this.props.layoutDoc.dataViz_rowGuids); + return this.props.pairs?.filter(pair => this.incomingLinks[0]!.dataViz_selectedRows && StrListCast(this.incomingLinks[0].dataViz_selectedRows).includes(guids[this.props.pairs.indexOf(pair)])); } @computed get incomingLinks() { return LinkManager.Instance.getAllRelatedLinks(this.props.rootDoc) // out of all links .filter(link => { - return link.link_anchor_1 == this.props.rootDoc.draggedFrom}) // get links where this chart doc is the target of the link + return link.link_anchor_1 == this.props.rootDoc.draggedFrom; + }) // 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 } @computed get columns() { - if (!this.props.layoutDoc.rowGuids) this.props.layoutDoc.rowGuids = new List(); - const guids = Cast(this.props.layoutDoc.rowGuids, listSpec("string"), null); - if (guids.length==0) this.props.pairs.map(row => guids.push(Utils.GenerateGuid())); - return this._tableData.length ? Array.from(Object.keys(this._tableData[0])).filter(header => header!='' && header!=undefined) : []; + if (!this.props.layoutDoc.dataViz_rowGuids) this.props.layoutDoc.dataViz_rowGuids = new List(); + const guids = Cast(this.props.layoutDoc.dataViz_rowGuids, listSpec('string'), null); + if (guids.length == 0) this.props.pairs.map(row => guids.push(Utils.GenerateGuid())); + return this._tableData.length ? Array.from(Object.keys(this._tableData[0])).filter(header => header != '' && header != undefined) : []; } // updates the 'selected' field to no longer include rows that aren't in the table filterSelectedRowsDown() { - if (!this.props.layoutDoc.selected) this.props.layoutDoc.selected = new List(); - const selected = Cast(this.props.layoutDoc.selected, listSpec("string"), null); - const incomingSelected = this.incomingLinks.length? StrListCast(this.incomingLinks[0].selected) : undefined; - if (incomingSelected){ + if (!this.props.layoutDoc.dataViz_selectedRows) this.props.layoutDoc.dataViz_selectedRows = new List(); + const selected = Cast(this.props.layoutDoc.dataViz_selectedRows, listSpec('string'), null); + const incomingSelected = this.incomingLinks.length ? StrListCast(this.incomingLinks[0].dataViz_selectedRows) : undefined; + if (incomingSelected) { selected.map(guid => { - if (!incomingSelected.includes(guid)) selected.splice(selected.indexOf(guid), 1)}); // filters through selected to remove guids that were removed in the incoming data + if (!incomingSelected.includes(guid)) selected.splice(selected.indexOf(guid), 1); + }); // filters through selected to remove guids that were removed in the incoming data } } render() { this.filterSelectedRowsDown(); - if (this._tableData.length>0){ + if (this._tableData.length > 0) { return ( -
    +
    {p[col]} + var colSelected = this.props.axes[0]==col || this.props.axes[1]==col; + return ( + {p[col]} {p[col]}
    @@ -83,7 +84,8 @@ export class TableBox extends React.Component { 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, - fontWeight: 'bolder', border: '3px solid black' + fontWeight: 'bolder', + border: '3px solid black', }} onPointerDown={e => { const downX = e.clientX; @@ -91,12 +93,13 @@ export class TableBox extends React.Component { setupMoveUpEvents( {}, e, - e => { // dragging off a column to create a brushed DataVizBox + e => { + // dragging off a column to create a brushed DataVizBox const sourceAnchorCreator = () => this.props.docView?.()!.rootDoc!; const targetCreator = (annotationOn: Doc | undefined) => { const embedding = Doc.MakeEmbedding(this.props.docView?.()!.rootDoc!); - embedding._dataVizView = DataVizView.TABLE; - embedding._data_vizAxes = new List([col, col]); + embedding._dataViz = DataVizView.TABLE; + embedding._dataViz_axes = new List([col, col]); embedding._draggedFrom = this.props.docView?.()!.rootDoc!; embedding.annotationOn = annotationOn; //this.props.docView?.()!.rootDoc!; embedding.histogramBarColors = Field.Copy(this.props.layoutDoc.histogramBarColors); @@ -142,25 +145,33 @@ export class TableBox extends React.Component { {this._tableData?.map((p, i) => { var containsData = false; - var guid = StrListCast(this.props.layoutDoc.rowGuids)![this.props.pairs.indexOf(p)] - this.columns.map(col => {if (p[col]!='' && p[col]!=null && p[col]!=undefined) containsData = true}) - if (containsData){ + var guid = StrListCast(this.props.layoutDoc.dataViz_rowGuids)![this.props.pairs.indexOf(p)]; + this.columns.map(col => { + if (p[col] != '' && p[col] != null && p[col] != undefined) containsData = true; + }); + if (containsData) { return ( - { + { // selecting a row - const selected = Cast(this.props.layoutDoc.selected, listSpec("string"), null); + const selected = Cast(this.props.layoutDoc.dataViz_selectedRows, listSpec('string'), null); if (selected.includes(guid)) selected.splice(selected.indexOf(guid), 1); else { - selected.push(guid)}; - })} style={{ background: StrListCast(this.props.layoutDoc.selected).includes(guid) ? 'lightgrey' : '', width: '110%' }}> + selected.push(guid); + } + })} + style={{ background: StrListCast(this.props.layoutDoc.dataViz_selectedRows).includes(guid) ? 'lightgrey' : '', width: '110%' }}> {this.columns.map(col => { - // each cell - var colSelected = this.props.axes[0]==col || this.props.axes[1]==col; - return ( - - )})} + ); + })} ); } @@ -169,12 +180,10 @@ export class TableBox extends React.Component {
    + // each cell + var colSelected = this.props.axes[0] == col || this.props.axes[1] == col; + return ( + {p[col]}
    ); - } - else return ( - // when it is a brushed table and the incoming table doesn't have any rows selected -
    - Selected rows of data from the incoming DataVizBox to display. -
    - ) + } else + return ( + // when it is a brushed table and the incoming table doesn't have any rows selected +
    Selected rows of data from the incoming DataVizBox to display.
    + ); } } diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 90fb55290..c5dead708 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -113,7 +113,7 @@ export interface DocComponentView { getAnchor?: (addAsAnnotation: boolean, pinData?: PinProps) => Doc; // returns an Anchor Doc that represents the current state of the doc's componentview (e.g., the current playhead location of a an audio/video box) restoreView?: (viewSpec: Doc) => boolean; scrollPreview?: (docView: DocumentView, doc: Doc, focusSpeed: number, options: DocFocusOptions) => Opt; // returns the duration of the focus - brushView?: (view: { width: number; height: number; panX: number; panY: number }) => void; + brushView?: (view: { width: number; height: number; panX: number; panY: number }, transTime: number) => void; getView?: (doc: Doc) => Promise>; // returns a nested DocumentView for the specified doc or undefined addDocTab?: (doc: Doc, where: OpenWhere) => boolean; // determines how to add a document - used in following links to open the target ina local lightbox addDocument?: (doc: Doc | Doc[], annotationKey?: string) => boolean; // add a document (used only by collections) @@ -1095,6 +1095,8 @@ export class DocumentViewInternal extends DocComponent ); const targetDoc = showTitle?.startsWith('_') ? this.layoutDoc : this.rootDoc; - const background = StrCast( - SharingManager.Instance.users.find(u => u.user.email === this.dataDoc.author)?.sharingDoc.headingColor, - Doc.UserDoc().layout_showTitle && [DocumentType.RTF, DocumentType.COL].includes(this.rootDoc.type as any) ? StrCast(Doc.SharingDoc().headingColor) : SettingsManager.Instance.userVariantColor - ); + const background = StrCast(SharingManager.Instance.users.find(u => u.user.email === this.dataDoc.author)?.sharingDoc.headingColor, StrCast(Doc.SharingDoc().headingColor, SettingsManager.Instance.userVariantColor)); const sidebarWidthPercent = +StrCast(this.layoutDoc.layout_sidebarWidthPercent).replace('%', ''); const titleView = !showTitle ? null : (
    , root: Doc) { - const dir = presEffectDoc?.presEffectDirection ?? presEffectDoc?.followLinkAnimDirection; + const dir = presEffectDoc?.presentation_effectDirection ?? presEffectDoc?.followLinkAnimDirection; const effectProps = { left: dir === PresEffectDirection.Left, right: dir === PresEffectDirection.Right, @@ -1212,10 +1211,10 @@ export class DocumentViewInternal extends DocComponent{renderDoc}; @@ -1543,7 +1542,7 @@ export class DocumentView extends React.Component {
    console.log('PARSE error', e)} renderInWrapper={false} jsx={StrCast(this.textHtmlOverlay)} />
    , - { presEffect: this.htmlOverlayEffect ?? 'Zoom' } as any as Doc, + { presentation_effect: this.htmlOverlayEffect ?? 'Zoom' } as any as Doc, this.rootDoc )}{' '} diff --git a/src/client/views/nodes/FontIconBox/FontIconBox.tsx b/src/client/views/nodes/FontIconBox/FontIconBox.tsx index 1b2209224..bf3c79cf9 100644 --- a/src/client/views/nodes/FontIconBox/FontIconBox.tsx +++ b/src/client/views/nodes/FontIconBox/FontIconBox.tsx @@ -267,7 +267,7 @@ export class FontIconBox extends DocComponent() { return ScriptCast(this.rootDoc.script); } - colorBatch:UndoManager.Batch|undefined; + colorBatch: UndoManager.Batch | undefined; /** * Color button */ @@ -285,7 +285,7 @@ export class FontIconBox extends DocComponent() { setFinalColor={value => { this.colorScript?.script.run({ this: this.layoutDoc, self: this.rootDoc, value: value, _readOnly_: false }); this.colorBatch?.end(); - this.colorBatch= undefined; + this.colorBatch = undefined; }} selectedColor={curColor} type={Type.PRIM} diff --git a/src/client/views/nodes/FunctionPlotBox.tsx b/src/client/views/nodes/FunctionPlotBox.tsx index 61711417f..40f48dafe 100644 --- a/src/client/views/nodes/FunctionPlotBox.tsx +++ b/src/client/views/nodes/FunctionPlotBox.tsx @@ -48,8 +48,8 @@ export class FunctionPlotBox extends ViewBoxAnnotatableComponent annotationOn: this.rootDoc, }); PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: { ...(pinProps?.pinData ?? {}), datarange: true } }, this.rootDoc); - anchor.presXRange = new List(Array.from(this._plot.options.xAxis.domain)); - anchor.presYRange = new List(Array.from(this._plot.options.yAxis.domain)); + anchor.config_xRange = new List(Array.from(this._plot.options.xAxis.domain)); + anchor.config_yRange = new List(Array.from(this._plot.options.yAxis.domain)); if (addAsAnnotation) this.addDocument(anchor); return anchor; }; diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index d763753a5..c7ccd1ea0 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -22,7 +22,6 @@ import { DocumentType } from '../../documents/DocumentTypes'; import { Networking } from '../../Network'; import { DocumentManager } from '../../util/DocumentManager'; import { DragManager } from '../../util/DragManager'; -import { SnappingManager } from '../../util/SnappingManager'; import { undoBatch } from '../../util/UndoManager'; import { ContextMenu } from '../../views/ContextMenu'; import { CollectionFreeFormView } from '../collections/collectionFreeForm/CollectionFreeFormView'; @@ -80,10 +79,10 @@ export class ImageBox extends ViewBoxAnnotatableComponent { const self = this; const keys = Object.keys(ids).slice(); //for (const key of [...keys.filter(id => id !== 'layout' && !id.includes('_')).sort(), ...keys.filter(id => id === 'layout' || id.includes('_')).sort()]) { - for (const key of keys.sort()) { + for (const key of keys.sort((a: string, b: string) => { + const a_ = a.split('_')[0]; + const b_ = b.split('_')[0]; + if (a_ < b_) return -1; + if (a_ > b_) return 1; + if (a === a_) return -1; + if (b === b_) return 1; + return a === b ? 0 : a < b ? -1 : 1; + })) { rows.push( () { this.props.setContentView?.(this); } render() { - if (this.dataDoc.treeViewOpen === undefined) setTimeout(() => (this.dataDoc.treeViewOpen = true)); + if (this.dataDoc.treeView_Open === undefined) setTimeout(() => (this.dataDoc.treeView_Open = true)); return (
    void); @computed get inlineTextAnnotations() { - return this.allMapMarkers.filter(a => a.textInlineAnnotations); + return this.allMapMarkers.filter(a => a.text_inlineAnnotations); } @observable private _map: google.maps.Map = null as unknown as google.maps.Map; diff --git a/src/client/views/nodes/MapBox/MapBox2.tsx b/src/client/views/nodes/MapBox/MapBox2.tsx index a9154c5bb..b3ae8242d 100644 --- a/src/client/views/nodes/MapBox/MapBox2.tsx +++ b/src/client/views/nodes/MapBox/MapBox2.tsx @@ -100,7 +100,7 @@ export class MapBox2 extends ViewBoxAnnotatableComponent void); @computed get inlineTextAnnotations() { - return this.allMapMarkers.filter(a => a.textInlineAnnotations); + return this.allMapMarkers.filter(a => a.text_inlineAnnotations); } @observable private _map: google.maps.Map = null as unknown as google.maps.Map; diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx index fd4c6366b..758b49655 100644 --- a/src/client/views/nodes/PDFBox.tsx +++ b/src/client/views/nodes/PDFBox.tsx @@ -213,7 +213,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent this._pdfViewer?.brushView(view); + brushView = (view: { width: number; height: number; panX: number; panY: number }, transTime: number) => this._pdfViewer?.brushView(view, transTime); sidebarAddDocTab = (doc: Doc, where: OpenWhere) => { if (DocListCast(this.props.Document[this.props.fieldKey + '_sidebar']).includes(doc) && !this.SidebarShown) { @@ -224,7 +224,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent { this._initialScrollTarget = anchor; - return this._pdfViewer?.scrollFocus(anchor, NumCast(anchor.y, NumCast(anchor.presViewScroll)), options); + return this._pdfViewer?.scrollFocus(anchor, NumCast(anchor.y, NumCast(anchor.config_scrollTop)), options); }; getView = async (doc: Doc) => { @@ -247,7 +247,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent void); - private _setBrushViewer: undefined | ((view: { width: number; height: number; panX: number; panY: number }) => void); + private _setBrushViewer: undefined | ((view: { width: number; height: number; panX: number; panY: number }, transTime: number) => void); private _mainCont: React.RefObject = React.createRef(); private _outerRef: React.RefObject = React.createRef(); private _disposers: { [name: string]: IReactionDisposer } = {}; @@ -91,7 +91,7 @@ export class WebBox extends ViewBoxAnnotatableComponent a.textInlineAnnotations); + return this.allAnnotations.filter(a => a.text_inlineAnnotations); } @computed get webField() { return Cast(this.rootDoc[this.props.fieldKey], WebField)?.url; @@ -133,7 +133,7 @@ export class WebBox extends ViewBoxAnnotatableComponent void) => (this._setBrushViewer = func); - brushView = (view: { width: number; height: number; panX: number; panY: number }) => this._setBrushViewer?.(view); + setBrushViewer = (func?: (view: { width: number; height: number; panX: number; panY: number }, transTime: number) => void) => (this._setBrushViewer = func); + brushView = (view: { width: number; height: number; panX: number; panY: number }, transTime: number) => this._setBrushViewer?.(view, transTime); focus = (anchor: Doc, options: DocFocusOptions) => { if (anchor !== this.rootDoc && this._outerRef.current) { const windowHeight = this.props.PanelHeight() / (this.props.NativeDimScaling?.() || 1); @@ -303,7 +303,7 @@ export class WebBox extends ViewBoxAnnotatableComponent { if (Doc.AreProtosEqual(doc, this.rootDoc)) return new Promise>(res => res(this.props.DocumentView?.())); if (this.rootDoc.layout_fieldKey === 'layout_icon') this.props.DocumentView?.().iconify(); - const webUrl = WebCast(doc.presData)?.url; + const webUrl = WebCast(doc.config_data)?.url; if (this._url && webUrl && webUrl.href !== this._url) this.setData(webUrl.href); if (this._sidebarRef?.current?.makeDocUnfiltered(doc) && !this.SidebarShown) this.toggleSidebar(false); return new Promise>(res => DocumentManager.Instance.AddViewRenderedCb(doc, dv => res(dv))); @@ -334,7 +334,7 @@ export class WebBox extends ViewBoxAnnotatableComponent { - (doc instanceof Doc ? [doc] : doc).forEach(doc => (doc.presData = new WebField(this._url))); + (doc instanceof Doc ? [doc] : doc).forEach(doc => (doc.config_data = new WebField(this._url))); return this.addDocument(doc, annotationKey); }; diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index 1dcc445e8..eea4f513e 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -417,7 +417,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent (tr = this.hyperlinkTerm(tr, term, newAutoLinks))); 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); - this.prepareForTyping(); + // this.prepareForTyping(); } oldAutoLinks.filter(oldLink => !newAutoLinks.has(oldLink) && oldLink.link_anchor_2 !== this.rootDoc).forEach(LinkManager.Instance.deleteLink); }; @@ -730,7 +730,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent { - const trail = DocCast(anchor.presTrail); + const trail = DocCast(anchor.presentationTrail); if (trail) { Doc.ActivePresentation = trail; this.props.addDocTab(trail, OpenWhere.replaceRight); @@ -1237,7 +1237,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent this.props.isSelected(), action(selected => { - selected && this.prepareForTyping(); + //selected && setTimeout(() => this.prepareForTyping()); if (FormattedTextBox._globalHighlights.has('Bold Text')) { this.layoutDoc[DocCss] = this.layoutDoc[DocCss] + 1; // css change happens outside of mobx/react, so this will notify anyone interested in the layout that it has changed } @@ -1550,18 +1550,17 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent { - this._editorView?.dispatch( - this._editorView?.state.tr.setStoredMarks([ - ...(this._editorView.state.storedMarks?.filter(mark => ![schema.marks.em, schema.marks.underline, schema.marks.pFontFamily, schema.marks.pFontSize, schema.marks.strong, schema.marks.pFontColor].includes(mark.type)) ?? []), - ...[schema.marks.user_mark.create({ userid: Doc.CurrentUserEmail, modified: Math.floor(Date.now() / 1000) })], - ...(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().fontWeight === 'bold' ? [schema.mark(schema.marks.strong)] : []), - ]) - ); + if (!this._editorView) return; + const docDefaultMarks = [ + ...(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().fontWeight === 'bold' ? [schema.mark(schema.marks.strong)] : []), + ...[schema.marks.user_mark.create({ userid: Doc.CurrentUserEmail, modified: Math.floor(Date.now() / 1000) })], + ]; + this._editorView?.dispatch(this._editorView?.state.tr.setStoredMarks(docDefaultMarks)); }; @action diff --git a/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts b/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts index 112a0d87e..ec11079b4 100644 --- a/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts +++ b/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts @@ -334,7 +334,7 @@ export function buildKeymap>(schema: S, props: any, mapKey //Command to create a blank space bind('Space', (state: EditorState, dispatch: (tx: Transaction) => void) => { - if (GetEffectiveAcl(props.DataDoc) != AclEdit && GetEffectiveAcl(props.DataDoc) != AclAugment && GetEffectiveAcl(props.DataDoc) != AclAdmin) return true; + if (props.DataDoc && GetEffectiveAcl(props.DataDoc) != AclEdit && GetEffectiveAcl(props.DataDoc) != AclAugment && GetEffectiveAcl(props.DataDoc) != AclAdmin) return true; const marks = state.storedMarks || (state.selection.$to.parentOffset && state.selection.$from.marks()); dispatch(splitMetadata(marks, state.tr)); return false; diff --git a/src/client/views/nodes/formattedText/RichTextMenu.tsx b/src/client/views/nodes/formattedText/RichTextMenu.tsx index 7c3e4baad..9c46459b0 100644 --- a/src/client/views/nodes/formattedText/RichTextMenu.tsx +++ b/src/client/views/nodes/formattedText/RichTextMenu.tsx @@ -104,7 +104,7 @@ export class RichTextMenu extends AntimodeMenu { _disposer: IReactionDisposer | undefined; componentDidMount() { this._disposer = reaction( - () => SelectionManager.Views(), + () => SelectionManager.Views().slice(), views => this.updateMenu(undefined, undefined, undefined) ); } diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx index aaedffc77..05f59d8fe 100644 --- a/src/client/views/nodes/trails/PresBox.tsx +++ b/src/client/views/nodes/trails/PresBox.tsx @@ -74,7 +74,7 @@ export class PresBox extends ViewBoxBaseComponent() { constructor(props: any) { super(props); if (!PresBox.navigateToDocScript) { - PresBox.navigateToDocScript = ScriptField.MakeFunction('navigateToDoc(self.presentationTargetDoc, self)')!; + PresBox.navigateToDocScript = ScriptField.MakeFunction('navigateToDoc(self.presentation_targetDoc, self)')!; } } @@ -116,7 +116,7 @@ export class PresBox extends ViewBoxBaseComponent() { return DocListCast(this.rootDoc[this.presFieldKey]); } @computed get tagDocs() { - return this.childDocs.map(doc => Cast(doc.presentationTargetDoc, Doc, null)); + return this.childDocs.map(doc => Cast(doc.presentation_targetDoc, Doc, null)); } @computed get itemIndex() { return NumCast(this.rootDoc._itemIndex); @@ -125,10 +125,10 @@ export class PresBox extends ViewBoxBaseComponent() { return DocCast(this.childDocs[NumCast(this.rootDoc._itemIndex)]); } @computed get targetDoc() { - return Cast(this.activeItem?.presentationTargetDoc, Doc, null); + return Cast(this.activeItem?.presentation_targetDoc, Doc, null); } public static targetRenderedDoc = (doc: Doc) => { - const targetDoc = Cast(doc?.presentationTargetDoc, Doc, null); + const targetDoc = Cast(doc?.presentation_targetDoc, Doc, null); return targetDoc?.layout_unrendered ? DocCast(targetDoc.annotationOn) : targetDoc; }; @computed get scrollable() { @@ -149,7 +149,7 @@ export class PresBox extends ViewBoxBaseComponent() { @computed get selectedDoc() { return this.selectedDocumentView?.rootDoc; } - isActiveItemTarget = (layoutDoc: Doc) => this.activeItem?.presentationTargetDoc === layoutDoc; + isActiveItemTarget = (layoutDoc: Doc) => this.activeItem?.presentation_targetDoc === layoutDoc; clearSelectedArray = () => this.selectedArray.clear(); addToSelectedArray = action((doc: Doc) => this.selectedArray.add(doc)); removeFromSelectedArray = action((doc: Doc) => this.selectedArray.delete(doc)); @@ -196,18 +196,18 @@ export class PresBox extends ViewBoxBaseComponent() { } this.turnOffEdit(true); this._disposers.selection = reaction( - () => SelectionManager.Views(), + () => SelectionManager.Views().slice(), views => (!PresBox.Instance || views.some(view => view.props.Document === this.rootDoc)) && this.updateCurrentPresentation(), { fireImmediately: true } ); this._disposers.editing = reaction( - () => this.layoutDoc.presStatus === PresStatus.Edit, + () => this.layoutDoc.presentation_status === PresStatus.Edit, editing => { if (editing) { this.childDocs.forEach(doc => { - if (doc.presIndexed !== undefined) { + if (doc.presentation_indexed !== undefined) { this.progressivizedItems(doc)?.forEach(indexedDoc => (indexedDoc.opacity = undefined)); - doc.presIndexed = Math.min(this.progressivizedItems(doc)?.length ?? 0, 1); + doc.presentation_indexed = Math.min(this.progressivizedItems(doc)?.length ?? 0, 1); } }); } @@ -224,10 +224,10 @@ export class PresBox extends ViewBoxBaseComponent() { _mediaTimer!: [NodeJS.Timeout, Doc]; // 'Play on next' for audio or video therefore first navigate to the audio/video before it should be played startTempMedia = (targetDoc: Doc, activeItem: Doc) => { - const duration: number = NumCast(activeItem.presEndTime) - NumCast(activeItem.presStartTime); + const duration: number = NumCast(activeItem.config_clipEnd) - NumCast(activeItem.config_clipStart); if ([DocumentType.VID, DocumentType.AUDIO].includes(targetDoc.type as any)) { const targMedia = DocumentManager.Instance.getDocumentView(targetDoc); - targMedia?.ComponentView?.playFrom?.(NumCast(activeItem.presStartTime), NumCast(activeItem.presStartTime) + duration); + targMedia?.ComponentView?.playFrom?.(NumCast(activeItem.config_clipStart), NumCast(activeItem.config_clipStart) + duration); } }; @@ -251,12 +251,12 @@ export class PresBox extends ViewBoxBaseComponent() { (nextSelected: number, force = false) => () => { if (nextSelected < this.childDocs.length) { - if (force || this.childDocs[nextSelected].groupWithUp) { + if (force || this.childDocs[nextSelected].presentation_groupWithUp) { this.addToSelectedArray(this.childDocs[nextSelected]); - const serial = nextSelected + 1 < this.childDocs.length && NumCast(this.childDocs[nextSelected + 1].groupWithUp) > 1; + const serial = nextSelected + 1 < this.childDocs.length && NumCast(this.childDocs[nextSelected + 1].presentation_groupWithUp) > 1; if (serial) { this.gotoDocument(nextSelected, this.activeItem, true, async () => { - const waitTime = NumCast(this.activeItem.presDuration) - NumCast(this.activeItem.presTransition); + const waitTime = NumCast(this.activeItem.presentation_duration) - NumCast(this.activeItem.presentation_transition); await new Promise(res => setTimeout(() => res(), Math.max(0, waitTime))); doGroupWithUp(nextSelected + 1)(); }); @@ -274,7 +274,7 @@ export class PresBox extends ViewBoxBaseComponent() { // docs within a slide target that will be progressively revealed progressivizedItems = (doc: Doc) => { const targetList = PresBox.targetRenderedDoc(doc); - if (doc.presIndexed !== undefined && targetList) { + if (doc.presentation_indexed !== undefined && targetList) { const listItems = (Cast(targetList[Doc.LayoutFieldKey(targetList)], listSpec(Doc), null)?.filter(d => d instanceof Doc) as Doc[]) ?? DocListCast(targetList[Doc.LayoutFieldKey(targetList) + '_annotations']); return listItems.filter(doc => !doc.layout_unrendered); } @@ -283,7 +283,7 @@ export class PresBox extends ViewBoxBaseComponent() { @action next = () => { const progressiveReveal = (first: boolean) => { - const presIndexed = Cast(this.activeItem?.presIndexed, 'number', null); + const presIndexed = Cast(this.activeItem?.presentation_indexed, 'number', null); if (presIndexed !== undefined) { const targetRenderedDoc = PresBox.targetRenderedDoc(this.activeItem); targetRenderedDoc._dataTransition = 'all 1s'; @@ -296,8 +296,8 @@ export class PresBox extends ViewBoxBaseComponent() { const targetView = listItems && DocumentManager.Instance.getFirstDocumentView(listItemDoc); Doc.linkFollowUnhighlight(); Doc.HighlightDoc(listItemDoc); - listItemDoc.presEffect = this.activeItem.presBulletEffect; - listItemDoc.presTransition = 500; + listItemDoc.presentation_effect = this.activeItem.presBulletEffect; + listItemDoc.presentation_transition = 500; targetView?.setAnimEffect(listItemDoc, 500); if (targetView?.docView && this.activeItem.presBulletExpand) { targetView.docView._animateScalingTo = 1.2; @@ -308,7 +308,7 @@ export class PresBox extends ViewBoxBaseComponent() { }); } listItemDoc.opacity = undefined; - this.activeItem.presIndexed = presIndexed + 1; + this.activeItem.presentation_indexed = presIndexed + 1; } return true; } @@ -322,7 +322,7 @@ export class PresBox extends ViewBoxBaseComponent() { this.nextSlide(curLast + 1 === this.childDocs.length ? (this.layoutDoc.presLoop ? 0 : curLast) : curLast + 1); progressiveReveal(true); // shows first progressive document, but without a transition effect } else { - if (this.childDocs[this.itemIndex + 1] === undefined && (this.layoutDoc.presLoop || this.layoutDoc.presStatus === PresStatus.Edit)) { + if (this.childDocs[this.itemIndex + 1] === undefined && (this.layoutDoc.presLoop || this.layoutDoc.presentation_status === PresStatus.Edit)) { // Case 2: Last slide and presLoop is toggled ON or it is in Edit mode this.nextSlide(0); progressiveReveal(true); // shows first progressive document, but without a transition effect @@ -338,9 +338,9 @@ export class PresBox extends ViewBoxBaseComponent() { const activeItem: Doc = this.activeItem; let prevSelected = this.itemIndex; // Functionality for group with up - let didZoom = activeItem.presMovement; - for (; prevSelected > 0 && this.childDocs[Math.max(0, prevSelected - 1)].groupWithUp; prevSelected--) { - didZoom = didZoom === 'none' ? this.childDocs[prevSelected].presMovement : didZoom; + let didZoom = activeItem.presentation_movement; + for (; prevSelected > 0 && this.childDocs[Math.max(0, prevSelected - 1)].presentation_groupWithUp; prevSelected--) { + didZoom = didZoom === 'none' ? this.childDocs[prevSelected].presentation_movement : didZoom; } if (activeItem && this.childDocs[this.itemIndex - 1] !== undefined) { // Case 2: There are no other frames so it should go to the previous slide @@ -361,20 +361,20 @@ export class PresBox extends ViewBoxBaseComponent() { Doc.UnBrushAllDocs(); if (index >= 0 && index < this.childDocs.length) { this.rootDoc._itemIndex = index; - if (from?.mediaStopTriggerList && this.layoutDoc.presStatus !== PresStatus.Edit) { + if (from?.mediaStopTriggerList && this.layoutDoc.presentation_status !== PresStatus.Edit) { DocListCast(from.mediaStopTriggerList).forEach(this.stopTempMedia); } - if (from?.mediaStop === 'auto' && this.layoutDoc.presStatus !== PresStatus.Edit) { - this.stopTempMedia(from.presentationTargetDoc); + if (from?.mediaStop === 'auto' && this.layoutDoc.presentation_status !== PresStatus.Edit) { + this.stopTempMedia(from.presentation_targetDoc); } // If next slide is audio / video 'Play automatically' then the next slide should be played - if (this.layoutDoc.presStatus !== PresStatus.Edit && (this.targetDoc.type === DocumentType.AUDIO || this.targetDoc.type === DocumentType.VID) && this.activeItem.mediaStart === 'auto') { + if (this.layoutDoc.presentation_status !== PresStatus.Edit && (this.targetDoc.type === DocumentType.AUDIO || this.targetDoc.type === DocumentType.VID) && this.activeItem.mediaStart === 'auto') { this.startTempMedia(this.targetDoc, this.activeItem); } if (!group) this.clearSelectedArray(); this.childDocs[index] && this.addToSelectedArray(this.childDocs[index]); //Update selected array this.turnOffEdit(); - this.navigateToActiveItem(finished); //Handles movement to element only when presTrail is list + this.navigateToActiveItem(finished); //Handles movement to element only when presentationTrail is list this.doHideBeforeAfter(); //Handles hide after/before } }); @@ -398,33 +398,33 @@ export class PresBox extends ViewBoxBaseComponent() { @action playAnnotation = (anno: AudioField) => {}; @action - static restoreTargetDocView(bestTargetView: Opt, activeItem: Doc, transTime: number, pinDocLayout: boolean = BoolCast(activeItem.presPinLayout), pinDataTypes?: pinDataTypes, targetDoc?: Doc) { + static restoreTargetDocView(bestTargetView: Opt, activeItem: Doc, transTime: number, pinDocLayout: boolean = BoolCast(activeItem.config_pinLayout), pinDataTypes?: pinDataTypes, targetDoc?: Doc) { const bestTarget = bestTargetView?.rootDoc ?? (targetDoc?.layout_unrendered ? DocCast(targetDoc?.annotationOn) : targetDoc); if (!bestTarget) return; let changed = false; if (pinDocLayout) { if ( - bestTarget.x !== NumCast(activeItem.presX, NumCast(bestTarget.x)) || - bestTarget.y !== NumCast(activeItem.presY, NumCast(bestTarget.y)) || - bestTarget.rotation !== NumCast(activeItem.presRotation, NumCast(bestTarget.rotation)) || - bestTarget.width !== NumCast(activeItem.presWidth, NumCast(bestTarget.width)) || - bestTarget.height !== NumCast(activeItem.presHeight, NumCast(bestTarget.height)) + bestTarget.x !== NumCast(activeItem.config_x, NumCast(bestTarget.x)) || + bestTarget.y !== NumCast(activeItem.config_y, NumCast(bestTarget.y)) || + bestTarget.rotation !== NumCast(activeItem.config_rotation, NumCast(bestTarget.rotation)) || + bestTarget.width !== NumCast(activeItem.config_width, NumCast(bestTarget.width)) || + bestTarget.height !== NumCast(activeItem.config_height, NumCast(bestTarget.height)) ) { bestTarget._dataTransition = `all ${transTime}ms`; - bestTarget.x = NumCast(activeItem.presX, NumCast(bestTarget.x)); - bestTarget.y = NumCast(activeItem.presY, NumCast(bestTarget.y)); - bestTarget.rotation = NumCast(activeItem.presRotation, NumCast(bestTarget.rotation)); - bestTarget.width = NumCast(activeItem.presWidth, NumCast(bestTarget.width)); - bestTarget.height = NumCast(activeItem.presHeight, NumCast(bestTarget.height)); + bestTarget.x = NumCast(activeItem.config_x, NumCast(bestTarget.x)); + bestTarget.y = NumCast(activeItem.config_y, NumCast(bestTarget.y)); + bestTarget.rotation = NumCast(activeItem.config_rotation, NumCast(bestTarget.rotation)); + bestTarget.width = NumCast(activeItem.config_width, NumCast(bestTarget.width)); + bestTarget.height = NumCast(activeItem.config_height, NumCast(bestTarget.height)); setTimeout(() => (bestTarget._dataTransition = undefined), transTime + 10); changed = true; } } - const activeFrame = activeItem.presActiveFrame ?? activeItem.presCurrentFrame; + const activeFrame = activeItem.config_activeFrame ?? activeItem.config_currentFrame; if (activeFrame !== undefined) { - const transTime = NumCast(activeItem.presTransition, 500); - const acontext = activeItem.presActiveFrame !== undefined ? DocCast(DocCast(activeItem.presentationTargetDoc).embedContainer) : DocCast(activeItem.presentationTargetDoc); + const transTime = NumCast(activeItem.presentation_transition, 500); + const acontext = activeItem.config_activeFrame !== undefined ? DocCast(DocCast(activeItem.presentation_targetDoc).embedContainer) : DocCast(activeItem.presentation_targetDoc); const context = DocCast(acontext)?.annotationOn ? DocCast(DocCast(acontext).annotationOn) : acontext; if (context) { const ffview = DocumentManager.Instance.getFirstDocumentView(context)?.props.CollectionFreeFormDocumentView?.().props.CollectionFreeFormView; @@ -434,73 +434,73 @@ export class PresBox extends ViewBoxBaseComponent() { } } } - if ((pinDataTypes?.dataview && activeItem.presData !== undefined) || (!pinDataTypes && activeItem.presData !== undefined)) { + if ((pinDataTypes?.dataview && activeItem.config_data !== undefined) || (!pinDataTypes && activeItem.config_data !== undefined)) { bestTarget._dataTransition = `all ${transTime}ms`; const fkey = Doc.LayoutFieldKey(bestTarget); const setData = bestTargetView?.ComponentView?.setData; - if (setData) setData(activeItem.presData); - else Doc.GetProto(bestTarget)[fkey] = activeItem.presData instanceof ObjectField ? activeItem.presData[Copy]() : activeItem.presData; - bestTarget[fkey + '_usePath'] = activeItem.presUsePath; + if (setData) setData(activeItem.config_data); + else Doc.GetProto(bestTarget)[fkey] = activeItem.config_data instanceof ObjectField ? activeItem.config_data[Copy]() : activeItem.config_data; + bestTarget[fkey + '_usePath'] = activeItem.config_usePath; setTimeout(() => (bestTarget._dataTransition = undefined), transTime + 10); } - if (pinDataTypes?.datarange || (!pinDataTypes && activeItem.presXRange !== undefined)) { - if (bestTarget.xRange !== activeItem.presXRange) { - bestTarget.xRange = (activeItem.presXRange as ObjectField)?.[Copy](); + if (pinDataTypes?.datarange || (!pinDataTypes && activeItem.config_xRange !== undefined)) { + if (bestTarget.xRange !== activeItem.config_xRange) { + bestTarget.xRange = (activeItem.config_xRange as ObjectField)?.[Copy](); changed = true; } - if (bestTarget.yRange !== activeItem.presYRange) { - bestTarget.yRange = (activeItem.presYRange as ObjectField)?.[Copy](); + if (bestTarget.yRange !== activeItem.config_yRange) { + bestTarget.yRange = (activeItem.config_yRange as ObjectField)?.[Copy](); changed = true; } } - if (pinDataTypes?.clippable || (!pinDataTypes && activeItem.presClipWidth !== undefined)) { + if (pinDataTypes?.clippable || (!pinDataTypes && activeItem.config_clipWidth !== undefined)) { const fkey = '_' + Doc.LayoutFieldKey(bestTarget); - if (bestTarget[fkey + '_clipWidth'] !== activeItem.presClipWidth) { - bestTarget[fkey + '_clipWidth'] = activeItem.presClipWidth; + if (bestTarget[fkey + '_clipWidth'] !== activeItem.config_clipWidth) { + bestTarget[fkey + '_clipWidth'] = activeItem.config_clipWidth; changed = true; } } - if (pinDataTypes?.temporal || (!pinDataTypes && activeItem.presStartTime !== undefined)) { - if (bestTarget._layout_currentTimecode !== activeItem.presStartTime) { - bestTarget._layout_currentTimecode = activeItem.presStartTime; + if (pinDataTypes?.temporal || (!pinDataTypes && activeItem.config_clipStart !== undefined)) { + if (bestTarget._layout_currentTimecode !== activeItem.config_clipStart) { + bestTarget._layout_currentTimecode = activeItem.config_clipStart; changed = true; } } - if (pinDataTypes?.inkable || (!pinDataTypes && (activeItem.presFillColor !== undefined || activeItem.color !== undefined))) { - if (bestTarget.fillColor !== activeItem.presFillColor) { - Doc.GetProto(bestTarget).fillColor = activeItem.presFillColor; + if (pinDataTypes?.inkable || (!pinDataTypes && (activeItem.config_fillColor !== undefined || activeItem.color !== undefined))) { + if (bestTarget.fillColor !== activeItem.config_fillColor) { + Doc.GetProto(bestTarget).fillColor = activeItem.config_fillColor; changed = true; } - if (bestTarget.color !== activeItem.presColor) { - Doc.GetProto(bestTarget).color = activeItem.presColor; + if (bestTarget.color !== activeItem.config_color) { + Doc.GetProto(bestTarget).color = activeItem.config_color; changed = true; } if (bestTarget.width !== activeItem.width) { - bestTarget._width = NumCast(activeItem.presWidth, NumCast(bestTarget.width)); + bestTarget._width = NumCast(activeItem.config_width, NumCast(bestTarget.width)); changed = true; } if (bestTarget.height !== activeItem.height) { - bestTarget._height = NumCast(activeItem.presHeight, NumCast(bestTarget.height)); + bestTarget._height = NumCast(activeItem.config_height, NumCast(bestTarget.height)); changed = true; } } - if ((pinDataTypes?.type_collection && activeItem.presViewType !== undefined) || (!pinDataTypes && activeItem.presViewType !== undefined)) { - if (bestTarget._type_collection !== activeItem.presViewType) { - bestTarget._type_collection = activeItem.presViewType; + if ((pinDataTypes?.type_collection && activeItem.config_viewType !== undefined) || (!pinDataTypes && activeItem.config_viewType !== undefined)) { + if (bestTarget._type_collection !== activeItem.config_viewType) { + bestTarget._type_collection = activeItem.config_viewType; changed = true; } } - if ((pinDataTypes?.filters && activeItem.presDocFilters !== undefined) || (!pinDataTypes && activeItem.presDocFilters !== undefined)) { - if (bestTarget.childFilters !== activeItem.presDocFilters) { - bestTarget.childFilters = ObjectField.MakeCopy(activeItem.presDocFilters as ObjectField) || new List([]); + if ((pinDataTypes?.filters && activeItem.config_docFilters !== undefined) || (!pinDataTypes && activeItem.config_docFilters !== undefined)) { + if (bestTarget.childFilters !== activeItem.config_docFilters) { + bestTarget.childFilters = ObjectField.MakeCopy(activeItem.config_docFilters as ObjectField) || new List([]); changed = true; } } - if ((pinDataTypes?.pivot && activeItem.presPivotField !== undefined) || (!pinDataTypes && activeItem.presPivotField !== undefined)) { - if (bestTarget.pivotField !== activeItem.presPivotField) { - bestTarget.pivotField = activeItem.presPivotField; + if ((pinDataTypes?.pivot && activeItem.config_pivotField !== undefined) || (!pinDataTypes && activeItem.config_pivotField !== undefined)) { + if (bestTarget.pivotField !== activeItem.config_pivotField) { + bestTarget.pivotField = activeItem.config_pivotField; bestTarget._prevFilterIndex = 1; // need to revisit this...see CollectionTimeView changed = true; } @@ -509,21 +509,21 @@ export class PresBox extends ViewBoxBaseComponent() { changed = true; } - if (pinDataTypes?.scrollable || (!pinDataTypes && activeItem.presViewScroll !== undefined)) { - if (bestTarget._layout_scrollTop !== activeItem.presViewScroll) { - bestTarget._layout_scrollTop = activeItem.presViewScroll; + if (pinDataTypes?.scrollable || (!pinDataTypes && activeItem.config_scrollTop !== undefined)) { + if (bestTarget._layout_scrollTop !== activeItem.config_scrollTop) { + bestTarget._layout_scrollTop = activeItem.config_scrollTop; changed = true; - const contentBounds = Cast(activeItem.presPinViewBounds, listSpec('number')); + const contentBounds = Cast(activeItem.config_viewBounds, listSpec('number')); if (contentBounds) { const dv = DocumentManager.Instance.getDocumentView(bestTarget)?.ComponentView; - dv?.brushView?.({ panX: (contentBounds[0] + contentBounds[2]) / 2, panY: (contentBounds[1] + contentBounds[3]) / 2, width: contentBounds[2] - contentBounds[0], height: contentBounds[3] - contentBounds[1] }); + dv?.brushView?.({ panX: (contentBounds[0] + contentBounds[2]) / 2, panY: (contentBounds[1] + contentBounds[3]) / 2, width: contentBounds[2] - contentBounds[0], height: contentBounds[3] - contentBounds[1] }, transTime); } } } - if (pinDataTypes?.dataannos || (!pinDataTypes && activeItem.presAnnotations !== undefined)) { + if (pinDataTypes?.dataannos || (!pinDataTypes && activeItem.config_annotations !== undefined)) { const fkey = Doc.LayoutFieldKey(bestTarget); const oldItems = DocListCast(bestTarget[fkey + '_annotations']).filter(doc => doc.layout_unrendered); - const newItems = DocListCast(activeItem.presAnnotations).map(doc => { + const newItems = DocListCast(activeItem.config_annotations).map(doc => { doc.hidden = false; return doc; }); @@ -536,11 +536,11 @@ export class PresBox extends ViewBoxBaseComponent() { const newList = new List([...oldItems, ...hiddenItems, ...newItems]); Doc.GetProto(bestTarget)[fkey + '_annotations'] = newList; } - if (pinDataTypes?.poslayoutview || (!pinDataTypes && activeItem.presPinLayoutData !== undefined)) { + if (pinDataTypes?.poslayoutview || (!pinDataTypes && activeItem.config_pinLayoutData !== undefined)) { changed = true; const layoutField = Doc.LayoutFieldKey(bestTarget); const transitioned = new Set(); - StrListCast(activeItem.presPinLayoutData) + StrListCast(activeItem.config_pinLayoutData) .map(str => JSON.parse(str) as { id: string; x: number; y: number; back: string; fill: string; w: number; h: number; data: string; text: string }) .forEach(async data => { const doc = DocCast(DocServer.GetCachedRefField(data.id)); @@ -562,8 +562,8 @@ export class PresBox extends ViewBoxBaseComponent() { }); setTimeout(() => Array.from(transitioned).forEach(action(doc => (doc._dataTransition = undefined))), transTime + 10); } - if ((pinDataTypes?.pannable || (!pinDataTypes && (activeItem.presPinViewBounds !== undefined || activeItem.presPanX !== undefined || activeItem.presViewScale !== undefined))) && !bestTarget._isGroup) { - const contentBounds = Cast(activeItem.presPinViewBounds, listSpec('number')); + if ((pinDataTypes?.pannable || (!pinDataTypes && (activeItem.config_viewBounds !== undefined || activeItem.config_panX !== undefined || activeItem.config_viewScale !== undefined))) && !bestTarget._isGroup) { + const contentBounds = Cast(activeItem.config_viewBounds, listSpec('number')); if (contentBounds) { const viewport = { panX: (contentBounds[0] + contentBounds[2]) / 2, panY: (contentBounds[1] + contentBounds[3]) / 2, width: contentBounds[2] - contentBounds[0], height: contentBounds[3] - contentBounds[1] }; bestTarget._freeform_panX = viewport.panX; @@ -572,14 +572,14 @@ export class PresBox extends ViewBoxBaseComponent() { if (dv) { changed = true; const computedScale = NumCast(activeItem.presZoom, 1) * Math.min(dv.props.PanelWidth() / viewport.width, dv.props.PanelHeight() / viewport.height); - activeItem.presMovement === PresMovement.Zoom && (bestTarget._freeform_scale = computedScale); - dv.ComponentView?.brushView?.(viewport); + activeItem.presentation_movement === PresMovement.Zoom && (bestTarget._freeform_scale = computedScale); + dv.ComponentView?.brushView?.(viewport, transTime); } } else { - if (bestTarget._freeform_panX !== activeItem.presPanX || bestTarget._freeform_panY !== activeItem.presPanY || bestTarget._freeform_scale !== activeItem.presViewScale) { - bestTarget._freeform_panX = activeItem.presPanX ?? bestTarget._freeform_panX; - bestTarget._freeform_panY = activeItem.presPanY ?? bestTarget._freeform_panY; - bestTarget._freeform_scale = activeItem.presViewScale ?? bestTarget._freeform_scale; + if (bestTarget._freeform_panX !== activeItem.config_panX || bestTarget._freeform_panY !== activeItem.config_panY || bestTarget._freeform_scale !== activeItem.config_viewScale) { + bestTarget._freeform_panX = activeItem.config_panX ?? bestTarget._freeform_panX; + bestTarget._freeform_panY = activeItem.config_panY ?? bestTarget._freeform_panY; + bestTarget._freeform_scale = activeItem.config_viewScale ?? bestTarget._freeform_scale; changed = true; } } @@ -594,17 +594,19 @@ export class PresBox extends ViewBoxBaseComponent() { /// target doc when navigating to it. @action static pinDocView(pinDoc: Doc, pinProps: PinProps, targetDoc: Doc) { + pinDoc.presentation = true; + pinDoc.config = ''; if (pinProps.pinDocLayout) { - pinDoc.presPinLayout = true; - pinDoc.presX = NumCast(targetDoc.x); - pinDoc.presY = NumCast(targetDoc.y); - pinDoc.presRotation = NumCast(targetDoc.rotation); - pinDoc.presWidth = NumCast(targetDoc.width); - pinDoc.presHeight = NumCast(targetDoc.height); + pinDoc.config_pinLayout = true; + pinDoc.config_x = NumCast(targetDoc.x); + pinDoc.config_y = NumCast(targetDoc.y); + pinDoc.config_rotation = NumCast(targetDoc.rotation); + pinDoc.config_width = NumCast(targetDoc.width); + pinDoc.config_height = NumCast(targetDoc.height); } if (pinProps.pinAudioPlay) pinDoc.presPlayAudio = true; if (pinProps.pinData) { - pinDoc.presPinData = + pinDoc.config_pinData = pinProps.pinData.scrollable || pinProps.pinData.temporal || pinProps.pinData.pannable || @@ -616,30 +618,30 @@ export class PresBox extends ViewBoxBaseComponent() { pinProps?.activeFrame !== undefined; const fkey = Doc.LayoutFieldKey(targetDoc); if (pinProps.pinData.dataview) { - pinDoc.presUsePath = targetDoc[fkey + '_usePath']; - pinDoc.presData = targetDoc[fkey] instanceof ObjectField ? (targetDoc[fkey] as ObjectField)[Copy]() : targetDoc.data; + pinDoc.config_usePath = targetDoc[fkey + '_usePath']; + pinDoc.config_data = targetDoc[fkey] instanceof ObjectField ? (targetDoc[fkey] as ObjectField)[Copy]() : targetDoc.data; } if (pinProps.pinData.dataannos) { const fkey = Doc.LayoutFieldKey(targetDoc); - pinDoc.presAnnotations = new List(DocListCast(Doc.GetProto(targetDoc)[fkey + '_annotations']).filter(doc => !doc.layout_unrendered)); + pinDoc.config_annotations = new List(DocListCast(Doc.GetProto(targetDoc)[fkey + '_annotations']).filter(doc => !doc.layout_unrendered)); } if (pinProps.pinData.inkable) { - pinDoc.presFillColor = targetDoc.fillColor; - pinDoc.presColor = targetDoc.color; - pinDoc.presWidth = targetDoc._width; - pinDoc.presHeight = targetDoc._height; + pinDoc.config_fillColor = targetDoc.fillColor; + pinDoc.config_color = targetDoc.color; + pinDoc.config_width = targetDoc._width; + pinDoc.config_height = targetDoc._height; } - if (pinProps.pinData.scrollable) pinDoc.presViewScroll = targetDoc._layout_scrollTop; + if (pinProps.pinData.scrollable) pinDoc.config_scrollTop = targetDoc._layout_scrollTop; if (pinProps.pinData.clippable) { const fkey = Doc.LayoutFieldKey(targetDoc); - pinDoc.presClipWidth = targetDoc[fkey + '_clipWidth']; + pinDoc.config_clipWidth = targetDoc[fkey + '_clipWidth']; } if (pinProps.pinData.datarange) { - pinDoc.presXRange = undefined; //targetDoc?.xrange; - pinDoc.presYRange = undefined; //targetDoc?.yrange; + pinDoc.config_xRange = undefined; //targetDoc?.xrange; + pinDoc.config_yRange = undefined; //targetDoc?.yrange; } if (pinProps.pinData.poslayoutview) - pinDoc.presPinLayoutData = new List( + pinDoc.config_pinLayoutData = new List( DocListCast(targetDoc[fkey] as ObjectField).map(d => JSON.stringify({ id: d[Id], @@ -654,28 +656,28 @@ export class PresBox extends ViewBoxBaseComponent() { }) ) ); - if (pinProps.pinData.type_collection) pinDoc.presViewType = targetDoc._type_collection; - if (pinProps.pinData.filters) pinDoc.presDocFilters = ObjectField.MakeCopy(targetDoc.childFilters as ObjectField); - if (pinProps.pinData.pivot) pinDoc.presPivotField = targetDoc._pivotField; + if (pinProps.pinData.type_collection) pinDoc.config_viewType = targetDoc._type_collection; + if (pinProps.pinData.filters) pinDoc.config_docFilters = ObjectField.MakeCopy(targetDoc.childFilters as ObjectField); + if (pinProps.pinData.pivot) pinDoc.config_pivotField = targetDoc._pivotField; if (pinProps.pinData.pannable) { - pinDoc.presPanX = NumCast(targetDoc._freeform_panX); - pinDoc.presPanY = NumCast(targetDoc._freeform_panY); - pinDoc.presViewScale = NumCast(targetDoc._freeform_scale, 1); + pinDoc.config_panX = NumCast(targetDoc._freeform_panX); + pinDoc.config_panY = NumCast(targetDoc._freeform_panY); + pinDoc.config_viewScale = NumCast(targetDoc._freeform_scale, 1); } if (pinProps.pinData.temporal) { - pinDoc.presStartTime = targetDoc._layout_currentTimecode; - const duration = NumCast(pinDoc[`${Doc.LayoutFieldKey(pinDoc)}_duration`], NumCast(targetDoc.presStartTime) + 0.1); - pinDoc.presEndTime = NumCast(targetDoc.clipEnd, duration); + pinDoc.config_clipStart = targetDoc._layout_currentTimecode; + const duration = NumCast(pinDoc[`${Doc.LayoutFieldKey(pinDoc)}_duration`], NumCast(targetDoc.config_clipStart) + 0.1); + pinDoc.config_clipEnd = NumCast(targetDoc.clipEnd, duration); } } if (pinProps?.pinViewport) { // If pinWithView option set then update scale and x / y props of slide const bounds = pinProps.pinViewport; - pinDoc.presPinView = true; - pinDoc.presViewScale = NumCast(targetDoc._freeform_scale, 1); - pinDoc.presPanX = bounds.left + bounds.width / 2; - pinDoc.presPanY = bounds.top + bounds.height / 2; - pinDoc.presPinViewBounds = new List([bounds.left, bounds.top, bounds.left + bounds.width, bounds.top + bounds.height]); + pinDoc.config_pinView = true; + pinDoc.config_viewScale = NumCast(targetDoc._freeform_scale, 1); + pinDoc.config_panX = bounds.left + bounds.width / 2; + pinDoc.config_panY = bounds.top + bounds.height / 2; + pinDoc.config_viewBounds = new List([bounds.left, bounds.top, bounds.left + bounds.width, bounds.top + bounds.height]); } } /** @@ -712,23 +714,23 @@ export class PresBox extends ViewBoxBaseComponent() { }; static NavigateToTarget(targetDoc: Doc, activeItem: Doc, finished?: () => void) { - if (activeItem.presMovement === PresMovement.None && targetDoc.type === DocumentType.SCRIPTING) { + if (activeItem.presentation_movement === PresMovement.None && targetDoc.type === DocumentType.SCRIPTING) { (DocumentManager.Instance.getFirstDocumentView(targetDoc)?.ComponentView as ScriptingBox)?.onRun?.(); return; } - const effect = activeItem.presEffect && activeItem.presEffect !== PresEffect.None ? activeItem.presEffect : undefined; - const presTime = NumCast(activeItem.presTransition, effect ? 750 : 500); + const effect = activeItem.presentation_effect && activeItem.presentation_effect !== PresEffect.None ? activeItem.presentation_effect : undefined; + const presTime = NumCast(activeItem.presentation_transition, effect ? 750 : 500); const options: DocFocusOptions = { - willPan: activeItem.presMovement !== PresMovement.None, - willZoomCentered: activeItem.presMovement === PresMovement.Zoom || activeItem.presMovement === PresMovement.Jump || activeItem.presMovement === PresMovement.Center, - zoomScale: activeItem.presMovement === PresMovement.Center ? 0 : NumCast(activeItem.presZoom, 1), - zoomTime: activeItem.presMovement === PresMovement.Jump ? 0 : Math.min(Math.max(effect ? 750 : 500, (effect ? 0.2 : 1) * presTime), presTime), + willPan: activeItem.presentation_movement !== PresMovement.None, + willZoomCentered: activeItem.presentation_movement === PresMovement.Zoom || activeItem.presentation_movement === PresMovement.Jump || activeItem.presentation_movement === PresMovement.Center, + zoomScale: activeItem.presentation_movement === PresMovement.Center ? 0 : NumCast(activeItem.presZoom, 1), + zoomTime: activeItem.presentation_movement === PresMovement.Jump ? 0 : Math.min(Math.max(effect ? 750 : 500, (effect ? 0.2 : 1) * presTime), presTime), effect: activeItem, noSelect: true, openLocation: OpenWhere.addLeft, anchorDoc: activeItem, easeFunc: StrCast(activeItem.presEaseFunc, 'ease') as any, - zoomTextSelections: BoolCast(activeItem.presZoomText), + zoomTextSelections: BoolCast(activeItem.presentation_zoomText), playAudio: BoolCast(activeItem.presPlayAudio), }; if (activeItem.presOpenInLightbox) { @@ -738,7 +740,7 @@ export class PresBox extends ViewBoxBaseComponent() { } } if (targetDoc) { - if (activeItem.presentationTargetDoc instanceof Doc) activeItem.presentationTargetDoc[Animation] = undefined; + if (activeItem.presentation_targetDoc instanceof Doc) activeItem.presentation_targetDoc[Animation] = undefined; DocumentManager.Instance.AddViewRenderedCb(LightboxView.LightboxDoc, dv => { // if target or the doc it annotates is not in the lightbox, then close the lightbox @@ -761,16 +763,16 @@ export class PresBox extends ViewBoxBaseComponent() { const tagDoc = PresBox.targetRenderedDoc(curDoc); const itemIndexes: number[] = this.getAllIndexes(this.tagDocs, tagDoc); let opacity: Opt = index === this.itemIndex ? 1 : undefined; - if (curDoc.presHide) { + if (curDoc.presentation_hide) { if (index !== this.itemIndex) { opacity = 1; } } const hidingIndBef = itemIndexes.find(item => item >= this.itemIndex) ?? itemIndexes.slice().reverse().lastElement(); - if (curDoc.presHideBefore && index === hidingIndBef) { + if (curDoc.presentation_hideBefore && index === hidingIndBef) { if (index > this.itemIndex) { opacity = 0; - } else if (index === this.itemIndex || !curDoc.presHideAfter) { + } else if (index === this.itemIndex || !curDoc.presentation_hideAfter) { opacity = 1; setTimeout(() => (tagDoc._dataTransition = undefined), 1000); } @@ -780,15 +782,15 @@ export class PresBox extends ViewBoxBaseComponent() { .slice() .reverse() .find(item => item <= this.itemIndex) ?? itemIndexes.lastElement(); - if (curDoc.presHideAfter && index === hidingIndAft) { + if (curDoc.presentation_hideAfter && index === hidingIndAft) { if (index < this.itemIndex) { opacity = 0; - } else if (index === this.itemIndex || !curDoc.presHideBefore) { + } else if (index === this.itemIndex || !curDoc.presentation_hideBefore) { opacity = 1; } } const hidingInd = itemIndexes.find(item => item === this.itemIndex); - if (curDoc.presHide && index === hidingInd) { + if (curDoc.presentation_hide && index === hidingInd) { if (index === this.itemIndex) { opacity = 0; } @@ -846,9 +848,9 @@ export class PresBox extends ViewBoxBaseComponent() { // The function pauses the auto presentation @action pauseAutoPres = () => { - if (this.layoutDoc.presStatus === PresStatus.Autoplay) { + if (this.layoutDoc.presentation_status === PresStatus.Autoplay) { if (this._presTimer) clearTimeout(this._presTimer); - this.layoutDoc.presStatus = PresStatus.Manual; + this.layoutDoc.presentation_status = PresStatus.Manual; this.childDocs.forEach(this.stopTempMedia); } }; @@ -879,23 +881,23 @@ export class PresBox extends ViewBoxBaseComponent() { runInAction(() => (this._expandBoolean = !this._expandBoolean)); this.rootDoc.expandBoolean = this._expandBoolean; this.childDocs.forEach(doc => { - doc.presExpandInlineButton = this._expandBoolean; + doc.presentation_expandInlineButton = this._expandBoolean; }); }; initializePresState = (startIndex: number) => { this.childDocs.forEach((doc, index) => { const tagDoc = PresBox.targetRenderedDoc(doc); - if (doc.presHideBefore && index > startIndex) tagDoc.opacity = 0; - if (doc.presHideAfter && index < startIndex) tagDoc.opacity = 0; - if (doc.presIndexed !== undefined && index >= startIndex) { - const startInd = NumCast(doc.presIndexedStart); + if (doc.presentation_hideBefore && index > startIndex) tagDoc.opacity = 0; + if (doc.presentation_hideAfter && index < startIndex) tagDoc.opacity = 0; + if (doc.presentation_indexed !== undefined && index >= startIndex) { + const startInd = NumCast(doc.presentation_indexedStart); this.progressivizedItems(doc) ?.slice(startInd) .forEach(indexedDoc => (indexedDoc.opacity = 0)); - doc.presIndexed = Math.min(this.progressivizedItems(doc)?.length ?? 0, startInd); + doc.presentation_indexed = Math.min(this.progressivizedItems(doc)?.length ?? 0, startInd); } - // if (doc.presHide && this.childDocs.indexOf(doc) === startIndex) tagDoc.opacity = 0; + // if (doc.presentation_hide && this.childDocs.indexOf(doc) === startIndex) tagDoc.opacity = 0; }); }; @@ -909,13 +911,13 @@ export class PresBox extends ViewBoxBaseComponent() { PresBox.Instance = this; clearTimeout(this._presTimer); if (this.childDocs.length) { - this.layoutDoc.presStatus = PresStatus.Autoplay; + this.layoutDoc.presentation_status = PresStatus.Autoplay; this.initializePresState(startIndex); const func = () => { - const delay = NumCast(this.activeItem.presDuration, this.activeItem.type === DocumentType.SCRIPTING ? 0 : 2500) + NumCast(this.activeItem.presTransition); + const delay = NumCast(this.activeItem.presentation_duration, this.activeItem.type === DocumentType.SCRIPTING ? 0 : 2500) + NumCast(this.activeItem.presentation_transition); this._presTimer = setTimeout(() => { - if (!this.next()) this.layoutDoc.presStatus = this._exitTrail?.() ?? PresStatus.Manual; - this.layoutDoc.presStatus === PresStatus.Autoplay && func(); + if (!this.next()) this.layoutDoc.presentation_status = this._exitTrail?.() ?? PresStatus.Manual; + this.layoutDoc.presentation_status === PresStatus.Autoplay && func(); }, delay); }; this.gotoDocument(startIndex, this.activeItem, undefined, func); @@ -949,7 +951,7 @@ export class PresBox extends ViewBoxBaseComponent() { doc._width = PresBox.minimizedWidth; Doc.AddToMyOverlay(doc); PresBox.Instance?.initializePresState(PresBox.Instance.itemIndex); - return (doc.presStatus = PresStatus.Manual); + return (doc.presentation_status = PresStatus.Manual); } /** @@ -993,34 +995,34 @@ export class PresBox extends ViewBoxBaseComponent() { }); movementName = action((activeItem: Doc) => { - if (![PresMovement.Zoom, PresMovement.Pan, PresMovement.Center, PresMovement.Jump, PresMovement.None].includes(StrCast(activeItem.presMovement) as any)) { + if (![PresMovement.Zoom, PresMovement.Pan, PresMovement.Center, PresMovement.Jump, PresMovement.None].includes(StrCast(activeItem.presentation_movement) as any)) { return PresMovement.Zoom; } - return StrCast(activeItem.presMovement); + return StrCast(activeItem.presentation_movement); }); whenChildContentsActiveChanged = action((isActive: boolean) => this.props.whenChildContentsActiveChanged((this._isChildActive = isActive))); // For dragging documents into the presentation trail addDocumentFilter = (docs: Doc[]) => { docs.forEach((doc, i) => { - if (doc.presentationTargetDoc) return true; + if (doc.presentation_targetDoc) return true; if (doc.type === DocumentType.LABEL) { const audio = Cast(doc.annotationOn, Doc, null); if (audio) { audio.mediaStart = 'manual'; audio.mediaStop = 'manual'; - audio.presStartTime = NumCast(doc._timecodeToShow /* audioStart */, NumCast(doc._timecodeToShow /* videoStart */)); - audio.presEndTime = NumCast(doc._timecodeToHide /* audioEnd */, NumCast(doc._timecodeToHide /* videoEnd */)); - audio.presDuration = audio.presStartTime - audio.presEndTime; + audio.config_clipStart = NumCast(doc._timecodeToShow /* audioStart */, NumCast(doc._timecodeToShow /* videoStart */)); + audio.config_clipEnd = NumCast(doc._timecodeToHide /* audioEnd */, NumCast(doc._timecodeToHide /* videoEnd */)); + audio.presentation_duration = audio.config_clipStart - audio.config_clipEnd; TabDocView.PinDoc(audio, { audioRange: true }); setTimeout(() => this.removeDocument(doc), 0); return false; } } else { - if (!doc.presentationTargetDoc) doc.title = doc.title + ' - Slide'; - doc.presentationTargetDoc = doc.createdFrom; // dropped document will be a new embedding of an embedded document somewhere else. - doc.presMovement = PresMovement.Zoom; - if (this._expandBoolean) doc.presExpandInlineButton = true; + if (!doc.presentation_targetDoc) doc.title = doc.title + ' - Slide'; + doc.presentation_targetDoc = doc.createdFrom; // dropped document will be a new embedding of an embedded document somewhere else. + doc.presentation_movement = PresMovement.Zoom; + if (this._expandBoolean) doc.presentation_expandInlineButton = true; } }); return true; @@ -1040,7 +1042,7 @@ export class PresBox extends ViewBoxBaseComponent() { @computed get listOfSelected() { return Array.from(this.selectedArray).map((doc: Doc, index: any) => { const curDoc = Cast(doc, Doc, null); - const tagDoc = Cast(curDoc.presentationTargetDoc, Doc, null); + const tagDoc = Cast(curDoc.presentation_targetDoc, Doc, null); if (curDoc && curDoc === this.activeItem) return (
    @@ -1146,7 +1148,7 @@ export class PresBox extends ViewBoxBaseComponent() { if (anchorNode && anchorNode.className?.includes('lm_title')) return; switch (e.key) { case 'Backspace': - if (this.layoutDoc.presStatus === 'edit') { + if (this.layoutDoc.presentation_status === 'edit') { undoBatch( action(() => { for (const doc of this.selectedArray) { @@ -1163,11 +1165,11 @@ export class PresBox extends ViewBoxBaseComponent() { case 'Escape': if (Doc.IsInMyOverlay(this.layoutDoc)) { this.exitClicked(); - } else if (this.layoutDoc.presStatus === PresStatus.Edit) { + } else if (this.layoutDoc.presentation_status === PresStatus.Edit) { this.clearSelectedArray(); this._eleArray.length = this._dragArray.length = 0; } else { - this.layoutDoc.presStatus = PresStatus.Edit; + this.layoutDoc.presentation_status = PresStatus.Edit; } if (this._presTimer) clearTimeout(this._presTimer); handled = true; @@ -1184,7 +1186,7 @@ export class PresBox extends ViewBoxBaseComponent() { this.next(); if (this._presTimer) { clearTimeout(this._presTimer); - this.layoutDoc.presStatus = PresStatus.Manual; + this.layoutDoc.presentation_status = PresStatus.Manual; } } handled = true; @@ -1201,19 +1203,19 @@ export class PresBox extends ViewBoxBaseComponent() { this.back(); if (this._presTimer) { clearTimeout(this._presTimer); - this.layoutDoc.presStatus = PresStatus.Manual; + this.layoutDoc.presentation_status = PresStatus.Manual; } } handled = true; break; case 'Spacebar': case ' ': - if (this.layoutDoc.presStatus === PresStatus.Manual) this.startOrPause(true); - else if (this.layoutDoc.presStatus === PresStatus.Autoplay) if (this._presTimer) clearTimeout(this._presTimer); + if (this.layoutDoc.presentation_status === PresStatus.Manual) this.startOrPause(true); + else if (this.layoutDoc.presentation_status === PresStatus.Autoplay) if (this._presTimer) clearTimeout(this._presTimer); handled = true; break; case 'a': - if ((e.metaKey || e.altKey) && this.layoutDoc.presStatus === 'edit') { + if ((e.metaKey || e.altKey) && this.layoutDoc.presentation_status === 'edit') { this.clearSelectedArray(); this.childDocs.forEach(doc => this.addToSelectedArray(doc)); handled = true; @@ -1236,9 +1238,9 @@ export class PresBox extends ViewBoxBaseComponent() { const presCollection = DocumentManager.GetContextPath(this.activeItem).reverse().lastElement(); const dv = DocumentManager.Instance.getDocumentView(presCollection); this.childDocs - .filter(doc => Cast(doc.presentationTargetDoc, Doc, null)) + .filter(doc => Cast(doc.presentation_targetDoc, Doc, null)) .forEach((doc, index) => { - const tagDoc = Cast(doc.presentationTargetDoc, Doc, null); + const tagDoc = Cast(doc.presentation_targetDoc, Doc, null); const srcContext = Cast(tagDoc.embedContainer, Doc, null); const width = NumCast(tagDoc._width) / 10; const height = Math.max(NumCast(tagDoc._height) / 10, 15); @@ -1271,17 +1273,17 @@ export class PresBox extends ViewBoxBaseComponent() {
    ); } - } else if (doc.presPinView && presCollection === tagDoc && dv) { + } else if (doc.config_pinView && presCollection === tagDoc && dv) { // Case B: Document is presPinView and is presCollection - const scale: number = 1 / NumCast(doc.presViewScale); + const scale: number = 1 / NumCast(doc.config_viewScale); const height: number = dv.props.PanelHeight() * scale; const width: number = dv.props.PanelWidth() * scale; const indWidth = width / 10; const indHeight = Math.max(height / 10, 15); const indEdge = Math.max(indWidth, indHeight); const indFontSize = indEdge * 0.8; - const xLoc: number = NumCast(doc.presPanX) - width / 2; - const yLoc: number = NumCast(doc.presPanY) - height / 2; + const xLoc: number = NumCast(doc.config_panX) - width / 2; + const yLoc: number = NumCast(doc.config_panY) - height / 2; docs.push(tagDoc); order.push( <> @@ -1307,15 +1309,15 @@ export class PresBox extends ViewBoxBaseComponent() { @computed get paths() { let pathPoints = ''; this.childDocs.forEach((doc, index) => { - const tagDoc = Cast(doc.presentationTargetDoc, Doc, null); + const tagDoc = Cast(doc.presentation_targetDoc, Doc, null); if (tagDoc) { const n1x = NumCast(tagDoc.x) + NumCast(tagDoc._width) / 2; const n1y = NumCast(tagDoc.y) + NumCast(tagDoc._height) / 2; if ((index = 0)) pathPoints = n1x + ',' + n1y; else pathPoints = pathPoints + ' ' + n1x + ',' + n1y; - } else if (doc.presPinView) { - const n1x = NumCast(doc.presPanX); - const n1y = NumCast(doc.presPanY); + } else if (doc.config_pinView) { + const n1x = NumCast(doc.config_panX); + const n1y = NumCast(doc.config_panY); if ((index = 0)) pathPoints = n1x + ',' + n1y; else pathPoints = pathPoints + ' ' + n1x + ',' + n1y; } @@ -1339,7 +1341,7 @@ export class PresBox extends ViewBoxBaseComponent() { } getPaths = (collection: Doc) => this.paths; // needs to be smarter and figure out the paths to draw for this specific collection. or better yet, draw everything in an overlay layer instad of within a collection - // Converts seconds to ms and updates presTransition + // Converts seconds to ms and updates presentation_transition public static SetTransitionTime = (number: String, setter: (timeInMS: number) => void, change?: number) => { let timeInMS = Number(number) * 1000; if (change) timeInMS += change; @@ -1350,10 +1352,10 @@ export class PresBox extends ViewBoxBaseComponent() { @undoBatch updateTransitionTime = (number: String, change?: number) => { - PresBox.SetTransitionTime(number, (timeInMS: number) => this.selectedArray.forEach(doc => (doc.presTransition = timeInMS)), change); + PresBox.SetTransitionTime(number, (timeInMS: number) => this.selectedArray.forEach(doc => (doc.presentation_transition = timeInMS)), change); }; - // Converts seconds to ms and updates presTransition + // Converts seconds to ms and updates presentation_transition @undoBatch updateZoom = (number: String, change?: number) => { let scale = Number(number) / 100; @@ -1364,7 +1366,7 @@ export class PresBox extends ViewBoxBaseComponent() { }; /* - * Converts seconds to ms and updates presDuration + * Converts seconds to ms and updates presentation_duration */ @undoBatch updateDurationTime = (number: String, change?: number) => { @@ -1372,31 +1374,31 @@ export class PresBox extends ViewBoxBaseComponent() { if (change) timeInMS += change; if (timeInMS < 100) timeInMS = 100; if (timeInMS > 20000) timeInMS = 20000; - this.selectedArray.forEach(doc => (doc.presDuration = timeInMS)); + this.selectedArray.forEach(doc => (doc.presentation_duration = timeInMS)); }; @undoBatch - updateMovement = action((movement: PresMovement, all?: boolean) => (all ? this.childDocs : this.selectedArray).forEach(doc => (doc.presMovement = movement))); + updateMovement = action((movement: PresMovement, all?: boolean) => (all ? this.childDocs : this.selectedArray).forEach(doc => (doc.presentation_movement = movement))); @undoBatch @action updateHideBefore = (activeItem: Doc) => { - activeItem.presHideBefore = !activeItem.presHideBefore; - this.selectedArray.forEach(doc => (doc.presHideBefore = activeItem.presHideBefore)); + activeItem.presentation_hideBefore = !activeItem.presentation_hideBefore; + this.selectedArray.forEach(doc => (doc.presentation_hideBefore = activeItem.presentation_hideBefore)); }; @undoBatch @action updateHide = (activeItem: Doc) => { - activeItem.presHide = !activeItem.presHide; - this.selectedArray.forEach(doc => (doc.presHide = activeItem.presHide)); + activeItem.presentation_hide = !activeItem.presentation_hide; + this.selectedArray.forEach(doc => (doc.presentation_hide = activeItem.presentation_hide)); }; @undoBatch @action updateHideAfter = (activeItem: Doc) => { - activeItem.presHideAfter = !activeItem.presHideAfter; - this.selectedArray.forEach(doc => (doc.presHideAfter = activeItem.presHideAfter)); + activeItem.presentation_hideAfter = !activeItem.presentation_hideAfter; + this.selectedArray.forEach(doc => (doc.presentation_hideAfter = activeItem.presentation_hideAfter)); }; @undoBatch @@ -1415,11 +1417,11 @@ export class PresBox extends ViewBoxBaseComponent() { @undoBatch @action - updateEffectDirection = (effect: PresEffectDirection, all?: boolean) => (all ? this.childDocs : this.selectedArray).forEach(doc => (doc.presEffectDirection = effect)); + updateEffectDirection = (effect: PresEffectDirection, all?: boolean) => (all ? this.childDocs : this.selectedArray).forEach(doc => (doc.presentation_effectDirection = effect)); @undoBatch @action - updateEffect = (effect: PresEffect, bullet: boolean, all?: boolean) => (all ? this.childDocs : this.selectedArray).forEach(doc => (bullet ? (doc.presBulletEffect = effect) : (doc.presEffect = effect))); + updateEffect = (effect: PresEffect, bullet: boolean, all?: boolean) => (all ? this.childDocs : this.selectedArray).forEach(doc => (bullet ? (doc.presBulletEffect = effect) : (doc.presentation_effect = effect))); static _sliderBatch: any; public static inputter = (min: string, step: string, max: string, value: number, active: boolean, change: (val: string) => void, hmargin?: number) => { @@ -1449,16 +1451,16 @@ export class PresBox extends ViewBoxBaseComponent() { @undoBatch @action applyTo = (array: Doc[]) => { - this.updateMovement(this.activeItem.presMovement as PresMovement, true); - this.updateEffect(this.activeItem.presEffect as PresEffect, false, true); + this.updateMovement(this.activeItem.presentation_movement as PresMovement, true); + this.updateEffect(this.activeItem.presentation_effect as PresEffect, false, true); this.updateEffect(this.activeItem.presBulletEffect as PresEffect, true, true); - this.updateEffectDirection(this.activeItem.presEffectDirection as PresEffectDirection, true); - const { presTransition, presDuration, presHideBefore, presHideAfter } = this.activeItem; + this.updateEffectDirection(this.activeItem.presentation_effectDirection as PresEffectDirection, true); + const { presentation_transition, presentation_duration, presentation_hideBefore, presentation_hideAfter } = this.activeItem; array.forEach(curDoc => { - curDoc.presTransition = presTransition; - curDoc.presDuration = presDuration; - curDoc.presHideBefore = presHideBefore; - curDoc.presHideAfter = presHideAfter; + curDoc.presentation_transition = presentation_transition; + curDoc.presentation_duration = presentation_duration; + curDoc.presentation_hideBefore = presentation_hideBefore; + curDoc.presentation_hideAfter = presentation_hideAfter; }); }; @@ -1466,24 +1468,24 @@ export class PresBox extends ViewBoxBaseComponent() { const activeItem = this.activeItem; if (activeItem && this.targetDoc) { const targetType = this.targetDoc.type; - let duration = activeItem.presDuration ? NumCast(activeItem.presDuration) / 1000 : 0; + let duration = activeItem.presentation_duration ? NumCast(activeItem.presentation_duration) / 1000 : 0; if (activeItem.type === DocumentType.AUDIO) duration = NumCast(activeItem.duration); return (
    {'Hide before presented'}
    }> -
    this.updateHideBefore(activeItem)}> +
    this.updateHideBefore(activeItem)}> Hide before
    {'Hide while presented'}
    }> -
    this.updateHide(activeItem)}> +
    this.updateHide(activeItem)}> Hide
    {'Hide after presented'}
    }> -
    this.updateHideAfter(activeItem)}> +
    this.updateHideAfter(activeItem)}> Hide after
    @@ -1532,7 +1534,10 @@ export class PresBox extends ViewBoxBaseComponent() { if (activeItem && this.targetDoc) { const effect = activeItem.presBulletEffect ? activeItem.presBulletEffect : PresMovement.None; const bulletEffect = (effect: PresEffect) => ( -
    this.updateEffect(effect, true)}> +
    this.updateEffect(effect, true)}> {effect}
    ); @@ -1545,25 +1550,31 @@ export class PresBox extends ViewBoxBaseComponent() { style={{ margin: 10 }} type="checkbox" onChange={() => { - activeItem.presIndexed = activeItem.presIndexed === undefined ? 0 : undefined; - activeItem.presHideBefore = activeItem.presIndexed !== undefined; + activeItem.presentation_indexed = activeItem.presentation_indexed === undefined ? 0 : undefined; + activeItem.presentation_hideBefore = activeItem.presentation_indexed !== undefined; const tagDoc = PresBox.targetRenderedDoc(this.activeItem); const type = DocCast(tagDoc?.annotationOn)?.type ?? tagDoc.type; - activeItem.presIndexedStart = type === DocumentType.COL ? 1 : 0; + activeItem.presentation_indexedStart = type === DocumentType.COL ? 1 : 0; // a progressivized slide doesn't have sub-slides, but rather iterates over the data list of the target being progressivized. // to avoid creating a new slide to correspond to each of the target's data list, we create a computedField to refernce the target's data list. let dataField = Doc.LayoutFieldKey(tagDoc); if (Cast(tagDoc[dataField], listSpec(Doc), null)?.filter(d => d instanceof Doc) === undefined) dataField = dataField + '_annotations'; - if (DocCast(activeItem.presentationTargetDoc).annotationOn) activeItem.data = ComputedField.MakeFunction(`self.presentationTargetDoc.annotationOn["${dataField}"]`); - else activeItem.data = ComputedField.MakeFunction(`self.presentationTargetDoc["${dataField}"]`); + if (DocCast(activeItem.presentation_targetDoc).annotationOn) activeItem.data = ComputedField.MakeFunction(`self.presentation_targetDoc.annotationOn["${dataField}"]`); + else activeItem.data = ComputedField.MakeFunction(`self.presentation_targetDoc["${dataField}"]`); }} - checked={Cast(activeItem.presIndexed, 'number', null) !== undefined ? true : false} + checked={Cast(activeItem.presentation_indexed, 'number', null) !== undefined ? true : false} />
    Progressivize First Bullet
    - (activeItem.presIndexedStart = activeItem.presIndexedStart ? 0 : 1)} checked={!NumCast(activeItem.presIndexedStart)} /> + (activeItem.presentation_indexedStart = activeItem.presentation_indexedStart ? 0 : 1)} + checked={!NumCast(activeItem.presentation_indexedStart)} + />
    Expand Current Bullet
    @@ -1598,18 +1609,21 @@ export class PresBox extends ViewBoxBaseComponent() { } @computed get transitionDropdown() { const activeItem = this.activeItem; - const presEffect = (effect: PresEffect) => ( -
    this.updateEffect(effect, false)}> + const preseEffect = (effect: PresEffect) => ( +
    this.updateEffect(effect, false)}> {effect}
    ); const presMovement = (movement: PresMovement) => ( -
    this.updateMovement(movement)}> +
    this.updateMovement(movement)}> {movement}
    ); const presDirection = (direction: PresEffectDirection, icon: string, gridColumn: number, gridRow: number, opts: object) => { - const color = activeItem.presEffectDirection === direction || (direction === PresEffectDirection.Center && !activeItem.presEffectDirection) ? Colors.LIGHT_BLUE : 'black'; + const color = activeItem.presentation_effectDirection === direction || (direction === PresEffectDirection.Center && !activeItem.presentation_effectDirection) ? Colors.LIGHT_BLUE : 'black'; return ( {direction}
    }>
    () { ); }; if (activeItem && this.targetDoc) { - const transitionSpeed = activeItem.presTransition ? NumCast(activeItem.presTransition) / 1000 : 0.5; + const transitionSpeed = activeItem.presentation_transition ? NumCast(activeItem.presentation_transition) / 1000 : 0.5; const zoom = NumCast(activeItem.presZoom, 1) * 100; - const effect = activeItem.presEffect ? activeItem.presEffect : PresMovement.None; + const effect = activeItem.presentation_effect ? activeItem.presentation_effect : PresMovement.None; return (
    { @@ -1654,7 +1668,7 @@ export class PresBox extends ViewBoxBaseComponent() { {presMovement(PresMovement.Jump)}
    -
    +
    Zoom (% screen filled)
    this.updateZoom(e.target.value)} />% @@ -1668,7 +1682,7 @@ export class PresBox extends ViewBoxBaseComponent() {
    - {PresBox.inputter('0', '1', '100', zoom, activeItem.presMovement === PresMovement.Zoom, this.updateZoom)} + {PresBox.inputter('0', '1', '100', zoom, activeItem.presentation_movement === PresMovement.Zoom, this.updateZoom)}
    Transition Time
    @@ -1698,7 +1712,13 @@ export class PresBox extends ViewBoxBaseComponent() {
    Zoom Text Selections
    - (activeItem.presZoomText = !BoolCast(activeItem.presZoomText))} checked={BoolCast(activeItem.presZoomText)} /> + (activeItem.presentation_zoomText = !BoolCast(activeItem.presentation_zoomText))} + checked={BoolCast(activeItem.presentation_zoomText)} + />
    () { {effect?.toString()}
    e.stopPropagation()}> - {presEffect(PresEffect.None)} - {presEffect(PresEffect.Fade)} - {presEffect(PresEffect.Flip)} - {presEffect(PresEffect.Rotate)} - {presEffect(PresEffect.Bounce)} - {presEffect(PresEffect.Roll)} + {preseEffect(PresEffect.None)} + {preseEffect(PresEffect.Fade)} + {preseEffect(PresEffect.Flip)} + {preseEffect(PresEffect.Rotate)} + {preseEffect(PresEffect.Bounce)} + {preseEffect(PresEffect.Roll)}
    Effect direction
    -
    {StrCast(this.activeItem.presEffectDirection)}
    +
    {StrCast(this.activeItem.presentation_effectDirection)}
    {presDirection(PresEffectDirection.Left, 'angle-right', 1, 2, {})} @@ -1760,10 +1780,10 @@ export class PresBox extends ViewBoxBaseComponent() { style={{ textAlign: 'center', width: '100%', height: 15, fontSize: 10 }} type="number" readOnly={true} - value={NumCast(activeItem.presStartTime).toFixed(2)} + value={NumCast(activeItem.config_clipStart).toFixed(2)} onKeyDown={e => e.stopPropagation()} onChange={action((e: React.ChangeEvent) => { - activeItem.presStartTime = Number(e.target.value); + activeItem.config_clipStart = Number(e.target.value); })} />
    @@ -1773,7 +1793,7 @@ export class PresBox extends ViewBoxBaseComponent() { Duration (s)
    - {Math.round((NumCast(activeItem.presEndTime) - NumCast(activeItem.presStartTime)) * 10) / 10} + {Math.round((NumCast(activeItem.config_clipEnd) - NumCast(activeItem.config_clipStart)) * 10) / 10}
    @@ -1787,9 +1807,9 @@ export class PresBox extends ViewBoxBaseComponent() { style={{ textAlign: 'center', width: '100%', height: 15, fontSize: 10 }} type="number" readOnly={true} - value={NumCast(activeItem.presEndTime).toFixed(2)} + value={NumCast(activeItem.config_clipEnd).toFixed(2)} onChange={action((e: React.ChangeEvent) => { - activeItem.presEndTime = Number(e.target.value); + activeItem.config_clipEnd = Number(e.target.value); })} />
    @@ -1801,12 +1821,12 @@ export class PresBox extends ViewBoxBaseComponent() { step="0.1" min={clipStart} max={clipEnd} - value={NumCast(activeItem.presEndTime)} + value={NumCast(activeItem.config_clipEnd)} style={{ gridColumn: 1, gridRow: 1 }} className={`toolbar-slider ${'end'}`} id="toolbar-slider" onPointerDown={e => { - this._batch = UndoManager.StartBatch('presEndTime'); + this._batch = UndoManager.StartBatch('config_clipEnd'); const endBlock = document.getElementById('endTime'); if (endBlock) { endBlock.style.color = Colors.LIGHT_GRAY; @@ -1824,7 +1844,7 @@ export class PresBox extends ViewBoxBaseComponent() { }} onChange={(e: React.ChangeEvent) => { e.stopPropagation(); - activeItem.presEndTime = Number(e.target.value); + activeItem.config_clipEnd = Number(e.target.value); }} /> () { step="0.1" min={clipStart} max={clipEnd} - value={NumCast(activeItem.presStartTime)} + value={NumCast(activeItem.config_clipStart)} style={{ gridColumn: 1, gridRow: 1 }} className={`toolbar-slider ${'start'}`} id="toolbar-slider" onPointerDown={e => { - this._batch = UndoManager.StartBatch('presStartTime'); + this._batch = UndoManager.StartBatch('config_clipStart'); const startBlock = document.getElementById('startTime'); if (startBlock) { startBlock.style.color = Colors.LIGHT_GRAY; @@ -1855,7 +1875,7 @@ export class PresBox extends ViewBoxBaseComponent() { }} onChange={(e: React.ChangeEvent) => { e.stopPropagation(); - activeItem.presStartTime = Number(e.target.value); + activeItem.config_clipStart = Number(e.target.value); }} />
    @@ -1916,7 +1936,7 @@ export class PresBox extends ViewBoxBaseComponent() { return (
    e.stopPropagation()} onPointerUp={e => e.stopPropagation()} onPointerDown={e => e.stopPropagation()}> @@ -2053,10 +2073,10 @@ export class PresBox extends ViewBoxBaseComponent() { if (doc) { const tabMap = CollectionDockingView.Instance?.tabMap; const tab = tabMap && Array.from(tabMap).find(tab => tab.DashDoc.type === DocumentType.COL)?.DashDoc; - const presCollection = DocumentManager.GetContextPath(this.activeItem).reverse().lastElement().presentationTargetDoc ?? tab; + const presCollection = DocumentManager.GetContextPath(this.activeItem).reverse().lastElement().presentation_targetDoc ?? tab; const data = Cast(presCollection?.data, listSpec(Doc)); - const presData = Cast(this.rootDoc.data, listSpec(Doc)); - if (data && presData) { + const config_data = Cast(this.rootDoc.data, listSpec(Doc)); + if (data && config_data) { data.push(doc); TabDocView.PinDoc(doc, {}); this.gotoDocument(this.childDocs.length, this.activeItem); @@ -2105,7 +2125,7 @@ export class PresBox extends ViewBoxBaseComponent() { className="dropdown-play-button" onClick={undoBatch( action(() => { - this.layoutDoc.presStatus = 'manual'; + this.layoutDoc.presentation_status = 'manual'; this.initializePresState(this.itemIndex); this.turnOffEdit(true); this.gotoDocument(this.itemIndex, this.activeItem); @@ -2181,7 +2201,7 @@ export class PresBox extends ViewBoxBaseComponent() { className={`presBox-buttons${Doc.IsInMyOverlay(this.rootDoc) ? ' inOverlay' : ''}`} style={{ background: Doc.ActivePresentation === this.rootDoc ? Colors.LIGHT_BLUE : undefined, display: !this.rootDoc._chromeHidden ? 'none' : undefined }}> {isMini ? null : ( - e.stopPropagation()} onChange={this.viewChanged} value={mode}> @@ -2196,12 +2216,12 @@ export class PresBox extends ViewBoxBaseComponent() { )}
    - +
    { if (this.childDocs.length) { - this.layoutDoc.presStatus = 'manual'; + this.layoutDoc.presentation_status = 'manual'; this.initializePresState(this.itemIndex); this.gotoDocument(this.itemIndex, this.activeItem); } @@ -2227,12 +2247,15 @@ export class PresBox extends ViewBoxBaseComponent() { } @computed get playButtons() { - const presEnd = !this.layoutDoc.presLoop && this.itemIndex === this.childDocs.length - 1 && (this.activeItem.presIndexed === undefined || NumCast(this.activeItem.presIndexed) === (this.progressivizedItems(this.activeItem)?.length ?? 0)); + const presEnd = + !this.layoutDoc.presLoop && + this.itemIndex === this.childDocs.length - 1 && + (this.activeItem.presentation_indexed === undefined || NumCast(this.activeItem.presentation_indexed) === (this.progressivizedItems(this.activeItem)?.length ?? 0)); const presStart: boolean = !this.layoutDoc.presLoop && this.itemIndex === 0; const inOverlay = Doc.IsInMyOverlay(this.rootDoc); // Case 1: There are still other frames and should go through all frames before going to next slide return ( -
    +
    {'Loop'}
    }>
    () { this.back(); if (this._presTimer) { clearTimeout(this._presTimer); - this.layoutDoc.presStatus = PresStatus.Manual; + this.layoutDoc.presentation_status = PresStatus.Manual; } e.stopPropagation(); }, @@ -2265,9 +2288,9 @@ export class PresBox extends ViewBoxBaseComponent() { }>
    - {this.layoutDoc.presStatus === PresStatus.Autoplay ? 'Pause' : 'Autoplay'}
    }> + {this.layoutDoc.presentation_status === PresStatus.Autoplay ? 'Pause' : 'Autoplay'}
    }>
    setupMoveUpEvents(this, e, returnFalse, emptyFunction, () => this.startOrPause(true), false, false)}> - +
    () { this.next(); if (this._presTimer) { clearTimeout(this._presTimer); - this.layoutDoc.presStatus = PresStatus.Manual; + this.layoutDoc.presentation_status = PresStatus.Manual; } e.stopPropagation(); }, @@ -2316,7 +2339,7 @@ export class PresBox extends ViewBoxBaseComponent() {
    this.gotoDocument(0, this.activeItem)} style={{ display: inOverlay || this.props.PanelWidth() > 250 ? 'inline-flex' : 'none' }}> {inOverlay ? '' : 'Slide'} {this.itemIndex + 1} - {this.activeItem?.presIndexed !== undefined ? `(${this.activeItem.presIndexed}/${this.progressivizedItems(this.activeItem)?.length})` : ''} / {this.childDocs.length} + {this.activeItem?.presentation_indexed !== undefined ? `(${this.activeItem.presentation_indexed}/${this.progressivizedItems(this.activeItem)?.length})` : ''} / {this.childDocs.length}
    {this.props.PanelWidth() > 250 ? ( @@ -2324,7 +2347,7 @@ export class PresBox extends ViewBoxBaseComponent() { className="presPanel-button-text" onClick={undoBatch( action(() => { - this.layoutDoc.presStatus = PresStatus.Edit; + this.layoutDoc.presentation_status = PresStatus.Edit; clearTimeout(this._presTimer); }) )}> @@ -2342,7 +2365,7 @@ export class PresBox extends ViewBoxBaseComponent() { @action startOrPause = (makeActive = true) => { makeActive && this.updateCurrentPresentation(); - if (!this.layoutDoc.presStatus || this.layoutDoc.presStatus === PresStatus.Manual || this.layoutDoc.presStatus === PresStatus.Edit) this.startPresentation(this.itemIndex); + if (!this.layoutDoc.presentation_status || this.layoutDoc.presentation_status === PresStatus.Manual || this.layoutDoc.presentation_status === PresStatus.Edit) this.startPresentation(this.itemIndex); else this.pauseAutoPres(); }; @@ -2351,7 +2374,7 @@ export class PresBox extends ViewBoxBaseComponent() { this.back(); if (this._presTimer) { clearTimeout(this._presTimer); - this.layoutDoc.presStatus = PresStatus.Manual; + this.layoutDoc.presentation_status = PresStatus.Manual; } }; @@ -2360,19 +2383,19 @@ export class PresBox extends ViewBoxBaseComponent() { this.next(); if (this._presTimer) { clearTimeout(this._presTimer); - this.layoutDoc.presStatus = PresStatus.Manual; + this.layoutDoc.presentation_status = PresStatus.Manual; } }; @undoBatch @action exitClicked = () => { - this.layoutDoc.presStatus = this._exitTrail?.() ?? this.exitMinimize(); + this.layoutDoc.presentation_status = this._exitTrail?.() ?? this.exitMinimize(); clearTimeout(this._presTimer); }; AddToMap = (treeViewDoc: Doc, index: number[]) => { - if (!treeViewDoc.presentationTargetDoc) return this.childDocs; // if treeViewDoc is not a pres elements, then it's a sub-bullet of a progressivized slide which isn't added to the linearized list of pres elements since it's not really a pres element. + if (!treeViewDoc.presentation_targetDoc) return this.childDocs; // if treeViewDoc is not a pres elements, then it's a sub-bullet of a progressivized slide which isn't added to the linearized list of pres elements since it's not really a pres element. var indexNum = 0; for (let i = 0; i < index.length; i++) { indexNum += index[i] * 10 ** -i; @@ -2388,20 +2411,23 @@ export class PresBox extends ViewBoxBaseComponent() { }; RemFromMap = (treeViewDoc: Doc, index: number[]) => { - if (!treeViewDoc.presentationTargetDoc) return this.childDocs; // if treeViewDoc is not a pres elements, then it's a sub-bullet of a progressivized slide which isn't added to the linearized list of pres elements since it's not really a pres element. + if (!treeViewDoc.presentation_targetDoc) return this.childDocs; // if treeViewDoc is not a pres elements, then it's a sub-bullet of a progressivized slide which isn't added to the linearized list of pres elements since it's not really a pres element. if (!this._unmounting && this.isTree) { this._treeViewMap.delete(treeViewDoc); this.dataDoc[this.presFieldKey] = new List(this.sort(this._treeViewMap)); } }; - sort = (treeViewMap: Map) => [...treeViewMap.entries()].sort((a: [Doc, number], b: [Doc, number]) => (a[1] > b[1] ? 1 : a[1] < b[1] ? -1 : 0)).map(kv => kv[0]); + sort = (treeView_Map: Map) => [...treeView_Map.entries()].sort((a: [Doc, number], b: [Doc, number]) => (a[1] > b[1] ? 1 : a[1] < b[1] ? -1 : 0)).map(kv => kv[0]); render() { // needed to ensure that the childDocs are loaded for looking up fields this.childDocs.slice(); const mode = StrCast(this.rootDoc._type_collection) as CollectionViewType; - const presEnd = !this.layoutDoc.presLoop && this.itemIndex === this.childDocs.length - 1 && (this.activeItem.presIndexed === undefined || NumCast(this.activeItem.presIndexed) === (this.progressivizedItems(this.activeItem)?.length ?? 0)); + const presEnd = + !this.layoutDoc.presLoop && + this.itemIndex === this.childDocs.length - 1 && + (this.activeItem.presentation_indexed === undefined || NumCast(this.activeItem.presentation_indexed) === (this.progressivizedItems(this.activeItem)?.length ?? 0)); const presStart = !this.layoutDoc.presLoop && this.itemIndex === 0; return this.props.addDocTab === returnFalse ? ( // bcz: hack!! - addDocTab === returnFalse only when this is being rendered by the OverlayView which means the doc is a mini player
    e.stopPropagation()} onPointerEnter={action(e => (this._forceKeyEvents = true))}> @@ -2420,9 +2446,9 @@ export class PresBox extends ViewBoxBaseComponent() {
    setupMoveUpEvents(this, e, returnFalse, returnFalse, this.prevClicked, false, false)}>
    - {this.layoutDoc.presStatus === PresStatus.Autoplay ? 'Pause' : 'Autoplay'}
    }> + {this.layoutDoc.presentation_status === PresStatus.Autoplay ? 'Pause' : 'Autoplay'}
    }>
    setupMoveUpEvents(this, e, returnFalse, returnFalse, () => this.startOrPause(true), false, false)}> - +
    setupMoveUpEvents(this, e, returnFalse, returnFalse, this.nextClicked, false, false)}> @@ -2436,7 +2462,7 @@ export class PresBox extends ViewBoxBaseComponent() {
    Slide {this.itemIndex + 1} - {this.activeItem?.presIndexed !== undefined ? `(${this.activeItem.presIndexed}/${this.progressivizedItems(this.activeItem)?.length})` : ''} / {this.childDocs.length} + {this.activeItem?.presentation_indexed !== undefined ? `(${this.activeItem.presentation_indexed}/${this.progressivizedItems(this.activeItem)?.length})` : ''} / {this.childDocs.length}
    setupMoveUpEvents(this, e, returnFalse, returnFalse, this.exitClicked, false, false)}> @@ -2460,6 +2486,7 @@ export class PresBox extends ViewBoxBaseComponent() { moveDocument={returnFalse} ignoreUnrendered={true} childDragAction="move" + setContentView={emptyFunction} //childLayoutFitWidth={returnTrue} childOpacity={returnOne} childClickScript={PresBox.navigateToDocScript} diff --git a/src/client/views/nodes/trails/PresElementBox.tsx b/src/client/views/nodes/trails/PresElementBox.tsx index f31cf6147..aa514be3b 100644 --- a/src/client/views/nodes/trails/PresElementBox.tsx +++ b/src/client/views/nodes/trails/PresElementBox.tsx @@ -58,13 +58,13 @@ export class PresElementBox extends ViewBoxBaseComponent() { return this.props.DocumentView?.().props.docViewPath().lastElement()?.rootDoc; } @computed get targetDoc() { - return Cast(this.rootDoc.presentationTargetDoc, Doc, null) || this.rootDoc; + return Cast(this.rootDoc.presentation_targetDoc, Doc, null) || this.rootDoc; } componentDidMount() { this.layoutDoc.layout_hideLinkButton = true; this._heightDisposer = reaction( - () => ({ expand: this.rootDoc.presExpandInlineButton, height: this.collapsedHeight }), + () => ({ expand: this.rootDoc.presentation_expandInlineButton, height: this.collapsedHeight }), ({ expand, height }) => (this.layoutDoc._height = height + (expand ? this.expandViewHeight : 0)), { fireImmediately: true } ); @@ -79,7 +79,7 @@ export class PresElementBox extends ViewBoxBaseComponent() { ScreenToLocalListTransform = (xCord: number, yCord: number) => [xCord, yCord]; @action - presExpandDocumentClick = () => (this.rootDoc.presExpandInlineButton = !this.rootDoc.presExpandInlineButton); + presExpandDocumentClick = () => (this.rootDoc.presentation_expandInlineButton = !this.rootDoc.presentation_expandInlineButton); embedHeight = (): number => this.collapsedHeight + this.expandViewHeight; // embedWidth = () => this.props.PanelWidth(); @@ -94,7 +94,7 @@ export class PresElementBox extends ViewBoxBaseComponent() { * presentation element. */ @computed get renderEmbeddedInline() { - return !this.rootDoc.presExpandInlineButton || !this.targetDoc ? null : ( + return !this.rootDoc.presentation_expandInlineButton || !this.targetDoc ? null : (
    () { @computed get transition() { let transitionInS: number; - if (this.rootDoc.presTransition) transitionInS = NumCast(this.rootDoc.presTransition) / 1000; + if (this.rootDoc.presentation_transition) transitionInS = NumCast(this.rootDoc.presentation_transition) / 1000; else transitionInS = 0.5; - return this.rootDoc.presMovement === PresMovement.Jump || this.rootDoc.presMovement === PresMovement.None ? null : 'M: ' + transitionInS + 's'; + return this.rootDoc.presentation_movement === PresMovement.Jump || this.rootDoc.presentation_movement === PresMovement.None ? null : 'M: ' + transitionInS + 's'; } private _itemRef: React.RefObject = React.createRef(); @@ -238,7 +238,7 @@ export class PresElementBox extends ViewBoxBaseComponent() { onPointerMove = (e: PointerEvent) => { const slide = this._itemRef.current!; - const dragIsPresItem = DragManager.docsBeingDragged.some(d => d.presentationTargetDoc); + const dragIsPresItem = DragManager.docsBeingDragged.some(d => d.presentation_targetDoc); if (slide && dragIsPresItem) { const rect = slide.getBoundingClientRect(); const y = e.clientY - rect.top; //y position within the element. @@ -296,12 +296,12 @@ export class PresElementBox extends ViewBoxBaseComponent() { @action updateCapturedContainerLayout = (presTargetDoc: Doc, activeItem: Doc) => { const targetDoc = DocCast(presTargetDoc.annotationOn) ?? presTargetDoc; - activeItem.presX = NumCast(targetDoc.x); - activeItem.presY = NumCast(targetDoc.y); - activeItem.presRotation = NumCast(targetDoc.rotation); - activeItem.presWidth = NumCast(targetDoc.width); - activeItem.presHeight = NumCast(targetDoc.height); - activeItem.presPinLayout = true; + activeItem.config_x = NumCast(targetDoc.x); + activeItem.config_y = NumCast(targetDoc.y); + activeItem.config_rotation = NumCast(targetDoc.rotation); + activeItem.config_width = NumCast(targetDoc.width); + activeItem.config_height = NumCast(targetDoc.height); + activeItem.config_pinLayout = true; }; /** * Method called for updating the view of the currently selected document @@ -421,7 +421,7 @@ export class PresElementBox extends ViewBoxBaseComponent() {
    setupMoveUpEvents(this, e, returnFalse, emptyFunction, () => this.updateCapturedContainerLayout(targetDoc, activeItem), true)} - style={{ opacity: activeItem.presPinLayout ? 1 : 0.5, fontWeight: 700, display: 'flex' }}> + style={{ opacity: activeItem.config_pinLayout ? 1 : 0.5, fontWeight: 700, display: 'flex' }}> L
    @@ -431,7 +431,7 @@ export class PresElementBox extends ViewBoxBaseComponent() {
    setupMoveUpEvents(this, e, returnFalse, emptyFunction, () => this.updateCapturedViewContents(targetDoc, activeItem))} - style={{ opacity: activeItem.presPinData || activeItem.presPinView ? 1 : 0.5, fontWeight: 700, display: 'flex' }}> + style={{ opacity: activeItem.config_pinData || activeItem.config_pinView ? 1 : 0.5, fontWeight: 700, display: 'flex' }}> C
    @@ -445,19 +445,19 @@ export class PresElementBox extends ViewBoxBaseComponent() { ); if (this.indexInPres !== 0) { items.push( - {activeItem.groupWithUp ? 'Ungroup' : 'Group with up'}
    }> + {activeItem.presentation_groupWithUp ? 'Ungroup' : 'Group with up'}
    }>
    (activeItem.groupWithUp = (NumCast(activeItem.groupWithUp) + 1) % 3)} + onClick={() => (activeItem.presentation_groupWithUp = (NumCast(activeItem.presentation_groupWithUp) + 1) % 3)} style={{ zIndex: 1000 - this.indexInPres, fontWeight: 700, - backgroundColor: activeItem.groupWithUp ? (presColorBool ? presBoxColor : Colors.MEDIUM_BLUE) : undefined, - outline: NumCast(activeItem.groupWithUp) > 1 ? 'solid black 1px' : undefined, - height: activeItem.groupWithUp ? 53 : 18, - transform: activeItem.groupWithUp ? 'translate(0, -17px)' : undefined, + backgroundColor: activeItem.presentation_groupWithUp ? (presColorBool ? presBoxColor : Colors.MEDIUM_BLUE) : undefined, + outline: NumCast(activeItem.presentation_groupWithUp) > 1 ? 'solid black 1px' : undefined, + height: activeItem.presentation_groupWithUp ? 53 : 18, + transform: activeItem.presentation_groupWithUp ? 'translate(0, -17px)' : undefined, }}> -
    +
    e.stopPropagation()} />
    @@ -465,14 +465,14 @@ export class PresElementBox extends ViewBoxBaseComponent() { ); } items.push( - {this.rootDoc.presExpandInlineButton ? 'Minimize' : 'Expand'}
    }> + {this.rootDoc.presentation_expandInlineButton ? 'Minimize' : 'Expand'}
    }>
    { e.stopPropagation(); this.presExpandDocumentClick(); }}> - e.stopPropagation()} /> + e.stopPropagation()} />
    ); @@ -534,7 +534,7 @@ export class PresElementBox extends ViewBoxBaseComponent() { style={{ display: 'inline-flex', pointerEvents: isSelected ? undefined : 'none', - width: `calc(100% ${this.rootDoc.presExpandInlineButton ? '- 50%' : ''} - ${this.presButtons.length * 22}px`, + width: `calc(100% ${this.rootDoc.presentation_expandInlineButton ? '- 50%' : ''} - ${this.presButtons.length * 22}px`, cursor: isSelected ? 'text' : 'grab', }}>
    { render() { return (
    - {DocListCast(this.props.anno.textInlineAnnotations).map(a => ( + {DocListCast(this.props.anno.text_inlineAnnotations).map(a => ( ))}
    @@ -61,7 +61,7 @@ class RegionAnnotation extends React.Component { isTargetToggler = () => BoolCast(this.annoTextRegion.followLinkToggle); @undoBatch showTargetTrail = (anchor: Doc) => { - const trail = DocCast(anchor.presTrail); + const trail = DocCast(anchor.presentationTrail); if (trail) { Doc.ActivePresentation = trail; this.props.addDocTab(trail, OpenWhere.replaceRight); diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx index 1319a236d..395fbd1ca 100644 --- a/src/client/views/pdf/PDFViewer.tsx +++ b/src/client/views/pdf/PDFViewer.tsx @@ -68,7 +68,7 @@ export class PDFViewer extends React.Component { private _styleRule: any; // stylesheet rule for making hyperlinks clickable private _retries = 0; // number of times tried to create the PDF viewer private _setPreviewCursor: undefined | ((x: number, y: number, drag: boolean, hide: boolean) => void); - private _setBrushViewer: undefined | ((view: { width: number; height: number; panX: number; panY: number }) => void); + private _setBrushViewer: undefined | ((view: { width: number; height: number; panX: number; panY: number }, transTime: number) => void); private _annotationLayer: React.RefObject = React.createRef(); private _disposers: { [name: string]: IReactionDisposer } = {}; private _viewer: React.RefObject = React.createRef(); @@ -95,7 +95,7 @@ export class PDFViewer extends React.Component { return DocUtils.FilterDocs(DocListCast(this.props.dataDoc[this.props.fieldKey + '_annotations']), this.props.childFilters(), this.props.childFiltersByRanges()); } @computed get inlineTextAnnotations() { - return this.allAnnotations.filter(a => a.textInlineAnnotations); + return this.allAnnotations.filter(a => a.text_inlineAnnotations); } componentDidMount = async () => { @@ -195,7 +195,7 @@ export class PDFViewer extends React.Component { return focusSpeed; }; crop = (region: Doc | undefined, addCrop?: boolean) => this.props.crop(region, addCrop); - brushView = (view: { width: number; height: number; panX: number; panY: number }) => this._setBrushViewer?.(view); + brushView = (view: { width: number; height: number; panX: number; panY: number }, transTime: number) => this._setBrushViewer?.(view, transTime); @action setupPdfJsViewer = async () => { @@ -470,7 +470,7 @@ export class PDFViewer extends React.Component { }; setPreviewCursor = (func?: (x: number, y: number, drag: boolean, hide: boolean) => void) => (this._setPreviewCursor = func); - setBrushViewer = (func?: (view: { width: number; height: number; panX: number; panY: number }) => void) => (this._setBrushViewer = func); + setBrushViewer = (func?: (view: { width: number; height: number; panX: number; panY: number }, transTime: number) => void) => (this._setBrushViewer = func); @action onZoomWheel = (e: React.WheelEvent) => { diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts index eb52cff88..d3912b8a0 100644 --- a/src/fields/Doc.ts +++ b/src/fields/Doc.ts @@ -1363,9 +1363,9 @@ export namespace Doc { UnhighlightWatchers.push(watcher); } else watcher(); } - export function linkFollowHighlight(destDoc: Doc | Doc[], dataAndDisplayDocs = true, presEffect?: Doc) { + export function linkFollowHighlight(destDoc: Doc | Doc[], dataAndDisplayDocs = true, presentation_effect?: Doc) { linkFollowUnhighlight(); - (destDoc instanceof Doc ? [destDoc] : destDoc).forEach(doc => Doc.HighlightDoc(doc, dataAndDisplayDocs, presEffect)); + (destDoc instanceof Doc ? [destDoc] : destDoc).forEach(doc => Doc.HighlightDoc(doc, dataAndDisplayDocs, presentation_effect)); document.removeEventListener('pointerdown', linkFollowUnhighlight); document.addEventListener('pointerdown', linkFollowUnhighlight); if (UnhighlightTimer) clearTimeout(UnhighlightTimer); @@ -1380,11 +1380,11 @@ export namespace Doc { if (!doc || GetEffectiveAcl(doc) === AclPrivate || GetEffectiveAcl(Doc.GetProto(doc)) === AclPrivate || doc.opacity === 0) return false; return doc[Highlight] || Doc.GetProto(doc)[Highlight]; } - export function HighlightDoc(doc: Doc, dataAndDisplayDocs = true, presEffect?: Doc) { + export function HighlightDoc(doc: Doc, dataAndDisplayDocs = true, presentation_effect?: Doc) { runInAction(() => { highlightedDocs.add(doc); doc[Highlight] = true; - doc[Animation] = presEffect; + doc[Animation] = presentation_effect; if (dataAndDisplayDocs) { highlightedDocs.add(Doc.GetProto(doc)); Doc.GetProto(doc)[Highlight] = true; diff --git a/src/fields/documentSchemas.ts b/src/fields/documentSchemas.ts index 76b287be7..e33a17416 100644 --- a/src/fields/documentSchemas.ts +++ b/src/fields/documentSchemas.ts @@ -72,11 +72,11 @@ export const documentSchema = createSchema({ stroke_endMarker: 'string', stroke_dash: 'string', textTransform: 'string', - treeViewOpen: 'boolean', // flag denoting whether the documents sub-tree (contents) is visible or hidden - treeViewExpandedView: 'string', // name of field whose contents are being displayed as the document's subtree - treeViewExpandedViewLock: 'boolean', // whether the expanded view can be changed - treeViewOpenIsTransient: 'boolean', // ignores the treeViewOpen flag (for allowing a view to not be slaved to other views of the document) - treeViewType: 'string', // whether tree view is an outline, file syste or (default) hierarchy. For outline, clicks edit document titles immediately since double-click opening is turned off + treeView_Open: 'boolean', // flag denoting whether the documents sub-tree (contents) is visible or hidden + treeView_ExpandedView: 'string', // name of field whose contents are being displayed as the document's subtree + treeView_ExpandedViewLock: 'boolean', // whether the expanded view can be changed + treeView_OpenIsTransient: 'boolean', // ignores the treeView_Open flag (for allowing a view to not be slaved to other views of the document) + treeView_Type: 'string', // whether tree view is an outline, file syste or (default) hierarchy. For outline, clicks edit document titles immediately since double-click opening is turned off // interaction and linking properties ignoreClick: 'boolean', // whether documents ignores input clicks (but does not ignore manipulation and other events) -- cgit v1.2.3-70-g09d2 From 18b3b9e5eab4a7902390033feb0a1c7e379cf7d6 Mon Sep 17 00:00:00 2001 From: srichman333 Date: Thu, 17 Aug 2023 10:41:34 -0400 Subject: text tells user to select more / different data bug fix + other console error fixes --- src/client/views/nodes/DataVizBox/DataVizBox.tsx | 4 ++-- src/client/views/nodes/DataVizBox/components/Histogram.tsx | 2 +- src/client/views/nodes/DataVizBox/components/LineChart.tsx | 2 +- src/client/views/nodes/DataVizBox/components/PieChart.tsx | 2 +- src/client/views/nodes/DataVizBox/components/TableBox.tsx | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) (limited to 'src/client/views/nodes/DataVizBox/components/TableBox.tsx') diff --git a/src/client/views/nodes/DataVizBox/DataVizBox.tsx b/src/client/views/nodes/DataVizBox/DataVizBox.tsx index 0cc73f32f..220a082d1 100644 --- a/src/client/views/nodes/DataVizBox/DataVizBox.tsx +++ b/src/client/views/nodes/DataVizBox/DataVizBox.tsx @@ -1,4 +1,4 @@ -import { action, computed, ObservableMap, ObservableSet } from 'mobx'; +import { action, computed, ObservableMap } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; import { Doc, Field, StrListCast } from '../../../../fields/Doc'; @@ -108,6 +108,7 @@ export class DataVizBox extends ViewBoxAnnotatableComponent() { componentDidMount() { this.props.setContentView?.(this); this.fetchData(); + if (!this.layoutDoc._dataVizView) this.layoutDoc._dataVizView = this.dataVizView; } fetchData() { @@ -118,7 +119,6 @@ export class DataVizBox extends ViewBoxAnnotatableComponent() { } render() { - if (!this.layoutDoc._dataVizView) this.layoutDoc._dataVizView = this.dataVizView; return !this.pairs?.length ? ( // displays how to get data into the DataVizBox if its empty
    diff --git a/src/client/views/nodes/DataVizBox/components/Histogram.tsx b/src/client/views/nodes/DataVizBox/components/Histogram.tsx index df6aac6bc..e078043c1 100644 --- a/src/client/views/nodes/DataVizBox/components/Histogram.tsx +++ b/src/client/views/nodes/DataVizBox/components/Histogram.tsx @@ -429,7 +429,7 @@ export class Histogram extends React.Component { this.componentDidMount(); - if (this._histogramData.length>0){ + if (this._histogramData.length>0 || (!this.incomingLinks || this.incomingLinks.length==0)){ return ( this.props.axes.length >= 1 ? (
    diff --git a/src/client/views/nodes/DataVizBox/components/LineChart.tsx b/src/client/views/nodes/DataVizBox/components/LineChart.tsx index 8bace941f..468780185 100644 --- a/src/client/views/nodes/DataVizBox/components/LineChart.tsx +++ b/src/client/views/nodes/DataVizBox/components/LineChart.tsx @@ -358,7 +358,7 @@ export class LineChart extends React.Component { else if (this.props.axes.length>0) titleAccessor = '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){ + if (this._lineChartData.length>0 || (!this.incomingLinks || this.incomingLinks.length==0)){ return ( this.props.axes.length>=2 && /\d/.test(this.props.pairs[0][this.props.axes[0]]) && /\d/.test(this.props.pairs[0][this.props.axes[1]]) ? (
    diff --git a/src/client/views/nodes/DataVizBox/components/PieChart.tsx b/src/client/views/nodes/DataVizBox/components/PieChart.tsx index 0c54d0a4e..657d496aa 100644 --- a/src/client/views/nodes/DataVizBox/components/PieChart.tsx +++ b/src/client/views/nodes/DataVizBox/components/PieChart.tsx @@ -337,7 +337,7 @@ export class PieChart extends React.Component { var sliceColors = StrListCast(this.props.layoutDoc.pieSliceColors).map(each => each.split('::')); sliceColors.map(each => {if (each[0]==curSelectedSliceName!) selectedSliceColor = each[1]}); - if (this._piechartData.length>0){ + if (this._piechartData.length>0 || (!this.incomingLinks || this.incomingLinks.length==0)){ return ( this.props.axes.length >= 1 ? (
    diff --git a/src/client/views/nodes/DataVizBox/components/TableBox.tsx b/src/client/views/nodes/DataVizBox/components/TableBox.tsx index f56d34fa6..7b3e700ac 100644 --- a/src/client/views/nodes/DataVizBox/components/TableBox.tsx +++ b/src/client/views/nodes/DataVizBox/components/TableBox.tsx @@ -155,7 +155,7 @@ export class TableBox extends React.Component { })} style={{ background: StrListCast(this.props.layoutDoc.selected).includes(guid) ? 'lightgrey' : '', width: '110%' }}> {this.columns.map(col => { // each cell - var colSelected = this.props.axes[0]==col || this.props.axes[1]==col; + var 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 ( {p[col]} -- cgit v1.2.3-70-g09d2 From 992dc2bdb82ac304945a1dad43a885350587c017 Mon Sep 17 00:00:00 2001 From: bobzel Date: Thu, 17 Aug 2023 13:27:06 -0400 Subject: fixed field name mismatch in dataVizBox --- src/client/views/nodes/DataVizBox/DataVizBox.tsx | 2 +- src/client/views/nodes/DataVizBox/components/TableBox.tsx | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'src/client/views/nodes/DataVizBox/components/TableBox.tsx') diff --git a/src/client/views/nodes/DataVizBox/DataVizBox.tsx b/src/client/views/nodes/DataVizBox/DataVizBox.tsx index 9c59fcd13..c07ab5ba1 100644 --- a/src/client/views/nodes/DataVizBox/DataVizBox.tsx +++ b/src/client/views/nodes/DataVizBox/DataVizBox.tsx @@ -155,7 +155,7 @@ export class DataVizBox extends ViewBoxAnnotatableComponent() { componentDidMount() { this.props.setContentView?.(this); this.fetchData(); - if (!this.layoutDoc._dataVizView) this.layoutDoc._dataVizView = this.dataVizView; + if (!this.layoutDoc._dataViz) this.layoutDoc._dataViz = this.dataVizView; } fetchData() { diff --git a/src/client/views/nodes/DataVizBox/components/TableBox.tsx b/src/client/views/nodes/DataVizBox/components/TableBox.tsx index edec72cc5..70483ac6f 100644 --- a/src/client/views/nodes/DataVizBox/components/TableBox.tsx +++ b/src/client/views/nodes/DataVizBox/components/TableBox.tsx @@ -164,10 +164,10 @@ export class TableBox extends React.Component { })} style={{ background: StrListCast(this.props.layoutDoc.dataViz_selectedRows).includes(guid) ? 'lightgrey' : '', width: '110%' }}> {this.columns.map(col => { - // each cell - var 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 ( - + // each cell + var 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 ( + {p[col]} ); -- cgit v1.2.3-70-g09d2