基於Web實如今線繪畫拓撲圖[GraphEditor]

網絡拓撲圖原本已經整理有一段時間了,一次項目會議寫集中邊界監控系統的時候上級要求使用能夠在系統中畫網絡拓撲圖,沒辦法當時找不到現有的程序來參考 只能硬着頭皮,頂着風險來完成[固然來邊界安全的,固然要安全型高啊],一同事找到一些源碼來分析,固然了有源碼分析比本身想的效率要快得多 可是也很讓人頭痛,怎樣才能實現,怎樣才能嵌入到Web項目中? 這個集控那個項目已近完成有一段時間了,最近呢一些網友要借鑑我修改後的代碼,和一些效果我最近整理了一份可是當時因爲比較忙,沒有發到博客中 去!只是寫了一個簡單的Demo供參考和利用,因爲最近又有一些朋友也來問這個問題,爲了方便與資源共享,我仍是整理了這邊文章,和網絡拓撲的運用,固然 技術確定還有更加優化好的控件,有的話但願共同窗習! 下面是我編寫的一個簡單的Demojavascript

這是簡單畫的一個拓撲圖:css

 

這是簡單的繪畫界面,Tab切換後是快捷鍵保存的後的模板[相似圖表,也能夠編輯],在這裏就先不演示了html

固然若是須要,請加入羣直接下載分享文件[完整的Demo]java

下面來詳解下文件的配置,和代碼分析jquery

首先來看下web.xmlweb

 
 1 <?xml version="1.0" encoding="UTF-8"?>  2 <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5">  3 <display-name></display-name>  4 <servlet>  5 <description>This is the description of my J2EE component</description>  6 <display-name>This is the display name of my J2EE component</display-name>  7 <servlet-name>SaveToXmlServlet</servlet-name>  8 <servlet-class>grapheditor.SaveToXmlServlet</servlet-class>  9 </servlet> 10 <servlet-mapping> 11 <servlet-name>SaveToXmlServlet</servlet-name> 12 <url-pattern>/SaveToXmlServlet</url-pattern> 13 </servlet-mapping> 14 <welcome-file-list> 15 <welcome-file>graph.jsp</welcome-file> 16 </welcome-file-list> 17 </web-app>
 

配置很少,相信熟練Web的開發的這個就不用解釋了,一看便能理解其中的配置,這裏就不詳細介紹了數據庫

