首页 > 解决方案 > 为什么 selection.exit().size() 为零?

问题描述

我正在尝试通过将空数组加入 d3 选择来从 svg 中删除 rect 元素。

它不工作。

大概我误解了什么。

下面的代码片段设置了 svg。当您按下“清除”按钮时,没有任何反应。

我有 3 个问题(也标记在代码注释中);

  1. 为什么在加入 4 个数据项并创建 4 个关联元素后选择不报告大小 4?
  2. 在 clearSVG 函数中,为什么将“no”数据加入现有选择后 exit() 大小为 0。
  3. 为什么没有删除矩形(可能在 Q2 中回答)。

function init(){
    let initialData = [
        {x:0,y:0,c:"black"},
        {x:0,y:90,c:"orange"},
        {x:90,y:0,c:"green"},
        {x:90,y:90,c:"yellow"}        
    ];
    
    let nodes = d3.select("#svg").selectAll("dataNode") ;
            
    //console.log(`empty nodes size: ${nodes.size()}  all good .. ?`);      // reports 0  
    
    nodes    
    .data(initialData)
    .enter()
    .append(`svg:rect`)
    .attr("class", `dataNode`)
    .attr("x", function(d){return d.x;})
    .attr("y", function(d){return d.y;})     
    .attr("width", 10)
    .attr("height", 10)      
    .attr("fill", function(d){return d.c;}) ;
    
    //console.log(`initial data nodes size: ${nodes.size()} - Q1. why is this not 4 ?`); //reports 0
   
};

function clearSVG(){
    let nodes = d3.select("#svg").selectAll(".dataNode"); // all 4 rect elements in the svg
    //console.log(`nodes size: ${nodes.size()}`);// looking good.. 4 nodes reported
    let newData = [] ; // nada, no data 
    nodes.data(newData) ; // join nothing to the rects - no datum for any element in the selection
    //console.log(`exit size: ${nodes.exit().size()} - Q2. Why is this 0 and not 4 ?`);
    nodes.exit().remove();    
    //console.log(`Q3. Why are the rects still present ?`);
};


init();
*{
    border:none;
    padding:0;       
    font-family:Arial;
    box-sizing:border-box;
}
body{
    margin:10px;
}
#svg{
    display: inline-block ;
    width:100px;
    height:100px;

}
#plotBackGround{
    fill: #FBFBFB;  
}
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<svg id="svg" viewBox="0 0 100 100" >
   <rect id="plotBackGround" x="0" y="0" width="100" height="100"></rect>
</svg>                           
    
<BR><BR>
       
<button class="btn btn-primary" onclick="clearSVG();">Clear</button>

编辑

总结公认答案的症结;selection.data()、.enter()、.append()、.exit() 和 .remove() 返回新的选择。它们不会修改调用它们的选择或返回对它或其部分的引用。

结束编辑

标签: javascriptd3.js

解决方案


问题

这里的问题很简单:您没有正确的更新选​​择。

让我们来看看。你首先这样做:

let nodes = d3.select("#svg").selectAll(".dataNode");

然后,您更改数据:

let newData = [];
nodes.data(newData);

然而,你并没有改变nodes,它们保持原样。当您稍后执行以下操作时:

nodes.exit().remove();

你实际上只是这样做:

d3.select("#svg").selectAll(".dataNode").exit().remove();

如您所见,这没有什么意义。

解决方案

编写正确的更新选​​择。它应该是:

nodes = nodes.data(newData);

如果我们替换 的值nodes,它将有效地为我们提供:

d3.select("#svg").selectAll(".dataNode").data(newData).exit().remove();

这是仅具有该更改的代码:

function init(){
    let initialData = [
        {x:0,y:0,c:"black"},
        {x:0,y:90,c:"orange"},
        {x:90,y:0,c:"green"},
        {x:90,y:90,c:"yellow"}        
    ];
    
    let nodes = d3.select("#svg").selectAll("dataNode") ;
            
    //console.log(`empty nodes size: ${nodes.size()}  all good .. ?`);      // reports 0  
    
    nodes    
    .data(initialData)
    .enter()
    .append(`svg:rect`)
    .attr("class", `dataNode`)
    .attr("x", function(d){return d.x;})
    .attr("y", function(d){return d.y;})     
    .attr("width", 10)
    .attr("height", 10)      
    .attr("fill", function(d){return d.c;}) ;
    
    //console.log(`initial data nodes size: ${nodes.size()} - Q1. why is this not 4 ?`); //reports 0
   
};

function clearSVG(){
    let nodes = d3.select("#svg").selectAll(".dataNode"); // all 4 rect elements in the svg
    //console.log(`nodes size: ${nodes.size()}`);// looking good.. 4 nodes reported
    let newData = [] ; // nada, no data 
    nodes = nodes.data(newData) ; // join nothing to the rects - no datum for any element in the selection
    //console.log(`exit size: ${nodes.exit().size()} - Q2. Why is this 0 and not 4 ?`);
    nodes.exit().remove();    
    //console.log(`Q3. Why are the rects still present ?`);
};


init();
*{
    border:none;
    padding:0;       
    font-family:Arial;
    box-sizing:border-box;
}
body{
    margin:10px;
}
#svg{
    display: inline-block ;
    width:100px;
    height:100px;

}
#plotBackGround{
    fill: #FBFBFB;  
}
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<svg id="svg" viewBox="0 0 100 100" >
   <rect id="plotBackGround" x="0" y="0" width="100" height="100"></rect>
</svg>                           
    
<BR><BR>
       
<button class="btn btn-primary" onclick="clearSVG();">Clear</button>


推荐阅读