aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorNaafiyan Ahmed <naafiyan@gmail.com>2022-07-13 17:01:21 -0400
committerNaafiyan Ahmed <naafiyan@gmail.com>2022-07-13 17:01:21 -0400
commit6a117b8779d1e3c00fbe67cb38c7cde1fe5b0552 (patch)
treedf3aecfd5bc486c1ca3f7d76fcbca7a4f958e2c7 /src
parent90a4aace3a5701c0332e180b5bd1119dd38ec52c (diff)
got basic d3js graph to work
Diffstat (limited to 'src')
-rw-r--r--src/client/views/nodes/DataVizBox/ChartBox.tsx151
-rw-r--r--src/client/views/nodes/DataVizBox/LineChart.tsx122
2 files changed, 179 insertions, 94 deletions
diff --git a/src/client/views/nodes/DataVizBox/ChartBox.tsx b/src/client/views/nodes/DataVizBox/ChartBox.tsx
index 42bd8a7f6..36d23d30e 100644
--- a/src/client/views/nodes/DataVizBox/ChartBox.tsx
+++ b/src/client/views/nodes/DataVizBox/ChartBox.tsx
@@ -6,81 +6,37 @@ import { Doc } from '../../../../fields/Doc';
import { ChartJSOrUndefined } from 'react-chartjs-2/dist/types';
import { action, computed, observable } from 'mobx';
import { Cast, StrCast } from '../../../../fields/Types';
-import { LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, Legend, ResponsiveContainer } from 'recharts';
+// import { LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, Legend, ResponsiveContainer } from 'recharts';
import { CategoricalChartState } from 'recharts/types/chart/generateCategoricalChart';
+import { LineChart } from './LineChart';
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)';
-const data = [
- {
- name: 'Page A',
- uv: 4000,
- pv: 2400,
- amt: 2400,
- },
- {
- name: 'Page B',
- uv: 3000,
- pv: 1398,
- amt: 2210,
- },
- {
- name: 'Page C',
- uv: 2000,
- pv: 9800,
- amt: 2290,
- },
- {
- name: 'Page D',
- uv: 2780,
- pv: 3908,
- amt: 2000,
- },
- {
- name: 'Page E',
- uv: 1890,
- pv: 4800,
- amt: 2181,
- },
- {
- name: 'Page F',
- uv: 2390,
- pv: 3800,
- amt: 2500,
- },
- {
- name: 'Page G',
- uv: 3490,
- pv: 4300,
- amt: 2100,
- },
-];
-
export interface RechartData {
name: string | number;
y: number;
}
+export interface DataPoints {
+ x: number;
+ y: number;
+}
+
+export interface ChartData {
+ xLabel: string;
+ yLabel: string;
+ data: DataPoints[];
+}
+
@observer
export class ChartBox extends React.Component<ChartBoxProps> {
- @observable private _chartData: RechartData[] = [];
+ @observable private _chartData: ChartData | undefined = undefined;
@computed get currView() {
if (this.props.rootDoc._dataVizView) {
@@ -104,16 +60,22 @@ export class ChartBox extends React.Component<ChartBoxProps> {
return;
}
- // generate the chart data according to the RechartData type from the pairs prop
- const chartData: RechartData[] = [];
- this.props.pairs.forEach(pair => {
- chartData.push({
- name: pair.x,
- y: pair.y,
+ const data: ChartData = {
+ xLabel: '',
+ yLabel: '',
+ data: [],
+ };
+
+ if (this.props.pairs && this.props.pairs.length > 0) {
+ data.xLabel = 'x';
+ data.yLabel = 'y';
+ this.props.pairs.forEach(pair => {
+ data.data.push({ x: pair.x, y: pair.y });
});
- });
+ }
- this._chartData = chartData;
+ this._chartData = data;
+ this.props.rootDoc._chartData = JSON.stringify(data);
}
// @action
@@ -200,35 +162,35 @@ export class ChartBox extends React.Component<ChartBoxProps> {
// console.log(e);
// }
- @computed get reLineChart() {
- return (
- <ResponsiveContainer width="80%" height="80%">
- <LineChart
- width={500}
- height={300}
- data={this._chartData}
- margin={{
- top: 5,
- right: 30,
- left: 20,
- bottom: 5,
- }}
- onMouseDown={e => console.log(e)}
- onMouseMove={e => this.onMouseMove(e)}>
- <CartesianGrid strokeDasharray="3 3" />
- <XAxis dataKey="name" onMouseDown={e => console.log(e)} />
- <YAxis />
- <Tooltip />
- <Legend />
- <Line type="monotone" dataKey="y" stroke="#8884d8" activeDot={{ r: 8, onClick: this.handleDotClick }} />
- {/* <Line type="monotone" dataKey="uv" stroke="#82ca9d" /> */}
- </LineChart>
- </ResponsiveContainer>
- );
- }
+ // @computed get reLineChart() {
+ // return (
+ // // <ResponsiveContainer width="80%" height="80%">
+ // <LineChart
+ // width={500}
+ // height={300}
+ // data={this._chartData}
+ // margin={{
+ // top: 5,
+ // right: 30,
+ // left: 20,
+ // bottom: 5,
+ // }}
+ // onMouseDown={e => console.log(e)}
+ // onMouseMove={e => this.onMouseMove(e)}>
+ // <CartesianGrid strokeDasharray="3 3" />
+ // <XAxis dataKey="name" onMouseDown={e => console.log(e)} />
+ // <YAxis />
+ // <Tooltip />
+ // <Legend />
+ // <Line type="monotone" dataKey="y" stroke="#8884d8" activeDot={{ r: 8, onClick: this.handleDotClick }} />
+ // {/* <Line type="monotone" dataKey="uv" stroke="#82ca9d" /> */}
+ // </LineChart>
+ // // </ResponsiveContainer>
+ // );
+ // }
render() {
- if (this.props.pairs && this._chartData.length > 0) {
+ if (this.props.pairs && this._chartData) {
return (
<div>
<div>
@@ -237,7 +199,8 @@ export class ChartBox extends React.Component<ChartBoxProps> {
) : (
<Bar ref={this._chartRef} options={this.options} data={this._chartJsData} onClick={e => this.onClick(e)} />
)} */}
- {this.reLineChart}
+ {/* {this.reLineChart} */}
+ <LineChart width={500} height={300} data={this._chartData} />
</div>
<button onClick={e => this.onClickChangeChart(e)} value="line">
Line
diff --git a/src/client/views/nodes/DataVizBox/LineChart.tsx b/src/client/views/nodes/DataVizBox/LineChart.tsx
new file mode 100644
index 000000000..2d2e67d4f
--- /dev/null
+++ b/src/client/views/nodes/DataVizBox/LineChart.tsx
@@ -0,0 +1,122 @@
+import { computed, IReactionDisposer, reaction } from 'mobx';
+import { observer } from 'mobx-react';
+import * as React from 'react';
+import { ChartData, DataPoints } from './ChartBox';
+// import d3
+import * as d3 from 'd3';
+
+interface LineChartProps {
+ data: ChartData;
+ width: number;
+ height: number;
+}
+
+@observer
+export class LineChart extends React.Component<LineChartProps> {
+ private _dataReactionDisposer: IReactionDisposer | undefined = undefined;
+
+ componentDidMount() {
+ console.log('Getting to line chart');
+ this.drawChart();
+ this._dataReactionDisposer = reaction(() => this.props.data, this.drawChart);
+ }
+
+ componentWillUnmount() {
+ if (this._dataReactionDisposer) {
+ this._dataReactionDisposer();
+ }
+ }
+
+ drawChart() {
+ console.log('Getting called');
+ console.log(this.props.data);
+ const margin = { top: 50, right: 50, bottom: 50, left: 50 };
+ const { data } = this.props;
+
+ const yMin = d3.min(data.data, d => d.y);
+ const yMax = d3.max(data.data, d => d.y);
+
+ // TODO: nda - modify data.x to support strings
+
+ const xMin = d3.min(data.data, d => d.x);
+ const xMax = d3.max(data.data, d => d.x);
+
+ // adding svg
+ const svg = d3.select('#chart-container').append('svg').attr('width', '100%').attr('height', '100%').append('g').attr('transform', `translate(${margin.left}, ${margin.top})`);
+
+ // adding tooltip
+ // const tooltip = d3.select('#chart-container').append('div').attr('class', 'tooltip');
+
+ if (!xMin || !xMax || !yMin || !yMax) {
+ // TODO: nda - error handle
+ return;
+ }
+ // adding x axis
+ const xScale = d3.scaleLinear().domain([xMin, xMax]).range([0, this.props.width]);
+
+ const yScale = d3.scaleLinear().domain([yMin, yMax]).range([this.props.height, 0]);
+
+ // create a line function that takes in the data.data.x and data.data.y
+ // TODO: nda - fix the types for the d here
+ const lineGen = d3
+ .line<DataPoints>()
+ .x(d => xScale(d.x))
+ .y(d => yScale(d.y))
+ .curve(d3.curveMonotoneX);
+
+ // adding the line to the svg
+ svg.append('g')
+ .attr('class', 'grid')
+ .attr('transform', `translate(0,${this.props.height})`)
+ .call(
+ d3
+ .axisBottom(xScale)
+ .tickSize(-this.props.height)
+ .tickFormat((a, b) => '')
+ );
+ svg.append('g')
+ .attr('class', 'grid')
+ .call(
+ d3
+ .axisLeft(yScale)
+ .tickSize(-this.props.width)
+ .tickFormat((a, b) => '')
+ );
+ svg.append('g').attr('class', 'x-axis').attr('transform', `translate(0,${this.props.height})`).call(d3.axisBottom(xScale).tickSize(15));
+ svg.append('g').attr('class', 'y-axis').call(d3.axisLeft(yScale));
+
+ // draw the line
+ svg.append('path').datum(data.data).attr('fill', 'none').attr('stroke', '#f6c3d0').attr('stroke-width', 4).attr('class', 'line').attr('d', lineGen);
+
+ const focus = svg.append('g').attr('class', 'focus').style('display', 'none');
+ focus.append('circle').attr('r', 5).attr('class', 'circle');
+ // const tooltip = d3.select('#container').append('div').attr('class', 'tooltip').style('opacity', 0);
+
+ // const mousemove = (event) => {
+ // const bisect = d3.bisector((d: DataPoints) => d.x).left;
+ // const xPos = d3.pointer(this)[0];
+ // const x0 = bisect(data.data, xScale.invert(xPos));
+ // const d0 = data.data[x0];
+ // focus.attr('transform', `translate(${xScale(d0.x)},${yScale(d0.y)})`);
+ // tooltip.transition().duration(300).style('opacity', 0.9);
+ // tooltip.html(d0.tooltipContent || d0.label).style('transform', `translate(${xScale(d0.label) + 30}px,${yScale(d0.value) - 30}px)`);
+ // }
+
+ // svg.append('rect')
+ // .attr('class', 'overlay')
+ // .attr('width', this.props.width)
+ // .attr('height', this.props.height)
+ // .style('opacity', 0)
+ // .on('mouseover', () => {
+ // focus.style('display', null);
+ // })
+ // .on('mouseout', () => {
+ // tooltip.transition().duration(300).style('opacity', 0);
+ // })
+ // .on('mousemove', mousemove);
+ }
+
+ render() {
+ return <div id="chart-container"></div>;
+ }
+}