接着咱們來編寫JSP頁面,這裏爲了方便看和傳輸數據,我JS接直接放到一塊兒了windows

 
 1 <%@ page language="java" %>  2 <%@ page contentType="text/html; charset=utf-8"%>  3 <%String path =request.getContextPath();%>  4 <head>  5 <head>  6 <title>Graph Editor</title>  7 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">  8 <script type="text/javascript" src="../../../../js/default/jquery-1.6.2.js"></script>  9 <script type="text/javascript" src="../../../../js/default/jquery-ui-1.8.16.custom.min.js"></script>  10 <link rel="stylesheet" type="text/css" href="styles/grapheditor.css">  11 <script type="text/javascript">  12 //全局變量  13 var MAX_REQUEST_SIZE = 10485760;  14 var MAX_WIDTH = 6000;  15 var MAX_HEIGHT = 6000;  16  17 //保存地址或導入地址  18 var EXPORT_URL = '/visecMc/ExportServlet';  19 var SAVE_URL = '/visecMc/SaveMapServlet';  20 var OPEN_URL = '/open';  21 var RESOURCES_PATH = 'resources';  22 var RESOURCE_BASE = RESOURCES_PATH + '/grapheditor';  23 var STENCIL_PATH = 'stencils';  24 var IMAGE_PATH = 'images';  25 var STYLE_PATH = 'styles';  26 var CSS_PATH = 'styles';  27 var OPEN_FORM = 'open.html';  28  29 //指定鏈接模式爲觸摸設備(至少有一個應該是正確的)  30 var tapAndHoldStartsConnection = true;  31 var showConnectorImg = true;  32  33 // 解析URL參數。支持參數:  34 // - lang = xy:指定用戶界面的語言。  35 // - 觸摸= 1:使touch-style用戶界面。  36 // - 存儲=當地:支持HTML5本地存儲。  37 var urlParams = (function(url)  38  {  39 var result = new Object();  40 var idx = url.lastIndexOf('?');  41  42 if (idx > 0)  43  {  44 var params = url.substring(idx + 1).split('&');  45  46 for (var i = 0; i < params.length; i++)  47  {  48 idx = params[i].indexOf('=');  49  50 if (idx > 0)  51  {  52 result[params[i].substring(0, idx)] = params[i].substring(idx + 1);  53  }  54  }  55  }  56  57 return result;  58  })(window.location.href);  59  60 // 設置用戶界面語言的基本路徑,經過URL參數和配置  61 // 支持的語言,以免404年代。裝運的全部核心語言  62 // 資源是禁用grapheditor所需的全部資源。  63 // 屬性。注意,在這個例子中兩個資源的加載  64 // 文件(特殊包,默認包)是禁用的  65 // 保存一個GET請求。這就要求全部資源存在  66 // 每一個屬性文件,由於只有一個文件被加載。  67 mxLoadResources = false;  68 mxBasePath = '../../../src';  69 mxLanguage = urlParams['lang'];  70 mxLanguages = ['de'];  71 </script>  72 <script type="text/javascript" src="js/mxClient.js"></script>  73 <script type="text/javascript" src="js/Editor.js"></script>  74 <script type="text/javascript" src="js/Graph.js"></script>  75 <script type="text/javascript" src="js/Shapes.js"></script>  76 <script type="text/javascript" src="js/EditorUi.js"></script>  77 <script type="text/javascript" src="js/Actions.js"></script>  78 <script type="text/javascript" src="js/Menus.js"></script>  79 <script type="text/javascript" src="js/Sidebar.js"></script>  80 <script type="text/javascript" src="js/Toolbar.js"></script>  81 <script type="text/javascript" src="js/Dialogs.js"></script>  82 <script type="text/javascript" src="jscolor/jscolor.js"></script>  83 </head>  84 <body class="geEditor">  85 <input type="hidden" id="mapTp" value="qsy"/>  86 <input type="hidden" id="path" value="<%=path %>"/>  87 <script type="text/javascript">  88 // EditorUi更新擴展I / O操做狀態  89  (function()  90  {  91 var editorUiInit = EditorUi.prototype.init;  92  93 EditorUi.prototype.init = function()  94  {  95 editorUiInit.apply(this, arguments);  96 //this.actions.get('export').setEnabled(false);  97 //須要一個後端更新動做狀態  98 if (!useLocalStorage)  99  { 100 mxUtils.post(OPEN_URL, '', mxUtils.bind(this, function(req) 101  { 102 var enabled = req.getStatus() != 404; 103 this.actions.get('open').setEnabled(enabled || fileSupport); 104 this.actions.get('import').setEnabled(enabled || fileSupport); 105 this.actions.get('save').setEnabled(true); 106  })); 107  } 108  }; 109  })(); 110 111 new EditorUi(new Editor()); 112 </script> 113 </body>
 

上訴文件呢,主要負責拓撲圖的繪畫與相關操做界面的代碼後端

因爲相關的文件過多,我這裏之舉出比較重要的幾個問文件安全

