Posted on by & filed under Content - Highlights and Reviews, Programming & Development.

A guest post by Roland Dunn, a partner at Refined Practice, currently working on D3-based visualization tools, among other things. You can find him on Twitter at @roland_dunn, and at http://www.cloudshapes.co.uk/.

A few months ago, I came across Mike Bostock’s Point-Along-Path Interpolation example (figure below), which I was quite intrigued by. It uses a path element to describe the route a circle should follow, and uses a transition.attrTween to actually move the circle along that route. The attrTween code calls the path element’s getPointAtLength function to find out what the position of the circle should be at any particular point in time, before actually rendering the circle.

mbostock-point-path-m

I thought that writing about how to re-work the Point-Along-Path Interpolation example using a reusable D3.js approach might make an interesting blog post, or at least a good way to illustrate what I learned about modular & reusable D3.js.
gist-bigger

I ended up writing the Using AttrTween, Transitions and MV* in Reusable D3 Demo Gist example (figure above), which demonstrates a number of different aspects of using D3.js, not just code reusability:

  • Waiting for enter, update and exit functions (that use transitions) to complete, and using d3.dispatch and events to move the code onto its next state (once the transitions are complete)
  • Waiting for a number of other transitions to finish, transitions that use attrTween. Code again uses d3.dispatch to move onto next code state
  • Customizing a transition’s easing function
  • How to incorporate all of the above in “reusable” or modular D3

One of the key things I really wanted to say in this post though (Part 2 will be published tomorrow), was that in writing the code as if it were reusable (the reality is I’m probably not going to reuse very much of this demo), I’ve ended up writing what I think is pretty modular code. I find my code is cleaner (at least I like to think so), my thinking is more clear, code responsibilities (e.g managing data, rendering SVG elements) are more distinct, and the resulting code has moved towards a model-view-controller/thing type structure (a good thing I think). Code referenced in this article is up on Github as a Gist, and viewable at http://bl.ocks.org/cloudshapes/5909708.

So now, for me, if I’m writing something other than a really really simple D3 example, I find myself wanting to take this modular approach, particularly an MV* approach – even if the code has no hope of producing something reusable – as the resulting code is cleaner and easier to understand.

Reusable D3 Approach & Terminology

I’m not going to go into great detail explaining the approach used to writing reusable D3 code. I’ll leave that to other sources, such as:

Before we continue, I do need to include a tiny bit of terminology. We will call a component a reusable piece of code generating graphics, which doesn’t represent a complete chart, but a part meant to be composed with other elements.
And, a module is a reusable piece of code that doesn’t generate graphics, such as a module managing JSON, or controlling a JavaScript timer.

What Does the Demo Actually Do?

svg-layout-m

The code creates two-to-three “patterns”, where each “pattern” consists of a path that is either a circle, a spiral or a sine wave, and where a circle (accompanied by some text) navigates round the patterns path (whatever the path is). Once all the circles currently on display have completed their trips (each takes different lengths of time to complete), the code randomly decides a number of things regarding the next set of patterns to render:

  • Whether to show two or three patterns, and if only two, which two
  • The colors of the paths, the circles, and the text
  • Which transition ease setting to use for each pattern
  • The duration of each transition – each pattern has its own duration
  • What the path of each pattern will be: sine, circle or spiral
  • Which direction the circle should travel around the path

SVG Elements Making Up a Pattern

g-pattern-elements-m

Each of the visual ‘patterns’ is structured (in terms of SVG elements) as in the above screengrab. A ‘g’ element is the primary container, holding a path element, and another ‘g’ element (this time class ‘inner’). The ‘inner’ ‘g’ class contains a circle (the circle that moves), and a text element (the text that accompanies the circle).

The screengrab below provides another view of a ‘patterns’ SVG elements (taken from Chrome’s Developer Tools):

chrome-elements-highlighted.m2

Code Structure

