aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/client/views/nodes/DataVizBox/ChartBox.tsx100
-rw-r--r--src/client/views/nodes/DataVizBox/ChartInterface.ts36
-rw-r--r--src/client/views/nodes/DataVizBox/DataVizBox.tsx84
-rw-r--r--src/client/views/nodes/DataVizBox/components/LineChart.tsx187
-rw-r--r--src/client/views/nodes/DataVizBox/components/TableBox.tsx31
-rw-r--r--src/client/views/nodes/DataVizBox/utils/D3Utils.ts2
6 files changed, 133 insertions, 307 deletions
diff --git a/src/client/views/nodes/DataVizBox/ChartBox.tsx b/src/client/views/nodes/DataVizBox/ChartBox.tsx
deleted file mode 100644
index ee577b9fd..000000000
--- a/src/client/views/nodes/DataVizBox/ChartBox.tsx
+++ /dev/null
@@ -1,100 +0,0 @@
-import { observer } from 'mobx-react';
-import * as React from 'react';
-import { Doc } from '../../../../fields/Doc';
-import { action, computed, observable } from 'mobx';
-import { NumCast, StrCast } from '../../../../fields/Types';
-import { LineChart } from './components/LineChart';
-import { Chart, ChartData } from './ChartInterface';
-import { PinProps } from '../trails';
-
-export interface ChartBoxProps {
- rootDoc: Doc;
- dataDoc: Doc;
- height: number;
- pairs: { x: number; y: number }[];
- setChartBox: (chartBox: ChartBox) => void;
- getAnchor: () => Doc;
-}
-
-export interface DataPoint {
- x: number;
- y: number;
-}
-
-@observer
-export class ChartBox extends React.Component<ChartBoxProps> {
- @observable private _chartData: ChartData | undefined = undefined;
- private currChart: Chart | 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';
- }
- }
-
- setCurrChart = (chart: Chart) => {
- this.currChart = chart;
- };
-
- @action
- generateChartData() {
- if (this.props.rootDoc._chartData) {
- this._chartData = JSON.parse(StrCast(this.props.rootDoc._chartData));
- return;
- }
-
- 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 => {
- // TODO: nda - add actual support for multiple sets of data
- data.data[0].push({ x: pair.x, y: pair.y });
- });
- }
-
- this._chartData = data;
- this.props.rootDoc._chartData = JSON.stringify(data);
- }
-
- componentDidMount = () => {
- this.generateChartData();
- this.props.setChartBox(this);
- };
-
- @action
- onClickChangeChart = (e: React.MouseEvent<HTMLButtonElement>) => {
- e.preventDefault();
- e.stopPropagation();
- console.log(e.currentTarget.value);
- this.props.rootDoc._currChartView = e.currentTarget.value.toLowerCase();
- };
-
- getAnchor = (pinProps?: PinProps) => this.currChart?._getAnchor(pinProps);
-
- restoreView = (data: Doc) => this.currChart?.restoreView(data);
-
- render() {
- if (this.props.pairs && this._chartData) {
- const width = NumCast(this.props.rootDoc._width) * 0.9;
- const height = this.props.height * 0.9;
- const margin = { top: 10, right: 50, bottom: 50, left: 50 };
- return <LineChart margin={margin} width={width} height={height} chartData={this._chartData} setCurrChart={this.setCurrChart} dataDoc={this.props.dataDoc} fieldKey={'data'} getAnchor={this.props.getAnchor} />;
- }
- return <div />;
- }
-}
diff --git a/src/client/views/nodes/DataVizBox/ChartInterface.ts b/src/client/views/nodes/DataVizBox/ChartInterface.ts
deleted file mode 100644
index 8ebcc2a5f..000000000
--- a/src/client/views/nodes/DataVizBox/ChartInterface.ts
+++ /dev/null
@@ -1,36 +0,0 @@
-import { Doc } from '../../../../fields/Doc';
-import { PinProps } from '../trails';
-import { DataPoint } from './ChartBox';
-
-export interface Chart {
- tooltipContent: (data: DataPoint) => string;
- drawChart: () => void;
- restoreView: (data: any) => boolean;
- height: number;
- width: number;
- // TODO: nda - probably want to get rid of this to keep charts more generic
- _getAnchor: (pinProps?: PinProps) => Doc;
-}
-
-export interface ChartProps {
- chartData: ChartData;
- width: number;
- height: number;
- dataDoc: Doc;
- fieldKey: string;
- // returns linechart component but should be generic chart
- setCurrChart: (chart: Chart) => void;
- getAnchor: () => Doc;
- margin: {
- top: number;
- right: number;
- bottom: number;
- left: number;
- };
-}
-
-export interface ChartData {
- xLabel: string;
- yLabel: string;
- data: DataPoint[][];
-}
diff --git a/src/client/views/nodes/DataVizBox/DataVizBox.tsx b/src/client/views/nodes/DataVizBox/DataVizBox.tsx
index 68766e8dc..e279a1262 100644
--- a/src/client/views/nodes/DataVizBox/DataVizBox.tsx
+++ b/src/client/views/nodes/DataVizBox/DataVizBox.tsx
@@ -2,29 +2,32 @@ import { action, computed, observable } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
import { Doc } from '../../../../fields/Doc';
-import { BoolCast, Cast, StrCast } from '../../../../fields/Types';
+import { Cast, NumCast, StrCast } from '../../../../fields/Types';
import { CsvField } from '../../../../fields/URLField';
import { Docs } from '../../../documents/Documents';
import { ViewBoxAnnotatableComponent } from '../../DocComponent';
-import { FieldViewProps, FieldView } from '../FieldView';
-import { ChartBox } from './ChartBox';
-import './DataVizBox.scss';
-import { TableBox } from './components/TableBox';
+import { FieldView, FieldViewProps } from '../FieldView';
import { PinProps } from '../trails';
+import { LineChart } from './components/LineChart';
+import { TableBox } from './components/TableBox';
+import './DataVizBox.scss';
enum DataVizView {
TABLE = 'table',
- HISTOGRAM = 'histogram',
+ LINECHART = 'lineChart',
}
@observer
export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
+ public static LayoutString(fieldKey: string) {
+ return FieldView.LayoutString(DataVizBox, fieldKey);
+ }
// says we have an object and any string
// 2 ways of doing it
// @observable private pairs: { [key: string]: number | string | undefined }[] = [];
// @observable private pairs: { [key: string]: FieldResult }[] = [];
@observable private pairs: { x: number; y: number }[] = [];
- private _chartBox: ChartBox | undefined;
+ private _chartRenderer: LineChart | undefined;
// // another way would be store a schema that defines the type of data we are expecting from an imported doc
// method1() {
@@ -45,25 +48,18 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
// [key: string]: FieldResult;
// instead of numeric x,y in there,
- // TODO: nda - make this use enum values instead
- // @observable private currView: DataVizView = DataVizView.TABLE;
-
// TODO: nda - use onmousedown and onmouseup when dragging and changing height and width to update the height and width props only when dragging stops
- setChartBox = (chartBox: ChartBox) => {
- this._chartBox = chartBox;
- };
-
- @computed get currView() {
- return StrCast(this.rootDoc._dataVizView, 'table');
+ @computed get dataVizView(): DataVizView {
+ return StrCast(this.rootDoc._dataVizView, 'table') as DataVizView;
}
@action
restoreView = (data: Doc) => {
- const changed = this.currView !== data.dataView && (this.rootDoc._dataVizView = data.dataView);
- const func = () => this._chartBox?.restoreView(data);
+ const changed = this.dataVizView !== data.presDataVizView && (this.rootDoc._dataVizView = data.presDataVizView);
+ const func = () => this._chartRenderer?.restoreView(data);
if (changed) {
- setTimeout(func);
+ setTimeout(func, 100);
return changed ? true : false;
}
return func() ?? false;
@@ -71,38 +67,27 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
getAnchor = (addAsAnnotation?: boolean, pinProps?: PinProps) => {
const anchor =
- this._chartBox?.getAnchor(pinProps) ??
+ this._chartRenderer?.getAnchor(pinProps) ??
Docs.Create.TextanchorDocument({
// when we clear selection -> we should have it so chartBox getAnchor returns undefined
// this is for when we want the whole doc (so when the chartBox getAnchor returns without a marker)
/*put in some options*/
});
- anchor.dataView = this.currView;
+ anchor.presDataVizView = this.dataVizView;
this.addDocument(anchor);
return anchor;
};
- constructor(props: any) {
- super(props);
- if (!this.rootDoc._dataVizView) {
- // TODO: nda - this might not always want to default to "table"
- this.rootDoc._dataVizView = 'table';
- }
- }
-
- public static LayoutString(fieldKey: string) {
- return FieldView.LayoutString(DataVizBox, fieldKey);
- }
@computed get selectView() {
- switch (this.currView) {
- case 'table':
- return <TableBox pairs={this.pairs} />;
- case 'histogram':
- return <ChartBox height={this.props.PanelHeight() - 32 /* height of 'change view' button */} getAnchor={this.getAnchor} setChartBox={this.setChartBox} rootDoc={this.rootDoc} pairs={this.pairs} dataDoc={this.dataDoc} />;
- // case "histogram":
- // return (<HistogramBox rootDoc={this.rootDoc} pairs={this.pairs}/>)
+ const width = NumCast(this.rootDoc._width) * 0.9;
+ const height = (this.props.PanelHeight() - 32) /* height of 'change view' button */ * 0.9;
+ const margin = { top: 10, right: 50, bottom: 50, left: 50 };
+ // prettier-ignore
+ switch (this.dataVizView) {
+ case DataVizView.TABLE: return <TableBox pairs={this.pairs} />;
+ case DataVizView.LINECHART: return <LineChart ref={r => (this._chartRenderer = r ?? undefined)} height={height} width={width} fieldKey={this.fieldKey} margin={margin} rootDoc={this.rootDoc} pairs={this.pairs} dataDoc={this.dataDoc} />;
}
}
@@ -116,34 +101,25 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
componentDidMount() {
this.props.setContentView?.(this);
- // this.createPairs();
this.fetchData();
}
fetchData() {
- const uri = this.dataUrl?.url.href;
- fetch('/csvData?uri=' + uri).then(res =>
- res.json().then(
- action(res => {
- this.pairs = res;
- })
- )
- );
+ fetch('/csvData?uri=' + this.dataUrl?.url.href) //
+ .then(res => res.json().then(action(res => !res.errno && (this.pairs = res))));
}
// handle changing the view using a button
@action changeViewHandler(e: React.MouseEvent<HTMLButtonElement>) {
e.preventDefault();
e.stopPropagation();
- this.rootDoc._dataVizView = this.currView === 'table' ? 'histogram' : 'table';
+ this.rootDoc._dataVizView = this.dataVizView === DataVizView.TABLE ? DataVizView.LINECHART : DataVizView.TABLE;
}
render() {
- if (this.pairs.length == 0) {
- return <div>Loading...</div>;
- }
-
- return (
+ return this.pairs.length == 0 ? (
+ <div>Loading...</div>
+ ) : (
<div
className="dataViz"
onWheel={e => e.stopPropagation()}
diff --git a/src/client/views/nodes/DataVizBox/components/LineChart.tsx b/src/client/views/nodes/DataVizBox/components/LineChart.tsx
index e5f7dc4f4..313164691 100644
--- a/src/client/views/nodes/DataVizBox/components/LineChart.tsx
+++ b/src/client/views/nodes/DataVizBox/components/LineChart.tsx
@@ -1,18 +1,15 @@
import { action, computed, IReactionDisposer, observable, reaction } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
-import { 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';
-import { Chart, ChartProps } from '../ChartInterface';
-import './Chart.scss';
-import { List } from '../../../../../fields/List';
-import { PinProps, PresBox } from '../../trails';
import { listSpec } from '../../../../../fields/Schema';
import { Cast } from '../../../../../fields/Types';
+import { Docs } from '../../../../documents/Documents';
+import { PinProps, PresBox } from '../../trails';
+import { createLineGenerator, drawLine, minMaxRange, scaleCreatorNumerical, xAxisCreator, xGrid, yAxisCreator, yGrid } from '../utils/D3Utils';
+import './Chart.scss';
type minMaxRange = {
xMin: number | undefined;
@@ -21,22 +18,43 @@ type minMaxRange = {
yMax: number | undefined;
};
-interface SelectedDataPoint {
+export interface DataPoint {
x: number;
y: number;
+}
+interface SelectedDataPoint extends DataPoint {
elem?: d3.Selection<d3.BaseType, unknown, SVGGElement, unknown>;
}
+export interface LineChartData {
+ xLabel: string;
+ yLabel: string;
+ dataSet: DataPoint[][];
+}
+export interface LineChartProps {
+ rootDoc: Doc;
+ pairs: { x: number; y: number }[];
+ width: number;
+ height: number;
+ dataDoc: Doc;
+ fieldKey: string;
+ margin: {
+ top: number;
+ right: number;
+ bottom: number;
+ left: number;
+ };
+}
@observer
-export class LineChart extends React.Component<ChartProps> implements Chart {
- private _dataReactionDisposer: IReactionDisposer | undefined = undefined;
- private _heightReactionDisposer: IReactionDisposer | undefined = undefined;
- private _widthReactionDisposer: IReactionDisposer | undefined;
+export class LineChart extends React.Component<LineChartProps> {
+ private _disposers: { [key: string]: IReactionDisposer } = {};
@observable private _x: number = 0;
@observable private _y: number = 0;
@observable private _currSelected: SelectedDataPoint | undefined = undefined;
+ @observable private _lineChartData: LineChartData | undefined = undefined;
// create ref for the div
- private _chartRef: React.RefObject<HTMLDivElement> = React.createRef();
+ private _lineChartRef: React.RefObject<HTMLDivElement> = React.createRef();
+ private _lineChartSvg: d3.Selection<SVGGElement, unknown, null, undefined> | undefined;
private _rangeVals: minMaxRange = {
xMin: undefined,
xMax: undefined,
@@ -45,43 +63,47 @@ export class LineChart extends React.Component<ChartProps> implements Chart {
};
// TODO: nda - some sort of mapping that keeps track of the annotated points so we can easily remove when annotations list updates
- private _chartSvg: d3.Selection<SVGGElement, unknown, null, undefined> | 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
-
+ componentWillUnmount() {
+ Array.from(Object.keys(this._disposers)).forEach(key => this._disposers[key]());
+ }
componentDidMount = () => {
- this._dataReactionDisposer = reaction(
- () => this.props.chartData,
- chartData => {
- this._rangeVals = minMaxRange(chartData.data);
- this.drawChart();
+ this._disposers.chartData = reaction(
+ () => ({ dataSet: this._lineChartData?.dataSet, w: this.props.width, h: this.props.height }),
+ vals => {
+ if (vals.dataSet) {
+ this._rangeVals = minMaxRange(vals.dataSet);
+ this.drawChart(vals.dataSet);
+ }
},
{ fireImmediately: true }
);
- // DocumentDecorations.Instance.Interacting
- this._heightReactionDisposer = reaction(() => this.props.height, this.drawChart.bind(this));
- this._widthReactionDisposer = reaction(() => this.props.width, this.drawChart.bind(this));
- reaction(
+ this._disposers.annos = 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
- console.log(annotations);
// this.drawAnnotations()
// loop through annotations and draw them
- annotations.forEach(a => {
- this.drawAnnotations(Number(a.x), Number(a.y));
- });
+ annotations.forEach(a => this.drawAnnotations(Number(a.x), Number(a.y)));
// this.drawAnnotations(annotations.x, annotations.y);
},
{ fireImmediately: true }
);
-
- this.props.setCurrChart(this);
+ this.generateChartData();
};
+ @action
+ generateChartData() {
+ this._lineChartData = {
+ xLabel: 'x',
+ yLabel: 'y',
+ // TODO: nda - add actual support for multiple sets of data
+ dataSet: [this.props.pairs?.map(pair => ({ x: pair.x, y: pair.y }))],
+ };
+ }
+
+ // 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
+
// gets called whenever the "data-annotations" fields gets updated
drawAnnotations(dataX: number, dataY: number) {
// TODO: nda - can optimize this by having some sort of mapping of the x and y values to the individual circle elements
@@ -115,45 +137,27 @@ export class LineChart extends React.Component<ChartProps> implements Chart {
}
return false;
};
- _getAnchor = (pinProps?: PinProps) => {
- // store whatever information would allow me to reselect the same thing (store parameters I would pass to get the exact same element)
+ // create a document anchor that stores whatever is needed to reconstruct the viewing state (selection,zoom,etc)
+ getAnchor = (pinProps?: PinProps) => {
const anchor = Docs.Create.TextanchorDocument({
- /*put in some options*/
title: 'line doc selection' + this._currSelected?.x,
});
PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: { ...(pinProps?.pinData ?? {}), dataviz: this._currSelected ? [this._currSelected.x, this._currSelected.y] : undefined } }, this.props.dataDoc);
return anchor;
- // 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>(${data.x},${data.y})</b>`;
- }
-
- @computed get height(): number {
+ @computed get height() {
return this.props.height - this.props.margin.top - this.props.margin.bottom;
}
- @computed get width(): number {
+ @computed get width() {
return this.props.width - this.props.margin.left - this.props.margin.right;
}
setupTooltip() {
const tooltip = d3
- .select(this._chartRef.current)
+ .select(this._lineChartRef.current)
.append('div')
.attr('class', 'tooltip')
.style('opacity', 0)
@@ -169,13 +173,13 @@ export class LineChart extends React.Component<ChartProps> implements Chart {
@action
setCurrSelected(x: number, y: number) {
// TODO: nda - get rid of svg element in the list?
- this._currSelected = { x: x, y: y };
+ this._currSelected = { x, y };
}
drawDataPoints(data: DataPoint[], idx: number, xScale: d3.ScaleLinear<number, number, never>, yScale: d3.ScaleLinear<number, number, never>) {
- if (this._chartSvg) {
+ if (this._lineChartSvg) {
const circleClass = '.circle-' + idx;
- this._chartSvg
+ this._lineChartSvg
.selectAll(circleClass)
.data(data)
.join('circle') // enter append
@@ -189,30 +193,13 @@ export class LineChart extends React.Component<ChartProps> implements Chart {
}
// TODO: nda - can use d3.create() to create html element instead of appending
- drawChart() {
- const { chartData, margin } = this.props;
- const data = chartData.data[0];
+ drawChart = (dataSet: DataPoint[][]) => {
// clearing tooltip and the current chart
- 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
+ d3.select(this._lineChartRef.current).select('svg').remove();
+ d3.select(this._lineChartRef.current).select('.tooltip').remove();
const { xMin, xMax, yMin, yMax } = this._rangeVals;
- // const svg = d3.select(this._chartRef.current).append(this.svgContainer.html());
- // adding svg
- this._chartSvg = d3
- .select(this._chartRef.current)
- .append('svg')
- .attr('width', `${this.width + margin.right + margin.left}`)
- .attr('height', `${this.height + margin.top + margin.bottom}`)
- .append('g')
- .attr('transform', `translate(${margin.left}, ${margin.top})`);
-
- const svg = this._chartSvg;
-
- if (xMin == undefined || xMax == undefined || yMin == undefined || yMax == undefined) {
- // TODO: nda - error handle
+ if (xMin === undefined || xMax === undefined || yMin === undefined || yMax === undefined) {
return;
}
@@ -220,9 +207,15 @@ export class LineChart extends React.Component<ChartProps> implements Chart {
const xScale = scaleCreatorNumerical(xMin, xMax, 0, this.width);
const yScale = scaleCreatorNumerical(0, yMax, this.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);
+ // adding svg
+ const margin = this.props.margin;
+ const svg = (this._lineChartSvg = d3
+ .select(this._lineChartRef.current)
+ .append('svg')
+ .attr('width', `${this.width + margin.right + margin.left}`)
+ .attr('height', `${this.height + margin.top + margin.bottom}`)
+ .append('g')
+ .attr('transform', `translate(${margin.left}, ${margin.top})`));
// create x and y grids
xGrid(svg.append('g'), this.height, xScale);
@@ -230,7 +223,9 @@ export class LineChart extends React.Component<ChartProps> implements Chart {
xAxisCreator(svg.append('g'), this.height, xScale);
yAxisCreator(svg.append('g'), this.width, yScale);
- // draw the line
+ // draw the plot line
+ const data = dataSet[0];
+ const lineGen = createLineGenerator(xScale, yScale);
drawLine(svg.append('path'), data, lineGen);
// draw the datapoint circle
@@ -243,16 +238,15 @@ export class LineChart extends React.Component<ChartProps> implements Chart {
const mousemove = action((e: any) => {
const bisect = d3.bisector((d: DataPoint) => d.x).left;
const xPos = d3.pointer(e)[0];
- const x0 = bisect(data, xScale.invert(xPos - 25));
+ const x0 = bisect(data, xScale.invert(xPos - 25)); // shift x by -25 so that you can reach points on the left-side axis
const d0 = data[x0];
this._x = d0.x;
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);
// TODO: nda - updating the inner html could be deadly cause injection attacks!
tooltip
- .html(() => this.tooltipContent(d0))
+ .html(() => `<b>(${d0.x},${d0.y})</b>`) // text content for tooltip
.style('pointer-events', 'none')
.style('transform', `translate(${xScale(d0.x) - this.width / 2 + 12}px,${yScale(d0.y) + 30}px)`);
});
@@ -260,7 +254,7 @@ export class LineChart extends React.Component<ChartProps> implements Chart {
const onPointClick = action((e: any) => {
const bisect = d3.bisector((d: DataPoint) => d.x).left;
const xPos = d3.pointer(e)[0];
- const x0 = bisect(data, xScale.invert(xPos - 25));
+ const x0 = bisect(data, xScale.invert(xPos - 25)); // shift x by -25 so that you can reach points on the left-side axis
const d0 = data[x0];
this._x = d0.x;
this._y = d0.y;
@@ -269,27 +263,22 @@ export class LineChart extends React.Component<ChartProps> implements Chart {
this._currSelected = { x: d0.x, y: d0.y, elem: selected };
});
- this._chartSvg
- .append('rect')
+ svg.append('rect')
.attr('class', 'overlay')
.attr('width', this.width)
.attr('height', this.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);
- })
- .on('mouseout', () => {
- tooltip.transition().duration(300).style('opacity', 0);
- })
+ .on('mouseover', () => focus.style('display', null))
+ .on('mouseout', () => tooltip.transition().duration(300).style('opacity', 0))
.on('mousemove', mousemove)
.on('click', onPointClick);
- }
+ };
render() {
return (
- <div ref={this._chartRef} className="chart-container">
+ <div ref={this._lineChartRef} className="chart-container">
<span>Curr Selected: {this._currSelected ? `x: ${this._currSelected.x} y: ${this._currSelected.y}` : 'none'}</span>
</div>
);
diff --git a/src/client/views/nodes/DataVizBox/components/TableBox.tsx b/src/client/views/nodes/DataVizBox/components/TableBox.tsx
index dfa8262d8..28114036f 100644
--- a/src/client/views/nodes/DataVizBox/components/TableBox.tsx
+++ b/src/client/views/nodes/DataVizBox/components/TableBox.tsx
@@ -1,16 +1,12 @@
-import { action, computed, observable } from "mobx";
-import { observer } from "mobx-react";
-import * as React from "react";
+import { action, computed, observable } from 'mobx';
+import { observer } from 'mobx-react';
+import * as React from 'react';
interface TableBoxProps {
- pairs: {x: number, y:number}[]
+ pairs: { x: number; y: number }[];
}
-
export class TableBox extends React.Component<TableBoxProps> {
-
-
-
render() {
return (
<div className="table-container">
@@ -22,16 +18,17 @@ export class TableBox extends React.Component<TableBoxProps> {
</tr>
</thead>
<tbody>
- {this.props.pairs.map(p => {
- return (<tr className="table-row">
- <td>{p.x}</td>
- <td>{p.y}</td>
- </tr>)
- })}
+ {this.props.pairs?.map(p => {
+ return (
+ <tr className="table-row">
+ <td>{p.x}</td>
+ <td>{p.y}</td>
+ </tr>
+ );
+ })}
</tbody>
</table>
</div>
- )
+ );
}
-
-} \ No newline at end of file
+}
diff --git a/src/client/views/nodes/DataVizBox/utils/D3Utils.ts b/src/client/views/nodes/DataVizBox/utils/D3Utils.ts
index 2bb091999..e1ff6f8eb 100644
--- a/src/client/views/nodes/DataVizBox/utils/D3Utils.ts
+++ b/src/client/views/nodes/DataVizBox/utils/D3Utils.ts
@@ -1,5 +1,5 @@
import * as d3 from 'd3';
-import { DataPoint } from '../ChartBox';
+import { DataPoint } from '../components/LineChart';
// TODO: nda - implement function that can handle range for strings