D3:如何为一维数组的每个数据元素添加一个父 DOM 元素和多个子 DOM 元素?

问题描述 投票:0回答:1

我无法为一维数组中的每个数据条目创建一个组 g 以及两个子 SVG 组件(textrect)。

allCorrespondingYValues 是一个类似 [1,2,3,4] 的数组

selection.selectAll("g.y-crosshair-tooltip").data(allCorrespondingYValues)
   .join('g')
      .attr("class", "y-crosshair-tooltip")
      .attr("transform", d => "translate(" + (width - margin.right) + "," + (yScale(d)) + ")")
   //.select("text").join('text') // Method 1: Nothing appears, just 1 'g' per data
   //.join("text")                // Method 2: Nothing appears, just 1 'g' per data
   //.append("text")              // Method 3: this will continuously append a new text element inside the parent 'g' every time the crosshair moves and the function this code is contained in is called
   //.selectAll("text").data(d => d).join("text") // Method 4: Throws errors.
   .selectAll("text").data([null]).join("text") // Method 5: This works and creates only 1 child text element for the 'g', but the text is always null because its referencing the null dataset, not the parent dataset.
      .attr("dx", -15) // position relative to its group
      .attr("dy", -15)
      .attr("fill", "black")
      .text(d => "$" + d)

我尝试的四种方法都在上面的代码中,每个方法旁边的注释都解释了它们的问题。最令我惊讶的是方法 1 不起作用,因为 Mike's Selection Guide 提到“select 还会将数据从父级传播到子级,而 selectAll 则不会”和“数据绑定到元素...通过追加从父级继承” 、插入或选择。”所以我希望通过使用

.select("text").join('text')
,我可以只引用来自父级的数据。相反,生成的 DOM 显示 nothing 已添加到父级“g”中。

所以我的两个问题是...

  1. 为什么方法1不起作用?
  2. 为每个数据元素创建父元素和多个子元素的最佳实践方法是什么?

我发现了几个类似的 stackoverflow 问题,但大多数都比较旧,并且使用 Enter() 而不是 join(),或者有 2D 数据数组,所以像方法 4 这样的东西可以工作......而对我来说,我试图参考从父母到孩子的完全相同的数据。

谢谢!

d3.js
1个回答
0
投票

您正在尝试使用join

的“简写”版本
,这不适合您的目的,并且您的尝试只会使代码变得复杂。相反,请使用常规版本,您可以在其中指定显式函数:

<!DOCTYPE html>

<html>
  <head>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/7.8.5/d3.js"></script>
  </head>

  <body>
    <svg></svg>
    <script>
      d3.select("svg")
        .attr("width", 300)
        .attr("height", 300)
        .selectAll("g")
        .data([1,2,3,4])
        .join(
          (enter) => {
            const g = enter.append("g")
              .attr("transform", (d, i) => "translate(" + (i * 16) + ", 20)");
            g.append("text")
              .text(d => d);              
          });
    </script>
  </body>
</html>

© www.soinside.com 2019 - 2024. All rights reserved.