Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Zooming and brushing in d3 force directed graph

I'm having a problem in getting D3 to perform proper brushing when zooming is performed.

I have a jsFiddle created here http://jsfiddle.net/Gwp25/2/ showing the network with some dummy data I found elsewhere. The operation to follow is this. Zoom in (using mousewheel), then turn on brushing. After doing this, brush the nodes. The nodes that are selected are off - some out of the brush area. Here is the relevant part of the code dealing with the selecting of nodes within the brush extent.

            .on("brush", function() {
                var extent = d3.event.target.extent();
                console.log(extent);
                d3.selectAll(".node").select("circle").classed("selected", function(d) {
                    return d.selected = (extent[0][0] <= x_scale(d.x) && x_scale(d.x) < extent[1][0]
                            && extent[0][1] <= d3.tran(d.y) && y_scale(d.y) < extent[1][1]);
                });
            })

Does anyone have an idea to fix this. I know it's to do with the nodes and their original position and x, but I'm not quite sure about how to get the node x and y with respect to their zoomed location.

Any ideas?

like image 886
Eamonn Avatar asked Jan 03 '14 01:01

Eamonn


People also ask

What is D3 force?

D3's force layout uses physics based rules to position visual elements. This article shows how to use D3's force layout and how to use it to create network visualisations and circle clusters. D3's force layout uses a physics based simulator for positioning visual elements.

What is force simulation in D3?

# d3.forceSimulation([nodes]) · Source. Creates a new simulation with the specified array of nodes and no forces. If nodes is not specified, it defaults to the empty array. The simulator starts automatically; use simulation. on to listen for tick events as the simulation runs.


1 Answers

I believe I have a working version of what you're looking for: http://jsfiddle.net/Gwp25/8/

You were close on the implementation. I'll explain what I changed to make it work.

First, I attached scales to the zoom function. This is important as d3 will automatically update them as you zoom in and out. It's important to note that I did not use your identity scales. If you use an identity scale d3 zoom behavior will not update the scale. Here are the scales that I created that are identical to yours when there is no zoom:

var x_scale = d3.scale.linear().domain([0, chartWidth]).range([0, chartWidth]);
var y_scale = d3.scale.linear().domain([0, chartHeight]).range([0, chartHeight]);

Now the brush also takes scales as parameters. This is where you mistakenly put the original identity scales. So even though the graph was zoomed and panned you used the same scale to map points to the newly zoomed graph.

In order to feed the brush the correct scales, you can access the zoom behavior's scales by calling: zoom.x() or zoom.y().

Once you've done this the rest is gravy.

Note: I hacked the code a bit so I could access your zoom function in toggleBrushing by making it a global variable. I don't recommend keeping it this way, but I didn't want to do heavy refactoring. Good luck, hope that helps!

like image 186
Ben Rudolph Avatar answered Dec 26 '22 00:12

Ben Rudolph