clientjs/packages/dashboard-components/src/ui/RowChart.jsx
changeset 0 5f4fcbc80b37
equal deleted inserted replaced
-1:000000000000 0:5f4fcbc80b37
       
     1 /* eslint func-names: "off" */
       
     2 import React, { Component } from 'react';
       
     3 import PropTypes from 'prop-types';
       
     4 import * as d3 from 'd3';
       
     5 import { withRouter } from 'react-router-dom';
       
     6 
       
     7 import './RowChart.scss';
       
     8 
       
     9 
       
    10 /**
       
    11  * TODO: As a first implementation we have chosen to delagate the barchart DOM drawing to D3.
       
    12  * This may not be the optimum solution. This may have to be rewrittten to use
       
    13  * React for elementt creation and D3 as the visualisation kernel.
       
    14  */
       
    15 class RowChart extends Component {
       
    16   static propTypes = {
       
    17     data: PropTypes.PropTypes.arrayOf(PropTypes.object).isRequired,
       
    18     tagPrefix: PropTypes.string.isRequired,
       
    19     history: PropTypes.object.isRequired,
       
    20   }
       
    21 
       
    22   componentDidMount() {
       
    23     this.drawChart();
       
    24   }
       
    25 
       
    26   componentDidUpdate() {
       
    27     this.drawChart();
       
    28   }
       
    29 
       
    30   drawChart() {
       
    31     const { node } = this;
       
    32     const { data, tagPrefix } = this.props;
       
    33 
       
    34     const width = 800;
       
    35     const barHeight = 30;
       
    36     const height = barHeight * data.length;
       
    37     const valueMargin = 4;
       
    38     const yAxisHMargin = 10;
       
    39     const yAxisVMargin = 10;
       
    40     const barVMargin = 10;
       
    41 
       
    42     const y = d3.scaleBand()
       
    43       .rangeRound([0, height])
       
    44       .padding(0.1)
       
    45       .domain(data.map(d => d.tag));
       
    46 
       
    47     const yAxis = d3.axisLeft(y);
       
    48 
       
    49     d3.select(node).selectAll('svg').remove();
       
    50     const chart = d3.select(node)
       
    51       .append('svg')
       
    52       .attr('width', '100%');
       
    53 
       
    54     const barsContainer = chart.append('g')
       
    55       .attr('class', 'bars-container');
       
    56 
       
    57     const yAxisContainer = chart.append('g')
       
    58       .attr('class', 'y-axis axis')
       
    59       .call(yAxis);
       
    60 
       
    61     let yAxisWidth = 0;
       
    62     chart.selectAll('.y-axis text')
       
    63       .each(function () { yAxisWidth = Math.max(yAxisWidth, this.getBBox().width); });
       
    64 
       
    65     const x = d3.scaleLinear()
       
    66       .range([0, width - yAxisWidth - yAxisHMargin])
       
    67       .domain([0, d3.max(data, d => d.count)]);
       
    68 
       
    69     const xAxis = d3.axisBottom(x);
       
    70 
       
    71     const xAxisContainer = chart.append('g')
       
    72       .attr('class', 'y-axis axis')
       
    73       .attr('transform', `translate(${[yAxisWidth + 2 * yAxisHMargin, height + yAxisVMargin]})`)
       
    74       .call(xAxis);
       
    75 
       
    76     const bar = barsContainer.selectAll('.bars-container')
       
    77       .data(data)
       
    78       .enter().append('g')
       
    79       .attr('transform', (d, i) => `translate(0,${i * barHeight})`)
       
    80       .attr('class', 'graph-bar');
       
    81 
       
    82     bar.append('rect')
       
    83       .attr('width', d => x(d.count))
       
    84       .attr('height', barHeight - barVMargin)
       
    85       .attr('fill', d => d.color)
       
    86       .attr('stroke', d => d.color)
       
    87       .attr('transform', 'translate(0,5)')
       
    88       .on('click', (d) => {
       
    89         const { history } = this.props;
       
    90         history.push(`/annotations/${tagPrefix}${d.tag}`);
       
    91       });
       
    92 
       
    93     bar.append('text')
       
    94       .attr('y', barHeight / 2)
       
    95       .attr('dy', '.35em')
       
    96       .attr('dx', -valueMargin)
       
    97       .attr('text-anchor', 'end')
       
    98       .text(d => d.count)
       
    99       .attr('x', function (d) {
       
   100         const xWidth = this.getBBox().width;
       
   101         return Math.max(xWidth + valueMargin, x(d.count));
       
   102       });
       
   103 
       
   104     yAxisContainer.attr('transform', `translate(${yAxisWidth + yAxisHMargin},0)`);
       
   105     barsContainer.attr('transform', `translate(${yAxisWidth + 2 * yAxisHMargin},0)`);
       
   106 
       
   107     const totalHeight = height + xAxisContainer.node().getBBox().height + yAxisVMargin;
       
   108     const totalWidth = width + 2 * yAxisHMargin;
       
   109 
       
   110     chart.attr('viewBox', [0, 0, totalWidth, totalHeight].join(' '));
       
   111   }
       
   112 
       
   113   render() {
       
   114     return (
       
   115       <div className="row chart-container">
       
   116         <div className="col col-12" ref={(elt) => { this.node = elt; }} />
       
   117       </div>
       
   118     );
       
   119   }
       
   120 }
       
   121 
       
   122 export default withRouter(RowChart);