最近为了实现一个网页版的拓扑图, 采用了qunee.js这个js库. 觉得挺不错 . 记一下自己的使用心得.
qunee是一个js库,封装了html5的canvas的许多方法,在上面也做了自己的很多开发, 可以实现许多效果。
下面列举和运维相关的一些应用:
子网模式 http://demo.qunee.com/#SubNetwork
Demo
内网拓扑 http://demo.qunee.com/#Sinopec
Network Demo
公网拓扑 http://demo.qunee.com/#Public
Server Network
网络组织图表 http://demo.qunee.com/#Network
Organization Chart
总线模式 http://demo.qunee.com/#Bus
Demo
设备面板 http://demo.qunee.com/#Equipment
Demo
设备告警图一 http://demo.qunee.com/#Monitoring
Demo
设备告警图二 http://demo.qunee.com/#Alarm
Demo
VOIP http://demo.qunee.com/#VOIP
Demo
网络数据流 http://demo.qunee.com/#Flowing
Demo
VPC管理 http://demo.qunee.com/#VPC
Manager Demo
机房分布图 http://demo.qunee.com/#2.5D
Room Demo
除此之外, qunee还能用来绘制流程图, 思维导图, 地铁图, 中国地图等等,
其它应用的demo请移步qunne的官网 http://demo.qunee.com/。
我这边的项目要实现的是一个网络逻辑拓扑, 要绘制出各个IDC核心设备上的VRF和防火墙的逻辑连接关系。 之所以要实现逻辑路由是为了能够在交换机的vrf创建网关后, 可以实现自动在与其直连的防火墙上添加路由。 所以第一步就需要展示交换机的vrf和防火墙的关系。
qunee官网上建议的开发流程是: 1. 采集数据 2. 转换数据 3. 数据呈现 4. 交互和操作
我也基本上是参照这个开发流程来做的。
【数据采集】
1。 从核心交换机上抓取所有vrf的接口信息 show ip interface vrf <vrf_name>
2. 抓取防火墙上的接口信息(可以通过设备厂商提供的api或者通过设备配置得到)
3. 遍历从交换机和防火墙上获取的接口信息,如果两个接口在同一vlan下,且ip属于同一网段, 则认为两个接口在逻辑上是连接的
【数据转换】
这个取决于你要绘制出什么样的图形。 不过你可以先生成一个图, 后面在进行修正。不需要一步到位,可以根据最后图形展现的效果做多次迭代修改。
数据格式可以转换成下面的形式:
{
"nodes"
:[{
"name"
:
"A"
,
"x"
: -100,
"y"
: -50,
"id"
: 1}, {
"name"
:
"B"
,
"id"
: 2}],
"edges"
: [{
"name"
:
"Edge"
,
"from"
:1,
"to"
:2}]}
这个格式是一个json的格式, 有两个大的键值, 一个是nodes,存储要创建的节点信息,一个是edges, 存储节点之间的连线信息,即节点之间是怎么连接的。
需要说明的是, nodes中的“x” 和 “y”是指节点的x轴和y轴坐标, 这个信息不一定要有, 你可以指定,也可以不指定。个人推荐不指定x和y坐标值, 后面采用qunee提供的自动布局的方式,更加简单高效,而且可以应对拓扑会不断变化的需求。
另外 nodes中 “id” 不一定是整数,也可以是字符串, 而edges中的from 和 to分别是两个节点的id。
根据这个数据格式,需要编写对应的解析函数,转成对应的qunee元素,代码如下:
function
translateToQuneeElements(json, graph){
var
map = {};
if
(json.nodes){
Q.forEach(json.nodes,
function
(data){
var
node = graph.createNode(data.name, data.x || 0, data.y || 0);
node.set(
"data"
, data);
map[data.id] = node;
// 节点加入图元容器,这个会在数据呈现部分说明
model.add(node);
});
}
if
(json.edges){
Q.forEach(json.edges,
function
(data){
var
from = map[data.from];
var
to = map[data.to];
if
(!from || !to){
return
;
}
var
edge = graph.createEdge(data.name, from, to);
edge.set(
"data"
, data);
}, graph);
}
}
|
【数据呈现】
布局上,我采用了弹簧自动布局方式
// 弹簧布局
var layouter = new Q.SpringLayouter(graph);
layouter.elastic = 1; // 设置弹性系数
layouter.attractive = 0.1; // 设置中心吸引力系数
layouter.repulsion = 60; // 设置斥力系数
layouter.start();
通过调整上面的三个系数,可以得到松散适度的布局图。 更多关于弹簧布局的说明,请移步官网文档: http://doc.qunee.com/pages/viewpage.action?pageId=1147023。
另外我把所有的元素加入了图元容器model中, 加入图元容器可以方便的实现容器内节点的搜索,事件绑定等操作。
关于图元容器的说明, 请移步官网的说明 http://doc.qunee.com/pages/viewpage.action?pageId=1146976
同时我加了个搜索框,可以支持对图元进行搜索,
$("#btn_search").on("click", function(){
var _c = $("input#search").val();
var c = _c.toUpperCase();
var selectionModel = model.selectionModel;
selectionModel.clear();
model.forEachByDepthFirst(function(node){ // 图元的按图的深度优先遍历, 具体说明参考 http://doc.qunee.com/pages/viewpage.action?pageId=1146987
if (node.name.indexOf(c) > -1){
Q.log(node.name);
selectionModel.select(node); // 如果匹配到对应的图元, 则置为选中模式
}
});
});
为了让匹配到图元的时候,能够更加突出,我修改了图元选中模式的样式。
var styles = {};
styles[Q.Styles.SELECTION_COLOR] = 'red';
styles[Q.Styles.SELECTION_BORDER] = 2;
styles[Q.Styles.SELECTION_SHADOW_BLUR] = 12;
graph.styles = styles;
更多的样式说明, 请移步 http://doc.qunee.com/pages/viewpage.action?pageId=1147158
【交互和操作】
这块暂时还没有完善。
后面会支持点击交换机或者防火墙可以跳转到对应的详情页面
还有提供源ip和目的ip,可以在拓扑上显示逻辑路由,实现可视化的traceroute。
------------------<<<<< 未完待续 >>>>>>-----------------------