aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/nodes/DataVizBox/DataVizBox.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/views/nodes/DataVizBox/DataVizBox.tsx')
-rw-r--r--src/client/views/nodes/DataVizBox/DataVizBox.tsx181
1 files changed, 87 insertions, 94 deletions
diff --git a/src/client/views/nodes/DataVizBox/DataVizBox.tsx b/src/client/views/nodes/DataVizBox/DataVizBox.tsx
index ea053b09d..742dc60d1 100644
--- a/src/client/views/nodes/DataVizBox/DataVizBox.tsx
+++ b/src/client/views/nodes/DataVizBox/DataVizBox.tsx
@@ -1,6 +1,6 @@
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { Colors, Toggle, ToggleType, Type } from 'browndash-components';
-import { ObservableMap, action, computed, observable, runInAction } from 'mobx';
+import { IReactionDisposer, ObservableMap, action, computed, makeObservable, observable, reaction, runInAction } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
import { emptyFunction, returnEmptyString, returnFalse, returnOne, setupMoveUpEvents } from '../../../../Utils';
@@ -14,13 +14,13 @@ import { TraceMobx } from '../../../../fields/util';
import { DocUtils, Docs } from '../../../documents/Documents';
import { DocumentManager } from '../../../util/DocumentManager';
import { UndoManager, undoable } from '../../../util/UndoManager';
-import { ViewBoxAnnotatableComponent } from '../../DocComponent';
+import { ViewBoxAnnotatableComponent, ViewBoxInterface } from '../../DocComponent';
import { MarqueeAnnotator } from '../../MarqueeAnnotator';
import { SidebarAnnos } from '../../SidebarAnnos';
import { AnchorMenu } from '../../pdf/AnchorMenu';
import { GPTPopup } from '../../pdf/GPTPopup/GPTPopup';
-import { DocFocusOptions, DocumentView } from '../DocumentView';
-import { FieldView, FieldViewProps } from '../FieldView';
+import { DocumentView } from '../DocumentView';
+import { FocusViewOptions, FieldView, FieldViewProps } from '../FieldView';
import { PinProps } from '../trails';
import './DataVizBox.scss';
import { Histogram } from './components/Histogram';
@@ -37,22 +37,28 @@ export enum DataVizView {
}
@observer
-export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
+export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() implements ViewBoxInterface {
private _mainCont: React.RefObject<HTMLDivElement> = React.createRef();
private _marqueeref = React.createRef<MarqueeAnnotator>();
private _annotationLayer: React.RefObject<HTMLDivElement> = React.createRef();
+ private _disposers: { [name: string]: IReactionDisposer } = {};
anchorMenuClick?: () => undefined | ((anchor: Doc) => void);
crop: ((region: Doc | undefined, addCrop?: boolean) => Doc | undefined) | undefined;
@observable _marqueeing: number[] | undefined = undefined;
@observable _savedAnnotations = new ObservableMap<number, HTMLDivElement[]>();
- @observable schemaBoxLength: any = 0;
+
+ constructor(props: FieldViewProps) {
+ super(props);
+ makeObservable(this);
+ this._props.setContentViewBox?.(this);
+ }
@computed get annotationLayer() {
TraceMobx();
return <div className="dataVizBox-annotationLayer" style={{ height: this._props.PanelHeight(), width: this._props.PanelWidth() }} ref={this._annotationLayer} />;
}
marqueeDown = (e: React.PointerEvent) => {
- if (!e.altKey && e.button === 0 && NumCast(this.Document._freeform_scale, 1) <= NumCast(this.Document.freeform_scaleMin, 1) && this._props.isContentActive(true) && ![InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(Doc.ActiveTool)) {
+ if (!e.altKey && e.button === 0 && NumCast(this.Document._freeform_scale, 1) <= NumCast(this.Document.freeform_scaleMin, 1) && this._props.isContentActive() && ![InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(Doc.ActiveTool)) {
setupMoveUpEvents(
this,
e,
@@ -218,12 +224,12 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
.ScreenToLocalTransform()
.scale(this._props.NativeDimScaling?.() || 1)
.transformDirection(delta[0], delta[1]);
- const fullWidth = this._props.width;
- const mapWidth = fullWidth! - this.sidebarWidth();
+ const fullWidth = NumCast(this.layoutDoc._width);
+ const mapWidth = fullWidth - this.sidebarWidth();
if (this.sidebarWidth() + localDelta[0] > 0) {
this.layoutDoc._layout_showSidebar = true;
- this.layoutDoc._width = fullWidth! + localDelta[0];
- this.layoutDoc._layout_sidebarWidthPercent = ((100 * (this.sidebarWidth() + localDelta[0])) / (fullWidth! + localDelta[0])).toString() + '%';
+ this.layoutDoc._layout_sidebarWidthPercent = ((100 * (this.sidebarWidth() + localDelta[0])) / (fullWidth + localDelta[0])).toString() + '%';
+ this.layoutDoc._width = fullWidth + localDelta[0];
} else {
this.layoutDoc._layout_showSidebar = false;
this.layoutDoc._width = mapWidth;
@@ -235,7 +241,7 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
() => UndoManager.RunInBatch(this.toggleSidebar, 'toggle sidebar')
);
};
- getView = async (doc: Doc, options: DocFocusOptions) => {
+ getView = async (doc: Doc, options: FocusViewOptions) => {
if (this._sidebarRef?.current?.makeDocUnfiltered(doc) && !this.SidebarShown) {
options.didMove = true;
this.toggleSidebar();
@@ -256,14 +262,73 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
sidebarRemoveDocument = (doc: Doc | Doc[], sidebarKey?: string) => this.removeDocument(doc, sidebarKey);
componentDidMount() {
- this._props.setContentView?.(this);
+ this._props.setContentViewBox?.(this);
if (!DataVizBox.dataset.has(CsvCast(this.dataDoc[this.fieldKey]).url.href)) this.fetchData();
+ this._disposers.datavis = reaction(
+ () => {
+ if (this.layoutDoc.dataViz_schemaLive==undefined) this.layoutDoc.dataViz_schemaLive = true;
+ const getFrom = DocCast(this.layoutDoc.dataViz_asSchema);
+ const keys = Cast(getFrom?.schema_columnKeys, listSpec('string'))?.filter(key => key != 'text');
+ if (!keys) return;
+ const children = DocListCast(getFrom[Doc.LayoutFieldKey(getFrom)]);
+ var current: { [key: string]: string }[] = [];
+ children
+ .filter(child => child)
+ .forEach(child => {
+ const row: { [key: string]: string } = {};
+ keys.forEach(key => {
+ var cell = child[key];
+ if (cell && (cell as string)) cell = cell.toString().replace(/\,/g, '');
+ row[key] = StrCast(cell);
+ });
+ current.push(row);
+ });
+ if (!this.layoutDoc._dataViz_schemaOG){ // makes a copy of the original table for the "live" toggle
+ let csvRows = [];
+ csvRows.push(keys.join(','));
+ for (let i = 0; i < children.length; i++) {
+ let eachRow = [];
+ for (let j = 0; j < keys.length; j++) {
+ var cell = children[i][keys[j]];
+ if (cell && (cell as string)) cell = cell.toString().replace(/\,/g, '');
+ eachRow.push(cell);
+ }
+ csvRows.push(eachRow);
+ }
+ const blob = new Blob([csvRows.join('\n')], { type: 'text/csv' });
+ const options = { x: 0, y: 0, title: 'schemaTable for static dataviz', _width: 300, _height: 100, type: 'text/csv' };
+ const file = new File([blob], 'schemaTable for static dataviz', options);
+ const loading = Docs.Create.LoadingDocument(file, options);
+ DocUtils.uploadFileToDoc(file, {}, loading);
+ this.layoutDoc._dataViz_schemaOG = loading;
+ }
+ const ogDoc = this.layoutDoc._dataViz_schemaOG as Doc
+ const ogHref = CsvCast(ogDoc[this.fieldKey])? CsvCast(ogDoc[this.fieldKey]).url.href : undefined;
+ const href = CsvCast(this.Document[this.fieldKey]).url.href
+ if (ogHref && !DataVizBox.datasetSchemaOG.has(href)){ // sets original dataset to the var
+ DataVizBox.datasetSchemaOG.set(href, []);
+ fetch('/csvData?uri=' + ogHref)
+ .then(res => res.json().then(action(res => !res.errno && DataVizBox.datasetSchemaOG.set(href, res))));
+ }
+ return current;
+ },
+ current => {
+ if (current) {
+ const href = CsvCast(this.Document[this.fieldKey]).url.href;
+ if (this.layoutDoc.dataViz_schemaLive) DataVizBox.dataset.set(href, current);
+ else DataVizBox.dataset.set(href, DataVizBox.datasetSchemaOG.get(href)!);
+ }
+ },
+ { fireImmediately: true }
+ );
}
fetchData = () => {
- DataVizBox.dataset.set(CsvCast(this.dataDoc[this.fieldKey]).url.href, []); // assign temporary dataset as a lock to prevent duplicate server requests
- fetch('/csvData?uri=' + this.dataUrl?.url.href) //
- .then(res => res.json().then(action(res => !res.errno && DataVizBox.dataset.set(CsvCast(this.dataDoc[this.fieldKey]).url.href, res))));
+ if (!this.Document.dataViz_asSchema) {
+ DataVizBox.dataset.set(CsvCast(this.dataDoc[this.fieldKey]).url.href, []); // assign temporary dataset as a lock to prevent duplicate server requests
+ fetch('/csvData?uri=' + this.dataUrl?.url.href) //
+ .then(res => res.json().then(action(res => !res.errno && DataVizBox.dataset.set(CsvCast(this.dataDoc[this.fieldKey]).url.href, res))));
+ }
};
// toggles for user to decide which chart type to view the data in
@@ -277,12 +342,12 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
titleCol: this.titleCol,
//width: this.SidebarShown? this._props.PanelWidth()*.9/1.2: this._props.PanelWidth() * 0.9,
height: (this._props.PanelHeight() / scale - 32) /* height of 'change view' button */ * 0.9,
- width: (this._props.PanelWidth() / scale) * 0.9,
+ width: ((this._props.PanelWidth() - this.sidebarWidth()) / scale) * 0.9,
margin: { top: 10, right: 25, bottom: 75, left: 45 },
};
if (!this.records.length) return 'no data/visualization';
switch (this.dataVizView) {
- case DataVizView.TABLE: return <TableBox {...sharedProps} docView={this._props.DocumentView} selectAxes={this.selectAxes} selectTitleCol={this.selectTitleCol}/>;
+ case DataVizView.TABLE: return <TableBox {...sharedProps} docView={this.DocumentView} selectAxes={this.selectAxes} selectTitleCol={this.selectTitleCol}/>;
case DataVizView.LINECHART: return <LineChart {...sharedProps} dataDoc={this.dataDoc} fieldKey={this.fieldKey} ref={r => (this._vizRenderer = r ?? undefined)} vizBox={this} />;
case DataVizView.HISTOGRAM: return <Histogram {...sharedProps} dataDoc={this.dataDoc} fieldKey={this.fieldKey} ref={r => (this._vizRenderer = r ?? undefined)} />;
case DataVizView.PIECHART: return <PieChart {...sharedProps} dataDoc={this.dataDoc} fieldKey={this.fieldKey} ref={r => (this._vizRenderer = r ?? undefined)}
@@ -293,7 +358,7 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
@action
onPointerDown = (e: React.PointerEvent): void => {
if ((this.Document._freeform_scale || 1) !== 1) return;
- if (!e.altKey && e.button === 0 && this._props.isContentActive(true) && ![InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(Doc.ActiveTool)) {
+ if (!e.altKey && e.button === 0 && this._props.isContentActive() && ![InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(Doc.ActiveTool)) {
this._props.select(false);
MarqueeAnnotator.clearAnnotations(this._savedAnnotations);
this._marqueeing = [e.clientX, e.clientY];
@@ -333,81 +398,9 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
@action
changeLiveSchemaCheckbox = () => {
this.layoutDoc.dataViz_schemaLive = !this.layoutDoc.dataViz_schemaLive
- this.updateSchemaViz();
}
- @action
- setDataset(href: any, data: any) {
- DataVizBox.dataset.set(href, data);
- }
-
- @action
- // handles when the dataviz doc was made by copying a schema table
- updateSchemaViz = () => {
- const href = CsvCast(this.Document[this.fieldKey]).url.href;
- const getFromDoc = DocCast(this.layoutDoc.dataViz_asSchema);
- const children = DocListCast(getFromDoc[Doc.LayoutFieldKey(getFromDoc)]);
-
- if (children.length != this.schemaBoxLength) {
- if (this.layoutDoc.dataViz_schemaLive || !DataVizBox.datasetSchemaOG.has(href)){
- const keys = Cast(getFromDoc.schema_columnKeys, listSpec('string'))?.filter(key => key != 'text');
- if (!keys) return;
-
- if (!this.layoutDoc._dataViz_schemaOG){
- // makes a copy of the original table for the "live" toggle
- let csvRows = [];
- csvRows.push(keys.join(','));
- for (let i = 0; i < children.length; i++) {
- let eachRow = [];
- for (let j = 0; j < keys.length; j++) {
- var cell = children[i][keys[j]];
- if (cell && (cell as string)) cell = cell.toString().replace(/\,/g, '');
- eachRow.push(cell);
- }
- csvRows.push(eachRow);
- }
- const blob = new Blob([csvRows.join('\n')], { type: 'text/csv' });
- const options = { x: 0, y: 0, title: 'schemaTable for static dataviz', _width: 300, _height: 100, type: 'text/csv' };
- const file = new File([blob], 'schemaTable for static dataviz', options);
- const loading = Docs.Create.LoadingDocument(file, options);
- DocUtils.uploadFileToDoc(file, {}, loading);
- this.layoutDoc._dataViz_schemaOG = loading;
- }
-
- const ogDoc = this.layoutDoc._dataViz_schemaOG as Doc
- const ogHref = CsvCast(ogDoc[this.fieldKey])? CsvCast(ogDoc[this.fieldKey]).url.href : undefined;
- if (ogHref && !DataVizBox.datasetSchemaOG.has(href)){
- DataVizBox.datasetSchemaOG.set(href, []);
- fetch('/csvData?uri=' + ogHref)
- .then(res => res.json().then(action(res => !res.errno && DataVizBox.datasetSchemaOG.set(href, res))));
- }
-
- var current: { [key: string]: string }[] = [];
- for (let i = 0; i < children.length; i++) {
- var row: { [key: string]: string } = {};
- if (children[i]) {
- for (let j = 0; j < keys.length; j++) {
- var cell = children[i][keys[j]];
- if (cell && (cell as string)) cell = cell.toString().replace(/\,/g, '');
- row[keys[j]] = StrCast(cell);
- }
- }
- current.push(row);
- }
- this.setDataset(href, current);
- }
- else {
- this.setDataset(href, DataVizBox.datasetSchemaOG.get(href));
- }
- }
- };
-
render() {
- if (this.layoutDoc.dataViz_schemaLive == undefined) this.layoutDoc.dataViz_schemaLive = true;
- if (this.layoutDoc && this.layoutDoc.dataViz_asSchema) {
- this.updateSchemaViz();
- }
-
const scale = this._props.NativeDimScaling?.() || 1;
return !this.records.length ? (
// displays how to get data into the DataVizBox if its empty
@@ -425,7 +418,7 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
}}
onWheel={e => e.stopPropagation()}
ref={this._mainCont}>
- <div className={'datatype-button'}>
+ <div className="datatype-button">
<Toggle text={' TABLE '} toggleType={ToggleType.BUTTON} type={Type.SEC} color={'black'} onClick={e => (this.layoutDoc._dataViz = DataVizView.TABLE)} toggleStatus={this.layoutDoc._dataViz === DataVizView.TABLE} />
<Toggle text={'LINECHART'} toggleType={ToggleType.BUTTON} type={Type.SEC} color={'black'} onClick={e => (this.layoutDoc._dataViz = DataVizView.LINECHART)} toggleStatus={this.layoutDoc._dataViz === DataVizView.LINECHART} />
<Toggle text={'HISTOGRAM'} toggleType={ToggleType.BUTTON} type={Type.SEC} color={'black'} onClick={e => (this.layoutDoc._dataViz = DataVizView.HISTOGRAM)} toggleStatus={this.layoutDoc._dataViz === DataVizView.HISTOGRAM} />
@@ -461,7 +454,7 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
</div>
{this.sidebarHandle}
{this.annotationLayer}
- {!this._mainCont.current || !this._annotationLayer.current ? null : (
+ {!this._mainCont.current || !this.DocumentView || !this._annotationLayer.current ? null : (
<MarqueeAnnotator
ref={this._marqueeref}
Document={this.Document}
@@ -469,7 +462,7 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
scrollTop={0}
annotationLayerScrollTop={NumCast(this.Document._layout_scrollTop)}
scaling={returnOne}
- docView={this._props.DocumentView!}
+ docView={this.DocumentView}
addDocument={this.sidebarAddDocument}
finishMarquee={this.finishMarquee}
savedAnnotations={this.savedAnnotations}