0

I am handling a large dataset to render for D3 force-layout, but realised that the performance suffers a lot using SVG. Read that rendering in canvas is much better, so am trying to understand it now.

One of the functions I need to code for is the addition of new nodes & links in the existing graph (without a refresh), as well as new links. Is there any hack that can be done to do this? Since canvas doesn't have DOM structure like SVG for me to select and update...

Am referencing to this canvas force-layout create using d3v4. https://bl.ocks.org/mbostock/ad70335eeef6d167bc36fd3c04378048

Thanks!

Jake
  • 2,482
  • 7
  • 27
  • 51
  • What have you tried so far? – Arnaud Stephan Apr 30 '18 at 09:54
  • tbh, I'm at a lost using canvas, first-timer. Had spent a lot of time coding this entire thing in SVG & was dismayed at the performance. For nodes update, what I did it is to svg.selectAll('.node'), than filter it to the nodes I require, and update the the radius "r" to change the node size... is there something similar I can use for canvas? – Jake Apr 30 '18 at 09:58
  • any small tips will be very appreciated – Jake Apr 30 '18 at 10:00
  • Look at this post for help: https://simonsarris.com/making-html5-canvas-useful/ – Ash Apr 30 '18 at 10:13
  • this looks potentially useful @VishalAsh , lemmi take a look! – Jake May 02 '18 at 13:57

1 Answers1

1

There's a really good post that someone put together about using canvas called Working with D3.js and Canvas.

In short I'd recommend doing some data-binding into some dummy HTML, and using the results of this to render your output.

First create a fake DOM element that you can use

const fakeContainer = d3.select(document.createElement("custom"));

Now data-bind to it. Note, only create it the once, re-use it for re-renders.

const join = fakeContainer
        .selectAll("circle")
        .data(myData);

join.exit().remove();
join.enter().append("circle");

Then when it comes to rendering:

fakeContainer.each(function(d) {
    // Render a canvas circle
});
Ian
  • 33,605
  • 26
  • 118
  • 198
  • Thanks Ian, looks like something I can work on, cross fingers! – Jake Apr 30 '18 at 13:29
  • Hi Ian, took a look and tried thinking through the logic. However, I think this piece of code doesn't help, becos it only teaches how to render a circle or shape. The trick is after rendering, how am I able to select the same circle (out of many in the force-graph) that are also moving around in the background and update the node size? And how do I add a new node to the graph without a complete refresh? – Jake May 02 '18 at 13:55
  • @Jake the canvas is designed to handle a complete refresh - and it's fast at doing that. Typically you'd clear the context, render all the circles again. You could try and get clever and just clear part of the canvas context but that's going to start becoming hard work. – Ian May 02 '18 at 14:46
  • I understand what u meant now, this other answer helped to explain a little better https://stackoverflow.com/questions/39191683/adding-nodes-dynamically-to-d3-force-layout-in-version-4. So basically I just need to update the array and call tick again and everything will be 'updated'. Thanks! – Jake May 02 '18 at 15:24