Check out a free preview of the full Introduction to D3.js course
The "Force Practice: Using D3 Force & Position" Lesson is part of the full, Introduction to D3.js course featured in this preview video. Here's what you'd learn in this lesson:
Shirley demonstrates how to add animation to the graph developed in the first part of the Force Practice segment by using the D3 force layout.
Transcript from the "Force Practice: Using D3 Force & Position" Lesson
[00:00:00]
>> The very first thing we're going to draw is the links, because the links we want to be all the way at the bottom. So let's go and make our link = d3.select.svg.selectAll of the links. And in this case, we're going to use a line element. We're going to pass in our data, and our data is our graph object and the links array within the graphs of graph.links.
[00:00:42]
And then for the key function, we're going to pass back the id on each of these links. Use our join to create the lines. And actually, what I need to do is I think actually, I'm going to say select all of the links, select all the elements with class link.
[00:01:08]
And then once we've created and updated, created the line element then that we're going to say let's have that as class is link is true. And then we're going to have our attribute, we wanna stroke that and a light gray, let's say, and let's give opacity of 0.5.
[00:01:37]
So that because there'll be a lot of lines, a lot of links and that you can kind of see them even when they're overlapping each other. And now if we inspect the SVG, what we should see is all of the lines created, but not yet showing up. It's not being rendered yet because we haven't used D3 force layout to calculate the positions of the nodes yet.
[00:02:06]
So let's go ahead and create our flowers. And for the sake of time, I'm just gonna go back to our previous notebook and just like grab our flowers code from there. And copy and paste that, sorry for all the scroll. Okay, so I'm going to grab our flowers code, const flower.
[00:02:44]
And actually, I don't need to do any of the animation, so I'm gonna just take that part out. So thus I don't need the update and exit either. I don't need the transition. And what we should see now with our flowers created is we should see all of the flowers, all the way, Gosh!
[00:03:19]
Ooh, svg.selectAll, yes. Copied and pasted too blindly. Okay, so d3.select, and and we're not supposed to be citing the attribute. So we've copied and pasted the flowers from our previous notebook, took out all of the animation things and took out the translate positioning for now. So we should be able to see all of our flowers, perfect, all the way up here is clustered up at 00, which is the default because we haven't set the positions yet.
[00:04:01]
And then, Let's finally go ahead and make our genres. And so for our genres, we're gonna call that genres = d3.select(svg). And we're going to call that, let's select all of the elements that have the class genre on it. We're going to bind the data. And actually, another thing I have done incorrectly is for the flowers, and you want to be binding the graph.nodes, and we're going to use a key function d.title.
[00:04:52]
So that should be the final change we need to do on the flowers. And then we are going to do, The data we want is graph.genres. And for the key function, let's use the label, Join. We're going to make these texts elements, and let's make sure to add the class genre on there.
[00:05:27]
So that our selection matches true. And let's put the text, and that should be the title. And let's just go ahead and center that text. So now, we should have all of the elements we need rendered. And then this is where we're going to use force simulation. And so let's go and call it const simulation.
[00:06:03]
And we're going to call d3.forceSimulation. And we're going to pass in nodes. And the nodes that we want is we actually want the combination of the flower nodes and the genres together as the nodes that we use to calculate all of the positions. So let's go ahead and use low dash to union our array of nodes, and our array of genres.
[00:06:38]
We're going to pass that into the force simulation. We're going to tell the force simulation that one of the first forces that we want to apply is the link, d3.forceLink. So we want to have an attractive force between any nodes that are linked to each other. So that's passing graph.links.
[00:07:04]
And again because graph.links, its source and target are already directly referencing our node objects. We don't need to specify any sort of identifier to connect them to the .id function that we saw earlier in the example. And I'm going to say that I want to avoid collision between each of the each of the nodes.
[00:07:38]
So what I'm going to do is I'm going to say forceCollide. And I'm going to pass in radius, and that radius will be dependent on the size of my node. So for my flowers, I want it to be I think d.scale. And then remember that our d.scale is dependent on our petals being I think 100 byte, 100 pixels in size.
[00:08:21]
And then finally, I want to center our, Nodes on the midpoint of our SVG containers, so that's width divided by 2. And for the height I'm actually using width divided by 2. So in that case the center would be width divided by 4. And a small note about collide, so I'm using collide and the other example I gave is force many body, so the negative or positive charge.
[00:08:59]
And I find oftentimes that now I use them together, they kinda like end up doing very similar things. So I usually just use one or the other. And in this case, I chose to use collide. And then finally, we're going to say what should happen on each tick.
[00:09:21]
So on each tick the positions update, so then we want to go and update the positions for our flowers. And so let's transform translate that with the newly calculated x,y positions. And this again is a reason why the original data array is directly mutated. Because we bound that original data array to our DOM elements, and then we need to be able to access those DOM elements, the bound data on those DOM elements on each tick.
[00:10:07]
And then we expect the x,y positions to be in that bound data element. And that's why it gets mutated directly. Do the same thing for the genres. And then finally, for our links, for our line elements, the attributes are x1. And so x1 should be the x position of the source.
[00:10:44]
And I'm just gonna copy and paste, These over. So that's y1, x2, y2, source.y, then target.x, and target.y. And if we've done this part correctly, a big if, then if we run this up here, It should hopefully be, there we go, yeah. I'm still struggling a little bit to get to the final layout at once.
[00:11:34]
And there's definitely settings, and toggles, and levers, that we can pull to get it to arrive to an optimal layout faster. But for the purposes of this exercise, I think we've gotten it to a good point. And if we filter the R movies back in, then we can see that it's updating correctly.
[00:12:04]
Yeah, so there we go. [LAUGH] We got the, wait, no, the genres are not being, The genre texts are not showing up. So let me go ahead and debug that really quickly, hopefully quickly. selectAll genres, classed('genre', true), join( 'text'), d.label, yes, label, we want it label And again, if you weren't able to get all of the code because my laptop is struggling, then you can find the solution to all of the code in the other cell.
Learn Straight from the Experts Who Shape the Modern Web
- In-depth Courses
- Industry Leading Experts
- Learning Paths
- Live Interactive Workshops