Most of this focuses on the ‘hard part’ of d3, which is the concept of the selection and data join. This is about what you might call an easier part, or an even-lower-level one: SVG.
SVG, short for Scalable Vector Graphics, is a standard for vector drawing that integrates with HTML and is implemented by most browsers. Unlike Canvas, it’s not raster-based but rather preserves the structure of your drawing and is much like HTML in terms of events, updates, and being-a-tree. Unlike Canvas, it’s old, big, and complex.
Just like math, we tend to use a subset of SVG for most drawings: here’s that.
There are a few basic shapes available in SVG:
<circle> is a circle: you’ll always want to set its attribute
r for radius. Circles are positioned with
cy, or with transforms.
<rect> is a rectangle: it requires a
height attribute to show up, and is positioned with
y attributes, or transforms.
<path> is the most versatile kind of shape: filled, it can look like a polygon, unfilled it can look like a line. You can shape it into a circle or a rectangle, or use it as the path for text to shape around. Even though SVG also has a
<polyline> element, most of the maps and drawings you see in d3 are made of paths, since paths can express all of the same shapes.
The path data attribute is a source of much confusion for new users of d3, since it’s confusing. That is, for the purposes of efficiency, it’s very concise and has optional syntax: sometimes coordinates are separated with
, but they don’t have to be, and saying
L10 10 L10 10 is equivalent to saying
L10 10 10 10.
The basic parts of path data are commands, like
L, which say ‘draw a line from here to there’ or ‘start a new line’ or ‘draw a squiggly line’ or ‘close this line by adding a segment back to the first point’.
Then there are coordinates, like
10 10, which are X and Y positions of places to go. Path data is just coordinates and commands, strung together to tell lines where to start, go, and end.
This railroad diagram may or may not bring you some sense of higher enlightenment about path data.
SVG has its own transforms, with a very similar syntax, which you can use to position any element. And unlike HTML, there are no ‘float’ or ‘inline’ ideas in SVG - the position of each element doesn’t affect the position of elements outside of its subtree.
On the downside, SVG transforms are sometimes not 3D accelerated when HTML transforms are - so they aren’t necessarily fast.
There are also has positioning attributes - you can set the position of a
y attributes, and of a circle with
cy. Sometimes these are useful - especially with text, when you can set position relative to the baseline with positioning attributes and then positioning in the page with a
A bit odd from the perspective of HTML is the
<g> element, but it’s incredibly useful, for a variety of reasons.
g element is a group: meaning, you can put elements into
g and those elements are transformed when
g is transformed, they’re removed when it’s removed, and so on.
SVG currently doesn’t support z-indexes order of elements on a page is their order in rendering. Thus, it makes sense to have logical groups of elements in the page - for instance, the iD editor uses several
<g> elements to stack roads, buildings, and rivers on top of each other in the right order.
SVG also doesn’t use nesting as much as HTML, so
<g> is used to group items that are really just stacked on top of each other, like if you need a multi-circle stack for a bullseye.
<g> element is often used in a very similar fashion to Canvas’s idea of transformations - by using a
<g>, you can shift the contents of a graph so that there’s a margin around its boundary, or scale groups of shapes all at once.
<g> is really useful for d3 because it provides a DOM way of expressing subselections - you can use a
<g> element for each series of a multiple series chart or for each chapter of a book, and easily bind the group of data to the
<g> and the subsets to its contents.
SVG can be styled with CSS, but uses different properties to do roughly equivalent styling. It’s basically more unified - to set the fill of a circle, you set its
fill, and the same thing to set the fill of text or a path.
d3 protects us from the oddity of interacting with SVG elements through some built-in magic. If you used d3 in the olden days, you would see code like
Herein lies a little detail: HTML and SVG use XML Namespaces so that both SVG and HTML can have tags named
text without a conflict. SVG uses the namespace
http://www.w3.org/2000/svg, so instead of simply calling
document.createElement, you’ll need to use its cousin
To create an SVG element with a circle of radius 5, you would write:
A little dirty, right? Anyway, d3 simplifies this since 2.6 by automatically using the namespace
http://www.w3.org/2000/svg to create the
<svg> element, and then selections automatically use that namespace for each new insertion.