I've been learning about d3, and I'm a bit confused about selecting. Consider the following example:
Specifically, let's look at this line:
var node = svg.selectAll(".node")
.data(nodes)
.enter().append("circle")
.attr("class", "node")
.attr("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; })
.attr("r", 8)
.style("fill", function(d, i) { return fill(i & 3); })
.style("stroke", function(d, i) { return d3.rgb(fill(i & 3)).darker(2); })
.call(force.drag)
.on("mousedown", function() { d3.event.stopPropagation(); });
In the documentation it says, "A selection is an array of elements pulled from the current document." I interpret this to mean that svg.selectAll(.node)
creates an array of elements of class .node
pulled from the current document, but as far as I can tell there are no such elements! Unless I'm confused - and I'm almost certain that I am - the only place in the document where something is given the class "node" is after the selection has already occurred (when we write .attr("class", "node")
).
So what is going on here? What does svg.selectAll(".node")
actually select?
I've been learning about d3, and I'm a bit confused about selecting. Consider the following example:
http://bl.ocks/mbostock/1021841
Specifically, let's look at this line:
var node = svg.selectAll(".node")
.data(nodes)
.enter().append("circle")
.attr("class", "node")
.attr("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; })
.attr("r", 8)
.style("fill", function(d, i) { return fill(i & 3); })
.style("stroke", function(d, i) { return d3.rgb(fill(i & 3)).darker(2); })
.call(force.drag)
.on("mousedown", function() { d3.event.stopPropagation(); });
In the documentation it says, "A selection is an array of elements pulled from the current document." I interpret this to mean that svg.selectAll(.node)
creates an array of elements of class .node
pulled from the current document, but as far as I can tell there are no such elements! Unless I'm confused - and I'm almost certain that I am - the only place in the document where something is given the class "node" is after the selection has already occurred (when we write .attr("class", "node")
).
So what is going on here? What does svg.selectAll(".node")
actually select?
- the .enter().append() after the .data() is the one making the reference for it and then you work on that. – Harshal Carpenter Commented Oct 28, 2015 at 19:53
- @HarshalCarpenter But what object is .data(nodes).enter().append() acting on? – Paul Siegel Commented Oct 28, 2015 at 19:55
- .data(nodes) is applied on .selectAll(). Then, if selectAll(rect) does not find any 'rect', then .enter().append() makes the reference and then it works with .data(). – Harshal Carpenter Commented Oct 28, 2015 at 19:57
- 4 Have a look at Mike Bostocks Thinking with Joins. It answers exactly this question. – altocumulus Commented Oct 28, 2015 at 20:10
- 1 @HarshalCarpenter There are so many of them. Reading through the tutorials mentioned on the first ten lines will give you a firm grip on the basic concepts and a thorough understanding of what's going on. You may then more easily shift to special techniques like geo data etc. Also have a look at and try to understand the thousands of examples. – altocumulus Commented Oct 28, 2015 at 20:25
1 Answer
Reset to default 13Although, at first sight, this may look like a simple and silly question, the answer to it is probably the most important one for everyone trying to do some serious work with D3.js. Always keep in mind, that D3.js is all about binding data to some DOM structure and providing the means of keeping your data and the document in sync.
Your statement does exactly that:
Select all elements having class
node
. This may very well return an empty selection, as it is in your case, but it will still be ad3.selection
.Bind data to this selection. Based on the above mentioned selection this will, on a per-element basis, pute a join checking if the new data is a) not yet bound to this selection, b) has been bound before, or c) was bound before but is not included in the new data any more. Depending on the result of this check the selection will be divided into an enter, an update, or an exit selection, respectively.
Because your selection was empty in the first place. All data will end up in the enter selection which is retrieved by calling
selection.enter()
.You are now able to append your new elements corresponding to the newly bound data by calling
selection.append()
on the enter selection.
Have a look at the excellent article Thinking with Joins by Mike Bostock for a more in-depth explanation of what is going on.