【问题标题】:d3 selection confusion with exit() and remove()d3 选择与 exit() 和 remove() 混淆
【发布时间】:2017-12-04 23:23:31
【问题描述】:

所以我正在研究一些 d3 教程,并了解一些事情为什么会以它们的方式工作,并且我遇到了一个特殊的选择实例,它的行为不符合预期。所以我想知道是否有人可以向我解释这一点。

var sales = [
    { product: 'Hoodie',  count: 7 },
    { product: 'Jacket',  count: 6 },
    { product: 'Snuggie', count: 9 },
];

var rects = svg.selectAll('rect')
  .data(sales).enter();

var maxCount = d3.max(sales, function(d, i) {
    return d.count;
});
var x = d3.scaleLinear()
    .range([0, 300])
    .domain([0, maxCount]);
var y = d3.scaleBand()
    .rangeRound([0, 75])
    .domain(sales.map(function(d, i) {
        return d.product;
    }));

rects.append('rect')
    .attr('x', x(0))
    .attr('y', function(d, i) {
        return y(d.product);
    })
    .attr('height', y.bandwidth())
    .attr('width', function(d, i) {
        return x(d.count);
    });  

这一切都很好,生成了 3 个与销售数据相对应的水平条,但这里是我看到歧义的地方:

sales.pop();

rects.data(sales).exit().remove();

最后一行应该从视觉中删除弹出的栏,但它不起作用。我认为我缺少的 d3 选择肯定有什么问题,因为这确实有效:

d3.selectAll('rect').data(sales).exit().remove();

此外,当我打破第一个不起作用的元素时,它似乎确实在退出时选择了正确的元素,但似乎并没有删除它。无论如何,如果有人能解释这里发生了什么,那将非常有帮助,谢谢!

注意:使用 d3 v4

【问题讨论】:

    标签: javascript d3.js data-visualization


    【解决方案1】:

    这是您的rects 选择:

    var rects = svg.selectAll('rect')
        .data(sales).enter();
    

    所以,当你这样做时:

    rects.data(sales).exit().remove();
    

    你正在有效地这样做:

    svg.selectAll('rect')
        .data(sales)
        .enter()
        .data(sales)
        .exit()
        .remove();
    

    因此,您正在绑定数据,调用enter,再次绑定数据并调用exit!哇!

    解决方案:只需创建一个常规的、老式的“更新”选择:

    var rects = svg.selectAll('rect')
        .data(sales);
    

    这是一个带有您的代码的基本演示,在 2 秒后调用 exit

    var svg = d3.select("svg")
    
    var sales = [{
      product: 'Hoodie',
      count: 7
    }, {
      product: 'Jacket',
      count: 6
    }, {
      product: 'Snuggie',
      count: 9
    }, ];
    
    draw();
    
    function draw() {
    
      var rects = svg.selectAll('rect')
        .data(sales);
    
      var maxCount = d3.max(sales, function(d, i) {
        return d.count;
      });
      var x = d3.scaleLinear()
        .range([0, 300])
        .domain([0, maxCount]);
      var y = d3.scaleBand()
        .rangeRound([0, 75])
        .domain(sales.map(function(d, i) {
          return d.product;
        }))
        .padding(.2);
    
      var rectsEnter = rects.enter().append('rect')
        .attr('x', x(0))
        .attr('y', function(d, i) {
          return y(d.product);
        })
        .attr('height', y.bandwidth())
        .attr('width', function(d, i) {
          return x(d.count);
        });
    
      rects.exit().remove();
    
    }
    
    d3.timeout(function() {
      sales.pop();
      draw()
    }, 2000)
    <script src="https://d3js.org/d3.v4.min.js"></script>
    <svg></svg>

    【讨论】:

    • 我的印象是您需要再次调用 .data(sales) 才能重新加入数据,但我想这是错误的。我能够让您的示例正常工作,但是当我移动 sales.pop();以上 rects.exit().remove() 并删除超时,删除功能似乎仍然无法正常工作,我不确定这是为什么。
    【解决方案2】:

    rects 已经是 d3 选择,所以你只需要rects.exit().remove()

    【讨论】:

      猜你喜欢
      • 2016-05-08
      • 2014-04-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-08-02
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多