D3: Explanation of the Attention Hungry UK Ministers App
Introduction:
This is an explanation of the "Attention Hungry Ministers" application. A few notes about the app, code, etc:
- The code follows the reusable D3 approach as described by Mike Bostock, and as described in the Developing a D3.js Edge book.
- A bit of terminology: a component is a reusable chunk of code that generates graphics & which doesn't represent a complete chart; a module is a reusable chunk of code that doesn't generate graphics (for example a forced graph).
- This code use a model-view-controller type pattern.
- There's more information regarding all of the above on a previous blog post.
Description of the SVG Elements in Use:
We've got one SVG element, and a 'g' element for each 'face'. Each 'face' breaks down as follows:
So for the most part, each face is rendered as a vertical stack of two circles (one for the pupil ontop of one for the eye), which themselves are ontop of an image, which are all ontop of a circle.
When a face (government minister in this case) becomes the centre of attention, i.e. when it's clicked on, or when the it's randomly chosen (via a timer and random selection), for a brief period of time that particular 'face' 'g' element is augmented with a couple of things:
- 'g' element that contains two text elements (for nice layering - see https://groups.google.com/forum/#!msg/d3-js/NIamAI9Yy60/NiEvwEMGA4IJ).
- Ripple (which I took from https://bl.ocks.org/4503672)
Components and Modules:
The structure of the app is as follows, with one central controller module running the show:
- There is in fact really only one component (i.e. chunk of code that actually really renders anything), and that's the faceManager component (although the "progress display" component does exist briefly at the beginning). This takes an array of data, passed to it from the controller, and renders the individual 'face' 'g' elements. The controller periodically calls the "transform" function of the faceManager component, which whizzes through each of the 'faces', renders the eyes, and renders the faces.
- The controller module contains a whole slew of other modules - and one component: initially the "progress display" component is loaded up to show The Queen whilst images, sounds, etc are loading. There are timer modules used to control the random changing of the minister at the centre of attention, control the emanating circles, and randomly choose eye targets for each minister.
- But the core of the controller is a force layout and associated code to control the collisions, much of which was taken from a few Mike Bostock examples: http://mbostock.github.io/d3/talk/20111018/collision.html, https://bl.ocks.org/mbostock/1021841, https://bl.ocks.org/mbostock/1748247.
- The controller also handles events that arise from selections of the checkboxes, and the Sound On/Off button.
Sources of Code, Examples, Information:
Many examples, demos, forum posts were looked at, absorbed, and used in this code. Here's a list:
- Mike Bostock force layout examples: https://bl.ocks.org/mbostock/1021841, https://bl.ocks.org/mbostock/1748247
- Getting the pixel width of a chunk of text (using JQuery): http://stackoverflow.com/questions/5353385/how-to-calculate-the-length-in-pixels-of-a-string-in-javascript. http://stackoverflow.com/questions/4910407/get-string-length-in-pixels-with-javascript. If writing this again I would use the getBBox method. See a Mike Bostock gist for further information: https://bl.ocks.org/mbostock/1160929
- Drop-shadow text drawing technique: https://groups.google.com/forum/#!msg/d3-js/NIamAI9Yy60/NiEvwEMGA4IJ.
- Thanks is due to Chris Viau who helped a little with a couple of queries.
- I found this useful re: data binding: http://stackoverflow.com/questions/10086167/d3-how-to-deal-with-json-data-structures/10091516#10091516.
- Mike Bostock example re: bounding box for a forced graph: http://mbostock.github.io/d3/talk/20110921/bounding.html
- I found this useful re: starting and stopping transitions: http://xaedes.de/dev/transitions/
- Mike Bostock example re: emanating concentric circles: https://bl.ocks.org/4503672.
- Adding a removing nodes to a forced layout: http://stackoverflow.com/questions/9539294/adding-new-nodes-to-force-directed-layout, and https://bl.ocks.org/mbostock/1095795.
Sound:
For sound, I used the howler.js library, not because it's the most amazing library, but primarily because it seems simple to use, and seems to work.
That's It!
Code-reuse in action, as many of the bits'n'pieces here were also used in the D3: Reusable D3 With The Queen, Prince Charles, a Corgi and Pie Charts demo. If you have any comments, do go ahead and leave a comment at the bottom of this page, or if you've got any questions, do get in touch!.