Let's create a simple D3-powered data-driven visualization to test your configuration. Create a new HTML file in your development environment and import the D3 library, or import it into any HTML page using the <script> tag as shown in the last section. Then add an <svg> and a <script> block inside your page's <body> as follows:
<body>
<svg id="chart" width="600" height="200"></svg>
<script>
</script>
</body>
Now add the following array inside the <script> block:
const array = [100, 200, 300, 350, 375, 400, 500];
We will use that array to generate a series of dots. Type in the following code (you can ignore the comments), which consists of a series of chained commands:
d3.select("#chart") // selects the svg element by id (like JQuery)
.selectAll("circle") // declares the elements we would like to create
.data([100]) // sets the data to drive the creation of the
// elements
.enter() // creates a selection to add elements per
// data item
.append("circle") // appends an element of this type to each
// data item
.attr("r", 10) // sets “r” attribute
.attr("cy", 100) // sets “cy” attribute
.attr("cx", d => d) // sets “cx” attribute (same as function(d) {
// return d; }
If your configuration is working correctly, when you load the page containing this code in a browser, you should see a single dot on the screen:
A dot on a screen created with D3. Code: HelloWorld/1-intro-d3.html
If you inspect the dot with your browser's JavaScript development tools, you will notice that the following code was generated inside the SVG:
<svg width="600" height="200">
<circle r="10" cy="100" cx="100"></circle>
</svg>
The preceding JavaScript code selects the <svg> element from the page and then selects all <circle> elements inside it. But there aren’t any, so the selection is empty. The next line, however, contains a data() command with a one-element array: [100]. The enter() command binds the data to the selection creating a selection of <circle> placeholders the same size as the data array. In this case, it will only contain one placeholder. Finally, the append() command, called in the context of this selection, appends a <circle> element to it, making it a child of the <svg> element.
The last three commands set attribute values and the last one takes a function and returns the element received by the function, which is used as the attribute's value. This element is the value 100 that was stored in the array passed to the data() command.
The code is available in the HelloWorld/1-intro-d3.html file from the GitHub repository for this chapter.
Now let's make some changes. Replace the [100] in the data() command with array. It will now reference the seven-element array we created before:
.data(array)
Run the page again. What happened? Consider the following screenshot:
Several dots added to the screen with positions driven by the data. Code: HelloWorld/2-binding.html
Now there are seven dots on the screen; the same number of dots as the data array. And each dot is positioned at a different horizontal position (which was defined by the cx property of the <circle>) that is set using values from the data array. We used the data array to drive the position of each circle.
Now skip a line and add this code after the selection (see HelloWorld/3-update.html):
setTimeout(function() {
d3.select("#chart").selectAll("circle")
.data([50, 75, 125, 225, 325, 425, 450])
.attr("r", 5)
.attr("cx", d => d)
.style("fill", "red")
}, 2000)
This code will run two seconds after the page loads and shows the circles in the positions defined by the first chain of commands. The function inside it selects the #chart SVG element again, and then all the circles inside it. But this time, these circles do exist. The data() command binds a new data array to the selection. No enter() command is called because there aren't any elements to be added.
The attr() commands are used to the circle's attributes. Only two attr()commands were called in the preceding code because we are only changing two attributes: the radius of the circle, and the position, which will now obtain its value from the new array. Besides that, we also used style() to change the color of the dots. If you run this file, two seconds later, the dots shrink, move to the left and become red:
The dots changed color, size, and position after an update. Code: HelloWorld/3-update.html
One very nice feature of D3 is how simple it is to animate transitions. You just need to chain a transition() command before the attributes and styles that changed. The default transition takes a quarter of a second. Let's make it a little longer by configuring duration. Add the following line between the data() command and the first attr(), to add a one-second transition during the data update:
.transition().duration(1000)
Your page body should now look like this (see HelloWorld/4-transition.html):
<body>
<svg id="chart" width="600" height="200"></svg>
<script>
const array = [100, 200, 300, 350, 375, 400, 500];
d3.select("#chart")
.selectAll("circle")
.data(array)
.enter()
.append("circle")
.attr("r", "10")
.attr("cy", 100)
.attr("cx", d => d)
setTimeout(function() {
d3.select("#chart").selectAll("circle")
.data([50, 75, 125, 225, 325, 425, 450])
.transition().duration(1000)
.attr("r", 5)
.attr("cx", d => d)
.style("fill", "red")
}, 2000)
</script>
</body>
Now, after two seconds, the dots will spend another second changing color, shrinking, and moving to the left. Congratulations! You created a full D3 application, complete with data updates and transitions.