天天看點

基于Web實作網絡拓撲圖

想想好像好久沒用寫部落格了! 由于最近想跳槽了(ps:盡管公司挽留,提出一些異與往常的挽留“制度”,But确實已經死心了) ,發現前一段時間一些做Hadoop,和Spark同僚時常來請教網絡拓撲圖的有關問題,由于當時确實比較忙,沒時間幫着一起分析,表示歉意!

先前整理過份簡單的Demo 但是不詳細  基于Web實作線上繪畫拓撲圖[GraphEditor]

首先呢這裡是要詳述的幾個要點:(我用圖是直接顯示了~) (當然這套UI子產品是後期改動的~重點不在這裡)        [備案:後續使用文檔]

顯示拓撲圖

基于Web實作網絡拓撲圖
基于Web實作網絡拓撲圖

其次呢是一些後期加上去的代碼,我想既然用了網絡拓撲圖,後期的可塑性應該是很強的,部分都是後續需求加上去的!

基于Web實作網絡拓撲圖
基于Web實作網絡拓撲圖
基于Web實作網絡拓撲圖
基于Web實作網絡拓撲圖

言歸正傳,看完一些簡單的流程圖,我想都大概知道他的基本用途,和後期的塑造價值

一些簡單的用途比如:做大資料Hadoop,Spark是的個個伺服器之間的關系,以及關系流程圖的描述; 大型企業的負載叢集管理的關系以及流程圖,安全管理,OA企業人士管理.....多事不可缺少的素材!

主要JQ代碼子產品:

基于Web實作網絡拓撲圖

上面的一些常量是一些屬性!

用于綁定一些菜單資訊

編輯儲存

(主要檔案:mxClient.js , Editor.js ,Graph.js,Shapes.js,EditorUi.js,Actions.js,Menus.js,Sidebar.js,                 Toolbar.js,Dialogs.js,jscolor.js )

核心檔案代碼如下:

EditorUi.js

