网络拓扑图本来已经整理有一段时间了,一次项目会议写集中边界监控系统的时候上级要求使用可以在系统中画网络拓扑图,没办法当时找不到现有的程序来参考 只能硬着头皮,顶着风险来完成[当然来边界安全的,当然要安全型高啊],一同事找到一些源码来分析,当然了有源码分析比自己想的效率要快得多 但是也很让人头痛,怎样才能实现,怎样才能嵌入到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

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

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

  1. 基于Web实现网络拓扑图

    想想好像好久没用写博客了! 由于最近想跳槽了(ps:尽管公司挽留,提出一些异与往常的挽留“制度”,But确实已经死心了) ,发现前一段时间一些做Hadoop,和Spark同事时常来请教网络拓扑图的有关 ...

  2. 基于Web在线考试系统的设计与实现

    这是一个课程设计的文档,源码及文档数据库我都修改过了,貌似这里复制过来的时候图片不能贴出,下载地址:http://download.csdn.net/detail/sdksdk0/9361973   ...

  3. 基于 WebSocket 实现 WebGL 3D 拓扑图实时数据通讯同步(二)

    我们上一篇<基于 WebSocket 实现 WebGL 3D 拓扑图实时数据通讯同步(一)>主要讲解了如何搭建一个实时数据通讯服务器,客户端与服务端是如何通讯的,相信通过上一篇的讲解,再配 ...

  4. Responsive Web CSS – 在线响应式布局创建器

    如果您已经使用了 CSS 或前端框架,创建响应式布局应该不难. 然而,如果你刚涉足这类布局,Responsive Web CSS 可以帮助你快速上手. 这是一个基于 Web 的工具,使任何人都可以通过 ...

  5. Tridiv:基于 Web 的 CSS 编辑器,创建炫丽 3D 图形

    Tridiv 是一个基于 Web 的编辑器,使用 CSS 创建 3D 形状.它提供了一个传统的四个面板的操作界面,给出了从每个平面的视图,以及一个预览窗格中示出的最终的效果.使用 Tridiv 可以创 ...

  6. Eclipse Che:下一代基于 Web 的 IDE

    即使对于熟练的开发人员,想要去为一个项目贡献代码,正确的安装和配置一个集成开发环境.工作区 workspace和构建工具,都是一个十分艰难和浪费时间的任务.Codenvy 的CEO,Tyler Jew ...

  7. Hya.io – 基于 Web 的数字音频工作站

    Hya.io 是基于 Web 的音频应用程序,通过 Web MIDI ,音频合成器,音序以及大量的插件来支持硬件 MIDI .您可以添加插件到工作区,将其连接到路由音频,进行播放和实验. HYA 支持 ...

  8. 基于Web的企业网和互联网的信息和应用( 1194.22 )

    基于Web的企业网和互联网的信息和应用( 1194.22 ) 原文更新日期: 2001年6月21日原文地址: http://www.access-board.gov/sec508/guide/1194 ...

  9. 基于Web的系统测试方法

    基于Web的系统测试与传统的软件测试既有相同之处,也有不同的地方,对软件测试提出了新的挑战.基于Web的系统测试不但需要检查和验证是否按照设计的要求运行,而且还要评价系统在不同用户的浏览器端的显示是否 ...

随机推荐

  1. [Nuxt] Add Arrays of Data to the Vuex Store and Display Them in Vue.js Templates

    You add array of todos to the store simply by adding them to the state defined in your store/index.j ...

  2. storm原理介绍

    目录 storm原理介绍 一.原理介绍 二.配置 三.并行度 (一)storm拓扑的并行度可以从以下4个维度进行设置: (二)并行度的设置方法 (三)示例 四.分组 五.可靠性 (一)spout (二 ...

  3. c#.net公共帮助类

    c#.net公共帮助类 比较全面的c#帮助类 比较全面的c#帮助类,日常工作收集,包括前面几家公司用到的,各式各样的几乎都能找到,所有功能性代码都是独立的类,类与类之间没有联系,可以单独引用至项目,分 ...

  4. 微信小程序--成语猜猜看

    原文链接:https://mp.weixin.qq.com/s/p6OMCbTHOYGJsjGOINpYvQ 1 概述 微信最近有很多火爆的小程序.成语猜猜看算得上前十火爆的了.今天我们就分享这样的小 ...

  5. [RxJS] Conclusion: when to use Subjects

    As a conclusion to this course about RxJS subjects, let's review when and why should you use them. F ...

  6. 【hdu5527】【2015ACM/ICPC亚洲区长春站 】Too Rich

    题目链接: pid=5527">http://acm.hdu.edu.cn/showproblem.php?pid=5527 题意&题解: 感觉自己真是弱啊,自己想的贪心是错的 ...

  7. php curl header头

    工作中第一次用到header做个记录 工作中需要在heaer里面加上 Authorization 用来验证身份 public function index() { $url = "http: ...

  8. java异常——捕获异常+再次抛出异常与异常链

    [0]README 0.1) 本文描述+源代码均 转自 core java volume 1, 旨在理解 java异常--捕获异常+再次抛出异常与异常链 的相关知识: [1]捕获异常相关 1.1)如果 ...

  9. HDU4268 Alice and Bob 【贪心】

    Alice and Bob Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) T ...

  10. C#验证手机号

    using System.Text.RegularExpressions; private bool IsMobile(string phoneNo) { return Regex.IsMatch(p ...