1

I am trying to visualize the server availability (and later other things, once this works) by fetching data from the Zabbix API. You can see an example on how the data returned looks like [here][1] in the Zabbix API Documentation.

Getting the data is not the problem, but I am having some trouble with d3.js's data joining I think, or rather how I am supposed to do this.

After fetching the data I get a array of servers sorted alphabetically, and I want the new servers to appear, the ones removed to just disappear and any changes in availability (or otherwise - in the future) to be reflected with color or whatever else I might think of.

The point is that the graph shouldn't re-initialize, it should just be updated by adding or removing nodes.

Which is the bit I am having problems with. I have managed to add more and more nodes to the list (never clearing it), I have managed to get them to "redraw" each time I fetch new data, i.e all the nodes are added again, and snap to the center like they first do when you load the page.

And the third which has resulted in all the nodes being stuck in the top left corner.

The latter which is the current state of my code.

I am a bit unsure what I am doing wrong at this point, I was looking at this which seems to be fairly close to what I need, without the links anyway (for now). That works fine, and I've tried to replicate that behavior in my code, - yet it does not work.

I would appreciate it if someone had some pointers for me, that would be awesome. I have been playing with this at work for the past week without getting much further :)

Thanks!

Because I only have access to Zabbix at work I am really only able to test things in the 16-21 time period CET time, which is for about another 4~ hours today. If anyone have any suggestions during the night I will try it out tomorrow :D

My code on GitHub will be in a link below my post, since this lack of reputation on this site has put me in a gloomy hole where I can only add two links to my post.

Why isn't this global? I have more than 10 rep on other SE sites..

Edit:

Still having trouble, every time the data is refreshed the circles "enter" like they do when you first load this: http://mbostock.github.com/d3/talk/20111018/collision.html No idea what to do now :/

VividD
  • 10,456
  • 6
  • 64
  • 111
flexd
  • 819
  • 7
  • 17

1 Answers1

1

What you mention in there is the default behaviour of D3. When you add nodes they will be inserted in the upper left corner. You can change this behaviour by writing your own placement method and directly setting the X and Y of each node when you add it to your force directed graph.

The trick is to apply this algorithm:

1) calculate the limits of the viewport (say the limits of your drawing area - 20) and use the tricks from the force directed bound example ( http://bl.ocks.org/1129492 )

2) then for each visualization tick do this: calculate forces to keep nodes in viewport

3) the algorithm to keep node in viewport would be something along these lines: for each node calculate X and Y according to the forces that can be applied on the 4 directions (top left, bottom left, top right, bottom right) - if it's closer to upper left then you will set X and Y accordingly....anyway it will not be outside the screen....

Another trick would be to set up the root node in the center (see this post: How do I set the focal node in a D3.js Force Directed Graph?). That would help stabilize your graph. Another advice would be to try to not mix ajax calls with your redraws. Ideally use some callbacks and call redraw when data is loaded, otherwise you will end up with spaghetti code (it's not unusual for force directed graphs to be larger than 1000 lines).

Hope it helps.

Community
  • 1
  • 1
paxRoman
  • 2,064
  • 3
  • 19
  • 32
  • The nodes did appear properly in working fashion earlier at the centre of my svg display area before, I am not sure what happened, or what I did to change that :/ I am quite new to javascript so it is a bit messy now, but it was a lot worse earlier before I cleaned it up a bit. I just tried adding `svg.selectAll("g.node") .attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });` to my on "tick" event, and d.x and d.y are both undefined :/ – flexd Jun 26 '12 at 18:15
  • ok then. just apply the techniques you find in mike's tutorials about enter - update - exit and everything should be fine from now on :) – paxRoman Jun 26 '12 at 18:18
  • That's the problem. I have! Through countless iterations this whole past week, the demos and everything look identical to what I do, yet it's not working here :s. Which is why I finally ask here, I have no clue what is causing it to just not work now. Edit: Updated the gist to be more callback-y – flexd Jun 26 '12 at 18:22
  • The example I have been looking at is this http://bl.ocks.org/1095795#index.html which seems to be exactly what I want and need. I have tried making my code as identical to that as possible. – flexd Jun 26 '12 at 18:27
  • I guess what I am wondering is, how can that example get away with not setting anything special, but my code doing the exact same things just does not work at all? – flexd Jun 26 '12 at 18:46
  • it's not that it does not set anything since it clearly does (gravity, distance, charge, size)...I read your code again, but I was not able to find the section where you update your links...there might an error in that part of the code...every force layout has nodes and links ...but in your case is not immediately obvious which are the links....plus in the draw method you should update both nodes and links...whereas in your code I only see the nodes updated... – paxRoman Jun 26 '12 at 19:36
  • I have no links at all, there are no links between the nodes currently. – flexd Jun 26 '12 at 20:12
  • I have this semi-working now, but back to my original problem. I am not removing any nodes, just adding them each update. I just want to REPLACE the nodes list with a new list of nodes, isn't that possible? I do not get a incremental/decremental update of how the server status has changed. – flexd Jun 27 '12 at 14:43
  • you have to decide what you want: 1) you either have a list of nodes and you update it or 2) you replace the list each time... your answer almost points to the fact that you replace it each time... both are possible... what is the last version of your code? gist.github.com/49af02dab7bb060e939a – paxRoman Jun 27 '12 at 19:22
  • https://github.com/flexd/zstatus/blob/master/js/main.js is the latest. That "works" in the way that they are not just added, and then added again (and the list grows). But they are still "entering" every time the data is updated (i.e sliding in from the edges towards the center). If I update a node that is already in the list, I just want nothing to happen if there are no changes. If I add a node that wasn't there, it should slide in or just appear and if something is removed it should just disappear or something like that. – flexd Jun 28 '12 at 05:47
  • that happens because with nodes.slice(0) you always create a new array of nodes (http://www.w3schools.com/jsref/jsref_slice_array.asp)... therefore it's obvious that they will always "enter" again ... – paxRoman Jun 28 '12 at 09:10
  • Oh really? I had the same problem when I was just passing nodes directly iirc, I am going to work in about an hour so I will try it out then :) Thanks for all the help so far! – flexd Jun 28 '12 at 11:03
  • I just changed that nodes.slice(0) to just nodes, and it (still) has no effect. Perhaps the problem is not so obvious after all. :/ – flexd Jun 28 '12 at 13:51
  • That is ridiculous heh, are you on IRC at all? I can join any network, I'm already on efnet/freenode/quakenet. – flexd Jun 29 '12 at 16:47