使用SVG Rect更改React状态单击处理程序

时间:2018-05-06 21:20:44

标签: javascript reactjs d3.js

通常我会确保为我的问题包含一个代码示例,但是在这种情况下,我的代码与the following D3 Radio Button example 100%相似,我只是想将其包含在我的反应组件中。

示例中的相关代码是点击处理程序:

.on("click",function(d,i) {
  updateButtonColors(d3.select(this), d3.select(this.parentNode))
  d3.select("#numberToggle").text(i+1)
});

然而,我没有切换数字,而是在点击此单选按钮时尝试更改我的反应应用的状态。现在,假设我只是试图将状态设置为1,2或3之一,那样(i + 1)就是我想要设置的状态。< / p>

我尝试直接在点击处理程序中调用setState(),但是我的状态没有改变。有关如何做到这一点的任何想法?如果我需要更多代码,请告诉我。

编辑:我已经尝试添加到目前为止我所拥有的代码片段,但我很难让它在stackoverflow上运行。

class App extends React.Component {
  constructor(props) { 
    super(props);
    this.state = { 
      chartType: 1
    }
  }
  
  drawChartTypeButton() {
    
    // colors for different button states 
    const defaultColor= "#7777BB"
    const hoverColor= "#0000ff"
    const pressedColor= "#000077"
    const bWidth= 8; //button width
    const bHeight= 5; //button height
    const bSpace= 1; //space between buttons
    const x0 = 5; //x offset
    const y0 = 5; //y offset
    const labels = [1, 2, 3];
    const updateButtonColors = function(button, parent) {
      parent.selectAll("rect")
        .attr("fill",defaultColor)

      button.select("rect")
        .attr("fill",pressedColor)
    }
    
    // groups for each button (which will hold a rect and text)
    const chartTypeButton = d3.select('g.allbuttons')    
    const buttonGroups= chartTypeButton.selectAll("g.button")
      .data(labels)
      .enter()
      .append("g")
      .attr("class", "button")
      .style("cursor", "pointer")
      .on("click", function(d,i) {
        updateButtonColors(d3.select(this), d3.select(this.parentNode))
        this.setState({chartType: 2})
      })
      .on("mouseover", function() {
        if (d3.select(this).select("rect").attr("fill") != pressedColor) {
          d3.select(this)
            .select("rect")
            .attr("fill",hoverColor);
        }
      })
      .on("mouseout", function() {
        if (d3.select(this).select("rect").attr("fill") != pressedColor) {
          d3.select(this)
            .select("rect")
            .attr("fill",defaultColor);
        }
      })
    
    buttonGroups.append("rect")
      .attr("class","buttonRect")
      .attr("width",bWidth)
      .attr("height",bHeight)
      .attr("x", function(d,i) {return x0+(bWidth+bSpace)*i;})
      .attr("y",y0)
      .attr("rx",1) //rx and ry give the buttons rounded corners
      .attr("ry",1)
      .attr("fill",defaultColor)
    
    // adding text to each toggle button group, centered 
    // within the toggle button rect
    buttonGroups.append("text")
      .attr("class","buttonText")
      .attr("font-family", "arial")
      .attr("font-size", "0.1em")
      .attr("x",function(d,i) {
        return x0 + (bWidth+bSpace)*i + bWidth/2;
      })
      .attr("y",y0)
      .attr("text-anchor","middle")
      .attr("dominant-baseline","central")
      .attr("fill","black")
      .text(function(d) {return d;})
  }
  
  componentDidMount() {
    
    const chart = d3.select('.chart')
      .attr('width', 320)
      .attr('height', 240)
      .attr("viewBox", "0, 0, " + 50 + ", " + 50 + "")
      
    this.drawChartTypeButton();
    
  }
  
  render() {
    return(
      <div className='container'>
        <svg className='chart'>
          <g className="allbuttons" />
        </svg>
      </div>
    );
  }
}

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

<div id='root'>
  Damnit Work
</div>

1 个答案:

答案 0 :(得分:1)

您似乎混淆了点击处理程序中的this范围,您对选择器使用this作为反应组件。

