diff options
Diffstat (limited to 'src/client/views/nodes/DataVizBox/ChartBox.tsx')
-rw-r--r-- | src/client/views/nodes/DataVizBox/ChartBox.tsx | 162 |
1 files changed, 162 insertions, 0 deletions
diff --git a/src/client/views/nodes/DataVizBox/ChartBox.tsx b/src/client/views/nodes/DataVizBox/ChartBox.tsx new file mode 100644 index 000000000..07f754637 --- /dev/null +++ b/src/client/views/nodes/DataVizBox/ChartBox.tsx @@ -0,0 +1,162 @@ +import { observer } from "mobx-react"; +import * as React from "react"; +import { Doc } from "../../../../fields/Doc"; +import { + Chart as ChartJS, + CategoryScale, + LinearScale, + BarElement, + Title, + Tooltip, + Legend, + InteractionItem, + PointElement, + LineElement, + } from 'chart.js'; + import { Bar, getDatasetAtEvent, getElementAtEvent, Line } from 'react-chartjs-2'; +import { ChartJSOrUndefined } from "react-chartjs-2/dist/types"; +import { action, computed, observable } from "mobx"; +import { Cast, StrCast } from "../../../../fields/Types"; + + +export interface ChartBoxProps { + rootDoc: Doc; + pairs: {x: number, y:number}[]; +} + +export interface ChartJsData { + labels: number[]; + datasets: { + label: string; + data: number[]; + backgroundColor: string[]; + }[] +} + +ChartJS.register( + CategoryScale, + LinearScale, + BarElement, + Title, + Tooltip, + Legend, + PointElement, + LineElement + ); + +const primaryColor = 'rgba(53, 162, 235, 0.5)'; +const selectedColor = 'rgba(255, 99, 132, 0.5)'; + +@observer +export class ChartBox extends React.Component<ChartBoxProps> { + private _chartRef: any = React.createRef<ChartJSOrUndefined<"bar", number[], string>>(); + + @observable private _prevColor: string | undefined= undefined; + @observable private _prevIndex: { dIndex: number, index: number} | undefined = undefined; + @observable private _chartJsData: ChartJsData | undefined= undefined; + + @computed get currView() { + if (this.props.rootDoc._dataVizView) { + return StrCast(this.props.rootDoc._currChartView); + } else { + return "table"; + } + } + + constructor(props: any) { + super(props); + if (!this.props.rootDoc._currChartView) { + this.props.rootDoc._currChartView = "bar"; + } + } + + @computed get options() { + return { + responsive: true, + plugins: { + legend: { + position: 'top' as const, + }, + title: { + display: true, + text: 'Bar Chart', + }, + }, + } + } + + @action + generateChartJsData() { + if (this.props.rootDoc._chartData) { + // parse the string into a json object + this._chartJsData = JSON.parse(StrCast(this.props.rootDoc._chartData)); + this._prevColor = StrCast(this.props.rootDoc._prevColor); + this._prevIndex = JSON.parse(StrCast(this.props.rootDoc._prevIndex)); + return; + } + const labels = this.props.pairs.map(p => p.x); + const dataset = { + label: 'Dataset 1', + data: this.props.pairs.map(p => p.y), + backgroundColor: this.props.pairs.map(p => primaryColor), + } + const data = { + labels, + datasets: [dataset] + }; + this._chartJsData = data; + } + + componentDidMount() { + this.generateChartJsData(); + } + + @action + onClickChangeChart = (e: React.MouseEvent<HTMLButtonElement>) => { + e.preventDefault(); + e.stopPropagation(); + console.log(e.currentTarget.value); + this.props.rootDoc._currChartView = e.currentTarget.value.toLowerCase(); + } + + @action + onClick = (e: any) => { + e.preventDefault(); + if (getDatasetAtEvent(this._chartRef.current, e).length == 0) return; + if (!this._chartJsData) return; + if (this._prevIndex && this._prevColor) { + this._chartJsData.datasets[this._prevIndex.dIndex].backgroundColor[this._prevIndex.index] = this._prevColor; + } + + const currSelected = getElementAtEvent(this._chartRef.current, e); + const index = { datasetIndex: currSelected[0].datasetIndex, index: currSelected[0].index }; + this._prevIndex = { dIndex: index.datasetIndex, index: index.index }; + this._prevColor = this._chartJsData.datasets[index.datasetIndex].backgroundColor[index.index]; + this._chartJsData.datasets[index.datasetIndex].backgroundColor[index.index] = selectedColor; + this._chartRef.current.update(); + // stringify this._chartJsData + const strData = JSON.stringify(this._chartJsData); + this.props.rootDoc._chartData = strData; + this.props.rootDoc._prevColor = this._prevColor; + this.props.rootDoc._prevIndex = JSON.stringify(this._prevIndex); + } + + render() { + if (this.props.pairs && this._chartJsData) { + return ( + <div> + <div> + {this.props.rootDoc._currChartView == "line" ? + (<Line ref={this._chartRef} options={this.options} data={this._chartJsData} onClick={(e) => this.onClick(e)} />) : + (<Bar ref={this._chartRef} options={this.options} data={this._chartJsData} onClick={(e) => this.onClick(e)} />) + } + </div> + <button onClick={(e) => this.onClickChangeChart(e)} value="line">Line</button> + <button onClick={(e) => this.onClickChangeChart(e)} value="bar">Bar</button> + </div> + ) + } else { + return <div></div> + } + } +}
\ No newline at end of file |