D3 Selections In Depth
By: Liron Hazan
Tags: Data Visualization, JavaScript, In Depth, Frontend, D3js

D3 Selections In Depth

Care to understand how things work under the hood? if so I assume you already reached out the following Mike Bostock’s (the creator of d3) post from 2013.

The post explains the selections implementation. Tough 2013 seems like a lifetime ago in Javascript, the general concepts are the same.The post described the selections structure as a subclass of array. but that was in the past when version 3 was the latest.

Today the returned selection structure is an object.

The selection holds:

An array of the selected elements (groups).

An array of the root element.

Accessors to the transformation methods (used for updating and manipulating the DOM).

Let’s run some code!

Open your browser’s dev-tools console where your d3 project runs and execute the following basic selection: d3.select(‘body’):

So what exactly happened?

The select(‘selector’) is a factory function which returns a new Selection instance as follows:

new Selection([[document.querySelector(selector)]], [document.documentElement])

When we pass the selector to the select()/selectAll() functions, d3 will use it to query the DOM for that element.

It will also place the query result in an array, and will pass it to the Selector’s constructor function.

As we can see, the Selection constructor gets 2 arguments (groups, parents):

function Selection(groups, parents) {

this._groups = groups;

this._parents = parents;

}

The Selection instance will now hold a private reference to the selected element groups.

The selection methods can access the group elements and return a new or updated selection reference (depends on the method).

This technique is called “method chaining” and it enabled by returning the selection instance (using “this”).

If we’ll dig deeper we’ll see that the transformation functions returns the selection_each which iterates the elements, executes the user callback if there’s one and eventually returns the Selection reference (this).

BTW did you recognise the Functor functional pattern in d3.select() ? if so you’ll probably appreciate this post.

Into the sources:

In one of your npm project install the d3-selection package and load it into a simple webpage as follows:

<html lang="en">

<head>

<meta charset="utf-8" />

<meta name="viewport" content="width=device-width, initial-scale=1" />

<script src="node_modules/d3-selection/dist/d3-selection.js"></script>

<link rel="stylesheet" href="style.css" />

</head>

<body>

<div> text </div>

<script>

d3.select('div')

.style('color', 'tomato');

</script>

</body>

</html>

Now open the source tab, find the ‘d3-selection.js’ source and place the breakpoint on the select() function (line ~876).

Paste the following into the console:

new Selection([[document.querySelector(selector)]], [document.documentElement])

Whenever we get a selection in a declarative way, we get a new Selection reference that we can join data into and append groups of elements we want to transform.

Add another breakpoint to the selection_style function (the style function point to it) and during the break log the following:

this.each((value == null

? styleRemove : typeof value === "function"

? styleFunction

: styleConstant)(name, value, priority == null ? "" : priority))

You’ll see that the style() methods eventually will return a reference to the selection we work on with the transformed DOM.

Finally, since most of us use ES6 classes syntax, here’s a basic runnable selection example I just had to make :)