在D3中 - 同步两组单选按钮并更新React State

时间:2018-05-22 06:00:20

标签: reactjs d3.js

首先让我分享一个代码示例,它将非常清楚,轻松地突出我目前遇到的问题:

class App extends React.Component {
  constructor(props) { 
    super(props);
    
    this.state = {
      oppDiv: 'none',
      oppTeam: 'none'
    }
    
    this.chartProps = {
      myLightGrey: '#EEE',
      myMidGrey: '#999',
      myDarkGrey: '#333',
    }
  }
  
  updateButtonColors(button, parent, self) {
    const { myLightGrey, myDarkGrey } = self.chartProps;
    parent.selectAll("rect")
      .attr("fill", myLightGrey)
    parent.selectAll("text")
      .attr("fill", myDarkGrey)


    button.select("rect")
      .attr("fill", myDarkGrey)
    button.select("text")
      .attr("fill", myLightGrey)
  }
  
  grabTeamInfo() {
    var data = [{"teamid":"ARI","division":"NL West"},{"teamid":"ATL","division":"NL East"},{"teamid":"BAL","division":"AL East"},{"teamid":"BOS","division":"AL East"},{"teamid":"CHC","division":"NL Central"},{"teamid":"CWS","division":"AL Central"},{"teamid":"CIN","division":"NL Central"},{"teamid":"CLE","division":"AL Central"},{"teamid":"COL","division":"NL West"},{"teamid":"DET","division":"AL Central"},{"teamid":"HOU","division":"AL West"},{"teamid":"KC","division":"AL Central"},{"teamid":"LAA","division":"AL West"},{"teamid":"LAD","division":"NL West"},{"teamid":"MIA","division":"NL East"},{"teamid":"MIL","division":"NL Central"},{"teamid":"MIN","division":"AL Central"},{"teamid":"NYM","division":"NL East"},{"teamid":"NYY","division":"AL East"},{"teamid":"OAK","division":"AL West"},{"teamid":"PHI","division":"NL East"},{"teamid":"PIT","division":"NL Central"},{"teamid":"STL","division":"NL Central"},{"teamid":"SD","division":"NL West"},{"teamid":"SF","division":"NL West"},{"teamid":"SEA","division":"AL West"},{"teamid":"TB","division":"AL East"},{"teamid":"TEX","division":"AL West"},{"teamid":"TOR","division":"AL East"},{"teamid":"WAS","division":"NL East"}];
  
    return data;
  }
  
