Biswajit Banerjee

### Creating an animation with d3.js

How the closest-point return animation was created

##### Introduction

In Part 8 of the series on return algorithms for plasticity we animated the closest-point return algorithm as shown below.

An animated GIF of the plot can be generated using the following R script.

Let us explore how the animation at the top of the page was produced using d3.js.

#### Input data

The input data that can be seen in the R function ReadAndPlotClosestPoint were generated during a simulation using print statements. These have to be converted into a form that can be read easily by Javascript. For our simulation we converted these into JSON and created the file yieldSurfData.json that contains:

#### The HTML file

In the HTML file, I added the following to allow the animation to be added to the DOM.

#### The Javascript code

Let us now explore the Javascript code used to generate the animation.

##### Generating points on the yield surface

We first generate points on the yield surface in $z-r'$-space. These are displayed in blue in the figure. The function computeYieldSurface takes an input the data for a single iteration (read from the JSON file) and the number of points to be used to discretize the yield surface.

The procedure is identical to that used in the R script, except for two differences:

• the d3.range function is used to create the vector of $\theta$ values. This function differs from the R function seq in that the end point of the range is not included in the sequence that is produced. Therefore, the set of points produced by d3.js is not identical to that produced by R.
• the function returns a zipped array created with d3.zip instead of a R dataframe.
##### Drawing the yield surface and closest-point projection

We use the drawYieldSurface function to plot and animate the yield surface and the closest-point projection. Let us look at the full code first and then explore some of the details.

Let us now look at some of the details of the code.

###### Creating the SVG

First we select the <div> in our HTML file using d3.select and add a SVG canvas to it:

###### Creating the canvas group

Then we create a subset of the SVG canvas as the region where the plot will be produced and identify it using a group g. This area has to be translated so that the top left hand corner is at the right position.

###### Creating map from real to canvas coordinates

We then compute the true yield surface and find the extents of the domain of the plot based on the yield surface and the trial stress state. We use these extents to create maps from real coordinates to svg coordinates. Separate maps are also created so that the axis labels can be converted into MPa.

###### Creating SVG polyline generator

To plot the polylines that represent the yield surface, its approximation, and the closest point projection, we need a function that can convert a set of points to the SVG representation of a polyline. We generate that function using d3.line:

###### Creating the axes and the yield surface

Next, we create the axes. The generation of axes using d3.js is straightforward, but we have to keep in mind that a translation may be required depending on the position of the axis.

After the axes have been created, we add the polyline representing the yield surface to the SVG. This is done using the zipped data returned from the computeYieldSurface function. Because the yield surface does not change during closest-point search iterations, we use the data from the first iteration to plot this curve.

Notice that we use the .datum method in this case and that the attribute d is set using the line function we had defined earlier.

###### Creating groups for each iteration

Now that the fixed content of the plot has been created, we are ready to create the content that changes between iterations. To do that, we loop through the iterations and add a group for each iteration:

We set the opacity of the group to 0 so that although all the objects in the plot have been created, none are visible when the animation starts.

###### Adding circles to the approximate surface

Now we are ready to add in the polyline approximation to the yield surface in red. The procedure is identical to the plot of the full yield surface. We also add circles to each vertex of the polyline using

###### Adding triangles to the projection line

Next we add the line that represents the closest-point projection (in green) and add triangles to the end points for clarity. The triangles are added using

###### Setting up the animation

Now we can terminate the loop of the iterations and proceed to setting up the animation. We start the animation by selecting the group that has class iteration0 and use a transition that takes 1 second to move from one frame to the next. We call the drawNextSurf method when the animation starts.

The drawNextSurf method changes the opacity of the active group to 1, waits for 1 second, and then changes back the opacity to 0.

After that, it increments to iteration count, selects the next group, and recurses after a short delay.

To allow for the animation to loop, we set the iteration index to 0 when the total number of iterations in the data is reached.

#### Remarks

This d3.js animation took me 2 days to complete, starting from absolutely no knowledge of the library, and with significant breaks in the workflow. I’d suggest that, since a novice can learn and use the library so quickly, d3.js should be an essential tool in the computational engineers toolbox to make data available in the form of interactive plots instead of the static (and hard to grasp) plots that are the norm in engineering literature.

In the next article, we will go back to the work on XML particle data that we had started earlier and discuss ways to reading XML files using C++ code.