You've made it this far and haven't seen any colorful graphics. Which
I'm sure is the only reason you want to use D3 - to impress friends,
family, and crushes with your data-visualizing prowess. Well, the
time is now. Kind of. Future lessons will expand on not only the
capabilities of SVG, but also additional functionality of D3. Let's
make some squares!
<div id='chart'></div>
var root = d3.select('#chart').append('svg')
.attr('width', 200)
.attr('height', 200)
.style('border', '1px solid black');
root.selectAll('rect')
.data([5, 25, 80]).enter()
.append('rect')
.attr('x', Object)
.attr('y', Object)
.attr('width', 15)
.attr('height', 10)
.attr('fill', '#c63')
.attr('stroke', 'black');
There is a lot going on in that sample, much of it new. First off
is SVG - which has a
W3C Recommendation.
Or, in other words, a descriptive manual. It works; though for now
we will mainly concern ourselves with the
basic shapes.
SVG can be embedded within HTML. D3 makes this simple; you need
only append an
svg
element
to part of the DOM. This element functions much like the
body
element in a webpage -
it is the root onto which all other elements must be added. Relevant code:
var root = d3.select('#chart').append('svg')
.attr('width', 200)
.attr('height', 200)
.style('border', '1px solid black');
It is a very good idea to explicitly set the
width
and
height
of the root
svg
element as they default
to
100%
.
You'll note the dimensions here, and elsewhere for SVG elements,
can be raw numbers with no attached unit. When specifying values
for attributes on SVG nodes (that is, using
.attr(...);
), the units
are assumed to be in the "current user coordinate system". For
now, pretend that means 'pixels'. You can always add a
CSS2 unit
as well, such as
.attr('x', '53px')
or
.attr('y', '2em')
but it tends to be easier to simply ignore the unit unless necessary.
The whole spec is available
here
for the curious or the curiously demented that enjoy reading
standards documents.
The next new bit is our select - we used element type selection
instead of classes. That is, we wrote
.selectAll('rect')
instead
of
.selectAll('.some-class')
.
Why? Well, for one thing, it saves a line of code in the example (we
no longer need to add a class attribute that matches the selection). It
also seemed like a good idea to mix it up. Keep you on your toes.
Moving on, we have these curious lines:
.append('rect')
.attr('x', Object)
.attr('y', Object)
The first one should be straightforward - we are no longer creating
HTML elements. Now, we are in the brave new world of SVG elements.
rect
is a simple one to start with. The other two lines are
quite mysterious. Somewhat magic, one might say. I'd agree - you
will see, on occaison,
String
or
Object
used as a value.
Remember that values can either be literals (like a string or number),
or a function that is evaluated once per node/datum? Well,
String
and
Object
are just functions.
So the line
.attr('x', Object)
is equivalent to
.attr('x', function(d, i) { return Object(d, i); })
and also to
.attr('x', function(d, i) { return d; })
Object
, then, is essentially
the identity function (and, luckily, it ignores every argument other
than the first). Remember, you are free to use any function as
a value argument - it need not be defined inline, or even defined
by you.
The coordinate system in SVG uses the top-left corner as the origin;
x increases right-wards and y increases down-wards.
The final two lines are just setting up our visuals:
.attr('fill', '#c63')
.attr('stroke', 'black');
Those should be self-explanatory, but they aren't the only way
of styling SVG elements. You can also put it in your CSS (or
embed a style element in the SVG element, an advanced topic I'm
going to pretend I didn't mention because I don't want to go into
it). There are many, many style attributes and a legion of values
to set. You can read all about them from
the horse's mouth, or you can just pick up bits and pieces
from the examples here. Your call.
There is one final example to offer, provided without commentary.
You should be able to
figure it out. Just remember -
datum
can be anything.
<div id='chart'></div>
var root = d3.select('#chart').append('svg')
.attr('width', 600)
.attr('height', 600)
.style('border', '1px solid black');
var rects = [
{x: -5, y: -5, w: 150, h: 195},
{x: -5, y: 200, w: 150, h: 230},
{x: 155, y: 435, w: 395, h: 175},
{x: 555, y: 435, w: 55, h: 80},
{x: 155, y: -5, w: 450, h: 435, fill: '#731000'},
{x: -5, y: 435, w: 150, h: 175, fill: '#0b183b'},
{x: 555, y: 520, w: 55, h: 90, fill: '#d49800'}
];
root.selectAll('rect')
.data(rects).enter()
.append('rect')
.attr('x', function(d) { return d.x; })
.attr('y', function(d) { return d.y; })
.attr('width', function(d) { return d.w; })
.attr('height', function(d) { return d.h; })
.attr('fill', function(d) { return d.fill || '#eef2d1'; })
.attr('stroke-width', 10)
.attr('stroke', 'black');
The next lesson will cover more of the D3 library, specifically
those parts focused on making drawing easier, as well as a whole
spread of SVG elements yet to be seen. And, don't worry,
animations will come soon after (so you can get your
zwoops
and
schwedaddles and really impress your friends). There
will be a detour through nested selections on the way, so don't get
too excited.