Javascript 将标题附加到D3树布局会导致错误(D3)

Javascript 将标题附加到D3树布局会导致错误(D3),javascript,d3.js,svg,title,Javascript,D3.js,Svg,Title,我正在尝试向D3树布局中的一些SVG标签添加工具提示。 以下是使用过渡渲染标签的函数: buildLabels() { const labelSelection = d3.select('svg g.labels') .selectAll('text.label') .data(this.nodes); labelSelection.exit() .remove(); labelSelection.enter() .append('text')

我正在尝试向D3树布局中的一些SVG标签添加工具提示。 以下是使用过渡渲染标签的函数:

buildLabels() {
  const labelSelection = d3.select('svg g.labels')
    .selectAll('text.label')
    .data(this.nodes);
  labelSelection.exit()
    .remove();

  labelSelection.enter()
    .append('text')
    .style('fill', 'none')
    .style('stroke', 'none')
    .style('stroke-width', '0')
    .attr('transform', (d: any) => // ...)
    .style('fill-opacity', 0)
    .transition()
    .duration(450)
    .ease(d3.easeCircleIn)
    .attr('transform', (d: any) => {
      // ...
    })
    .attr('class', 'label')
    .style('stroke', '#393D3E')
    .style('fill', '#393D3E')
    .style('fill-opacity', 1)
    .style('stroke-width', '.4')
    .style('text-anchor', (d: any) => d.parent ? 'start' : 'end')
    .text(d => d.name);
}
labelSelection.enter() 
  .append('text') // returns a selection of newly entered text elements
  .style(...)     // returns that same selection
  .attr(... )     // returns that same selection
 //  ...
 .transition()    // returns a transition
 .duration(450)   // returns that same transition
 .ease(...)       // returns that same transition
  // ...
 .text(d => d.name) // returns that same transition
 .append(...)       // error
我试着加上

.append('title')
.text(d => d.name)
.text
之后,我得到一个长控制台错误

core.js:4061 ERROR TypeError: labelSelection.enter(...).append(...).style(...).style(...).style(...).attr(...).style(...).transition(...).duration(...).ease(...).attr(...).attr(...).style(...).style(...).style(...).style(...).style(...).text(...).append is not a function
如果我将功能更改为:

labelSelection.enter()
  .append('text')
  .text(d => d.name)
  .append('title')
  .text(d => d.name);
我得到了我期待的DOM,这是

<text>
  Node name
  <title>Node name</title>
</text>

节点名
节点名
但是,没有一个节点看起来是正确的,并且没有它们应该具有的位置。当然,也会删除所有的转换


我的问题是,是否有其他方法可以添加一个不笨重的标题,或者如何避免上面的错误。谢谢

您正试图附加到转换:

buildLabels() {
  const labelSelection = d3.select('svg g.labels')
    .selectAll('text.label')
    .data(this.nodes);
  labelSelection.exit()
    .remove();

  labelSelection.enter()
    .append('text')
    .style('fill', 'none')
    .style('stroke', 'none')
    .style('stroke-width', '0')
    .attr('transform', (d: any) => // ...)
    .style('fill-opacity', 0)
    .transition()
    .duration(450)
    .ease(d3.easeCircleIn)
    .attr('transform', (d: any) => {
      // ...
    })
    .attr('class', 'label')
    .style('stroke', '#393D3E')
    .style('fill', '#393D3E')
    .style('fill-opacity', 1)
    .style('stroke-width', '.4')
    .style('text-anchor', (d: any) => d.parent ? 'start' : 'end')
    .text(d => d.name);
}
labelSelection.enter() 
  .append('text') // returns a selection of newly entered text elements
  .style(...)     // returns that same selection
  .attr(... )     // returns that same selection
 //  ...
 .transition()    // returns a transition
 .duration(450)   // returns that same transition
 .ease(...)       // returns that same transition
  // ...
 .text(d => d.name) // returns that same transition
 .append(...)       // error
转换和选择共享许多方法(例如
.style()
.attr()
,甚至
.text()
),因此它们看起来非常相似,但并不共享所有方法

您可以执行
selection.append()
,但不能执行
transition.append()
。这就是为什么您会收到错误消息,
append
不是一种转换方法,这解释了您的错误消息:

labelSelection.enter(...).append(...).style(...).style(...).style(...).attr(...).style(...).transition(...).duration(...).ease(...).attr(...).attr(...).style(...).style(...).style(...).style(...).style(...).text(...).append is not a function
.text在这种情况下返回一个转换(因为它被链接到一个转换,如上面第一个代码块中所示),因此我们可以将其简化为“transition.append不是函数”

相反,您可以通过保留对相关选择的引用来打破方法链接:

var labelEnter = labelSelection.enter() 
  .append('text') 
  .style(...)     
  .attr(... )     
 //  ...


 labelEnter.transition()    
 .duration(450)   
 .ease(...)      
 //  ...

 labelEnter.append("title")
   .text(...)
另一种方法是使用
transition.selection()
,它返回转换对应的选择,我认为这会使方法链变得不必要的长:

 labelSelection.enter() 
  .append('text') 
  .style(...)     
  .attr(... )     
 //  ...
 .transition()    
 .duration(450)   
 .ease(...)      
  // ...
 .text(d => d.name); 
 .selection()   // return a selection instead of a transition
 .append("title")
   .text(...)