3. D 3 I S …
• A JavaScript library that maps Data to DOM Nodes
• Extended via layouts & plugins for rich data
visualisations
• You still need to write code to draw things
• Fast on its own, but you can easily make it sluggish
• BSD Licensed — http://d3js.org/
4. H T T P S : / / G I T H U B . C O M / M B O S T O C K / D 3 /
W I K I / G A L L E RY
G E T S TA R T E D W I T H D 3
5. B A S I C D 3 T U T O R I A L
• Adding nodes
• Mapping data to nodes
• Data Driven Documents
• Examples 01-06 at http://soasta.github.io/improving-
d3-performance/d3/
6. A N I M AT E D D 3 C H A R T S
• Force Directed Layout
• Reacting to user interaction
• Reacting to changing data
7. F O R C E D I R E C T E D L AY O U T
U S I N G P H Y S I C S
8. F O R C E D I R E C T E D L AY O U T
• http://bl.ocks.org/mbostock/4062045
• Took basic Force Directed Layout and added
enhancements:
• Convex hulls
• Labels
• Mouseovers
• Variable sized points
9. F O R C E D I R E C T E D L AY O U T —
P R O B L E M S
• Rendering is O(n) based on number of SVG nodes
• Calculations are O(n2
) based on number of links
• Drawing the hull is expensive as nodes move around a
lot
10. F O R C E D I R E C T E D L AY O U T —
S O L U T I O N S
• Reduce number of links by using a Minimum Spanning
Tree
• Identify clusters and only link one node from each
cluster
• Visually reduce nodes within the cluster using
approximation
• Add decorators later as the animation stabilizes
11. F O R C E D I R E C T E D L AY O U T —
A D D I T I O N A L O P T I O N S
• We could use CANVAS to get rid of SVG nodes
• Create subgroups within each group to further reduce
links
• Get rid of some of our visual enhancements
12. E D G E B U N D L E D L AY O U T
U S E R I N T E R A C T I O N
13. E D G E B U N D L E D L AY O U T
• http://bl.ocks.org/mbostock/7607999
• We added many more links
• Links colored based on performance
• Links sized based on volume of data flow
• Mouseover should highlight connected links
• Nodes sized based on volume within that node
14. E D G E B U N D L E D L AY O U T — P R O B L E M S
• Default behaviour is to iterate through every link on
mouseover and change colour — this is slooooow!
• Using CSS class to change colour causes major re-
render
• Quickly cycling through nodes has noticeable lag
15. E D G E B U N D L E D L AY O U T — S O L U T I O N S
• First we tried to not iterate, just use CSS class
cascades
• This was a trade off because we ended up adding a
large number of classes, two per node and one per
link
16. E D G E B U N D L E D L AY O U T — S O L U T I O N S
• The second attempt was to use CANVAS to draw
everything
• The problem here is that CANVAS is not great for text,
and mouseovers no longer worked
17. E D G E B U N D L E D L AY O U T — S O L U T I O N S
• The third attempt was to use CANVAS to draw links
and SVG for nodes
• The biggest problem was to make sure they
overlapped perfectly, ie, it was a small problem.
18. C A N VA S D O E S N O T
S U P P O R T B E Z I E R C U R V E S ! ! !
E X C E P T …
19. D 3 W I T H C A N VA S
• There are some great examples online…
• https://bocoup.com/weblog/d3js-and-canvas
• https://gist.github.com/mbostock/1276463
• But not quite what we wanted
20. D 3 W I T H C A N VA S
• Create a Custom XML NameSpace
• Map dummy nodes from this namespace for each link
• Each dummy node contains the SVG path required to
draw the curve as well as other attributes
• After all nodes have been mapped, call a renderer to
convert this to CANVAS
22. var pathAttrs =
["strokeStyle", "lineCap", "lineJoin", "lineWidth"];
ctx.beginPath();
pathAttrs.forEach(function(a) {
var val = node.attr(selected + a) || node.attr(a);
if(a === "strokeStyle") {
var color = d3.rgb(val);
val = "rgba(" +
color.r + "," +
color.g + "," +
color.b + "," +
node.attr(selected + "opacity") + ")";
}
ctx[a] = val;
});
A P P LY I N G S T Y L E S
23. var path = node.attr("d"), m;
while((m = path.match(/^ *([MLCQ])([d.,e-]+) */))) {
var cmd = m[1];
var coords = m[2].split(",").map(pathToCoords);
path = path.replace(/^ *([MLCQ])([d.,e-]+) */, "");
switch(cmd) {
case "M":
ctx.moveTo(coords[0], coords[1]);
break;
case "L":
ctx.lineTo(coords[0], coords[1]);
break;
case "C":
ctx.bezierCurveTo(coords[0], coords[1], coords[2], coords[3],
coords[4], coords[5]);
break;
case "Q":
ctx.quadraticCurveTo(coords[0], coords[1],
coords[2], coords[3]);
break;
}
}
D R A W I N G C U R V E S
24. B U T I T S T I L L WA S N ’ T
FA S T E N O U G H !
25. E N H A N C E M E N T S
• Use 2 CANVAS elements,
• one to hold the background (ie, all links),
• the second to show the currently selected links
• Change opacity on the background to darken it
• If mouse pointer returns to last selected node, just
redisplay
26. S U M M A RY
• Number of DOM nodes is very significant
• Reduce calculations on in-memory objects
• Show approximate data, based on available pixels and
power
• Use CANVAS when mouse interaction is not required
• Cache repeated states rather than redrawing them