I am trying to understand how d3's methods work. 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. 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. To make the question clear, I am going to use simple examples.
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:
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. Which means it does have neither a circle nor g nor div as its child. Then what is the selectAll method is used for ? 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.