基于Web实现网络拓扑图

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

先前整理过份简单的Demo 但是不详细  基于Web实现在线绘画拓扑图[GraphEditor]

首先呢这里是要详述的几个要点:(我用图是直接显示了~) (当然这套UI模块是后期改动的~重点不在这里)        [备案:后续使用文档]

显示拓扑图

其次呢是一些后期加上去的代码,我想既然用了网络拓扑图,后期的可塑性应该是很强的,部分都是后续需求加上去的!

言归正传,看完一些简单的流程图,我想都大概知道他的基本用途,和后期的塑造价值

一些简单的用途比如:做大数据Hadoop,Spark是的个个服务器之间的关系,以及关系流程图的描述; 大型企业的负载集群管理的关系以及流程图,安全管理,OA企业人士管理.....多事不可缺少的素材!

主要JQ代码模块:

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

用于绑定一些菜单信息

编辑保存

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

核心文件代码如下:

EditorUi.js

  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

这里是图形化操作以后保存拓扑对于的Xml文件,便于再次访问,或者查看的时候加载原信息!

如操作功能:

对应的通过上面EditorUi.js文件中EditorUi.prototype.save = function()控制,我是通过一个Servlet来保存XML文件

 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源码

  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

工具栏~Sidebar.js

如:图标A区 ,图标B区的控制

源码:

   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', 'gateWayVPN', '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;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

对应于配置属性文件的参数变量:

右键菜单绑定设备,设置线宽

文档比较乱! 也有点赶~

欢迎加入一起讨论,后期的开发与研讨,还有一些瓶颈没有解决....

Demo下载地址:点击下载

本文基于署名 2.5 中国大陆许可协议发布,欢迎转载,演绎或用于商业目的,但是必须且在文章页面明显位置给出原文链接Dana、Li(包含链接),具体操作方式可参考此处。如您有任何疑问或者授权方面的协商,请留言或加Q群!
原文地址:https://www.cnblogs.com/visec479/p/4360052.html