D3.js无法更新组中的现有元素

时间:2019-05-28 16:36:58

标签: javascript d3.js svg

我正在尝试使用d3.js和es6类构建图表。 我有一组数据data = [{someProp: '', hasWarning: true}, ...]。 某些数据元素可以具有hasWarning属性。

如果存在此属性,则在父组中绘制<path class="notification"></path>元素。

<g id="g-parent" transform="translate(500, 300)" class="group">
    <circle r="50" cx="10" cy="10" fill="red"></circle>
    <path d="..." transform="translate(30,-40) scale(0.05)"></path>
</g>

当数据更新时,我重画了通知。但是,如果某些.notification已经存在,我的代码将添加一个新项,而不是更新exisitng。

Here is example

如何避免添加新元素并更新现有元素?

1 个答案:

答案 0 :(得分:0)

在您的renderNotifications中,您可以在添加任何现有通知之前将其删除。

class ChartRenderer {
  constructor(data) {
    this.data = data;
    this.lineFn = d3.line().curve(d3.curveLinear);
  }

  renderSvg() {
    this.svg = d3.select('body')
      .append('svg')
      .attr('width', 1000)
      .attr('height', 1000)
      .attr('id', 1000);
  }

  renderContainer() {
    this.container = this.svg.append('g')
      .attr('id', 'testUpdate');
  }

  renderGroups() {
    this.groupSelection = this.container.selectAll('.group')
      .data(this.data);

    this.groupEnter = this.groupSelection.enter()
      .append('g')
      .attr('id', (d, i) => `g-${d._id}`)
      .attr('transform', (d, i) => `translate(${d.position.x}, ${d.position.y})`)
      .attr('class', 'group');

    this.groupSelection
      .exit()
      .classed('remove', true)
      .transition()
      .delay(200)
      .remove();
  }

  renderCircles() {
    this.circles = this.groupEnter
      .append('circle')
      .attr('r', 50)
      .attr('cx', 10)
      .attr('cy', 10)
      .attr('fill', 'red');
  }


  renderNotifications() {
    this.groupEnter.select('.notification').remove();
    this.notifications = this.groupEnter.filter(d => d.hasWarnings)
      .append('path')
      .attr('class', 'notification')
      .attr('d', 'M248.747 204.705l6.588 112c.373 6.343 5.626 11.295 11.979 11.295h41.37a12 12 0 0 0 11.979-11.295l6.588-112c.405-6.893-5.075-12.705-11.979-12.705h-54.547c-6.903 0-12.383 5.812-11.978 12.705zM330 384c0 23.196-18.804 42-42 42s-42-18.804-42-42 18.804-42 42-42 42 18.804 42 42zm-.423-360.015c-18.433-31.951-64.687-32.009-83.154 0L6.477 440.013C-11.945 471.946 11.118 512 48.054 512H527.94c36.865 0 60.035-39.993 41.577-71.987L329.577 23.985zM53.191 455.002L282.803 57.008c2.309-4.002 8.085-4.002 10.394 0l229.612 397.993c2.308 4-.579 8.998-5.197 8.998H58.388c-4.617.001-7.504-4.997-5.197-8.997z')
      .attr('transform', 'translate(30,-40) scale(0.05)');

  }
}


class Chart {
  constructor(data = []) {
    // console.log(data);
    this.data = data;
    this.data.forEach(this.multiplyElementCoordinates);

    this.renderer = new ChartRenderer(this.data);
    this.draw();
  }

  draw() {
    this.renderer.renderSvg();
    this.renderer.renderContainer();
    this.renderer.renderGroups();
    this.renderer.renderCircles();
    this.renderer.renderNotifications();
  }

  multiplyElementCoordinates(el) {
    el.position.x *= 100;
    el.position.y *= 100;
  }

  toggleNotifications() {
    this.data.forEach(d => {
      d.hasWarnings = true;
    });

    this.renderer.renderNotifications();
  }
}


const data = [{
    _id: 'first',
    position: {
      x: 5,
      y: 1
    },
    hasWarnings: true
  },
  {
    _id: 'second',
    position: {
      x: 5,
      y: 3
    }
  },
  {
    _id: 'third',
    position: {
      x: 3,
      y: 5
    }
  },
  {
    _id: 'fourth',
    type: 'Condition',
    position: {
      x: 7,
      y: 5
    }
  }
];
const lineChart = new Chart(data);

setTimeout(() => {
  lineChart.toggleNotifications();
}, 5000)
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>

Your Forked Fiddle