D3 g元素内的圆圈/文本的常规更新模式过渡

时间:2018-09-28 18:47:13

标签: javascript d3.js

这是基于先前的帖子I made here的-我正在其中的工作是在嵌套在g元素内的圆和文本元素上实现d3常规更新模式。下面是一个可重现的示例:

class App extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      mybutton: "A"
    }
  }

  handleButtonChange = (event) => {
    this.setState({
      mybutton: event.target.value
    });
  };

  drawPoints() {
    const {
      mybutton
    } = this.state;

    const myData = [{
        x1: 30,
        x2: 140,
        y1: 50,
        y2: 60,
        letter: "A"
      },
      {
        x1: 50,
        x2: 150,
        y1: 60,
        y2: 120,
        letter: "B"
      },
      {
        x1: 70,
        x2: 120,
        y1: 70,
        y2: 110,
        letter: "C"
      }
    ];

    const pointsLayer = d3.select('#my-svg').select('g.points')
    const xShift = function(d) {
      if (mybutton === "A") {
        return d.x1
      } else {
        return d.x2
      }
    }
    const yShift = function(d) {
      if (mybutton === "A") {
        return d.y1
      } else {
        return d.y2
      }
    }
    const textChange = function(d) {
      if (mybutton === "A") {
        return "white"
      } else {
        return "black"
      }
    }
    const circleColorChange = function(d) {
      if (mybutton === "A") {
        return "#FF0000"
      } else {
        return "#FFAAAA"
      }
    }

    let groups = pointsLayer.selectAll(".myGroups")
      .data(myData);

    const groupsExit = groups.exit().remove();

    const groupsEnter = groups.enter()
      .append("g")
      .attr("class", "myGroups");

    groupsEnter.append("circle")
      .attr("r", 20)
      .attr("fill", d => circleColorChange(d));

    groupsEnter.selectAll("circle")
      .transition()
	  .duration(1000)
	  .delay((d, i) => i * 0.5)
		.attr("fill", d => circleColorChange(d))

    groupsEnter.append("text")
      .style("text-anchor", "middle")
      .style("dominant-baseline", "central")
      .text(d => d.letter);

    groups = groupsEnter.merge(groups)
      .attr("transform", d => "translate(" + xShift(d) + "," + yShift(d) + ")");
    //        .on("mouseover", ...)
    //        .on("mouseout", ...)

  }

  componentDidMount() {
    d3.select('#my-svg')
      .attr('width', '100%')
      .attr('height', '100%')
      .attr('viewBox', "0 0 " + (800) + " " + 600)
      .attr('preserveAspectRatio', "xMaxYMax")

    this.drawPoints();
  }

  componentDidUpdate() {
    this.drawPoints()
  }

  render() {

    const {
      mybutton
    } = this.state;
    return ( <
      div >
      <
      form >
      <
      div >
      <
      label >
      <
      input type = {
        "radio"
      }
      value = {
        "A"
      }
      checked = {
        mybutton === "A"
      }
      onChange = {
        this.handleButtonChange
      }
      /> <
      span > {
        "A"
      } < /span> < /
      label > <
      /div> <
      div >
      <
      label >
      <
      input type = {
        "radio"
      }
      value = {
        "B"
      }
      checked = {
        mybutton === "B"
      }
      onChange = {
        this.handleButtonChange
      }
      /> <
      span > {
        "B"
      } < /span> < /
      label > <
      /div> < /
      form >

      <
      svg id = "my-svg" >
      <
      g className = "points" / >
      <
      /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>

上面示例中可能不正确的相关代码行如下:

groupsEnter.selectAll("circle")
      .transition()
      .duration(1000)
      .delay((d, i) => i * 0.5)
        .attr("fill", d => circleColorChange(d))

在单击A或B的按钮时,我正在寻求以下行为:

  • 每个circleColorChange()函数的颜色变化
  • 文本和圆圈的平滑滑动,而不是当前的瞬时跳跃
  • 更改文本的颜色,具有类似于circleColorChange()的功能,但显然可以为文本着色

对于我的散点图(对于圆/文本的堆叠)而言,圆和文本在g个元素内非常重要。然而,尽管大约30分钟阅读了d3选择文档,但这种转移到带有圆圈/文本的g元素给我实现一般更新模式带来了很多问题。

一如既往,在此感谢您的帮助-非常好奇我在这里做错了什么。

1 个答案:

答案 0 :(得分:2)

您基于<p>组而不是现有组进行了颜色更改更新。我更改为以下内容以更新现有组:

enter()

groups.selectAll("circle")
          .transition()
          .duration(1000)
          .delay((d, i) => i * 0.5)
            .attr("fill", d => circleColorChange(d))
class App extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      mybutton: "A"
    }
  }

  handleButtonChange = (event) => {
    this.setState({
      mybutton: event.target.value
    });
  };

  drawPoints() {
    const {
      mybutton
    } = this.state;

    const myData = [{
        x1: 30,
        x2: 140,
        y1: 50,
        y2: 60,
        letter: "A"
      },
      {
        x1: 50,
        x2: 150,
        y1: 60,
        y2: 120,
        letter: "B"
      },
      {
        x1: 70,
        x2: 120,
        y1: 70,
        y2: 110,
        letter: "C"
      }
    ];

    const pointsLayer = d3.select('#my-svg').select('g.points')
    const xShift = function(d) {
      if (mybutton === "A") {
        return d.x1
      } else {
        return d.x2
      }
    }
    const yShift = function(d) {
      if (mybutton === "A") {
        return d.y1
      } else {
        return d.y2
      }
    }
    const textChange = function(d) {
      if (mybutton === "A") {
        return "white"
      } else {
        return "black"
      }
    }
    const circleColorChange = function(d) {
      if (mybutton === "A") {
        return "#FF0000"
      } else {
        return "#FFAAAA"
      }
    }

    let groups = pointsLayer.selectAll(".myGroups")
      .data(myData);

    const groupsExit = groups.exit().remove();

    const groupsEnter = groups.enter()
      .append("g")
      .attr("class", "myGroups");

    groupsEnter.append("circle")
      .attr("r", 20)
      .attr("fill", d => circleColorChange(d));

    groups.selectAll("circle")
      .transition()
	  .duration(1000)
	  .delay((d, i) => i * 0.5)
		.attr("fill", d => circleColorChange(d))

    groupsEnter.append("text")
      .style("text-anchor", "middle")
      .style("dominant-baseline", "central")
      .text(d => d.letter);

    groups = groupsEnter.merge(groups)
      .attr("transform", d => "translate(" + xShift(d) + "," + yShift(d) + ")");
    //        .on("mouseover", ...)
    //        .on("mouseout", ...)

  }

  componentDidMount() {
    d3.select('#my-svg')
      .attr('width', '100%')
      .attr('height', '100%')
      .attr('viewBox', "0 0 " + (800) + " " + 600)
      .attr('preserveAspectRatio', "xMaxYMax")

    this.drawPoints();
  }

  componentDidUpdate() {
    this.drawPoints()
  }

  render() {

    const {
      mybutton
    } = this.state;
    return ( <
      div >
      <
      form >
      <
      div >
      <
      label >
      <
      input type = {
        "radio"
      }
      value = {
        "A"
      }
      checked = {
        mybutton === "A"
      }
      onChange = {
        this.handleButtonChange
      }
      /> <
      span > {
        "A"
      } < /span> < /
      label > <
      /div> <
      div >
      <
      label >
      <
      input type = {
        "radio"
      }
      value = {
        "B"
      }
      checked = {
        mybutton === "B"
      }
      onChange = {
        this.handleButtonChange
      }
      /> <
      span > {
        "B"
      } < /span> < /
      label > <
      /div> < /
      form >

      <
      svg id = "my-svg" >
      <
      g className = "points" / >
      <
      /svg> < /
      div >
    );
  }
}

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