简体   繁体   English

对d3的selectAll方法的好奇心

[英]curiosity on d3's selectAll method

I am trying to understand how d3's methods work. 我试图了解d3的方法是如何工作的。 I think I've been quite getting d3, basic level of course, but there is one weird thing about selectAll method I don't understand. 我认为我已经非常了解d3,基本水平当然,但是有一个奇怪的事情,我不明白selectAll方法。 So when I try to create and append dom nodes to selected dom element, no matter it exists or not, sometimes it creates four nodes or two, or six on the other cases. 因此,当我尝试创建并将dom节点附加到选定的dom元素时,无论它是否存在,有时它会创建四个节点或两个节点,或者在其他情况下创建六个节点。 To make the question clear, I am going to use simple examples. 为了使问题清楚,我将使用简单的例子。

HTML: HTML:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
  </head>
  <body>
     <svg></svg>
  </body>
</html>

JS: JS:

    dummyData = [
         {
           name: 'A',
           age: 50
         },
         {
           name: 'B',
           age: 20
         }
       ]

    svg = d3.select('svg')
            .attr('width','500')
            .attr('height', '300')
          .append('g')
            .attr('transform','translate(40, 40)');


function example_1() {

    svg.selectAll('circle')
      .data(dummyData)
      .enter()
    .append('circle')
      .attr('transform', d => `translate(${d.age}, 20)`)
      .attr('cx',32).attr('cy',53)
      .attr('r',15);

 }


function example_2() {

    svg.selectAll('g')
      .data(dummyData)
      .enter()
    .append('circle')
      .attr('transform', d => `translate(${d.age}, 20)`)
      .attr('cx',32)
      .attr('cy',53)
      .attr('r',15);
}

function example_3() {

    svg.selectAll('div')  // This div is an arbitrary value. It can be any html tag to output the same result 
      .data(dummyData)
      .enter()
    .append('circle')
      .attr('transform', d => `translate(${d.age}, 20)`)
      .attr('cx',32)
      .attr('cy',53)
      .attr('r',15);

 }

function example_4() {

   svg.selectAll('g')
      .data(dummyData)
      .enter()
    .append('circle')
      .attr('transform', d => `translate(${d.age}, 20)`)
      .attr('cx',32)
      .attr('cy',53)
      .attr('r',15);

    svg.selectAll('g')
      .data(dummyData)
      .enter()
    .append('path')
      .attr('stroke','#000')
      .attr('d',`M5,5H500`)
}

function example_5() {

   svg.selectAll('g')
      .data(dummyData)
      .enter()
    .append('circle')
      .attr('transform', d => `translate(${d.age}, 20)`)
      .attr('cx',32)
      .attr('cy',53)
      .attr('r',15);

    svg.selectAll('g')
      .data(dummyData)
      .enter()
    .append('g')
    .append('path')
      .attr('stroke','#000')
      .attr('d',`M5,5H500`)
}


example_1(); // This one creates DOM as: 

<svg>
  <g>
    <circle></circle>
    <circle></circle>
  </g>
</svg>

example_2(); // This one creates DOM as:

<svg>
  <g>
    <circle></circle>
    <circle></circle>
    <circle></circle>
    <circle></circle>
  </g>
</svg>

example_3(); // This one creates DOM as:

<svg>
  <g>
    <circle></circle>
    <circle></circle>
    <circle></circle>
    <circle></circle>
  </g>
</svg>

example_4(); // This one creates DOM as:

<svg>
  <g>
    <circle></circle>
    <circle></circle>
    <path></path>
    <path></path>
    <circle></circle>
    <circle></circle>
    <path></path>
    <path></path>
  </g>
</svg>

example_5(); // This one creates DOM as:

<svg>
  <g>
    <circle></circle>
    <circle></circle>
    <g>
      <path></path>
    </g>
    <g>
      <path></path>
    </g>
  </g>
</svg>

