A few months ago I published a post about how to create a force graph using React and D3. But what if the force graph data source is enormous? Would you still use D3 or are there any other solutions out there?
In this post I’ll explain how you can combine both D3 and PixiJS to create almost the same force graph but in a different way which will enable you to support bigger data sources.
In the app we created we faced a very painful performance problem. While D3 helped us to create the relevant force graph we needed to show on screen, the data source we were using became very large. When using D3, the graph representation underneath is created using SVG and that means that when the data source becomes larger the amount of SVG elements increase. The more SVG elements you have on screen the less performant the app becomes.
So, how can we solve the problem? What if we could transfer D3 SVG representation into canvas representation. Would that help?
In our app it helped.
Enter PixiJS
PixiJS is a flexible 2D WebGL renderer library which is working on top of HTML5 canvas element.
Note - I won’t get into PixiJS fundamentals in this post and I encourage you to go to it’s website for further reading.
In a whole what I did was to use the D3 force graph simulation on one hand to keep the force graph simulation and I let PixiJS handle all the rendering on top of the canvas element.
Creating the Example App
I’m going to refactor a little bit the app I created in the “Creating a Force Graph using React and D3” post. That means that if you haven’t read it go ahead and do that before you continue reading this post.
First you will need to install PixiJS library. In command line run the following code to install both PixiJS and PixiJS Viewport, which will help us to support things like zoom in and out:
npm i pixi.js pixi-viewport
After the libraries are installed we are ready to proceed.
I’ll use the same ForceGraph component container I created in the previous post, but this time I’ll use the runForceGraphPixi function instead of runForceGraph. runForceGraphPixi will be responsible to create and run the new force graph.
Building the Force Graph Generator
The force graph generator will be a function that will be responsible to generate the graph. Here is the declaration of the function which gets the containing div, the data for links and nodes and a function to generate a node tooltip:
You can see that I import both D3 and PixiJS and I use the same signature that I used in runForceGraph from the previous post. Now let’s implement the function.
The first lines of code will be to copy the data and to get the container’s width and height :
I also add a variable I’ll use later to control the nodes drag and drop and clean the container from it’s previously generated HTML content.
Then, let’s add a few helper functions:
The helper functions will help us to add the tooltip, to support the coloring of the nodes and also to create the drag and drop functionality.
Now we add the code that will create the nodes and their links and will simulate the force graph:
Pay attention that I add both a Pixi.Applicaiton and also d3.forceSimulation. The PixiJS application will be responsible for the graph rendering according to the force simulation that D3 exposes.
When the graph is ready we will add a few event handlers to handle what is going to happen when the tick is happening :
In the tick event we clean all the links and then redraw them on the canvas again.
Last but not least, we will return the destroy function that the graph container is going to use when it’s going to unmount the graph:
The whole function source code:
Now that everything is set in place you can run the app and look at your fancy force graph.
Summary
In the post, I showed you how to create a force graph component using React, D3 and PixiJS libraries. You can find the graph code here.
Top comments (1)
Hi
I need to rotate a 3d-force-graph like nodes and links should be move individually just like 3d rotation
now it's rotating like this
video:
watch.screencastify.com/v/rA5E7rOQ...
but it's rotating like a single geometry but i want to rotate every links with respect to geometry