D3 Force Directed Graph ajax update

d9705996

I am using d3.js and jquery with a PHP back-end (based on yii framework) to create a dynamic force directed graph to represent the current state of hosts and services on the network that we are monitoring using Nagios.

The graph shows root -> hostgroups -> hosts -> services. I have created a server side function to return a JSON object in the following format

{
    "nodes": [
        {
            "name": "MaaS",
            "object_id": 0
        },
        {
            "name": "Convergence",
            "object_id": "531",
            "colour": "#999900"
        },
        {
            "name": "maas-servers",
            "object_id": "719",
            "colour": "#999900"
        },
        {
            "name": "hrg-cube",
            "object_id": "400",
            "colour": "#660033"
        }
    ],
    "links": [
        {
            "source": 0,
            "target": "531"
        },
        {
            "source": 0,
            "target": "719"
        },
        {
            "source": "719",
            "target": "400"
        }
    ]
}

The nodes contain an object id which is used in the links and colour for displaying the state of the node (OK = green, WARNING = yellow, etc) The links has the source object ids and target object ids for the nodes. The nodes and links may change as new hosts are added or removed from the monitoring system

I have the following code which setups the initial SVG and then every 10 seconds

  1. Retrieves the current JSON object
  2. Creates map of the links
  3. Selects the current nodes and links and binds them to the JSON data
  4. Entering links are added and exiting links are removed
  5. updated and added nodes will change their fill colour and have a tooltip with their name added
  6. Force is started

    $.ajaxSetup({ cache: false }); width = 960, height = 500; node = []; link = []; force = d3.layout.force() .charge(-1000) .linkDistance(1) .size([width, height]);

    svg = d3.select("body").append("svg")
        .attr("width", width)
        .attr("height", height)
      .append("g");
    
    setInterval(function(){
        $.ajax({
            url: "<?php echo $url;?>",
            type: "post",
            async: false,
            datatype: "json",
            success: function(json, textStatus, XMLHttpRequest) 
            {
                json = $.parseJSON(json);
    
                var nodeMap = {};
                json.nodes.forEach(function(x) { nodeMap[x.object_id] = x; });
                json.links = json.links.map(function(x) {
                    return {
                        source: nodeMap[x.source],
                        target: nodeMap[x.target],
                    };
                });
    
                link = svg.selectAll("line")
                    .data(json.links);
    
                node = svg.selectAll("circle")
                    .data(json.nodes,function(d){return d.object_id})
    
                link.enter().append("line").attr("stroke-width",1).attr('stroke','#999');
                link.exit().remove();
    
                node.enter().append("circle").attr("r",5);
                node.exit().remove();
    
                node.attr("fill",function(d){return d.colour});
    
                node.append("title")
                  .text(function(d) { return d.name; });
    
                node.call(force.drag);
    
                force
                    .nodes(node.data())
                    .links(link.data()) 
                    .start()
    
                force.on("tick", function() {
    
                    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("cx", function(d) { return d.x = Math.max(5, Math.min(width - 5, d.x));  })
                        .attr("cy", function(d) { return d.y = Math.max(5, Math.min(height - 5, d.y)); });
    
                });
            }
        });
    },10000);
    

An example of the output can be seen at Network Visualization

All of the above works correctly with the exception that every time the code loops it causes the visualization to restart and the nodes all bounce about until they settle. What I need is for any current items to stay as they are but any new nodes and links are added to the visualisation and are clickable and draggable, etc.

If anyone can help I would be eternally grateful.

d9705996

I have managed to find a solution to the problem using a mixture of all the advice above, below is the code I have used

    var width = $(document).width();
    var height = $(document).height();

    var outer = d3.select("#chart")
        .append("svg:svg")
            .attr("width", width)
            .attr("height", height)
            .attr("pointer-events", "all");

    var vis = outer
        .append('svg:g')
            .call(d3.behavior.zoom().on("zoom", rescale))
            .on("dblclick.zoom", null)
        .append('svg:g')

        vis.append('svg:rect')
            .attr('width', width)
            .attr('height', height)
            .attr('fill', 'white');

        var force = d3.layout.force()
            .size([width, height])
            .nodes([]) // initialize with a single node
            .linkDistance(1)
            .charge(-500)
            .on("tick", tick);

        nodes = force.nodes(),
            links = force.links();

        var node = vis.selectAll(".node"),
            link = vis.selectAll(".link");

       redraw();

       setInterval(function(){
           $.ajax({
                url: "<?php echo $url;?>",
                type: "post",
                async: false,
                datatype: "json",
                success: function(json, textStatus, XMLHttpRequest) 
                {
                    var current_nodes = [];
                    var delete_nodes = [];
                    var json = $.parseJSON(json);

                    $.each(json.nodes, function (i,data){

                        result = $.grep(nodes, function(e){ return e.object_id == data.object_id; });
                        if (!result.length)
                        {
                            nodes.push(data);
                        }
                        else
                        {
                            pos = nodes.map(function(e) { return e.object_id; }).indexOf(data.object_id);
                            nodes[pos].colour = data.colour;
                        }
                        current_nodes.push(data.object_id);             
                    });

                    $.each(nodes,function(i,data){
                        if(current_nodes.indexOf(data.object_id) == -1)
                        {
                            delete_nodes.push(data.index);
                        }       
                    });
                    $.each(delete_nodes,function(i,data){
                        nodes.splice(data,1); 
                    });

                    var nodeMap = {};
                    nodes.forEach(function(x) { nodeMap[x.object_id] = x; });
                    links = json.links.map(function(x) {
                        return {
                            source: nodeMap[x.source],
                            target: nodeMap[x.target],
                            colour: x.colour,
                        };
                    });
                    redraw();
                }
            });
       },2000);


       function redraw()
       {
           node = node.data(nodes,function(d){ return d.object_id;});
           node.enter().insert("circle")
                .attr("r", 5)
           node.attr("fill", function(d){return d.colour})
           node.exit().remove();

           link = link.data(links);
           link.enter().append("line")
               .attr("stroke-width",1)
           link.attr('stroke',function(d){return d.colour});
           link.exit().remove();
           force.start();

       }

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

          node.attr("cx", function(d) { return Math.round(d.x); })
              .attr("cy", function(d) { return Math.round(d.y); });
        }

       function rescale() {
            trans=d3.event.translate;
            scale=d3.event.scale;

            vis.attr("transform",
                "translate(" + trans + ")"
                + " scale(" + scale + ")"); 
        }

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

From Dev

D3 force-directed graph: update node position

From Dev

D3 force directed graph direction

From Dev

Introducing Arrow(directed), in Force Directed Graph d3

From Dev

d3 force directed graph downward force simulation

From Dev

D3 force directed graph: Performance issue in a complex graph

From Dev

"Pinning" nodes in a D3 force-directed graph

From Dev

Adding label to the links in D3 force directed graph

From Dev

d3 force directed graph remove text cursor

From Dev

d3 force directed graph don't select text

From Dev

semantic zooming of the force directed graph in d3

From Dev

modifying the d3 force-directed graph example

From Dev

d3 force directed graph, links not being drawn

From Dev

D3 force directed graph moving text

From Dev

modifying the d3 force-directed graph example

From Dev

Load JSON object into D3 Force Directed Graph

From Dev

Dynamically change color of D3 Node (force directed graph)

From Dev

JUNG force directed graph

From Dev

Having trouble converting a D3 v3 Force Directed graph into D3 v4 library implementation?

From Dev

How to add a dynamic legend to a D3 force directed graph in Apex?

From Dev

How to draw a simple Force-directed graph in D3 Javascript

From Dev

The links between the nodes in Force-Directed Graph in D3 Javascript

From Dev

How to restrict number of nodes initially in d3 Force directed graph

From Dev

How to render links as elbow connectors in d3 force directed graph

From Dev

D3 force directed graph node - text is being duplicated when expading

From Dev

How to make it so D3 Force Directed Graph generates nodes in same position each time

From Dev

Unable to Delete links from a D3 force directed graph with arrows

From Dev

Collapsible D3 force directed graph with non-tree data

From Dev

How to choose which JSON file to use in your D3 force directed graph

From Dev

D3 Force Directed Graph: why don't the flags appear?

Related Related

  1. 1

    D3 force-directed graph: update node position

  2. 2

    D3 force directed graph direction

  3. 3

    Introducing Arrow(directed), in Force Directed Graph d3

  4. 4

    d3 force directed graph downward force simulation

  5. 5

    D3 force directed graph: Performance issue in a complex graph

  6. 6

    "Pinning" nodes in a D3 force-directed graph

  7. 7

    Adding label to the links in D3 force directed graph

  8. 8

    d3 force directed graph remove text cursor

  9. 9

    d3 force directed graph don't select text

  10. 10

    semantic zooming of the force directed graph in d3

  11. 11

    modifying the d3 force-directed graph example

  12. 12

    d3 force directed graph, links not being drawn

  13. 13

    D3 force directed graph moving text

  14. 14

    modifying the d3 force-directed graph example

  15. 15

    Load JSON object into D3 Force Directed Graph

  16. 16

    Dynamically change color of D3 Node (force directed graph)

  17. 17

    JUNG force directed graph

  18. 18

    Having trouble converting a D3 v3 Force Directed graph into D3 v4 library implementation?

  19. 19

    How to add a dynamic legend to a D3 force directed graph in Apex?

  20. 20

    How to draw a simple Force-directed graph in D3 Javascript

  21. 21

    The links between the nodes in Force-Directed Graph in D3 Javascript

  22. 22

    How to restrict number of nodes initially in d3 Force directed graph

  23. 23

    How to render links as elbow connectors in d3 force directed graph

  24. 24

    D3 force directed graph node - text is being duplicated when expading

  25. 25

    How to make it so D3 Force Directed Graph generates nodes in same position each time

  26. 26

    Unable to Delete links from a D3 force directed graph with arrows

  27. 27

    Collapsible D3 force directed graph with non-tree data

  28. 28

    How to choose which JSON file to use in your D3 force directed graph

  29. 29

    D3 Force Directed Graph: why don't the flags appear?

HotTag

Archive