But how was the code actually structured to render these SVG elements? I ended up with the following structure:

code-structure-m

Lets look at the data and the model.

Data

The data associated with each ‘pattern’ is held in its own instance of a “d3.cloudshapes.patternData” module. Below is a little snippet of the ‘patternData’ module:

Each d3.cloudshapes.patternData instance holds almost all the data necessary to render each pattern, including the path, the circle and text, but not all of the data. Each instance does not hold the points necessary to pass to a d3.svg.line generator to generate path data for the path element. Instead, each instance holds the data necessary to generate those points to pass to a d3.svg.line generator (otherwise the d3.cloudshapes.patternData instances would have used up large chunks of memory).

The ‘pattern’ variable contains the type of the path, e.g. circle / sine / spiral. The ‘patternData’ variable is a d3.map (I think of a d3.map as similar to a Dictionary in Python), and is used to hold onto the data used to generate the points:

Some spiral data being assigned to the patternData d3.map variable:

The “exports.createCircle” (see below), “exports.createSpiral” and “exports.createSineWave” functions can then call exports.get_pattern_points (see below), which can use the ‘pattern’ variable to simply look up the data in the ‘patternData’ variable, execute a switch on the ‘pattern’ and call the appropriate function to actually generate the necessary points.

The “exports.createCircle” (see below), “exports.createSpiral” and “exports.createSineWave” functions are all called by an instance of the “d3.cloudshapes.patternManager” component to generate the points (and then throw the points away once the path is defined) :

Let’s have a look at how the main body of the code uses the d3.cloudshapes.patternData module:

The main body of the JavaScript creates two arrays, cached_data and live_data. cached_data contains three instances of the d3.cloudshapes.patternData module and acts as our backup repository. live_data contains references to the instances held in cached_data, and periodically has references added or deleted. live_data is the array that’s actually passed to and used by the d3.cloudshapes.patternManager component (which then actually renders the patterns).

In essence then, the “model” is represented by the three instances of the d3.cloudshapes.patternData module referenced by the two arrays.

Conclusion

It’s worth noting that in this discussion of the data and the model, we have covered the d3.map, and the general code pattern used in d3.cloudshapes.patternData is also used in D3 itself (see Mike Bostock’s article on reusable D3). The code pattern, however, is just a particular use of JavaScript to generate a modular chunk of code. In Part 2 of this post, we will dive deeper into the D3.js used in our demo, starting off with the View, and then the Controller and Process.

Safari Books Online has the content you need

Getting Started with D3 teaches you how to create beautiful, interactive, browser-based data visualizations with the D3 JavaScript library. This hands-on book shows you how to use a combination of JavaScript and SVG to build everything from simple bar charts to complex infographics. You’ll learn how to use basic D3 tools by building visualizations based on real data from the New York Metropolitan Transit Authority.
Developing a D3.js Edge is aimed at intermediate developers, so to get the most from this book you need to know some JavaScript, and you should have experience creating graphics using D3. Many examples created in the real world with D3, can best be described as “spaghetti code.” So, if you are interested in using D3 in a reusable and modular way, which is of course in line with modern development practices, then this book is for you!
Visual Storytelling with D3: An Introduction to Data Visualization in JavaScript provides readers with a strong framework of principles for making well-conceived and well-crafted infographics, as well as detailed and practical instructions for how to really wield D3, the best tool for making web infographics available. An extended example is used in the book to explain how to put theory to practical use.

About the author

roland.photo Roland is a partner at Refined Practice, currently working on their D3
based visualization tool, among other things. You can find him on Twitter at @roland_dunn, and at http://www.cloudshapes.co.uk/, where he does daft visualizations such as A #D3.js Visualization of Senior UK Government Cabinet Ministers and Reusable D3 With The Queen, Prince Charles, a Corgi and Pie Charts.

Tags: AttrTween, D3.js, JSON, MV*, Reusable D3, Transitions,

Comments are closed.