将D3条形图转换为React D3条形图

时间:2016-07-13 22:15:10

标签: javascript d3.js reactjs

我正在将香草D3水平条形图转换为React D3水平条形图。我可以通过React渲染条形图,但是有一些问题:

  1. 如何展开条形组件(width = matrix[x1])以便它们 不要堆叠在一起? - > 已解决,请参阅下文
  2. 如何在第1组的顶部渲染第二组条形组件(width = matrix[x0])? - > 已解决,请参阅下文
  3. 如何向条形组件添加过渡?
  4. 我首先提供工作香草D3,然后提供准工作反应D3秒。

    数据:

    var matrix = [{y:0, x0:221, x1:2054},
     {y:1, x0:581, x1:1891},
     {y:2, x0:2485, x1:5128},
     {y:3, x0:135, x1:8849},
     {y:4, x0:31, x1:242}];
    

    Vanilla D3

    // Constants
    var width = 450,
        barHeight = 20,
        height = 300,
        delay = 500,
        duration = 750;
    
    // Type Chart
    var chart = d3.select('.typeBarChart')
      .attr('width', width)
      .attr('height', barHeight*matrix.length);
    
    // X-axis
    var maxCrime = d3.max(matrix, (d) => {
      return d.x1;
    });
    
    var x = d3.scale.linear()
        .domain([0, maxCrime+50])
        .range([0, width]);
    
    var bar = chart.selectAll("g")
        .data(matrix)
        .enter()
        .append("g")
        .attr("transform", function(d, i) { return "translate(0," + i * barHeight + ")"; });
    
    bar.append("rect")
        .attr("fill","steelblue")
        .attr("width", 0)
        .attr("height", barHeight - 1)
      .transition()
      .delay(delay)
      .duration(duration)
      .ease("bounce")
        .attr("width", function(d) { return x(d.x1); })
        .attr("height", barHeight - 1);
    
    bar.append("rect")
        .attr("fill","#E6550D")
        .attr("width", 0)
        .attr("height", barHeight - 1)
      .transition()
      .delay(delay)
      .duration(duration)
      .ease("bounce")
        .attr("width", function(d) { return x(d.x0); })
        .attr("height", barHeight - 1);
    
    bar.append("text")
      .transition()
      .delay(delay+duration)
        .attr("x", function(d) {
          if (d.x1 < 1000) {
            return x(d.x1) + 20;
          } else {
            return x(d.x1) - 3;
          }
        })
        .attr("y", barHeight / 2)
        .attr("dy", ".35em")
        .text(function(d) { return d.x1; });
    

    React Components

    const BarChart = React.createClass({
      render() {
        let { width, height, matrix } = this.props; // matrix data passed in from container component
    
        let maxCrime = d3.max(matrix, (d) => {return d.x1});
    
        let xScale = d3.scale.linear()
          .domain([0, maxCrime+50])
          .range([0, width]);
    
        return (
          <div>
            <h3>Rendering BarChart with React</h3>
            <svg
              width={width}
              height={height} >
                <DataSeries
                  xScale={xScale}
                  matrix={matrix} />
            </svg>
          </div>
        );
      }
    });
    
    const DataSeries = React.createClass({
      propTypes: {
        barHeight:          React.PropTypes.number,
        colors:             React.PropTypes.array,
        matrix:             React.PropTypes.array,
        xScale:             React.PropTypes.func
      },
    
      getDefaultProps() {
        return {
          barHeight:          20,
          matrix:             [],
          colors:             [
                                '#b2182b',
                                '#ef8a62',
                                '#fddbc7',
                                '#d1e5f0',
                                '#67a9cf',
                                '#2166ac'
                              ]
        };
      },
    
      render() {
        let { barHeight, matrix, colors, xScale } = this.props;
        let bars = matrix.map( (datum, index) => {
            return (
              <Bar
                key={index}
                width={xScale(datum.x1)}
                height={barHeight-1}
                fill={colors[index]}
              />
            );
          });
    
        return (
          <g>{bars}</g>
        );
      }    
    });
    
    const Bar = React.createClass({
      propTypes: {
        key:                React.PropTypes.number,
        width:              React.PropTypes.number,
        height:             React.PropTypes.number,
        colors:             React.PropTypes.array,
        matrix:             React.PropTypes.array,
        xScale:             React.PropTypes.func
      },
    
      getDefaultProps() {
        return {
          matrix:               [],
        };
      },
    
      render() {
        let { width, height, fill } = this.props;
    
        return (
          <rect
            width={width}
            height={height}
            fill={fill}
          />
        );
      }
    });
    

