基于Web实现在线绘画拓扑图[GraphEditor]

网络拓扑图本来已经整理有一段时间了,一次项目会议写集中边界监控系统的时候上级要求使用可以在系统中画网络拓扑图,没办法当时找不到现有的程序来参考 只能硬着头皮,顶着风险来完成[当然来边界安全的,当然要安全型高啊],一同事找到一些源码来分析,当然了有源码分析比自己想的效率要快得多 但是也很让人头痛,怎样才能实现,怎样才能嵌入到Web项目中? 这个集控那个项目已近完成有一段时间了,最近呢一些网友要借鉴我修改后的代码,和一些效果我最近整理了一份但是当时由于比较忙,没有发到博客中 去!只是写了一个简单的Demo供参考和利用,由于最近又有一些朋友也来问这个问题,为了方便与资源共享,我还是整理了这边文章,和网络拓扑的运用,当然 技术肯定还有更加优化好的控件,有的话希望共同学习! 下面是我编写的一个简单的Demo

这是简单画的一个拓扑图:

 

这是简单的绘画界面,Tab切换后是快捷键保存的后的模板[类似图表,也可以编辑],在这里就先不演示了

当然如果需要,请加入群直接下载分享文件[完整的Demo]

下面来详解下文件的配置,和代码分析

首先来看下web.xml

 
 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接直接放到一起了

 
  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

上诉网站都是英文版的当时,也只是略看一些资料!

posted on 2014-11-24 18:20  记性特差  阅读(772)  评论(1编辑  收藏  举报