Actions.js主要獲取座標並進行處理的JS文件

 
 1 function Actions(editorUi)  2 {  3 this.editorUi = editorUi;  4 this.actions = new Object();  5 this.init();  6 };  7  8 /**  9  * 添加默認的行爲  10 */  11 Actions.prototype.init = function()  12 {  13 var ui = this.editorUi;  14 var editor = ui.editor;  15 var graph = editor.graph;  16 graph.cellsMovable=!0;//設置不可移動  17 graph.cellsDisconnectable=!0;//設置邊不可編輯  18 graph.cellsResizable=!0;//設置不可改變大小  19 $.post($("#path").val()+"/SaveToXmlServlet",{"tp":$("#mapTp").val(),"type":"get"},function(text){  20 if(text=="0"){  21 alert("文件加載失敗!");  22 }else{  23 var xml = text;  24 var doc = mxUtils.parseXml(xml);  25 var model = new mxGraphModel();  26 var codec = new mxCodec(doc);  27  codec.decode(doc.documentElement, model);  28 var children = model.getChildren(model.getChildAt(model.getRoot(), 0));  29  graph.setSelectionCells(editor.graph.importCells(children));  30  }  31  });  32  33 // 文件操做  34 this.addAction('new', function() { window.open(ui.getUrl()); });  35 this.addAction('open', function()  36  {  37 window.openNew = true;  38 window.openKey = 'open';  39  40  ui.openFile();  41  });  42 this.addAction('import', function()  43  {  44 window.openNew = false;  45 window.openKey = 'import';  46  47 // 後關閉對話框打開  48 window.openFile = new OpenFile(mxUtils.bind(this, function()  49  {  50  ui.hideDialog();  51  }));  52  53 window.openFile.setConsumer(mxUtils.bind(this, function(xml, filename)  54  {  55 try  56  {  57 var doc = mxUtils.parseXml(xml);  58 var model = new mxGraphModel();  59 var codec = new mxCodec(doc);  60  codec.decode(doc.documentElement, model);  61  62 var children = model.getChildren(model.getChildAt(model.getRoot(), 0));  63  editor.graph.setSelectionCells(editor.graph.importCells(children));  64  }  65 catch (e)  66  {  67 mxUtils.alert(mxResources.get('invalidOrMissingFile') + ': ' + e.message);  68  }  69  }));  70  71 // 刪除openFile是否關閉對話框  72 ui.showDialog(new OpenDialog(this).container, 300, 180, true, true, function()  73  {  74 window.openFile = null;  75  });  76  });  77 this.addAction('save', function() { ui.save(); }, null, null, 'Ctrl+S');  78 //addAction(saveAs,函數(){ ui.saveFile(真正);},空,空,「Ctrl + Shift-S」);  79 //addAction(「出口」,函數(){ ui。showDialog(新ExportDialog(ui)。容器、300、200,真的,真的);},空,空,「Ctrl + E」);  80 //(「editFile」,新的行動(mxResources.get(「編輯」),mxUtils。綁定(此功能()  81 //(「editFile」,新的行動(mxResources.get(「編輯」),mxUtils。綁定(此功能()  82 this.addAction('pageSetup', function() { ui.showDialog(new PageSetupDialog(ui).container, 300, 200, true, true); });  83 this.addAction('print', function() { ui.showDialog(new PrintDialog(ui).container, 300, 200, true, true); }, null, 'sprite-print', 'Ctrl+P');  84 this.addAction('preview', function() { mxUtils.show(graph, null, 10, 10); });  85  86 // Edit actions  87 this.addAction('undo', function() { editor.undoManager.undo(); }, null, 'sprite-undo', 'Ctrl+Z');  88 this.addAction('redo', function() { editor.undoManager.redo(); }, null, 'sprite-redo', 'Ctrl+Y');  89 this.addAction('cut', function() { mxClipboard.cut(graph); }, null, 'sprite-cut', 'Ctrl+X');  90 this.addAction('copy', function() { mxClipboard.copy(graph); }, null, 'sprite-copy', 'Ctrl+C');  91 this.addAction('paste', function() { mxClipboard.paste(graph); }, false, 'sprite-paste', 'Ctrl+V');  92 this.addAction('delete', function() { graph.removeCells(); }, null, null, 'Delete');  93 this.addAction('duplicate', function()  94  {  95 var s = graph.gridSize;  96 graph.setSelectionCells(graph.moveCells(graph.getSelectionCells(), s, s, true));  97 }, null, null, 'Ctrl+D');  98 this.addAction('selectVertices', function() { graph.selectVertices(); }, null, null, 'Ctrl+Shift+V');  99 this.addAction('selectEdges', function() { graph.selectEdges(); }, null, null, 'Ctrl+Shift+E'); 100 this.addAction('selectAll', function() { graph.selectAll(); }, null, null, 'Ctrl+A'); 101 102 // 導航 103 this.addAction('home', function() { graph.home(); }, null, null, 'Home'); 104 this.addAction('exitGroup', function() { graph.exitGroup(); }, null, null, 'Page Up'); 105 this.addAction('enterGroup', function() { graph.enterGroup(); }, null, null, 'Page Down'); 106 this.addAction('expand', function() { graph.foldCells(false); }, null, null, 'Enter'); 107 this.addAction('collapse', function() { graph.foldCells(true); }, null, null, 'Backspace'); 108 109 //安排操做 110 this.addAction('toFront', function() { graph.orderCells(false); }, null, null, 'Ctrl+F'); 111 this.addAction('toBack', function() { graph.orderCells(true); }, null, null, 'Ctrl+B'); 112 this.addAction('group', function() { graph.setSelectionCell(graph.groupCells(null, 0)); }, null, null, 'Ctrl+G'); 113 this.addAction('ungroup', function() { graph.setSelectionCells(graph.ungroupCells()); }, null, null, 'Ctrl+U'); 114 this.addAction('removeFromGroup', function() { graph.removeCellsFromParent(); }); 115 this.addAction('editLink', function() 116  { 117 var cell = graph.getSelectionCell(); 118 var link = graph.getLinkForCell(cell); 119 120 if (link == null) 121  { 122 link = ''; 123  } 124 125 link = mxUtils.prompt(mxResources.get('enterValue'), link); 126 127 if (link != null) 128  { 129  graph.setLinkForCell(cell, link); 130  } 131  }); 132 this.addAction('openLink', function() 133  { 134 var cell = graph.getSelectionCell(); 135 var link = graph.getLinkForCell(cell); 136 137 if (link != null) 138  { 139  window.open(link); 140  } 141  }); 142 this.addAction('autosize', function() 143  { 144 var cells = graph.getSelectionCells(); 145 146 if (cells != null) 147  { 148  graph.getModel().beginUpdate(); 149 try 150  { 151 for (var i = 0; i < cells.length; i++) 152  { 153 var cell = cells[i]; 154 155 if (graph.getModel().getChildCount(cell)) 156  { 157 graph.updateGroupBounds([cell], 20); 158  } 159 else 160  { 161  graph.updateCellSize(cell); 162  } 163  } 164  } 165 finally 166  { 167  graph.getModel().endUpdate(); 168  } 169  } 170  }); 171 this.addAction('rotation', function() 172  { 173 var value = '0'; 174 var state = graph.getView().getState(graph.getSelectionCell()); 175 176 if (state != null) 177  { 178 value = state.style[mxConstants.STYLE_ROTATION] || value; 179  } 180 181 value = mxUtils.prompt(mxResources.get('enterValue') + ' (' + 182 mxResources.get('rotation') + ' 0-360)', value); 183 184 if (value != null) 185  { 186  graph.setCellStyles(mxConstants.STYLE_ROTATION, value); 187  } 188  }); 189 this.addAction('rotate', function() 190  { 191 var cells = graph.getSelectionCells(); 192 193 if (cells != null) 194  { 195  graph.getModel().beginUpdate(); 196 try 197  { 198 for (var i = 0; i < cells.length; i++) 199  { 200 var cell = cells[i]; 201 202 if (graph.getModel().isVertex(cell) && graph.getModel().getChildCount(cell) == 0) 203  { 204 var geo = graph.getCellGeometry(cell); 205 206 if (geo != null) 207  { 208 // 旋轉幾何圖形的大小和位置 209 geo = geo.clone(); 210 geo.x += geo.width / 2 - geo.height / 2; 211 geo.y += geo.height / 2 - geo.width / 2; 212 var tmp = geo.width; 213 geo.width = geo.height; 214 geo.height = tmp; 215  graph.getModel().setGeometry(cell, geo); 216 217 //讀取當前的方向並提出90度 218 var state = graph.view.getState(cell); 219 220 if (state != null) 221  { 222 var dir = state.style[mxConstants.STYLE_DIRECTION] || 'east'/*default*/; 223 224 if (dir == 'east') 225  { 226 dir = 'south'; 227  } 228 else if (dir == 'south') 229  { 230 dir = 'west'; 231  } 232 else if (dir == 'west') 233  { 234 dir = 'north'; 235  } 236 else if (dir == 'north') 237  { 238 dir = 'east'; 239  } 240 241  graph.setCellStyles(mxConstants.STYLE_DIRECTION, dir, [cell]); 242  } 243  } 244  } 245  } 246  } 247 finally 248  { 249  graph.getModel().endUpdate(); 250  } 251  } 252 }, null, null, 'Ctrl+R'); 253 254 //視圖操做 255 this.addAction('actualSize', function() 256  { 257 graph.zoomTo(1); 258  }); 259 this.addAction('zoomIn', function() { graph.zoomIn(); }, null, null, 'Add'); 260 this.addAction('zoomOut', function() { graph.zoomOut(); }, null, null, 'Subtract'); 261 this.addAction('fitWindow', function() { graph.fit(); }); 262 263 this.addAction('fitPage', mxUtils.bind(this, function() 264  { 265 if (!graph.pageVisible) 266  { 267 this.get('pageView').funct(); 268  } 269 var fmt = graph.pageFormat; 270 var ps = graph.pageScale; 271 var cw = graph.container.clientWidth - 20; 272 var ch = graph.container.clientHeight - 20; 273 274 var scale = Math.floor(100 * Math.min(cw / fmt.width / ps, ch / fmt.height / ps)) / 100; 275  graph.zoomTo(scale); 276 277 graph.container.scrollLeft = Math.round(graph.view.translate.x * scale - Math.max(10, (graph.container.clientWidth - fmt.width * ps * scale) / 2)); 278 graph.container.scrollTop = Math.round(graph.view.translate.y * scale - Math.max(10, (graph.container.clientHeight - fmt.height * ps * scale) / 2)); 279  })); 280 this.addAction('fitPageWidth', mxUtils.bind(this, function() 281  { 282 if (!graph.pageVisible) 283  { 284 this.get('pageView').funct(); 285  } 286 287 var fmt = graph.pageFormat; 288 var ps = graph.pageScale; 289 var cw = graph.container.clientWidth - 20; 290 291 var scale = Math.floor(100 * cw / fmt.width / ps) / 100; 292  graph.zoomTo(scale); 293 294 graph.container.scrollLeft = Math.round(graph.view.translate.x * scale - Math.max(10, (graph.container.clientWidth - fmt.width * ps * scale) / 2)); 295 graph.container.scrollTop = Math.round(graph.view.translate.y * scale - Math.max(10, (graph.container.clientHeight - fmt.height * ps * scale) / 2)); 296  })); 297 this.put('customZoom', new Action(mxResources.get('custom'), function() 298  { 299 var value = mxUtils.prompt(mxResources.get('enterValue') + ' (%)', parseInt(graph.getView().getScale() * 100)); 300 301 if (value != null && value.length > 0 && !isNaN(parseInt(value))) 302  { 303 graph.zoomTo(parseInt(value) / 100); 304  } 305  })); 306 307 //選擇操做 308 var action = null; 309 action = this.addAction('grid', function() 310  { 311 graph.setGridEnabled(!graph.isGridEnabled()); 312  editor.updateGraphComponents(); 313 }, null, null, 'Ctrl+Shift+G'); 314 action.setToggleAction(true); 315 action.setSelectedCallback(function() { return graph.isGridEnabled(); }); 316 action = this.addAction('guides', function() { graph.graphHandler.guidesEnabled = !graph.graphHandler.guidesEnabled; }); 317 action.setToggleAction(true); 318 action.setSelectedCallback(function() { return graph.graphHandler.guidesEnabled; }); 319 action = this.addAction('tooltips', function() 320  { 321 graph.tooltipHandler.setEnabled(!graph.tooltipHandler.isEnabled()); 322  }); 323 action.setToggleAction(true); 324 action.setSelectedCallback(function() { return graph.tooltipHandler.isEnabled(); }); 325 action = this.addAction('navigation', function() 326  { 327 graph.foldingEnabled = !graph.foldingEnabled; 328  graph.view.revalidate(); 329  }); 330 action.setToggleAction(true); 331 action.setSelectedCallback(function() { return graph.foldingEnabled; }); 332 action = this.addAction('scrollbars', function() 333  { 334 graph.scrollbars = !graph.scrollbars; 335  editor.updateGraphComponents(); 336 337 if (!graph.scrollbars) 338  { 339 var t = graph.view.translate; 340 graph.view.setTranslate(t.x - graph.container.scrollLeft / graph.view.scale, t.y - graph.container.scrollTop / graph.view.scale); 341 graph.container.scrollLeft = 0; 342 graph.container.scrollTop = 0; 343  graph.sizeDidChange(); 344  } 345 else 346  { 347 var dx = graph.view.translate.x; 348 var dy = graph.view.translate.y; 349 350 graph.view.translate.x = 0; 351 graph.view.translate.y = 0; 352  graph.sizeDidChange(); 353 graph.container.scrollLeft -= Math.round(dx * graph.view.scale); 354 graph.container.scrollTop -= Math.round(dy * graph.view.scale); 355  } 356 }, !mxClient.IS_TOUCH); 357 action.setToggleAction(true); 358 action.setSelectedCallback(function() { return graph.container.style.overflow == 'auto'; }); 359 action = this.addAction('pageView', mxUtils.bind(this, function() 360  { 361 graph.pageVisible = !graph.pageVisible; 362 graph.pageBreaksVisible = graph.pageVisible; 363 graph.preferPageSize = graph.pageBreaksVisible; 364  graph.view.validate(); 365  graph.sizeDidChange(); 366 367  editor.updateGraphComponents(); 368  editor.outline.update(); 369 370 if (mxUtils.hasScrollbars(graph.container)) 371  { 372 if (graph.pageVisible) 373  { 374 graph.container.scrollLeft -= 20; 375 graph.container.scrollTop -= 20; 376  } 377 else 378  { 379 graph.container.scrollLeft += 20; 380 graph.container.scrollTop += 20; 381  } 382  } 383  })); 384 action.setToggleAction(true); 385 action.setSelectedCallback(function() { return graph.pageVisible; }); 386 this.put('pageBackgroundColor', new Action(mxResources.get('backgroundColor'), function() 387  { 388 var apply = function(color) 389  { 390 graph.background = color; 391  editor.updateGraphComponents(); 392  }; 393 394 var cd = new ColorDialog(ui, graph.background || 'none', apply); 395 ui.showDialog(cd.container, 220, 360, true, false); 396 397 if (!mxClient.IS_TOUCH) 398  { 399  cd.colorInput.focus(); 400  } 401  })); 402 action = this.addAction('connect', function() 403  { 404 graph.setConnectable(!graph.connectionHandler.isEnabled()); 405 }, null, null, 'Ctrl+Q'); 406 action.setToggleAction(true); 407 action.setSelectedCallback(function() { return graph.connectionHandler.isEnabled(); }); 408 409 410 this.addAction('help', function() 411  { 412 var ext = ''; 413 414 if (mxResources.isLanguageSupported(mxClient.language)) 415  { 416 ext = '_' + mxClient.language; 417  } 418 419 window.open(RESOURCES_PATH + '/help' + ext + '.html'); 420  }); 421 this.put('about', new Action(mxResources.get('about') + ' Graph Editor', function() 422  { 423 ui.showDialog(new AboutDialog(ui).container, 320, 280, true, true); 424 }, null, null, 'F1')); 425 426 //風格 427 var toggleFontStyle = mxUtils.bind(this, function(key, style) 428  { 429 this.addAction(key, function() 430  { 431  graph.toggleCellStyleFlags(mxConstants.STYLE_FONTSTYLE, style); 432  }); 433  }); 434 435 toggleFontStyle('bold', mxConstants.FONT_BOLD); 436 toggleFontStyle('italic', mxConstants.FONT_ITALIC); 437 toggleFontStyle('underline', mxConstants.FONT_UNDERLINE); 438 439 //顏色 440 this.addAction('fontColor', function() { ui.menus.pickColor(mxConstants.STYLE_FONTCOLOR); }); 441 this.addAction('strokeColor', function() { ui.menus.pickColor(mxConstants.STYLE_STROKECOLOR); }); 442 this.addAction('fillColor', function() { ui.menus.pickColor(mxConstants.STYLE_FILLCOLOR); }); 443 this.addAction('gradientColor', function() { ui.menus.pickColor(mxConstants.STYLE_GRADIENTCOLOR); }); 444 this.addAction('backgroundColor', function() { ui.menus.pickColor(mxConstants.STYLE_LABEL_BACKGROUNDCOLOR); }); 445 this.addAction('borderColor', function() { ui.menus.pickColor(mxConstants.STYLE_LABEL_BORDERCOLOR); }); 446 447 // 格式 448 this.addAction('shadow', function() { graph.toggleCellStyles(mxConstants.STYLE_SHADOW); }); 449 this.addAction('dashed', function() { graph.toggleCellStyles(mxConstants.STYLE_DASHED); }); 450 this.addAction('rounded', function() { graph.toggleCellStyles(mxConstants.STYLE_ROUNDED); }); 451 this.addAction('style', function() 452  { 453 var cells = graph.getSelectionCells(); 454 455 if (cells != null && cells.length > 0) 456  { 457 var model = graph.getModel(); 458 var style = mxUtils.prompt(mxResources.get('enterValue')+ ' (' + mxResources.get('style') + ')', 459 model.getStyle(cells[0]) || ''); 460 461 if (style != null) 462  { 463  graph.setCellStyle(style, cells); 464  } 465  } 466  }); 467 this.addAction('setAsDefaultEdge', function() 468  { 469 var cell = graph.getSelectionCell(); 470 471 if (cell != null && graph.getModel().isEdge(cell)) 472  { 473 //目前採起的快照單元的調用 474 var proto = graph.getModel().cloneCells([cell])[0]; 475 476 //刪除條目- / exitXY風格 477 var style = proto.getStyle(); 478 style = mxUtils.setStyle(style, mxConstants.STYLE_ENTRY_X, ''); 479 style = mxUtils.setStyle(style, mxConstants.STYLE_ENTRY_Y, ''); 480 style = mxUtils.setStyle(style, mxConstants.STYLE_EXIT_X, ''); 481 style = mxUtils.setStyle(style, mxConstants.STYLE_EXIT_Y, ''); 482  proto.setStyle(style); 483 484 //使用鏈接的邊緣模板預覽 485 graph.connectionHandler.createEdgeState = function(me) 486  { 487 return graph.view.createState(proto); 488  }; 489 490 //從邊緣模板建立新鏈接 491 graph.connectionHandler.factoryMethod = function() 492  { 493 return graph.cloneCells([proto])[0]; 494  }; 495  } 496  }); 497 this.addAction('image', function() 498  { 499  function updateImage(value, w, h) 500  { 501 var select = null; 502 var cells = graph.getSelectionCells(); 503 504  graph.getModel().beginUpdate(); 505 try 506  { 507 //若是沒有選中單元格插入新的細胞 508 if (cells.length == 0) 509  { 510 var gs = graph.getGridSize(); 511 cells = [graph.insertVertex(graph.getDefaultParent(), null, '', gs, gs, w, h)]; 512 select = cells; 513  } 514 515  graph.setCellStyles(mxConstants.STYLE_IMAGE, value, cells); 516 graph.setCellStyles(mxConstants.STYLE_SHAPE, 'image', cells); 517 518 if (graph.getSelectionCount() == 1) 519  { 520 if (w != null && h != null) 521  { 522 var cell = cells[0]; 523 var geo = graph.getModel().getGeometry(cell); 524 525 if (geo != null) 526  { 527 geo = geo.clone(); 528 geo.width = w; 529 geo.height = h; 530  graph.getModel().setGeometry(cell, geo); 531  } 532  } 533  } 534  } 535 finally 536  { 537  graph.getModel().endUpdate(); 538  } 539 540 if (select != null) 541  { 542 graph.setSelectionCells(select); 543 graph.scrollCellToVisible(select[0]); 544  } 545  }; 546 547 var value = ''; 548 var state = graph.getView().getState(graph.getSelectionCell()); 549 550 if (state != null) 551  { 552 value = state.style[mxConstants.STYLE_IMAGE] || value; 553  } 554 555 value = mxUtils.prompt(mxResources.get('enterValue') + ' (' + mxResources.get('url') + ')', value); 556 557 if (value != null) 558  { 559 if (value.length > 0) 560  { 561 var img = new Image(); 562 563 img.onload = function() 564  { 565  updateImage(value, img.width, img.height); 566  }; 567 img.onerror = function() 568  { 569 mxUtils.alert(mxResources.get('fileNotFound')); 570  }; 571 572 img.src = value; 573  } 574  } 575  }); 576 }; 577 578 /** 579  * 註冊名字下行動。 580 */ 581 Actions.prototype.addAction = function(key, funct, enabled, iconCls, shortcut) 582 { 583 return this.put(key, new Action(mxResources.get(key), funct, enabled, iconCls, shortcut)); 584 }; 585 586 /** 587  *註冊名字下行動。 588 */ 589 Actions.prototype.put = function(name, action) 590 { 591 this.actions[name] = action; 592 593 return action; 594 }; 595 596 /** 597  * 返回給定名稱的行動或null若是沒有這樣的行動存在。 598 */ 599 Actions.prototype.get = function(name) 600 { 601 return this.actions[name]; 602 }; 603 604 /** 605  * 構造一個新的行動爲給定的參數。 606 */ 607 function Action(label, funct, enabled, iconCls, shortcut) 608 { 609 mxEventSource.call(this); 610 this.label = label; 611 this.funct = funct; 612 this.enabled = (enabled != null) ? enabled : true; 613 this.iconCls = iconCls; 614 this.shortcut = shortcut; 615 }; 616 617 //行動繼承自mxEventSource 618 mxUtils.extend(Action, mxEventSource); 619 620 Action.prototype.setEnabled = function(value) 621 { 622 if (this.enabled != value) 623  { 624 this.enabled = value; 625 this.fireEvent(new mxEventObject('stateChanged')); 626  } 627 }; 628 629 Action.prototype.setToggleAction = function(value) 630 { 631 this.toggleAction = value; 632 }; 633 634 Action.prototype.setSelectedCallback = function(funct) 635 { 636 this.selectedCallback = funct; 637 }; 638 639 Action.prototype.isSelected = function() 640 { 641 return this.selectedCallback(); 642 };
 

進行座標分配的XML文件集以及相應的圖標

 

以一個數據庫圖標的座標管理XML的部分數據爲例database.xml

 
 1 <shapes name="mxGraph.aws.database">  2 <shape name="ElastiCache" h="56.81" w="55.7" aspect="variable" strokewidth="inherit">  3 <connections>  4 <constraint x="0.5" y="0" perimeter="0" name="N"/>  5 <constraint x="0.5" y="1" perimeter="0" name="S"/>  6 <constraint x="0" y="0.5" perimeter="0" name="W"/>  7 <constraint x="1" y="0.5" perimeter="0" name="E"/>  8 <constraint x="0.025" y="0.025" perimeter="0" name="NW"/>  9 <constraint x="0.025" y="0.975" perimeter="0" name="SW"/> 10 <constraint x="0.975" y="0.025" perimeter="0" name="NE"/> 11 <constraint x="0.975" y="0.975" perimeter="0" name="SE"/> 12 </connections> 13 <background> 14 <path> 15 <move x="0" y="51.81"/> 16 <curve x1="0" y1="54.57" x2="2.24" y2="56.81" x3="5" y3="56.81"/> 17 <line x="50.7" y="56.81"/> 18 <curve x1="53.46" y1="56.81" x2="55.7" y2="54.57" x3="55.7" y3="51.81"/> 19 <line x="55.7" y="5"/> 20 <curve x1="55.7" y1="2.24" x2="53.46" y2="0" x3="50.7" y3="0"/> 21 <line x="5" y="0"/> 22 <curve x1="2.24" y1="0" x2="0" y2="2.24" x3="0" y3="5"/> 23 <line x="0" y="51.81"/> 24 <close/> 25 </path> 26 </background> 27 <foreground> 28 <fillstroke/>
 

我寫的這個SaveToXmlServlet.java文件的目的是將網絡拓撲圖保存至對應的XML文件中  以及  讀取網絡拓撲圖對應的XML文件

 
 1 package grapheditor;  2 import java.io.BufferedReader;  3 import java.io.File;  4 import java.io.FileReader;  5 import java.io.IOException;  6 import java.io.PrintWriter;  7 import java.io.RandomAccessFile;  8 import javax.servlet.ServletException;  9 import javax.servlet.http.HttpServlet; 10 import javax.servlet.http.HttpServletRequest; 11 import javax.servlet.http.HttpServletResponse; 12 /** 13  * 將網絡拓撲圖保存至對應的XML文件中 以及 讀取網絡拓撲圖對應的XML文件 14  * @author Visec·Dana 15  * @version V2.0 2014-7-17 16 */ 17 public class SaveToXmlServlet extends HttpServlet { 18 private static final long serialVersionUID = 1L; 19 public void doGet(HttpServletRequest request, HttpServletResponse response) 20  throws ServletException, IOException { 21 this.doPost(request, response); 22  } 23 public void doPost(HttpServletRequest request, HttpServletResponse response) 24  throws ServletException, IOException { 25 response.setContentType("text/html;charset=utf-8"); 26 response.setCharacterEncoding("utf-8"); 27 request.setCharacterEncoding("utf-8"); 28 String type = request.getParameter("type"); 29 String tp = request.getParameter("tp"); 30 StringBuffer result = new StringBuffer(""); 31 String xmlPath=new String(""); 32 String strPath = this.getClass().getResource("/").toString(); 33 xmlPath = ("qsy".equals(tp))?"network_map/network_qsy.xml":("dzj".equals(tp))?"network_map/network_dzj.xml":("zdw".equals(tp))?"network_map/network_zdw.xml":"network_map/network_sp.xml"; 34 String osName = System.getProperties().getProperty("os.name"); 35 if(osName.toLowerCase().indexOf("windows")>-1){ 36 strPath=strPath.substring(6)+xmlPath; 37 }else{ 38 strPath=strPath.substring(5)+xmlPath; 39  } 40 File file = new File(strPath); 41 if(file.isFile()){//判斷該路徑是否爲一個文件 42 if("set".equals(type.toLowerCase())){//文件保存 43 String xml = request.getParameter("xml"); 44 if(xml==null||"".equals(xml)){ 45 result.append("0"); 46 }else{ 47 RandomAccessFile randomAccessFile = new RandomAccessFile(strPath, "rw"); 48 randomAccessFile.seek(0); 49 randomAccessFile.setLength(0); 50  randomAccessFile.write(xml.getBytes()); 51  randomAccessFile.close(); 52 result.append("1"); 53  } 54 }else if("get".equals(type.toLowerCase())){//獲取文件信息 55 //開始讀取 56 BufferedReader reader = new BufferedReader(new FileReader(new File(strPath))); 57 String tempString = null; 58 // 一次讀入一行,直到讀入null爲文件結束 59 while ((tempString = reader.readLine()) != null){ 60  result.append(tempString); 61  } 62  reader.close(); 63  } 64 }else{ 65 System.out.println(strPath+" 找不到!"); 66 result.append("0"); 67  } 68 69 PrintWriter out = response.getWriter(); 70 out.write(result.toString()); 71 out.flush(); 72 out.close(); 73  } 74 75 }
 

固然這個文件的基礎是先前有繪製好的拓撲圖已經保存了相應的座標位置和相應的數據

我編寫network_qsy.xml是用來存儲相應的座標的臨時文件

文件配置,以及不一樣項目之間的嵌入都不同,全部就不詳細介紹了,如感興趣的朋友歡加入羣一塊兒探討更多相關技術提升自身水平!

固然部分網友可能留意到

這裏部分功能是沒有完善的,能力有限,還需一些時間來琢磨!

固然後期的開發是無窮的,後期也在此基礎上添加了右鍵綁定相關設備,合一拖動的形式配置相關信息,

參考資料:http://www.yworks.com/en/products_yed_about.html

              http://docs.cryengine.com/display/SDKDOC2/Flow+Graph+Editor

              http://www.univ-orleans.fr/lifo/software/Agape/javadoc/agape/applications/GraphEditor.html

上訴網站都是英文版的當時,也只是略看一些資料!

相關文章
相關標籤/搜索