2023年7月21日发(作者:)
基于Web实现在线绘画拓扑图[GraphEditor]⽹络拓扑图本来已经整理有⼀段时间了,⼀次项⽬会议写集中边界监控系统的时候上级要求使⽤可以在系统中画⽹络拓扑图,没办法当时找不到现有的程序来参考只能硬着头⽪,顶着风险来完成[当然来边界安全的,当然要安全型⾼啊],⼀同事找到⼀些源码来分析,当然了有源码分析⽐⾃⼰想的效率要快得多但是也很让⼈头痛,怎样才能实现,怎样才能嵌⼊到Web项⽬中?这个集控那个项⽬已近完成有⼀段时间了,最近呢⼀些⽹友要借鉴我修改后的代码,和⼀些效果我最近整理了⼀份但是当时由于⽐较忙,没有发到博客中去!只是写了⼀个简单的Demo供参考和利⽤,由于最近⼜有⼀些朋友也来问这个问题,为了⽅便与资源共享,我还是整理了这边⽂章,和⽹络拓扑的运⽤,当然技术肯定还有更加优化好的控件,有的话希望共同!下⾯是我编写的⼀个简单的Demo这是简单画的⼀个拓扑图:
这是简单的绘画界⾯,Tab切换后是快捷键保存的后的模板[类似图表,也可以编辑],在这⾥就先不了当然如果需要,请加⼊群直接下载分享⽂件[完整的Demo]下⾯来详解下⽂件的配置,和代码分析⾸先来看下01.
02.
03.
04.
05.
06.
07.
08.
09.
10.
11.
12.
13.
14.
15.
16.
17.
02.
03.
04.
05.
06.
07.
08.
09.
10.
11.
12.
<%@ page language="java" %><%@ page contentType="text/html; charset=utf-8"%><%String path =textPath();%>
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
复制代码上诉⽂件呢,主要负责拓扑图的绘画与相关操作界⾯的代码由于相关的⽂件过多,我这⾥之举出⽐较重要的⼏个问⽂件主要获取坐标并进⾏处理的JS⽂件01.
02.
03.
04.
05.
06.
07.
08.
09.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
function Actions(editorUi){ Ui = editorUi; s = new Object(); ();};/*** 添加默认的⾏为*/ = function(){ var ui = Ui; var editor = ; var graph = ; ovable=!0;//设置不可移动 isconnectable=!0;//设置边不可编辑 esizable=!0;//设置不可改变⼤⼩ $.post($("#path").val()+"/SaveToXmlServlet",{"tp":$("#mapTp").val(),"type":"get"},function(text){ if(text=="0"){ alert("⽂件加载失败!"); }else{ var xml = text;24. var doc = **ml(xml);25. var model = new mxGraphModel();26. var codec = new mxCodec(doc);27. (ntElement, model);28. var children = ldren(ldAt(t(), 0));29. ectionCells(Cells(children));30. }
31. });32.
33. // ⽂件操作34. ion('new', function() { (()); });35. ion('open', function()36. {37. w = true;38. y = 'open';39.
40. le();41. });42. ion('import', function()43. {44. w = false;45. y = 'import';46.
47. // 后关闭对话框打开48. le = new OpenFile((this, function()49. {50. alog();51. }));52.
53. sumer((this, function(xml, filename)54. {55. try56. {57. var doc = **ml(xml);58. var model = new mxGraphModel();59. var codec = new mxCodec(doc);60. (ntElement, model);61.
62. var children = ldren(ldAt(t(), 0));63. ectionCells(Cells(children));64. }65. catch (e)66. {67. (('invalidOrMissingFile') + ': ' + e);68. }69. }));70.
71. // 删除openFile是否关闭对话框72. alog(new OpenDialog(this).container, 300, 180, true, true, function()73. {74. le = null;75. });76. });77. ion('save', function() { (); }, null, null, 'Ctrl+S');78. //addAction(saveAs,函数(){ le(真正);},空,空,“Ctrl + Shift-S”);79. //addAction(“出⼝”,函数(){ ui。showDialog(新ExportDialog(ui)。容器、300、200,真的,真的);},空,空,“Ctrl + E”);80. //(“editFile”,新的⾏动((“编辑”),mxUtils。绑定(此功能()81. //(“editFile”,新的⾏动((“编辑”),mxUtils。绑定(此功能()82. ion('pageSetup', function() { alog(new PageSetupDialog(ui).container, 300, 200, true, true); });83. ion('print', function() { alog(new PrintDialog(ui).container, 300, 200, true, true); }, null, 'sprite-print', 'Ctrl+P');84. ion('preview', function() { (graph, null, 10, 10); });85.
86. // Edit actions87. ion('undo', function() { (); }, null, 'sprite-undo', 'Ctrl+Z');88. ion('redo', function() { (); }, null, 'sprite-redo', 'Ctrl+Y');89. ion('cut', function() { (graph); }, null, 'sprite-cut', 'Ctrl+X');90. ion('copy', function() { (graph); }, null, 'sprite-copy', 'Ctrl+C');91. ion('paste', function() { (graph); }, false, 'sprite-paste', 'Ctrl+V');92. ion('delete', function() { Cells(); }, null, null, 'Delete');93. ion('duplicate', function()94. {95. var s = ze;96. ectionCells(lls(ectionCells(), s, s, true));97. }, null, null, 'Ctrl+D');98. ion('selectVertices', function() { Vertices(); }, null, null, 'Ctrl+Shift+V');99. ion('selectEdges', function() { Edges(); }, null, null, 'Ctrl+Shift+E');100. ion('selectAll', function() { All(); }, null, null, 'Ctrl+A');101.
102. // 导航103. ion('home', function() { (); }, null, null, 'Home');104. ion('exitGroup', function() { oup(); }, null, null, 'Page Up');105. ion('enterGroup', function() { roup(); }, null, null, 'Page Down');106. ion('expand', function() { lls(false); }, null, null, 'Enter');107. ion('collapse', function() { lls(true); }, null, null, 'Backspace');108.
109. //安排操作110. ion('toFront', function() { ells(false); }, null, null, 'Ctrl+F');111. ion('toBack', function() { ells(true); }, null, null, 'Ctrl+B');112. ion('group', function() { ectionCell(ells(null, 0)); }, null, null, 'Ctrl+G');113. ion('ungroup', function() { ectionCells(pCells()); }, null, null, 'Ctrl+U');114. ion('removeFromGroup', function() { CellsFromParent(); });115. ion('editLink', function()116. {117. var cell = ectionCell();118. var link = kForCell(cell);119.
120. if (link == null)121. {122. link = '';123. }124.
125. link = (('enterValue'), link);126.
127. if (link != null)128. {129. kForCell(cell, link);130. }131. });132. ion('openLink', function()133. {134. var cell = ectionCell();135. var link = kForCell(cell);136.
137. if (link != null)138. {139. (link);140. }141. });142. ion('autosize', function()143. {144. var cells = ectionCells();145.
146. if (cells != null)147. {148. el().beginUpdate();149. try150. {151. for (var i = 0; i < ; i++)152. {153. var cell = cells[i];154.
155. if (el().getChildCount(cell))156. {157. GroupBounds([cell], 20);158. }159. else160. {161. CellSize(cell);162. }163. }164. }165. finally166. {167. el().endUpdate();168. }169. }170. });171. ion('rotation', function()172. {173. var value = '0';174. var state = w().getState(ectionCell());175.
176. if (state != null)177. {178. value = [_ROTATION] || value;179. }180.
181. value = (('enterValue') + ' (' +182. ('rotation') + ' 0-360)', value);183.
184. if (value != null)185. {186. lStyles(_ROTATION, value);187. }188. });189. ion('rotate', function()190. {191. var cells = ectionCells();192.
193. if (cells != null)194. {195. el().beginUpdate();196. try197. {198. for (var i = 0; i < ; i++)199. {200. var cell = cells[i];201.
202. if (el().isVertex(cell) && el().getChildCount(cell) == 0)203. {204. var geo = lGeometry(cell);205.
206. if (geo != null)207. {208. // 旋转⼏何图形的⼤⼩和位置209. geo = ();210. geo.x += / 2 - / 2;211. geo.y += / 2 - / 2;212. var tmp = ;213. = ;214. = tmp;215. el().setGeometry(cell, geo);216.
217. //读取当前的⽅向并提出90度218. var state = te(cell);219.
220. if (state != null)221. {222. var dir = [_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. lStyles(_DIRECTION, dir, [cell]);242. }243. }244. }245. }246. }247. finally248. {249. el().endUpdate();250. }251. }252. }, null, null, 'Ctrl+R');253.
254. //视图操作255. ion('actualSize', function()256. {257. (1);258. });259. ion('zoomIn', function() { (); }, null, null, 'Add');260. ion('zoomOut', function() { t(); }, null, null, 'Subtract');261. ion('fitWindow', function() { (); });262.
263. ion('fitPage', (this, function()264. {265. if (!sible)266. {267. ('pageView').funct();268. }269. var fmt = rmat;270. var ps = ale;271. var cw = Width - 20;272. var ch = Height - 20;273.
274. var scale = (100 * (cw / / ps, ch / / ps)) / 100;275. (scale);276.
277. Left = (ate.x * scale - (10, (Width - * ps * scale) / 2));278. Top = (ate.y * scale - (10, (Height - * ps * scale) / 2));279. }));280. ion('fitPageWidth', (this, function()281. {282. if (!sible)283. {284. ('pageView').funct();285. }286.
287. var fmt = rmat;288. var ps = ale;289. var cw = Width - 20;290.
291. var scale = (100 * cw / / ps) / 100;292. (scale);293.
294. Left = (ate.x * scale - (10, (Width - * ps * scale) / 2));295. Top = (ate.y * scale - (10, (Height - * ps * scale) / 2));296. }));297. ('customZoom', new Action(('custom'), function()298. {299. var value = (('enterValue') + ' (%)', parseInt(w().getScale() * 100));300.
301. if (value != null && > 0 && !isNaN(parseInt(value)))302. {303. (parseInt(value) / 100);304. }305. }));306.
307. //选择操作308. var action = null;309. action = ion('grid', function()310. {311. dEnabled(!Enabled());312. GraphComponents();313. }, null, null, 'Ctrl+Shift+G');314. gleAction(true);315. ectedCallback(function() { return Enabled(); });316. action = ion('guides', function() { Enabled = !Enabled; });317. gleAction(true);318. ectedCallback(function() { return Enabled; });319. action = ion('tooltips', function()320. {321. bled(!led());322. });323. gleAction(true);324. ectedCallback(function() { return led(); });325. action = ion('navigation', function()326. {327. gEnabled = !gEnabled;328. date();329. });330. gleAction(true);331. ectedCallback(function() { return gEnabled; });332. action = ion('scrollbars', function()333. {334. bars = !bars;335. GraphComponents();336.
337. if (!bars)338. {339. var t = ate;340. nslate(t.x - Left / , t.y - Top / );341. Left = 0;342. Top = 0;343. dChange();344. }345. else346. {347. var dx = ate.x;348. var dy = ate.y;349.
350. ate.x = 0;351. ate.y = 0;352. dChange();353. Left -= (dx * );354. Top -= (dy * );355. }356. }, !_TOUCH);357. gleAction(true);358. ectedCallback(function() { return ow == 'auto'; });359. action = ion('pageView', (this, function()360. {361. sible = !sible;362. eaksVisible = sible;
363. PageSize = eaksVisible;364. te();365. dChange();366.
367. GraphComponents();368. ();369.
370. if (ollbars(ner))371. {372. if (sible)373. {374. Left -= 20;375. Top -= 20;376. }377. else378. {379. Left += 20;380. Top += 20;381. }382. }383. }));384. gleAction(true);385. ectedCallback(function() { return sible; });386. ('pageBackgroundColor', new Action(('backgroundColor'), function()387. {388. var apply = function(color)389. {390. ound = color;391. GraphComponents();392. };393.
394. var cd = new ColorDialog(ui, ound || 'none', apply);395. alog(ner, 220, 360, true, false);396.
397. if (!_TOUCH)398. {399. ();400. }401. }));402. action = ion('connect', function()403. {404. nectable(!led());405. }, null, null, 'Ctrl+Q');406. gleAction(true);407. ectedCallback(function() { return led(); });408.
409.
410. ion('help', function()411. {412. var ext = '';413.
414. if (uageSupported(ge))415. {416. ext = '_' + ge;417. }418.
419. (RESOURCES_PATH + '/help' + ext + '.html');420. });421. ('about', new Action(('about') + ' Graph Editor', function()422. {423. alog(new AboutDialog(ui).container, 320, 280, true, true);424. }, null, null, 'F1'));425.
426. //风格427. var toggleFontStyle = (this, function(key, style)428. {429. ion(key, function()430. {431. CellStyleFlags(_FONTSTYLE, style);432. });433. });434.
435. toggleFontStyle('bold', _BOLD);436. toggleFontStyle('italic', _ITALIC);437. toggleFontStyle('underline', _UNDERLINE);438.
439. //颜⾊440. ion('fontColor', function() { lor(_FONTCOLOR); });441. ion('strokeColor', function() { lor(_STROKECOLOR); });442. ion('fillColor', function() { lor(_FILLCOLOR); });443. ion('gradientColor', function() { lor(_GRADIENTCOLOR); });444. ion('backgroundColor', function() { lor(_LABEL_BACKGROUNDCOLOR); });445. ion('borderColor', function() { lor(_LABEL_BORDERCOLOR); });446.
447. // 格式448. ion('shadow', function() { CellStyles(_SHADOW); });449. ion('dashed', function() { CellStyles(_DASHED); });450. ion('rounded', function() { CellStyles(_ROUNDED); });451. ion('style', function()452. {453. var cells = ectionCells();454.
455. if (cells != null && > 0)456. {457. var model = el();458. var style = (('enterValue')+ ' (' + ('style') + ')',459. le(cells[0]) || '');460.
461. if (style != null)462. {463. lStyle(style, cells);464. }465. }466. });467. ion('setAsDefaultEdge', function()468. {469. var cell = ectionCell();470.
471. if (cell != null && el().isEdge(cell))472. {473. //⽬前采取的快照单元的调⽤474. var proto = el().cloneCells([cell])[0];475.
476. //删除条⽬- / exitXY风格477. var style = le();478. style = le(style, _ENTRY_X, '');479. style = le(style, _ENTRY_Y, '');480. style = le(style, _EXIT_X, '');481. style = le(style, _EXIT_Y, '');482. le(style);483.
484. //使⽤连接的边缘模板预览485. EdgeState = function(me)486. {487. return State(proto);488. };489.
490. //从边缘模板创建新连接491. yMethod = function()492. {493. return ells([proto])[0];494. };495. }496. });497. ion('image', function()498. {499. function updateImage(value, w, h)500. {501. var select = null;502. var cells = ectionCells();503.
504. el().beginUpdate();505. try506. {507. //如果没有选中单元格插⼊新的细胞508. if ( == 0)509. {510. var gs = dSize();511. cells = [Vertex(aultParent(), null, '', gs, gs, w, h)];512. select = cells;513. }514.
515. lStyles(_IMAGE, value, cells);516. lStyles(_SHAPE, 'image', cells);517.
518. if (ectionCount() == 1)519. {520. if (w != null && h != null)521. {522. var cell = cells[0];523. var geo = el().getGeometry(cell);524.
525. if (geo != null)526. {527. geo = ();528. = w;529. = h;530. el().setGeometry(cell, geo);531. }532. }533. }534. }535. finally536. {537. el().endUpdate();538. }539.
540. if (select != null)541. {542. ectionCells(select);543. CellToVisible(select[0]);544. }545. };546.
547. var value = '';548. var state = w().getState(ectionCell());549.
550. if (state != null)551. {552. value = [_IMAGE] || value;553. }554.
555. value = (('enterValue') + ' (' + ('url') + ')', value);556.
557. if (value != null)558. {559. if ( > 0)560. {561. var img = new Image();562.
563. = function()564. {565. updateImage(value, , );566. };567. r = function()568.
569.
570.
571.
572.
573.
574.
575.
576.
577.
578.
579.
580.
581.
582.
583.
{ (('fileNotFound')); };
= value; } } });};/*** 注册名字下⾏动。*/ion = function(key, funct, enabled, iconCls, shortcut){ return (key, new Action((key), funct, enabled, iconCls, shortcut));584. };585.
586. /**587. *注册名字下⾏动。588. */589. = function(name, action)590. {591. s[name] = action;592.
593. return action;594. };595.
596. /**597. * 返回给定名称的⾏动或null如果没有这样的⾏动存在。598. */599. = function(name)600. {601. return s[name];602. };603.
604. /**605. * 构造⼀个新的⾏动为给定的参数。606. */607. function Action(label, funct, enabled, iconCls, shortcut)608. {609. (this);610. = label;611. = funct;612. d = (enabled != null) ? enabled : true;613. s = iconCls;614. ut = shortcut;615. };616.
617. //⾏动继承⾃mxEventSource618. (Action, mxEventSource);619.
620. bled = function(value)621. {622. if (d != value)623. {624. d = value;625. ent(new mxEventObject('stateChanged'));626. }627. };628.
629. gleAction = function(value)630. {631. Action = value;632. };633.
634. ectedCallback = function(funct)635. {636.
637.
638.
639.
640.
641.
642.
edCallback = funct;};cted = function(){ return edCallback();};复制代码进⾏坐标分配的XML⽂件集以及相应的图标
以⼀个数据库图标的坐标管理XML的部分数据为例01.
02.
03.
04.
05.
06.
07.
08.
09.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
02.
03.
04.
05.
06.
07.
08.
09.
10.
11.
12.
13.
14.
15.
package grapheditor;import edReader;import ;import ader;import ption;import riter;import AccessFile;import tException;import rvlet;import rvletRequest;import rvletResponse;/*** 将⽹络拓扑图保存⾄对应的XML⽂件中 以及 读取⽹络拓扑图对应的XML⽂件* @author Visec·Dana* @version V2.0 2014-7-1716.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
*/public class SaveToXmlServlet extends HttpServlet { private static final long serialVersionUID = 1L; public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { (request, response); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { tentType("text/html;charset=utf-8"); racterEncoding("utf-8"); racterEncoding("utf-8"); String type = ameter("type"); String tp = ameter("tp"); StringBuffer result = new StringBuffer(""); String xmlPath=new String(""); String strPath = ss().getResource("/").toString(); xmlPath = ("qsy".equals(tp))?"network_map/network_":("dzj".equals(tp))?"network_map/network_":("zdw".equals(tp))?"network_map/network_":"network_map/network_"; String osName = perties().getProperty(""); if(rCase().indexOf("windows")>-1){ strPath=ing(6)+xmlPath; }else{ strPath=ing(5)+xmlPath; } File file = new File(strPath); if(()){//判断该路径是否为⼀个⽂件 if("set".equals(rCase())){//⽂件保存 String xml = ameter("xml"); if(xml==null||"".equals(xml)){ ("0"); }else{ RandomAccessFile randomAccessFile = new RandomAccessFile(strPath, "rw"); (0); gth(0); (es()); (); ("1"); } }else if("get".equals(rCase())){//获取⽂件信息 //开始读取 BufferedReader reader = new BufferedReader(new FileReader(new File(strPath))); String tempString = null; // ⼀次读⼊⼀⾏,直到读⼊null为⽂件结束 while ((tempString = ne()) != null){ (tempString); } (); } }else{ n(strPath+" 找不到!"); ("0"); } PrintWriter out = ter(); (ng()); (); (); }}复制代码当然这个⽂件的基础是先前有绘制好的拓扑图已经保存了相应的坐标位置和相应的数据 我编写network_是⽤来存储相应的坐标的临时⽂件⽂件配置,以及不同项⽬之间的嵌⼊都不⼀样,所有就不详细介绍了,如感兴趣的朋友欢加⼊群⼀起探讨更多相关技术提⾼⾃⾝⽔平!当然部分⽹友可能留意到
这⾥部分功能是没有完善的,能⼒有限,还需⼀些时间来琢磨!当然后期的开发是⽆穷的,后期也在此基础上添加了右键绑定相关设备,合⼀拖动的形式配置相关信息,
参考资料:
上诉都是英⽂版的当时,也只是略看⼀些资料!
via:
发布者:admin,转转请注明出处:http://www.yc00.com/web/1689952315a296354.html
评论列表(0条)