13

I think a many of you, who worked with D3.js, already experienced the same thing: your network or whatever moveable elements you took keep flying out of the svg-element if they are pushed to hard. If my network is to large the outer nodes disappear, they kind of 'fall of the edge of the world'.

I'm pretty shure there is a way to make the border of the svg a solid 'wall', so elements can't leave it and fly invisible through space :)

What did you do with this problem? How did you solve it?

Thanks in advance, David

David
  • 335
  • 3
  • 16

3 Answers3

15

In the end, if you find the right sites on the web it's pretty easy. http://bl.ocks.org/1129492 does exactly what I wanted - the objects can't slip out of the svg. So he just added some constraints when updating the nodes positions. My 'tick' function ended up like

node.attr("cx", function(d) { return d.x = Math.max(15, Math.min(width - 15, d.x)); })
    .attr("cy", function(d) { return d.y = Math.max(15, Math.min(height - 15, d.y)); });

link.attr("x1", function(d) { return d.source.x; })
    .attr("y1", function(d) { return d.source.y; })
    .attr("x2", function(d) { return d.target.x; })
    .attr("y2", function(d) { return d.target.y; });

node.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });

This is called whenever something important might happen, the "tick"-thing is something built somewhere deep inside D3.js, so don't ask me about that. :)

The first two lines and the last one in the given code check that the coordinates don't get out of the box.

Hope this can help someone out there to do the job faster than I did ;)

Have a good time, Dave

David
  • 335
  • 3
  • 16
2

To make the boundaries a solid "wall" in a force-directed graph, you would need to implement some custom collision detection for the edges of the bounding box. Here's an example of a custom collision detection.

christopher's approach will work well for smallish graphs, but for graphs much larger than the viewport they will scale to unreadably small sizes. The approach I give above will also fail on large graphs in small viewports as the collisions will at some point be unable to be resolved.

For really large graphs, I would recommend instead simply allowing the user to pan and zoom out. This SO post gives some tips about zooming. You will also need to create a rect that is the size of your graph as a target to receive mouse events. You can resize this dynamically to the size of, for example, a force directed graph, in the tick event handler.

Hope those are some useful pointers.

Community
  • 1
  • 1
seb
  • 3,646
  • 26
  • 21
  • the 'tick' was a thing to mention here, as you can see I solved the problem in the tick-function, but without any zooming :) – David Jan 23 '13 at 14:04
0

The general way to fix graph visualization running away from you is to get the bounding box, then create a transformation on the SVG that maps the bounding box onto the viewport exactly (keeping the aspect ratio clamped to some vaguely reasonable value).

If the user zooms in, then you forget about this process.

The result will be that if "stuff" flies away you effectively will see it zooming out. And the user can zoom is as they please.

The key to getting this working well is to write down a state graph. When something triggers a recalculation you go into "fix the bounding box" mode, and when the graphs mostly stops moving , you switch to "user controls zoom" mode. Getting this to work well means getting the transitions between the states right (always provide an override for advanced users).

christopher
  • 1,061
  • 2
  • 8
  • 10
  • Thank you for the assisstance! Now I found exactly what I wanted, and it's working without any zoom-stuff. I thought it to be much more difficult, but it turned out to be very easy to control changes in the coordinates not to pop out of the box ;) – David Jan 23 '13 at 14:06