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 { 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() .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
; } }