d3 v4 + react + es6 + crossfilter: Selection.exit().remove() 不工作

d3 v4 + react + es6 + crossfilter: Selection.exit().remove() not working

我正在使用 crossfilter.js and d3.js v4 with ES6 style React in an attempt to make dimensional charts with context brushing. Essentially, I took this example 并将其转换为 ES6。

我遇到的问题是 selection.exit().remove() 不起作用,以至于在每次重绘时,越来越多的圆圈附加到 svg g 元素。创建画笔时会触发重绘。我通过 运行

检查
selection.exit()
  .attr('class', d => {
    console.log('anything');
    return 'anything';
  })
  .remove();

但没有输出任何内容,所以我认为我的数据选择无效。

上下文如下:

componentDidMount() {
  const el = ReactDOM.findDOMNode(this); // the mounted svg element

  const svg = d3.select(el)
    .attr('width', 300)
    .attr('height', 500);

  const g = svg.append('g')
    .attr('transform', 'translate(32,32)');

  let circles = g.append('g')
    .selectAll('circle');

  const brushGroup = g.append('g')
    .attr('class', 'brush')
    .call(brush);

  function redraw() {
    const all = group.all(); // crossfilter group returns an array

    xAxisGroup.call(xAxis);
    yAxisGroup.call(yAxis);

    circles = circles.data(all, d => d); // keyFn for data constancy

    circles.enter().append('circle')
      .attr('r', radius)
      .attr('cx', plotX) // radius + plotX/Y are simple curry functions
      .attr('cy', plotY);

    circles.exit().remove(); // not working!!
  }

  redraw();
}

我也知道 v4 中 d3-selection 的这一变化,但我不太确定哪些行是我的 update 哪些是我的 update + enter.

如有任何帮助,我们将不胜感激。谢谢!

我怀疑问题出在以下两点之一。可能在下面#1。如果没有一个工作示例来测试事情,很难说清楚,但是你去吧:

  1. 我认为 selectAlldata 连接应该在 redraw 函数中一起发生。因为您永远不会在重绘函数中重做 selectAll,所以您的选择永远不会包含任何元素。如果您在 redraw 函数中检查 enterexit 选择,您的 enter 选择将始终包含所有数据点,因为基础选择是空的。

  2. 你的数据键函数returns一个对象。由于该对象是 Crossfilter 的 group.all 的结果,它们应该可以通过引用进行比较,但是 circles.data(all, d => d.key).

  3. 会更安全

解决方案应该是:

componentDidMount() {
  const el = ReactDOM.findDOMNode(this); // the mounted svg element

  const svg = d3.select(el)
    .attr('width', 300)
    .attr('height', 500);

  const g = svg.append('g')
    .attr('transform', 'translate(32,32)');

  let circlesGroup = g.append('g'); // Just hang on to the group

  const brushGroup = g.append('g')
    .attr('class', 'brush')
    .call(brush);

  function redraw() {
    const all = group.all(); // crossfilter group returns an array

    xAxisGroup.call(xAxis);
    yAxisGroup.call(yAxis);

    let circles = circlesGroup // Do the selection and data join here
      .selectAll('circle')
        .data(all, d => d.key); // Have the key function return a key, not an object

    circles.enter().append('circle')
      .attr('r', radius)
      .attr('cx', plotX) // radius + plotX/Y are simple curry functions
      .attr('cy', plotY);

    circles.exit().remove();
  }

  redraw();
}