diff options
author | bobzel <zzzman@gmail.com> | 2023-04-17 09:37:16 -0400 |
---|---|---|
committer | bobzel <zzzman@gmail.com> | 2023-04-17 09:37:16 -0400 |
commit | 6a9e80de419af14bece7a48e55edc1543d69f20f (patch) | |
tree | 71ae1b819bc4f7fdb699ae90c035eb86275c5006 /src/client/views/nodes/DataVizBox/DataVizBox.tsx | |
parent | 0a38e3f91f4f85f07fdbb7575ceb678032dcdfe9 (diff) | |
parent | 8127616d06b4db2b29de0b13068810fd19e77b5e (diff) |
Merge branch 'master' into james-server-stats
Diffstat (limited to 'src/client/views/nodes/DataVizBox/DataVizBox.tsx')
-rw-r--r-- | src/client/views/nodes/DataVizBox/DataVizBox.tsx | 181 |
1 files changed, 121 insertions, 60 deletions
diff --git a/src/client/views/nodes/DataVizBox/DataVizBox.tsx b/src/client/views/nodes/DataVizBox/DataVizBox.tsx index 592723ee9..eb25d3264 100644 --- a/src/client/views/nodes/DataVizBox/DataVizBox.tsx +++ b/src/client/views/nodes/DataVizBox/DataVizBox.tsx @@ -1,90 +1,151 @@ -import { action, computed, observable } from "mobx"; -import { observer } from "mobx-react"; -import * as React from "react"; -import { StrCast } from "../../../../fields/Types"; -import { ViewBoxBaseComponent } from "../../DocComponent"; -import { FieldViewProps, FieldView } from "../FieldView"; -import "./DataVizBox.scss"; -import { HistogramBox } from "./HistogramBox"; -import { TableBox } from "./TableBox"; - -enum DataVizView { - TABLE = "table", - HISTOGRAM= "histogram" -} +import { action, computed, observable, 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, NumCast, StrCast } from '../../../../fields/Types'; +import { CsvField } from '../../../../fields/URLField'; +import { Docs } from '../../../documents/Documents'; +import { ViewBoxAnnotatableComponent } from '../../DocComponent'; +import { FieldView, FieldViewProps } from '../FieldView'; +import { PinProps } from '../trails'; +import { LineChart } from './components/LineChart'; +import { TableBox } from './components/TableBox'; +import './DataVizBox.scss'; +export enum DataVizView { + TABLE = 'table', + LINECHART = 'lineChart', +} @observer -export class DataVizBox extends ViewBoxBaseComponent<FieldViewProps>() { - @observable private pairs: {x: number, y:number}[] = [{x: 1, y:2}]; - - // TODO: nda - make this use enum values instead - // @observable private currView: DataVizView = DataVizView.TABLE; - @computed get currView() { - if (this.rootDoc._dataVizView) { - return StrCast(this.rootDoc._dataVizView); - } else { - return "table"; - } +export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { + public static LayoutString(fieldKey: string) { + return FieldView.LayoutString(DataVizBox, fieldKey); } - - constructor(props: any) { - super(props); - if (!this.rootDoc._dataVizView) { - // TODO: nda - this might not always want to default to "table" - this.rootDoc._dataVizView = "table"; - } + // 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 }[] = []; + static pairSet = new ObservableMap<string, { [key: string]: string }[]>(); + @computed.struct get pairs() { + return DataVizBox.pairSet.get(StrCast(this.rootDoc.fileUpload)); } + private _chartRenderer: LineChart | 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 - public static LayoutString(fieldKey: string) { return FieldView.LayoutString(DataVizBox, fieldKey); } + @computed get dataVizView(): DataVizView { + return StrCast(this.layoutDoc._dataVizView, 'table') as DataVizView; + } @action - private createPairs() { - const xVals: number[] = [0, 1, 2, 3, 4, 5]; - // const yVals: number[] = [10, 20, 30, 40, 50, 60]; - const yVals: number[] = [1, 2, 3, 4, 5, 6]; - let pairs: { - x: number, - y:number - }[] = []; - if (xVals.length != yVals.length) return pairs; - for (let i = 0; i < xVals.length; i++) { - pairs.push({x: xVals[i], y: yVals[i]}); + 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._dataVizAxes = new List<string>(StrListCast(data.presDataVizAxes))); + const func = () => this._chartRenderer?.restoreView(data); + if (changedView || changedAxes) { + setTimeout(func, 100); + return true; } - this.pairs = pairs; - return pairs; + return func() ?? false; + }; + + getAnchor = (addAsAnnotation?: boolean, pinProps?: PinProps) => { + const anchor = + this._chartRenderer?.getAnchor(pinProps) ?? + Docs.Create.TextanchorDocument({ + unrendered: true, + // when we clear selection -> we should have it so chartBox getAnchor returns undefined + // 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<string>(this.axes) : undefined; + + this.addDocument(anchor); + return anchor; + }; + + @computed.struct get axes() { + return StrListCast(this.layoutDoc.dataVizAxes); } + selectAxes = (axes: string[]) => (this.layoutDoc.dataVizAxes = new List<string>(axes)); @computed get selectView() { - switch(this.currView) { - case "table": - return (<TableBox pairs={this.pairs} />) - case "histogram": - return (<HistogramBox rootDoc={this.rootDoc} pairs={this.pairs}/>) + 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'; + // prettier-ignore + switch (this.dataVizView) { + case DataVizView.TABLE: return <TableBox pairs={this.pairs} axes={this.axes} docView={this.props.DocumentView} selectAxes={this.selectAxes}/>; + case DataVizView.LINECHART: return <LineChart ref={r => (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 pairVals() { - return this.createPairs(); + @computed get dataUrl() { + return Cast(this.dataDoc[this.fieldKey], CsvField); } componentDidMount() { - this.createPairs(); + this.props.setContentView?.(this); + this.fetchData(); + } + + fetchData() { + if (DataVizBox.pairSet.has(StrCast(this.rootDoc.fileUpload))) return; + DataVizBox.pairSet.set(StrCast(this.rootDoc.fileUpload), []); + fetch('/csvData?uri=' + this.dataUrl?.url.href) // + .then(res => res.json().then(action(res => !res.errno && DataVizBox.pairSet.set(StrCast(this.rootDoc.fileUpload), res)))); } // handle changing the view using a button @action changeViewHandler(e: React.MouseEvent<HTMLButtonElement>) { e.preventDefault(); e.stopPropagation(); - this.rootDoc._dataVizView = this.currView == "table" ? "histogram" : "table"; + this.layoutDoc._dataVizView = this.dataVizView === DataVizView.TABLE ? DataVizView.LINECHART : DataVizView.TABLE; } render() { - return ( - <div className="dataViz"> - <button onClick={(e) => this.changeViewHandler(e)}>Change View</button> + return !this.pairs?.length ? ( + <div>Loading...</div> + ) : ( + <div + className="dataViz" + onWheel={e => e.stopPropagation()} + ref={r => + r?.addEventListener( + 'wheel', // if scrollTop is 0, then don't let wheel trigger scroll on any container (which it would since onScroll won't be triggered on this) + (e: WheelEvent) => { + if (!r.scrollTop && e.deltaY <= 0) e.preventDefault(); + e.stopPropagation(); + }, + { passive: false } + ) + }> + <button onClick={e => this.changeViewHandler(e)}>{this.dataVizView === DataVizView.TABLE ? DataVizView.LINECHART : DataVizView.TABLE}</button> {this.selectView} </div> ); } -}
\ No newline at end of file +} |