I M P R O V I N G D 3 P E R F O R M A N C E W I T H
C A N VA S A N D O T H E R H A C K S
WebTechCon 2015
2015-10-27
Philip Tellis
@bluesmoon
https://github.com/lognormal/boomerang
http://www.soasta.com/mpulse/
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/
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
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/
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
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
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
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
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
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
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
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
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
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
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
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.
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 …
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
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
d3.ns.prefix.custom = "https://foo-bar.com/edge_bundling.html";
d3.select("body").append("custom:sketch")
.classed("link-container", true);
…
linkBinding.enter()
.append("custom:path")
.attr("lineCap", "round")
.attr("lineJoin", "round")
.attr("lineWidth", .2)
.attr("opacity", 0.1)
.attr("selected-opacity", 0.3);
linkBinding
.attr("selected-lineWidth", function(d) { return
weightScale(d.weight); })
.attr("d", function(d) { return line(d.path); });
C R E AT I N G N O D E S
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
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
B U T I T S T I L L WA S N ’ T
FA S T E N O U G H !
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
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
Thank You

More Related Content

PPTX
2019-01-24 Sequelize ORM (Object Relational Mapper): models, migrations, oh my
PDF
Spark meets Telemetry
PDF
Introduction to d3js (and SVG)
PPT
Data Visualizations with D3
PDF
Learn D3.js in 90 minutes
PDF
Having fun with graphs, a short introduction to D3.js
PPT
Playing with d3.js
PDF
D3.js and SVG
2019-01-24 Sequelize ORM (Object Relational Mapper): models, migrations, oh my
Spark meets Telemetry
Introduction to d3js (and SVG)
Data Visualizations with D3
Learn D3.js in 90 minutes
Having fun with graphs, a short introduction to D3.js
Playing with d3.js
D3.js and SVG

Similar to Improving D3 Performance with CANVAS and other Hacks (20)

PPTX
Visdjango presentation django_boston_oct_2014
PPTX
SVGD3Angular2React
PPTX
Svcc 2013-d3
PPTX
SVCC 2013 D3.js Presentation (10/05/2013)
PPTX
D3.JS Tips & Tricks (export to svg, crossfilter, maps etc.)
PDF
Utahjs D3
PDF
Introduction to data visualisation with D3
PPTX
SVG, CSS3, and D3 for Beginners
PDF
Data Visualization on the Web - Intro to D3
PDF
D3: Easy and flexible data visualisation using web standards
PPT
HTML5 Canvas
PPTX
PPTX
Dreamforce 2014 - Introduction to d3.js
PPT
Svg Overview And Js Libraries
PDF
HTML5 Canvas - The Future of Graphics on the Web
PDF
Learning d3
PDF
Visualize your graph database
PPTX
Introduction to D3.js
PPTX
Academy PRO: HTML5 API graphics
PPTX
Academy PRO: D3, part 1
Visdjango presentation django_boston_oct_2014
SVGD3Angular2React
Svcc 2013-d3
SVCC 2013 D3.js Presentation (10/05/2013)
D3.JS Tips & Tricks (export to svg, crossfilter, maps etc.)
Utahjs D3
Introduction to data visualisation with D3
SVG, CSS3, and D3 for Beginners
Data Visualization on the Web - Intro to D3
D3: Easy and flexible data visualisation using web standards
HTML5 Canvas
Dreamforce 2014 - Introduction to d3.js
Svg Overview And Js Libraries
HTML5 Canvas - The Future of Graphics on the Web
Learning d3
Visualize your graph database
Introduction to D3.js
Academy PRO: HTML5 API graphics
Academy PRO: D3, part 1

More from Philip Tellis (20)