通常我们可以使用箭头函数保留this范围,但是你似乎还需要d3,只需创建一个保存当前上下文的局部变量,这样你就可以在你的点击函数中重复使用它/ p>

// create a local reference to "this" in the drawCharTypeButton function
const self = this; 

// use the local reference to update the componenents state
.on("click", function(d,i) {
    updateButtonColors(d3.select(this), d3.select(this.parentNode));
    self.setState({chartType: 2});
})

然后您当前的代码将正常工作(如果它只显示3个按钮,则选择3个中的任何一个)

请注意,在您的示例代码中,chartWidthchartHeight变量未定义,因此我将它们设置为320x240,因此它与SO上的渲染空间匹配一点

&#13;
&#13;
class App extends React.Component {
  constructor(props) { 
    super(props);
    this.state = { 
      chartType: 1
    }
  }
  
  drawChartTypeButton() {
    
    // colors for different button states 
    const defaultColor= "#7777BB"
    const hoverColor= "#0000ff"
    const pressedColor= "#000077"
    const bWidth= 8; //button width
    const bHeight= 6; //button height
    const bSpace= 0.5; //space between buttons
    const x0 = 5; //x offset
    const y0 = 14; //y offset
    const labels = [1, 2, 3];
    const updateButtonColors = function(button, parent) {
      parent.selectAll("rect")
        .attr("fill",defaultColor)

      button.select("rect")
        .attr("fill",pressedColor)
    }
    
    // groups for each button (which will hold a rect and text)
    const self = this;
    const chartTypeButton = d3.select('g.allbuttons')    
    const buttonGroups= chartTypeButton.selectAll("g.button")
      .data(labels)
      .enter()
      .append("g")
      .attr("class", "button")
      .style("cursor", "pointer")
      .on("click", function(d,i) {
        updateButtonColors(d3.select(this), d3.select(this.parentNode))
        self.setState({chartType: 2})
      })
      .on("mouseover", function() {
        if (d3.select(this).select("rect").attr("fill") != pressedColor) {
          d3.select(this)
            .select("rect")
            .attr("fill",hoverColor);
        }
      })
      .on("mouseout", function() {
        if (d3.select(this).select("rect").attr("fill") != pressedColor) {
          d3.select(this)
            .select("rect")
            .attr("fill",defaultColor);
        }
      })
    
    buttonGroups.append("rect")
      .attr("class","buttonRect")
      .attr("width",bWidth)
      .attr("height",bHeight)
      .attr("x", function(d,i) {return x0+(bWidth+bSpace)*i;})
      .attr("y",y0)
      .attr("rx",5) //rx and ry give the buttons rounded corners
      .attr("ry",5)
      .attr("fill",defaultColor)
    
    // adding text to each toggle button group, centered 
    // within the toggle button rect
    buttonGroups.append("text")
      .attr("class","buttonText")
      .attr("font-family", "arial")
      .attr("font-size", "0.1em")
      .attr("x",function(d,i) {
        return x0 + (bWidth+bSpace)*i + bWidth/2;
      })
      .attr("y",y0+bHeight/2)
      .attr("text-anchor","middle")
      .attr("dominant-baseline","central")
      .attr("fill","white")
      .text(function(d) {return d;})
  }
  
  componentDidMount() {
    
    const chart = d3.select('.chart')
      .attr('width', 160)
      .attr('height', 120)
      .attr("viewBox", "0, 0, " + 50 + ", " + 50 + "")
      
    this.drawChartTypeButton();
    
  }
  
  render() {
    return(
      <div className='container'>
        <svg className='chart'>
          <g className="allbuttons" />
        </svg>
      </div>
    );
  }
}

ReactDOM.render(
  <App />,
  document.getElementById('root')
);
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>

<div id='root'>
  Damnit Work
</div>
&#13;
&#13;
&#13;

关于组合的最佳实践,你应该尝试在内进行所有DOM操作。

现在找到一个可能不完全可能的图表,但这3个按钮可以很容易地呈现而不需要

我还没有合并这些渲染引擎,所以我不能说你当前的方法是否有缺点