首页 > 解决方案 > 为什么我对 selection.join() 的调用没有返回输入选择?

问题描述

我已经设法<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>

标签: javascriptd3.js

解决方案


用文档的话来说:

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

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

这意味着selection.join()应该已经返回您所追求的选择,即更新节点的合并选择以及新输入的选择。正如您在代码中亲眼目睹的那样,由于文档未涵盖的小细节,情况并非如此。

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

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

  1. 对于简单的情况,只需省略大括号,这将使箭头函数返回表达式的值:

    .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()选择包括由 enter 和更新处理程序合并为一个返回的选择。尽管我无法为这种相当越野的用途提出应用程序,但可能值得将这些知识留在我们的脑海中。


推荐阅读