基于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

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

时间: 2024-10-13 02:00:04

基于Web实现在线绘画拓扑图[GraphEditor]的相关文章

基于WEB的企业用能信息在线填报系统设计

源码下载:http://download.csdn.net/detail/yiduiguwen/9523660 二.课题来源及选题依据 对于任何一家企业来说,其正常的生产过程都需要各种的一次或二次能源,针对能源使用计量数据的管理和应用,在企业发展过程中有着日益重要的作用.企业用能数据反映了消耗水平的高低,可以及时有效地指导企业有关部门及时采取行之有效的措施降低能耗,提高企业的节能意识,推动节能工作深入开展. 对于企业用能情况的查询与更新,不同企业员工应当具有不同的处理权限,比如某些低级别用户只能

Eclipse Che:下一代基于 Web 的 IDE

即使对于熟练的开发人员,想要去为一个项目贡献代码,正确的安装和配置一个集成开发环境.工作区 workspace和构建工具,都是一个十分艰难和浪费时间的任务.Codenvy 的CEO,Tyler Jewell,也面临着这个问题.当他养好了一些小病,又处理了一些管理工作之后,试图建立一个简单的 Java 项目来找回他曾经的编程技能.经过多天的努力,Jewell 的项目依然无法工作,但这就是给予了他灵感.他想做个可以让"任何人,任何时候都可以为安装软件的项目做贡献"的东西. 正是这个想法引发

基于 Web 的 Go 语言 IDE - Wide 1.1.0 公布!

公布 1.1.0 这个版本号改进了非常多细节,已经全然能够用于正式项目的开发 同一时候我们上线了 Wide 在线服务 到眼下,我们提供了 Wide 和 Solo 两个在线服务,详情请看这里. Wide 是什么 Wide 是一个基于 Web 的 Go 语言团队 IDE. 在线开发:打开浏览器就能够进行开发.全快捷键 智能提示:代码自己主动完毕.查看表达式.编译反馈.Lint 实时执行:极速编译.实时结果输出 团队协同:统一开发环境,分布式开发.代码分享 DevOps! 另外,除了使用上面我们提到的

pyDash:一个基于 web 的 Linux 性能监测工具

pyDash 是一个轻量且基于 web 的 Linux 性能监测工具,它是用 Python 和 Django 加上 Chart.js 来写的.经测试,在下面这些主流 Linux 发行版上可运行:CentOS.Fedora.Ubuntu.Debian.Raspbian 以及 Pidora .-- Ravi Saive 本文导航 -如何在 Linux 系统下安装 pyDash12% pyDash 是一个轻量且基于 web 的 Linux 性能监测工具[1],它是用 Python 和 Django[2

基于 Web 的 Go 语言 IDE - Wide 1.5.0 发布!

Wide 是什么 Wide 是一个基于 Web 的 Go 语言团队 IDE. 在线开发:打开浏览器就可以进行开发.全快捷键 智能提示:代码自动完成.查看表达式.编译反馈.Lint 实时运行:极速编译.实时结果输出 团队协同:统一开发环境,分布式开发,代码分享 DevOps! 大家可以使用我们提供的 Wide 在线服务,也可以自行下载并在本地环境运行 Wide 私服! Playground Wide 提供了运行单文件的 Playground,可以看作是 golang.org 的 Go Playgr

基于 Web 的 Go 语言 IDE - Wide 1.2.0 发布!

Wide 是什么 Wide 是一个基于 Web 的 Go 语言团队 IDE. 在线开发:打开浏览器就可以进行开发.全快捷键 智能提示:代码自动完成.查看表达式.编译反馈.Lint 实时运行:极速编译.实时结果输出 团队协同:统一开发环境,分布式开发,代码分享 DevOps! 大家可以使用我们提供的 Wide 在线服务,也可以自行下载并在本地环境运行 Wide 私服! Playground Wide 提供了运行单文件的 Playground,可以看作是 golang.org 的 Go Playgr

N个富文本编辑器/基于Web的HTML编辑器

转自:http://www.cnblogs.com/lingyuan/archive/2010/11/15/1877447.html 基于WEB的HTML 编辑器,WYSIWYG所见即所得的编辑器,或是一个富文本的编辑器,是我们在开发WEB应用时接收用户输入时必需要考虑的问题.下面是一些开源的WEB在线的WYSWIG编辑器. 1.FCKeditorFCKeditor 这些在线编辑器中最著名的一个,其功能相当的强大,很像一个Web的Word软件.它可以方便地和ASP, ASP.NET, PHP,

如何基于web技术开发国产化网管软件

随着Java和web技术的成熟及其在Internet上的广泛应用,网络管理技术和模式迎来了又一次革命.在网络管理领域,通过Web技术(如Web服务器,HTTP协议.HTML和Java语言等)来集成网络管理系统,就能够获得可运行于各种平台的简单有效的管理工具.特别是目前人们对计算机网络管理工具的要求已不仅仅局限于集中式管理模式,而要求网络管理工具具有分布计算能力.近几年来随着Java.EJB.XML等技术的发展与成熟使人们对网络管理的分布式要求已成为现实. 1. 基于Web的网络管理模式的特点 分

基于web的数字化校园管理集成方案

软件系列 :基于web的数字化校园管理集成方案 开发公司: 慈溪市顺通网络技术有限公司 开发时间:2013/5/21 1. 引言 1.1编写目的 1.2项目背景 2.总体设计说明: 3. 系统概述 3.1系统建设目标 3.2系统功能 4.系统使用说明 4.1登录界面 4.1登录界面 4.2权限设置-个人权限 4.3学年管理 4.4学期管理 4.5年级管理 4.6班级管理及维护 4.61添加班级 4.62批量添加班级 4.63班级维护 4.64班级升迁设置 4.65班级升迁 4.66升迁管理 4.