基于Web實作網絡拓撲圖
基于Web實作網絡拓撲圖
1 /**
  2 *$id:Action 。JS,V 2015-3-23
  3 *$author Dana丶Li$
  4 */
  5 /**
  6  * 建構了一種新的圖形編輯器
  7  * 編輯管理 實作方法管理
  8  */
  9 EditorUi = function(editor, container)
 10 {
 11     this.editor = editor || new Editor();
 12     this.container = container || document.body;
 13     var graph = editor.graph;
 14     //禁用滾動條 
 15     this.container.style.overflow = \'hidden\';
 16 
 17     var textEditing =  mxUtils.bind(this, function(evt)
 18     {
 19         if (evt == null)
 20         {
 21             evt = window.event;
 22         }
 23         
 24         if (this.isSelectionAllowed(evt))
 25         {
 26             return true;
 27         }
 28         
 29         return graph.isEditing() || this.dialog != null;
 30     });
 31 
 32     //禁用文本選擇而不是編輯沒有對話框可見 
 33     if (this.container == document.body)
 34     {
 35         document.onselectstart = textEditing;
 36         document.onmousedown = textEditing;
 37     }
 38     
 39     //使用内置的上下文菜單編輯時 
 40     if (mxClient.IS_IE && document.documentMode != 9)
 41     {
 42         mxEvent.addListener(this.container, \'contextmenu\', textEditing);
 43     }
 44     else
 45     {
 46         this.container.oncontextmenu = textEditing;
 47     }
 48 
 49     //圖像預fetches子菜單 
 50     new Image().src = mxPopupMenu.prototype.submenuImage;
 51 
 52     //預取連接配接圖像 
 53     if (mxConnectionHandler.prototype.connectImage != null)
 54     {
 55         new Image().src = mxConnectionHandler.prototype.connectImage.src;
 56     }
 57     
 58     //建立使用者界面 
 59     this.actions = new Actions(this);
 60     this.menus = new Menus(this);
 61     this.createDivs();
 62     this.refresh();
 63     this.createUi();
 64 
 65     //contains the given the inside main圖審小組 
 66     graph.init(this.diagramContainer);
 67     graph.refresh();
 68     
 69     //使容器的滾動條和設定光标樣式
 70     graph.container.setAttribute(\'tabindex\', \'0\');
 71        graph.container.style.overflow = (touchStyle) ? \'hidden\' : \'auto\';
 72        graph.container.style.cursor = \'default\';
 73     graph.container.style.backgroundImage = \'url(\' + IMAGE_PATH + \'/grid.gif)\';
 74        graph.container.focus();
 75        
 76        //保持圖形容器集中在滑鼠按下 
 77        var graphFireMouseEvent = graph.fireMouseEvent;
 78        graph.fireMouseEvent = function(evtName, me, sender)
 79        {
 80            if (evtName == mxEvent.MOUSE_DOWN)
 81            {
 82                this.container.focus();
 83            }
 84            
 85            graphFireMouseEvent.apply(this, arguments);
 86        };
 87 
 88        //在滑鼠經過時自動擴充配置 
 89     graph.panningHandler.autoExpand = true;
 90 
 91     //對上下文菜單 
 92     graph.panningHandler.factoryMethod = mxUtils.bind(this, function(menu, cell, evt)
 93     {
 94         this.menus.createPopupMenu(menu, cell, evt);
 95     });
 96     
 97     //初始化輪廓 
 98     editor.outline.init(this.outlineContainer);
 99     
100     //隐藏菜單 
101     var md = (mxClient.IS_TOUCH) ? \'touchstart\' : \'mousedown\';
102     mxEvent.addListener(document, md, mxUtils.bind(this, function(evt)
103     {
104         graph.panningHandler.hideMenu();
105     }));
106 
107     //增加了手勢操作(縮放) 
108     if (mxClient.IS_TOUCH)
109     {
110         mxEvent.addListener(graph.container, \'gesturechange\',
111             mxUtils.bind(this, function(evt)
112             {
113                 graph.view.getDrawPane().setAttribute(\'transform\', \'scale(\' + evt.scale + \')\');
114                 graph.view.getOverlayPane().style.visibility = \'hidden\';
115             })
116         );
117     
118         mxEvent.addListener(graph.container, \'gestureend\',
119             mxUtils.bind(this, function(evt)
120             {
121                 graph.view.getDrawPane().removeAttribute(\'transform\');
122                 graph.zoomToCenter = true;
123                 graph.zoom(evt.scale);
124                 graph.view.getOverlayPane().style.visibility = \'visible\';
125             })
126         );
127     }
128     
129     // Create handler for key events
130     var keyHandler = this.createKeyHandler(editor);
131     
132     // Getter for key handler
133     this.getKeyHandler = function()
134     {
135         return keyHandler;
136     };
137 
138     // Shows dialog if changes are lost
139     window.onbeforeunload = function()
140     {
141         if (editor.modified)
142         {
143             //return mxResources.get(\'allChangesLost\');
144         }
145     };
146 
147     // Updates the editor UI after the window has been resized
148        mxEvent.addListener(window, \'resize\', mxUtils.bind(this, function()
149        {
150            this.refresh();
151            graph.sizeDidChange();
152            this.editor.outline.update(false);
153            this.editor.outline.outline.sizeDidChange();
154        }));
155 
156     // Updates action and menu states
157        this.init();
158        this.open();
159 };
160 
161 /**
162  * Specifies the size of the split bar.
163  */
164 EditorUi.prototype.splitSize = (mxClient.IS_TOUCH) ? 16 : 8;
165 
166 /**
167  * Specifies the height of the menubar. Default is 34.
168  */
169 EditorUi.prototype.menubarHeight = 34;
170 
171 /**
172  * Specifies the height of the toolbar. Default is 46.
173  */
174 EditorUi.prototype.toolbarHeight = 46;
175 
176 /**
177  * Specifies the height of the footer. Default is 28.
178  */
179 EditorUi.prototype.footerHeight = 28;
180 
181 /**
182  * Specifies the position of the horizontal split bar. Default is 190.
183  */
184 EditorUi.prototype.hsplitPosition = 190;
185 
186 /**
187  * Specifies the position of the vertical split bar. Default is 190.
188  */
189 EditorUi.prototype.vsplitPosition = 190;
190 
191 /**
192  * Installs the listeners to update the action states.
193  */
194 EditorUi.prototype.init = function()
195 {
196     // Updates action states
197     this.addUndoListener();
198     this.addSelectionListener();
199 
200     // Overrides clipboard to update paste action state
201     var paste = this.actions.get(\'paste\');
202     
203     var updatePaste = function()
204     {
205         paste.setEnabled(!mxClipboard.isEmpty());
206     };
207     
208     var mxClipboardCut = mxClipboard.cut;
209     mxClipboard.cut = function()
210     {
211         mxClipboardCut.apply(this, arguments);
212         updatePaste();
213     };
214     
215     var mxClipboardCopy = mxClipboard.copy;
216     mxClipboard.copy = function()
217     {
218         mxClipboardCopy.apply(this, arguments);
219         updatePaste();
220     };
221 };
222 
223 /**
224  * Hook for allowing selection and context menu for certain events.
225  */
226 EditorUi.prototype.isSelectionAllowed = function(evt)
227 {
228     return false;
229 };
230 
231 /**
232  * Opens the current diagram via the window.opener if one exists.
233  */
234 EditorUi.prototype.open = function()
235 {
236     // Cross-domain window access is not allowed in FF, so if we
237     // were opened from another domain then this will fail.
238     try
239     {
240         if (window.opener != null && window.opener.openFile != null)
241         {
242             window.opener.openFile.setConsumer(mxUtils.bind(this, function(xml, filename)
243             {
244                 try
245                 {
246                     var doc = mxUtils.parseXml(xml); 
247                     this.editor.setGraphXml(doc.documentElement);
248                     this.editor.modified = false;
249                     this.editor.undoManager.clear();
250                     
251                     if (filename != null)
252                     {
253                         this.editor.filename = filename;
254                     }
255                 }
256                 catch (e)
257                 {
258                     mxUtils.alert(mxResources.get(\'invalidOrMissingFile\') + \': \' + e.message);
259                 }
260             }));
261         }
262     }
263     catch(e)
264     {
265         // ignore
266     }
267 };
268 
269 /**
270  * 在給定的檔案名儲存目前圖。
271  */
272 EditorUi.prototype.save = function()
273 {
274     var xml = mxUtils.getXml(this.editor.getGraphXml());
275     //火狐浏覽器
276     //if (navigator.userAgent.indexOf(\'Firefox\') >= 0){
277     //}
278     xml="<mxGraphModel grid=\"0\" guides=\"1\" tooltips=\"1\" connect=\"1\" fold=\"1\" page=\"0\" pageScale=\"1\" pageWidth=\"826\" pageHeight=\"1169\">"+xml+"</mxGraphModel>"
279     
280     //将xml代碼儲存至伺服器檔案
281     $.post($("#path").val()+"/SaveToXmlServlet",{"tp":$("#mapTp").val(),"xml":xml,"type":"set"},function(text){
282         if(text=="0"){
283             alert("儲存失敗!");
284         }
285     });
286 };
287 
288 /**
289  * 傳回一個拷貝沒有狀态這個編輯器的URL。
290  */
291 EditorUi.prototype.getUrl = function(pathname)
292 {
293     var href = (pathname != null) ? pathname : window.location.pathname;
294     var parms = (pathname.indexOf(\'?\') > 0) ? 1 : 0;
295     
296     // Removes template URL parameter for new blank diagram
297     for (var key in urlParams)
298     {
299         if (parms == 0)
300         {
301             href += \'?\';
302         }
303         else
304         {
305             href += \'&\';
306         }
307     
308         href += key + \'=\' + urlParams[key];
309         parms++;
310     }
311     
312     return href;
313 };
314 
315 /**
316  * 更新的撤銷/重做項的狀态。
317  */
318 EditorUi.prototype.addUndoListener = function()
319 {
320     var undo = this.actions.get(\'undo\');
321     var redo = this.actions.get(\'redo\');
322     
323     var undoMgr = this.editor.undoManager;
324     
325     var undoListener = function()
326     {
327         undo.setEnabled(undoMgr.canUndo());
328         redo.setEnabled(undoMgr.canRedo());
329     };
330 
331     undoMgr.addListener(mxEvent.ADD, undoListener);
332     undoMgr.addListener(mxEvent.UNDO, undoListener);
333     undoMgr.addListener(mxEvent.REDO, undoListener);
334     undoMgr.addListener(mxEvent.CLEAR, undoListener);
335     
336     // Updates the button states once
337     undoListener();
338 };
339 
340 /**
341  * Updates the states of the given toolbar items based on the selection.
342  */
343 EditorUi.prototype.addSelectionListener = function()
344 {
345     var selectionListener = mxUtils.bind(this, function()
346     {
347         var graph = this.editor.graph;
348         var selected = !graph.isSelectionEmpty();
349         var vertexSelected = false;
350         var edgeSelected = false;
351 
352         var cells = graph.getSelectionCells();
353         
354         if (cells != null)
355         {
356             for (var i = 0; i < cells.length; i++)
357             {
358                 var cell = cells[i];
359                 
360                 if (graph.getModel().isEdge(cell))
361                 {
362                     edgeSelected = true;
363                 }
364                 
365                 if (graph.getModel().isVertex(cell))
366                 {
367                     vertexSelected = true;
368                 }
369                 
370                 if (edgeSelected && vertexSelected)
371                 {
372                     break;
373                 }
374             }
375         }
376         
377         // 更新動作狀态
378         var actions = [\'cut\', \'copy\', \'delete\', \'duplicate\', \'bold\', \'italic\', \'style\', \'fillColor\',
379                        \'gradientColor\', \'underline\', \'fontColor\', \'strokeColor\', \'backgroundColor\',
380                        \'borderColor\', \'toFront\', \'toBack\', \'dashed\', \'rounded\', \'shadow\', \'rotate\',
381                        \'autosize\'];
382         
383         for (var i = 0; i < actions.length; i++)
384         {
385             this.actions.get(actions[i]).setEnabled(selected);
386         }
387         
388         this.actions.get(\'rotation\').setEnabled(vertexSelected);
389            this.actions.get(\'group\').setEnabled(graph.getSelectionCount() > 1);
390            this.actions.get(\'ungroup\').setEnabled(graph.getSelectionCount() == 1 &&
391                    graph.getModel().getChildCount(graph.getSelectionCell()) > 0);
392            var oneVertexSelected = vertexSelected && graph.getSelectionCount() == 1;
393            this.actions.get(\'removeFromGroup\').setEnabled(oneVertexSelected &&
394                    graph.getModel().isVertex(graph.getModel().getParent(graph.getSelectionCell())));
395 
396         //更新菜單狀态 
397         var menus = [\'fontFamily\', \'fontSize\', \'alignment\', \'position\', \'text\', \'format\',
398             \'arrange\', \'linewidth\', \'spacing\', \'gradient\'];
399 
400         for (var i = 0; i < menus.length; i++)
401         {
402             this.menus.get(menus[i]).setEnabled(selected);
403         }
404         
405         menus = [\'line\', \'lineend\', \'linestart\'];
406 
407          for (var i = 0; i < menus.length; i++)
408          {
409              this.menus.get(menus[i]).setEnabled(edgeSelected);
410          }
411          
412            this.actions.get(\'setAsDefaultEdge\').setEnabled(edgeSelected);
413             
414         this.menus.get(\'align\').setEnabled(graph.getSelectionCount() > 1);
415         this.menus.get(\'direction\').setEnabled(vertexSelected || (edgeSelected &&
416                 graph.isLoop(graph.view.getState(graph.getSelectionCell()))));
417         this.menus.get(\'navigation\').setEnabled(graph.foldingEnabled && ((graph.view.currentRoot != null) ||
418                 (graph.getSelectionCount() == 1 && graph.isValidRoot(graph.getSelectionCell()))));
419         this.actions.get(\'home\').setEnabled(graph.view.currentRoot != null);
420         this.actions.get(\'exitGroup\').setEnabled(graph.view.currentRoot != null);
421         var groupEnabled = graph.getSelectionCount() == 1 && graph.isValidRoot(graph.getSelectionCell());
422         this.actions.get(\'enterGroup\').setEnabled(groupEnabled);
423         this.actions.get(\'expand\').setEnabled(groupEnabled);
424         this.actions.get(\'collapse\').setEnabled(groupEnabled);
425         this.actions.get(\'editLink\').setEnabled(graph.getSelectionCount() == 1);
426         this.actions.get(\'openLink\').setEnabled(graph.getSelectionCount() == 1 &&
427                 graph.getLinkForCell(graph.getSelectionCell()) != null);
428     });
429         
430     this.editor.graph.getSelectionModel().addListener(mxEvent.CHANGE, selectionListener);
431     selectionListener();
432 };
433 
434 /**
435  * Refreshes the viewport.
436  */
437 EditorUi.prototype.refresh = function()
438 {
439     var quirks = mxClient.IS_IE && (document.documentMode == null || document.documentMode == 5);
440     var w = this.container.clientWidth;
441     var h = this.container.clientHeight;
442 
443     if (this.container == document.body)
444     {
445         w = document.body.clientWidth || document.documentElement.clientWidth;
446         h = (quirks) ? document.body.clientHeight || document.documentElement.clientHeight : document.documentElement.clientHeight;
447     }
448     
449     var effHsplitPosition = Math.max(0, Math.min(this.hsplitPosition, w - this.splitSize - 20));
450     var effVsplitPosition = Math.max(0, Math.min(this.vsplitPosition, h - this.menubarHeight - this.toolbarHeight - this.footerHeight - this.splitSize - 1));
451     
452     this.menubarContainer.style.height = this.menubarHeight + \'px\';
453     this.toolbarContainer.style.top = this.menubarHeight + \'px\';
454     this.toolbarContainer.style.height = this.toolbarHeight + \'px\';
455     this.sidebarContainer.style.top = (this.menubarHeight + this.toolbarHeight) + \'px\';
456     this.sidebarContainer.style.width = effHsplitPosition + \'px\';
457     this.outlineContainer.style.width = effHsplitPosition + \'px\';
458     this.outlineContainer.style.height = effVsplitPosition + \'px\';
459     this.outlineContainer.style.bottom = this.footerHeight + \'px\';
460     this.diagramContainer.style.left = (effHsplitPosition + this.splitSize) + \'px\';
461     this.diagramContainer.style.top = this.sidebarContainer.style.top;
462     this.footerContainer.style.height = this.footerHeight + \'px\';
463     this.hsplit.style.top = this.sidebarContainer.style.top;
464     this.hsplit.style.bottom = this.outlineContainer.style.bottom;
465     this.hsplit.style.left = effHsplitPosition + \'px\';
466     this.vsplit.style.width = this.sidebarContainer.style.width;
467     this.vsplit.style.bottom = (effVsplitPosition + this.footerHeight) + \'px\';
468     
469     if (quirks)
470     {
471         this.menubarContainer.style.width = w + \'px\';
472         this.toolbarContainer.style.width = this.menubarContainer.style.width;
473         var sidebarHeight = (h - effVsplitPosition - this.splitSize - this.footerHeight - this.menubarHeight - this.toolbarHeight);
474         this.sidebarContainer.style.height = sidebarHeight + \'px\';
475         this.diagramContainer.style.width = (w - effHsplitPosition - this.splitSize) + \'px\';
476         var diagramHeight = (h - this.footerHeight - this.menubarHeight - this.toolbarHeight);
477         this.diagramContainer.style.height = diagramHeight + \'px\';
478         this.footerContainer.style.width = this.menubarContainer.style.width;
479         this.hsplit.style.height = diagramHeight + \'px\';
480     }
481     else
482     {
483         this.sidebarContainer.style.bottom = (effVsplitPosition + this.splitSize + this.footerHeight) + \'px\';
484         this.diagramContainer.style.bottom = this.outlineContainer.style.bottom;
485     }
486 };
487 
488 /**
489  * Creates the required containers.
490  */
491 EditorUi.prototype.createDivs = function()
492 {
493     this.menubarContainer = this.createDiv(\'geMenubarContainer\');
494     this.toolbarContainer = this.createDiv(\'geToolbarContainer\');
495     this.sidebarContainer = this.createDiv(\'geSidebarContainer\');
496     this.outlineContainer = this.createDiv(\'geOutlineContainer\');
497     this.diagramContainer = this.createDiv(\'geDiagramContainer\');
498     this.footerContainer = this.createDiv(\'geFooterContainer\');
499     this.hsplit = this.createDiv(\'geHsplit\');
500     this.vsplit = this.createDiv(\'geVsplit\');
501 
502     // Sets static style for containers
503     this.menubarContainer.style.top = \'0px\';
504     this.menubarContainer.style.left = \'0px\';
505     this.menubarContainer.style.right = \'0px\';
506     this.toolbarContainer.style.left = \'0px\';
507     this.toolbarContainer.style.right = \'0px\';
508     this.sidebarContainer.style.left = \'0px\';
509     this.outlineContainer.style.left = \'0px\';
510     this.diagramContainer.style.right = \'0px\';
511     this.footerContainer.style.left = \'0px\';
512     this.footerContainer.style.right = \'0px\';
513     this.footerContainer.style.bottom = \'0px\';
514     this.vsplit.style.left = \'0px\';
515     this.vsplit.style.height = this.splitSize + \'px\';
516     this.hsplit.style.width = this.splitSize + \'px\';
517 };
518 
519 /**
520  * Creates the required containers.
521  */
522 EditorUi.prototype.createUi = function()
523 {
524     // Creates menubar
525     this.menubar = this.menus.createMenubar(this.createDiv(\'geMenubar\'));
526     this.menubarContainer.appendChild(this.menubar.container);
527     
528     // Creates toolbar
529     this.toolbar = this.createToolbar(this.createDiv(\'geToolbar\'));
530     this.toolbarContainer.appendChild(this.toolbar.container);
531     
532     // Creates the sidebar
533     this.sidebar = this.createSidebar(this.sidebarContainer);
534 
535     // Creates the footer
536     this.footerContainer.appendChild(this.createFooter());
537 
538     // Adds status bar in menubar
539     this.statusContainer = this.createStatusContainer();
540 
541     // Connects the status bar to the editor status
542     this.editor.addListener(\'statusChanged\', mxUtils.bind(this, function()
543     {
544         this.setStatusText(this.editor.getStatus());
545     }));
546     
547     this.setStatusText(this.editor.getStatus());
548     this.menubar.container.appendChild(this.statusContainer);
549     
550     // Inserts into DOM
551     this.container.appendChild(this.menubarContainer);
552     this.container.appendChild(this.toolbarContainer);
553     this.container.appendChild(this.sidebarContainer);
554     this.container.appendChild(this.outlineContainer);
555     this.container.appendChild(this.diagramContainer);
556     this.container.appendChild(this.footerContainer);
557     this.container.appendChild(this.hsplit);
558     this.container.appendChild(this.vsplit);
559     
560     // HSplit
561     this.addSplitHandler(this.hsplit, true, 0, mxUtils.bind(this, function(value)
562     {
563         this.hsplitPosition = value;
564         this.refresh();
565         this.editor.graph.sizeDidChange();
566         this.editor.outline.update(false);
567         this.editor.outline.outline.sizeDidChange();
568     }));
569 
570     // VSplit
571     this.addSplitHandler(this.vsplit, false, this.footerHeight, mxUtils.bind(this, function(value)
572     {
573         this.vsplitPosition = value;
574         this.refresh();
575         this.editor.outline.update(false);
576         this.editor.outline.outline.sizeDidChange();
577     }));
578 };
579 
580 /**
581  * Creates a new toolbar for the given container.
582  */
583 EditorUi.prototype.createStatusContainer = function()
584 {
585     var container = document.createElement(\'a\');
586     container.className = \'geItem geStatus\';
587     
588     return container;
589 };
590 
591 /**
592  * Creates a new toolbar for the given container.
593  */
594 EditorUi.prototype.setStatusText = function(value)
595 {
596     this.statusContainer.innerHTML = value;
597 };
598 
599 /**
600  * Creates a new toolbar for the given container.
601  */
602 EditorUi.prototype.createToolbar = function(container)
603 {
604     return new Toolbar(this, container);
605 };
606 
607 /**
608  * Creates a new sidebar for the given container.
609  */
610 EditorUi.prototype.createSidebar = function(container)
611 {
612     return new Sidebar(this, container);
613 };
614 
615 /**
616  * Creates and returns a new footer.
617  */
618 EditorUi.prototype.createFooter = function()
619 {
620     return this.createDiv(\'geFooter\');
621 };
622 
623 /**
624  * Creates the actual toolbar for the toolbar container.
625  */
626 EditorUi.prototype.createDiv = function(classname)
627 {
628     var elt = document.createElement(\'div\');
629     elt.className = classname;
630     
631     return elt;
632 };
633 
634 /**
635  * Updates the states of the given undo/redo items.
636  */
637 EditorUi.prototype.addSplitHandler = function(elt, horizontal, dx, onChange)
638 {
639     var start = null;
640     var initial = null;
641     
642     function getValue()
643     {
644         return parseInt(((horizontal) ? elt.style.left : elt.style.bottom));
645     }
646 
647     var md = (mxClient.IS_TOUCH) ? \'touchstart\' : \'mousedown\';
648     var mm = (mxClient.IS_TOUCH) ? \'touchmove\' : \'mousemove\';
649     var mu = (mxClient.IS_TOUCH) ? \'touchend\' : \'mouseup\';
650     
651     mxEvent.addListener(elt, md, function(evt)
652     {
653         start = new mxPoint(mxEvent.getClientX(evt), mxEvent.getClientY(evt));
654         initial = getValue();
655         mxEvent.consume(evt);
656     });
657     
658     function moveHandler(evt)
659     {
660         if (start != null)
661         {
662             var pt = new mxPoint(mxEvent.getClientX(evt), mxEvent.getClientY(evt));
663             onChange(Math.max(0, initial + ((horizontal) ? (pt.x - start.x) : (start.y - pt.y)) - dx));
664             mxEvent.consume(evt);
665         }
666     }
667     
668     mxEvent.addListener(document, mm, moveHandler);
669     
670     mxEvent.addListener(document, mu, function(evt)
671     {
672         moveHandler(evt);
673         start = null;
674         initial = null;
675     });
676 };
677 
678 /**
679  * Displays a print dialog.
680  */
681 EditorUi.prototype.showDialog = function(elt, w, h, modal, closable, onClose)
682 {
683     this.hideDialog();
684     this.dialog = new Dialog(this, elt, w, (mxClient.IS_VML) ? h - 12 : h, modal, closable, onClose);
685 };
686 
687 /**
688  * Displays a print dialog.
689  */
690 EditorUi.prototype.hideDialog = function()
691 {
692     if (this.dialog != null)
693     {
694         this.dialog.close();
695         this.dialog = null;
696         this.editor.graph.container.focus();
697     }
698 };
699 
700 /**
701  * Adds the label menu items to the given menu and parent.
702  */
703 EditorUi.prototype.openFile = function()
704 {
705     // Closes dialog after open
706     window.openFile = new OpenFile(mxUtils.bind(this, function()
707     {
708         this.hideDialog();
709     }));
710 
711     // Removes openFile if dialog is closed
712     this.showDialog(new OpenDialog(this).container, 300, 180, true, true, function()
713     {
714         window.openFile = null;
715     });
716 };
717 
718 /**
719  * Adds the label menu items to the given menu and parent.
720  */
721 EditorUi.prototype.saveFile = function(forceDialog)
722 {
723     if (!forceDialog && this.editor.filename != null)
724     {
725         this.save(this.editor.getOrCreateFilename());
726     }
727     else
728     {
729         this.showDialog(new SaveDialog(this).container, 300, 100, true, true);
730     }
731 };
732 
733 /**
734  * Executes the given layout.
735  */
736 EditorUi.prototype.executeLayout = function(layout, animate, ignoreChildCount)
737 {
738     var graph = this.editor.graph;
739     var cell = graph.getSelectionCell();
740 
741     graph.getModel().beginUpdate();
742     try
743     {
744         layout.execute(graph.getDefaultParent(), cell);
745     }
746     catch (e)
747     {
748         throw e;
749     }
750     finally
751     {
752         // Animates the changes in the graph model except
753         // for Camino, where animation is too slow
754         if (animate && navigator.userAgent.indexOf(\'Camino\') < 0)
755         {
756             // New API for animating graph layout results asynchronously
757             var morph = new mxMorphing(graph);
758             morph.addListener(mxEvent.DONE, mxUtils.bind(this, function()
759             {
760                 graph.getModel().endUpdate();
761             }));
762             
763             morph.startAnimation();
764         }
765         else
766         {
767             graph.getModel().endUpdate();
768         }
769     }
770 };
771 
772 /**
773  * Creates the keyboard event handler for the current graph and history.
774  */
775 EditorUi.prototype.createKeyHandler = function(editor)
776 {
777     var graph = this.editor.graph;
778     var keyHandler = new mxKeyHandler(graph);
779     
780     // Routes command-key to control-key on Mac
781     keyHandler.isControlDown = function(evt)
782     {
783         return mxEvent.isControlDown(evt) || (mxClient.IS_MAC && evt.metaKey);
784     };
785     
786     // Helper function to move cells with the cursor keys
787     function nudge(keyCode)
788     {
789         if (!graph.isSelectionEmpty())
790         {
791             var dx = 0;
792             var dy = 0;
793             
794             if (keyCode == 37)
795             {
796                 dx = -1;
797             }
798             else if (keyCode == 38)
799             {
800                 dy = -1;
801             }
802             else if (keyCode == 39)
803             {
804                 dx = 1;
805             }
806             else if (keyCode == 40)
807             {
808                 dy = 1;
809             }
810             
811             graph.moveCells(graph.getSelectionCells(), dx, dy);
812             graph.scrollCellVisible(graph.getSelectionCell());
813         }
814     };
815 
816     // Binds keystrokes to actions
817     var bindAction = mxUtils.bind(this, function(code, control, key, shift)
818     {
819         var action = this.actions.get(key);
820         
821         if (action != null)
822         {
823             var f = function()
824             {
825                 if (action.enabled)
826                 {
827                     action.funct();
828                 }
829             };
830             
831             if (control)
832             {
833                 if (shift)
834                 {
835                     keyHandler.bindControlShiftKey(code, f);
836                 }
837                 else
838                 {
839                     keyHandler.bindControlKey(code, f);
840                 }
841             }
842             else
843             {
844                 if (shift)
845                 {
846                     keyHandler.bindShiftKey(code, f);
847                 }
848                 else
849                 {
850                     keyHandler.bindKey(code, f);
851                 }
852             }
853         }
854     });
855     
856     var ui = this;
857     var keyHandleEscape = keyHandler.escape;
858     keyHandler.escape = function(evt)
859     {
860         ui.hideDialog();
861         keyHandleEscape.apply(this, arguments);
862     };
863     
864     // Ignores enter keystroke. Remove this line if you want the
865     // enter keystroke to stop editing.
866     keyHandler.enter = function() {};
867     keyHandler.bindKey(8, function() { graph.foldCells(true); }); // Backspace
868     keyHandler.bindKey(13, function() { graph.foldCells(false); }); // Enter
869     keyHandler.bindKey(33, function() { graph.exitGroup(); }); // Page Up
870     keyHandler.bindKey(34, function() { graph.enterGroup(); }); // Page Down
871     keyHandler.bindKey(36, function() { graph.home(); }); // Home
872     keyHandler.bindKey(35, function() { graph.refresh(); }); // End
873     keyHandler.bindKey(37, function() { nudge(37); }); // Left arrow
874     keyHandler.bindKey(38, function() { nudge(38); }); // Up arrow
875     keyHandler.bindKey(39, function() { nudge(39); }); // Right arrow
876     keyHandler.bindKey(40, function() { nudge(40); }); // Down arrow
877     keyHandler.bindKey(113, function() { graph.startEditingAtCell(); });
878     bindAction(46, false, \'delete\'); // Delete
879     bindAction(82, true, \'rotate\'); // Ctrl+R
880     bindAction(83, true, \'save\'); // Ctrl+S
881     bindAction(83, true, \'saveAs\', true); // Ctrl+Shift+S
882     bindAction(107, false, \'zoomIn\'); // Add
883     bindAction(109, false, \'zoomOut\'); // Subtract
884     bindAction(65, true, \'selectAll\'); // Ctrl+A
885     bindAction(86, true, \'selectVertices\', true); // Ctrl+Shift+V
886     bindAction(69, true, \'selectEdges\', true); // Ctrl+Shift+E
887     bindAction(69, true, \'export\'); // Ctrl+Shift+E
888     bindAction(66, true, \'toBack\'); // Ctrl+B
889     bindAction(70, true, \'toFront\'); // Ctrl+F
890     bindAction(68, true, \'duplicate\'); // Ctrl+D
891     bindAction(90, true, \'undo\'); // Ctrl+Z
892     bindAction(89, true, \'redo\'); // Ctrl+Y
893     bindAction(88, true, \'cut\'); // Ctrl+X
894     bindAction(67, true, \'copy\'); // Ctrl+C
895     bindAction(81, true, \'connect\'); // Ctrl+Q
896     bindAction(86, true, \'paste\'); // Ctrl+V
897     bindAction(71, true, \'group\'); // Ctrl+G
898     bindAction(71, true, \'grid\', true); // Ctrl+Shift+G
899     bindAction(85, true, \'ungroup\'); // Ctrl+U
900     bindAction(112, false, \'about\'); // F1
901     
902     return keyHandler;
903 };      

View Code

基于Web實作網絡拓撲圖

這裡是圖形化操作以後儲存拓撲對于的Xml檔案,便于再次通路,或者檢視的時候加載原資訊!

如操作功能:

基于Web實作網絡拓撲圖

對應的通過上面EditorUi.js檔案中EditorUi.prototype.save = function()控制,我是通過一個Servlet來儲存XML檔案

基于Web實作網絡拓撲圖
基于Web實作網絡拓撲圖
1 package com.visec.systemConfig;
 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  * <p>Title: 網絡拓撲圖儲存</p>
14  * <p>Description: 将網絡拓撲圖儲存至對應的xml檔案中  以及  讀取網絡拓撲圖對應的xml檔案</p>
15  * <p>Copyright: Copyright (c) 2015</p>
16  * <p>Company: XXX科技</p>
17  * @author 李尚志
18  * @version 3.0
19  */
20 public class SaveToXmlServlet extends HttpServlet {
21     private static final long serialVersionUID = 1L;
22     public void doGet(HttpServletRequest request, HttpServletResponse response)
23             throws ServletException, IOException {
24         doPost(request,response);
25     }
26     public void doPost(HttpServletRequest request, HttpServletResponse response)
27             throws ServletException, IOException {
28         response.setContentType("text/html;charset=utf-8");
29         response.setCharacterEncoding("utf-8");
30         request.setCharacterEncoding("utf-8");
31         String type = request.getParameter("type");
32         String tp = request.getParameter("tp");
33         StringBuffer result = new StringBuffer("");
34         String xmlPath=new String("");
35         String strPath = this.getClass().getResource("/").toString();
36         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";
37         String osName = System.getProperties().getProperty("os.name");
38         if(osName.toLowerCase().indexOf("windows")>-1){
39             strPath=strPath.substring(6)+xmlPath;
40         }else{
41             strPath=strPath.substring(5)+xmlPath;
42         }
43         File file = new File(strPath);
44         if(file.isFile()){//判斷該路徑是否為一個檔案
45             if("set".equals(type.toLowerCase())){//檔案儲存
46                 String xml = request.getParameter("xml");
47                 if(xml==null||"".equals(xml)){
48                     result.append("0");
49                 }else{
50                     RandomAccessFile randomAccessFile = new RandomAccessFile(strPath, "rw");
51                     randomAccessFile.seek(0);
52                     randomAccessFile.setLength(0);
53                     randomAccessFile.write(xml.getBytes());
54                     randomAccessFile.close();
55                     result.append("1");
56                 }
57             }else if("get".equals(type.toLowerCase())){//擷取檔案資訊
58                 //開始讀取
59                 BufferedReader reader = new BufferedReader(new FileReader(new File(strPath)));
60                 String tempString = null;
61                 // 一次讀入一行,直到讀入null為檔案結束
62                 while ((tempString = reader.readLine()) != null){
63                     result.append(tempString);
64                 }
65                 reader.close();
66             }
67         }else{
68             System.out.println(strPath+" 找不到!");
69             result.append("0");
70         }
71         PrintWriter out = response.getWriter();
72         out.write(result.toString());
73         out.flush();
74         out.close();
75     }
76 
77 }      

View Code

 當我們再次通路編輯頁面時,即要加載先前對應的XML檔案

主要檔案( Actions.js和上述Servlet中get方法)

Servlet在此處省略(上述中已提供源碼)

Actions.js源碼

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

View Code

基于Web實作網絡拓撲圖

工具欄~Sidebar.js

基于Web實作網絡拓撲圖

如:圖示A區 ,圖示B區的控制

源碼:

基于Web實作網絡拓撲圖
基于Web實作網絡拓撲圖
1 /**
   2 *$id:Action 。JS,V 2015-3-23
   3 *$author Dana丶Li$
   4 */
   5 /**
   6  * Construcs a new sidebar for the given editor.
   7  */
   8 function Sidebar(editorUi, container)
   9 {
  10     this.editorUi = editorUi;
  11     this.container = container;
  12     this.palettes = new Object();
  13     this.showTooltips = true;
  14     this.graph = new Graph(document.createElement(\'div\'), null, null, this.editorUi.editor.graph.getStylesheet());
  15     this.graph.foldingEnabled = false;
  16     this.graph.autoScroll = false;
  17     this.graph.setTooltips(false);
  18     this.graph.setConnectable(false);
  19     this.graph.resetViewOnRootChange = false;
  20     this.graph.view.setTranslate(this.thumbBorder, this.thumbBorder);
  21     this.graph.setEnabled(false);
  22 
  23     // Workaround for VML rendering in IE8 standards mode where the container must be in the DOM
  24     // so that VML references can be restored via document.getElementById in mxShape.init.
  25     if (document.documentMode == 8)
  26     {
  27         document.body.appendChild(this.graph.container);
  28     }
  29     
  30     // Workaround for no rendering in 0 coordinate in FF 10
  31     if (this.shiftThumbs)
  32     {
  33         this.graph.view.canvas.setAttribute(\'transform\', \'translate(1, 1)\');
  34     }
  35     
  36     if (!mxClient.IS_TOUCH)
  37     {
  38         mxEvent.addListener(document, \'mouseup\', mxUtils.bind(this, function()
  39         {
  40             this.showTooltips = true;
  41         }));
  42     
  43         // Enables tooltips after scroll
  44         mxEvent.addListener(container, \'scroll\', mxUtils.bind(this, function()
  45         {
  46             this.showTooltips = true;
  47         }));
  48         
  49         mxEvent.addListener(document, \'mousedown\', mxUtils.bind(this, function()
  50         {
  51             this.showTooltips = false;
  52             this.hideTooltip();
  53         }));
  54 
  55         mxEvent.addListener(document, \'mousemove\', mxUtils.bind(this, function(evt)
  56         {
  57             var src = mxEvent.getSource(evt);
  58             
  59             while (src != null)
  60             {
  61                 if (src == this.currentElt)
  62                 {
  63                     return;
  64                 }
  65                 
  66                 src = src.parentNode;
  67             }
  68             
  69             this.hideTooltip();
  70         }));
  71 
  72         // Handles mouse leaving the window
  73         mxEvent.addListener(document, \'mouseout\', mxUtils.bind(this, function(evt)
  74         {
  75             if (evt.toElement == null && evt.relatedTarget == null)
  76             {
  77                 this.hideTooltip();
  78             }
  79         }));
  80     }
  81     
  82     this.init();
  83     
  84     //圖像預fetches提示 
  85     new Image().src = IMAGE_PATH + \'/tooltip.png\';
  86 };
  87 
  88 /**
  89  * 将所有工具欄的側邊欄。
  90  */
  91 Sidebar.prototype.init = function()
  92 {
  93     var dir = STENCIL_PATH;
  94     
  95     //this.addGeneralPalette(true);
  96     //this.addUmlPalette(true);
  97     //this.addBpmnPalette(dir, false);
  98     //this.addStencilPalette(\'flowchart\', \'Flowchart\', dir + \'/flowchart.xml\',\';fillColor=#ffffff;strokeColor=#000000;strokeWidth=2\');
  99     //this.addStencilPalette(\'basic\', mxResources.get(\'basic\'), dir + \'/basic.xml\',\';fillColor=#ffffff;strokeColor=#000000;strokeWidth=2\');
 100     //this.addStencilPalette(\'arrows\', mxResources.get(\'arrows\'), dir + \'/arrows.xml\',\';fillColor=#ffffff;strokeColor=#000000;strokeWidth=2\');
 101     
 102     this.addImagePalette(\'clipart\', mxResources.get(\'clipart\'), dir + \'/clipart/\', \'_128x128.png\',
 103         [ \'colud\',  \'Firewall_02\', \'Server_Tower\',  \'serverDB\', \'serverAuth\', 
 104         \'serverPrint\', \'serverEmail\', \'serverDisk\', \'Router_Icon\', \'routerFirewall\', \'route1\', \'atm\', \'police\', 
 105           \'accessServer\',\'SIP\', \'sipProxy\', \'ITP\', \'CA\', \'3U\', \'ipv6Route\', 
 106         \'3layer\', \'pbx\', \'IDS\', \'actionCheck\', \'gateWay***\', \'server1\',\'server2\',\'normalServer\',\'IPSAN\',\'H3Cswitch\']);
 107         
 108     this.addImagePalette(\'clipartB\', mxResources.get(\'clipartB\'), dir + \'/clipart/\', \'.png\',
 109         [ \'pic1\',\'pic2\',\'pic3\',\'pic4\',\'pic5\',\'pic6\',\'pic7\',\'pic8\',\'pic9\',\'pic10\',\'pic11\',\'pic12\',\'pic13\',\'pic14\',\'pic15\']);
 110 
 111 };
 112 
 113 /**
 114  * 指定工具提示應該是可見的。預設的是真的。
 115  */
 116 Sidebar.prototype.enableTooltips = !mxClient.IS_TOUCH;
 117 
 118 /**
 119  * 将縮略圖1像素。
 120  */
 121 Sidebar.prototype.shiftThumbs = mxClient.IS_SVG || document.documentMode == 8;
 122 
 123 /**
 124  * 指定工具提示的延遲。預設是16像素。
 125  */
 126 Sidebar.prototype.tooltipBorder = 16;
 127 
 128 /**
 129  * 指定工具提示的延遲。預設是2像素。
 130  */
 131 Sidebar.prototype.thumbBorder = 2;
 132 
 133 /**
 134  * Specifies the delay for the tooltip. Default is 300 ms.
 135  */
 136 Sidebar.prototype.tooltipDelay = 300;
 137 
 138 /**
 139  * Specifies if edges should be used as templates if clicked. Default is true.
 140  */
 141 Sidebar.prototype.installEdges = true;
 142 
 143 /**
 144  * Specifies the URL of the gear image.
 145  */
 146 Sidebar.prototype.gearImage = STENCIL_PATH + \'/clipart/Gear_128x128.png\';
 147 
 148 /**
 149  * Specifies the width of the thumbnails.
 150  */
 151 Sidebar.prototype.thumbWidth = 26;
 152 
 153 /**
 154  * Specifies the height of the thumbnails.
 155  */
 156 Sidebar.prototype.thumbHeight = 26;
 157 
 158 /**
 159  * Adds all palettes to the sidebar.
 160  */
 161 Sidebar.prototype.showTooltip = function(elt, cells)
 162 {
 163     if (this.enableTooltips && this.showTooltips)
 164     {
 165         if (this.currentElt != elt)
 166         {
 167             if (this.thread != null)
 168             {
 169                 window.clearTimeout(this.thread);
 170                 this.thread = null;
 171             }
 172             
 173             var show = mxUtils.bind(this, function()
 174             {
 175                 // Workaround for off-screen text rendering in IE
 176                 var old = mxText.prototype.getTableSize;
 177                 
 178                 if (this.graph.dialect != mxConstants.DIALECT_SVG)
 179                 {
 180                     mxText.prototype.getTableSize = function(table)
 181                     {
 182                         var oldParent = table.parentNode;
 183                         
 184                         document.body.appendChild(table);
 185                         var size = new mxRectangle(0, 0, table.offsetWidth, table.offsetHeight);
 186                         oldParent.appendChild(table);
 187                         
 188                         return size;
 189                     };
 190                 }
 191                 
 192                 // Lazy creation of the DOM nodes and graph instance
 193                 if (this.tooltip == null)
 194                 {
 195                     this.tooltip = document.createElement(\'div\');
 196                     this.tooltip.className = \'geSidebarTooltip\';
 197                     document.body.appendChild(this.tooltip);
 198                     
 199                     this.graph2 = new Graph(this.tooltip, null, null, this.editorUi.editor.graph.getStylesheet());
 200                     this.graph2.view.setTranslate(this.tooltipBorder, this.tooltipBorder);
 201                     this.graph2.resetViewOnRootChange = false;
 202                     this.graph2.foldingEnabled = false;
 203                     this.graph2.autoScroll = false;
 204                     this.graph2.setTooltips(false);
 205                     this.graph2.setConnectable(false);
 206                     this.graph2.setEnabled(false);
 207                     
 208                     this.tooltipImage = mxUtils.createImage(IMAGE_PATH + \'/tooltip.png\');
 209                     this.tooltipImage.style.position = \'absolute\';
 210                     this.tooltipImage.style.width = \'14px\';
 211                     this.tooltipImage.style.height = \'27px\';
 212                     
 213                     document.body.appendChild(this.tooltipImage);                
 214                 }
 215                 
 216                 this.graph2.model.clear();
 217                 this.graph2.addCells(cells);
 218                 
 219                 var bounds = this.graph2.getGraphBounds();
 220                 var width = bounds.x + bounds.width + this.tooltipBorder;
 221                 var height = bounds.y + bounds.height + this.tooltipBorder;
 222                 
 223                 if (mxClient.IS_QUIRKS)
 224                 {
 225                     width += 4;
 226                     height += 4;
 227                 }
 228                 
 229                 this.tooltip.style.display = \'block\';
 230                 this.tooltip.style.overflow = \'visible\';
 231                 this.tooltipImage.style.visibility = \'visible\';
 232                 this.tooltip.style.width = width + \'px\';
 233                 this.tooltip.style.height = height + \'px\';
 234         
 235                 var left = this.container.clientWidth + this.editorUi.splitSize + 3;
 236                 var top = Math.max(0, (this.container.offsetTop + elt.offsetTop - this.container.scrollTop - height / 2 + 16));
 237 
 238                 // Workaround for ignored position CSS style in IE9
 239                 // (changes to relative without the following line)
 240                 this.tooltip.style.position = \'absolute\';
 241                 this.tooltip.style.left = left + \'px\';
 242                 this.tooltip.style.top = top + \'px\';
 243                 this.tooltipImage.style.left = (left - 13) + \'px\';
 244                 this.tooltipImage.style.top = (top + height / 2 - 13) + \'px\';
 245                 
 246                 mxText.prototype.getTableSize = old;
 247             });
 248 
 249             if (this.tooltip != null && this.tooltip.style.display != \'none\')
 250             {
 251                 show();
 252             }
 253             else
 254             {
 255                 this.thread = window.setTimeout(show, this.tooltipDelay);
 256             }
 257 
 258             this.currentElt = elt;
 259         }
 260     }
 261 };
 262 
 263 /**
 264  * Hides the current tooltip.
 265  */
 266 Sidebar.prototype.hideTooltip = function()
 267 {
 268     if (this.thread != null)
 269     {
 270         window.clearTimeout(this.thread);
 271         this.thread = null;
 272     }
 273     
 274     if (this.tooltip != null)
 275     {
 276         this.tooltip.style.display = \'none\';
 277         this.tooltipImage.style.visibility = \'hidden\';
 278         this.currentElt = null;
 279     }
 280 };
 281 
 282 /**
 283  * Adds the general palette to the sidebar.
 284  */
 285 Sidebar.prototype.addGeneralPalette = function(expand)
 286 {
 287     this.addPalette(\'general\', mxResources.get(\'general\'), expand || true, mxUtils.bind(this, function(content)
 288     {
 289         content.appendChild(this.createVertexTemplate(\'swimlane\', 200, 200, \'Container\'));
 290         content.appendChild(this.createVertexTemplate(\'swimlane;horizontal=0\', 200, 200, \'Pool\'));
 291         content.appendChild(this.createVertexTemplate(\'text\', 40, 26, \'Text\'));
 292         content.appendChild(this.createVertexTemplate(\'icon;image=\' + this.gearImage, 60, 60, \'Image\'));
 293         content.appendChild(this.createVertexTemplate(\'label;image=\' + this.gearImage, 140, 60, \'Label\'));
 294         content.appendChild(this.createVertexTemplate(null, 120, 60));
 295         content.appendChild(this.createVertexTemplate(\'rounded=1\', 120, 60));
 296         content.appendChild(this.createVertexTemplate(\'ellipse\', 80, 80));
 297         content.appendChild(this.createVertexTemplate(\'ellipse;shape=doubleEllipse\', 80, 80));
 298         content.appendChild(this.createVertexTemplate(\'triangle\', 60, 80));
 299         content.appendChild(this.createVertexTemplate(\'rhombus\', 80, 80));
 300         content.appendChild(this.createVertexTemplate(\'shape=hexagon\', 120, 80));
 301         content.appendChild(this.createVertexTemplate(\'shape=actor;verticalLabelPosition=bottom;verticalAlign=top\', 40, 60));
 302         content.appendChild(this.createVertexTemplate(\'ellipse;shape=cloud\', 120, 80));
 303         content.appendChild(this.createVertexTemplate(\'shape=cylinder\', 60, 80));
 304         content.appendChild(this.createVertexTemplate(\'line\', 160, 10));
 305         content.appendChild(this.createVertexTemplate(\'line;direction=south\', 10, 160));
 306         content.appendChild(this.createVertexTemplate(\'shape=xor\', 60, 80));
 307         content.appendChild(this.createVertexTemplate(\'shape=or\', 60, 80));
 308         content.appendChild(this.createVertexTemplate(\'shape=step\', 120, 80));
 309         content.appendChild(this.createVertexTemplate(\'shape=tape\', 120, 100));
 310         content.appendChild(this.createVertexTemplate(\'shape=cube\', 120, 80));
 311         content.appendChild(this.createVertexTemplate(\'shape=note\', 80, 100));
 312         content.appendChild(this.createVertexTemplate(\'shape=folder\', 120, 120));
 313         content.appendChild(this.createVertexTemplate(\'shape=card\', 60, 80));
 314         content.appendChild(this.createVertexTemplate(\'shape=plus\', 20, 20));
 315 
 316         content.appendChild(this.createEdgeTemplate(\'edgeStyle=none;endArrow=none;\', 100, 100));
 317         content.appendChild(this.createEdgeTemplate(\'edgeStyle=none\', 100, 100));
 318         content.appendChild(this.createEdgeTemplate(\'edgeStyle=elbowEdgeStyle;elbow=horizontal\', 100, 100));
 319         content.appendChild(this.createEdgeTemplate(\'edgeStyle=elbowEdgeStyle;elbow=vertical\', 100, 100));
 320         content.appendChild(this.createEdgeTemplate(\'edgeStyle=entityRelationEdgeStyle\', 100, 100));
 321         content.appendChild(this.createEdgeTemplate(\'edgeStyle=segmentEdgeStyle\', 100, 100));
 322         content.appendChild(this.createEdgeTemplate(\'edgeStyle=orthogonalEdgeStyle\', 100, 100));
 323         content.appendChild(this.createEdgeTemplate(\'shape=link\', 100, 100));
 324         content.appendChild(this.createEdgeTemplate(\'arrow\', 100, 100));
 325     }));
 326 };
 327 
 328 /**
 329  * Adds the general palette to the sidebar.
 330  */
 331 Sidebar.prototype.addUmlPalette = function(expand)
 332 {
 333     this.addPalette(\'uml\', \'UML\', expand || false, mxUtils.bind(this, function(content)
 334     {
 335         content.appendChild(this.createVertexTemplate(\'\', 110, 50, \'Object\'));
 336         
 337         var classCell = new mxCell(\'<p style="margin:0px;margin-top:4px;text-align:center;">\' +
 338                 \'<b>Class</b></p>\' +
 339                 \'<hr/><div style="height:2px;"></div><hr/>\', new mxGeometry(0, 0, 140, 60),
 340                 \'verticalAlign=top;align=left;overflow=fill;fontSize=12;fontFamily=Helvetica;html=1\');
 341         classCell.vertex = true;
 342         content.appendChild(this.createVertexTemplateFromCells([classCell], 140, 60));
 343         
 344         var classCell = new mxCell(\'<p style="margin:0px;margin-top:4px;text-align:center;">\' +
 345                 \'<b>Class</b></p>\' +
 346                 \'<hr/><p style="margin:0px;margin-left:4px;">+ field: Type</p><hr/>\' +
 347                 \'<p style="margin:0px;margin-left:4px;">+ method(): Type</p>\', new mxGeometry(0, 0, 160, 90),
 348                 \'verticalAlign=top;align=left;overflow=fill;fontSize=12;fontFamily=Helvetica;html=1\');
 349         classCell.vertex = true;
 350         content.appendChild(this.createVertexTemplateFromCells([classCell], 160, 90));
 351         
 352         var classCell = new mxCell(\'<p style="margin:0px;margin-top:4px;text-align:center;">\' +
 353                 \'<i>&lt;&lt;Interface&gt;&gt;</i><br/><b>Interface</b></p>\' +
 354                 \'<hr/><p style="margin:0px;margin-left:4px;">+ field1: Type<br/>\' +
 355                 \'+ field2: Type</p>\' +
 356                 \'<hr/><p style="margin:0px;margin-left:4px;">\' +
 357                 \'+ method1(Type): Type<br/>\' +
 358                 \'+ method2(Type, Type): Type</p>\', new mxGeometry(0, 0, 190, 140),
 359                 \'verticalAlign=top;align=left;overflow=fill;fontSize=12;fontFamily=Helvetica;html=1\');
 360         classCell.vertex = true;
 361         content.appendChild(this.createVertexTemplateFromCells([classCell], 190, 140));
 362 
 363         var classCell = new mxCell(\'Module\', new mxGeometry(0, 0, 120, 60),
 364             \'shape=component;align=left;spacingLeft=36\');
 365         classCell.vertex = true;
 366 
 367         content.appendChild(this.createVertexTemplateFromCells([classCell], 120, 60));
 368 
 369         var classCell = new mxCell(\'&lt;&lt;component&gt;&gt;<br/><b>Component</b>\', new mxGeometry(0, 0, 180, 90),
 370             \'overflow=fill;html=1\');
 371         classCell.vertex = true;
 372         var classCell1 = new mxCell(\'\', new mxGeometry(1, 0, 20, 20), \'shape=component;jettyWidth=8;jettyHeight=4;\');
 373         classCell1.vertex = true;
 374         classCell1.connectable = false;
 375         classCell1.geometry.relative = true;
 376         classCell1.geometry.offset = new mxPoint(-30, 10);
 377         classCell.insert(classCell1);
 378     
 379         content.appendChild(this.createVertexTemplateFromCells([classCell], 180, 90));
 380 
 381         var classCell = new mxCell(\'<p style="margin:0px;margin-top:6px;text-align:center;"><b>Component</b></p>\' +
 382                 \'<hr/><p style="margin:0px;margin-left:8px;">+ Attribute1: Type<br/>+ Attribute2: Type</p>\', new mxGeometry(0, 0, 180, 90),
 383             \'verticalAlign=top;align=left;overflow=fill;html=1\');
 384         classCell.vertex = true;
 385         var classCell1 = new mxCell(\'\', new mxGeometry(1, 0, 20, 20), \'shape=component;jettyWidth=8;jettyHeight=4;\');
 386         classCell1.vertex = true;
 387         classCell1.connectable = false;
 388         classCell1.geometry.relative = true;
 389         classCell1.geometry.offset = new mxPoint(-23, 3);
 390         classCell.insert(classCell1);
 391 
 392         content.appendChild(this.createVertexTemplateFromCells([classCell], 180, 90));
 393 
 394         content.appendChild(this.createVertexTemplate(\'shape=lollipop;direction=south;\', 30, 10));
 395 
 396         var cardCell = new mxCell(\'Block\', new mxGeometry(0, 0, 180, 120),
 397                 \'verticalAlign=top;align=left;spacingTop=8;spacingLeft=2;spacingRight=12;shape=cube;size=10;direction=south;fontStyle=4;\');
 398         cardCell.vertex = true;
 399         content.appendChild(this.createVertexTemplateFromCells([cardCell], 180, 120));
 400 
 401         content.appendChild(this.createVertexTemplate(\'shape=folder;fontStyle=1;spacingTop=10;tabWidth=40;tabHeight=14;tabPosition=left;\', 70, 50,
 402             \'package\'));
 403 
 404         var classCell = new mxCell(\'<p style="margin:0px;margin-top:4px;text-align:center;text-decoration:underline;">\' +
 405                 \'<b>Object:Type</b></p><hr/>\' +
 406                 \'<p style="margin:0px;margin-left:8px;">field1 = value1<br/>field2 = value2<br>field3 = value3</p>\',
 407                 new mxGeometry(0, 0, 160, 90),
 408                 \'verticalAlign=top;align=left;overflow=fill;fontSize=12;fontFamily=Helvetica;html=1\');
 409         classCell.vertex = true;
 410         content.appendChild(this.createVertexTemplateFromCells([classCell], 160, 90));
 411 
 412         var tableCell = new mxCell(\'<table cellpadding="5" style="font-size:9pt;border:none;border-collapse:collapse;width:100%;">\' +
 413                 \'<tr><td colspan="2" style="border:1px solid gray;background:#e4e4e4;">Tablename</td></tr>\' +
 414                 \'<tr><td style="border:1px solid gray;">PK</td><td style="border:1px solid gray;">uniqueId</td></tr>\' +
 415                 \'<tr><td style="border:1px solid gray;">FK1</td><td style="border:1px solid gray;">foreignKey</td></tr>\' +
 416                 \'<tr><td style="border:1px solid gray;"></td><td style="border:1px solid gray;">fieldname</td></tr>\' +
 417                 \'</table>\', new mxGeometry(0, 0, 180, 99), \'verticalAlign=top;align=left;overflow=fill;html=1\');
 418         tableCell.vertex = true;
 419         content.appendChild(this.createVertexTemplateFromCells([tableCell], 180, 99));
 420         
 421         content.appendChild(this.createVertexTemplate(\'shape=umlActor;verticalLabelPosition=bottom;verticalAlign=top\', 40, 80, \'Actor\'));
 422         content.appendChild(this.createVertexTemplate(\'ellipse\', 140, 70, \'Use Case\'));
 423 
 424         var cardCell = new mxCell(\'\', new mxGeometry(0, 0, 30, 30),
 425             \'ellipse;shape=startState;fillColor=#000000;strokeColor=#ff0000;\');
 426         cardCell.vertex = true;
 427         
 428         var assoc2 = new mxCell(\'\', new mxGeometry(0, 0, 0, 0), \'edgeStyle=elbowEdgeStyle;elbow=horizontal;verticalAlign=bottom;endArrow=open;endSize=8;strokeColor=#ff0000;\');
 429         assoc2.geometry.setTerminalPoint(new mxPoint(15, 70), false);
 430         assoc2.edge = true;
 431         
 432         cardCell.insertEdge(assoc2, true);
 433         
 434         content.appendChild(this.createVertexTemplateFromCells([cardCell, assoc2], 30, 30));
 435         
 436         var cardCell = new mxCell(\'Activity\', new mxGeometry(0, 0, 120, 40),
 437             \'rounded=1;arcSize=40;fillColor=#ffffc0;strokeColor=#ff0000;\');
 438         cardCell.vertex = true;
 439         
 440         var assoc2 = new mxCell(\'\', new mxGeometry(0, 0, 0, 0), \'edgeStyle=elbowEdgeStyle;elbow=horizontal;verticalAlign=bottom;endArrow=open;endSize=8;strokeColor=#ff0000;\');
 441         assoc2.geometry.setTerminalPoint(new mxPoint(60, 80), false);
 442         assoc2.edge = true;
 443         
 444         cardCell.insertEdge(assoc2, true);
 445         
 446         content.appendChild(this.createVertexTemplateFromCells([cardCell, assoc2], 120, 40));
 447         
 448         var cardCell = new mxCell(\'<div style="margin-top:8px;"><b>Composite State</b><hr/>Subtitle</div>\', new mxGeometry(0, 0, 160, 60),
 449             \'rounded=1;arcSize=40;overflow=fill;html=1;verticalAlign=top;fillColor=#ffffc0;strokeColor=#ff0000;\');
 450         cardCell.vertex = true;
 451         
 452         var assoc2 = new mxCell(\'\', new mxGeometry(0, 0, 0, 0), \'edgeStyle=elbowEdgeStyle;elbow=horizontal;verticalAlign=bottom;endArrow=open;endSize=8;strokeColor=#ff0000;\');
 453         assoc2.geometry.setTerminalPoint(new mxPoint(80, 100), false);
 454         assoc2.edge = true;
 455         
 456         cardCell.insertEdge(assoc2, true);
 457         
 458         content.appendChild(this.createVertexTemplateFromCells([cardCell, assoc2], 160, 60));
 459         
 460         var cardCell = new mxCell(\'Condition\', new mxGeometry(0, 0, 80, 40),
 461             \'rhombus;fillColor=#ffffc0;strokeColor=#ff0000;\');
 462         cardCell.vertex = true;
 463         
 464         var assoc1 = new mxCell(\'no\', new mxGeometry(0, 0, 0, 0), \'edgeStyle=elbowEdgeStyle;elbow=horizontal;align=left;verticalAlign=bottom;endArrow=open;endSize=8;strokeColor=#ff0000;\');
 465         assoc1.geometry.setTerminalPoint(new mxPoint(120, 20), false);
 466         assoc1.geometry.relative = true;
 467         assoc1.geometry.x = -1;
 468         assoc1.edge = true;
 469         
 470         cardCell.insertEdge(assoc1, true);
 471         
 472         var assoc2 = new mxCell(\'yes\', new mxGeometry(0, 0, 0, 0), \'edgeStyle=elbowEdgeStyle;elbow=horizontal;align=left;verticalAlign=top;endArrow=open;endSize=8;strokeColor=#ff0000;\');
 473         assoc2.geometry.setTerminalPoint(new mxPoint(40, 80), false);
 474         assoc2.geometry.relative = true;
 475         assoc2.geometry.x = -1;
 476         assoc2.edge = true;
 477         
 478         cardCell.insertEdge(assoc2, true);
 479         
 480         content.appendChild(this.createVertexTemplateFromCells([cardCell, assoc1, assoc2], 80, 40));
 481         
 482         var cardCell = new mxCell(\'\', new mxGeometry(0, 0, 200, 10),
 483             \'shape=line;strokeWidth=6;strokeColor=#ff0000;\');
 484         cardCell.vertex = true;
 485         
 486         var assoc2 = new mxCell(\'\', new mxGeometry(0, 0, 0, 0), \'edgeStyle=elbowEdgeStyle;elbow=horizontal;verticalAlign=bottom;endArrow=open;endSize=8;strokeColor=#ff0000;\');
 487         assoc2.geometry.setTerminalPoint(new mxPoint(100, 50), false);
 488         assoc2.edge = true;
 489         
 490         cardCell.insertEdge(assoc2, true);
 491     
 492         content.appendChild(this.createVertexTemplateFromCells([cardCell, assoc2], 200, 10));
 493 
 494         content.appendChild(this.createVertexTemplate(\'ellipse;shape=endState;fillColor=#000000;strokeColor=#ff0000\', 30, 30));
 495         
 496         var classCell1 = new mxCell(\':Object\', new mxGeometry(0, 0, 100, 50));
 497          classCell1.vertex = true;
 498          
 499          var classCell2 = new mxCell(\'\', new mxGeometry(40, 50, 20, 240), \'shape=line;direction=north;dashed=1\');
 500          classCell2.vertex = true;
 501          
 502         content.appendChild(this.createVertexTemplateFromCells([classCell1, classCell2], 100, 290));
 503         
 504         var classCell1 = new mxCell(\'\', new mxGeometry(100, 0, 20, 70));
 505          classCell1.vertex = true;
 506 
 507         var assoc1 = new mxCell(\'invoke\', new mxGeometry(0, 0, 0, 0), \'edgeStyle=elbowEdgeStyle;elbow=vertical;verticalAlign=bottom;endArrow=block;\');
 508         assoc1.geometry.setTerminalPoint(new mxPoint(0, 0), true);
 509         assoc1.edge = true;
 510         
 511         classCell1.insertEdge(assoc1, false);
 512 
 513         content.appendChild(this.createVertexTemplateFromCells([classCell1, assoc1], 120, 70));
 514         
 515          var classCell1 = new mxCell(\'\', new mxGeometry(100, 0, 20, 70));
 516          classCell1.vertex = true;
 517 
 518         var assoc1 = new mxCell(\'invoke\', new mxGeometry(0, 0, 0, 0), \'edgeStyle=elbowEdgeStyle;elbow=vertical;verticalAlign=bottom;endArrow=block;\');
 519         assoc1.geometry.setTerminalPoint(new mxPoint(0, 0), true);
 520         assoc1.edge = true;
 521         
 522         classCell1.insertEdge(assoc1, false);
 523         
 524         var assoc2 = new mxCell(\'return\', new mxGeometry(0, 0, 0, 0), \'edgeStyle=elbowEdgeStyle;elbow=vertical;verticalAlign=bottom;dashed=1;endArrow=open;endSize=8;\');
 525         assoc2.geometry.setTerminalPoint(new mxPoint(0, 70), false);
 526         assoc2.edge = true;
 527         
 528         classCell1.insertEdge(assoc2, true);
 529         
 530         var assoc3 = new mxCell(\'invoke\', new mxGeometry(0, 0, 0, 0), \'edgeStyle=elbowEdgeStyle;elbow=vertical;align=left;endArrow=open;\');
 531         assoc3.edge = true;
 532         
 533         classCell1.insertEdge(assoc3, true);
 534         classCell1.insertEdge(assoc3, false);
 535         
 536         content.appendChild(this.createVertexTemplateFromCells([classCell1, assoc1, assoc2, assoc3], 120, 70));
 537         
 538         var assoc = new mxCell(\'name\', new mxGeometry(0, 0, 0, 0), \'endArrow=block;endFill=1;edgeStyle=orthogonalEdgeStyle;align=left;verticalAlign=top;\');
 539         assoc.geometry.setTerminalPoint(new mxPoint(0, 0), true);
 540         assoc.geometry.setTerminalPoint(new mxPoint(160, 0), false);
 541         assoc.geometry.relative = true;
 542         assoc.geometry.x = -1;
 543         assoc.edge = true;
 544         
 545         var sourceLabel = new mxCell(\'1\', new mxGeometry(-1, 0, 0, 0), \'resizable=0;align=left;verticalAlign=bottom;labelBackgroundColor=#ffffff;fontSize=10\');
 546         sourceLabel.geometry.relative = true;
 547         sourceLabel.setConnectable(false);
 548         sourceLabel.vertex = true;
 549         assoc.insert(sourceLabel);
 550         
 551         content.appendChild(this.createEdgeTemplateFromCells([assoc], 160, 0));
 552         
 553         var assoc = new mxCell(\'\', new mxGeometry(0, 0, 0, 0), \'endArrow=none;edgeStyle=orthogonalEdgeStyle;\');
 554         assoc.geometry.setTerminalPoint(new mxPoint(0, 0), true);
 555         assoc.geometry.setTerminalPoint(new mxPoint(160, 0), false);
 556         assoc.edge = true;
 557         
 558         var sourceLabel = new mxCell(\'parent\', new mxGeometry(-1, 0, 0, 0), \'resizable=0;align=left;verticalAlign=bottom;labelBackgroundColor=#ffffff;fontSize=10\');
 559         sourceLabel.geometry.relative = true;
 560         sourceLabel.setConnectable(false);
 561         sourceLabel.vertex = true;
 562         assoc.insert(sourceLabel);
 563         
 564         var targetLabel = new mxCell(\'child\', new mxGeometry(1, 0, 0, 0), \'resizable=0;align=right;verticalAlign=bottom;labelBackgroundColor=#ffffff;fontSize=10\');
 565         targetLabel.geometry.relative = true;
 566         targetLabel.setConnectable(false);
 567         targetLabel.vertex = true;
 568         assoc.insert(targetLabel);
 569         
 570         content.appendChild(this.createEdgeTemplateFromCells([assoc], 160, 0));
 571         
 572         var assoc = new mxCell(\'1\', new mxGeometry(0, 0, 0, 0), \'endArrow=open;endSize=12;startArrow=diamondThin;startSize=14;startFill=0;edgeStyle=orthogonalEdgeStyle;align=left;verticalAlign=bottom;\');
 573         assoc.geometry.setTerminalPoint(new mxPoint(0, 0), true);
 574         assoc.geometry.setTerminalPoint(new mxPoint(160, 0), false);
 575         assoc.geometry.relative = true;
 576         assoc.geometry.x = -1;
 577         assoc.edge = true;
 578         
 579         content.appendChild(this.createEdgeTemplateFromCells([assoc], 160, 0));
 580         
 581         var assoc = new mxCell(\'Relation\', new mxGeometry(0, 0, 0, 0), \'endArrow=open;endSize=12;startArrow=diamondThin;startSize=14;startFill=0;edgeStyle=orthogonalEdgeStyle;\');
 582         assoc.geometry.setTerminalPoint(new mxPoint(0, 0), true);
 583         assoc.geometry.setTerminalPoint(new mxPoint(160, 0), false);
 584         assoc.edge = true;
 585         
 586         var sourceLabel = new mxCell(\'0..n\', new mxGeometry(-1, 0, 0, 0), \'resizable=0;align=left;verticalAlign=top;labelBackgroundColor=#ffffff;fontSize=10\');
 587         sourceLabel.geometry.relative = true;
 588         sourceLabel.setConnectable(false);
 589         sourceLabel.vertex = true;
 590         assoc.insert(sourceLabel);
 591         
 592         var targetLabel = new mxCell(\'1\', new mxGeometry(1, 0, 0, 0), \'resizable=0;align=right;verticalAlign=top;labelBackgroundColor=#ffffff;fontSize=10\');
 593         targetLabel.geometry.relative = true;
 594         targetLabel.setConnectable(false);
 595         targetLabel.vertex = true;
 596         assoc.insert(targetLabel);
 597         
 598         content.appendChild(this.createEdgeTemplateFromCells([assoc], 160, 0));
 599         
 600         var assoc = new mxCell(\'Use\', new mxGeometry(0, 0, 0, 0), \'endArrow=open;endSize=12;dashed=1\');
 601         assoc.geometry.setTerminalPoint(new mxPoint(0, 0), true);
 602         assoc.geometry.setTerminalPoint(new mxPoint(160, 0), false);
 603         assoc.edge = true;
 604         
 605         content.appendChild(this.createEdgeTemplateFromCells([assoc], 160, 0));
 606         
 607         var assoc = new mxCell(\'Extends\', new mxGeometry(0, 0, 0, 0), \'endArrow=block;endSize=16;endFill=0;dashed=1\');
 608         assoc.geometry.setTerminalPoint(new mxPoint(0, 0), true);
 609         assoc.geometry.setTerminalPoint(new mxPoint(160, 0), false);
 610         assoc.edge = true;
 611         
 612         content.appendChild(this.createEdgeTemplateFromCells([assoc], 160, 0));
 613         
 614         var assoc = new mxCell(\'\', new mxGeometry(0, 0, 0, 0), \'endArrow=block;startArrow=block;endFill=1;startFill=1\');
 615         assoc.geometry.setTerminalPoint(new mxPoint(0, 0), true);
 616         assoc.geometry.setTerminalPoint(new mxPoint(160, 0), false);
 617         assoc.edge = true;
 618         
 619         content.appendChild(this.createEdgeTemplateFromCells([assoc], 160, 0));
 620     }));
 621 };
 622 
 623 /**
 624  * Adds the BPMN library to the sidebar.
 625  */
 626 Sidebar.prototype.addBpmnPalette = function(dir, expand)
 627 {
 628     this.addStencilPalette(\'bpmn\', \'BPMN\', dir + \'/bpmn.xml\',
 629         \';fillColor=#ffffff;strokeColor=#000000;perimeter=ellipsePerimeter;\',
 630         [\'Cancel\', \'Error\', \'Link\', \'Message\', \'Compensation\', \'Multiple\', \'Rule\', \'Timer\'],
 631         function(content)
 632         {
 633             content.appendChild(this.createVertexTemplate(\'swimlane;horizontal=0;\', 300, 160, \'Pool\'));
 634         
 635             var classCell = new mxCell(\'Process\', new mxGeometry(0, 0, 140, 60),
 636                 \'rounded=1\');
 637             classCell.vertex = true;
 638             var classCell1 = new mxCell(\'\', new mxGeometry(1, 1, 30, 30), \'shape=mxgraph.bpmn.timer_start;perimeter=ellipsePerimeter;\');
 639             classCell1.vertex = true;
 640             classCell1.geometry.relative = true;
 641             classCell1.geometry.offset = new mxPoint(-40, -15);
 642             classCell.insert(classCell1);
 643             
 644             content.appendChild(this.createVertexTemplateFromCells([classCell], 140, 60));
 645             
 646             var classCell = new mxCell(\'Process\', new mxGeometry(0, 0, 140, 60),
 647                 \'rounded=1\');
 648             classCell.vertex = true;
 649             var classCell1 = new mxCell(\'\', new mxGeometry(0.5, 1, 12, 12), \'shape=plus\');
 650             classCell1.vertex = true;
 651             classCell1.connectable = false;
 652             classCell1.geometry.relative = true;
 653             classCell1.geometry.offset = new mxPoint(-6, -12);
 654             classCell.insert(classCell1);
 655             
 656             content.appendChild(this.createVertexTemplateFromCells([classCell], 140, 60));
 657             
 658             var classCell = new mxCell(\'Process\', new mxGeometry(0, 0, 140, 60),
 659                 \'rounded=1\');
 660             classCell.vertex = true;
 661             var classCell1 = new mxCell(\'\', new mxGeometry(0, 0, 20, 14), \'shape=message\');
 662             classCell1.vertex = true;
 663             classCell1.connectable = false;
 664             classCell1.geometry.relative = true;
 665             classCell1.geometry.offset = new mxPoint(5, 5);
 666             classCell.insert(classCell1);
 667             
 668             content.appendChild(this.createVertexTemplateFromCells([classCell], 140, 60));
 669             
 670             var classCell = new mxCell(\'\', new mxGeometry(0, 0, 60, 40), \'shape=message\');
 671             classCell.vertex = true;
 672     
 673             content.appendChild(this.createEdgeTemplateFromCells([classCell], 60, 40));
 674     
 675             var assoc = new mxCell(\'Sequence\', new mxGeometry(0, 0, 0, 0), \'endArrow=block;endFill=1;endSize=6\');
 676             assoc.geometry.setTerminalPoint(new mxPoint(0, 0), true);
 677             assoc.geometry.setTerminalPoint(new mxPoint(160, 0), false);
 678             assoc.edge = true;
 679     
 680             content.appendChild(this.createEdgeTemplateFromCells([assoc], 160, 0));
 681             
 682             var assoc = new mxCell(\'Default\', new mxGeometry(0, 0, 0, 0), \'startArrow=dash;startSize=8;endArrow=block;endFill=1;endSize=6\');
 683             assoc.geometry.setTerminalPoint(new mxPoint(0, 0), true);
 684             assoc.geometry.setTerminalPoint(new mxPoint(160, 0), false);
 685             assoc.edge = true;
 686             
 687             content.appendChild(this.createEdgeTemplateFromCells([assoc], 160, 0));
 688             
 689             var assoc = new mxCell(\'Conditional\', new mxGeometry(0, 0, 0, 0), \'startArrow=diamondThin;startFill=0;startSize=14;endArrow=block;endFill=1;endSize=6\');
 690             assoc.geometry.setTerminalPoint(new mxPoint(0, 0), true);
 691             assoc.geometry.setTerminalPoint(new mxPoint(160, 0), false);
 692             assoc.edge = true;
 693             
 694             content.appendChild(this.createEdgeTemplateFromCells([assoc], 160, 0));
 695             
 696             var assoc = new mxCell(\'\', new mxGeometry(0, 0, 0, 0), \'startArrow=oval;startFill=0;startSize=7;endArrow=block;endFill=0;endSize=10;dashed=1\');
 697             assoc.geometry.setTerminalPoint(new mxPoint(0, 0), true);
 698             assoc.geometry.setTerminalPoint(new mxPoint(160, 0), false);
 699             assoc.edge = true;
 700     
 701             content.appendChild(this.createEdgeTemplateFromCells([assoc], 160, 0));
 702     
 703             var assoc = new mxCell(\'\', new mxGeometry(0, 0, 0, 0), \'startArrow=oval;startFill=0;startSize=7;endArrow=block;endFill=0;endSize=10;dashed=1\');
 704             assoc.geometry.setTerminalPoint(new mxPoint(0, 0), true);
 705             assoc.geometry.setTerminalPoint(new mxPoint(160, 0), false);
 706             assoc.edge = true;
 707             
 708             var sourceLabel = new mxCell(\'\', new mxGeometry(0, 0, 20, 14), \'shape=message\');
 709             sourceLabel.geometry.relative = true;
 710             sourceLabel.setConnectable(false);
 711             sourceLabel.vertex = true;
 712             sourceLabel.geometry.offset = new mxPoint(-10, -7);
 713             assoc.insert(sourceLabel);
 714     
 715             content.appendChild(this.createEdgeTemplateFromCells([assoc], 160, 0));
 716             
 717             var assoc = new mxCell(\'\', new mxGeometry(0, 0, 0, 0), \'shape=link\');
 718             assoc.geometry.setTerminalPoint(new mxPoint(0, 0), true);
 719             assoc.geometry.setTerminalPoint(new mxPoint(160, 0), false);
 720             assoc.edge = true;
 721     
 722             content.appendChild(this.createEdgeTemplateFromCells([assoc], 160, 0));
 723         }, 0.5);
 724 };
 725 
 726 /**
 727  * Creates and returns the given title element.
 728  */
 729 Sidebar.prototype.createTitle = function(label)
 730 {
 731     var elt = document.createElement(\'a\');
 732     elt.setAttribute(\'href\', \'javascript:void(0);\');
 733     elt.className = \'geTitle\';
 734     mxUtils.write(elt, label);
 735 
 736     return elt;
 737 };
 738 
 739 /**
 740  * Creates a thumbnail for the given cells.
 741  */
 742 Sidebar.prototype.createThumb = function(cells, width, height, parent)
 743 {
 744     // Workaround for off-screen text rendering in IE
 745     var old = mxText.prototype.getTableSize;
 746     
 747     if (this.graph.dialect != mxConstants.DIALECT_SVG)
 748     {
 749         mxText.prototype.getTableSize = function(table)
 750         {
 751             var oldParent = table.parentNode;
 752             
 753             document.body.appendChild(table);
 754             var size = new mxRectangle(0, 0, table.offsetWidth, table.offsetHeight);
 755             oldParent.appendChild(table);
 756             
 757             return size;
 758         };
 759     }
 760     
 761     var prev = mxImageShape.prototype.preserveImageAspect;
 762     mxImageShape.prototype.preserveImageAspect = false;
 763     
 764     this.graph.view.rendering = false;
 765     this.graph.view.setScale(1);
 766     this.graph.addCells(cells);
 767     var bounds = this.graph.getGraphBounds();
 768 
 769     var corr = (this.shiftThumbs) ? this.thumbBorder + 1 : this.thumbBorder;
 770     var s = Math.min((width - 1) / (bounds.x + bounds.width + corr),
 771         (height - 1) / (bounds.y + bounds.height + corr));
 772     this.graph.view.setScale(s);
 773     this.graph.view.rendering = true;
 774     this.graph.refresh();
 775     mxImageShape.prototype.preserveImageAspect = prev;
 776 
 777     bounds = this.graph.getGraphBounds();
 778     var dx = Math.max(0, Math.floor((width - bounds.width) / 2));
 779     var dy = Math.max(0, Math.floor((height - bounds.height) / 2));
 780     
 781     var node = null;
 782     
 783     // For supporting HTML labels in IE9 standards mode the container is cloned instead
 784     if (this.graph.dialect == mxConstants.DIALECT_SVG && !mxClient.IS_IE)
 785     {
 786         node = this.graph.view.getCanvas().ownerSVGElement.cloneNode(true);
 787     }
 788     // Workaround for VML rendering in IE8 standards mode
 789     else if (document.documentMode == 8)
 790     {
 791         node = this.graph.container.cloneNode(false);
 792         node.innerHTML = this.graph.container.innerHTML;
 793     }
 794     else
 795     {
 796         node = this.graph.container.cloneNode(true);
 797     }
 798     
 799     this.graph.getModel().clear();
 800     
 801     // Outer dimension is (32, 32)
 802     var dd = (this.shiftThumbs) ? 2 : 3;
 803     node.style.position = \'relative\';
 804     node.style.overflow = \'visible\';
 805     node.style.cursor = \'pointer\';
 806     node.style.left = (dx + dd) + \'px\';
 807     node.style.top = (dy + dd) + \'px\';
 808     node.style.width = width + \'px\';
 809     node.style.height = height + \'px\';
 810     
 811     parent.appendChild(node);
 812     mxText.prototype.getTableSize = old;
 813 };
 814 
 815 /**
 816  * Creates and returns a new palette item for the given image.
 817  */
 818 Sidebar.prototype.createItem = function(cells)
 819 {
 820     var elt = document.createElement(\'a\');
 821     elt.setAttribute(\'href\', \'javascript:void(0);\');
 822     elt.className = \'geItem\';
 823     
 824     // Blocks default click action
 825     mxEvent.addListener(elt, \'click\', function(evt)
 826     {
 827         mxEvent.consume(evt);
 828     });
 829 
 830     this.createThumb(cells, this.thumbWidth, this.thumbHeight, elt);
 831     
 832     return elt;
 833 };
 834 
 835 /**
 836  * Creates a drop handler for inserting the given cells.
 837  */
 838 Sidebar.prototype.createDropHandler = function(cells, allowSplit)
 839 {
 840     return function(graph, evt, target, x, y)
 841     {
 842         cells = graph.getImportableCells(cells);
 843         
 844         if (cells.length > 0)
 845         {
 846             var validDropTarget = (target != null) ?
 847                 graph.isValidDropTarget(target, cells, evt) : false;
 848             var select = null;
 849             
 850             if (target != null && !validDropTarget)
 851             {
 852                 target = null;
 853             }
 854             
 855             // Splits the target edge or inserts into target group
 856             if (allowSplit && graph.isSplitEnabled() && graph.isSplitTarget(target, cells, evt))
 857             {
 858                 graph.splitEdge(target, cells, null, x, y);
 859                 select = cells;
 860             }
 861             else if (cells.length > 0)
 862             {
 863                 select = graph.importCells(cells, x, y, target);
 864             }
 865             
 866             if (select != null && select.length > 0)
 867             {
 868                 graph.scrollCellToVisible(select[0]);
 869                 graph.setSelectionCells(select);
 870             }
 871         }
 872     };
 873 };
 874 
 875 /**
 876  * Creates and returns a preview element for the given width and height.
 877  */
 878 Sidebar.prototype.createDragPreview = function(width, height)
 879 {
 880     var elt = document.createElement(\'div\');
 881     elt.style.border = \'1px dashed black\';
 882     elt.style.width = width + \'px\';
 883     elt.style.height = height + \'px\';
 884     
 885     return elt;
 886 };
 887 
 888 /**
 889  * Creates a drag source for the given element.
 890  */
 891 Sidebar.prototype.createDragSource = function(elt, dropHandler, preview)
 892 {
 893     var dragSource = mxUtils.makeDraggable(elt, this.editorUi.editor.graph, dropHandler,
 894         preview, 0, 0, this.editorUi.editor.graph.autoscroll, true, true);
 895 
 896     // Allows drop into cell only if target is a valid root
 897     dragSource.getDropTarget = function(graph, x, y)
 898     {
 899         var target = mxDragSource.prototype.getDropTarget.apply(this, arguments);
 900         
 901         if (!graph.isValidRoot(target))
 902         {
 903             target = null;
 904         }
 905         
 906         return target;
 907     };
 908     
 909     return dragSource;
 910 };
 911 
 912 /**
 913  * Adds a handler for inserting the cell with a single click.
 914  */
 915 Sidebar.prototype.addClickHandler = function(elt, ds)
 916 {
 917     var graph = this.editorUi.editor.graph;
 918     var first = null;
 919     
 920     var md = (mxClient.IS_TOUCH) ? \'touchstart\' : \'mousedown\';
 921     mxEvent.addListener(elt, md, function(evt)
 922     {
 923         first = new mxPoint(mxEvent.getClientX(evt), mxEvent.getClientY(evt));
 924     });
 925     
 926     var oldMouseUp = ds.mouseUp;
 927     ds.mouseUp = function(evt)
 928     {
 929         if (!mxEvent.isPopupTrigger(evt) && this.currentGraph == null && first != null)
 930         {
 931             var tol = graph.tolerance;
 932             
 933             if (Math.abs(first.x - mxEvent.getClientX(evt)) <= tol &&
 934                 Math.abs(first.y - mxEvent.getClientY(evt)) <= tol)
 935             {
 936                 var gs = graph.getGridSize();
 937                 ds.drop(graph, evt, null, gs, gs);
 938             }
 939         }
 940 
 941         oldMouseUp.apply(this, arguments);
 942         first = null;
 943     };
 944 };
 945 
 946 /**
 947  * Creates a drop handler for inserting the given cells.
 948  */
 949 Sidebar.prototype.createVertexTemplate = function(style, width, height, value)
 950 {
 951     var cells = [new mxCell((value != null) ? value : \'\', new mxGeometry(0, 0, width, height), style)];
 952     cells[0].vertex = true;
 953     
 954     return this.createVertexTemplateFromCells(cells, width, height);
 955 };
 956 
 957 /**
 958  * Creates a drop handler for inserting the given cells.
 959  */
 960 Sidebar.prototype.createVertexTemplateFromCells = function(cells, width, height)
 961 {
 962     var elt = this.createItem(cells);
 963     var ds = this.createDragSource(elt, this.createDropHandler(cells, true), this.createDragPreview(width, height));
 964     this.addClickHandler(elt, ds);
 965 
 966     // Uses guides for vertices only if enabled in graph
 967     ds.isGuidesEnabled = mxUtils.bind(this, function()
 968     {
 969         return this.editorUi.editor.graph.graphHandler.guidesEnabled;
 970     });
 971 
 972     // Shows a tooltip with the rendered cell
 973     if (!touchStyle)
 974     {
 975         mxEvent.addListener(elt, \'mousemove\', mxUtils.bind(this, function(evt)
 976         {
 977             this.showTooltip(elt, cells);
 978         }));
 979     }
 980     
 981     return elt;
 982 };
 983 
 984 /**
 985  * Creates a drop handler for inserting the given cells.
 986  */
 987 Sidebar.prototype.createEdgeTemplate = function(style, width, height, value)
 988 {
 989     var cells = [new mxCell((value != null) ? value : \'\', new mxGeometry(0, 0, width, height), style)];
 990     cells[0].geometry.setTerminalPoint(new mxPoint(0, height), true);
 991     cells[0].geometry.setTerminalPoint(new mxPoint(width, 0), false);
 992     cells[0].edge = true;
 993     
 994     return this.createEdgeTemplateFromCells(cells, width, height);
 995 };
 996 
 997 /**
 998  * Creates a drop handler for inserting the given cells.
 999  */
1000 Sidebar.prototype.createEdgeTemplateFromCells = function(cells, width, height)
1001 {
1002     var elt = this.createItem(cells);
1003     this.createDragSource(elt, this.createDropHandler(cells, false), this.createDragPreview(width, height));
1004 
1005     // Installs the default edge
1006     var graph = this.editorUi.editor.graph;
1007     mxEvent.addListener(elt, \'click\', mxUtils.bind(this, function(evt)
1008     {
1009         if (this.installEdges)
1010         {
1011             // Uses edge template for connect preview
1012             graph.connectionHandler.createEdgeState = function(me)
1013             {
1014                 return graph.view.createState(cells[0]);
1015             };
1016     
1017             // Creates new connections from edge template
1018             graph.connectionHandler.factoryMethod = function()
1019             {
1020                 return graph.cloneCells([cells[0]])[0];
1021             };
1022         }
1023         
1024         // Highlights the entry for 200ms
1025         elt.style.backgroundColor = \'#ffffff\';
1026         
1027         window.setTimeout(function()
1028         {
1029             elt.style.backgroundColor = \'\';
1030         }, 200);
1031         
1032         mxEvent.consume(evt);
1033     }));
1034 
1035     // Shows a tooltip with the rendered cell
1036     if (!touchStyle)
1037     {
1038         mxEvent.addListener(elt, \'mousemove\', mxUtils.bind(this, function(evt)
1039         {
1040             this.showTooltip(elt, cells);
1041         }));
1042     }
1043     
1044     return elt;
1045 };
1046 
1047 /**
1048  * Adds the given palette.
1049  */
1050 Sidebar.prototype.addPalette = function(id, title, expanded, onInit)
1051 {
1052     var elt = this.createTitle(title);
1053     this.container.appendChild(elt);
1054     
1055     var div = document.createElement(\'div\');
1056     div.className = \'geSidebar\';
1057     
1058     if (expanded)
1059     {
1060         onInit(div);
1061         onInit = null;
1062     }
1063     else
1064     {
1065         div.style.display = \'none\';
1066     }
1067     
1068     this.addFoldingHandler(elt, div, onInit);
1069     
1070     var outer = document.createElement(\'div\');
1071     outer.appendChild(div);
1072     this.container.appendChild(outer);
1073     
1074     // Keeps references to the DOM nodes
1075     if (id != null)
1076     {
1077         this.palettes[id] = [elt, outer];
1078     }
1079 };
1080 
1081 /**
1082  * Create the given title element.
1083  */
1084 Sidebar.prototype.addFoldingHandler = function(title, content, funct)
1085 {
1086     var initialized = false;
1087 
1088     title.style.backgroundImage = (content.style.display == \'none\') ?
1089         \'url(\' + IMAGE_PATH + \'/collapsed.gif)\' : \'url(\' + IMAGE_PATH + \'/expanded.gif)\';
1090     title.style.backgroundRepeat = \'no-repeat\';
1091     title.style.backgroundPosition = \'100% 50%\';
1092     
1093     mxEvent.addListener(title, \'click\', function(evt)
1094     {
1095         if (content.style.display == \'none\')
1096         {
1097             if (!initialized)
1098             {
1099                 initialized = true;
1100                 
1101                 if (funct != null)
1102                 {
1103                     funct(content);
1104                 }
1105             }
1106             
1107             title.style.backgroundImage = \'url(\' + IMAGE_PATH + \'/expanded.gif)\';
1108             content.style.display = \'block\';
1109         }
1110         else
1111         {
1112             title.style.backgroundImage = \'url(\' + IMAGE_PATH + \'/collapsed.gif)\';
1113             content.style.display = \'none\';
1114         }
1115         
1116         mxEvent.consume(evt);
1117     });
1118 };
1119 
1120 /**
1121  * Removes the palette for the given ID.
1122  */
1123 Sidebar.prototype.removePalette = function(id)
1124 {
1125     var elts = this.palettes[id];
1126     
1127     if (elts != null)
1128     {
1129         this.palettes[id] = null;
1130         
1131         for (var i = 0; i < elts.length; i++)
1132         {
1133             this.container.removeChild(elts[i]);
1134         }
1135         
1136         return true;
1137     }
1138     
1139     return false;
1140 };
1141 
1142 /**
1143  * Adds the given image palette.
1144  */
1145 Sidebar.prototype.addImagePalette = function(id, title, prefix, postfix, items)
1146 {
1147     this.addPalette(id, title, true, mxUtils.bind(this, function(content)
1148     {
1149         for (var i = 0; i < items.length; i++)
1150         {
1151             var icon = prefix + items[i] + postfix;
1152             content.appendChild(this.createVertexTemplate(\'image;image=\' + icon, 80, 80, \'\'));
1153         }
1154     }));
1155 };
1156 
1157 /**
1158  * Adds the given stencil palette.
1159  */
1160 Sidebar.prototype.addStencilPalette = function(id, title, stencilFile, style, ignore, onInit, scale)
1161 {
1162     scale = (scale != null) ? scale : 1;
1163     
1164     this.addPalette(id, title, false, mxUtils.bind(this, function(content)
1165     {
1166         if (style == null)
1167         {
1168             style = \'\';
1169         }
1170         
1171         if (onInit != null)
1172         {
1173             onInit.call(this, content);
1174         }
1175 
1176         mxStencilRegistry.loadStencilSet(stencilFile, mxUtils.bind(this, function(packageName, stencilName, displayName, w, h)
1177         {
1178             if (ignore == null || mxUtils.indexOf(ignore, stencilName) < 0)
1179             {
1180                 content.appendChild(this.createVertexTemplate(\'shape=\' + packageName + stencilName.toLowerCase() + style,
1181                     Math.round(w * scale), Math.round(h * scale), \'\'));
1182             }
1183         }), true);
1184     }));
1185 };      

View Code

基于Web實作網絡拓撲圖

對應于配置屬性檔案的參數變量:

基于Web實作網絡拓撲圖

右鍵菜單綁定裝置,設定線寬

基于Web實作網絡拓撲圖

文檔比較亂! 也有點趕~

歡迎加入一起讨論,後期的開發與研讨,還有一些瓶頸沒有解決....

Demo下載下傳位址:點選下載下傳

本文基于署名 2.5 ***許可協定釋出,歡迎轉載,演繹或用于商業目的,但是必須且在文章頁面明顯位置給出原文連結Dana、Li(包含連結),具體操作方式可參考此處。如您有任何疑問或者授權方面的協商,請留言或加Q群!