PDF
Frontend Performance: Beginner to Expert to Crazy Person
PDF
Frontend Performance: De débutant à Expert à Fou Furieux
PDF
Frontend Performance: Expert to Crazy Person
PDF
Beyond Page Level Metrics
PDF
Frontend Performance: Beginner to Expert to Crazy Person (San Diego Web Perf ...
PDF
Frontend Performance: Beginner to Expert to Crazy Person
PDF
Frontend Performance: Beginner to Expert to Crazy Person
PDF
Frontend Performance: Beginner to Expert to Crazy Person
PDF
mmm... beacons
PDF
RUM Distillation 101 -- Part I
PDF
Improving 3rd Party Script Performance With IFrames
PDF
Extending Boomerang
PDF
Abusing JavaScript to measure Web Performance, or, "how does boomerang work?"
PDF
The Statistics of Web Performance Analysis
PDF
Abusing JavaScript to Measure Web Performance
PDF
Rum for Breakfast
PDF
Analysing network characteristics with JavaScript
PDF
A Node.JS bag of goodies for analyzing Web Traffic
PDF
Input sanitization
PDF
Messing with JavaScript and the DOM to measure network characteristics
Frontend Performance: Beginner to Expert to Crazy Person
Frontend Performance: De débutant à Expert à Fou Furieux
Frontend Performance: Expert to Crazy Person
Beyond Page Level Metrics
Frontend Performance: Beginner to Expert to Crazy Person (San Diego Web Perf ...
Frontend Performance: Beginner to Expert to Crazy Person
Frontend Performance: Beginner to Expert to Crazy Person
Frontend Performance: Beginner to Expert to Crazy Person
mmm... beacons
RUM Distillation 101 -- Part I
Improving 3rd Party Script Performance With IFrames
Extending Boomerang
Abusing JavaScript to measure Web Performance, or, "how does boomerang work?"
The Statistics of Web Performance Analysis
Abusing JavaScript to Measure Web Performance
Rum for Breakfast
Analysing network characteristics with JavaScript
A Node.JS bag of goodies for analyzing Web Traffic
Input sanitization
Messing with JavaScript and the DOM to measure network characteristics

Recently uploaded (20)

PDF
Decision Optimization - From Theory to Practice
PPTX
Strategic Picks — Prioritising the Right Agentic Use Cases [2/6]
PDF
Applying Agentic AI in Enterprise Automation
PDF
“Introduction to Designing with AI Agents,” a Presentation from Amazon Web Se...
PDF
Optimizing bioinformatics applications: a novel approach with human protein d...
PDF
Domain-specific knowledge and context in large language models: challenges, c...
PPTX
Report in SIP_Distance_Learning_Technology_Impact.pptx
PDF
Peak of Data & AI Encore: Scalable Design & Infrastructure
PDF
Gestión Unificada de los Riegos Externos
PDF
FASHION-DRIVEN TEXTILES AS A CRYSTAL OF A NEW STREAM FOR STAKEHOLDER CAPITALI...
PPTX
AQUEEL MUSHTAQUE FAKIH COMPUTER CENTER .
PDF
Addressing the challenges of harmonizing law and artificial intelligence tech...
PPTX
Slides World Game (s) Great Redesign Eco Economic Epochs.pptx
PDF
NewMind AI Journal Monthly Chronicles - August 2025
PDF
【AI論文解説】高速・高品質な生成を実現するFlow Map Models(Part 1~3)
PDF
Introduction to c language from lecture slides
PDF
eBook Outline_ AI in Cybersecurity – The Future of Digital Defense.pdf
PDF
TicketRoot: Event Tech Solutions Deck 2025
PPT
Overviiew on Intellectual property right
PPTX
CRM(Customer Relationship Managmnet) Presentation
Decision Optimization - From Theory to Practice
Strategic Picks — Prioritising the Right Agentic Use Cases [2/6]
Applying Agentic AI in Enterprise Automation
“Introduction to Designing with AI Agents,” a Presentation from Amazon Web Se...
Optimizing bioinformatics applications: a novel approach with human protein d...
Domain-specific knowledge and context in large language models: challenges, c...
Report in SIP_Distance_Learning_Technology_Impact.pptx
Peak of Data & AI Encore: Scalable Design & Infrastructure
Gestión Unificada de los Riegos Externos
FASHION-DRIVEN TEXTILES AS A CRYSTAL OF A NEW STREAM FOR STAKEHOLDER CAPITALI...
AQUEEL MUSHTAQUE FAKIH COMPUTER CENTER .
Addressing the challenges of harmonizing law and artificial intelligence tech...
Slides World Game (s) Great Redesign Eco Economic Epochs.pptx
NewMind AI Journal Monthly Chronicles - August 2025
【AI論文解説】高速・高品質な生成を実現するFlow Map Models(Part 1~3)
Introduction to c language from lecture slides
eBook Outline_ AI in Cybersecurity – The Future of Digital Defense.pdf
TicketRoot: Event Tech Solutions Deck 2025
Overviiew on Intellectual property right
CRM(Customer Relationship Managmnet) Presentation

Improving D3 Performance with CANVAS and other Hacks

  • 1. I M P R O V I N G D 3 P E R F O R M A N C E W I T H C A N VA S A N D O T H E R H A C K S WebTechCon 2015 2015-10-27
  • 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
  • 21. d3.ns.prefix.custom = "https://foo-bar.com/edge_bundling.html"; d3.select("body").append("custom:sketch") .classed("link-container", true); … linkBinding.enter() .append("custom:path") .attr("lineCap", "round") .attr("lineJoin", "round") .attr("lineWidth", .2) .attr("opacity", 0.1) .attr("selected-opacity", 0.3); linkBinding .attr("selected-lineWidth", function(d) { return weightScale(d.weight); }) .attr("d", function(d) { return line(d.path); }); C R E AT I N G N O D E S
  • 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