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