  drawOppDivision() {
    
    const teamInfo = this.grabTeamInfo();
    const { myLightGrey, myMidGrey, myDarkGrey } = this.chartProps;
    const { updateButtonColors } = this;
    const divs = ["NL East", "NL Central", "NL West", "AL East", "AL Central", "AL West"];
    d3.select('g.oppDivision')
      .attr("transform", "translate(" + 585 + "," + 135 + ")")
        
    // Draw Button Group For 6 Divisions
    // ==================================
    const oppDivision = d3.select('g.oppDivision')
      .selectAll('.divisions')
      .data(divs)
      .enter()
      .append("g")
        .attr("class", "divisions")
        .attr("cursor", "pointer")
      
    oppDivision.append("rect")
      .attr("x", (d,i) => (i % 3)*67)
      .attr("y", (d,i) => i > 2 ? 27 : 0)
      .attr("rx", 4).attr("ry", 4)
      .attr("width", 65).attr("height", 25)
      .attr("stroke", "#BBB")
      .attr("fill", "#EEE")
    
    oppDivision.append("text")
      .attr("x", (d,i) => 32 + (i % 3)*67)
      .attr("y", (d,i) => i > 2 ? 15 + 27 : 15 + 0)
      .style("font-size", "0.7em")
      .style("text-anchor", "middle")
      .style("font-weight", "700")
      .text(d => d)
    
    const self = this;
    oppDivision
      .on("click", function(d,i) {
        updateButtonColors(d3.select(this), d3.select(this.parentNode), self)
        self.setState({oppDiv: divs[i]})
      })
      .on("mouseover", function() {
        if (d3.select(this).select("rect").attr("fill") != myDarkGrey) {
          d3.select(this)
            .select("rect")
            .attr("fill", myMidGrey); // lol almost here keep trying
        }
      })
      .on("mouseout", function() {
        if (d3.select(this).select("rect").attr("fill") != myDarkGrey) {
          d3.select(this)
            .select("rect")
            .attr("fill", myLightGrey);
        }
      });
    
    // Draw Title
    d3.select('g.oppDivision').append("text")
      .attr("x", -1).attr("y", -15)
      .style("font-size", '1.25em')
      .style("font-weight", '700')
      .style("fill", myDarkGrey)
      .text("Opposing Div / Team") 
  }
  drawOppTeam() {
    
    // Draw Button Group For 5 Teams In Selected Division
    // ====================================================
    // make an object with (team, division, abbrev) keys?
    const teamInfo = this.grabTeamInfo();
    const { myLightGrey, myMidGrey, myDarkGrey } = this.chartProps;
    const { updateButtonColors } = this;
    const { oppDiv } = this.state;
    
    const oppTeamList = teamInfo
      .filter(team => team.division == oppDiv)
      .map(team => team.teamid)
    
    // d3.select('g.oppTeam').selectAll('*').remove() 
    
    d3.select('g.oppTeam')
      .attr("transform", "translate(" + 585 + "," + 135 + ")")

    const oppTeam = d3.select('g.oppTeam')
      .selectAll('.oppteams')
      .data(oppTeamList)
    
    oppTeam
      .enter()
      .append("g")
        .attr("class", "oppteams")
        .attr("cursor", "pointer")

    oppTeam.append("rect")
      .attr("x", (d,i) => i * 40)
      .attr("y", 65)
      .attr("rx", 4).attr("ry", 4)
      .attr("width", 38).attr("height", 20)
      .attr("stroke", myMidGrey)
      .attr("fill", myLightGrey)    
    
    oppTeam.append("text")
      .attr("x", (d,i) => (i * 40)+20)
      .attr("y", 79)
      .style("font-size", "0.7em") 
      .style("font-weight", "700")
      .style("text-anchor", "middle")
      .text(d => d)
    
    oppTeam   // not wanting to work like it should (need D3 GUP)
      .exit()
      .remove()
    


    
    const self = this;
    oppTeam
      .on("click", function(d,i) {
        updateButtonColors(d3.select(this), d3.select(this.parentNode), self)
        self.setState({oppTeam: oppTeamList[i]})
      })
      .on("mouseover", function() {
        if (d3.select(this).select("rect").attr("fill") != myDarkGrey) {
          d3.select(this)
            .select("rect")
            .attr("fill", myMidGrey); // lol almost here keep trying
        }
      })
      .on("mouseout", function() {
        if (d3.select(this).select("rect").attr("fill") != myDarkGrey) {
          d3.select(this)
            .select("rect")
            .attr("fill", myLightGrey);
        }
      });
    // ======
  }
  
  componentDidUpdate() {
    this.drawOppTeam()
  }
  componentDidMount() {
    d3.select('#my-button-svg')
			.attr('width', '100%')
			.attr('height', '100%')
			.attr('viewBox', "0 0 " + (800) + " " + 600)  
			.attr('preserveAspectRatio', "xMaxYMax")  
  
    this.drawOppDivision();
  }
  
  render() {
    return(
      <div>
        <svg id='my-button-svg'>
          <g className="oppDivision" />
          <g className="oppTeam" />
        </svg>
      </div>
    );
  }
}