The variable, svg, is a dom node g as a child of svg in my example. 在我的例子中,变量svg是一个dom节点g,作为svg的子节点。 Which means it does have neither a circle nor g nor div as its child. 这意味着它既没有圆也没有g也没有div作为它的孩子。 Then what is the selectAll method is used for ? 那么selectAll方法用于什么? Why can we not just write as 为什么我们不能只写作

svg.data(dummyData)
  .enter()
.append('circle')
  .attr('transform', d => `translate(${d.age}, 20)`)
  .attr('cx',32).attr('cy',53)
  .attr('r',15);

Although I have tried with more different examples, it all behaves differently, but I really can't see what's happening behind the scene. 虽然我尝试了更多不同的例子,但它们的行为都不同,但我真的看不到场景背后发生了什么。 Please help me to understand at least a little. 请帮我理解至少一点。 I am very confused. 我很困扰。

Let's answer your last question first. 我们先回答你的最后一个问题。 Why can't you: 你为什么不能:

svg.data(dummyData).enter()

d3 is using an enter, update, exit pattern. d3正在使用输入,更新,退出模式。 There's tons of reading out there on the pattern and I highly recommend you study up on it. 关于这种模式有大量的阅读,我强烈建议你研究它。 But the quickie is this, it's not just about creating the initial elements but also updating them later. 但快速就是这样,它不仅仅是创建初始元素,还会在以后更新它们。 .selectAll is find me all the elements matching my selector. .selectAll是找到与我的选择器匹配的所有元素。 .data is bind the data to them. .data将数据绑定到它们。 .enter is tell me all the data elements that were not in my .selectAll . .enter是告诉我一切都不在我的数据元素.selectAll So, the answer to your question becomes, without a .selectAll , there's no way for d3 to calculate which data is entering and nothing is appended. 所以,你的问题的答案就变成了,没有.selectAlld3无法计算输入哪些数据,也没有附加任何数据。 In the classic usage, on an initial rendering, the .selectAll returns empty (none of them exist yet), so they are all entering. 在经典用法中,在初始渲染时, .selectAll返回空(它们都不存在),因此它们都进入。

Now, with the basics, let's follow your example 5: 现在,有了基础知识,让我们按照你的例子5:

svg.selectAll('g') //<-- no gs exist in svg
  .data(dummyData)
  .enter() //<-- so, since data is two elements
.append('circle') //<-- you get two circles
  .attr('transform', d => `translate(${d.age}, 20)`)
  .attr('cx',32)
  .attr('cy',53)
  .attr('r',15);

svg.selectAll('g') //<-- no gs still exist in svg
  .data(dummyData)
  .enter() //<-- so since data is two elements
.append('g') //<-- you get two gs
.append('path') //<-- each with a path under them
  .attr('stroke','#000')
  .attr('d',`M5,5H500`)

Now, what you are doing doesn't really make sense here. 现在,你在做什么并不是真的有意义。 Why select g if you care about circles? 如果你关心圈子,为什么选择g Usually, I wouldn't even recommend selecting elements at all. 通常,我甚至不建议选择元素。 If I want a circle to represent each of my datum , I would do something like: 如果我想用圆圈来表示我的每个数据 ,我会做类似的事情:

svg.selectAll('.my_cool_circle')
  .data(dummyData)
  .enter()
.append('circle')
.attr('class', 'my_cool_circle')
...

By using a class, I know that those circles are the circles represent my dummyData . 通过使用类,我知道那些圆圈代表我的dummyData Also, if I need to come back later an update my circles (because my data is now: 另外,如果我需要稍后再回来更新我的圈子(因为我的数据现在是:

dummyData = [
     {
       name: 'A',
       age: 50
     },
     {
       name: 'B',
       age: 20
     },
     {
       name: 'C',
       age: 30
     }          
   ]

). )。

Then: 然后:

 svg.selectAll('.my_cool_circle')
  .data(dummyData)
  .enter()

Would only return the 'C' datum and I'd only append 1 new circle. 只返回'C'数据,我只会追加1个新圆圈。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM