Let’s talk about D3 DOM Manipulation And Data Binding With D3 JavaScript. We’re moving forward with the D3 JavaScript library and in this tutorial, we’ll have a look at some important concepts as we begin to create data driven documents. First off, we’ll build on the idea of selecting elements from the DOM, and then actually changing and updating the attributes of those elements. There are a handful of methods to help us with this, and we’ll cover an example and use case for each one. Once we see how setting attributes on our selected elements works, we’ll move on to the nitty gritty of D3, and that is the idea of data binding. This will be the beginnings of using data to power the visualizations on the page.
D3 DOM Manipulation
Changing Element Attributes and Using CSS
In the prior tutorial, we had a look at some methods of the D3 library to perform HTML D3 DOM Manipulation. It is also very common to modify the attributes and styling of those HTML elements. Let’s take a look at the selection.attr(), selection.classed(), and selection.styled() methods now.
selection.attr()
By using the .attr() method, you can read, add, or modify any attribute in a selection. The easiest way to see how this works is with a few examples.
Using .attr() to add a class
This approach is very useful if you already have a collection of CSS classes that you have written, or if you would like to make use of 3rd party class names like those found in Bootstrap or Foundation. Consider our example which has an unordered list of elements. To assign a class name to all of those elements, we could do so just like this.
source before D3 script:
<ul class="list list-unstyled">
<li class="item">JavaScript</li>
<li class="item">The DOM</li>
<li class="item">Scalable Vector Graphics</li>
<li class="item">jQuery</li>
<li class="item">Content Delivery Network</li>
</ul>
D3 Script to Run
d3.selectAll('li') .attr('class','alert alert-warning');
source after running D3 script
<ul class="list list-unstyled">
<li class="alert alert-warning">JavaScript</li>
<li class="alert alert-warning">The DOM</li>
<li class="alert alert-warning">Scalable Vector Graphics</li>
<li class="alert alert-warning">jQuery</li>
<li class="alert alert-warning">Content Delivery Network</li>
</ul>
note: In this example, the signature of .attr('class', 'classname')
replaces any pre existing class applied to the element. We can see this because in the original source, each li
has a class of .item
. Once D3 does it’s work, we can now see that the .item
class is gone altogether and replaced with .alert alert-warning
which gives us the nice effect we see in the screenshot.
selection.classed()
The .classed() method runs a little differently. For example, we can use the signature of .classed('classname', true)
to basically turn a class on, without clobbering any existing class. Let’s see how to do this.
source before D3 script:
<ul class="list list-unstyled">
<li class="item">JavaScript</li>
<li class="item">The DOM</li>
<li class="item">Scalable Vector Graphics</li>
<li class="item">jQuery</li>
<li class="item">Content Delivery Network</li>
</ul>
D3 Script to Run
d3.selectAll('li') .classed('alert alert-info', true);
source after running D3 script
<ul class="list list-unstyled">
<li class="item alert alert-warning">JavaScript</li>
<li class="item alert alert-warning">The DOM</li>
<li class="item alert alert-warning">Scalable Vector Graphics</li>
<li class="item alert alert-warning">jQuery</li>
<li class="item alert alert-warning">Content Delivery Network</li>
</ul>
As we can see, the .item
class is left intact using this approach. The .classed() method also can accept an object as it’s argument. By doing this we can turn multiple classes on or off for a given element. Let’s select just one of the li
items, turn off the .item
class, then turn on two Bootstrap classes to see the result.
Fantastic! Once again here is the source of before and after the script running.
source before D3 script:
<ul class="list list-unstyled">
<li class="item">JavaScript</li>
<li class="item">The DOM</li>
<li class="item">Scalable Vector Graphics</li>
<li class="item">jQuery</li>
<li class="item">Content Delivery Network</li>
</ul>
D3 Script to Run
d3.selectAll('li:nth-child(5)') .classed({ 'item': false, 'alert alert-danger': true, 'lead': true });
source after running D3 script
<ul class="list list-unstyled">
<li class="item">JavaScript</li>
<li class="item">The DOM</li>
<li class="item">Scalable Vector Graphics</li>
<li class="item">jQuery</li>
<li class="alert alert-danger lead">Content Delivery Network</li>
</ul>
Cool! This time when we run our D3 script, the first four items are left untouched. On the fifth element however, we can see that the .item
class has been turned off, the .alert alert-danger
class has been turned on, and the .lead
class has also been turned on.
selection.style()
What about when you are not using predefined classes, but need to generate CSS styles dynamically and on the fly so to speak? That is exactly what the .style() method is for, and it has many, many use cases for working with D3. This is going to be the most flexible approach that will give you the most control, especially for animation to effects so it pays to be familiar with how it works. Here is an example in Firebug.
source before D3 script:
<ul class="list list-unstyled">
<li class="item">JavaScript</li>
<li class="item">The DOM</li>
<li class="item">Scalable Vector Graphics</li>
<li class="item">jQuery</li>
<li class="item">Content Delivery Network</li>
</ul>
D3 Script to Run
d3.selectAll('li:nth-child(3)') .style({ 'background': '#13afdf', 'margin': '7px', 'color': '#ffffff', 'padding': '11px' });
source after running D3 script
<ul class="list list-unstyled">
<li class="item">JavaScript</li>
<li class="item">The DOM</li>
<li class="item" style="background: none repeat scroll 0% 0% rgb(19, 175, 223); margin: 7px; color: rgb(255, 255, 255); padding: 11px;">Scalable Vector Graphics</li>
<li class="item">jQuery</li>
<li class="item">Content Delivery Network</li>
</ul>
Very Slick! With this approach, we can see there is no need to rely on a third party CSS framework or handwritten classes. We simply specify the styles we need and they are applied inline. Even though we generally like to put our styles in their own dedicated stylesheets, when styling dynamically in the DOM with real time applications like D3, inline is the way it needs to happen. The other thing to consider is that this approach is going to be the way we apply style to SVG, XML, and more.
Data Binding To The Document Object Model With D3
This is where things start to get interesting and fun. So far, we’ve really only covered basic selections, and then rudimentary styling and modifying of those elements. The point of D3 is to make use of data to power our visualizations, hence the name – Data Driven Documents! Let’s see an example of very basic data binding in action.
source before D3 script:
<ul class="list list-unstyled">
<li class="item">JavaScript</li>
<li class="item">The DOM</li>
<li class="item">Scalable Vector Graphics</li>
<li class="item">jQuery</li>
<li class="item">Content Delivery Network</li>
</ul>
D3 Script to Run
styles = [ {color: '#d6e9c6', width: 150}, {color: '#d9edf7', width: 200}, {color: '#fcf8e3', width: 250}, {color: '#f2dede', width: 300}, {color: '#bce8f1', width: 350} ]; d3.selectAll('li') .data(styles) .style({ 'background': function (data) { return data.color; }, 'width': function (data) { return (data.width + 'px') } });
source after running D3 script
<ul class="list list-unstyled">
<li class="item" style="background: none repeat scroll 0% 0% rgb(214, 233, 198); width: 150px;">JavaScript</li>
<li class="item" style="background: none repeat scroll 0% 0% rgb(217, 237, 247); width: 200px;">The DOM</li>
<li class="item" style="background: none repeat scroll 0% 0% rgb(252, 248, 227); width: 250px;">Scalable Vector Graphics</li>
<li class="item" style="background: none repeat scroll 0% 0% rgb(242, 222, 222); width: 300px;">jQuery</li>
<li class="item" style="background: none repeat scroll 0% 0% rgb(188, 232, 241); width: 350px;">Content Delivery Network</li>
</ul>
This particular example is a little bit more advanced because of the fact that we are creating an array of objects, passing that array to the .data() method to bind the data contained within, then we use the .style() method, and the value of the objects within use anonymous functions to return the variable data. Say What? In essence, if you’re not familiar with JavaScript, you’ll need to read up a bit on some of the JavaScript Tutorials here and elsewhere on the web, since we’ll need a good understanding of it. Especially important will be the idea of JavaScript functions being first class citizens in the language.
Control HTML Attributes and Bind Data To The DOM With D3 JavaScript Conclusion
Are we having fun yet? You bet we are! We’re starting to realize some of the power that working with D3 in our pages affords us. Plug this code into your own sandbox and have a play. Change the values of the data up in that final example. See what different kinds of colors and widths you can come up with. It’s just the beginning, and we’ll cover lots more in later tutorials.