懒得整理了,先把代码贴上去,后面有时间再梳理下
1 <!DOCTYPE html> 2 <html> 3 4 <head> 5 <title>ForceLayout</title> 6 <meta name="viewport" content="width=device-width, initial-scale=1,maximum-scale=1,user-scalable=no" /> 7 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> 8 <meta name="viewport" content="width=1024, height=768" /> 9 10 <meta charset="UTF-8"> 11 <style> 12 /*在手机浏览器中,长按可选中文本,但如果在应用中,会给人一种异样的感觉,最好还是禁用此功能为上*/ 13 * { 14 -webkit-touch-callout: none; 15 -webkit-user-select: none; 16 -khtml-user-select: none; 17 -moz-user-select: none; 18 -ms-user-select: none; 19 user-select: none; 20 } 21 22 html, 23 body { 24 padding: 0px; 25 margin: 0px; 26 } 27 28 .main { 29 margin: 0px; 30 padding: 0px; 31 position: absolute; 32 top: 0px; 33 bottom: 0px; 34 left: 0px; 35 right: 0px; 36 background: silver; 37 } 38 39 .tableHeader { 40 background: -webkit-linear-gradient(top, #e5e5e5 0%, #e5e5e5 50%, #dadada 50%, #e5e5e5 100%) !important; 41 background: -moz-linear-gradient(top, #e5e5e5 0%, #e5e5e5 50%, #dadada 50%, #e5e5e5 100%) !important; 42 background: -ms-linear-gradient(top, #e5e5e5 0%, #e5e5e5 50%, #dadada 50%, #e5e5e5 100%) !important; 43 background: linear-gradient(top, #e5e5e5 0%, #e5e5e5 50%, #dadada 50%, #e5e5e5 100%) !important; 44 } 45 </style> 46 <script> 47 function doNothing() { 48 window.event.returnValue = false; 49 return false; 50 } 51 </script> 52 <script src="ht.js"></script> 53 <script src="ht-forcelayout.js"></script> 54 <script type="text/javascript" src="ht-flow.js"></script> 55 <script type="text/javascript" src="ht-edgetype.js"></script> 56 <script type="text/javascript" src="ht-autolayout.js"></script> 57 <script src="ht-form.js"></script> 58 <script src="ht-cssanimation.js"></script> 59 <script src="ht-animation.js"></script> 60 <script src="ht-dialog.js"></script> 61 <script src="key.js"></script> 62 <script src="ht-contextmenu.js"></script> 63 <script src="ht-panel.js"></script> 64 <script src="ht-overview.js"></script> 65 66 <script> 67 var NodeArray = []; 68 69 ht.Default.setImage("bus", "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAADuUlEQVR4Xu2XS2hcVRzGf+ec+8hMnaRJbNQkJVRIfZS0ahobRKHu+rIPROtK1AqSLmyrVhBcZKWb1EYXBdGF+NioEVqirlSM4itiKImVoNWpj5a2ah5tJ5nk3vN3LvfOIpQJc1dZmA+++z/nu/P9z8c5ZxZXiQhLCQ38vwMsB1gOoCJ2vTi02ck1fmpFEAEBkIW/UqTTtaqw3OylJ7493P06YAGciMH83D1rG33aGzMABFYIS5TYgtEqImEK3TMKrRRCAgFBODE6dwB4C5ghQaaj95O3j49NyrwVufXIqFyZF/lnRuRiIa7R/JaU+vr+Mdn3Xl4eeTcvj5XqXcdOiRWRpwb/kFXde5pJoAFH1VzT2ZhzuVwExzFcmoWpGVtiGNVojjEp9CIorenf3caRnW0c3dXG2qYV/PJvwN1r6mjd/fQLgFMO4OJlb26p9fj+7CwZX1MMKVEW1Jo0egCeq5megcmCMF2IA41fKHLn6hzZuoYHgZpyAANCa63DlTlLjWcIQ7BWlRjXIArgaoIq9cif8Q1zIYSR38b+/NQcjobN7Q2Zdc8ObAOUAyiNwgLnLs+T812UAqM1WgSlVImQq0mp+y77P8wjAq6JL2vWLUbh2NiaY7Cx5UnguAKaNvaPnn9oU3PpCApopeJ/gQhlGKXQCqxQlR71AHhnTysTBXj5u7/JTxVxtWJXez23NWe4/40xRg51rHQAMAa0Jus7gCCACAugVFmrTrciPDp4FgEcFd8JgA9OT+L7LmgD4DkABT/HrPHwvYD113rU+hpRigUQIQ2EhX5FfDyf/Rkw8BcUsg2U7wAjB1bT+7XgukV+mghAa0SXUwI2BBvEVQAqhVGgiH1X+xEB4+d47aLD9CGoA5xyO6vB91w0IGHI9GAf8+fGAXBvuInaHQdRno/YsPJuKIXSpqJfHBetDZwCASgHWPfKBfZqMNkVaKM4/2YvG1pX0r33GQC++WKIkyeOct3DvUgQIhUCqCiAYxb1GwuHHxDeb5mEffVxgOfsADIUNQZtHMbzP9Kx8yB9fS8B0NPTw+df9rPpq1exYbDYDlThD0Epnjeax8s7MH46DwgQNTAEVijMzOK6HkA0jjR+PvM7NlxsB6rzl9ciedYDa5IK4GzdtuNYV1fXjRtuvwOAkyM/MDw8/OvHHw3uBwIqIKV/AvgNwEtCNCVsA7q3bNl6Zvv2+yRiNI605F1TBab11wMeVwMXuB7oBO5N2JloLhWQyl9lkzpgVcK6FOY0/qXH8qfZkgdYDvAftC1Oc+4ypOMAAAAASUVORK5CYII="); 70 //箭头 71 ht.Default.setImage('toArrow', { 72 width: 100, 73 height: 50, 74 comps: [ 75 { 76 type: 'shape', 77 points: [0, 25, 30, 25], 78 borderWidth: 4, 79 borderColor: 'lightgary' 80 }, 81 { 82 type: 'shape', 83 points: [15, 5, 30, 25, 15, 45, 50, 25, 15, 5], 84 background: 'lightgary', 85 borderWidth: 1, 86 borderColor: 'lightgary' 87 } 88 ] 89 }); 90 91 function init() { 92 var jsonData; 93 94 var url = "test.json"; 95 var request = new XMLHttpRequest(); 96 request.open("get", url); 97 request.send(null); 98 request.onload = function () { 99 if (request.status == 200) { 100 jsonData = JSON.parse(request.responseText); 101 var RightJson = [ 102 { 103 label: "系统部署图", 104 href: "http://www.baidu.com", 105 linkTarget: "_blank" 106 }, 107 { 108 label: "业务架构图", 109 action: function (item, event) { 110 console.log(item); 111 dialog.setConfig({ 112 title: item.nodeName, 113 titleIcon: 'bus', 114 content: "<h2>"+item.nodeName+"</h2>", 115 width: 250, 116 height: 250, 117 draggable: true, 118 dragModel: 'inside', 119 minDragSize: 50, 120 closable: true, 121 maximizable: true, 122 resizeMode: "wh", 123 buttons: [{ 124 label: "关闭", 125 action: function (button, e) { 126 dialog.hide(); 127 } 128 }], 129 buttonsAlign: "right", 130 action: function (item, e) { 131 console.log(item, e); 132 } 133 }); 134 dialog.show(); 135 } 136 } 137 ]; 138 // 创建数据模型容器 139 var dataModel = new ht.DataModel(); 140 // 创建拓扑图组件 141 var dialog = window.dialog = new ht.widget.Dialog(); 142 var graphView = new ht.graph.GraphView(dataModel); 143 view = graphView.getView(); 144 var panelGroup = new ht.widget.PanelGroup({ 145 hGap: 10, 146 vGap: 10 147 }); 148 var overview = new ht.graph.Overview(graphView); 149 // graphView.fitContent(true); 150 dm = graphView.dm(); 151 view.className = 'main'; 152 var contextmenu = new ht.widget.ContextMenu(); 153 contextmenu.enableGlobalKey(); 154 var clickValue; 155 graphView.addInteractorListener(function (e) { 156 if (e.kind != "clickData") { 157 return; 158 } 159 else if (e.event.button != "2") { 160 return; 161 } 162 else { 163 clickValue = e.data._tag; 164 } 165 }); 166 contextmenu.beforeShow = function (e) { 167 var data = graphView.getDataAt(e); 168 if (data === NodeArray[clickValue]) { 169 if (clickValue == null) { 170 return; 171 } 172 RightJson[1].nodeId = NodeArray[clickValue]._tag; 173 RightJson[1].nodeName = NodeArray[clickValue]._name; 174 this.setItems(RightJson); 175 } else { 176 this.setItems(null); 177 } 178 }; 179 contextmenu.addTo(view); 180 181 document.body.appendChild(view); 182 var searchPanel = new ht.widget.Panel({ 183 title: "检索", 184 width: 300, 185 narrowWhenCollapse: true, 186 contentHeight: 150, 187 expanded: true, 188 content: document.getElementById('test') 189 }); 190 searchPanel.setPositionRelativeTo("rightTop"); 191 searchPanel.setPosition(0, 0); 192 document.body.appendChild(searchPanel.getView()); 193 panelGroup.setRightTopPanels(searchPanel); 194 195 var overviewPanel = new ht.widget.Panel({ 196 title: "鹰眼", 197 restoreToolTip: "Overview", 198 titleIcon: "bus", 199 width: 300, 200 contentHeight: 200, 201 narrowWhenCollapse: true, 202 content: overview, 203 expanded: false 204 }); 205 overviewPanel.setPositionRelativeTo("rightBottom"); 206 overviewPanel.setPosition(0, 0); 207 document.body.appendChild(overviewPanel.getView()); 208 panelGroup.add(overviewPanel); 209 210 window.addEventListener('resize', function (e) { 211 graphView.invalidate(); 212 }, false); 213 214 var jsGroup = jsonData.Data.Group; 215 for (let index = 0; index < jsGroup.length; index++) { 216 var obj = jsGroup[index]; 217 CreateGroup(obj.ID, obj.Name, obj.Node, dataModel); 218 } 219 jsonData.Data.Edge.forEach(element => { 220 CreateEdge(element.SourceId, element.TargetId, dataModel); 221 }); 222 } 223 } 224 } 225 226 227 228 229 function CreateEdge(sourceId, targetId, dataModel) { 230 var edge = new ht.Edge(); 231 edge.setLayer('edgeLayer'); 232 edge.addStyleIcon("toArrow", { 233 position: 19, 234 keepOrien: true, 235 width: 30, 236 height: 15, 237 names: ['toArrow'] 238 }); 239 edge.s({ 240 'edge.type': 'ortho', 241 'edge.color': 'green', 242 'edge.width': 2, 243 }); 244 edge.setSource(NodeArray[sourceId]); 245 edge.setTarget(NodeArray[targetId]); 246 dataModel.add(edge); 247 } 248 249 function CreateGroup(id, name, node, dataModel) { 250 var group; 251 for (let index = 0; index < node.length; index++) { 252 const elementNode = node[index]; 253 if (index == 0) { 254 group = new ht.Group(); 255 group.setTag(id); 256 group.setName(name); 257 group.setExpanded(true); 258 dataModel.add(group); 259 } 260 CreateNode(elementNode, group, dataModel); 261 } 262 } 263 264 function CreateNode(elementNode, group, dataModel) { 265 var node = new ht.Node(); 266 node.setTag(elementNode.ID) 267 node.setName(elementNode.Name); 268 node.setImage(elementNode.ImgUrl); 269 node.setSize(elementNode.ImgWidth, elementNode.ImgHeight); 270 node.setPosition(elementNode.PositionX, elementNode.PositionY); 271 node.setParent(group); 272 node.setStyle('border.color', 'transparent'); 273 dataModel.add(node); 274 NodeArray[elementNode.ID] = node; 275 } 276 277 278 </script> 279 280 </head> 281 282 <body onload="init();" oncontextmenu="doNothing()"> 283 <div style="width: 100%;height:100%;" id="test"> 284 <label>检索条件<input id="search" type="text" placeholder="请输入检索条件"> <button id="btn_sure">确定</button></label> 285 </div> 286 <script> 287 document.getElementById('btn_sure').onclick = function () { 288 NodeArray.forEach(element => { 289 if (element._name.toLowerCase().indexOf(document.getElementById('search').value.toString().toLowerCase()) > -1) { 290 element.setStyle('border.color', 'green'); 291 } else { 292 element.setStyle('border.color', 'transparent'); 293 } 294 }); 295 if (document.getElementById('search').value.length == 0) { 296 NodeArray.forEach(element => { 297 element.setStyle('border.color', 'transparent'); 298 }) 299 } 300 } 301 </script> 302 </body> 303 304 </html>
JSON文件如下:
1 { 2 "Data": { 3 "Group": [{ 4 "ID": 1, 5 "Name": "系统分组1", 6 "Node": [{ 7 "ID":11, 8 "Name": "Group1_Node1", 9 "GroupId": 1, 10 "ImgWidth": 20, 11 "ImgHight": 20, 12 "ImgUrl": "bus", 13 "PositionX": 10, 14 "PositionY": 0 15 }, { 16 "ID": 12, 17 "Name": "Group1_Node2", 18 "GroupId": 1, 19 "ImgWidth": 20, 20 "ImgHight": 20, 21 "ImgUrl": "bus", 22 "PositionX": 100, 23 "PositionY": 0 24 },{ 25 "ID": 13, 26 "Name": "Group1_Node3", 27 "GroupId": 1, 28 "ImgWidth": 20, 29 "ImgHight": 20, 30 "ImgUrl": "bus", 31 "PositionX": 200, 32 "PositionY": 0 33 }] 34 }, { 35 "ID": 2, 36 "Name": "系统分组2", 37 "Node": [{ 38 "ID": 21, 39 "Name": "Group2_Node4", 40 "GroupId": 2, 41 "ImgWidth": 20, 42 "ImgHight": 20, 43 "ImgUrl": "bus", 44 "PositionX": 10, 45 "PositionY": 100 46 }, { 47 "ID": 22, 48 "Name": "Group2_Node5", 49 "GroupId": 2, 50 "ImgWidth": 20, 51 "ImgHight": 20, 52 "ImgUrl": "bus", 53 "PositionX": 100, 54 "PositionY": 100 55 }] 56 }, { 57 "ID": 3, 58 "Name": "系统分组3", 59 "Node": [{ 60 "ID":31, 61 "Name": "Group3_Node6", 62 "GroupId": 3, 63 "ImgWidth": 20, 64 "ImgHight": 20, 65 "ImgUrl": "bus", 66 "PositionX": 10, 67 "PositionY":200 68 }] 69 }], 70 "Edge": [{ 71 "SourceId": 13, 72 "TargetId": 12 73 }, { 74 "SourceId": 21, 75 "TargetId": 22 76 }, { 77 "SourceId": 11, 78 "TargetId": 21 79 }] 80 } 81 }