为什么我对selection.join()的调用未返回enter选择?

时间:2019-03-16 15:58:57

标签: javascript d3.js

我已经设法使用<g>创建了一些selection.join()标签。完成连接后,我想重新选择所有用于方法链的现有<g>标签的完整列表,即之前存在的标签加上已创建的标签减去销毁的标签。如何从joinedNodes变量中获取此信息?

 private createOrRemovePanelGroups(chartPanelsGroup: any, panelsRectangles: Array<Rectangle>): any {

    const joinedNodes: any = chartPanelsGroup
      .selectAll('g')
      .data(panelsRectangles)
      .join(
          enter => {
          enter.append('g');
      });

在下面的第二个示例中,该方法采用<g>中选定的selectedParentNode和矩形的描述符。它必须在此处绘制一个唯一的矩形。我使用ID进行选择。在第一次运行中,它被创建,但是不包含在.join()返回的选择中。因此,对于新创建的矩形,不执行最后4行。但是,如果第二次执行并且矩形已经存在,则会执行这些行,然后设置属性。

static drawRectangle(selectedParentNode: any, rectangle: Rectangle, uniqueId: any, classStyle: any) {

selectedParentNode
  .selectAll('#' + uniqueId)
  .data([{rectangle}])
  .join(
    (enter: any) => {
      enter
        .append('rect')
        .attr('id', uniqueId);
    },
    (update: any) => update
  )
  .attr('x',  rectangle.getLeftX())
  .attr('y', rectangle.getTopY())
  .attr('width',  rectangle.getWidth())
  .attr('height', rectangle.getHeight())
  .attr('class', classStyle);
}

我的具体问题可以归结为以下MCVE。为什么.join()返回的选择为空?

const joinedSelection = d3.select("body").selectAll(null)
  .data([1])
  .join(enter => { enter.append("p"); });
  
console.log(joinedSelection.empty());   // true -- Why is this selection empty?
  
<script src="https://d3js.org/d3.v5.js"></script>

1 个答案:

答案 0 :(得分:1)

用文档的话来说:

  

# 选择加入输入 [,更新] [,退出])<>

     

根据需要添加,删除和重新排序元素,以匹配先前由selection.data绑定的数据,返回merged输入并更新选择。

这意味着selection.join()应该已经返回了您要选择的内容,即更新后的节点以及新输入的节点的合并选择。正如您在代码中亲眼目睹的那样,情况并非如此,原因是文档中未包含一些小细节。

如果要将函数传递给.join()以便对输入,更新和退出时发生的情况进行细粒度控制,则前两个函数(输入和更新)必须返回它们所作用的相应选择(即返回输入或更新选择)!

在您的代码段中,用于enter选择的处理函数是一个箭头函数,执行一个代码块,该代码块不返回任何选择。因此,输入节点不包含在.join()返回的选择中。根据这些处理程序函数执行的复杂性,基本上有两种解决方法:

  1. 在简单情况下,只需省略大括号即可,这将使arrow函数返回表达式的值:

    .join(enter => enter.append('g'));        
    
  2. 对于更复杂的情况,您可以轻松地从代码块中返回选择:

    .join(enter => {
      // ...do some serious stuff first.
    
      // append the entering nodes
      enter = enter.append("g")
    
      // ...followed by even more action.
    
      // Finally return the selection.
      return enter;
    }
    

请注意,在使用上述(1.)解决方案读取的第二个代码段中,如何正确选择更新。

您的MCVE可以轻松地进行相应调整:

const joinedSelection = d3.select("body").selectAll(null)
  .data([1])
  .join(enter => { return enter.append("p"); });
//  .join(enter => enter.append("p"));  // works as well
  
console.log(joinedSelection.empty());   // false, contains enter selection
<script src="https://d3js.org/d3.v5.js"></script>


流氓用法(不是胆小的人)-与您的特定问题无关。

对回车或更新处理程序函数返回的选择类型没有限制;您可能还会返回任何选择,甚至是空选择或完全不相关的选择。 .join()返回的选择包括回车返回的选择,并且更新处理程序合并为一个。尽管我无法针对这种越野用途提出申请,但值得将这些知识放在脑后。