ReactDOM.render(
  <App />,
  document.getElementById('root')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.13.0/d3.min.js"></script>

<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.2.0/umd/react.development.js"></script>

<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.2.0/umd/react-dom.development.js"></script>


<div id='root'>
  Come On Work!
</div>

我正在努力让2个D3收音机在这里与他人携手合作。应该发生的是:

  • 点击6个部门中的任何一个将显示该棒球部门中5个团队的(正确)列表,并将突出显示该部门。
  • 点击一个新部门将显示5个新团队,并突出显示新部门。
  • 点击一个团队将突出显示该团队。

我面临的当前问题是:

  • 直到我第二次点击分部名称
  • 时才会出现团队列表
  • 团队名称不突出显示。

我认为这是React中整洁,干净的单选按钮代码,在按钮组之间具有简单而有用的交互性(特别是在团队和部门中,我需要一个棒球应用程序)。修复按钮无法正常工作(以及知道我的代码有什么问题)的原因,对我有所帮助!在此先感谢您的帮助。

1 个答案:

答案 0 :(得分:1)

快速修复它,现在似乎对我有用,请告诉我你是否正在寻找它!

从长远来看,我建议保持状态完全在React中(其中componentDidUpdate()负责更新样式)或完全在d3中(意味着你只是渲染SVG和React并不是&#39 ;之后触摸它,分割按钮单击处理程序调用{​​{1}}而不是drawOppTeam())。我认为这个问题很棘手的原因是两个库共享了状态处理。

&#13;
&#13;
componentDidUpdate()
&#13;
class App extends React.Component {
  constructor(props) { 
    super(props);
    
    this.state = {
      oppDiv: 'none',
      oppTeam: 'none'
    }
    
    this.chartProps = {
      myLightGrey: '#EEE',
      myMidGrey: '#999',
      myDarkGrey: '#333',
    }
  }
  
  updateButtonColors(button, parent, self) {
    const { myLightGrey, myDarkGrey } = self.chartProps;
    parent.selectAll("rect")
      .attr("fill", myLightGrey)
    parent.selectAll("text")
      .attr("fill", myDarkGrey)


    button.select("rect")
      .attr("fill", myDarkGrey)
    button.select("text")
      .attr("fill", myLightGrey)
  }
  
  grabTeamInfo() {
    var data = [{"teamid":"ARI","division":"NL West"},{"teamid":"ATL","division":"NL East"},{"teamid":"BAL","division":"AL East"},{"teamid":"BOS","division":"AL East"},{"teamid":"CHC","division":"NL Central"},{"teamid":"CWS","division":"AL Central"},{"teamid":"CIN","division":"NL Central"},{"teamid":"CLE","division":"AL Central"},{"teamid":"COL","division":"NL West"},{"teamid":"DET","division":"AL Central"},{"teamid":"HOU","division":"AL West"},{"teamid":"KC","division":"AL Central"},{"teamid":"LAA","division":"AL West"},{"teamid":"LAD","division":"NL West"},{"teamid":"MIA","division":"NL East"},{"teamid":"MIL","division":"NL Central"},{"teamid":"MIN","division":"AL Central"},{"teamid":"NYM","division":"NL East"},{"teamid":"NYY","division":"AL East"},{"teamid":"OAK","division":"AL West"},{"teamid":"PHI","division":"NL East"},{"teamid":"PIT","division":"NL Central"},{"teamid":"STL","division":"NL Central"},{"teamid":"SD","division":"NL West"},{"teamid":"SF","division":"NL West"},{"teamid":"SEA","division":"AL West"},{"teamid":"TB","division":"AL East"},{"teamid":"TEX","division":"AL West"},{"teamid":"TOR","division":"AL East"},{"teamid":"WAS","division":"NL East"}];
  
    return data;
  }
  
  drawOppDivision() {
    
    const teamInfo = this.grabTeamInfo();
    const { myLightGrey, myMidGrey, myDarkGrey } = this.chartProps;
    const { updateButtonColors } = this;
    const divs = ["NL East", "NL Central", "NL West", "AL East", "AL Central", "AL West"];
    d3.select('g.oppDivision')
      .attr("transform", "translate(" + 585 + "," + 135 + ")")
        
    // Draw Button Group For 6 Divisions
    // ==================================
    const oppDivision = d3.select('g.oppDivision')
      .selectAll('.divisions')
      .data(divs)
      .enter()
      .append("g")
        .attr("class", "divisions")
        .attr("cursor", "pointer")
      
    oppDivision.append("rect")
      .attr("x", (d,i) => (i % 3)*67)
      .attr("y", (d,i) => i > 2 ? 27 : 0)
      .attr("rx", 4).attr("ry", 4)
      .attr("width", 65).attr("height", 25)
      .attr("stroke", "#BBB")
      .attr("fill", "#EEE")
    
    oppDivision.append("text")
      .attr("x", (d,i) => 32 + (i % 3)*67)
      .attr("y", (d,i) => i > 2 ? 15 + 27 : 15 + 0)
      .style("font-size", "0.7em")
      .style("text-anchor", "middle")
      .style("font-weight", "700")
      .text(d => d)
    
    const self = this;
    oppDivision
      .on("click", function(d,i) {
        updateButtonColors(d3.select(this), d3.select(this.parentNode), self)
        self.setState({oppDiv: divs[i]})
      })
      .on("mouseover", function() {
        if (d3.select(this).select("rect").attr("fill") != myDarkGrey) {
          d3.select(this)
            .select("rect")
            .attr("fill", myMidGrey); // lol almost here keep trying
        }
      })
      .on("mouseout", function() {
        if (d3.select(this).select("rect").attr("fill") != myDarkGrey) {
          d3.select(this)
            .select("rect")
            .attr("fill", myLightGrey);
        }
      });
    
    // Draw Title
    d3.select('g.oppDivision').append("text")
      .attr("x", -1).attr("y", -15)
      .style("font-size", '1.25em')
      .style("font-weight", '700')
      .style("fill", myDarkGrey)
      .text("Opposing Div / Team") 
  }
  drawOppTeam() {
    
    // Draw Button Group For 5 Teams In Selected Division
    // ====================================================
    // make an object with (team, division, abbrev) keys?
    const teamInfo = this.grabTeamInfo();
    const { myLightGrey, myMidGrey, myDarkGrey } = this.chartProps;
    const { updateButtonColors } = this;
    const { oppDiv } = this.state;
    
    const oppTeamList = teamInfo
      .filter(team => team.division == oppDiv)
      .map(team => team.teamid)
    
    d3.select('g.oppTeam').selectAll('*').remove() 
    
    d3.select('g.oppTeam')
      .attr("transform", "translate(" + 585 + "," + 135 + ")")
      .attr("cursor", "pointer")

    const oppTeam = d3.select('g.oppTeam')
      .selectAll('.oppteams')
      .data(oppTeamList)
    

    const teams = oppTeam
      .enter()
      .append("g")
        .attr("class", "oppteams")
        

    teams.append("rect")
      .attr("x", (d,i) => i * 40)
      .attr("y", 65)
      .attr("rx", 4).attr("ry", 4)
      .attr("width", 38).attr("height", 20)
      .attr("stroke", (d) => this.state.oppTeam === d ? myLightGrey : myMidGrey)
      .attr("fill", (d) => this.state.oppTeam === d ? myDarkGrey : myLightGrey)    
    
    teams.append("text")
      .attr("x", (d,i) => (i * 40)+20)
      .attr("y", 79)
      .attr("fill", (d) => this.state.oppTeam === d ? myLightGrey : myDarkGrey)
      .style("font-size", "0.7em") 
      .style("font-weight", "700")
      .style("text-anchor", "middle")
      .text(d => d)
    
    //oppTeam   // not wanting to work like it should (need D3 GUP)
      //.exit()
      //.remove()
    


    
    const self = this;
    teams
      .on("click", function(d,i) {
        updateButtonColors(d3.select(this), d3.select(this.parentNode), self)
        self.setState({oppTeam: oppTeamList[i]})
      })
      .on("mouseover", function() {
        if (d3.select(this).select("rect").attr("fill") != myDarkGrey) {
          d3.select(this)
            .select("rect")
            .attr("fill", myMidGrey); // lol almost here keep trying
        }
      })
      .on("mouseout", function() {
        if (d3.select(this).select("rect").attr("fill") != myDarkGrey) {
          d3.select(this)
            .select("rect")
            .attr("fill", myLightGrey);
        }
      });
    // ======
  }
  
  componentDidUpdate() {
    this.drawOppTeam()
  }
  componentDidMount() {
    d3.select('#my-button-svg')
			.attr('width', '100%')
			.attr('height', '100%')
			.attr('viewBox', "0 0 " + (800) + " " + 600)  
			.attr('preserveAspectRatio', "xMaxYMax")  
  
    this.drawOppDivision();
  }
  
  render() {
    return(
      <div>
        <svg id='my-button-svg'>
          <g className="oppDivision" />
          <g className="oppTeam" />
        </svg>
      </div>
    );
  }
}

ReactDOM.render(
  <App />,
  document.getElementById('root')
);
&#13;
&#13;
&#13;