D3部队向图阿贾克斯更新部队、图阿贾克斯

2023-09-10 17:13:07 作者:逗比症患者

我使用d3.js和jQuery用PHP后端(基于Yii框架)来创建一个动态的力向图重新present网络上的主机和服务的当前状态,我们监控使用Nagios的。

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.

图表显示根 - > hostgroups - >主机 - >服务。我创建了一个服务器端的功能,按以下格式返回一个JSON对象

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

的节点包含其用于在链接和颜色显示所述节点(行=绿色,警告=黄色等)的状态的链接具有源对象的ID和目标对象id的节点的对象ID。节点和链接可能会改变,因为新的主机从监控系统中添加或删除

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

我有以下的code的设置初始SVG,然后每隔10秒

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

检索当前JSON对象 创建地图的链接 选择当前节点和链接,并将其绑定到JSON数据 输入链接加入和退出链接被删除 在更新和增加的节点会改变他们的填充颜色,并有 用他们的名字一个提示添加

强制启动 Retrieves the current JSON object Creates map of the links Selects the current nodes and links and binds them to the JSON data Entering links are added and exiting links are removed updated and added nodes will change their fill colour and have a tooltip with their name added

Force is started

$ ajaxSetup({缓存:假})。     宽度= 960,     高度= 500;     节点= [];     链接= [];     力= d3.layout.force()         .charge(-1000)         .linkDistance(1)         .size([宽,高]);

$.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

所有的正常工作与每一个在code循环时它会导致可视化重启异常,节点的所有反弹,直到他们解决上述作品。我需要为任何现有的项目,以保持原样,但任何新的节点和链接被添加到可视化,并点击和拖动等。

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.

推荐答案

我设法找到使用上述所有的建议混合物的解决问题的方法,下面是code我已经用

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 + ")"); 
        }