diff options
author | Naafiyan Ahmed <naafiyan@gmail.com> | 2022-07-13 17:01:21 -0400 |
---|---|---|
committer | Naafiyan Ahmed <naafiyan@gmail.com> | 2022-07-13 17:01:21 -0400 |
commit | 6a117b8779d1e3c00fbe67cb38c7cde1fe5b0552 (patch) | |
tree | df3aecfd5bc486c1ca3f7d76fcbca7a4f958e2c7 /src | |
parent | 90a4aace3a5701c0332e180b5bd1119dd38ec52c (diff) |
got basic d3js graph to work
Diffstat (limited to 'src')
-rw-r--r-- | src/client/views/nodes/DataVizBox/ChartBox.tsx | 151 | ||||
-rw-r--r-- | src/client/views/nodes/DataVizBox/LineChart.tsx | 122 |
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>; + } +} |