【问题标题】:d3 svg not rendering on initial component render. Reactd3 svg 不在初始组件渲染上渲染。反应
【发布时间】:2016-11-15 08:33:46
【问题描述】:

此组件是作为页面视图的一部分创建的,用户可以从初始仪表板导航到该页面视图。 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);

【问题讨论】:

    标签: javascript d3.js svg reactjs


    【解决方案1】:

    正如您所展示的,从render() 中调用this.renderBrainViz() 是不合适的,因为在render() 中创建的DOM 元素此时仍然是影子DOM 元素。它们只有在 render() 完成之后才成为真正的 DOM 元素,并且 React 会做它的事情来区分这些影子 DOM 元素并将其实现为真正的 DOM。也就是说,第一次调用render(),然后又调用this.renderBrainViz(),这一行:

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

    还没有.brain-one可供选择,因为它不存在。

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

    正确的方法是永远不要从render() 中调用this.renderRectangles(),而是从componentDidUpdate()componentDidMount() 中调用它,就像你已经注释掉的那样。 (那里不需要使用.bind())。

    另外,虽然从renderRectangles() 中调用d3.select(".brain-one") 可能是可以的,但是如果存在多个BrainComponents 就会有问题,因为这样就会有多个.brain-one 并且d3 会选择第一个遇到一个。更好的方法是使用 React 的 ref 功能来设置对 .brain-one 的引用:

    <div className="brain-one" ref="brainOne">
    

    这样,你可以做类似的事情

    d3.select(this.refs.brainOne).append("svg")
    

    最后,在renderRectangles() 中始终删除和重新创建.brain-canvas 可能不是一个好主意。相反,您永远不应该删除它,如果它不存在,则只能有条件地创建它。您可以像这样检查.brain-canvas 是否存在:

    if(d3.select(this.refs.brainOne).select('.brain-canvas').empty()) {
      // means it doesn't exist
    }
    

    或者,您可以使用一种技巧,返回大小为 1 或 0 的 .enter() 集,具体取决于它是否已经存在,使用以下方法:

    d3.select(this.refs.brainOne).selectAll('.brain-canvas')
      .data([null]) // bind to a data array of 1 element
    .enter()
      .append('svg') // will only append the svg if it doesn't exist yet
      .attr('class', 'brain-canvas')
      ....
    

    【讨论】:

    • 这非常有用,而且很有意义。
    猜你喜欢
    • 1970-01-01
    • 2021-06-04
    • 2018-07-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-04-04
    • 2020-03-08
    相关资源
    最近更新 更多