r2d3 可视化中的范围 - d3.selectAll 与 svg.selectAll

Scoping in r2d3 visualization - d3.selectAll vs svg.selectAll

为什么 d3.selectAll('rect')... 不能像下面脚本中的鼠标悬停功能那样工作,但 svg.selectAll('rect')... 可以?

svg 是 r2d3 的特殊预设选择器。

此外,我注意到 运行 例如d3.selectAll('rect').remove() 当 运行 来自 Rstudio 的可视化时,来自浏览器控制台的 d3.selectAll('rect').remove() 不起作用。

这来自 r2d3 示例,如 sample.js:

// !preview r2d3 data=c(0.3, 0.6, 0.8, 0.95, 0.40, 0.20)

var barHeight = Math.floor(height / data.length);

svg.selectAll('rect')
  .data(data)
  .enter().append('rect')
    .attr('width', function(d) { return d * width; })
    .attr('height', barHeight)
    .attr('y', function(d, i) { return i * barHeight; })
    .attr('fill', 'steelblue')
    .on('mouseover', function(d){
      d3.select(this).attr('fill', 'red')
      
      //svg.selectAll('rect').attr('fill', 'red')
      d3.selectAll('rect').attr('fill', 'red')
      
    })
    

运行 来自 R 通过 r2d3::r2d3("sample.js", data=c(0.3, 0.6, 0.8, 0.95, 0.40, 0.20))

默认情况下,r2d3 将可视化置于阴影中 DOM。 d3.select 和 d3.select 都从 DOM 的根元素开始搜索,但不要冒险进入影子 DOM 的子节点。

select 和 selectAll 都不会从正在搜索的当前树交叉到影子树中。由于 svg 是阴影 DOM 内元素的 selection,可以使用 svg.selectAll("rect") 找到矩形,但不能使用 d3.selectAll("rect") (矩形不是相对于 SVG 的“阴影”)。

最简单的解决方案是不创建阴影 DOM,方法是将 r2d3 阴影选项设置为 false。

例如(使用 r2d3 文档中的 base example):

r2d3(options(r2d3.shadow = FALSE), data=c(0.3, 0.6, 0.8, 0.95, 0.40, 0.20), script = "barchart.js")

当然,这样做会失去影子根提供的封装,但根据情况,这可能更可取或中立。

我发现有时 r2d3.shadow 选项并不总是有效,所以这是另一个可能的解决方案。事件目标的父级将是您放置它的 svg/g。

// !preview r2d3 data=c(0.3, 0.6, 0.8, 0.95, 0.40, 0.20)

var barHeight = Math.floor(height / data.length);

svg.selectAll('rect')
  .data(data)
  .enter().append('rect')
    .attr('width', function(d) { return d * width; })
    .attr('height', barHeight)
    .attr('y', function(d, i) { return i * barHeight; })
    .attr('fill', 'steelblue')
    .on('mouseover', function(d){
      const parent = d3.select(d.target.parentElement); // this is the original svg
      
      
      //svg.selectAll('rect').attr('fill', 'red')
      parent.selectAll('rect').attr('fill', 'blue')
      d3.select(this).attr('fill', 'red')
      
    })