1 个答案:

答案 0 :(得分:0)

我能够通过Google Foo对我所需的90%进行三角测量。唯一仍然缺少的部分是过渡。如果我能在别人面前解决这个问题,我会提交编辑。

export const BarChart = React.createClass({

  propTypes: {
    width:  React.PropTypes.number,
    height: React.PropTypes.number,
    data:   React.PropTypes.array.isRequired
  },

  getDefaultProps() {
    return {
      width: 450,
      height: 300
    };
  },

  structureData(districtNumber) {
    let { data, districtInfo } = this.props;

    if (districtNumber) {
      data = data.filter( (glob) => {
        return glob.district == districtNumber;
      });
    }

    const nestedData = d3.nest()
      .key(function(d) {
        return d.type;
      })
      .rollup(function (v) {
        return d3.sum(v, function(d) {return parseInt(d.count);} );
      })
      .entries(data)
      .sort((a, b) => {
        var nameA = a.key.toLowerCase(), nameB = b.key.toLowerCase();
        if (nameA < nameB) //sort string ascending
          return -1;
        if (nameA > nameB)
          return 1;
        return 0;
      });

    return nestedData;
  },

  matrixData(total, district) {
    let matrix = [];

    for (var i=0; i<total.length; i++) {
      var obj = {};
      obj['y'] = i;
      obj['x0'] = district[i].values;
      obj['x1'] = total[i].values;
      matrix.push(obj);
    }

    return matrix;

  },

  render() {
    let { width, height, districtInfo } = this.props;
    const dataTotal = this.structureData();
    const dataDistrict = this.structureData(districtInfo.district_number);

    const matrix = this.matrixData(dataTotal, dataDistrict);

    let maxCrime = d3.max(dataTotal, (d) => {return d.values});

    let xScale = d3.scale.linear()
      .domain([0, maxCrime+50])
      .range([0, width]);

    return (
      <div>
        <svg
          width={width}
          height={height} >
            <DataSeries
              xScale={xScale}
              matrix={matrix} />
        </svg>
      </div>
    );
  }
});

const DataSeries = React.createClass({
  propTypes: {
    barHeight:          React.PropTypes.number,
    colors:             React.PropTypes.array,
    matrix:             React.PropTypes.array,
    xScale:             React.PropTypes.func
  },

  getDefaultProps() {
    return {
      barHeight:          20,
      matrix:             [],
      // interpolationType:  'cardinal',
      colors:             [
                            '#b2182b',
                            '#ef8a62',
                            '#fddbc7',
                            '#d1e5f0',
                            '#67a9cf',
                            '#2166ac'
                          ]
    };
  },

  render() {
    let { barHeight, matrix, colors, xScale } = this.props;
    let barsTotal = matrix.map( (datum, index) => {

        let x = datum.x1 < 1000 ? xScale(datum.x1) + 20 : xScale(datum.x1) - 3;

        const barSettings = {
          datum: datum,
          width: xScale(datum.x1),
          height: barHeight-1,
          fill: colors[index],

        };

        const textSettings = {
          x: x,
          y: barHeight / 2,
          dy: ".35em",
        };

        return (
          <g key={index} transform={`translate(0, ${index*barHeight})`} >
            <Bar {...barSettings} />
            <text {...textSettings}>{datum.x1}</text>
          </g>
        );
      });

    let barsDistrict = matrix.map( (datum, index) => {

        const barSettings = {
          key: index,
          width: xScale(datum.x0),
          height: barHeight-1,
          fill: 'gray',
          transform: `translate(0, ${index*barHeight})`
        };

        return (
          <Bar {...barSettings} />
        );
      });

    return (
      <g>
        <g>{barsTotal}</g>
        <g>{barsDistrict}</g>
      </g>
    );
  }

});

const Bar = React.createClass({
  propTypes: {
    width:              React.PropTypes.number,
    height:             React.PropTypes.number,
    colors:             React.PropTypes.array,
    matrix:             React.PropTypes.array,
    xScale:             React.PropTypes.func
  },

  getDefaultProps() {
    return {
      matrix:               [],
    };
  },

  render() {
    return (
      <rect {...this.props} />
    );
  }
});