d3 svg无法渲染初始组件渲染。应对

时间:2016-07-12 22:52:19

标签: javascript d3.js svg reactjs

此组件是作为用户导航到初始仪表板之外的页面视图的一部分创建的。 svg需要正确呈现的所有数据似乎都正确记录,但SVG只是在初始导航到此视图时才创建。该函数正在运行,但html中没有显示SVG。起初我以为是因为图像还没有被加载,但SVG被附加到div而不是直接附加到图像所以它至少我认为会在html中显示减去宽度和高度。任何帮助将不胜感激。

import React, { Component, PropTypes } from 'react';
import $ from 'jquery';
import { connect } from 'react-redux';

class BrainComponent extends Component {
  static propTypes = {
  showBrainData: PropTypes.bool.isRequired,
  showThisHitData: PropTypes.object,
  hit: PropTypes.object
};

constructor(props, context) {
    super(props, context);
    this.state = {
        showBrainData: this.props.showBrainData,
    };
}

componentWillMount() {
    console.log(this.props);
}

handleBrainVizColor() {
    console.log(this.props.hit.Hic);
    let colorString;
    const hic = this.props.hit.Hic;
    const redNum = 80 + (Math.round(hic / 2));
    const greeNum = 180 - (Math.round(hic / 2));
    colorString = "rgba(" + redNum + "," + greeNum + ", 0, .4)";
    return colorString;
}

renderBrainViz() {
    console.log(this.props.hit);
    this.renderRecangles();
}

componentDidMount() {
    // this.renderBrainViz.bind(this);
}

renderRecangles() {
    d3.select(".brain-canvas").remove();
    const fillColor = this.handleBrainVizColor();
    console.log(this.props.showBrainData);
    if (this.props.showBrainData) {
    const brainWidth = $(".brain-img").width();
    const brainHeight = $(".brain-img").height();
    let xLocation;
    let yLocation;
    let width = brainWidth / 2;
    let height = brainHeight / 2;
    console.log(this.props.hit.ImpactDirection);

    switch (this.props.hit.ImpactDirection) {
        case 'URP':
            xLocation = brainWidth / 2;
            yLocation = 0;
        break;
        case 'LRP':
            xLocation = 0;
            yLocation = brainHeight / 2;
            height += 10;
            break;
        case 'CR':
            break;
        case 'LR':
            xLocation = 0;
            yLocation = 0;
            width = brainWidth;
            break;
        case 'UR':
            xLocation = 0;
            yLocation = brainWidth / 2;
            width = brainWidth;
            break;
        case 'BA':
            break;
        case 'LF':
            xLocation = 0;
            yLocation = 0;
            width = brainWidth;
            break;
        case 'UF':
            xLocation = 0;
            yLocation = 0;
            width = brainWidth;
            break;
        case 'ULP':
            xLocation = 0;
            yLocation = 0;
            break;
        case 'LLP':
            xLocation = 0;
            yLocation = 0;
            break;
        }

    const brainCanvas = d3.select(".brain-one").append("svg")
                .attr("width", brainWidth)
                .attr("height", brainHeight)
                .attr("class", "brain-canvas");
    brainCanvas.append("rect")
            .attr("x", xLocation)
            .attr("y", yLocation)
            .attr("width", width)
            .attr("height", height)
            .style("fill", fillColor);
    }
}

render () {
        return (
          <div className="brain-container">
              <div className="brain-one">
                  <img className="brain-img" src="https://s3-us-west-2.amazonaws.com/mvtrak/new-brain.png" />
              </div>
              { this.renderBrainViz() }
              { !this.props.showBrainData ? <div>
                <div className="brain-overlay"></div>
                <div className="select-hit-text">SELECT HIT BELOW</div>
              </div> : null }
          </div>
    );
 }
}

function mapStateToProps(state) {
   console.log(state);
   return {
      hit: state.hitData
   };
}

export default connect(mapStateToProps)(BrainComponent);

1 个答案:

答案 0 :(得分:3)

正如您所显示的那样,从this.renderBrainViz()内调用render()是不合适的,因为在render()内创建的DOM元素在此时仍然是影子DOM元素。它们只有在render()完成后才成为真正的DOM元素,而React会将这些影子DOM元素实现差异并将其实现为真正的DOM。换句话说,第一次调用render(),然后调用this.renderBrainViz(),这一行:

d3.select(".brain-one").append("svg")

尚未选择.brain-one,因为它不存在。

它适用于对render()的第二次调用,因为此时第一次调用已经存在.brain-one,但这是一个幸运的巧合。我仍然认为它不同步。

正确的方法是永远不要在this.renderRectangles()内拨打render(),而是在componentDidUpdate()内以及componentDidMount()内拨打,但请注明。 (那里不需要使用.bind())。

此外,虽然可以在d3.select(".brain-one")内拨打renderRectangles(),但如果存在多个BrainComponent,则会出现问题,因为这会有多个{{1}和d3将选择遇到的第一个。更好的方法是使用React的.brain-one功能设置对ref的引用:

.brain-one

这样,您可以执行类似

的操作
<div className="brain-one" ref="brainOne">

最后,在d3.select(this.refs.brainOne).append("svg") 内始终删除并重新创建renderRectangles()可能不是一个好主意。相反,你永远不应该删除它,只有条件地创建它,如果它不存在。您可以检查.brain-canvas是否存在,如下所示:

.brain-canvas

或者,你可以使用一种技巧,它将返回一个大小为1或0的if(d3.select(this.refs.brainOne).select('.brain-canvas').empty()) { // means it doesn't exist } 集,具体取决于它是否已经存在,使用以下内容:

.enter()