想想好像好久没用写博客了! 由于最近想跳槽了(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 };
这里是图形化操作以后保存拓扑对于的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 }
当我们再次访问编辑页面时,即要加载先前对应的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="测试网闸[内端]
通讯:192.168.0.199 
业务: 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 };
工具栏~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><<Interface>></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('<<component>><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 };
对应于配置属性文件的参数变量:
右键菜单绑定设备,设置线宽
文档比较乱! 也有点赶~
欢迎加入一起讨论,后期的开发与研讨,还有一些瓶颈没有解决....
Demo下载地址:点击下载