You're reading from Data Visualization with D3.js Cookbook
Use the force, Luke!
A master's words of wisdom to his apprentice
In this chapter we are going to cover one of the most fascinating aspects of D3: force. Force simulation is one of the most awe-inspiring techniques that you can add to your visualization. Through a number of highly interactive and fully-functional examples, we will help you explore not only the typical application of D3 force (for example, the force-directed graph), but also other essential aspects of force manipulation.
D3 force simulation support was created not as a separate capability, but rather as an additional D3 layout. As we have mentioned in Chapter 9, Lay Them Out, D3 layouts are non-visual data oriented layout management programs designed to be used with different visualization. Force layout was originally created for the purpose of implementing a specific visualization type called force-directed graph. Its implementation uses standard verlet integration based particle motion simulation with support...
In this recipe we will introduce you to the first two fundamental forces: gravity and charge. As we have mentioned before, one objective of force layout's design is to loosely simulate Newton's equation of motion with particles, and one major feature of this simulation is the force of charge. Additionally, force layout also implements pseudo gravity or more accurately a weak geometric constraint typically centered on the SVG that can be leveraged to keep your visualization from escaping the SVG canvas. In the following example we will learn how these two fundamental, and sometimes opposing forces, can be leveraged to generate various effects with a particle system.
Open your local copy of the following file in your web browser:
https://github.com/NickQiZhu/d3-cookbook/blob/master/src/chapter11/gravity-and-charge.html.
In our previous recipe we have touched upon force layout node object and its {x, y}
attributes, which determine where a node locates on the layout. In this recipe we will discuss another interesting aspect of physical motion simulation: momentum. D3 force layout has built-in support for momentum simulation which relies on the {px, py}
attributes on the node object. Let's see how this can be done in the example described in this recipe.
Open your local copy of the following file in your web browser:
https://github.com/NickQiZhu/d3-cookbook/blob/master/src/chapter11/momentum-and-friction.html.
In this recipe we will modify the previous recipe by first disabling both gravity and charge then giving newly added node some initial velocity. As a result now the faster you move the mouse higher the initial velocity and momentum will be for each node. Here is the code to do that:
<script type="text/javascript"> var force = d3.layout.force() ...
So far we have covered some important aspects of the force layout such as gravity, charge, friction, and momentum. In this recipe we will discuss another critical functionality: links. As we have mentioned in the introduction section, D3 force layout implements a scalable simple graph constraint, and in this recipe we will demonstrate how link constraint can be leveraged in conjunction with other forces.
Open your local copy of the following file in your web browser:
https://github.com/NickQiZhu/d3-cookbook/blob/master/src/chapter11/link-constraint.html.
In this recipe, whenever the user clicks their mouse we will generate a force-directed ring of particles constrained by links between nodes. Here is how it is implemented:
<script type="text/javascript"> var force = d3.layout.force() .gravity(0.1) .charge(-30) .friction(0.95) .linkDistance(20) .linkStrength(1); ...
So far we have learned to use force layout visualizing particles and links similar to how you would use force layout in its classic application, the forced-directed graph. This kind of visualization is what force layout was designed for in the first place. However, this is by no means the only way to utilize force in your visualization. In this recipe we will explore techniques that I call force-assisted visualization. With this technique you can add some randomness and arbitrariness into your visualization by leveraging force.
Open your local copy of the following file in your web browser:
https://github.com/NickQiZhu/d3-cookbook/blob/master/src/chapter11/arbitrary-visualization.html.
So far we have explored many interesting aspects and applications of D3 force layout; however, in all of these prior recipes we simply apply force layout's computation (gravity, charge, friction, and momentum) directly to our visualization. In this recipe we will go one step further to implement custom force manipulation, hence creating our own type of force.
In this recipe we will first generate five sets of colored particles then we assign corresponding colors and categorical force pull to user's touch, hence pulling only the particles that match the color. Since this recipe is a bit complex, I will give an example here: if I touch the visualization with my first finger it will generate a blue circle and pull all blue particles to that circle, while my second touch will generate an orange circle and only pull the orange particles. This type of force manipulation is commonly referred to as categorical multi-foci.
At last, we will show how to implement a force-directed graph, the classic application of D3 force layout. However, we believe with all the techniques and knowledge you have gained so far from this chapter implementing force-directed graph should feel quite straightforward.
Open your local copy of the following file in your web browser:
https://github.com/NickQiZhu/d3-cookbook/blob/master/src/chapter11/force-directed-graph.html.
In this recipe we will visualize the flare data set as a force-directed tree (tree is a special type of graph):
<script type="text/javascript"> var w = 1280, h = 800, z = d3.scale.category20c(); var force = d3.layout.force() .size([w, h]); var svg = d3.select("body").append("svg") .attr("width", w) .attr("height", h); d3.json("/data/flare.json", function(root) { var nodes = flatten(root), links = d3.layout.tree().links(nodes);...