Authored by qinchao

主机拓扑

@@ -56,40 +56,61 @@ public class HostInfoCtrl { @@ -56,40 +56,61 @@ public class HostInfoCtrl {
56 //初始化数据 56 //初始化数据
57 Map<String,List<HostGroup>> initDataMap = tmpConstructData(); 57 Map<String,List<HostGroup>> initDataMap = tmpConstructData();
58 58
59 - getJsonAntvData(initDataMap,true, mv); 59 + getJsonAntvData(initDataMap,6, mv);
60 60
61 return mv; 61 return mv;
62 } 62 }
63 63
64 - private void getJsonAntvData(Map<String,List<HostGroup>> initDataMap,boolean setXyFlag,ModelAndView mv){ 64 + //numInRow 第二层的节点一排放几个
  65 + private void getJsonAntvData(Map<String,List<HostGroup>> initDataMap,int numInRow,ModelAndView mv){
65 int beginx=60; 66 int beginx=60;
66 int beginy=60; 67 int beginy=60;
67 - int gap_h=100;  
68 - int gap_x=300;  
69 - int intval=140; 68 +
  69 + int gap_level_top_h=100;
  70 + int gap_h=50;
  71 +
70 List<AntvNode> nodes=new ArrayList<>(); 72 List<AntvNode> nodes=new ArrayList<>();
71 List<Map<String,String>> edges=new ArrayList<>(); 73 List<Map<String,String>> edges=new ArrayList<>();
72 74
73 - int count=0;  
74 int maxSize=0; 75 int maxSize=0;
  76 + int last_y=0;
75 for (Map.Entry<String, List<HostGroup>> entry : initDataMap.entrySet()) { 77 for (Map.Entry<String, List<HostGroup>> entry : initDataMap.entrySet()) {
76 String topNode = entry.getKey(); 78 String topNode = entry.getKey();
77 - AntvNode node=new AntvNode();  
78 - node.setLevel(0);  
79 - node.setId(topNode);  
80 - node.setLabel(topNode);  
81 - node.setShape("rect");  
82 - if(setXyFlag){  
83 - node.setX(beginx+(count*gap_x));  
84 - node.setY(beginy); 79 + AntvNode nodeLevelTop=new AntvNode();
  80 + nodeLevelTop.setLevel(0);
  81 + nodeLevelTop.setId(topNode);
  82 + nodeLevelTop.setLabel(topNode);
  83 + nodeLevelTop.setShape("rect");
  84 +
  85 + int top_node_x=beginx;
  86 + int top_node_y;
  87 + if(maxSize==0){
  88 + top_node_y=beginy;
  89 + }else{
  90 + top_node_y=last_y+gap_level_top_h;
85 } 91 }
86 92
87 - nodes.add(node);  
88 - int secondCount=1; 93 + nodeLevelTop.setX(top_node_x);
  94 + nodeLevelTop.setY(top_node_y);
  95 + nodes.add(nodeLevelTop);
  96 + last_y= nodeLevelTop.getY();
  97 +
  98 + maxSize++;
  99 +
89 List<HostGroup> ls=entry.getValue(); 100 List<HostGroup> ls=entry.getValue();
90 - if(ls.size()>maxSize){  
91 - maxSize = ls.size(); 101 + if(ls==null||ls.size()<=0){
  102 + nodeLevelTop.setLevel(1);
  103 +
  104 + continue;
  105 + }else{
  106 + double d=ls.size()*1.0/numInRow;
  107 + maxSize +=(int)Math.ceil(d);
92 } 108 }
  109 +
  110 +
  111 + int secondCount=1;
  112 + int row=1;
  113 + int GAP_BETWEEN_NODE_X=120;
93 for(HostGroup secondeNode:ls){ 114 for(HostGroup secondeNode:ls){
94 String sndNodeID=""+secondeNode.getId(); 115 String sndNodeID=""+secondeNode.getId();
95 AntvNode nodeSnd=new AntvNode(); 116 AntvNode nodeSnd=new AntvNode();
@@ -97,22 +118,29 @@ public class HostInfoCtrl { @@ -97,22 +118,29 @@ public class HostInfoCtrl {
97 nodeSnd.setId(sndNodeID); 118 nodeSnd.setId(sndNodeID);
98 nodeSnd.setLabel(secondeNode.getGroupName()); 119 nodeSnd.setLabel(secondeNode.getGroupName());
99 nodeSnd.setShape("rect"); 120 nodeSnd.setShape("rect");
100 - if(setXyFlag){  
101 - nodeSnd.setX(beginx+(count*gap_x)+intval);  
102 - nodeSnd.setY(beginy+secondCount*gap_h);  
103 - }  
104 - 121 + nodeSnd.setX(top_node_x+row*GAP_BETWEEN_NODE_X);
  122 + nodeSnd.setY(top_node_y+secondCount*gap_h);
105 nodes.add(nodeSnd); 123 nodes.add(nodeSnd);
  124 + last_y=nodeSnd.getY();
106 125
107 - secondCount++;  
108 //连线 126 //连线
  127 + //第二行,不再加连接线
  128 + if(secondCount==1){
109 Map<String,String> edgeMap=new HashMap<>(); 129 Map<String,String> edgeMap=new HashMap<>();
110 edgeMap.put("source",topNode); 130 edgeMap.put("source",topNode);
111 edgeMap.put("target",sndNodeID); 131 edgeMap.put("target",sndNodeID);
112 edges.add(edgeMap); 132 edges.add(edgeMap);
  133 + }
  134 +
  135 +
  136 + if(row<numInRow){
  137 + row++;
  138 + }else{
  139 + row = 1;
  140 + secondCount++;
  141 + }
113 142
114 } 143 }
115 - count++;  
116 } 144 }
117 145
118 AntvData data=new AntvData(); 146 AntvData data=new AntvData();
@@ -122,7 +150,7 @@ public class HostInfoCtrl { @@ -122,7 +150,7 @@ public class HostInfoCtrl {
122 String jsonString=gson.toJson( data,AntvData.class); 150 String jsonString=gson.toJson( data,AntvData.class);
123 151
124 mv.addObject("antvData",jsonString); 152 mv.addObject("antvData",jsonString);
125 - mv.addObject("antvHeight",100*(maxSize+1)); 153 + mv.addObject("antvHeight",last_y+100);
126 } 154 }
127 155
128 @RequestMapping("/toHostTopoSub") 156 @RequestMapping("/toHostTopoSub")
@@ -132,11 +160,9 @@ public class HostInfoCtrl { @@ -132,11 +160,9 @@ public class HostInfoCtrl {
132 160
133 //获取子节点(有可能不存在),比如前台-gateway ,有可能存在,前台-service 161 //获取子节点(有可能不存在),比如前台-gateway ,有可能存在,前台-service
134 String parentLabel="前台"; 162 String parentLabel="前台";
135 - int number=(int)(Math.random()*10);//[0,10]  
136 boolean subNodeFlag=false; 163 boolean subNodeFlag=false;
137 String currentLabel="gateway"; 164 String currentLabel="gateway";
138 - number=2;  
139 - if(number%2==0){ 165 + if(id!=null&&!id.endsWith("1")){
140 subNodeFlag=true; 166 subNodeFlag=true;
141 currentLabel="service"; 167 currentLabel="service";
142 } 168 }
@@ -144,7 +170,7 @@ public class HostInfoCtrl { @@ -144,7 +170,7 @@ public class HostInfoCtrl {
144 Map<String,List<HostGroup>> initDataMap =new LinkedHashMap<>(); 170 Map<String,List<HostGroup>> initDataMap =new LinkedHashMap<>();
145 initDataMap.put(currentLabel,tmpDetailData(subNodeFlag)); 171 initDataMap.put(currentLabel,tmpDetailData(subNodeFlag));
146 172
147 - getJsonAntvData(initDataMap,false, mv); 173 + getJsonAntvData(initDataMap,3, mv);
148 174
149 mv.addObject("parentLabel",parentLabel); 175 mv.addObject("parentLabel",parentLabel);
150 return mv; 176 return mv;
@@ -10,4 +10,5 @@ public class AntvNode { @@ -10,4 +10,5 @@ public class AntvNode {
10 private String label; 10 private String label;
11 private String id; 11 private String id;
12 private int level; 12 private int level;
  13 + private int[] size={100,30};
13 } 14 }
@@ -30,12 +30,35 @@ @@ -30,12 +30,35 @@
30 class="icon-home"></i> Home</a> <a href="#" class="current">主机拓扑图</a> 30 class="icon-home"></i> Home</a> <a href="#" class="current">主机拓扑图</a>
31 </div> 31 </div>
32 <div class="container-fluid"> 32 <div class="container-fluid">
33 - <div class="widget-box">  
34 - <div class="widget-title">  
35 - <h5>主机管理-主机拓扑图:${parentLabel}</h5> 33 +
  34 + <div class="widget-box" style="min-height: 600px;">
  35 + <div id="hostListTopoDiv" style="width:600px;float:left">
  36 +
  37 + </div>
  38 + <div class="widget-content nopadding" style="margin-left: 600px;border-left: 1px solid #E5E5E5;">
  39 + <div class="panel-body">
  40 +
  41 + <div>
  42 + <div class="form-inline" role="form"
  43 + style="float: left;">
  44 + <div class="input-group" style="float: left;">
  45 + <span class="input-group-addon">云可用区:</span>
  46 + <select id="cloudDetailType" name="cloudDetailType" class="form-control">
  47 + <option value="0">全部</option>
  48 + <%--<option value="1">AWS</option>--%>
  49 + <option value="21">腾讯云</option>
  50 + <option value="22">腾讯云az2</option>
  51 + <option value="23">腾讯云az3</option>
  52 + <%--<option value="3">其他</option>--%>
  53 + </select>
  54 + </div>
  55 + <button class="btn btn-primary" style="margin-left: 18px;" onclick="queryHost()">搜索</button>
36 </div> 56 </div>
37 - <div class="widget-content nopadding">  
38 - <div class="panel-body" id="hostListTopoDiv"> 57 + <div id="hostInfoTable" style="margin-top:2px;float: left;min-height: 500px;">
  58 +
  59 + </div>
  60 + </div>
  61 +
39 </div> 62 </div>
40 </div> 63 </div>
41 </div> 64 </div>
@@ -50,7 +73,6 @@ @@ -50,7 +73,6 @@
50 <script type="text/javascript"> 73 <script type="text/javascript">
51 // 第一步:获取数据 74 // 第一步:获取数据
52 var data=${antvData}; 75 var data=${antvData};
53 - console.log(data);  
54 // 第二步:注册图形 76 // 第二步:注册图形
55 G6.registNode('rect', { 77 G6.registNode('rect', {
56 // 设置锚点 78 // 设置锚点
@@ -62,12 +84,15 @@ @@ -62,12 +84,15 @@
62 } 84 }
63 }); 85 });
64 var nodes = data.nodes; 86 var nodes = data.nodes;
65 - var edges = data.edges; 87 + /* for(var i=0;i<nodes.length;i++){
  88 + nodes[i].size=[100,30];
  89 + }*/
  90 + var edges = [];//data.edges;
66 91
67 // 第三步:进行布局 92 // 第三步:进行布局
68 - var Layout = G6.Layout; 93 + /*var Layout = G6.Layout;
69 var margin = 60; 94 var margin = 60;
70 - var height = 800 - 2 * margin; 95 + var height = 1000 - 2 * margin;
71 var width = 500 - 2 * margin; 96 var width = 500 - 2 * margin;
72 97
73 var layout = new Layout.Flow({ 98 var layout = new Layout.Flow({
@@ -83,13 +108,12 @@ @@ -83,13 +108,12 @@
83 node.y = x; 108 node.y = x;
84 }); 109 });
85 110
86 - console.log(nodes); 111 + console.log(nodes);*/
87 // 第四步:初始化图 112 // 第四步:初始化图
88 var net = new G6.Net({ 113 var net = new G6.Net({
89 - fitView: 'autoZoom' ,// 自动缩放 114 + // fitView: 'autoZoom' // 自动缩放
  115 + height: ${antvHeight}, // 此处替换高度
90 behaviourFilter: ['wheelZoom', 'dragNode','dragBlank', 'dragCanvas'], 116 behaviourFilter: ['wheelZoom', 'dragNode','dragBlank', 'dragCanvas'],
91 - //height: ${antvHeight}, // 此处替换高度  
92 - // width:1000,  
93 id: "hostListTopoDiv" // 此处替换容器id 117 id: "hostListTopoDiv" // 此处替换容器id
94 }); 118 });
95 // 第五步:载入数据 119 // 第五步:载入数据
@@ -119,4 +143,117 @@ @@ -119,4 +143,117 @@
119 // 第八步:渲染关系图 143 // 第八步:渲染关系图
120 net.render(); 144 net.render();
121 145
  146 + //dblclick
  147 + var checkStyle = {
  148 + fill:"#FF0000",
  149 + lineWidth: 2
  150 + };
  151 + var normalStyle = {
  152 + fill:"#00A263",
  153 + lineWidth: 1
  154 + };
  155 +
  156 + var page_selected_node=[];
  157 + net.on('click', function(ev){
  158 + if(ev.itemType !== 'node'){
  159 + return;
  160 + }
  161 + var model=ev.item.getModel();
  162 + if(model.level==0){
  163 + return ;
  164 + }
  165 +
  166 + var changeStyle={};
  167 + if(model.checked){
  168 + model.checked=false;
  169 + changeStyle =normalStyle;
  170 +
  171 + for(var arri=0;arri<page_selected_node.length;arri++){
  172 + if(page_selected_node[arri].id==model.id){
  173 + page_selected_node.splice(arri,1);
  174 + break;
  175 + }
  176 + }
  177 + }else{
  178 + model.checked=true;
  179 + changeStyle = checkStyle;
  180 + page_selected_node.push(model);
  181 + }
  182 +
  183 + var keyShape = ev.item.getKeyShape();
  184 + keyShape.attr(changeStyle);
  185 + net.refresh();
  186 + });
  187 +
  188 + $(function () {
  189 + //加载表格
  190 + $("#hostInfoTable").table({
  191 + columnAutoWidth : false,
  192 + striped : true,
  193 + title : "主机信息列表",
  194 + dataType : "json",
  195 + pagination : true,
  196 + pageSize : 10,
  197 + loadFilter : function(data) {
  198 + return defaultLoadFilter(data);
  199 + },
  200 + columns : [
  201 + {
  202 + title: 'NO',
  203 + width : "40px",
  204 + formatter: function (value, row, index) {
  205 + return index+1;
  206 + }
  207 + },
  208 + {
  209 + title : "IP",
  210 + field : "hostIp",
  211 + width : "30%"
  212 + }, {
  213 + title : "云可用区",
  214 + field : "cloudDetailType",
  215 + formatter : function(value, rowData, rowIndex) {
  216 + if(value == 1){
  217 + return 'AWS';
  218 + } else if(value == 21){
  219 + return '腾讯云';
  220 + }else if(value == 22){
  221 + return '腾讯云az2';
  222 + }else if(value == 23){
  223 + return '腾讯云az3';
  224 + }else{
  225 + return value;
  226 + }
  227 + },
  228 + width : "20%"
  229 + }, {
  230 + title : "标签",
  231 + field : "tags",
  232 + formatter : function(value, rowData, rowIndex) {
  233 + if(value != null && value != ""){
  234 + return value.substr(0,value.length-1);
  235 + }
  236 +
  237 + }
  238 + }]
  239 + });
  240 + });
  241 +
  242 +
  243 +
  244 + function queryHost() {
  245 + console.log(page_selected_node);
  246 +
  247 + var opt = $("#hostInfoTable").data("table");
  248 + opt.url=contextPath +"hostInfoList/getHostInfos";
  249 +
  250 + var cloudDetailType = $("#cloudDetailType").val();
  251 + var param={
  252 + 'cloudDetailType': cloudDetailType,
  253 + tags:'["upstream-switch"]'
  254 + };
  255 +
  256 + $("#hostInfoTable").table("load",param);
  257 +
  258 + }
122 </script> 259 </script>
@@ -50,18 +50,20 @@ @@ -50,18 +50,20 @@
50 <script type="text/javascript"> 50 <script type="text/javascript">
51 // 第一步:获取数据 51 // 第一步:获取数据
52 var data=${antvData}; 52 var data=${antvData};
53 - console.log(data);  
54 // 第二步:注册图形 53 // 第二步:注册图形
55 G6.registNode('rect', { 54 G6.registNode('rect', {
56 // 设置锚点 55 // 设置锚点
57 getAnchorPoints: function(){ 56 getAnchorPoints: function(){
58 return [ 57 return [
59 - [0.5, 1], // 右边边的中点  
60 - [0, 0.5] // 左边边的中点 58 + [1, 0.1], // 右边边的中点
  59 + [0.5, 0] // 左边边的中点
61 ]; 60 ];
62 } 61 }
63 }); 62 });
64 var nodes = data.nodes; 63 var nodes = data.nodes;
  64 + /*for(var i=0;i<nodes.length;i++){
  65 + nodes[i].size=[100,30];
  66 + }*/
65 var edges = data.edges; 67 var edges = data.edges;
66 68
67 // 第三步:进行布局 69 // 第三步:进行布局
@@ -88,14 +90,14 @@ @@ -88,14 +90,14 @@
88 90
89 91
90 console.log(node.x,node.y); 92 console.log(node.x,node.y);
91 - });*/ 93 + });
92 94
93 - console.log(nodes); 95 + console.log(nodes);*/
94 // 第四步:初始化图 96 // 第四步:初始化图
95 var net = new G6.Net({ 97 var net = new G6.Net({
96 - // fitView: 'autoZoom' // 自动缩放  
97 - behaviourFilter: ['wheelZoom', 'dragNode','dragBlank', 'dragCanvas'], 98 + fitView: 'autoZoom' ,// 自动缩放
98 height: ${antvHeight}, // 此处替换高度 99 height: ${antvHeight}, // 此处替换高度
  100 + behaviourFilter: ['wheelZoom', 'dragNode','dragBlank', 'dragCanvas'],
99 // width:1000, 101 // width:1000,
100 id: "hostListTopoDiv" // 此处替换容器id 102 id: "hostListTopoDiv" // 此处替换容器id
101 }); 103 });
@@ -115,10 +117,12 @@ @@ -115,10 +117,12 @@
115 return attrs; 117 return attrs;
116 }); 118 });
117 net.edge() 119 net.edge()
118 - .shape('VH') 120 + .shape('HV')
119 .style({ 121 .style({
120 - stroke: "#00A263", 122 + stroke: "#CCC",
121 strokeOpacity: 0.6, 123 strokeOpacity: 0.6,
  124 + //lineWidth:1,
  125 + // lineDash:[5,5],
122 arrow: true 126 arrow: true
123 }); 127 });
124 // 第七步:添加图例 128 // 第七步:添加图例