首页 > 解决方案 > d3 元素未在 React 中呈现

问题描述

所以我为freecodecamp做了一个树形图,它工作正常,但我想让它更加动态,让用户选择要可视化的数据集(可以选择三个数据集)。为此,我发现这篇 Medium 文章解释了如何将 d3 集成到 react 中。

本质上,在我的render方法中,我使用了方法返回ref={node=>this.node=node}的 ref 属性div,并创建了一个函数,该函数使用引用将数据呈现到该函数上,并在anddiv中调用函数。componentDidMountcomponentDidUpdate

我遇到的问题是rectsvg 中的元素没有渲染。

我知道集成正在工作,因为我使用该函数呈现的第一件事是h4标题。我渲染的下一件事是svg元素。我知道svg正在渲染,因为我可以background-color在 CSS 中更改它并且它看起来很好。我知道 d3 层次结构正在工作,因为我root.leaves()在控制台中显示并且它显示了适当的数据。我没有收到任何错误消息,并且我知道整个createMap方法正在运行 b/c 我可以在函数结束时将某些内容很好地记录到控制台。我认为这可能是色标的问题,所以我将fillsrect设置为black,但仍然一无所获。

这是我的项目的链接,下面是 JS 代码。谁能告诉我这是怎么回事?

$(function(){

  const DATASETS = [
    {
      TYPE: 'KICKSTARTERS',
      NAME: 'Kickstarters',
      URL: 'https://cdn.rawgit.com/freeCodeCamp/testable-projects-fcc/a80ce8f9/src/data/tree_map/kickstarter-funding-data.json'
    },
    {
      TYPE: 'MOVIES',
      NAME: 'Movies',
      URL: 'https://cdn.rawgit.com/freeCodeCamp/testable-projects-fcc/a80ce8f9/src/data/tree_map/movie-data.json'
    },
    {
      TYPE: 'GAMES',
      NAME: 'Games',
      URL: 'https://cdn.rawgit.com/freeCodeCamp/testable-projects-fcc/a80ce8f9/src/data/tree_map/video-game-sales-data.json'
    }
  ];

  //REDUX
  const INDEX = 'INDEX';
  const INITIAL_STATE = 0;

  //action generator
  function setIndex(index){
    return {
      type: INDEX,
      index
    };
  }

  //reducer
  function indexReducer(state = INITIAL_STATE, action){
    switch(action.type){
      case INDEX: return action.index;
      default: return state;
    }
  }

  const store = Redux.createStore(indexReducer);

  //react
  class DropDown extends React.Component{
    constructor(props){
      super(props);
      this.handler = this.handler.bind(this);
    }
    handler(e){
      this.props.setIndex(e.target.selectedIndex);
    }
    render(){
      return (
        <select 
          id='dropdown'
          onChange={this.handler}>
          {DATASETS.map(e=><option>{e.NAME}</option>)}
        </select>
      )
    }
  }

  class Svg extends React.Component{
    constructor(props){
      super(props);
      this.createMap = this.createMap.bind(this);
    }
    componentDidMount(){
      this.createMap();
    }
    componentDidUpdate(){
      this.createMap();
    }
    createMap(){
      const NODE = this.node
      const DATASET = DATASETS[this.props.index];
      d3.select(NODE)
      .html('')
      .append('h4')
      .attr('id', 'description')
      .attr('class', 'text-center')
      .html(`Top ${DATASET.NAME}`)

      //svg setup
      const SVG_PADDING = 20;
      const SVG_WIDTH = 1000;
      const SVG_HEIGHT = 1400;

      var svg = d3.select(NODE)
      .append('svg')
      .attr('width', SVG_WIDTH)
      .attr('height', SVG_HEIGHT)
      .attr('id', 'map');

      d3.json(DATASET.URL)
      .then(
      function(data){
        //heirarchy and map
        var root = d3.hierarchy(data)
        .sum(d=>d.balue)
        .sort((a,b)=>b.height-a.height || b.value-a.value);

        var nodes = d3.treemap()
        .size([SVG_WIDTH, SVG_HEIGHT *  2/3])
        .padding(1)(root)
        .descendants();

        //scale
        var categories = [...new Set(root.leaves().map(e => e.data.category))].sort();
        var unityScale = d3.scaleLinear()
        .domain([0, categories.length]).range([0,1]);
        var colorScale = d3.scaleSequential(d3.interpolateRainbow);
        var discreteScale = d3.scaleOrdinal(d3.schemeCategory20b);

        //map cells
        var cell = svg.selectAll('.cell')
        .data(root.leaves())
        .enter().append('g')
        .attr('class', 'cell')
        .attr('transform', d=>`translate(${d.x0}, ${d.y0})`);

        cell.append('rect')
        .attr('class', 'tile')
        .attr('data-category', d=>d.data.category)
        .attr('data-name', d=>d.data.name)
        .attr('data-value', d=> d.data.value)
        .attr('x', 0).attr('y', 0)
        .attr('width', d=>d.x1-d.x0)
        .attr('height', d=>d.y1-d.y0)
        .attr('fill', d => colorScale(unityScale(categories.indexOf(d.data.category))))
      });

    }
    render(){
      const test = d3.select('#container')
      return <div ref={node=>this.node=node}/>
    }
  }

  //ReactRedux
  const Provider = ReactRedux.Provider;
  const connect = ReactRedux.connect;

  function mapDispatchToProps(dispatch){
    return {
      setIndex: index=>dispatch(setIndex(index))
    }
  }

  function mapStateToProps(state){
    return {
      index: state
    }
  }

  const DropDownConnection = connect(null, mapDispatchToProps)(DropDown);
  const SvgConnection = connect(mapStateToProps, null)(Svg);

  class Wrapper extends React.Component {
    render(){
      return(
        <Provider store={store}>
          <DropDownConnection/>
          <SvgConnection/>
        </Provider>
      )
    }
  }

  ReactDOM.render(<Wrapper/>, $('#container')[0]);
})

标签: reactjsd3.js

解决方案


推荐阅读