diff options
Diffstat (limited to 'src/client/views/nodes/DataVizBox/LineChart.tsx')
-rw-r--r-- | src/client/views/nodes/DataVizBox/LineChart.tsx | 128 |
1 files changed, 111 insertions, 17 deletions
diff --git a/src/client/views/nodes/DataVizBox/LineChart.tsx b/src/client/views/nodes/DataVizBox/LineChart.tsx index 42e9da3d7..89fb6e20b 100644 --- a/src/client/views/nodes/DataVizBox/LineChart.tsx +++ b/src/client/views/nodes/DataVizBox/LineChart.tsx @@ -5,13 +5,27 @@ import { ChartData, DataPoint } from './ChartBox'; // import d3 import * as d3 from 'd3'; import { minMaxRange, createLineGenerator, xGrid, yGrid, drawLine, xAxisCreator, yAxisCreator, scaleCreatorNumerical, scaleCreatorCategorical } from './utils/D3Utils'; +import { Docs } from '../../../documents/Documents'; +import { Doc, DocListCast } from '../../../../fields/Doc'; interface LineChartProps { data: ChartData; width: number; height: number; + dataDoc: Doc; + fieldKey: string; + // returns linechart component but should be generic chart + setCurrChart: (chart: LineChart | undefined) => void; + getAnchor: () => Doc; } +type minMaxRange = { + xMin: number | undefined; + xMax: number | undefined; + yMin: number | undefined; + yMax: number | undefined; +}; + interface SelectedDataPoint { x: number; y: number; @@ -21,61 +35,137 @@ interface SelectedDataPoint { @observer export class LineChart extends React.Component<LineChartProps> { private _dataReactionDisposer: IReactionDisposer | undefined = undefined; + private _heightReactionDisposer: IReactionDisposer | undefined = undefined; + private _widthReactionDisposer: IReactionDisposer | undefined; @observable private _x: number = 0; @observable private _y: number = 0; @observable private _currSelected: SelectedDataPoint | undefined = undefined; // create ref for the div private _chartRef: React.RefObject<HTMLDivElement> = React.createRef(); + private _rangeVals: minMaxRange = { + xMin: undefined, + xMax: undefined, + yMin: undefined, + yMax: undefined, + }; + + // anything that doesn't need to be recalculated should just be stored as drawCharts (i.e. computed values) and drawChart is gonna iterate over these observables and generate svgs based on that + + // write the getanchor function that gets whatever I want as the link anchor componentDidMount() { - console.log('Getting to line chart'); - this.drawChart(); - this._dataReactionDisposer = reaction(() => this.props.data, this.drawChart); + // this._rangeVals = minMaxRange(this.props.data.data); + // this.drawChart(); + this._dataReactionDisposer = reaction( + () => this.props.data, + data => { + this._rangeVals = minMaxRange(data.data); + this.drawChart(); + }, + { fireImmediately: true } + ); + this._heightReactionDisposer = reaction(() => this.props.height, this.drawChart.bind(this)); + this._widthReactionDisposer = reaction(() => this.props.width, this.drawChart.bind(this)); + reaction( + () => DocListCast(this.props.dataDoc[this.props.fieldKey + '-annotations']), + annotations => { + // modify how d3 renders so that anything in this annotations list would be potentially highlighted in some way + // could be blue colored to make it look like anchor + }, + { fireImmediately: true } + ); + setTimeout(() => { + this.props.setCurrChart(this); + }); + } + + // gets called whenever the "data-annotations" fields gets updated + drawAnnotations() {} + + _getAnchor() { + // store whatever information would allow me to reselect the same thing (store parameters I would pass to get the exact same element) + + // TODO: nda - look at pdfviewer get anchor for args + const doc = Docs.Create.TextanchorDocument({ + /*put in some options*/ + }); + // access curr selected from the charts + doc.x = this._currSelected?.x; + doc.y = this._currSelected?.y; + doc.chartType = 'line'; + return doc; + // have some other function in code that } componentWillUnmount() { if (this._dataReactionDisposer) { this._dataReactionDisposer(); } + if (this._heightReactionDisposer) { + this._heightReactionDisposer(); + } + if (this._widthReactionDisposer) { + this._widthReactionDisposer(); + } } tooltipContent(data: DataPoint) { return `<b>x: ${data.x} y: ${data.y}</b>`; } + // TODO: nda - can use d3.create() to create html element instead of appending drawChart() { + console.log('Drawing chart'); // clearing tooltip d3.select(this._chartRef.current).select('svg').remove(); d3.select(this._chartRef.current).select('.tooltip').remove(); + // TODO: nda - refactor code so that it only recalculates min max and things related to data on data update const margin = { top: 50, right: 50, bottom: 50, left: 50 }; const { data } = this.props; - const { xMin, xMax, yMin, yMax } = minMaxRange(data.data); + const { xMin, xMax, yMin, yMax } = this._rangeVals; + console.log('rangeVals', this._rangeVals); + + const width = this.props.width - margin.left - margin.right; + const height = this.props.height - margin.top - margin.bottom; + console.log('height, width', this.props.height, this.props.width); // adding svg - const svg = d3.select(this._chartRef.current).append('svg').attr('width', '100%').attr('height', '100%').append('g').attr('transform', `translate(${margin.left}, ${margin.top})`); + const svg = d3 + .select(this._chartRef.current) + .append('svg') + .attr('width', `${width + margin.right + margin.left}`) + .attr('height', `${height + margin.top + margin.bottom}`) + .append('g') + .attr('transform', `translate(${margin.left}, ${margin.top})`); // adding tooltip // const tooltip = d3.select('#chart-container').append('div').attr('class', 'tooltip'); + console.log('xMinMax:', xMin, xMax); + console.log('yMinMax:', yMin, yMax); - if (!xMin || !xMax || !yMin || !yMax) { + if (xMin == undefined || xMax == undefined || yMin == undefined || yMax == undefined) { + console.log('getting here'); // TODO: nda - error handle return; } - const xScale = scaleCreatorNumerical(xMin, xMax, 0, this.props.width); - // adding x axis - const yScale = scaleCreatorNumerical(0, yMax, this.props.height, 0); + + console.log('getting here'); + + // creating the x and y scales + const xScale = scaleCreatorNumerical(xMin, xMax, 0, width); + const yScale = scaleCreatorNumerical(0, yMax, 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 = createLineGenerator(xScale, yScale); // create x and y grids - xGrid(svg.append('g'), this.props.height, xScale); - yGrid(svg.append('g'), this.props.width, yScale); - xAxisCreator(svg.append('g'), this.props.height, xScale); - yAxisCreator(svg.append('g'), this.props.width, yScale); + xGrid(svg.append('g'), height, xScale); + yGrid(svg.append('g'), width, yScale); + xAxisCreator(svg.append('g'), height, xScale); + yAxisCreator(svg.append('g'), width, yScale); // draw the line drawLine(svg.append('path'), data.data, lineGen); @@ -117,8 +207,8 @@ export class LineChart extends React.Component<LineChartProps> { this._y = d0.y; focus.attr('transform', `translate(${xScale(d0.x)},${yScale(d0.y)})`); // TODO: nda - implement tooltips - // tooltip.transition().duration(300).style('opacity', 0.9); - // tooltip.html(() => this.tooltipContent(d0)).attr('transform', `translate(${xScale(d0.x) + 30}px,${yScale(d0.y) + 30}px)`); + tooltip.transition().duration(300).style('opacity', 0.9); + tooltip.html(() => this.tooltipContent(d0)).attr('transform', `translate(${xScale(d0.x) + 30}px,${yScale(d0.y) + 30}px)`); }); const onPointClick = action((e: any) => { @@ -132,13 +222,17 @@ export class LineChart extends React.Component<LineChartProps> { const selected = svg.selectAll('.circle-d1').filter((d: any) => d['data-x'] === d0.x && d['data-y'] === d0.y); this._currSelected = { x: d0.x, y: d0.y, elem: selected }; console.log('Getting here'); + setTimeout(() => this.props.getAnchor()); + // this.props.getAnchor(); console.log(this._currSelected); }); svg.append('rect') .attr('class', 'overlay') - .attr('width', this.props.width) - .attr('height', this.props.height) + .attr('width', width) + .attr('height', height + margin.top + margin.bottom) + .attr('fill', 'none') + .attr('translate', `translate(${margin.left}, ${-(margin.top + margin.bottom)})`) .style('opacity', 0) .on('mouseover', () => { focus.style('display', null); |