The statement

Link to original article: From D3 author Mike Bostock bost.ocks.org/mike/join/

Github Repository

If you feel good, why not go to Github and give it a star?

Content

Let’s say you want to draw a scatter diagram in D3, using each circle element of SVG to visualize your data. You’d be surprised to learn that D3 doesn’t have a direct way to create multiple DOM elements! What’s going on?

Of course, D3 has append methods that you can use to create individual elements. Such as:

svg.append("circle")
    .attr("cx", d.x)
    .attr("cy", d.y)
    .attr("r".2.5);
Copy the code

But that’s just one circle, so if you want to create multiple circles (each representing a data point). You might think to do that with a for loop, right? This is a pretty intuitive idea, and there’s nothing wrong with it, but before we get there let’s take a look at how creating multiple elements is implemented in D3:

svg.selectAll("circle")
  .data(data)
  .enter().append("circle")
    .attr("cx".function(d) { return d.x; })
    .attr("cy".function(d) { return d.y; })
    .attr("r".2.5);
Copy the code

The above code does exactly what you want: it creates a circle for each data point, using the x and y attributes of the data point as the coordinates of the circle. But what does selectAll(“circle”) in this code mean? Why do we select a circle that we know doesn’t currently exist, and then use the return value of this method to create a new element?

The idea of this code is: don’t tell D3 how to do it, but tell D3 what you want. If you want a one-to-one correspondence between the circle elements and the data, you should not tell D3 to create the circle elements, but rather tell D3:.selectall (“circle”) that the resulting circle set should correspond to.data(data). This idea is called a Join.

As can be seen from the above picture:

  • The data setCollection of DOM elementsThe intersection gives rise to the middleupdateA collection of
  • No DOM element corresponding to Data produces the one on the leftenterCollections (i.e., missing DOM elements)
  • Similarly, all DOM elements with no data corresponding to them produce the right-hand oneexitCollection (which means these DOM elements will be removed)

Now we can look at the code that uses the Enter-append model:

  1. First of all,svg.selectAll("circle")An empty collection is returned because the SVG container is currently empty. The SVG here is the parent node of all subsequent circle elements.
  2. svg.selectAll("circle")The set returned next sumsdataforJoinOperation, resulting in the three sets we mentioned above:updateThe collection,enterThe collection,exitBecause the set of Elements is initially empty, soupdateexitThe set is empty, andenterThe collection automatically generates a placeholder for each new data element.
  3. The default.data(data)Returns theupdateSet, becauseupdateThe collection is empty, so we’re not going to do anything with it, so here we call.enter()getenterCollection.
  4. Next, forenterFor every element in the set, we useselection.append('circle')(Note that operations on collections are applied to each element in the collection.) This creates one for each data pointcircle(These circles are in their parent SVG node)

Thinking in terms of joins means that all we need to do is declare a relationship between a DOM collection (such as the circle collection here) and a data collection, and describe that relationship by handling three different sets of states enter, Update, and exit.

Why, you may ask, do my data visualization work this way? What are the benefits? Why don’t I just use the for loop to create all the elements I want? The answer is that the idea is very good indeed, and its beauty lies in its generality. For now, our code only handles the Enter part, which is good enough for displaying static data, but if you want to display dynamic data, this Join approach will make your life a lot easier. You only need to do a few things with update and exit to get the effect you want. This also means that you can easily present real-time data, add dynamic interaction for users, and smoothly switch between different presentation data sets.

The following code shows the handling of exit and update collections:

var circle = svg.selectAll("circle")
  .data(data);

circle.exit().remove();

circle.enter().append("circle")
    .attr("r".2.5)
  .merge(circle)
    .attr("cx".function(d) { return d.x; })
    .attr("cy".function(d) { return d.y; });
Copy the code

Whenever the above code is executed, it recalculates the Join and maintains the correspondence between the DOM element collection and the data collection. If your new cube is smaller than the old one, the extra DOM elements will enter the exit collection and be removed. If the new data set is larger than the old one, the new data is entered into the Enter collection and a new DOM element is created. If the number of new datasets is the same as the number of old ones, only the update set will be updated.

The idea of using a Join makes our code more intuitive. You only need to deal with the set of three states, and you don’t need to make complicated logical decisions about if and for. You just have to describe how you want your data set to correspond to the DOM set.

Join also lets you perform different operations on DOM elements in different states. For example, you can work only on the Enter set so that all DOM elements are not updated every time, which can significantly improve the rendering efficiency of your data visualizations. Similarly, you can animate elements of a specified collection, such as the enter element with a zoom-in effect:

circle.enter().append("circle")
    .attr("r".0)
  .transition()
    .attr("r".2.5);
Copy the code

Or add a zoom hide effect to exit’s collection:

circle.exit().transition()
    .attr("r".0)
    .remove();
Copy the code

The translator’s note:

Here is a very good example (also from D3 authors) of the Join idea in practice:

Mike Bostock’s implementation

Here is my implementation of this example (as well as some other examples):

  • The online demo
  • The source code

Want to learn more about D3.js?

Here is my D3.js, Github address for data visualization, welcome to Start & fork :tada:

D3-blog

If you like it, check out the link below:)

Making the home page

Zhihu column

The Denver nuggets

Welcome to follow my official account: