D3 Force Directed Graph ajax actualización

Estoy usando d3.js y jquery con un back-end de PHP (basado en el framework yii) para crear un gráfico dinámico dirigido por fuerza para representar el estado actual de los hosts y servicios en la red que estamos monitoreando usando Nagios.

El gráfico muestra la raíz -> grupos de hosts -> hosts -> servicios. He creado una función del lado del servidor para devolver un objeto JSON en el siguiente formato

{
    "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"
        }
    ]
}

Los nodos contienen un ID de objeto que se usa en los enlaces y el color para mostrar el estado del nodo (OK = verde, ADVERTENCIA = amarillo, etc.) Los enlaces tienen los ID de objeto de origen y los ID de objeto de destino para los nodos. Los nodos y los enlaces pueden cambiar a medida que se agreguen o eliminen nuevos hosts del sistema de monitoreo

Tengo el siguiente código que configura el SVG inicial y luego cada 10 segundos

Recupera el objeto JSON actualCrea mapa de los enlaces.Selecciona los nodos y enlaces actuales y los enlaza a los datos JSONLos enlaces que ingresan se agregan y los enlaces que salen se eliminanLos nodos actualizados y agregados cambiarán su color de relleno y tendrán una información sobre herramientas con su nombre agregado

Se inicia la fuerza

$ .ajaxSetup ({cache: false}); ancho = 960, altura = 500; nodo = []; enlace = []; 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);

Un ejemplo de la salida se puede ver enVisualización de la red

Todo lo anterior funciona correctamente con la excepción de que cada vez que el código realiza un bucle, la visualización se reinicia y todos los nodos rebotan hasta que se asientan. Lo que necesito es que los elementos actuales permanezcan como están, pero los nodos y enlaces nuevos se agregan a la visualización y se pueden hacer clic y arrastrar, etc.

Si alguien me puede ayudar estaría eternamente agradecido.

Respuestas a la pregunta(4)

Su respuesta a la pregunta