【发布时间】:2013-08-16 04:45:35
【问题描述】:
我正在使用 d3.js 和 jquery 以及 PHP 后端(基于 yii 框架)来创建动态强制有向图来表示我们正在使用 Nagios 监控的网络上主机和服务的当前状态。
该图显示根 -> 主机组 -> 主机 -> 服务。我创建了一个服务器端函数以返回以下格式的 JSON 对象
{
"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,以及用于显示节点状态的颜色(OK = 绿色,WARNING = 黄色等)链接具有节点的源对象 ID 和目标对象 ID。随着新主机的添加或从监控系统中删除,节点和链接可能会发生变化
我有以下代码设置初始 SVG,然后每 10 秒设置一次
- 检索当前 JSON 对象
- 创建链接地图
- 选择当前节点和链接并将它们绑定到 JSON 数据
- 添加进入链接并删除退出链接
- 更新和添加的节点将改变其填充颜色并具有 添加名称的工具提示
-
强制开始
$.ajaxSetup({ 缓存: false }); 宽度 = 960, 高度 = 500; 节点 = []; 链接 = []; 力 = d3.layout.force() .charge(-1000) .linkDistance(1) .size([宽度,高度]);
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);
上述所有方法都可以正常工作,但每次代码循环时都会导致可视化重新启动,并且节点都会反弹,直到它们稳定下来。我需要的是让任何当前项目保持原样,但任何新节点和链接都会添加到可视化中,并且可以点击和拖动等。
如果有人能提供帮助,我将永远感激不尽。
【问题讨论】:
-
发生这种情况是因为您实际上每次都在重新加载数据并重新计算布局。我认为您应该找到一种方法来检查服务器端的更改,并找到一种方法将它们与更新时的内容连接起来,而不是每次都重新加载新的 JSON。例如,创建一个仅包含 new 节点和链接的 JSON,然后在调用
force.on("tick", function())时将这些对象推送到.nodes和.links -
我真的希望有一种方法可以避免将当前的可视化对象传回服务器,因为这会使整个解决方案变得更加复杂。我开始查看 d3.js 的原因是您将数据传递给 d3,它会计算出输入和退出数据的内容,从而使您不必手动执行此操作。没有替代方法吗?
-
实际上,我正在重新阅读您的评论,而 d3.js 没有 弄清楚数据中输入和退出的内容。它使用您提供的数据计算您告诉它的任何内容。如果要更改正在使用的数据,则必须自己更改。 :)
-
Aaa我在最后一条评论中搞砸了......对不起!您应该阅读一下:groups.google.com/forum/#!topic/d3-js/q8yz2OUMW8g 请点击链接,因为它们有宝贵的信息...
标签: ajax json d3.js force-layout