Adding rectangles to the group element

In this step, we'll look at the core functionality of D3 which shows how to bind data to elements. We'll create an example that shows a number of rectangles based on some random data. We'll update the data every couple of seconds, and see how we can use D3 to respond to these changes. If you want to look at this example in action, open the example D01-01.html from the chapter 01 folder in your browser. The result looks something like this:

The size and number of rectangles in the screen is randomly determined and the colors indicate whether a rectangle is added or an existing one is updated. If the rectangle is blue, an existing rectangle was selected and updated; if a rectangle is green, it was added to the rectangles already available. It works something like this:

  1. The first time the rectangles are shown, no rectangles are on screen, so all the rectangles are newly added and colored green. So, for this example, assume we add three rectangles, which, since no rectangles are present, they rendered green.
  2. After a couple of seconds, the data is updated. Now assume five rectangles need to be rendered. For this, we'll update the three rectangles which are already there with the new data. These are rendered blue since we're updating them. And we add two new rectangles, which are rendered green, just like in the first step.
  3. After another couple of seconds, the data is updated again. This time we need to render four rectangles. This means updating the first four rectangles, which will turn them blue, and we'll remove the last one, since that one isn't needed anymore.

To accomplish this, we'll first show you the complete code and then step through the different parts:

function show() { 
'use strict';

var margin = { top: 20, bottom: 20, right: 40, left: 40 },
width = 800 - margin.left - margin.right,
height = 400 - margin.top - margin.bottom;

var chart = d3.select(".chart")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + ","
+ margin.top + ")");

function update() {

var rectangleWidth = 100,
data = [],
numberOfRectangles = Math.ceil(Math.random() * 7);

for (var i = 0 ; i < numberOfRectangles ; i++) {
data.push((Math.random() * rectangleWidth / 2)
+ rectangleWidth / 2);
}

// Assign the data to the rectangles (should there be any)
var rectangles = chart.selectAll("rect").data(data);

// Set a style on the existing rectangles so we can see them
rectangles.attr("class", "update")
.attr("width", function(d) {return d})
.attr("height", function(d) {return d});

rectangles.enter()
.append("rect")
.attr("class", "enter")
.attr("x", function(d, i) { return i * (rectangleWidth + 5) })
.attr("y", 50)
.attr("width", function(d) {return d})
.attr("height", function(d) {return d});

// Handle rectangles which are left over
rectangles.exit().remove();

// we could also change the ones to be remove
// rectangles
// .exit()
// .attr("class", "remove");
}

// set initial value
update();
// and update every 3 seconds
d3.interval(function() { update(); }, 3000);
}

In the beginning of this function, you once again see the code we use to create and set up our SVG and main g elements. Let's ignore that and move on to the update() function. When this function is called it will take a couple of steps: