
D3.js (or simply D3) is a JavaScript library for processing and visualizing data. It provides handy utilities for handling and loading data arrays and creating DOM elements. This note describes the work with the main methods of the library, it is suitable for learning the basics of the library and immersing it in its logic and capabilities.
To understand the article useful knowledge of JS, HTML and CSS.
Fluent interface (fluent interface)
D3 implements an approach called fluent interface. When reading the code, it looks like a chain of methods. Each method is called on the object that returned the previous method. To make the code easy to read, each call is located on a separate line:
d3.select('body')
This example is on jsfiddle.net')
Sample
In D3, as in other JS libraries that work with DOM elements, interaction with a document begins with searching for elements in a document and creating a
selection — a wrapper for a set of elements. It gives access to library methods for modifying selected items.
Selection (selection) in D3 is created using the methods
d3.select () and
d3.selectAll () . To create a sample, D3 uses querySelector / querySelectorAll or Sizzle if it is connected to a page (for example, with jQuery).
d3.select('span')
The resulting selection is used to work with elements and to create a selection of descendants (subselection).
<span> </span> <p> <span> </span> <span></span> <span></span> <span></span> </p> <p> </p>
d3.select('span')
This example is on jsfiddle.netAlways remember which sample you're currently working with. Common mistakes when working with D3: call on a descendant element instead of a parent and attempt to change the properties of a nonexistent (deleted or not yet created) element.
The example already uses operations on elements (
selection.style (name [, value]) ), then we will consider them in more detail.
Calculation of values and functors
To work with the DOM, the D3 uses a similar API for all calls. Let's analyze it on the example of a popular task: adding or removing a class from an element. For this we need some sampling methods:
- selection.classed (name, value) adds or removes the class name depending on the boolean value value.
- selection.on (event, callback) is used to handle events, passing the name of the event to event (for example, “click”) and the callback handler function. Handler functions are called with the current element in this, as well as data and index in arguments. The event can be obtained in the variable d3.event. Reinstalling the handler will replace the previous one.
var pressed = false var button = d3.select('button')
This example is on jsfiddle.netNote that we use the selection stored in the button variable: calls on (as well as classed, attr, style, property, html, text) return the selection on which they are called, which is typical for fluid interfaces.
D3 handles transmitted values in a similar way. If you see in the [value] documentation, then most likely this is about:
- If you submit a value that is a function, it will be called with the data, index parameters (see below), and the context (this object) will be the element, the DOM node.
- If you submit a value that is not a function, it will be wrapped in a “functor” (a function that always returns the passed value)
- If you do not submit a value, the function will work as getter and return the value in question (for example, selection.style ('color') will return the text color if it is set for the element).
It is important to remember about the last nuance if you are building a call chain (such a getter should usually be the last element of the chain).
It is important to understand that values or functions are used once for each element in the sample, after which D3 “forgets” about them. In other words, changes in the data set or events in the document will not force D3 to “re-compute” the value, so this behavior must be set on our own, as we did with classed above.
Pay attention to the function arguments (data and index). They have a special meaning: index is the number of the element in the sample, and data is the data element specified for it. The presence of these parameters in each function called on the sample is one of the most important contracts in D3. This allows you to write a concise code that calculates the state of the properties of the elements depending on the data.
Typical work with sampling
Consider the popular methods on a more complex example, demonstrating how to work with DOM nodes of a document through sampling:
var svg = d3.select('body').append('svg') svg .append('text') .text('click somewhere') .attr('x', 50) .attr('y', 50) var events = [] svg.on('click', function () { events.push(d3.event) if (events.length > 5) events.shift() var circles = svg.selectAll('circle') .data(events, function (e) { return e.timeStamp }) .attr('fill', 'gray') circles .enter() .append('circle') .attr('cx', function (d) { return dx || d.pageX }) .attr('cy', function (d) { return dy || d.pageY }) .attr('fill', 'red') .attr('r', 10) circles .exit() .remove() })
This example is on jsfiddle.netRelated sets
In the example, special attention should be paid to the
data () method. Unlike other methods, it returns a modified sample that stores, in addition to a list of elements, the correspondence of these elements to elements. In the
translation of the article
Thinking with Joins, we tell in detail about the methods of
enter () and
exit () that this sample has and the possibilities that they give.
Animation and customization
It is easy to animate changing the properties of an element in D3; you need to call the
selection.transition () method. This method returns a sample that gradually changes the current values to new ones, creating an animated effect. The duration of the animation is set by the
transition.duration () method.
Add an animation when adding and removing items to the previous example:
var svg = d3.select('body').append('svg') svg .append('text') .text('click here') .attr('x', 50) .attr('y', 50) var events = [] svg.on('click', function () { events.push(d3.event) if (events.length > 5) events.shift() var circles = svg.selectAll('circle') .data(events, function (e) { return e.timeStamp }) .attr('fill', 'gray') circles .enter() .append('circle') .attr('cx', function (d) { return dx || d.pageX }) .attr('cy', function (d) { return dy || d.pageY }) .attr('fill', 'red') .attr('r', 0)
This example is on jsfiddle.netIn this article, I talked about the D3 sampling capabilities. I plan to devote the following notes to utilities for processing and loading data, drawing sets of SVG elements and creating interactive visualization elements.
I teach D3 on the “Data Visualization” course. If you want to master this tool and start applying it in your work, come to us. The closest course will take place in Moscow this weekend, recording and feedback from participants of the January course: http://brainwashing.pro/dataviz .