The first thing we need to do is create a g element to which we can add our own elements. Since we're visualizing data using SVG, we need to create this element inside the root SVG element we defined in our HTML skeleton in the previous section. We do this in the following manner:
function show() {
var margin = { top: 20, bottom: 20, right: 40, left: 40 },
width = 400 - 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 + ")");
}
In this code fragment, we see the first usage of the D3 API. We use d3.select to search for the first element with the class chart. This will find the SVG element we defined in our HTML template (<svg class="chart"></svg>), and this will allow us to modify that element. D3 uses a W3C Selectors API string to select elements (more information here: https://www.w3.org/TR/selectors-api/). Summarizing this means that you can use the same kind of selector strings that are also used in CSS to select specific elements:
- .className: selects the elements that have a class with the name className.
- .elemName: selects the elements of type elemName
- #id: selects the element that has an attribute id with a value id.
- .className1 .className2: selects all elements with the class name .className2 which are descendants from the element with class name .className2
Now that we have the SVG element, we use the attr function to set its width and height, leaving a bit of margin at all sides. Finally, we add the g element using the append function and position that element by taking into account the margins we defined by setting the transform attribute. D3 has a fluent API which means we can just chain commands and functions together (as you can see in the previous code fragment). This also means that the result of the final operation is assigned to the chart variable. So in this case, the chart variable is the g element we appended to the svg element.
A g element isn't rendered when you add it to a SVG element. The g element is just a container in which you can add other elements. The most useful part of the g element is that all of the transformations applied to this element are also applied to the children. So if you move the g element, the children will move as well. Additionally, all the attributes defined on this element are inherited by its children.
This might seem like a lot of work to just get an empty group to add elements to, but it is good practice to use a setup like this. Using margins allows us to more easily add axes or legends later on, without having to reposition everything and having a clear and well defined height and weight allows us to use other D3 features (such as scales) to correctly position elements, as we'll see later in this chapter.
At this point, it's also a good point to explain the transform attribute we use to position the g element inside the svg element. The transform attribute allows a couple of operations we can use to change the position and rotation of any SVG elements (such as g, text, rect). You'll see it used throughout this book, since it is the standard way to position SVG elements. The following table shows what can be done with the transform attribute:
Operation |
Description |
translate(x [y]) |
With the translate attribute, we can move the specified element along its X or Y axis. For example, with translate(40 60), we move the specified element 40 pixels to the right and 60 down. If you just want to move an element along the X axis, you can omit the second parameter. |
scale(x [y]) |
The scale operator, as the name implies, allows you to scale an element along the x and y axes. To double the width of an element, you can use scale(1 2), to half the size you use scale(0.5 0.5). Once again, the first parameter is mandatory, and the second one is optional. |
rotate(a [x] [y]) |
The rotate operation allows rotation of the element around a given point (x and y) for a degrees. If the x and y parameters aren't provided, the element is rotated around its center. You can specify a positive a to rotate clockwise (for example, rotate(120)) and a negative value to rotate counter-clockwise (rotate(-10)). |
skewX(a) / skewY(a) |
The skewX and skewY functions allow you to skew (to slant) an element alongside an axis by the specified a degrees: skewX(20) or skewY(-30). |
matrix(a b c d e f) |
The final option you can use is the matrix function. With the matrix operator you can specify an arbitrary matrix operation to be applied to the element. All the previous operations could be written using the matrix operator, but this isn't really that convenient. For instance, we could rewrite translate(40 60) like matrix(1 0 0 1 40 60) |
If you entered this code in your editor and looked at it in your browser you wouldn't really see anything yet. The reason is that we didn't specify a background color (using the fill attribute) for the svg or g element, so the default background color is used. We can, however, check what has happened. We mentioned that besides a good editor to create code, we'll also do a lot of debugging inside the browser, and Chrome has some of the best support. If you open the previous code in your browser, you can already see what is happening when you inspect the elements:
As you can see in this screenshot, the correct attributes have been set on the svg element, a g element is added, and the g element is transformed to position it correctly. If we want to style the svg element, we can use standard CSS for this. For instance, the following code (if added to the css file for this example) will set the background-color attribute of the svg element to black.
svg {
background-color: black;
}
It is good to understand that CSS styles and element attributes have different priorities. Styles set using the style property have the highest priority, next the styles applied through the CSS classes, and the element properties set directly on the element have the lowest priority.
When we now open the example in the browser, you'll see the svg element as a black rectangle:
At this point, we've got an svg element with a specific size, and one g element to which we'll add other elements in the rest of this example.