aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/nodes/DataVizBox/ChartBox.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/views/nodes/DataVizBox/ChartBox.tsx')
-rw-r--r--src/client/views/nodes/DataVizBox/ChartBox.tsx162
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