diff options
author | adhitya | 2016-04-12 07:02:39 +0000 |
---|---|---|
committer | adhitya | 2016-04-12 07:02:39 +0000 |
commit | dd83478e3fcaac98de690aa59e6288ad41a1c351 (patch) | |
tree | 38653bdf0ae95053f66777c4ac3fe5be5d8fbd33 /src | |
parent | 92f3207b50a1caca07df5c5b238212af3358905b (diff) | |
download | xcos-on-web-dd83478e3fcaac98de690aa59e6288ad41a1c351.tar.gz xcos-on-web-dd83478e3fcaac98de690aa59e6288ad41a1c351.tar.bz2 xcos-on-web-dd83478e3fcaac98de690aa59e6288ad41a1c351.zip |
Keyboard shortcuts work properly
Diffstat (limited to 'src')
159 files changed, 0 insertions, 79915 deletions
diff --git a/src/css/common.css b/src/css/common.css deleted file mode 100644 index 5eb0b45..0000000 --- a/src/css/common.css +++ /dev/null @@ -1,152 +0,0 @@ -div.mxRubberband { - position: absolute; - overflow: hidden; - border-style: solid; - border-width: 1px; - border-color: #0000FF; - background: #0077FF; -} -textarea.mxCellEditor { - background: url('../images/transparent.gif'); - border-style: solid; - border-color: black; - border-width: 0; - overflow: auto; -} -div.mxWindow { - -webkit-box-shadow: 3px 3px 12px #C0C0C0; - -moz-box-shadow: 3px 3px 12px #C0C0C0; - box-shadow: 3px 3px 12px #C0C0C0; - background: url('../images/window.gif'); - border-style: outset; - border-width: 1px; - position: absolute; - overflow: hidden; - z-index: 1; -} -table.mxWindow { - border-collapse: collapse; - table-layout: fixed; - font-family: Arial; - font-size: 8pt; -} -td.mxWindowTitle { - background: url('../images/window-title.gif') repeat-x; - text-overflow: ellipsis; - white-space: nowrap; - text-align: center; - font-weight: bold; - overflow: hidden; - height: 13px; - padding: 2px; - padding-top: 4px; - padding-bottom: 6px; - color: black; -} -td.mxWindowPane { - vertical-align: top; - padding: 0px; -} -div.mxWindowPane { - overflow: hidden; -} -td.mxWindowPane td { - font-family: Arial; - font-size: 8pt; -} -td.mxWindowPane input, td.mxWindowPane select, td.mxWindowPane textarea, td.mxWindowPane radio { - border-color: #8C8C8C; - border-style: solid; - border-width: 1px; - font-family: Arial; - font-size: 8pt; - padding: 1px; -} -td.mxWindowPane button { - background: url('../images/button.gif') repeat-x; - font-family: Arial; - font-size: 8pt; - padding: 2px; - float: left; -} -img.mxToolbarItem { - margin-right: 6px; - margin-bottom: 6px; - border-width: 1px; -} -select.mxToolbarCombo { - vertical-align: top; - border-style: inset; - border-width: 2px; -} -div.mxToolbarComboContainer { - padding: 2px; -} -img.mxToolbarMode { - margin: 2px; - margin-right: 4px; - margin-bottom: 4px; - border-width: 0px; -} -img.mxToolbarModeSelected { - margin: 0px; - margin-right: 2px; - margin-bottom: 2px; - border-width: 2px; - border-style: inset; -} -div.mxTooltip { - -webkit-box-shadow: 3px 3px 12px #C0C0C0; - -moz-box-shadow: 3px 3px 12px #C0C0C0; - box-shadow: 3px 3px 12px #C0C0C0; - background: #FFFFCC; - border-style: solid; - border-width: 1px; - border-color: black; - font-family: Arial; - font-size: 8pt; - position: absolute; - cursor: default; - padding: 4px; - color: black; -} -div.mxPopupMenu { - -webkit-box-shadow: 3px 3px 12px #C0C0C0; - -moz-box-shadow: 3px 3px 12px #C0C0C0; - box-shadow: 3px 3px 12px #C0C0C0; - background: url('../images/window.gif'); - position: absolute; - border-style: solid; - border-width: 1px; - border-color: black; - cursor: default; -} -table.mxPopupMenu { - border-collapse: collapse; - margin-top: 1px; - margin-bottom: 1px; -} -tr.mxPopupMenuItem { - color: black; - cursor: default; -} -td.mxPopupMenuItem.disabled { - opacity: 0.2; -} -td.mxPopupMenuItem.disabled { - _filter:alpha(opacity=20) !important; -} -tr.mxPopupMenuItemHover { - background-color: #000066; - color: #FFFFFF; -} -td.mxPopupMenuItem { - padding: 2px 30px 2px 10px; - white-space: nowrap; - font-family: Arial; - font-size: 8pt; -} -td.mxPopupMenuIcon { - background-color: #D0D0D0; - padding: 2px 4px 2px 4px; -} diff --git a/src/css/explorer.css b/src/css/explorer.css deleted file mode 100644 index dfbbd21..0000000 --- a/src/css/explorer.css +++ /dev/null @@ -1,15 +0,0 @@ -div.mxTooltip { - filter:progid:DXImageTransform.Microsoft.DropShadow(OffX=4, OffY=4, - Color='#A2A2A2', Positive='true') -} -div.mxPopupMenu { - filter:progid:DXImageTransform.Microsoft.DropShadow(OffX=4, OffY=4, - Color='#C0C0C0', Positive='true') -} -div.mxWindow { - filter:progid:DXImageTransform.Microsoft.DropShadow(OffX=4, OffY=4, - Color='#C0C0C0', Positive='true') -} -td.mxWindowTitle { - _height: 23px; -} diff --git a/src/images/button.gif b/src/images/button.gif Binary files differdeleted file mode 100644 index ad55cab..0000000 --- a/src/images/button.gif +++ /dev/null diff --git a/src/images/close.gif b/src/images/close.gif Binary files differdeleted file mode 100644 index 1069e94..0000000 --- a/src/images/close.gif +++ /dev/null diff --git a/src/images/collapsed.gif b/src/images/collapsed.gif Binary files differdeleted file mode 100644 index 0276444..0000000 --- a/src/images/collapsed.gif +++ /dev/null diff --git a/src/images/error.gif b/src/images/error.gif Binary files differdeleted file mode 100644 index 14e1aee..0000000 --- a/src/images/error.gif +++ /dev/null diff --git a/src/images/expanded.gif b/src/images/expanded.gif Binary files differdeleted file mode 100644 index 3767b0b..0000000 --- a/src/images/expanded.gif +++ /dev/null diff --git a/src/images/maximize.gif b/src/images/maximize.gif Binary files differdeleted file mode 100644 index e27cf3e..0000000 --- a/src/images/maximize.gif +++ /dev/null diff --git a/src/images/minimize.gif b/src/images/minimize.gif Binary files differdeleted file mode 100644 index 1e95e7c..0000000 --- a/src/images/minimize.gif +++ /dev/null diff --git a/src/images/normalize.gif b/src/images/normalize.gif Binary files differdeleted file mode 100644 index 34a8d30..0000000 --- a/src/images/normalize.gif +++ /dev/null diff --git a/src/images/point.gif b/src/images/point.gif Binary files differdeleted file mode 100644 index 9074c39..0000000 --- a/src/images/point.gif +++ /dev/null diff --git a/src/images/resize.gif b/src/images/resize.gif Binary files differdeleted file mode 100644 index ff558db..0000000 --- a/src/images/resize.gif +++ /dev/null diff --git a/src/images/separator.gif b/src/images/separator.gif Binary files differdeleted file mode 100644 index 5c1b895..0000000 --- a/src/images/separator.gif +++ /dev/null diff --git a/src/images/submenu.gif b/src/images/submenu.gif Binary files differdeleted file mode 100644 index ffe7617..0000000 --- a/src/images/submenu.gif +++ /dev/null diff --git a/src/images/transparent.gif b/src/images/transparent.gif Binary files differdeleted file mode 100644 index 76040f2..0000000 --- a/src/images/transparent.gif +++ /dev/null diff --git a/src/images/warning.gif b/src/images/warning.gif Binary files differdeleted file mode 100644 index 705235f..0000000 --- a/src/images/warning.gif +++ /dev/null diff --git a/src/images/warning.png b/src/images/warning.png Binary files differdeleted file mode 100644 index 2f78789..0000000 --- a/src/images/warning.png +++ /dev/null diff --git a/src/images/window-title.gif b/src/images/window-title.gif Binary files differdeleted file mode 100644 index 231def8..0000000 --- a/src/images/window-title.gif +++ /dev/null diff --git a/src/images/window.gif b/src/images/window.gif Binary files differdeleted file mode 100644 index 6631c4f..0000000 --- a/src/images/window.gif +++ /dev/null diff --git a/src/js/editor/mxDefaultKeyHandler.js b/src/js/editor/mxDefaultKeyHandler.js deleted file mode 100644 index 3814e5e..0000000 --- a/src/js/editor/mxDefaultKeyHandler.js +++ /dev/null @@ -1,126 +0,0 @@ -/** - * $Id: mxDefaultKeyHandler.js,v 1.26 2010-01-02 09:45:15 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -/** - * Class: mxDefaultKeyHandler - * - * Binds keycodes to actionnames in an editor. This aggregates an internal - * <handler> and extends the implementation of <mxKeyHandler.escape> to not - * only cancel the editing, but also hide the properties dialog and fire an - * <mxEditor.escape> event via <editor>. An instance of this class is created - * by <mxEditor> and stored in <mxEditor.keyHandler>. - * - * Example: - * - * Bind the delete key to the delete action in an existing editor. - * - * (code) - * var keyHandler = new mxDefaultKeyHandler(editor); - * keyHandler.bindAction(46, 'delete'); - * (end) - * - * Codec: - * - * This class uses the <mxDefaultKeyHandlerCodec> to read configuration - * data into an existing instance. See <mxDefaultKeyHandlerCodec> for a - * description of the configuration format. - * - * Keycodes: - * - * See <mxKeyHandler>. - * - * An <mxEvent.ESCAPE> event is fired via the editor if the escape key is - * pressed. - * - * Constructor: mxDefaultKeyHandler - * - * Constructs a new default key handler for the <mxEditor.graph> in the - * given <mxEditor>. (The editor may be null if a prototypical instance for - * a <mxDefaultKeyHandlerCodec> is created.) - * - * Parameters: - * - * editor - Reference to the enclosing <mxEditor>. - */ -function mxDefaultKeyHandler(editor) -{ - if (editor != null) - { - this.editor = editor; - this.handler = new mxKeyHandler(editor.graph); - - // Extends the escape function of the internal key - // handle to hide the properties dialog and fire - // the escape event via the editor instance - var old = this.handler.escape; - - this.handler.escape = function(evt) - { - old.apply(this, arguments); - editor.hideProperties(); - editor.fireEvent(new mxEventObject(mxEvent.ESCAPE, 'event', evt)); - }; - } -}; - -/** - * Variable: editor - * - * Reference to the enclosing <mxEditor>. - */ -mxDefaultKeyHandler.prototype.editor = null; - -/** - * Variable: handler - * - * Holds the <mxKeyHandler> for key event handling. - */ -mxDefaultKeyHandler.prototype.handler = null; - -/** - * Function: bindAction - * - * Binds the specified keycode to the given action in <editor>. The - * optional control flag specifies if the control key must be pressed - * to trigger the action. - * - * Parameters: - * - * code - Integer that specifies the keycode. - * action - Name of the action to execute in <editor>. - * control - Optional boolean that specifies if control must be pressed. - * Default is false. - */ -mxDefaultKeyHandler.prototype.bindAction = function (code, action, control) -{ - var keyHandler = mxUtils.bind(this, function() - { - this.editor.execute(action); - }); - - // Binds the function to control-down keycode - if (control) - { - this.handler.bindControlKey(code, keyHandler); - } - - // Binds the function to the normal keycode - else - { - this.handler.bindKey(code, keyHandler); - } -}; - -/** - * Function: destroy - * - * Destroys the <handler> associated with this object. This does normally - * not need to be called, the <handler> is destroyed automatically when the - * window unloads (in IE) by <mxEditor>. - */ -mxDefaultKeyHandler.prototype.destroy = function () -{ - this.handler.destroy(); - this.handler = null; -}; diff --git a/src/js/editor/mxDefaultPopupMenu.js b/src/js/editor/mxDefaultPopupMenu.js deleted file mode 100644 index 01c65b5..0000000 --- a/src/js/editor/mxDefaultPopupMenu.js +++ /dev/null @@ -1,300 +0,0 @@ -/** - * $Id: mxDefaultPopupMenu.js,v 1.29 2012-07-03 06:30:25 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -/** - * Class: mxDefaultPopupMenu - * - * Creates popupmenus for mouse events. This object holds an XML node - * which is a description of the popup menu to be created. In - * <createMenu>, the configuration is applied to the context and - * the resulting menu items are added to the menu dynamically. See - * <createMenu> for a description of the configuration format. - * - * This class does not create the DOM nodes required for the popup menu, it - * only parses an XML description to invoke the respective methods on an - * <mxPopupMenu> each time the menu is displayed. - * - * Codec: - * - * This class uses the <mxDefaultPopupMenuCodec> to read configuration - * data into an existing instance, however, the actual parsing is done - * by this class during program execution, so the format is described - * below. - * - * Constructor: mxDefaultPopupMenu - * - * Constructs a new popupmenu-factory based on given configuration. - * - * Paramaters: - * - * config - XML node that contains the configuration data. - */ -function mxDefaultPopupMenu(config) -{ - this.config = config; -}; - -/** - * Variable: imageBasePath - * - * Base path for all icon attributes in the config. Default is null. - */ -mxDefaultPopupMenu.prototype.imageBasePath = null; - -/** - * Variable: config - * - * XML node used as the description of new menu items. This node is - * used in <createMenu> to dynamically create the menu items if their - * respective conditions evaluate to true for the given arguments. - */ -mxDefaultPopupMenu.prototype.config = null; - -/** - * Function: createMenu - * - * This function is called from <mxEditor> to add items to the - * given menu based on <config>. The config is a sequence of - * the following nodes and attributes. - * - * Child Nodes: - * - * add - Adds a new menu item. See below for attributes. - * separator - Adds a separator. No attributes. - * condition - Adds a custom condition. Name attribute. - * - * The add-node may have a child node that defines a function to be invoked - * before the action is executed (or instead of an action to be executed). - * - * Attributes: - * - * as - Resource key for the label (needs entry in property file). - * action - Name of the action to execute in enclosing editor. - * icon - Optional icon (relative/absolute URL). - * iconCls - Optional CSS class for the icon. - * if - Optional name of condition that must be true(see below). - * name - Name of custom condition. Only for condition nodes. - * - * Conditions: - * - * nocell - No cell under the mouse. - * ncells - More than one cell selected. - * notRoot - Drilling position is other than home. - * cell - Cell under the mouse. - * notEmpty - Exactly one cell with children under mouse. - * expandable - Exactly one expandable cell under mouse. - * collapsable - Exactly one collapsable cell under mouse. - * validRoot - Exactly one cell which is a possible root under mouse. - * swimlane - Exactly one cell which is a swimlane under mouse. - * - * Example: - * - * To add a new item for a given action to the popupmenu: - * - * (code) - * <mxDefaultPopupMenu as="popupHandler"> - * <add as="delete" action="delete" icon="images/delete.gif" if="cell"/> - * </mxDefaultPopupMenu> - * (end) - * - * To add a new item for a custom function: - * - * (code) - * <mxDefaultPopupMenu as="popupHandler"> - * <add as="action1"><![CDATA[ - * function (editor, cell, evt) - * { - * editor.execute('action1', cell, 'myArg'); - * } - * ]]></add> - * </mxDefaultPopupMenu> - * (end) - * - * The above example invokes action1 with an additional third argument via - * the editor instance. The third argument is passed to the function that - * defines action1. If the add-node has no action-attribute, then only the - * function defined in the text content is executed, otherwise first the - * function and then the action defined in the action-attribute is - * executed. The function in the text content has 3 arguments, namely the - * <mxEditor> instance, the <mxCell> instance under the mouse, and the - * native mouse event. - * - * Custom Conditions: - * - * To add a new condition for popupmenu items: - * - * (code) - * <condition name="condition1"><![CDATA[ - * function (editor, cell, evt) - * { - * return cell != null; - * } - * ]]></condition> - * (end) - * - * The new condition can then be used in any item as follows: - * - * (code) - * <add as="action1" action="action1" icon="action1.gif" if="condition1"/> - * (end) - * - * The order in which the items and conditions appear is not significant as - * all connditions are evaluated before any items are created. - * - * Parameters: - * - * editor - Enclosing <mxEditor> instance. - * menu - <mxPopupMenu> that is used for adding items and separators. - * cell - Optional <mxCell> which is under the mousepointer. - * evt - Optional mouse event which triggered the menu. - */ -mxDefaultPopupMenu.prototype.createMenu = function(editor, menu, cell, evt) -{ - if (this.config != null) - { - var conditions = this.createConditions(editor, cell, evt); - var item = this.config.firstChild; - - this.addItems(editor, menu, cell, evt, conditions, item, null); - } -}; - -/** - * Function: addItems - * - * Recursively adds the given items and all of its children into the given menu. - * - * Parameters: - * - * editor - Enclosing <mxEditor> instance. - * menu - <mxPopupMenu> that is used for adding items and separators. - * cell - Optional <mxCell> which is under the mousepointer. - * evt - Optional mouse event which triggered the menu. - * conditions - Array of names boolean conditions. - * item - XML node that represents the current menu item. - * parent - DOM node that represents the parent menu item. - */ -mxDefaultPopupMenu.prototype.addItems = function(editor, menu, cell, evt, conditions, item, parent) -{ - var addSeparator = false; - - while (item != null) - { - if (item.nodeName == 'add') - { - var condition = item.getAttribute('if'); - - if (condition == null || conditions[condition]) - { - var as = item.getAttribute('as'); - as = mxResources.get(as) || as; - var funct = mxUtils.eval(mxUtils.getTextContent(item)); - var action = item.getAttribute('action'); - var icon = item.getAttribute('icon'); - var iconCls = item.getAttribute('iconCls'); - - if (addSeparator) - { - menu.addSeparator(parent); - addSeparator = false; - } - - if (icon != null && this.imageBasePath) - { - icon = this.imageBasePath + icon; - } - - var row = this.addAction(menu, editor, as, icon, funct, action, cell, parent, iconCls); - this.addItems(editor, menu, cell, evt, conditions, item.firstChild, row); - } - } - else if (item.nodeName == 'separator') - { - addSeparator = true; - } - - item = item.nextSibling; - } -}; - -/** - * Function: addAction - * - * Helper method to bind an action to a new menu item. - * - * Parameters: - * - * menu - <mxPopupMenu> that is used for adding items and separators. - * editor - Enclosing <mxEditor> instance. - * lab - String that represents the label of the menu item. - * icon - Optional URL that represents the icon of the menu item. - * action - Optional name of the action to execute in the given editor. - * funct - Optional function to execute before the optional action. The - * function takes an <mxEditor>, the <mxCell> under the mouse and the - * mouse event that triggered the call. - * cell - Optional <mxCell> to use as an argument for the action. - * parent - DOM node that represents the parent menu item. - * iconCls - Optional CSS class for the menu icon. - */ -mxDefaultPopupMenu.prototype.addAction = function(menu, editor, lab, icon, funct, action, cell, parent, iconCls) -{ - var clickHandler = function(evt) - { - if (typeof(funct) == 'function') - { - funct.call(editor, editor, cell, evt); - } - - if (action != null) - { - editor.execute(action, cell, evt); - } - }; - - return menu.addItem(lab, icon, clickHandler, parent, iconCls); -}; - -/** - * Function: createConditions - * - * Evaluates the default conditions for the given context. - */ -mxDefaultPopupMenu.prototype.createConditions = function(editor, cell, evt) -{ - // Creates array with conditions - var model = editor.graph.getModel(); - var childCount = model.getChildCount(cell); - - // Adds some frequently used conditions - var conditions = []; - conditions['nocell'] = cell == null; - conditions['ncells'] = editor.graph.getSelectionCount() > 1; - conditions['notRoot'] = model.getRoot() != - model.getParent(editor.graph.getDefaultParent()); - conditions['cell'] = cell != null; - - var isCell = cell != null && editor.graph.getSelectionCount() == 1; - conditions['nonEmpty'] = isCell && childCount > 0; - conditions['expandable'] = isCell && editor.graph.isCellFoldable(cell, false); - conditions['collapsable'] = isCell && editor.graph.isCellFoldable(cell, true); - conditions['validRoot'] = isCell && editor.graph.isValidRoot(cell); - conditions['emptyValidRoot'] = conditions['validRoot'] && childCount == 0; - conditions['swimlane'] = isCell && editor.graph.isSwimlane(cell); - - // Evaluates dynamic conditions from config file - var condNodes = this.config.getElementsByTagName('condition'); - - for (var i=0; i<condNodes.length; i++) - { - var funct = mxUtils.eval(mxUtils.getTextContent(condNodes[i])); - var name = condNodes[i].getAttribute('name'); - - if (name != null && typeof(funct) == 'function') - { - conditions[name] = funct(editor, cell, evt); - } - } - - return conditions; -}; diff --git a/src/js/editor/mxDefaultToolbar.js b/src/js/editor/mxDefaultToolbar.js deleted file mode 100644 index 3f8f901..0000000 --- a/src/js/editor/mxDefaultToolbar.js +++ /dev/null @@ -1,567 +0,0 @@ -/** - * $Id: mxDefaultToolbar.js,v 1.67 2012-04-11 07:00:52 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -/** - * Class: mxDefaultToolbar - * - * Toolbar for the editor. This modifies the state of the graph - * or inserts new cells upon mouse clicks. - * - * Example: - * - * Create a toolbar with a button to copy the selection into the clipboard, - * and a combo box with one action to paste the selection from the clipboard - * into the graph. - * - * (code) - * var toolbar = new mxDefaultToolbar(container, editor); - * toolbar.addItem('Copy', null, 'copy'); - * - * var combo = toolbar.addActionCombo('More actions...'); - * toolbar.addActionOption(combo, 'Paste', 'paste'); - * (end) - * - * Codec: - * - * This class uses the <mxDefaultToolbarCodec> to read configuration - * data into an existing instance. See <mxDefaultToolbarCodec> for a - * description of the configuration format. - * - * Constructor: mxDefaultToolbar - * - * Constructs a new toolbar for the given container and editor. The - * container and editor may be null if a prototypical instance for a - * <mxDefaultKeyHandlerCodec> is created. - * - * Parameters: - * - * container - DOM node that contains the toolbar. - * editor - Reference to the enclosing <mxEditor>. - */ -function mxDefaultToolbar(container, editor) -{ - this.editor = editor; - - if (container != null && - editor != null) - { - this.init(container); - } -}; - -/** - * Variable: editor - * - * Reference to the enclosing <mxEditor>. - */ -mxDefaultToolbar.prototype.editor = null; - -/** - * Variable: toolbar - * - * Holds the internal <mxToolbar>. - */ -mxDefaultToolbar.prototype.toolbar = null; - -/** - * Variable: resetHandler - * - * Reference to the function used to reset the <toolbar>. - */ -mxDefaultToolbar.prototype.resetHandler = null; - -/** - * Variable: spacing - * - * Defines the spacing between existing and new vertices in - * gridSize units when a new vertex is dropped on an existing - * cell. Default is 4 (40 pixels). - */ -mxDefaultToolbar.prototype.spacing = 4; - -/** - * Variable: connectOnDrop - * - * Specifies if elements should be connected if new cells are dropped onto - * connectable elements. Default is false. - */ -mxDefaultToolbar.prototype.connectOnDrop = false; - -/** - * Variable: init - * - * Constructs the <toolbar> for the given container and installs a listener - * that updates the <mxEditor.insertFunction> on <editor> if an item is - * selected in the toolbar. This assumes that <editor> is not null. - * - * Parameters: - * - * container - DOM node that contains the toolbar. - */ -mxDefaultToolbar.prototype.init = function(container) -{ - if (container != null) - { - this.toolbar = new mxToolbar(container); - - // Installs the insert function in the editor if an item is - // selected in the toolbar - this.toolbar.addListener(mxEvent.SELECT, - mxUtils.bind(this, function(sender, evt) - { - var funct = evt.getProperty('function'); - - if (funct != null) - { - this.editor.insertFunction = mxUtils.bind(this, function() - { - funct.apply(this, arguments); - this.toolbar.resetMode(); - }); - } - else - { - this.editor.insertFunction = null; - } - }) - ); - - // Resets the selected tool after a doubleclick or escape keystroke - this.resetHandler = mxUtils.bind(this, function() - { - if (this.toolbar != null) - { - this.toolbar.resetMode(true); - } - }); - - this.editor.graph.addListener(mxEvent.DOUBLE_CLICK, this.resetHandler); - this.editor.addListener(mxEvent.ESCAPE, this.resetHandler); - } -}; - -/** - * Function: addItem - * - * Adds a new item that executes the given action in <editor>. The title, - * icon and pressedIcon are used to display the toolbar item. - * - * Parameters: - * - * title - String that represents the title (tooltip) for the item. - * icon - URL of the icon to be used for displaying the item. - * action - Name of the action to execute when the item is clicked. - * pressed - Optional URL of the icon for the pressed state. - */ -mxDefaultToolbar.prototype.addItem = function(title, icon, action, pressed) -{ - var clickHandler = mxUtils.bind(this, function() - { - if (action != null && action.length > 0) - { - this.editor.execute(action); - } - }); - - return this.toolbar.addItem(title, icon, clickHandler, pressed); -}; - -/** - * Function: addSeparator - * - * Adds a vertical separator using the optional icon. - * - * Parameters: - * - * icon - Optional URL of the icon that represents the vertical separator. - * Default is <mxClient.imageBasePath> + '/separator.gif'. - */ -mxDefaultToolbar.prototype.addSeparator = function(icon) -{ - icon = icon || mxClient.imageBasePath + '/separator.gif'; - this.toolbar.addSeparator(icon); -}; - -/** - * Function: addCombo - * - * Helper method to invoke <mxToolbar.addCombo> on <toolbar> and return the - * resulting DOM node. - */ -mxDefaultToolbar.prototype.addCombo = function() -{ - return this.toolbar.addCombo(); -}; - -/** - * Function: addActionCombo - * - * Helper method to invoke <mxToolbar.addActionCombo> on <toolbar> using - * the given title and return the resulting DOM node. - * - * Parameters: - * - * title - String that represents the title of the combo. - */ -mxDefaultToolbar.prototype.addActionCombo = function(title) -{ - return this.toolbar.addActionCombo(title); -}; - -/** - * Function: addActionOption - * - * Binds the given action to a option with the specified label in the - * given combo. Combo is an object returned from an earlier call to - * <addCombo> or <addActionCombo>. - * - * Parameters: - * - * combo - DOM node that represents the combo box. - * title - String that represents the title of the combo. - * action - Name of the action to execute in <editor>. - */ -mxDefaultToolbar.prototype.addActionOption = function(combo, title, action) -{ - var clickHandler = mxUtils.bind(this, function() - { - this.editor.execute(action); - }); - - this.addOption(combo, title, clickHandler); -}; - -/** - * Function: addOption - * - * Helper method to invoke <mxToolbar.addOption> on <toolbar> and return - * the resulting DOM node that represents the option. - * - * Parameters: - * - * combo - DOM node that represents the combo box. - * title - String that represents the title of the combo. - * value - Object that represents the value of the option. - */ -mxDefaultToolbar.prototype.addOption = function(combo, title, value) -{ - return this.toolbar.addOption(combo, title, value); -}; - -/** - * Function: addMode - * - * Creates an item for selecting the given mode in the <editor>'s graph. - * Supported modenames are select, connect and pan. - * - * Parameters: - * - * title - String that represents the title of the item. - * icon - URL of the icon that represents the item. - * mode - String that represents the mode name to be used in - * <mxEditor.setMode>. - * pressed - Optional URL of the icon that represents the pressed state. - * funct - Optional JavaScript function that takes the <mxEditor> as the - * first and only argument that is executed after the mode has been - * selected. - */ -mxDefaultToolbar.prototype.addMode = function(title, icon, mode, pressed, funct) -{ - var clickHandler = mxUtils.bind(this, function() - { - this.editor.setMode(mode); - - if (funct != null) - { - funct(this.editor); - } - }); - - return this.toolbar.addSwitchMode(title, icon, clickHandler, pressed); -}; - -/** - * Function: addPrototype - * - * Creates an item for inserting a clone of the specified prototype cell into - * the <editor>'s graph. The ptype may either be a cell or a function that - * returns a cell. - * - * Parameters: - * - * title - String that represents the title of the item. - * icon - URL of the icon that represents the item. - * ptype - Function or object that represents the prototype cell. If ptype - * is a function then it is invoked with no arguments to create new - * instances. - * pressed - Optional URL of the icon that represents the pressed state. - * insert - Optional JavaScript function that handles an insert of the new - * cell. This function takes the <mxEditor>, new cell to be inserted, mouse - * event and optional <mxCell> under the mouse pointer as arguments. - * toggle - Optional boolean that specifies if the item can be toggled. - * Default is true. - */ -mxDefaultToolbar.prototype.addPrototype = function(title, icon, ptype, pressed, insert, toggle) -{ - // Creates a wrapper function that is in charge of constructing - // the new cell instance to be inserted into the graph - var factory = function() - { - if (typeof(ptype) == 'function') - { - return ptype(); - } - else if (ptype != null) - { - return ptype.clone(); - } - - return null; - }; - - // Defines the function for a click event on the graph - // after this item has been selected in the toolbar - var clickHandler = mxUtils.bind(this, function(evt, cell) - { - if (typeof(insert) == 'function') - { - insert(this.editor, factory(), evt, cell); - } - else - { - this.drop(factory(), evt, cell); - } - - this.toolbar.resetMode(); - mxEvent.consume(evt); - }); - - var img = this.toolbar.addMode(title, icon, clickHandler, pressed, null, toggle); - - // Creates a wrapper function that calls the click handler without - // the graph argument - var dropHandler = function(graph, evt, cell) - { - clickHandler(evt, cell); - }; - - this.installDropHandler(img, dropHandler); - - return img; -}; - -/** - * Function: drop - * - * Handles a drop from a toolbar item to the graph. The given vertex - * represents the new cell to be inserted. This invokes <insert> or - * <connect> depending on the given target cell. - * - * Parameters: - * - * vertex - <mxCell> to be inserted. - * evt - Mouse event that represents the drop. - * target - Optional <mxCell> that represents the drop target. - */ -mxDefaultToolbar.prototype.drop = function(vertex, evt, target) -{ - var graph = this.editor.graph; - var model = graph.getModel(); - - if (target == null || - model.isEdge(target) || - !this.connectOnDrop || - !graph.isCellConnectable(target)) - { - while (target != null && - !graph.isValidDropTarget(target, [vertex], evt)) - { - target = model.getParent(target); - } - - this.insert(vertex, evt, target); - } - else - { - this.connect(vertex, evt, target); - } -}; - -/** - * Function: insert - * - * Handles a drop by inserting the given vertex into the given parent cell - * or the default parent if no parent is specified. - * - * Parameters: - * - * vertex - <mxCell> to be inserted. - * evt - Mouse event that represents the drop. - * parent - Optional <mxCell> that represents the parent. - */ -mxDefaultToolbar.prototype.insert = function(vertex, evt, target) -{ - var graph = this.editor.graph; - - if (graph.canImportCell(vertex)) - { - var x = mxEvent.getClientX(evt); - var y = mxEvent.getClientY(evt); - var pt = mxUtils.convertPoint(graph.container, x, y); - - // Splits the target edge or inserts into target group - if (graph.isSplitEnabled() && - graph.isSplitTarget(target, [vertex], evt)) - { - return graph.splitEdge(target, [vertex], null, pt.x, pt.y); - } - else - { - return this.editor.addVertex(target, vertex, pt.x, pt.y); - } - } - - return null; -}; - -/** - * Function: connect - * - * Handles a drop by connecting the given vertex to the given source cell. - * - * vertex - <mxCell> to be inserted. - * evt - Mouse event that represents the drop. - * source - Optional <mxCell> that represents the source terminal. - */ -mxDefaultToolbar.prototype.connect = function(vertex, evt, source) -{ - var graph = this.editor.graph; - var model = graph.getModel(); - - if (source != null && - graph.isCellConnectable(vertex) && - graph.isEdgeValid(null, source, vertex)) - { - var edge = null; - - model.beginUpdate(); - try - { - var geo = model.getGeometry(source); - var g = model.getGeometry(vertex).clone(); - - // Moves the vertex away from the drop target that will - // be used as the source for the new connection - g.x = geo.x + (geo.width - g.width) / 2; - g.y = geo.y + (geo.height - g.height) / 2; - - var step = this.spacing * graph.gridSize; - var dist = model.getDirectedEdgeCount(source, true) * 20; - - if (this.editor.horizontalFlow) - { - g.x += (g.width + geo.width) / 2 + step + dist; - } - else - { - g.y += (g.height + geo.height) / 2 + step + dist; - } - - vertex.setGeometry(g); - - // Fires two add-events with the code below - should be fixed - // to only fire one add event for both inserts - var parent = model.getParent(source); - graph.addCell(vertex, parent); - graph.constrainChild(vertex); - - // Creates the edge using the editor instance and calls - // the second function that fires an add event - edge = this.editor.createEdge(source, vertex); - - if (model.getGeometry(edge) == null) - { - var edgeGeometry = new mxGeometry(); - edgeGeometry.relative = true; - - model.setGeometry(edge, edgeGeometry); - } - - graph.addEdge(edge, parent, source, vertex); - } - finally - { - model.endUpdate(); - } - - graph.setSelectionCells([vertex, edge]); - graph.scrollCellToVisible(vertex); - } -}; - -/** - * Function: installDropHandler - * - * Makes the given img draggable using the given function for handling a - * drop event. - * - * Parameters: - * - * img - DOM node that represents the image. - * dropHandler - Function that handles a drop of the image. - */ -mxDefaultToolbar.prototype.installDropHandler = function (img, dropHandler) -{ - var sprite = document.createElement('img'); - sprite.setAttribute('src', img.getAttribute('src')); - - // Handles delayed loading of the images - var loader = mxUtils.bind(this, function(evt) - { - // Preview uses the image node with double size. Later this can be - // changed to use a separate preview and guides, but for this the - // dropHandler must use the additional x- and y-arguments and the - // dragsource which makeDraggable returns much be configured to - // use guides via mxDragSource.isGuidesEnabled. - sprite.style.width = (2 * img.offsetWidth) + 'px'; - sprite.style.height = (2 * img.offsetHeight) + 'px'; - - mxUtils.makeDraggable(img, this.editor.graph, dropHandler, - sprite); - mxEvent.removeListener(sprite, 'load', loader); - }); - - if (mxClient.IS_IE) - { - loader(); - } - else - { - mxEvent.addListener(sprite, 'load', loader); - } -}; - -/** - * Function: destroy - * - * Destroys the <toolbar> associated with this object and removes all - * installed listeners. This does normally not need to be called, the - * <toolbar> is destroyed automatically when the window unloads (in IE) by - * <mxEditor>. - */ -mxDefaultToolbar.prototype.destroy = function () -{ - if (this.resetHandler != null) - { - this.editor.graph.removeListener('dblclick', this.resetHandler); - this.editor.removeListener('escape', this.resetHandler); - this.resetHandler = null; - } - - if (this.toolbar != null) - { - this.toolbar.destroy(); - this.toolbar = null; - } -}; diff --git a/src/js/editor/mxEditor.js b/src/js/editor/mxEditor.js deleted file mode 100644 index 9c57a9c..0000000 --- a/src/js/editor/mxEditor.js +++ /dev/null @@ -1,3220 +0,0 @@ -/** - * $Id: mxEditor.js,v 1.231 2012-12-03 18:02:25 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -/** - * Class: mxEditor - * - * Extends <mxEventSource> to implement a application wrapper for a graph that - * adds <actions>, I/O using <mxCodec>, auto-layout using <mxLayoutManager>, - * command history using <undoManager>, and standard dialogs and widgets, eg. - * properties, help, outline, toolbar, and popupmenu. It also adds <templates> - * to be used as cells in toolbars, auto-validation using the <validation> - * flag, attribute cycling using <cycleAttributeValues>, higher-level events - * such as <root>, and backend integration using <urlPost>, <urlImage>, - * <urlInit>, <urlNotify> and <urlPoll>. - * - * Actions: - * - * Actions are functions stored in the <actions> array under their names. The - * functions take the <mxEditor> as the first, and an optional <mxCell> as the - * second argument and are invoked using <execute>. Any additional arguments - * passed to execute are passed on to the action as-is. - * - * A list of built-in actions is available in the <addActions> description. - * - * Read/write Diagrams: - * - * To read a diagram from an XML string, for example from a textfield within the - * page, the following code is used: - * - * (code) - * var doc = mxUtils.parseXML(xmlString); - * var node = doc.documentElement; - * editor.readGraphModel(node); - * (end) - * - * For reading a diagram from a remote location, use the <open> method. - * - * To save diagrams in XML on a server, you can set the <urlPost> variable. - * This variable will be used in <getUrlPost> to construct a URL for the post - * request that is issued in the <save> method. The post request contains the - * XML representation of the diagram as returned by <writeGraphModel> in the - * xml parameter. - * - * On the server side, the post request is processed using standard - * technologies such as Java Servlets, CGI, .NET or ASP. - * - * Here are some examples of processing a post request in various languages. - * - * - Java: URLDecoder.decode(request.getParameter("xml"), "UTF-8").replace("\n", "
") - * - * Note that the linefeeds should only be replaced if the XML is - * processed in Java, for example when creating an image, but not - * if the XML is passed back to the client-side. - * - * - .NET: HttpUtility.UrlDecode(context.Request.Params["xml"]) - * - PHP: urldecode($_POST["xml"]) - * - * Creating images: - * - * A backend (Java, PHP or C#) is required for creating images. The - * distribution contains an example for each backend (ImageHandler.java, - * ImageHandler.cs and graph.php). More information about using a backend - * to create images can be found in the readme.html files. Note that the - * preview is implemented using VML/SVG in the browser and does not require - * a backend. The backend is only required to creates images (bitmaps). - * - * Special characters: - * - * Note There are five characters that should always appear in XML content as - * escapes, so that they do not interact with the syntax of the markup. These - * are part of the language for all documents based on XML and for HTML. - * - * - < (<) - * - > (>) - * - & (&) - * - " (") - * - ' (') - * - * Although it is part of the XML language, ' is not defined in HTML. - * For this reason the XHTML specification recommends instead the use of - * ' if text may be passed to a HTML user agent. - * - * If you are having problems with special characters on the server-side then - * you may want to try the <escapePostData> flag. - * - * For converting decimal escape sequences inside strings, a user has provided - * us with the following function: - * - * (code) - * function html2js(text) - * { - * var entitySearch = /&#[0-9]+;/; - * var entity; - * - * while (entity = entitySearch.exec(text)) - * { - * var charCode = entity[0].substring(2, entity[0].length -1); - * text = text.substring(0, entity.index) - * + String.fromCharCode(charCode) - * + text.substring(entity.index + entity[0].length); - * } - * - * return text; - * } - * (end) - * - * Otherwise try using hex escape sequences and the built-in unescape function - * for converting such strings. - * - * Local Files: - * - * For saving and opening local files, no standardized method exists that - * works across all browsers. The recommended way of dealing with local files - * is to create a backend that streams the XML data back to the browser (echo) - * as an attachment so that a Save-dialog is displayed on the client-side and - * the file can be saved to the local disk. - * - * For example, in PHP the code that does this looks as follows. - * - * (code) - * $xml = stripslashes($_POST["xml"]); - * header("Content-Disposition: attachment; filename=\"diagram.xml\""); - * echo($xml); - * (end) - * - * To open a local file, the file should be uploaded via a form in the browser - * and then opened from the server in the editor. - * - * Cell Properties: - * - * The properties displayed in the properties dialog are the attributes and - * values of the cell's user object, which is an XML node. The XML node is - * defined in the templates section of the config file. - * - * The templates are stored in <mxEditor.templates> and contain cells which - * are cloned at insertion time to create new vertices by use of drag and - * drop from the toolbar. Each entry in the toolbar for adding a new vertex - * must refer to an existing template. - * - * In the following example, the task node is a business object and only the - * mxCell node and its mxGeometry child contain graph information: - * - * (code) - * <Task label="Task" description=""> - * <mxCell vertex="true"> - * <mxGeometry as="geometry" width="72" height="32"/> - * </mxCell> - * </Task> - * (end) - * - * The idea is that the XML representation is inverse from the in-memory - * representation: The outer XML node is the user object and the inner node is - * the cell. This means the user object of the cell is the Task node with no - * children for the above example: - * - * (code) - * <Task label="Task" description=""/> - * (end) - * - * The Task node can have any tag name, attributes and child nodes. The - * <mxCodec> will use the XML hierarchy as the user object, while removing the - * "known annotations", such as the mxCell node. At save-time the cell data - * will be "merged" back into the user object. The user object is only modified - * via the properties dialog during the lifecycle of the cell. - * - * In the default implementation of <createProperties>, the user object's - * attributes are put into a form for editing. Attributes are changed using - * the <mxCellAttributeChange> action in the model. The dialog can be replaced - * by overriding the <createProperties> hook or by replacing the showProperties - * action in <actions>. Alternatively, the entry in the config file's popupmenu - * section can be modified to invoke a different action. - * - * If you want to displey the properties dialog on a doubleclick, you can set - * <mxEditor.dblClickAction> to showProperties as follows: - * - * (code) - * editor.dblClickAction = 'showProperties'; - * (end) - * - * Popupmenu and Toolbar: - * - * The toolbar and popupmenu are typically configured using the respective - * sections in the config file, that is, the popupmenu is defined as follows: - * - * (code) - * <mxEditor> - * <mxDefaultPopupMenu as="popupHandler"> - * <add as="cut" action="cut" icon="images/cut.gif"/> - * ... - * (end) - * - * New entries can be added to the toolbar by inserting an add-node into the - * above configuration. Existing entries may be removed and changed by - * modifying or removing the respective entries in the configuration. - * The configuration is read by the <mxDefaultPopupMenuCodec>, the format of the - * configuration is explained in <mxDefaultPopupMenu.decode>. - * - * The toolbar is defined in the mxDefaultToolbar section. Items can be added - * and removed in this section. - * - * (code) - * <mxEditor> - * <mxDefaultToolbar> - * <add as="save" action="save" icon="images/save.gif"/> - * <add as="Swimlane" template="swimlane" icon="images/swimlane.gif"/> - * ... - * (end) - * - * The format of the configuration is described in - * <mxDefaultToolbarCodec.decode>. - * - * Ids: - * - * For the IDs, there is an implicit behaviour in <mxCodec>: It moves the Id - * from the cell to the user object at encoding time and vice versa at decoding - * time. For example, if the Task node from above has an id attribute, then - * the <mxCell.id> of the corresponding cell will have this value. If there - * is no Id collision in the model, then the cell may be retrieved using this - * Id with the <mxGraphModel.getCell> function. If there is a collision, a new - * Id will be created for the cell using <mxGraphModel.createId>. At encoding - * time, this new Id will replace the value previously stored under the id - * attribute in the Task node. - * - * See <mxEditorCodec>, <mxDefaultToolbarCodec> and <mxDefaultPopupMenuCodec> - * for information about configuring the editor and user interface. - * - * Programmatically inserting cells: - * - * For inserting a new cell, say, by clicking a button in the document, - * the following code can be used. This requires an reference to the editor. - * - * (code) - * var userObject = new Object(); - * var parent = editor.graph.getDefaultParent(); - * var model = editor.graph.model; - * model.beginUpdate(); - * try - * { - * editor.graph.insertVertex(parent, null, userObject, 20, 20, 80, 30); - * } - * finally - * { - * model.endUpdate(); - * } - * (end) - * - * If a template cell from the config file should be inserted, then a clone - * of the template can be created as follows. The clone is then inserted using - * the add function instead of addVertex. - * - * (code) - * var template = editor.templates['task']; - * var clone = editor.graph.model.cloneCell(template); - * (end) - * - * Resources: - * - * resources/editor - Language resources for mxEditor - * - * Callback: onInit - * - * Called from within the constructor. In the callback, - * "this" refers to the editor instance. - * - * Cookie: mxgraph=seen - * - * Set when the editor is started. Never expires. Use - * <resetFirstTime> to reset this cookie. This cookie - * only exists if <onInit> is implemented. - * - * Event: mxEvent.OPEN - * - * Fires after a file was opened in <open>. The <code>filename</code> property - * contains the filename that was used. The same value is also available in - * <filename>. - * - * Event: mxEvent.SAVE - * - * Fires after the current file was saved in <save>. The <code>url</code> - * property contains the URL that was used for saving. - * - * Event: mxEvent.POST - * - * Fires if a successful response was received in <postDiagram>. The - * <code>request</code> property contains the <mxXmlRequest>, the - * <code>url</code> and <code>data</code> properties contain the URL and the - * data that were used in the post request. - * - * Event: mxEvent.ROOT - * - * Fires when the current root has changed, or when the title of the current - * root has changed. This event has no properties. - * - * Event: mxEvent.SESSION - * - * Fires when anything in the session has changed. The <code>session</code> - * property contains the respective <mxSession>. - * - * Event: mxEvent.BEFORE_ADD_VERTEX - * - * Fires before a vertex is added in <addVertex>. The <code>vertex</code> - * property contains the new vertex and the <code>parent</code> property - * contains its parent. - * - * Event: mxEvent.ADD_VERTEX - * - * Fires between begin- and endUpdate in <addVertex>. The <code>vertex</code> - * property contains the vertex that is being inserted. - * - * Event: mxEvent.AFTER_ADD_VERTEX - * - * Fires after a vertex was inserted and selected in <addVertex>. The - * <code>vertex</code> property contains the new vertex. - * - * Example: - * - * For starting an in-place edit after a new vertex has been added to the - * graph, the following code can be used. - * - * (code) - * editor.addListener(mxEvent.AFTER_ADD_VERTEX, function(sender, evt) - * { - * var vertex = evt.getProperty('vertex'); - * - * if (editor.graph.isCellEditable(vertex)) - * { - * editor.graph.startEditingAtCell(vertex); - * } - * }); - * (end) - * - * Event: mxEvent.ESCAPE - * - * Fires when the escape key is pressed. The <code>event</code> property - * contains the key event. - * - * Constructor: mxEditor - * - * Constructs a new editor. This function invokes the <onInit> callback - * upon completion. - * - * Example: - * - * (code) - * var config = mxUtils.load('config/diagrameditor.xml').getDocumentElement(); - * var editor = new mxEditor(config); - * (end) - * - * Parameters: - * - * config - Optional XML node that contains the configuration. - */ -function mxEditor(config) -{ - this.actions = []; - this.addActions(); - - // Executes the following only if a document has been instanciated. - // That is, don't execute when the editorcodec is setup. - if (document.body != null) - { - // Defines instance fields - this.cycleAttributeValues = []; - this.popupHandler = new mxDefaultPopupMenu(); - this.undoManager = new mxUndoManager(); - - // Creates the graph and toolbar without the containers - this.graph = this.createGraph(); - this.toolbar = this.createToolbar(); - - // Creates the global keyhandler (requires graph instance) - this.keyHandler = new mxDefaultKeyHandler(this); - - // Configures the editor using the URI - // which was passed to the ctor - this.configure(config); - - // Assigns the swimlaneIndicatorColorAttribute on the graph - this.graph.swimlaneIndicatorColorAttribute = this.cycleAttributeName; - - // Initializes the session if the urlInit - // member field of this editor is set. - if (!mxClient.IS_LOCAL && this.urlInit != null) - { - this.session = this.createSession(); - } - - // Checks ifthe <onInit> hook has been set - if (this.onInit != null) - { - // Invokes the <onInit> hook - this.onInit(); - } - - // Automatic deallocation of memory - if (mxClient.IS_IE) - { - mxEvent.addListener(window, 'unload', mxUtils.bind(this, function() - { - this.destroy(); - })); - } - } -}; - -/** - * Installs the required language resources at class - * loading time. - */ -if (mxLoadResources) -{ - mxResources.add(mxClient.basePath+'/resources/editor'); -} - -/** - * Extends mxEventSource. - */ -mxEditor.prototype = new mxEventSource(); -mxEditor.prototype.constructor = mxEditor; - -/** - * Group: Controls and Handlers - */ - -/** - * Variable: askZoomResource - * - * Specifies the resource key for the zoom dialog. If the resource for this - * key does not exist then the value is used as the error message. Default - * is 'askZoom'. - */ -mxEditor.prototype.askZoomResource = (mxClient.language != 'none') ? 'askZoom' : ''; - -/** - * Variable: lastSavedResource - * - * Specifies the resource key for the last saved info. If the resource for - * this key does not exist then the value is used as the error message. - * Default is 'lastSaved'. - */ -mxEditor.prototype.lastSavedResource = (mxClient.language != 'none') ? 'lastSaved' : ''; - -/** - * Variable: currentFileResource - * - * Specifies the resource key for the current file info. If the resource for - * this key does not exist then the value is used as the error message. - * Default is 'lastSaved'. - */ -mxEditor.prototype.currentFileResource = (mxClient.language != 'none') ? 'currentFile' : ''; - -/** - * Variable: propertiesResource - * - * Specifies the resource key for the properties window title. If the - * resource for this key does not exist then the value is used as the - * error message. Default is 'properties'. - */ -mxEditor.prototype.propertiesResource = (mxClient.language != 'none') ? 'properties' : ''; - -/** - * Variable: tasksResource - * - * Specifies the resource key for the tasks window title. If the - * resource for this key does not exist then the value is used as the - * error message. Default is 'tasks'. - */ -mxEditor.prototype.tasksResource = (mxClient.language != 'none') ? 'tasks' : ''; - -/** - * Variable: helpResource - * - * Specifies the resource key for the help window title. If the - * resource for this key does not exist then the value is used as the - * error message. Default is 'help'. - */ -mxEditor.prototype.helpResource = (mxClient.language != 'none') ? 'help' : ''; - -/** - * Variable: outlineResource - * - * Specifies the resource key for the outline window title. If the - * resource for this key does not exist then the value is used as the - * error message. Default is 'outline'. - */ -mxEditor.prototype.outlineResource = (mxClient.language != 'none') ? 'outline' : ''; - -/** - * Variable: outline - * - * Reference to the <mxWindow> that contains the outline. The <mxOutline> - * is stored in outline.outline. - */ -mxEditor.prototype.outline = null; - -/** - * Variable: graph - * - * Holds a <mxGraph> for displaying the diagram. The graph - * is created in <setGraphContainer>. - */ -mxEditor.prototype.graph = null; - -/** - * Variable: graphRenderHint - * - * Holds the render hint used for creating the - * graph in <setGraphContainer>. See <mxGraph>. - * Default is null. - */ -mxEditor.prototype.graphRenderHint = null; - -/** - * Variable: toolbar - * - * Holds a <mxDefaultToolbar> for displaying the toolbar. The - * toolbar is created in <setToolbarContainer>. - */ -mxEditor.prototype.toolbar = null; - -/** - * Variable: session - * - * Holds a <mxSession> instance associated with this editor. - */ -mxEditor.prototype.session = null; - -/** - * Variable: status - * - * DOM container that holds the statusbar. Default is null. - * Use <setStatusContainer> to set this value. - */ -mxEditor.prototype.status = null; - -/** - * Variable: popupHandler - * - * Holds a <mxDefaultPopupMenu> for displaying - * popupmenus. - */ -mxEditor.prototype.popupHandler = null; - -/** - * Variable: undoManager - * - * Holds an <mxUndoManager> for the command history. - */ -mxEditor.prototype.undoManager = null; - -/** - * Variable: keyHandler - * - * Holds a <mxDefaultKeyHandler> for handling keyboard events. - * The handler is created in <setGraphContainer>. - */ -mxEditor.prototype.keyHandler = null; - -/** - * Group: Actions and Options - */ - -/** - * Variable: actions - * - * Maps from actionnames to actions, which are functions taking - * the editor and the cell as arguments. Use <addAction> - * to add or replace an action and <execute> to execute an action - * by name, passing the cell to be operated upon as the second - * argument. - */ -mxEditor.prototype.actions = null; - -/** - * Variable: dblClickAction - * - * Specifies the name of the action to be executed - * when a cell is double clicked. Default is edit. - * - * To handle a singleclick, use the following code. - * - * (code) - * editor.graph.addListener(mxEvent.CLICK, function(sender, evt) - * { - * var e = evt.getProperty('event'); - * var cell = evt.getProperty('cell'); - * - * if (cell != null && !e.isConsumed()) - * { - * // Do something useful with cell... - * e.consume(); - * } - * }); - * (end) - */ -mxEditor.prototype.dblClickAction = 'edit'; - -/** - * Variable: swimlaneRequired - * - * Specifies if new cells must be inserted - * into an existing swimlane. Otherwise, cells - * that are not swimlanes can be inserted as - * top-level cells. Default is false. - */ -mxEditor.prototype.swimlaneRequired = false; - -/** - * Variable: disableContextMenu - * - * Specifies if the context menu should be disabled in the graph container. - * Default is true. - */ -mxEditor.prototype.disableContextMenu = true; - -/** - * Group: Templates - */ - -/** - * Variable: insertFunction - * - * Specifies the function to be used for inserting new - * cells into the graph. This is assigned from the - * <mxDefaultToolbar> if a vertex-tool is clicked. - */ -mxEditor.prototype.insertFunction = null; - -/** - * Variable: forcedInserting - * - * Specifies if a new cell should be inserted on a single - * click even using <insertFunction> if there is a cell - * under the mousepointer, otherwise the cell under the - * mousepointer is selected. Default is false. - */ -mxEditor.prototype.forcedInserting = false; - -/** - * Variable: templates - * - * Maps from names to protoype cells to be used - * in the toolbar for inserting new cells into - * the diagram. - */ -mxEditor.prototype.templates = null; - -/** - * Variable: defaultEdge - * - * Prototype edge cell that is used for creating - * new edges. - */ -mxEditor.prototype.defaultEdge = null; - -/** - * Variable: defaultEdgeStyle - * - * Specifies the edge style to be returned in <getEdgeStyle>. - * Default is null. - */ -mxEditor.prototype.defaultEdgeStyle = null; - -/** - * Variable: defaultGroup - * - * Prototype group cell that is used for creating - * new groups. - */ -mxEditor.prototype.defaultGroup = null; - -/** - * Variable: graphRenderHint - * - * Default size for the border of new groups. If null, - * then then <mxGraph.gridSize> is used. Default is - * null. - */ -mxEditor.prototype.groupBorderSize = null; - -/** - * Group: Backend Integration - */ - -/** - * Variable: filename - * - * Contains the URL of the last opened file as a string. - * Default is null. - */ -mxEditor.prototype.filename = null; - -/** - * Variable: lineFeed - * - * Character to be used for encoding linefeeds in <save>. Default is '
'. - */ -mxEditor.prototype.linefeed = '
'; - -/** - * Variable: postParameterName - * - * Specifies if the name of the post parameter that contains the diagram - * data in a post request to the server. Default is xml. - */ -mxEditor.prototype.postParameterName = 'xml'; - -/** - * Variable: escapePostData - * - * Specifies if the data in the post request for saving a diagram - * should be converted using encodeURIComponent. Default is true. - */ -mxEditor.prototype.escapePostData = true; - -/** - * Variable: urlPost - * - * Specifies the URL to be used for posting the diagram - * to a backend in <save>. - */ -mxEditor.prototype.urlPost = null; - -/** - * Variable: urlImage - * - * Specifies the URL to be used for creating a bitmap of - * the graph in the image action. - */ -mxEditor.prototype.urlImage = null; - -/** - * Variable: urlInit - * - * Specifies the URL to be used for initializing the session. - */ -mxEditor.prototype.urlInit = null; - -/** - * Variable: urlNotify - * - * Specifies the URL to be used for notifying the backend - * in the session. - */ -mxEditor.prototype.urlNotify = null; - -/** - * Variable: urlPoll - * - * Specifies the URL to be used for polling in the session. - */ -mxEditor.prototype.urlPoll = null; - -/** - * Group: Autolayout - */ - -/** - * Variable: horizontalFlow - * - * Specifies the direction of the flow - * in the diagram. This is used in the - * layout algorithms. Default is false, - * ie. vertical flow. - */ -mxEditor.prototype.horizontalFlow = false; - -/** - * Variable: layoutDiagram - * - * Specifies if the top-level elements in the - * diagram should be layed out using a vertical - * or horizontal stack depending on the setting - * of <horizontalFlow>. The spacing between the - * swimlanes is specified by <swimlaneSpacing>. - * Default is false. - * - * If the top-level elements are swimlanes, then - * the intra-swimlane layout is activated by - * the <layoutSwimlanes> switch. - */ -mxEditor.prototype.layoutDiagram = false; - -/** - * Variable: swimlaneSpacing - * - * Specifies the spacing between swimlanes if - * automatic layout is turned on in - * <layoutDiagram>. Default is 0. - */ -mxEditor.prototype.swimlaneSpacing = 0; - -/** - * Variable: maintainSwimlanes - * - * Specifies if the swimlanes should be kept at the same - * width or height depending on the setting of - * <horizontalFlow>. Default is false. - * - * For horizontal flows, all swimlanes - * have the same height and for vertical flows, all swimlanes - * have the same width. Furthermore, the swimlanes are - * automatically "stacked" if <layoutDiagram> is true. - */ -mxEditor.prototype.maintainSwimlanes = false; - -/** - * Variable: layoutSwimlanes - * - * Specifies if the children of swimlanes should - * be layed out, either vertically or horizontally - * depending on <horizontalFlow>. - * Default is false. - */ -mxEditor.prototype.layoutSwimlanes = false; - -/** - * Group: Attribute Cycling - */ - -/** - * Variable: cycleAttributeValues - * - * Specifies the attribute values to be cycled when - * inserting new swimlanes. Default is an empty - * array. - */ -mxEditor.prototype.cycleAttributeValues = null; - -/** - * Variable: cycleAttributeIndex - * - * Index of the last consumed attribute index. If a new - * swimlane is inserted, then the <cycleAttributeValues> - * at this index will be used as the value for - * <cycleAttributeName>. Default is 0. - */ -mxEditor.prototype.cycleAttributeIndex = 0; - -/** - * Variable: cycleAttributeName - * - * Name of the attribute to be assigned a <cycleAttributeValues> - * when inserting new swimlanes. Default is fillColor. - */ -mxEditor.prototype.cycleAttributeName = 'fillColor'; - -/** - * Group: Windows - */ - -/** - * Variable: tasks - * - * Holds the <mxWindow> created in <showTasks>. - */ -mxEditor.prototype.tasks = null; - -/** - * Variable: tasksWindowImage - * - * Icon for the tasks window. - */ -mxEditor.prototype.tasksWindowImage = null; - -/** - * Variable: tasksTop - * - * Specifies the top coordinate of the tasks window in pixels. - * Default is 20. - */ -mxEditor.prototype.tasksTop = 20; - -/** - * Variable: help - * - * Holds the <mxWindow> created in <showHelp>. - */ -mxEditor.prototype.help = null; - -/** - * Variable: helpWindowImage - * - * Icon for the help window. - */ -mxEditor.prototype.helpWindowImage = null; - -/** - * Variable: urlHelp - * - * Specifies the URL to be used for the contents of the - * Online Help window. This is usually specified in the - * resources file under urlHelp for language-specific - * online help support. - */ -mxEditor.prototype.urlHelp = null; - -/** - * Variable: helpWidth - * - * Specifies the width of the help window in pixels. - * Default is 300. - */ -mxEditor.prototype.helpWidth = 300; - -/** - * Variable: helpWidth - * - * Specifies the width of the help window in pixels. - * Default is 260. - */ -mxEditor.prototype.helpHeight = 260; - -/** - * Variable: propertiesWidth - * - * Specifies the width of the properties window in pixels. - * Default is 240. - */ -mxEditor.prototype.propertiesWidth = 240; - -/** - * Variable: propertiesHeight - * - * Specifies the height of the properties window in pixels. - * If no height is specified then the window will be automatically - * sized to fit its contents. Default is null. - */ -mxEditor.prototype.propertiesHeight = null; - -/** - * Variable: movePropertiesDialog - * - * Specifies if the properties dialog should be automatically - * moved near the cell it is displayed for, otherwise the - * dialog is not moved. This value is only taken into - * account if the dialog is already visible. Default is false. - */ -mxEditor.prototype.movePropertiesDialog = false; - -/** - * Variable: validating - * - * Specifies if <mxGraph.validateGraph> should automatically be invoked after - * each change. Default is false. - */ -mxEditor.prototype.validating = false; - -/** - * Variable: modified - * - * True if the graph has been modified since it was last saved. - */ -mxEditor.prototype.modified = false; - -/** - * Function: isModified - * - * Returns <modified>. - */ -mxEditor.prototype.isModified = function () -{ - return this.modified; -}; - -/** - * Function: setModified - * - * Sets <modified> to the specified boolean value. - */ -mxEditor.prototype.setModified = function (value) -{ - this.modified = value; -}; - -/** - * Function: addActions - * - * Adds the built-in actions to the editor instance. - * - * save - Saves the graph using <urlPost>. - * print - Shows the graph in a new print preview window. - * show - Shows the graph in a new window. - * exportImage - Shows the graph as a bitmap image using <getUrlImage>. - * refresh - Refreshes the graph's display. - * cut - Copies the current selection into the clipboard - * and removes it from the graph. - * copy - Copies the current selection into the clipboard. - * paste - Pastes the clipboard into the graph. - * delete - Removes the current selection from the graph. - * group - Puts the current selection into a new group. - * ungroup - Removes the selected groups and selects the children. - * undo - Undoes the last change on the graph model. - * redo - Redoes the last change on the graph model. - * zoom - Sets the zoom via a dialog. - * zoomIn - Zooms into the graph. - * zoomOut - Zooms out of the graph - * actualSize - Resets the scale and translation on the graph. - * fit - Changes the scale so that the graph fits into the window. - * showProperties - Shows the properties dialog. - * selectAll - Selects all cells. - * selectNone - Clears the selection. - * selectVertices - Selects all vertices. - * selectEdges = Selects all edges. - * edit - Starts editing the current selection cell. - * enterGroup - Drills down into the current selection cell. - * exitGroup - Moves up in the drilling hierachy - * home - Moves to the topmost parent in the drilling hierarchy - * selectPrevious - Selects the previous cell. - * selectNext - Selects the next cell. - * selectParent - Selects the parent of the selection cell. - * selectChild - Selects the first child of the selection cell. - * collapse - Collapses the currently selected cells. - * expand - Expands the currently selected cells. - * bold - Toggle bold text style. - * italic - Toggle italic text style. - * underline - Toggle underline text style. - * shadow - Toggle shadow text style. - * alignCellsLeft - Aligns the selection cells at the left. - * alignCellsCenter - Aligns the selection cells in the center. - * alignCellsRight - Aligns the selection cells at the right. - * alignCellsTop - Aligns the selection cells at the top. - * alignCellsMiddle - Aligns the selection cells in the middle. - * alignCellsBottom - Aligns the selection cells at the bottom. - * alignFontLeft - Sets the horizontal text alignment to left. - * alignFontCenter - Sets the horizontal text alignment to center. - * alignFontRight - Sets the horizontal text alignment to right. - * alignFontTop - Sets the vertical text alignment to top. - * alignFontMiddle - Sets the vertical text alignment to middle. - * alignFontBottom - Sets the vertical text alignment to bottom. - * toggleTasks - Shows or hides the tasks window. - * toggleHelp - Shows or hides the help window. - * toggleOutline - Shows or hides the outline window. - * toggleConsole - Shows or hides the console window. - */ -mxEditor.prototype.addActions = function () -{ - this.addAction('save', function(editor) - { - editor.save(); - }); - - this.addAction('print', function(editor) - { - var preview = new mxPrintPreview(editor.graph, 1); - preview.open(); - }); - - this.addAction('show', function(editor) - { - mxUtils.show(editor.graph, null, 10, 10); - }); - - this.addAction('exportImage', function(editor) - { - var url = editor.getUrlImage(); - - if (url == null || mxClient.IS_LOCAL) - { - editor.execute('show'); - } - else - { - var node = mxUtils.getViewXml(editor.graph, 1); - var xml = mxUtils.getXml(node, '\n'); - - mxUtils.submit(url, editor.postParameterName + '=' + - encodeURIComponent(xml), document, '_blank'); - } - }); - - this.addAction('refresh', function(editor) - { - editor.graph.refresh(); - }); - - this.addAction('cut', function(editor) - { - if (editor.graph.isEnabled()) - { - mxClipboard.cut(editor.graph); - } - }); - - this.addAction('copy', function(editor) - { - if (editor.graph.isEnabled()) - { - mxClipboard.copy(editor.graph); - } - }); - - this.addAction('paste', function(editor) - { - if (editor.graph.isEnabled()) - { - mxClipboard.paste(editor.graph); - } - }); - - this.addAction('delete', function(editor) - { - if (editor.graph.isEnabled()) - { - editor.graph.removeCells(); - } - }); - - this.addAction('group', function(editor) - { - if (editor.graph.isEnabled()) - { - editor.graph.setSelectionCell(editor.groupCells()); - } - }); - - this.addAction('ungroup', function(editor) - { - if (editor.graph.isEnabled()) - { - editor.graph.setSelectionCells(editor.graph.ungroupCells()); - } - }); - - this.addAction('removeFromParent', function(editor) - { - if (editor.graph.isEnabled()) - { - editor.graph.removeCellsFromParent(); - } - }); - - this.addAction('undo', function(editor) - { - if (editor.graph.isEnabled()) - { - editor.undo(); - } - }); - - this.addAction('redo', function(editor) - { - if (editor.graph.isEnabled()) - { - editor.redo(); - } - }); - - this.addAction('zoomIn', function(editor) - { - editor.graph.zoomIn(); - }); - - this.addAction('zoomOut', function(editor) - { - editor.graph.zoomOut(); - }); - - this.addAction('actualSize', function(editor) - { - editor.graph.zoomActual(); - }); - - this.addAction('fit', function(editor) - { - editor.graph.fit(); - }); - - this.addAction('showProperties', function(editor, cell) - { - editor.showProperties(cell); - }); - - this.addAction('selectAll', function(editor) - { - if (editor.graph.isEnabled()) - { - editor.graph.selectAll(); - } - }); - - this.addAction('selectNone', function(editor) - { - if (editor.graph.isEnabled()) - { - editor.graph.clearSelection(); - } - }); - - this.addAction('selectVertices', function(editor) - { - if (editor.graph.isEnabled()) - { - editor.graph.selectVertices(); - } - }); - - this.addAction('selectEdges', function(editor) - { - if (editor.graph.isEnabled()) - { - editor.graph.selectEdges(); - } - }); - - this.addAction('edit', function(editor, cell) - { - if (editor.graph.isEnabled() && - editor.graph.isCellEditable(cell)) - { - editor.graph.startEditingAtCell(cell); - } - }); - - this.addAction('toBack', function(editor, cell) - { - if (editor.graph.isEnabled()) - { - editor.graph.orderCells(true); - } - }); - - this.addAction('toFront', function(editor, cell) - { - if (editor.graph.isEnabled()) - { - editor.graph.orderCells(false); - } - }); - - this.addAction('enterGroup', function(editor, cell) - { - editor.graph.enterGroup(cell); - }); - - this.addAction('exitGroup', function(editor) - { - editor.graph.exitGroup(); - }); - - this.addAction('home', function(editor) - { - editor.graph.home(); - }); - - this.addAction('selectPrevious', function(editor) - { - if (editor.graph.isEnabled()) - { - editor.graph.selectPreviousCell(); - } - }); - - this.addAction('selectNext', function(editor) - { - if (editor.graph.isEnabled()) - { - editor.graph.selectNextCell(); - } - }); - - this.addAction('selectParent', function(editor) - { - if (editor.graph.isEnabled()) - { - editor.graph.selectParentCell(); - } - }); - - this.addAction('selectChild', function(editor) - { - if (editor.graph.isEnabled()) - { - editor.graph.selectChildCell(); - } - }); - - this.addAction('collapse', function(editor) - { - if (editor.graph.isEnabled()) - { - editor.graph.foldCells(true); - } - }); - - this.addAction('collapseAll', function(editor) - { - if (editor.graph.isEnabled()) - { - var cells = editor.graph.getChildVertices(); - editor.graph.foldCells(true, false, cells); - } - }); - - this.addAction('expand', function(editor) - { - if (editor.graph.isEnabled()) - { - editor.graph.foldCells(false); - } - }); - - this.addAction('expandAll', function(editor) - { - if (editor.graph.isEnabled()) - { - var cells = editor.graph.getChildVertices(); - editor.graph.foldCells(false, false, cells); - } - }); - - this.addAction('bold', function(editor) - { - if (editor.graph.isEnabled()) - { - editor.graph.toggleCellStyleFlags( - mxConstants.STYLE_FONTSTYLE, - mxConstants.FONT_BOLD); - } - }); - - this.addAction('italic', function(editor) - { - if (editor.graph.isEnabled()) - { - editor.graph.toggleCellStyleFlags( - mxConstants.STYLE_FONTSTYLE, - mxConstants.FONT_ITALIC); - } - }); - - this.addAction('underline', function(editor) - { - if (editor.graph.isEnabled()) - { - editor.graph.toggleCellStyleFlags( - mxConstants.STYLE_FONTSTYLE, - mxConstants.FONT_UNDERLINE); - } - }); - - this.addAction('shadow', function(editor) - { - if (editor.graph.isEnabled()) - { - editor.graph.toggleCellStyleFlags( - mxConstants.STYLE_FONTSTYLE, - mxConstants.FONT_SHADOW); - } - }); - - this.addAction('alignCellsLeft', function(editor) - { - if (editor.graph.isEnabled()) - { - editor.graph.alignCells(mxConstants.ALIGN_LEFT); - } - }); - - this.addAction('alignCellsCenter', function(editor) - { - if (editor.graph.isEnabled()) - { - editor.graph.alignCells(mxConstants.ALIGN_CENTER); - } - }); - - this.addAction('alignCellsRight', function(editor) - { - if (editor.graph.isEnabled()) - { - editor.graph.alignCells(mxConstants.ALIGN_RIGHT); - } - }); - - this.addAction('alignCellsTop', function(editor) - { - if (editor.graph.isEnabled()) - { - editor.graph.alignCells(mxConstants.ALIGN_TOP); - } - }); - - this.addAction('alignCellsMiddle', function(editor) - { - if (editor.graph.isEnabled()) - { - editor.graph.alignCells(mxConstants.ALIGN_MIDDLE); - } - }); - - this.addAction('alignCellsBottom', function(editor) - { - if (editor.graph.isEnabled()) - { - editor.graph.alignCells(mxConstants.ALIGN_BOTTOM); - } - }); - - this.addAction('alignFontLeft', function(editor) - { - - editor.graph.setCellStyles( - mxConstants.STYLE_ALIGN, - mxConstants.ALIGN_LEFT); - }); - - this.addAction('alignFontCenter', function(editor) - { - if (editor.graph.isEnabled()) - { - editor.graph.setCellStyles( - mxConstants.STYLE_ALIGN, - mxConstants.ALIGN_CENTER); - } - }); - - this.addAction('alignFontRight', function(editor) - { - if (editor.graph.isEnabled()) - { - editor.graph.setCellStyles( - mxConstants.STYLE_ALIGN, - mxConstants.ALIGN_RIGHT); - } - }); - - this.addAction('alignFontTop', function(editor) - { - if (editor.graph.isEnabled()) - { - editor.graph.setCellStyles( - mxConstants.STYLE_VERTICAL_ALIGN, - mxConstants.ALIGN_TOP); - } - }); - - this.addAction('alignFontMiddle', function(editor) - { - if (editor.graph.isEnabled()) - { - editor.graph.setCellStyles( - mxConstants.STYLE_VERTICAL_ALIGN, - mxConstants.ALIGN_MIDDLE); - } - }); - - this.addAction('alignFontBottom', function(editor) - { - if (editor.graph.isEnabled()) - { - editor.graph.setCellStyles( - mxConstants.STYLE_VERTICAL_ALIGN, - mxConstants.ALIGN_BOTTOM); - } - }); - - this.addAction('zoom', function(editor) - { - var current = editor.graph.getView().scale*100; - var scale = parseFloat(mxUtils.prompt( - mxResources.get(editor.askZoomResource) || - editor.askZoomResource, - current))/100; - - if (!isNaN(scale)) - { - editor.graph.getView().setScale(scale); - } - }); - - this.addAction('toggleTasks', function(editor) - { - if (editor.tasks != null) - { - editor.tasks.setVisible(!editor.tasks.isVisible()); - } - else - { - editor.showTasks(); - } - }); - - this.addAction('toggleHelp', function(editor) - { - if (editor.help != null) - { - editor.help.setVisible(!editor.help.isVisible()); - } - else - { - editor.showHelp(); - } - }); - - this.addAction('toggleOutline', function(editor) - { - if (editor.outline == null) - { - editor.showOutline(); - } - else - { - editor.outline.setVisible(!editor.outline.isVisible()); - } - }); - - this.addAction('toggleConsole', function(editor) - { - mxLog.setVisible(!mxLog.isVisible()); - }); -}; - -/** - * Function: createSession - * - * Creates and returns and <mxSession> using <urlInit>, <urlPoll> and <urlNotify>. - */ -mxEditor.prototype.createSession = function () -{ - // Routes any change events from the session - // through the editor and dispatches them as - // a session event. - var sessionChanged = mxUtils.bind(this, function(session) - { - this.fireEvent(new mxEventObject(mxEvent.SESSION, 'session', session)); - }); - - return this.connect(this.urlInit, this.urlPoll, - this.urlNotify, sessionChanged); -}; - -/** - * Function: configure - * - * Configures the editor using the specified node. To load the - * configuration from a given URL the following code can be used to obtain - * the XML node. - * - * (code) - * var node = mxUtils.load(url).getDocumentElement(); - * (end) - * - * Parameters: - * - * node - XML node that contains the configuration. - */ -mxEditor.prototype.configure = function (node) -{ - if (node != null) - { - // Creates a decoder for the XML data - // and uses it to configure the editor - var dec = new mxCodec(node.ownerDocument); - dec.decode(node, this); - - // Resets the counters, modified state and - // command history - this.resetHistory(); - } -}; - -/** - * Function: resetFirstTime - * - * Resets the cookie that is used to remember if the editor has already - * been used. - */ -mxEditor.prototype.resetFirstTime = function () -{ - document.cookie = - 'mxgraph=seen; expires=Fri, 27 Jul 2001 02:47:11 UTC; path=/'; -}; - -/** - * Function: resetHistory - * - * Resets the command history, modified state and counters. - */ -mxEditor.prototype.resetHistory = function () -{ - this.lastSnapshot = new Date().getTime(); - this.undoManager.clear(); - this.ignoredChanges = 0; - this.setModified(false); -}; - -/** - * Function: addAction - * - * Binds the specified actionname to the specified function. - * - * Parameters: - * - * actionname - String that specifies the name of the action - * to be added. - * funct - Function that implements the new action. The first - * argument of the function is the editor it is used - * with, the second argument is the cell it operates - * upon. - * - * Example: - * (code) - * editor.addAction('test', function(editor, cell) - * { - * mxUtils.alert("test "+cell); - * }); - * (end) - */ -mxEditor.prototype.addAction = function (actionname, funct) -{ - this.actions[actionname] = funct; -}; - -/** - * Function: execute - * - * Executes the function with the given name in <actions> passing the - * editor instance and given cell as the first and second argument. All - * additional arguments are passed to the action as well. This method - * contains a try-catch block and displays an error message if an action - * causes an exception. The exception is re-thrown after the error - * message was displayed. - * - * Example: - * - * (code) - * editor.execute("showProperties", cell); - * (end) - */ -mxEditor.prototype.execute = function (actionname, cell, evt) -{ - var action = this.actions[actionname]; - - if (action != null) - { - try - { - // Creates the array of arguments by replacing the actionname - // with the editor instance in the args of this function - var args = arguments; - args[0] = this; - - // Invokes the function on the editor using the args - action.apply(this, args); - } - catch (e) - { - mxUtils.error('Cannot execute ' + actionname + - ': ' + e.message, 280, true); - - throw e; - } - } - else - { - mxUtils.error('Cannot find action '+actionname, 280, true); - } -}; - -/** - * Function: addTemplate - * - * Adds the specified template under the given name in <templates>. - */ -mxEditor.prototype.addTemplate = function (name, template) -{ - this.templates[name] = template; -}; - -/** - * Function: getTemplate - * - * Returns the template for the given name. - */ -mxEditor.prototype.getTemplate = function (name) -{ - return this.templates[name]; -}; - -/** - * Function: createGraph - * - * Creates the <graph> for the editor. The graph is created with no - * container and is initialized from <setGraphContainer>. - */ -mxEditor.prototype.createGraph = function () -{ - var graph = new mxGraph(null, null, this.graphRenderHint); - - // Enables rubberband, tooltips, panning - graph.setTooltips(true); - graph.setPanning(true); - - // Overrides the dblclick method on the graph to - // invoke the dblClickAction for a cell and reset - // the selection tool in the toolbar - this.installDblClickHandler(graph); - - // Installs the command history - this.installUndoHandler(graph); - - // Installs the handlers for the root event - this.installDrillHandler(graph); - - // Installs the handler for validation - this.installChangeHandler(graph); - - // Installs the handler for calling the - // insert function and consume the - // event if an insert function is defined - this.installInsertHandler(graph); - - // Redirects the function for creating the - // popupmenu items - graph.panningHandler.factoryMethod = - mxUtils.bind(this, function(menu, cell, evt) - { - return this.createPopupMenu(menu, cell, evt); - }); - - // Redirects the function for creating - // new connections in the diagram - graph.connectionHandler.factoryMethod = - mxUtils.bind(this, function(source, target) - { - return this.createEdge(source, target); - }); - - // Maintains swimlanes and installs autolayout - this.createSwimlaneManager(graph); - this.createLayoutManager(graph); - - return graph; -}; - -/** - * Function: createSwimlaneManager - * - * Sets the graph's container using <mxGraph.init>. - */ -mxEditor.prototype.createSwimlaneManager = function (graph) -{ - var swimlaneMgr = new mxSwimlaneManager(graph, false); - - swimlaneMgr.isHorizontal = mxUtils.bind(this, function() - { - return this.horizontalFlow; - }); - - swimlaneMgr.isEnabled = mxUtils.bind(this, function() - { - return this.maintainSwimlanes; - }); - - return swimlaneMgr; -}; - -/** - * Function: createLayoutManager - * - * Creates a layout manager for the swimlane and diagram layouts, that - * is, the locally defined inter- and intraswimlane layouts. - */ -mxEditor.prototype.createLayoutManager = function (graph) -{ - var layoutMgr = new mxLayoutManager(graph); - - var self = this; // closure - layoutMgr.getLayout = function(cell) - { - var layout = null; - var model = self.graph.getModel(); - - if (model.getParent(cell) != null) - { - // Executes the swimlane layout if a child of - // a swimlane has been changed. The layout is - // lazy created in createSwimlaneLayout. - if (self.layoutSwimlanes && - graph.isSwimlane(cell)) - { - if (self.swimlaneLayout == null) - { - self.swimlaneLayout = self.createSwimlaneLayout(); - } - - layout = self.swimlaneLayout; - } - - // Executes the diagram layout if the modified - // cell is a top-level cell. The layout is - // lazy created in createDiagramLayout. - else if (self.layoutDiagram && - (graph.isValidRoot(cell) || - model.getParent(model.getParent(cell)) == null)) - { - if (self.diagramLayout == null) - { - self.diagramLayout = self.createDiagramLayout(); - } - - layout = self.diagramLayout; - } - } - - return layout; - }; - - return layoutMgr; -}; - -/** - * Function: setGraphContainer - * - * Sets the graph's container using <mxGraph.init>. - */ -mxEditor.prototype.setGraphContainer = function (container) -{ - if (this.graph.container == null) - { - // Creates the graph instance inside the given container and render hint - //this.graph = new mxGraph(container, null, this.graphRenderHint); - this.graph.init(container); - - // Install rubberband selection as the last - // action handler in the chain - this.rubberband = new mxRubberband(this.graph); - - // Disables the context menu - if (this.disableContextMenu) - { - mxEvent.disableContextMenu(container); - } - - // Workaround for stylesheet directives in IE - if (mxClient.IS_QUIRKS) - { - new mxDivResizer(container); - } - } -}; - -/** - * Function: installDblClickHandler - * - * Overrides <mxGraph.dblClick> to invoke <dblClickAction> - * on a cell and reset the selection tool in the toolbar. - */ -mxEditor.prototype.installDblClickHandler = function (graph) -{ - // Installs a listener for double click events - graph.addListener(mxEvent.DOUBLE_CLICK, - mxUtils.bind(this, function(sender, evt) - { - var cell = evt.getProperty('cell'); - - if (cell != null && - graph.isEnabled() && - this.dblClickAction != null) - { - this.execute(this.dblClickAction, cell); - evt.consume(); - } - }) - ); -}; - -/** - * Function: installUndoHandler - * - * Adds the <undoManager> to the graph model and the view. - */ -mxEditor.prototype.installUndoHandler = function (graph) -{ - var listener = mxUtils.bind(this, function(sender, evt) - { - var edit = evt.getProperty('edit'); - this.undoManager.undoableEditHappened(edit); - }); - - graph.getModel().addListener(mxEvent.UNDO, listener); - graph.getView().addListener(mxEvent.UNDO, listener); - - // Keeps the selection state in sync - var undoHandler = function(sender, evt) - { - var changes = evt.getProperty('edit').changes; - graph.setSelectionCells(graph.getSelectionCellsForChanges(changes)); - }; - - this.undoManager.addListener(mxEvent.UNDO, undoHandler); - this.undoManager.addListener(mxEvent.REDO, undoHandler); -}; - -/** - * Function: installDrillHandler - * - * Installs listeners for dispatching the <root> event. - */ -mxEditor.prototype.installDrillHandler = function (graph) -{ - var listener = mxUtils.bind(this, function(sender) - { - this.fireEvent(new mxEventObject(mxEvent.ROOT)); - }); - - graph.getView().addListener(mxEvent.DOWN, listener); - graph.getView().addListener(mxEvent.UP, listener); -}; - -/** - * Function: installChangeHandler - * - * Installs the listeners required to automatically validate - * the graph. On each change of the root, this implementation - * fires a <root> event. - */ -mxEditor.prototype.installChangeHandler = function (graph) -{ - var listener = mxUtils.bind(this, function(sender, evt) - { - // Updates the modified state - this.setModified(true); - - // Automatically validates the graph - // after each change - if (this.validating == true) - { - graph.validateGraph(); - } - - // Checks if the root has been changed - var changes = evt.getProperty('edit').changes; - - for (var i = 0; i < changes.length; i++) - { - var change = changes[i]; - - if (change instanceof mxRootChange || - (change instanceof mxValueChange && - change.cell == this.graph.model.root) || - (change instanceof mxCellAttributeChange && - change.cell == this.graph.model.root)) - { - this.fireEvent(new mxEventObject(mxEvent.ROOT)); - break; - } - } - }); - - graph.getModel().addListener(mxEvent.CHANGE, listener); -}; - -/** - * Function: installInsertHandler - * - * Installs the handler for invoking <insertFunction> if - * one is defined. - */ -mxEditor.prototype.installInsertHandler = function (graph) -{ - var self = this; // closure - var insertHandler = - { - mouseDown: function(sender, me) - { - if (self.insertFunction != null && - !me.isPopupTrigger() && - (self.forcedInserting || - me.getState() == null)) - { - self.graph.clearSelection(); - self.insertFunction(me.getEvent(), me.getCell()); - - // Consumes the rest of the events - // for this gesture (down, move, up) - this.isActive = true; - me.consume(); - } - }, - - mouseMove: function(sender, me) - { - if (this.isActive) - { - me.consume(); - } - }, - - mouseUp: function(sender, me) - { - if (this.isActive) - { - this.isActive = false; - me.consume(); - } - } - }; - - graph.addMouseListener(insertHandler); -}; - -/** - * Function: createDiagramLayout - * - * Creates the layout instance used to layout the - * swimlanes in the diagram. - */ -mxEditor.prototype.createDiagramLayout = function () -{ - var gs = this.graph.gridSize; - var layout = new mxStackLayout(this.graph, !this.horizontalFlow, - this.swimlaneSpacing, 2*gs, 2*gs); - - // Overrides isIgnored to only take into account swimlanes - layout.isVertexIgnored = function(cell) - { - return !layout.graph.isSwimlane(cell); - }; - - return layout; -}; - -/** - * Function: createSwimlaneLayout - * - * Creates the layout instance used to layout the - * children of each swimlane. - */ -mxEditor.prototype.createSwimlaneLayout = function () -{ - return new mxCompactTreeLayout(this.graph, this.horizontalFlow); -}; - -/** - * Function: createToolbar - * - * Creates the <toolbar> with no container. - */ -mxEditor.prototype.createToolbar = function () -{ - return new mxDefaultToolbar(null, this); -}; - -/** - * Function: setToolbarContainer - * - * Initializes the toolbar for the given container. - */ -mxEditor.prototype.setToolbarContainer = function (container) -{ - this.toolbar.init(container); - - // Workaround for stylesheet directives in IE - if (mxClient.IS_QUIRKS) - { - new mxDivResizer(container); - } -}; - -/** - * Function: setStatusContainer - * - * Creates the <status> using the specified container. - * - * This implementation adds listeners in the editor to - * display the last saved time and the current filename - * in the status bar. - * - * Parameters: - * - * container - DOM node that will contain the statusbar. - */ -mxEditor.prototype.setStatusContainer = function (container) -{ - if (this.status == null) - { - this.status = container; - - // Prints the last saved time in the status bar - // when files are saved - this.addListener(mxEvent.SAVE, mxUtils.bind(this, function() - { - var tstamp = new Date().toLocaleString(); - this.setStatus((mxResources.get(this.lastSavedResource) || - this.lastSavedResource)+': '+tstamp); - })); - - // Updates the statusbar to display the filename - // when new files are opened - this.addListener(mxEvent.OPEN, mxUtils.bind(this, function() - { - this.setStatus((mxResources.get(this.currentFileResource) || - this.currentFileResource)+': '+this.filename); - })); - - // Workaround for stylesheet directives in IE - if (mxClient.IS_QUIRKS) - { - new mxDivResizer(container); - } - } -}; - -/** - * Function: setStatus - * - * Display the specified message in the status bar. - * - * Parameters: - * - * message - String the specified the message to - * be displayed. - */ -mxEditor.prototype.setStatus = function (message) -{ - if (this.status != null && message != null) - { - this.status.innerHTML = message; - } -}; - -/** - * Function: setTitleContainer - * - * Creates a listener to update the inner HTML of the - * specified DOM node with the value of <getTitle>. - * - * Parameters: - * - * container - DOM node that will contain the title. - */ -mxEditor.prototype.setTitleContainer = function (container) -{ - this.addListener(mxEvent.ROOT, mxUtils.bind(this, function(sender) - { - container.innerHTML = this.getTitle(); - })); - - // Workaround for stylesheet directives in IE - if (mxClient.IS_QUIRKS) - { - new mxDivResizer(container); - } -}; - -/** - * Function: treeLayout - * - * Executes a vertical or horizontal compact tree layout - * using the specified cell as an argument. The cell may - * either be a group or the root of a tree. - * - * Parameters: - * - * cell - <mxCell> to use in the compact tree layout. - * horizontal - Optional boolean to specify the tree's - * orientation. Default is true. - */ -mxEditor.prototype.treeLayout = function (cell, horizontal) -{ - if (cell != null) - { - var layout = new mxCompactTreeLayout(this.graph, horizontal); - layout.execute(cell); - } -}; - -/** - * Function: getTitle - * - * Returns the string value for the current root of the - * diagram. - */ -mxEditor.prototype.getTitle = function () -{ - var title = ''; - var graph = this.graph; - var cell = graph.getCurrentRoot(); - - while (cell != null && - graph.getModel().getParent( - graph.getModel().getParent(cell)) != null) - { - // Append each label of a valid root - if (graph.isValidRoot(cell)) - { - title = ' > ' + - graph.convertValueToString(cell) + title; - } - - cell = graph.getModel().getParent(cell); - } - - var prefix = this.getRootTitle(); - - return prefix + title; -}; - -/** - * Function: getRootTitle - * - * Returns the string value of the root cell in - * <mxGraph.model>. - */ -mxEditor.prototype.getRootTitle = function () -{ - var root = this.graph.getModel().getRoot(); - return this.graph.convertValueToString(root); -}; - -/** - * Function: undo - * - * Undo the last change in <graph>. - */ -mxEditor.prototype.undo = function () -{ - this.undoManager.undo(); -}; - -/** - * Function: redo - * - * Redo the last change in <graph>. - */ -mxEditor.prototype.redo = function () -{ - this.undoManager.redo(); -}; - -/** - * Function: groupCells - * - * Invokes <createGroup> to create a new group cell and the invokes - * <mxGraph.groupCells>, using the grid size of the graph as the spacing - * in the group's content area. - */ -mxEditor.prototype.groupCells = function () -{ - var border = (this.groupBorderSize != null) ? - this.groupBorderSize : - this.graph.gridSize; - return this.graph.groupCells(this.createGroup(), border); -}; - -/** - * Function: createGroup - * - * Creates and returns a clone of <defaultGroup> to be used - * as a new group cell in <group>. - */ -mxEditor.prototype.createGroup = function () -{ - var model = this.graph.getModel(); - - return model.cloneCell(this.defaultGroup); -}; - -/** - * Function: open - * - * Opens the specified file synchronously and parses it using - * <readGraphModel>. It updates <filename> and fires an <open>-event after - * the file has been opened. Exceptions should be handled as follows: - * - * (code) - * try - * { - * editor.open(filename); - * } - * catch (e) - * { - * mxUtils.error('Cannot open ' + filename + - * ': ' + e.message, 280, true); - * } - * (end) - * - * Parameters: - * - * filename - URL of the file to be opened. - */ -mxEditor.prototype.open = function (filename) -{ - if (filename != null) - { - var xml = mxUtils.load(filename).getXml(); - this.readGraphModel(xml.documentElement); - this.filename = filename; - - this.fireEvent(new mxEventObject(mxEvent.OPEN, 'filename', filename)); - } -}; - -/** - * Function: readGraphModel - * - * Reads the specified XML node into the existing graph model and resets - * the command history and modified state. - */ -mxEditor.prototype.readGraphModel = function (node) -{ - var dec = new mxCodec(node.ownerDocument); - dec.decode(node, this.graph.getModel()); - this.resetHistory(); -}; - -/** - * Function: save - * - * Posts the string returned by <writeGraphModel> to the given URL or the - * URL returned by <getUrlPost>. The actual posting is carried out by - * <postDiagram>. If the URL is null then the resulting XML will be - * displayed using <mxUtils.popup>. Exceptions should be handled as - * follows: - * - * (code) - * try - * { - * editor.save(); - * } - * catch (e) - * { - * mxUtils.error('Cannot save : ' + e.message, 280, true); - * } - * (end) - */ -mxEditor.prototype.save = function (url, linefeed) -{ - // Gets the URL to post the data to - url = url || this.getUrlPost(); - - // Posts the data if the URL is not empty - if (url != null && url.length > 0) - { - var data = this.writeGraphModel(linefeed); - this.postDiagram(url, data); - - // Resets the modified flag - this.setModified(false); - } - - // Dispatches a save event - this.fireEvent(new mxEventObject(mxEvent.SAVE, 'url', url)); -}; - -/** - * Function: postDiagram - * - * Hook for subclassers to override the posting of a diagram - * represented by the given node to the given URL. This fires - * an asynchronous <post> event if the diagram has been posted. - * - * Example: - * - * To replace the diagram with the diagram in the response, use the - * following code. - * - * (code) - * editor.addListener(mxEvent.POST, function(sender, evt) - * { - * // Process response (replace diagram) - * var req = evt.getProperty('request'); - * var root = req.getDocumentElement(); - * editor.graph.readGraphModel(root) - * }); - * (end) - */ -mxEditor.prototype.postDiagram = function (url, data) -{ - if (this.escapePostData) - { - data = encodeURIComponent(data); - } - - mxUtils.post(url, this.postParameterName+'='+data, - mxUtils.bind(this, function(req) - { - this.fireEvent(new mxEventObject(mxEvent.POST, - 'request', req, 'url', url, 'data', data)); - }) - ); -}; - -/** - * Function: writeGraphModel - * - * Hook to create the string representation of the diagram. The default - * implementation uses an <mxCodec> to encode the graph model as - * follows: - * - * (code) - * var enc = new mxCodec(); - * var node = enc.encode(this.graph.getModel()); - * return mxUtils.getXml(node, this.linefeed); - * (end) - * - * Parameters: - * - * linefeed - Optional character to be used as the linefeed. Default is - * <linefeed>. - */ -mxEditor.prototype.writeGraphModel = function (linefeed) -{ - linefeed = (linefeed != null) ? linefeed : this.linefeed; - var enc = new mxCodec(); - var node = enc.encode(this.graph.getModel()); - - return mxUtils.getXml(node, linefeed); -}; - -/** - * Function: getUrlPost - * - * Returns the URL to post the diagram to. This is used - * in <save>. The default implementation returns <urlPost>, - * adding <code>?draft=true</code>. - */ -mxEditor.prototype.getUrlPost = function () -{ - return this.urlPost; -}; - -/** - * Function: getUrlImage - * - * Returns the URL to create the image with. This is typically - * the URL of a backend which accepts an XML representation - * of a graph view to create an image. The function is used - * in the image action to create an image. This implementation - * returns <urlImage>. - */ -mxEditor.prototype.getUrlImage = function () -{ - return this.urlImage; -}; - -/** - * Function: connect - * - * Creates and returns a session for the specified parameters, installing - * the onChange function as a change listener for the session. - */ -mxEditor.prototype.connect = function (urlInit, urlPoll, urlNotify, onChange) -{ - var session = null; - - if (!mxClient.IS_LOCAL) - { - session = new mxSession(this.graph.getModel(), - urlInit, urlPoll, urlNotify); - - // Resets the undo history if the session was initialized which is the - // case if the message carries a namespace to be used for new IDs. - session.addListener(mxEvent.RECEIVE, - mxUtils.bind(this, function(sender, evt) - { - var node = evt.getProperty('node'); - - if (node.getAttribute('namespace') != null) - { - this.resetHistory(); - } - }) - ); - - // Installs the listener for all events - // that signal a change of the session - session.addListener(mxEvent.DISCONNECT, onChange); - session.addListener(mxEvent.CONNECT, onChange); - session.addListener(mxEvent.NOTIFY, onChange); - session.addListener(mxEvent.GET, onChange); - session.start(); - } - - return session; -}; - -/** - * Function: swapStyles - * - * Swaps the styles for the given names in the graph's - * stylesheet and refreshes the graph. - */ -mxEditor.prototype.swapStyles = function (first, second) -{ - var style = this.graph.getStylesheet().styles[second]; - this.graph.getView().getStylesheet().putCellStyle( - second, this.graph.getStylesheet().styles[first]); - this.graph.getStylesheet().putCellStyle(first, style); - this.graph.refresh(); -}; - -/** - * Function: showProperties - * - * Creates and shows the properties dialog for the given - * cell. The content area of the dialog is created using - * <createProperties>. - */ -mxEditor.prototype.showProperties = function (cell) -{ - cell = cell || this.graph.getSelectionCell(); - - // Uses the root node for the properties dialog - // if not cell was passed in and no cell is - // selected - if (cell == null) - { - cell = this.graph.getCurrentRoot(); - - if (cell == null) - { - cell = this.graph.getModel().getRoot(); - } - } - - if (cell != null) - { - // Makes sure there is no in-place editor in the - // graph and computes the location of the dialog - this.graph.stopEditing(true); - - var offset = mxUtils.getOffset(this.graph.container); - var x = offset.x+10; - var y = offset.y; - - // Avoids moving the dialog if it is alredy open - if (this.properties != null && !this.movePropertiesDialog) - { - x = this.properties.getX(); - y = this.properties.getY(); - } - - // Places the dialog near the cell for which it - // displays the properties - else - { - var bounds = this.graph.getCellBounds(cell); - - if (bounds != null) - { - x += bounds.x+Math.min(200, bounds.width); - y += bounds.y; - } - } - - // Hides the existing properties dialog and creates a new one with the - // contents created in the hook method - this.hideProperties(); - var node = this.createProperties(cell); - - if (node != null) - { - // Displays the contents in a window and stores a reference to the - // window for later hiding of the window - this.properties = new mxWindow(mxResources.get(this.propertiesResource) || - this.propertiesResource, node, x, y, this.propertiesWidth, this.propertiesHeight, false); - this.properties.setVisible(true); - } - } -}; - -/** - * Function: isPropertiesVisible - * - * Returns true if the properties dialog is currently visible. - */ -mxEditor.prototype.isPropertiesVisible = function () -{ - return this.properties != null; -}; - -/** - * Function: createProperties - * - * Creates and returns the DOM node that represents the contents - * of the properties dialog for the given cell. This implementation - * works for user objects that are XML nodes and display all the - * node attributes in a form. - */ -mxEditor.prototype.createProperties = function (cell) -{ - var model = this.graph.getModel(); - var value = model.getValue(cell); - - if (mxUtils.isNode(value)) - { - // Creates a form for the user object inside - // the cell - var form = new mxForm('properties'); - - // Adds a readonly field for the cell id - var id = form.addText('ID', cell.getId()); - id.setAttribute('readonly', 'true'); - - var geo = null; - var yField = null; - var xField = null; - var widthField = null; - var heightField = null; - - // Adds fields for the location and size - if (model.isVertex(cell)) - { - geo = model.getGeometry(cell); - - if (geo != null) - { - yField = form.addText('top', geo.y); - xField = form.addText('left', geo.x); - widthField = form.addText('width', geo.width); - heightField = form.addText('height', geo.height); - } - } - - // Adds a field for the cell style - var tmp = model.getStyle(cell); - var style = form.addText('Style', tmp || ''); - - // Creates textareas for each attribute of the - // user object within the cell - var attrs = value.attributes; - var texts = []; - - for (var i = 0; i < attrs.length; i++) - { - // Creates a textarea with more lines for - // the cell label - var val = attrs[i].nodeValue; - texts[i] = form.addTextarea(attrs[i].nodeName, val, - (attrs[i].nodeName == 'label') ? 4 : 2); - } - - // Adds an OK and Cancel button to the dialog - // contents and implements the respective - // actions below - - // Defines the function to be executed when the - // OK button is pressed in the dialog - var okFunction = mxUtils.bind(this, function() - { - // Hides the dialog - this.hideProperties(); - - // Supports undo for the changes on the underlying - // XML structure / XML node attribute changes. - model.beginUpdate(); - try - { - if (geo != null) - { - geo = geo.clone(); - - geo.x = parseFloat(xField.value); - geo.y = parseFloat(yField.value); - geo.width = parseFloat(widthField.value); - geo.height = parseFloat(heightField.value); - - model.setGeometry(cell, geo); - } - - // Applies the style - if (style.value.length > 0) - { - model.setStyle(cell, style.value); - } - else - { - model.setStyle(cell, null); - } - - // Creates an undoable change for each - // attribute and executes it using the - // model, which will also make the change - // part of the current transaction - for (var i=0; i<attrs.length; i++) - { - var edit = new mxCellAttributeChange( - cell, attrs[i].nodeName, - texts[i].value); - model.execute(edit); - } - - // Checks if the graph wants cells to - // be automatically sized and updates - // the size as an undoable step if - // the feature is enabled - if (this.graph.isAutoSizeCell(cell)) - { - this.graph.updateCellSize(cell); - } - } - finally - { - model.endUpdate(); - } - }); - - // Defines the function to be executed when the - // Cancel button is pressed in the dialog - var cancelFunction = mxUtils.bind(this, function() - { - // Hides the dialog - this.hideProperties(); - }); - - form.addButtons(okFunction, cancelFunction); - - return form.table; - } - - return null; -}; - -/** - * Function: hideProperties - * - * Hides the properties dialog. - */ -mxEditor.prototype.hideProperties = function () -{ - if (this.properties != null) - { - this.properties.destroy(); - this.properties = null; - } -}; - -/** - * Function: showTasks - * - * Shows the tasks window. The tasks window is created using <createTasks>. The - * default width of the window is 200 pixels, the y-coordinate of the location - * can be specifies in <tasksTop> and the x-coordinate is right aligned with a - * 20 pixel offset from the right border. To change the location of the tasks - * window, the following code can be used: - * - * (code) - * var oldShowTasks = mxEditor.prototype.showTasks; - * mxEditor.prototype.showTasks = function() - * { - * oldShowTasks.apply(this, arguments); // "supercall" - * - * if (this.tasks != null) - * { - * this.tasks.setLocation(10, 10); - * } - * }; - * (end) - */ -mxEditor.prototype.showTasks = function () -{ - if (this.tasks == null) - { - var div = document.createElement('div'); - div.style.padding = '4px'; - div.style.paddingLeft = '20px'; - var w = document.body.clientWidth; - var wnd = new mxWindow( - mxResources.get(this.tasksResource) || - this.tasksResource, - div, w - 220, this.tasksTop, 200); - wnd.setClosable(true); - wnd.destroyOnClose = false; - - // Installs a function to update the contents - // of the tasks window on every change of the - // model, selection or root. - var funct = mxUtils.bind(this, function(sender) - { - mxEvent.release(div); - div.innerHTML = ''; - this.createTasks(div); - }); - - this.graph.getModel().addListener(mxEvent.CHANGE, funct); - this.graph.getSelectionModel().addListener(mxEvent.CHANGE, funct); - this.graph.addListener(mxEvent.ROOT, funct); - - // Assigns the icon to the tasks window - if (this.tasksWindowImage != null) - { - wnd.setImage(this.tasksWindowImage); - } - - this.tasks = wnd; - this.createTasks(div); - } - - this.tasks.setVisible(true); -}; - -/** - * Function: refreshTasks - * - * Updates the contents of the tasks window using <createTasks>. - */ -mxEditor.prototype.refreshTasks = function (div) -{ - if (this.tasks != null) - { - var div = this.tasks.content; - mxEvent.release(div); - div.innerHTML = ''; - this.createTasks(div); - } -}; - -/** - * Function: createTasks - * - * Updates the contents of the given DOM node to - * display the tasks associated with the current - * editor state. This is invoked whenever there - * is a possible change of state in the editor. - * Default implementation is empty. - */ -mxEditor.prototype.createTasks = function (div) -{ - // override -}; - -/** - * Function: showHelp - * - * Shows the help window. If the help window does not exist - * then it is created using an iframe pointing to the resource - * for the <code>urlHelp</code> key or <urlHelp> if the resource - * is undefined. - */ -mxEditor.prototype.showHelp = function (tasks) -{ - if (this.help == null) - { - var frame = document.createElement('iframe'); - frame.setAttribute('src', mxResources.get('urlHelp') || this.urlHelp); - frame.setAttribute('height', '100%'); - frame.setAttribute('width', '100%'); - frame.setAttribute('frameBorder', '0'); - frame.style.backgroundColor = 'white'; - - var w = document.body.clientWidth; - var h = (document.body.clientHeight || document.documentElement.clientHeight); - - var wnd = new mxWindow(mxResources.get(this.helpResource) || this.helpResource, - frame, (w-this.helpWidth)/2, (h-this.helpHeight)/3, this.helpWidth, this.helpHeight); - wnd.setMaximizable(true); - wnd.setClosable(true); - wnd.destroyOnClose = false; - wnd.setResizable(true); - - // Assigns the icon to the help window - if (this.helpWindowImage != null) - { - wnd.setImage(this.helpWindowImage); - } - - // Workaround for ignored iframe height 100% in FF - if (mxClient.IS_NS) - { - var handler = function(sender) - { - var h = wnd.div.offsetHeight; - frame.setAttribute('height', (h-26)+'px'); - }; - - wnd.addListener(mxEvent.RESIZE_END, handler); - wnd.addListener(mxEvent.MAXIMIZE, handler); - wnd.addListener(mxEvent.NORMALIZE, handler); - wnd.addListener(mxEvent.SHOW, handler); - } - - this.help = wnd; - } - - this.help.setVisible(true); -}; - -/** - * Function: showOutline - * - * Shows the outline window. If the window does not exist, then it is - * created using an <mxOutline>. - */ -mxEditor.prototype.showOutline = function () -{ - var create = this.outline == null; - - if (create) - { - var div = document.createElement('div'); - div.style.overflow = 'hidden'; - div.style.width = '100%'; - div.style.height = '100%'; - div.style.background = 'white'; - div.style.cursor = 'move'; - - var wnd = new mxWindow( - mxResources.get(this.outlineResource) || - this.outlineResource, - div, 600, 480, 200, 200, false); - - // Creates the outline in the specified div - // and links it to the existing graph - var outline = new mxOutline(this.graph, div); - wnd.setClosable(true); - wnd.setResizable(true); - wnd.destroyOnClose = false; - - wnd.addListener(mxEvent.RESIZE_END, function() - { - outline.update(); - }); - - this.outline = wnd; - this.outline.outline = outline; - } - - // Finally shows the outline - this.outline.setVisible(true); - this.outline.outline.update(true); -}; - -/** - * Function: setMode - * - * Puts the graph into the specified mode. The following modenames are - * supported: - * - * select - Selects using the left mouse button, new connections - * are disabled. - * connect - Selects using the left mouse button or creates new - * connections if mouse over cell hotspot. See <mxConnectionHandler>. - * pan - Pans using the left mouse button, new connections are disabled. - */ -mxEditor.prototype.setMode = function(modename) -{ - if (modename == 'select') - { - this.graph.panningHandler.useLeftButtonForPanning = false; - this.graph.setConnectable(false); - } - else if (modename == 'connect') - { - this.graph.panningHandler.useLeftButtonForPanning = false; - this.graph.setConnectable(true); - } - else if (modename == 'pan') - { - this.graph.panningHandler.useLeftButtonForPanning = true; - this.graph.setConnectable(false); - } -}; - -/** - * Function: createPopupMenu - * - * Uses <popupHandler> to create the menu in the graph's - * panning handler. The redirection is setup in - * <setToolbarContainer>. - */ -mxEditor.prototype.createPopupMenu = function (menu, cell, evt) -{ - this.popupHandler.createMenu(this, menu, cell, evt); -}; - -/** - * Function: createEdge - * - * Uses <defaultEdge> as the prototype for creating new edges - * in the connection handler of the graph. The style of the - * edge will be overridden with the value returned by - * <getEdgeStyle>. - */ -mxEditor.prototype.createEdge = function (source, target) -{ - // Clones the defaultedge prototype - var e = null; - - if (this.defaultEdge != null) - { - var model = this.graph.getModel(); - e = model.cloneCell(this.defaultEdge); - } - else - { - e = new mxCell(''); - e.setEdge(true); - - var geo = new mxGeometry(); - geo.relative = true; - e.setGeometry(geo); - } - - // Overrides the edge style - var style = this.getEdgeStyle(); - - if (style != null) - { - e.setStyle(style); - } - - return e; -}; - -/** - * Function: getEdgeStyle - * - * Returns a string identifying the style of new edges. - * The function is used in <createEdge> when new edges - * are created in the graph. - */ -mxEditor.prototype.getEdgeStyle = function () -{ - return this.defaultEdgeStyle; -}; - -/** - * Function: consumeCycleAttribute - * - * Returns the next attribute in <cycleAttributeValues> - * or null, if not attribute should be used in the - * specified cell. - */ -mxEditor.prototype.consumeCycleAttribute = function (cell) -{ - return (this.cycleAttributeValues != null && - this.cycleAttributeValues.length > 0 && - this.graph.isSwimlane(cell)) ? - this.cycleAttributeValues[this.cycleAttributeIndex++ % - this.cycleAttributeValues.length] : null; -}; - -/** - * Function: cycleAttribute - * - * Uses the returned value from <consumeCycleAttribute> - * as the value for the <cycleAttributeName> key in - * the given cell's style. - */ -mxEditor.prototype.cycleAttribute = function (cell) -{ - if (this.cycleAttributeName != null) - { - var value = this.consumeCycleAttribute(cell); - - if (value != null) - { - cell.setStyle(cell.getStyle()+';'+ - this.cycleAttributeName+'='+value); - } - } -}; - -/** - * Function: addVertex - * - * Adds the given vertex as a child of parent at the specified - * x and y coordinate and fires an <addVertex> event. - */ -mxEditor.prototype.addVertex = function (parent, vertex, x, y) -{ - var model = this.graph.getModel(); - - while (parent != null && !this.graph.isValidDropTarget(parent)) - { - parent = model.getParent(parent); - } - - parent = (parent != null) ? parent : this.graph.getSwimlaneAt(x, y); - var scale = this.graph.getView().scale; - - var geo = model.getGeometry(vertex); - var pgeo = model.getGeometry(parent); - - if (this.graph.isSwimlane(vertex) && - !this.graph.swimlaneNesting) - { - parent = null; - } - else if (parent == null && this.swimlaneRequired) - { - return null; - } - else if (parent != null && pgeo != null) - { - // Keeps vertex inside parent - var state = this.graph.getView().getState(parent); - - if (state != null) - { - x -= state.origin.x * scale; - y -= state.origin.y * scale; - - if (this.graph.isConstrainedMoving) - { - var width = geo.width; - var height = geo.height; - var tmp = state.x+state.width; - - if (x+width > tmp) - { - x -= x+width - tmp; - } - - tmp = state.y+state.height; - - if (y+height > tmp) - { - y -= y+height - tmp; - } - } - } - else if (pgeo != null) - { - x -= pgeo.x*scale; - y -= pgeo.y*scale; - } - } - - geo = geo.clone(); - geo.x = this.graph.snap(x / scale - - this.graph.getView().translate.x - - this.graph.gridSize/2); - geo.y = this.graph.snap(y / scale - - this.graph.getView().translate.y - - this.graph.gridSize/2); - vertex.setGeometry(geo); - - if (parent == null) - { - parent = this.graph.getDefaultParent(); - } - - this.cycleAttribute(vertex); - this.fireEvent(new mxEventObject(mxEvent.BEFORE_ADD_VERTEX, - 'vertex', vertex, 'parent', parent)); - - model.beginUpdate(); - try - { - vertex = this.graph.addCell(vertex, parent); - - if (vertex != null) - { - this.graph.constrainChild(vertex); - - this.fireEvent(new mxEventObject(mxEvent.ADD_VERTEX, 'vertex', vertex)); - } - } - finally - { - model.endUpdate(); - } - - if (vertex != null) - { - this.graph.setSelectionCell(vertex); - this.graph.scrollCellToVisible(vertex); - this.fireEvent(new mxEventObject(mxEvent.AFTER_ADD_VERTEX, 'vertex', vertex)); - } - - return vertex; -}; - -/** - * Function: destroy - * - * Removes the editor and all its associated resources. This does not - * normally need to be called, it is called automatically when the window - * unloads. - */ -mxEditor.prototype.destroy = function () -{ - if (!this.destroyed) - { - this.destroyed = true; - - if (this.tasks != null) - { - this.tasks.destroy(); - } - - if (this.outline != null) - { - this.outline.destroy(); - } - - if (this.properties != null) - { - this.properties.destroy(); - } - - if (this.keyHandler != null) - { - this.keyHandler.destroy(); - } - - if (this.rubberband != null) - { - this.rubberband.destroy(); - } - - if (this.toolbar != null) - { - this.toolbar.destroy(); - } - - if (this.graph != null) - { - this.graph.destroy(); - } - - this.status = null; - this.templates = null; - } -}; diff --git a/src/js/handler/mxCellHighlight.js b/src/js/handler/mxCellHighlight.js deleted file mode 100644 index f967f00..0000000 --- a/src/js/handler/mxCellHighlight.js +++ /dev/null @@ -1,271 +0,0 @@ -/** - * $Id: mxCellHighlight.js,v 1.25 2012-09-27 14:43:40 boris Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -/** - * Class: mxCellHighlight - * - * A helper class to highlight cells. Here is an example for a given cell. - * - * (code) - * var highlight = new mxCellHighlight(graph, '#ff0000', 2); - * highlight.highlight(graph.view.getState(cell))); - * (end) - * - * Constructor: mxCellHighlight - * - * Constructs a cell highlight. - */ -function mxCellHighlight(graph, highlightColor, strokeWidth) -{ - if (graph != null) - { - this.graph = graph; - this.highlightColor = (highlightColor != null) ? highlightColor : mxConstants.DEFAULT_VALID_COLOR; - this.strokeWidth = (strokeWidth != null) ? strokeWidth : mxConstants.HIGHLIGHT_STROKEWIDTH; - - // Updates the marker if the graph changes - this.repaintHandler = mxUtils.bind(this, function() - { - this.repaint(); - }); - - this.graph.getView().addListener(mxEvent.SCALE, this.repaintHandler); - this.graph.getView().addListener(mxEvent.TRANSLATE, this.repaintHandler); - this.graph.getView().addListener(mxEvent.SCALE_AND_TRANSLATE, this.repaintHandler); - this.graph.getModel().addListener(mxEvent.CHANGE, this.repaintHandler); - - // Hides the marker if the current root changes - this.resetHandler = mxUtils.bind(this, function() - { - this.hide(); - }); - - this.graph.getView().addListener(mxEvent.DOWN, this.resetHandler); - this.graph.getView().addListener(mxEvent.UP, this.resetHandler); - } -}; - -/** - * Variable: keepOnTop - * - * Specifies if the highlights should appear on top of everything - * else in the overlay pane. Default is false. - */ -mxCellHighlight.prototype.keepOnTop = false; - -/** - * Variable: graph - * - * Reference to the enclosing <mxGraph>. - */ -mxCellHighlight.prototype.graph = true; - -/** - * Variable: state - * - * Reference to the <mxCellState>. - */ -mxCellHighlight.prototype.state = null; - -/** - * Variable: spacing - * - * Specifies the spacing between the highlight for vertices and the vertex. - * Default is 2. - */ -mxCellHighlight.prototype.spacing = 2; - -/** - * Variable: resetHandler - * - * Holds the handler that automatically invokes reset if the highlight - * should be hidden. - */ -mxCellHighlight.prototype.resetHandler = null; - -/** - * Function: setHighlightColor - * - * Sets the color of the rectangle used to highlight drop targets. - * - * Parameters: - * - * color - String that represents the new highlight color. - */ -mxCellHighlight.prototype.setHighlightColor = function(color) -{ - this.highlightColor = color; - - if (this.shape != null) - { - if (this.shape.dialect == mxConstants.DIALECT_SVG) - { - this.shape.innerNode.setAttribute('stroke', color); - } - else if (this.shape.dialect == mxConstants.DIALECT_VML) - { - this.shape.node.strokecolor = color; - } - } -}; - -/** - * Function: drawHighlight - * - * Creates and returns the highlight shape for the given state. - */ -mxCellHighlight.prototype.drawHighlight = function() -{ - this.shape = this.createShape(); - this.repaint(); - - if (!this.keepOnTop && this.shape.node.parentNode.firstChild != this.shape.node) - { - this.shape.node.parentNode.insertBefore(this.shape.node, this.shape.node.parentNode.firstChild); - } - - // Workaround to force a repaint in AppleWebKit - if (this.graph.model.isEdge(this.state.cell)) - { - mxUtils.repaintGraph(this.graph, this.shape.points[0]); - } -}; - -/** - * Function: createShape - * - * Creates and returns the highlight shape for the given state. - */ -mxCellHighlight.prototype.createShape = function() -{ - var shape = null; - - if (this.graph.model.isEdge(this.state.cell)) - { - shape = new mxPolyline(this.state.absolutePoints, - this.highlightColor, this.strokeWidth); - } - else - { - shape = new mxRectangleShape( new mxRectangle(), - null, this.highlightColor, this.strokeWidth); - } - - shape.dialect = (this.graph.dialect != mxConstants.DIALECT_SVG) ? - mxConstants.DIALECT_VML : mxConstants.DIALECT_SVG; - shape.init(this.graph.getView().getOverlayPane()); - mxEvent.redirectMouseEvents(shape.node, this.graph, this.state); - - return shape; -}; - - -/** - * Function: repaint - * - * Updates the highlight after a change of the model or view. - */ -mxCellHighlight.prototype.repaint = function() -{ - if (this.state != null && this.shape != null) - { - if (this.graph.model.isEdge(this.state.cell)) - { - this.shape.points = this.state.absolutePoints; - } - else - { - this.shape.bounds = new mxRectangle(this.state.x - this.spacing, this.state.y - this.spacing, - this.state.width + 2 * this.spacing, this.state.height + 2 * this.spacing); - } - - // Uses cursor from shape in highlight - if (this.state.shape != null) - { - this.shape.setCursor(this.state.shape.getCursor()); - } - - var alpha = (!this.graph.model.isEdge(this.state.cell)) ? Number(this.state.style[mxConstants.STYLE_ROTATION] || '0') : 0; - - // Event-transparency - if (this.shape.dialect == mxConstants.DIALECT_SVG) - { - this.shape.node.setAttribute('style', 'pointer-events:none;'); - - if (alpha != 0) - { - var cx = this.state.getCenterX(); - var cy = this.state.getCenterY(); - var transform = 'rotate(' + alpha + ' ' + cx + ' ' + cy + ')'; - - this.shape.node.setAttribute('transform', transform); - } - } - else - { - this.shape.node.style.background = ''; - - if (alpha != 0) - { - this.shape.node.rotation = alpha; - } - } - - this.shape.redraw(); - } -}; - -/** - * Function: hide - * - * Resets the state of the cell marker. - */ -mxCellHighlight.prototype.hide = function() -{ - this.highlight(null); -}; - -/** - * Function: mark - * - * Marks the <markedState> and fires a <mark> event. - */ -mxCellHighlight.prototype.highlight = function(state) -{ - if (this.state != state) - { - if (this.shape != null) - { - this.shape.destroy(); - this.shape = null; - } - - this.state = state; - - if (this.state != null) - { - this.drawHighlight(); - } - } -}; - -/** - * Function: destroy - * - * Destroys the handler and all its resources and DOM nodes. - */ -mxCellHighlight.prototype.destroy = function() -{ - this.graph.getView().removeListener(this.repaintHandler); - this.graph.getModel().removeListener(this.repaintHandler); - - this.graph.getView().removeListener(this.resetHandler); - this.graph.getModel().removeListener(this.resetHandler); - - if (this.shape != null) - { - this.shape.destroy(); - this.shape = null; - } -}; diff --git a/src/js/handler/mxCellMarker.js b/src/js/handler/mxCellMarker.js deleted file mode 100644 index b336278..0000000 --- a/src/js/handler/mxCellMarker.js +++ /dev/null @@ -1,419 +0,0 @@ -/** - * $Id: mxCellMarker.js,v 1.30 2011-07-15 12:57:50 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -/** - * Class: mxCellMarker - * - * A helper class to process mouse locations and highlight cells. - * - * Helper class to highlight cells. To add a cell marker to an existing graph - * for highlighting all cells, the following code is used: - * - * (code) - * var marker = new mxCellMarker(graph); - * graph.addMouseListener({ - * mouseDown: function() {}, - * mouseMove: function(sender, me) - * { - * marker.process(me); - * }, - * mouseUp: function() {} - * }); - * (end) - * - * Event: mxEvent.MARK - * - * Fires after a cell has been marked or unmarked. The <code>state</code> - * property contains the marked <mxCellState> or null if no state is marked. - * - * Constructor: mxCellMarker - * - * Constructs a new cell marker. - * - * Parameters: - * - * graph - Reference to the enclosing <mxGraph>. - * validColor - Optional marker color for valid states. Default is - * <mxConstants.DEFAULT_VALID_COLOR>. - * invalidColor - Optional marker color for invalid states. Default is - * <mxConstants.DEFAULT_INVALID_COLOR>. - * hotspot - Portion of the width and hight where a state intersects a - * given coordinate pair. A value of 0 means always highlight. Default is - * <mxConstants.DEFAULT_HOTSPOT>. - */ -function mxCellMarker(graph, validColor, invalidColor, hotspot) -{ - if (graph != null) - { - this.graph = graph; - this.validColor = (validColor != null) ? validColor : mxConstants.DEFAULT_VALID_COLOR; - this.invalidColor = (validColor != null) ? invalidColor : mxConstants.DEFAULT_INVALID_COLOR; - this.hotspot = (hotspot != null) ? hotspot : mxConstants.DEFAULT_HOTSPOT; - - this.highlight = new mxCellHighlight(graph); - } -}; - -/** - * Extends mxEventSource. - */ -mxCellMarker.prototype = new mxEventSource(); -mxCellMarker.prototype.constructor = mxCellMarker; - -/** - * Variable: graph - * - * Reference to the enclosing <mxGraph>. - */ -mxCellMarker.prototype.graph = null; - -/** - * Variable: enabled - * - * Specifies if the marker is enabled. Default is true. - */ -mxCellMarker.prototype.enabled = true; - -/** - * Variable: hotspot - * - * Specifies the portion of the width and height that should trigger - * a highlight. The area around the center of the cell to be marked is used - * as the hotspot. Possible values are between 0 and 1. Default is - * mxConstants.DEFAULT_HOTSPOT. - */ -mxCellMarker.prototype.hotspot = mxConstants.DEFAULT_HOTSPOT; - -/** - * Variable: hotspotEnabled - * - * Specifies if the hotspot is enabled. Default is false. - */ -mxCellMarker.prototype.hotspotEnabled = false; - -/** - * Variable: validColor - * - * Holds the valid marker color. - */ -mxCellMarker.prototype.validColor = null; - -/** - * Variable: invalidColor - * - * Holds the invalid marker color. - */ -mxCellMarker.prototype.invalidColor = null; - -/** - * Variable: currentColor - * - * Holds the current marker color. - */ -mxCellMarker.prototype.currentColor = null; - -/** - * Variable: validState - * - * Holds the marked <mxCellState> if it is valid. - */ -mxCellMarker.prototype.validState = null; - -/** - * Variable: markedState - * - * Holds the marked <mxCellState>. - */ -mxCellMarker.prototype.markedState = null; - -/** - * Function: setEnabled - * - * Enables or disables event handling. This implementation - * updates <enabled>. - * - * Parameters: - * - * enabled - Boolean that specifies the new enabled state. - */ -mxCellMarker.prototype.setEnabled = function(enabled) -{ - this.enabled = enabled; -}; - -/** - * Function: isEnabled - * - * Returns true if events are handled. This implementation - * returns <enabled>. - */ -mxCellMarker.prototype.isEnabled = function() -{ - return this.enabled; -}; - -/** - * Function: setHotspot - * - * Sets the <hotspot>. - */ -mxCellMarker.prototype.setHotspot = function(hotspot) -{ - this.hotspot = hotspot; -}; - -/** - * Function: getHotspot - * - * Returns the <hotspot>. - */ -mxCellMarker.prototype.getHotspot = function() -{ - return this.hotspot; -}; - -/** - * Function: setHotspotEnabled - * - * Specifies whether the hotspot should be used in <intersects>. - */ -mxCellMarker.prototype.setHotspotEnabled = function(enabled) -{ - this.hotspotEnabled = enabled; -}; - -/** - * Function: isHotspotEnabled - * - * Returns true if hotspot is used in <intersects>. - */ -mxCellMarker.prototype.isHotspotEnabled = function() -{ - return this.hotspotEnabled; -}; - -/** - * Function: hasValidState - * - * Returns true if <validState> is not null. - */ -mxCellMarker.prototype.hasValidState = function() -{ - return this.validState != null; -}; - -/** - * Function: getValidState - * - * Returns the <validState>. - */ -mxCellMarker.prototype.getValidState = function() -{ - return this.validState; -}; - -/** - * Function: getMarkedState - * - * Returns the <markedState>. - */ -mxCellMarker.prototype.getMarkedState = function() -{ - return this.markedState; -}; - -/** - * Function: reset - * - * Resets the state of the cell marker. - */ -mxCellMarker.prototype.reset = function() -{ - this.validState = null; - - if (this.markedState != null) - { - this.markedState = null; - this.unmark(); - } -}; - -/** - * Function: process - * - * Processes the given event and cell and marks the state returned by - * <getState> with the color returned by <getMarkerColor>. If the - * markerColor is not null, then the state is stored in <markedState>. If - * <isValidState> returns true, then the state is stored in <validState> - * regardless of the marker color. The state is returned regardless of the - * marker color and valid state. - */ -mxCellMarker.prototype.process = function(me) -{ - var state = null; - - if (this.isEnabled()) - { - state = this.getState(me); - var isValid = (state != null) ? this.isValidState(state) : false; - var color = this.getMarkerColor(me.getEvent(), state, isValid); - - if (isValid) - { - this.validState = state; - } - else - { - this.validState = null; - } - - if (state != this.markedState || color != this.currentColor) - { - this.currentColor = color; - - if (state != null && this.currentColor != null) - { - this.markedState = state; - this.mark(); - } - else if (this.markedState != null) - { - this.markedState = null; - this.unmark(); - } - } - } - - return state; -}; - -/** - * Function: markCell - * - * Marks the given cell using the given color, or <validColor> if no color is specified. - */ -mxCellMarker.prototype.markCell = function(cell, color) -{ - var state = this.graph.getView().getState(cell); - - if (state != null) - { - this.currentColor = (color != null) ? color : this.validColor; - this.markedState = state; - this.mark(); - } -}; - -/** - * Function: mark - * - * Marks the <markedState> and fires a <mark> event. - */ -mxCellMarker.prototype.mark = function() -{ - this.highlight.setHighlightColor(this.currentColor); - this.highlight.highlight(this.markedState); - this.fireEvent(new mxEventObject(mxEvent.MARK, 'state', this.markedState)); -}; - -/** - * Function: unmark - * - * Hides the marker and fires a <mark> event. - */ -mxCellMarker.prototype.unmark = function() -{ - this.mark(); -}; - -/** - * Function: isValidState - * - * Returns true if the given <mxCellState> is a valid state. If this - * returns true, then the state is stored in <validState>. The return value - * of this method is used as the argument for <getMarkerColor>. - */ -mxCellMarker.prototype.isValidState = function(state) -{ - return true; -}; - -/** - * Function: getMarkerColor - * - * Returns the valid- or invalidColor depending on the value of isValid. - * The given <mxCellState> is ignored by this implementation. - */ -mxCellMarker.prototype.getMarkerColor = function(evt, state, isValid) -{ - return (isValid) ? this.validColor : this.invalidColor; -}; - -/** - * Function: getState - * - * Uses <getCell>, <getStateToMark> and <intersects> to return the - * <mxCellState> for the given <mxMouseEvent>. - */ -mxCellMarker.prototype.getState = function(me) -{ - var view = this.graph.getView(); - cell = this.getCell(me); - var state = this.getStateToMark(view.getState(cell)); - - return (state != null && this.intersects(state, me)) ? state : null; -}; - -/** - * Function: getCell - * - * Returns the <mxCell> for the given event and cell. This returns the - * given cell. - */ -mxCellMarker.prototype.getCell = function(me) -{ - return me.getCell(); -}; - -/** - * Function: getStateToMark - * - * Returns the <mxCellState> to be marked for the given <mxCellState> under - * the mouse. This returns the given state. - */ -mxCellMarker.prototype.getStateToMark = function(state) -{ - return state; -}; - -/** - * Function: intersects - * - * Returns true if the given coordinate pair intersects the given state. - * This returns true if the <hotspot> is 0 or the coordinates are inside - * the hotspot for the given cell state. - */ -mxCellMarker.prototype.intersects = function(state, me) -{ - if (this.hotspotEnabled) - { - return mxUtils.intersectsHotspot(state, me.getGraphX(), me.getGraphY(), - this.hotspot, mxConstants.MIN_HOTSPOT_SIZE, - mxConstants.MAX_HOTSPOT_SIZE); - } - - return true; -}; - -/** - * Function: destroy - * - * Destroys the handler and all its resources and DOM nodes. - */ -mxCellMarker.prototype.destroy = function() -{ - this.graph.getView().removeListener(this.resetHandler); - this.graph.getModel().removeListener(this.resetHandler); - this.highlight.destroy(); -}; diff --git a/src/js/handler/mxCellTracker.js b/src/js/handler/mxCellTracker.js deleted file mode 100644 index 5adcd6a..0000000 --- a/src/js/handler/mxCellTracker.js +++ /dev/null @@ -1,149 +0,0 @@ -/** - * $Id: mxCellTracker.js,v 1.9 2011-08-28 09:49:46 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -/** - * Class: mxCellTracker - * - * Event handler that highlights cells. Inherits from <mxCellMarker>. - * - * Example: - * - * (code) - * new mxCellTracker(graph, '#00FF00'); - * (end) - * - * For detecting dragEnter, dragOver and dragLeave on cells, the following - * code can be used: - * - * (code) - * graph.addMouseListener( - * { - * cell: null, - * mouseDown: function(sender, me) { }, - * mouseMove: function(sender, me) - * { - * var tmp = me.getCell(); - * - * if (tmp != this.cell) - * { - * if (this.cell != null) - * { - * this.dragLeave(me.getEvent(), this.cell); - * } - * - * this.cell = tmp; - * - * if (this.cell != null) - * { - * this.dragEnter(me.getEvent(), this.cell); - * } - * } - * - * if (this.cell != null) - * { - * this.dragOver(me.getEvent(), this.cell); - * } - * }, - * mouseUp: function(sender, me) { }, - * dragEnter: function(evt, cell) - * { - * mxLog.debug('dragEnter', cell.value); - * }, - * dragOver: function(evt, cell) - * { - * mxLog.debug('dragOver', cell.value); - * }, - * dragLeave: function(evt, cell) - * { - * mxLog.debug('dragLeave', cell.value); - * } - * }); - * (end) - * - * Constructor: mxCellTracker - * - * Constructs an event handler that highlights cells. - * - * Parameters: - * - * graph - Reference to the enclosing <mxGraph>. - * color - Color of the highlight. Default is blue. - * funct - Optional JavaScript function that is used to override - * <mxCellMarker.getCell>. - */ -function mxCellTracker(graph, color, funct) -{ - mxCellMarker.call(this, graph, color); - - this.graph.addMouseListener(this); - - if (funct != null) - { - this.getCell = funct; - } - - // Automatic deallocation of memory - if (mxClient.IS_IE) - { - mxEvent.addListener(window, 'unload', mxUtils.bind(this, function() - { - this.destroy(); - })); - } -}; - -/** - * Extends mxCellMarker. - */ -mxCellTracker.prototype = new mxCellMarker(); -mxCellTracker.prototype.constructor = mxCellTracker; - -/** - * Function: mouseDown - * - * Ignores the event. The event is not consumed. - */ -mxCellTracker.prototype.mouseDown = function(sender, me) { }; - -/** - * Function: mouseMove - * - * Handles the event by highlighting the cell under the mousepointer if it - * is over the hotspot region of the cell. - */ -mxCellTracker.prototype.mouseMove = function(sender, me) -{ - if (this.isEnabled()) - { - this.process(me); - } -}; - -/** - * Function: mouseUp - * - * Handles the event by reseting the highlight. - */ -mxCellTracker.prototype.mouseUp = function(sender, me) -{ - this.reset(); -}; - -/** - * Function: destroy - * - * Destroys the object and all its resources and DOM nodes. This doesn't - * normally need to be called. It is called automatically when the window - * unloads. - */ -mxCellTracker.prototype.destroy = function() -{ - if (!this.destroyed) - { - this.destroyed = true; - - this.graph.removeMouseListener(this); - mxCellMarker.prototype.destroy.apply(this); - } -}; diff --git a/src/js/handler/mxConnectionHandler.js b/src/js/handler/mxConnectionHandler.js deleted file mode 100644 index 07daaf8..0000000 --- a/src/js/handler/mxConnectionHandler.js +++ /dev/null @@ -1,1969 +0,0 @@ -/** - * $Id: mxConnectionHandler.js,v 1.216 2012-12-07 15:17:37 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -/** - * Class: mxConnectionHandler - * - * Graph event handler that creates new connections. Uses <mxTerminalMarker> - * for finding and highlighting the source and target vertices and - * <factoryMethod> to create the edge instance. This handler is built-into - * <mxGraph.connectionHandler> and enabled using <mxGraph.setConnectable>. - * - * Example: - * - * (code) - * new mxConnectionHandler(graph, function(source, target, style) - * { - * edge = new mxCell('', new mxGeometry()); - * edge.setEdge(true); - * edge.setStyle(style); - * edge.geometry.relative = true; - * return edge; - * }); - * (end) - * - * Here is an alternative solution that just sets a specific user object for - * new edges by overriding <insertEdge>. - * - * (code) - * mxConnectionHandlerInsertEdge = mxConnectionHandler.prototype.insertEdge; - * mxConnectionHandler.prototype.insertEdge = function(parent, id, value, source, target, style) - * { - * value = 'Test'; - * - * return mxConnectionHandlerInsertEdge.apply(this, arguments); - * }; - * (end) - * - * Using images to trigger connections: - * - * This handler uses mxTerminalMarker to find the source and target cell for - * the new connection and creates a new edge using <connect>. The new edge is - * created using <createEdge> which in turn uses <factoryMethod> or creates a - * new default edge. - * - * The handler uses a "highlight-paradigm" for indicating if a cell is being - * used as a source or target terminal, as seen in MS Visio and other products. - * In order to allow both, moving and connecting cells at the same time, - * <mxConstants.DEFAULT_HOTSPOT> is used in the handler to determine the hotspot - * of a cell, that is, the region of the cell which is used to trigger a new - * connection. The constant is a value between 0 and 1 that specifies the - * amount of the width and height around the center to be used for the hotspot - * of a cell and its default value is 0.5. In addition, - * <mxConstants.MIN_HOTSPOT_SIZE> defines the minimum number of pixels for the - * width and height of the hotspot. - * - * This solution, while standards compliant, may be somewhat confusing because - * there is no visual indicator for the hotspot and the highlight is seen to - * switch on and off while the mouse is being moved in and out. Furthermore, - * this paradigm does not allow to create different connections depending on - * the highlighted hotspot as there is only one hotspot per cell and it - * normally does not allow cells to be moved and connected at the same time as - * there is no clear indication of the connectable area of the cell. - * - * To come across these issues, the handle has an additional <createIcons> hook - * with a default implementation that allows to create one icon to be used to - * trigger new connections. If this icon is specified, then new connections can - * only be created if the image is clicked while the cell is being highlighted. - * The <createIcons> hook may be overridden to create more than one - * <mxImageShape> for creating new connections, but the default implementation - * supports one image and is used as follows: - * - * In order to display the "connect image" whenever the mouse is over the cell, - * an DEFAULT_HOTSPOT of 1 should be used: - * - * (code) - * mxConstants.DEFAULT_HOTSPOT = 1; - * (end) - * - * In order to avoid confusion with the highlighting, the highlight color - * should not be used with a connect image: - * - * (code) - * mxConstants.HIGHLIGHT_COLOR = null; - * (end) - * - * To install the image, the connectImage field of the mxConnectionHandler must - * be assigned a new <mxImage> instance: - * - * (code) - * mxConnectionHandler.prototype.connectImage = new mxImage('images/green-dot.gif', 14, 14); - * (end) - * - * This will use the green-dot.gif with a width and height of 14 pixels as the - * image to trigger new connections. In createIcons the icon field of the - * handler will be set in order to remember the icon that has been clicked for - * creating the new connection. This field will be available under selectedIcon - * in the connect method, which may be overridden to take the icon that - * triggered the new connection into account. This is useful if more than one - * icon may be used to create a connection. - * - * Group: Events - * - * Event: mxEvent.START - * - * Fires when a new connection is being created by the user. The <code>state</code> - * property contains the state of the source cell. - * - * Event: mxEvent.CONNECT - * - * Fires between begin- and endUpdate in <connect>. The <code>cell</code> - * property contains the inserted edge, the <code>event</code> and <code>target</code> - * properties contain the respective arguments that were passed to <connect> (where - * target corresponds to the dropTarget argument). - * - * Note that the target is the cell under the mouse where the mouse button was released. - * Depending on the logic in the handler, this doesn't necessarily have to be the target - * of the inserted edge. To print the source, target or any optional ports IDs that the - * edge is connected to, the following code can be used. To get more details about the - * actual connection point, <mxGraph.getConnectionConstraint> can be used. To resolve - * the port IDs, use <mxGraphModel.getCell>. - * - * (code) - * graph.connectionHandler.addListener(mxEvent.CONNECT, function(sender, evt) - * { - * var edge = evt.getProperty('cell'); - * var source = graph.getModel().getTerminal(edge, true); - * var target = graph.getModel().getTerminal(edge, false); - * - * var style = graph.getCellStyle(edge); - * var sourcePortId = style[mxConstants.STYLE_SOURCE_PORT]; - * var targetPortId = style[mxConstants.STYLE_TARGET_PORT]; - * - * mxLog.show(); - * mxLog.debug('connect', edge, source.id, target.id, sourcePortId, targetPortId); - * }); - * (end) - * - * Event: mxEvent.RESET - * - * Fires when the <reset> method is invoked. - * - * Constructor: mxConnectionHandler - * - * Constructs an event handler that connects vertices using the specified - * factory method to create the new edges. Modify - * <mxConstants.ACTIVE_REGION> to setup the region on a cell which triggers - * the creation of a new connection or use connect icons as explained - * above. - * - * Parameters: - * - * graph - Reference to the enclosing <mxGraph>. - * factoryMethod - Optional function to create the edge. The function takes - * the source and target <mxCell> as the first and second argument and an - * optional cell style from the preview as the third argument. It returns - * the <mxCell> that represents the new edge. - */ -function mxConnectionHandler(graph, factoryMethod) -{ - if (graph != null) - { - this.graph = graph; - this.factoryMethod = factoryMethod; - this.init(); - } -}; - -/** - * Extends mxEventSource. - */ -mxConnectionHandler.prototype = new mxEventSource(); -mxConnectionHandler.prototype.constructor = mxConnectionHandler; - -/** - * Variable: graph - * - * Reference to the enclosing <mxGraph>. - */ -mxConnectionHandler.prototype.graph = null; - -/** - * Variable: factoryMethod - * - * Function that is used for creating new edges. The function takes the - * source and target <mxCell> as the first and second argument and returns - * a new <mxCell> that represents the edge. This is used in <createEdge>. - */ -mxConnectionHandler.prototype.factoryMethod = true; - -/** - * Variable: moveIconFront - * - * Specifies if icons should be displayed inside the graph container instead - * of the overlay pane. This is used for HTML labels on vertices which hide - * the connect icon. This has precendence over <moveIconBack> when set - * to true. Default is false. - */ -mxConnectionHandler.prototype.moveIconFront = false; - -/** - * Variable: moveIconBack - * - * Specifies if icons should be moved to the back of the overlay pane. This can - * be set to true if the icons of the connection handler conflict with other - * handles, such as the vertex label move handle. Default is false. - */ -mxConnectionHandler.prototype.moveIconBack = false; - -/** - * Variable: connectImage - * - * <mxImage> that is used to trigger the creation of a new connection. This - * is used in <createIcons>. Default is null. - */ -mxConnectionHandler.prototype.connectImage = null; - -/** - * Variable: targetConnectImage - * - * Specifies if the connect icon should be centered on the target state - * while connections are being previewed. Default is false. - */ -mxConnectionHandler.prototype.targetConnectImage = false; - -/** - * Variable: enabled - * - * Specifies if events are handled. Default is true. - */ -mxConnectionHandler.prototype.enabled = true; - -/** - * Variable: select - * - * Specifies if new edges should be selected. Default is true. - */ -mxConnectionHandler.prototype.select = true; - -/** - * Variable: createTarget - * - * Specifies if <createTargetVertex> should be called if no target was under the - * mouse for the new connection. Setting this to true means the connection - * will be drawn as valid if no target is under the mouse, and - * <createTargetVertex> will be called before the connection is created between - * the source cell and the newly created vertex in <createTargetVertex>, which - * can be overridden to create a new target. Default is false. - */ -mxConnectionHandler.prototype.createTarget = false; - -/** - * Variable: marker - * - * Holds the <mxTerminalMarker> used for finding source and target cells. - */ -mxConnectionHandler.prototype.marker = null; - -/** - * Variable: constraintHandler - * - * Holds the <mxConstraintHandler> used for drawing and highlighting - * constraints. - */ -mxConnectionHandler.prototype.constraintHandler = null; - -/** - * Variable: error - * - * Holds the current validation error while connections are being created. - */ -mxConnectionHandler.prototype.error = null; - -/** - * Variable: waypointsEnabled - * - * Specifies if single clicks should add waypoints on the new edge. Default is - * false. - */ -mxConnectionHandler.prototype.waypointsEnabled = false; - -/** - * Variable: tapAndHoldEnabled - * - * Specifies if tap and hold should be used for starting connections on touch-based - * devices. Default is true. - */ -mxConnectionHandler.prototype.tapAndHoldEnabled = true; - -/** - * Variable: tapAndHoldDelay - * - * Specifies the time for a tap and hold. Default is 500 ms. - */ -mxConnectionHandler.prototype.tapAndHoldDelay = 500; - -/** - * Variable: tapAndHoldInProgress - * - * True if the timer for tap and hold events is running. - */ -mxConnectionHandler.prototype.tapAndHoldInProgress = false; - -/** - * Variable: tapAndHoldValid - * - * True as long as the timer is running and the touch events - * stay within the given <tapAndHoldTolerance>. - */ -mxConnectionHandler.prototype.tapAndHoldValid = false; - -/** - * Variable: tapAndHoldTolerance - * - * Specifies the tolerance for a tap and hold. Default is 4 pixels. - */ -mxConnectionHandler.prototype.tapAndHoldTolerance = 4; - -/** - * Variable: initialTouchX - * - * Holds the x-coordinate of the intial touch event for tap and hold. - */ -mxConnectionHandler.prototype.initialTouchX = 0; - -/** - * Variable: initialTouchY - * - * Holds the y-coordinate of the intial touch event for tap and hold. - */ -mxConnectionHandler.prototype.initialTouchY = 0; - -/** - * Variable: ignoreMouseDown - * - * Specifies if the connection handler should ignore the state of the mouse - * button when highlighting the source. Default is false, that is, the - * handler only highlights the source if no button is being pressed. - */ -mxConnectionHandler.prototype.ignoreMouseDown = false; - -/** - * Variable: first - * - * Holds the <mxPoint> where the mouseDown took place while the handler is - * active. - */ -mxConnectionHandler.prototype.first = null; - -/** - * Variable: connectIconOffset - * - * Holds the offset for connect icons during connection preview. - * Default is mxPoint(0, <mxConstants.TOOLTIP_VERTICAL_OFFSET>). - * Note that placing the icon under the mouse pointer with an - * offset of (0,0) will affect hit detection. - */ -mxConnectionHandler.prototype.connectIconOffset = new mxPoint(0, mxConstants.TOOLTIP_VERTICAL_OFFSET); - -/** - * Variable: edgeState - * - * Optional <mxCellState> that represents the preview edge while the - * handler is active. This is created in <createEdgeState>. - */ -mxConnectionHandler.prototype.edgeState = null; - -/** - * Variable: changeHandler - * - * Holds the change event listener for later removal. - */ -mxConnectionHandler.prototype.changeHandler = null; - -/** - * Variable: drillHandler - * - * Holds the drill event listener for later removal. - */ -mxConnectionHandler.prototype.drillHandler = null; - -/** - * Variable: mouseDownCounter - * - * Counts the number of mouseDown events since the start. The initial mouse - * down event counts as 1. - */ -mxConnectionHandler.prototype.mouseDownCounter = 0; - -/** - * Variable: movePreviewAway - * - * Switch to enable moving the preview away from the mousepointer. This is required in browsers - * where the preview cannot be made transparent to events and if the built-in hit detection on - * the HTML elements in the page should be used. Default is the value of <mxClient.IS_VML>. - */ -mxConnectionHandler.prototype.movePreviewAway = mxClient.IS_VML; - -/** - * Function: isEnabled - * - * Returns true if events are handled. This implementation - * returns <enabled>. - */ -mxConnectionHandler.prototype.isEnabled = function() -{ - return this.enabled; -}; - -/** - * Function: setEnabled - * - * Enables or disables event handling. This implementation - * updates <enabled>. - * - * Parameters: - * - * enabled - Boolean that specifies the new enabled state. - */ -mxConnectionHandler.prototype.setEnabled = function(enabled) -{ - this.enabled = enabled; -}; - -/** - * Function: isCreateTarget - * - * Returns <createTarget>. - */ -mxConnectionHandler.prototype.isCreateTarget = function() -{ - return this.createTarget; -}; - -/** - * Function: setCreateTarget - * - * Sets <createTarget>. - */ -mxConnectionHandler.prototype.setCreateTarget = function(value) -{ - this.createTarget = value; -}; - -/** - * Function: createShape - * - * Creates the preview shape for new connections. - */ -mxConnectionHandler.prototype.createShape = function() -{ - // Creates the edge preview - var shape = new mxPolyline([], mxConstants.INVALID_COLOR); - shape.isDashed = true; - shape.dialect = (this.graph.dialect != mxConstants.DIALECT_SVG) ? - mxConstants.DIALECT_VML : mxConstants.DIALECT_SVG; - shape.init(this.graph.getView().getOverlayPane()); - - // Event-transparency - if (this.graph.dialect == mxConstants.DIALECT_SVG) - { - // Sets event transparency on the internal shapes that represent - // the actual dashed line on the screen - shape.pipe.setAttribute('style', 'pointer-events:none;'); - shape.innerNode.setAttribute('style', 'pointer-events:none;'); - } - else - { - // Workaround no event transparency for preview in IE - // FIXME: 3,3 pixel offset for custom hit detection in IE - var getState = mxUtils.bind(this, function(evt) - { - var pt = mxUtils.convertPoint(this.graph.container, mxEvent.getClientX(evt), mxEvent.getClientY(evt)); - - return this.graph.view.getState(this.graph.getCellAt(pt.x, pt.y)); - }); - - // Redirects events on the shape to the graph - mxEvent.redirectMouseEvents(shape.node, this.graph, getState); - } - - return shape; -}; - -/** - * Function: init - * - * Initializes the shapes required for this connection handler. This should - * be invoked if <mxGraph.container> is assigned after the connection - * handler has been created. - */ -mxConnectionHandler.prototype.init = function() -{ - this.graph.addMouseListener(this); - this.marker = this.createMarker(); - this.constraintHandler = new mxConstraintHandler(this.graph); - - // Redraws the icons if the graph changes - this.changeHandler = mxUtils.bind(this, function(sender) - { - if (this.iconState != null) - { - this.iconState = this.graph.getView().getState(this.iconState.cell); - } - - if (this.iconState != null) - { - this.redrawIcons(this.icons, this.iconState); - } - else - { - this.destroyIcons(this.icons); - this.previous = null; - } - - this.constraintHandler.reset(); - }); - - this.graph.getModel().addListener(mxEvent.CHANGE, this.changeHandler); - this.graph.getView().addListener(mxEvent.SCALE, this.changeHandler); - this.graph.getView().addListener(mxEvent.TRANSLATE, this.changeHandler); - this.graph.getView().addListener(mxEvent.SCALE_AND_TRANSLATE, this.changeHandler); - - // Removes the icon if we step into/up or start editing - this.drillHandler = mxUtils.bind(this, function(sender) - { - this.destroyIcons(this.icons); - }); - - this.graph.addListener(mxEvent.START_EDITING, this.drillHandler); - this.graph.getView().addListener(mxEvent.DOWN, this.drillHandler); - this.graph.getView().addListener(mxEvent.UP, this.drillHandler); -}; - -/** - * Function: isConnectableCell - * - * Returns true if the given cell is connectable. This is a hook to - * disable floating connections. This implementation returns true. - */ -mxConnectionHandler.prototype.isConnectableCell = function(cell) -{ - return true; -}; - -/** - * Function: createMarker - * - * Creates and returns the <mxCellMarker> used in <marker>. - */ -mxConnectionHandler.prototype.createMarker = function() -{ - var marker = new mxCellMarker(this.graph); - marker.hotspotEnabled = true; - - // Overrides to return cell at location only if valid (so that - // there is no highlight for invalid cells) - marker.getCell = mxUtils.bind(this, function(evt, cell) - { - var cell = mxCellMarker.prototype.getCell.apply(marker, arguments); - this.error = null; - - if (!this.isConnectableCell(cell)) - { - return null; - } - - if (cell != null) - { - if (this.isConnecting()) - { - if (this.previous != null) - { - this.error = this.validateConnection(this.previous.cell, cell); - - if (this.error != null && this.error.length == 0) - { - cell = null; - - // Enables create target inside groups - if (this.isCreateTarget()) - { - this.error = null; - } - } - } - } - else if (!this.isValidSource(cell)) - { - cell = null; - } - } - else if (this.isConnecting() && !this.isCreateTarget() && - !this.graph.allowDanglingEdges) - { - this.error = ''; - } - - return cell; - }); - - // Sets the highlight color according to validateConnection - marker.isValidState = mxUtils.bind(this, function(state) - { - if (this.isConnecting()) - { - return this.error == null; - } - else - { - return mxCellMarker.prototype.isValidState.apply(marker, arguments); - } - }); - - // Overrides to use marker color only in highlight mode or for - // target selection - marker.getMarkerColor = mxUtils.bind(this, function(evt, state, isValid) - { - return (this.connectImage == null || this.isConnecting()) ? - mxCellMarker.prototype.getMarkerColor.apply(marker, arguments) : - null; - }); - - // Overrides to use hotspot only for source selection otherwise - // intersects always returns true when over a cell - marker.intersects = mxUtils.bind(this, function(state, evt) - { - if (this.connectImage != null || this.isConnecting()) - { - return true; - } - - return mxCellMarker.prototype.intersects.apply(marker, arguments); - }); - - return marker; -}; - -/** - * Function: start - * - * Starts a new connection for the given state and coordinates. - */ -mxConnectionHandler.prototype.start = function(state, x, y, edgeState) -{ - this.previous = state; - this.first = new mxPoint(x, y); - this.edgeState = (edgeState != null) ? edgeState : this.createEdgeState(null); - - // Marks the source state - this.marker.currentColor = this.marker.validColor; - this.marker.markedState = state; - this.marker.mark(); - - this.fireEvent(new mxEventObject(mxEvent.START, 'state', this.previous)); -}; - -/** - * Function: isConnecting - * - * Returns true if the source terminal has been clicked and a new - * connection is currently being previewed. - */ -mxConnectionHandler.prototype.isConnecting = function() -{ - return this.first != null && this.shape != null; -}; - -/** - * Function: isValidSource - * - * Returns <mxGraph.isValidSource> for the given source terminal. - * - * Parameters: - * - * cell - <mxCell> that represents the source terminal. - */ -mxConnectionHandler.prototype.isValidSource = function(cell) -{ - return this.graph.isValidSource(cell); -}; - -/** - * Function: isValidTarget - * - * Returns true. The call to <mxGraph.isValidTarget> is implicit by calling - * <mxGraph.getEdgeValidationError> in <validateConnection>. This is an - * additional hook for disabling certain targets in this specific handler. - * - * Parameters: - * - * cell - <mxCell> that represents the target terminal. - */ -mxConnectionHandler.prototype.isValidTarget = function(cell) -{ - return true; -}; - -/** - * Function: validateConnection - * - * Returns the error message or an empty string if the connection for the - * given source target pair is not valid. Otherwise it returns null. This - * implementation uses <mxGraph.getEdgeValidationError>. - * - * Parameters: - * - * source - <mxCell> that represents the source terminal. - * target - <mxCell> that represents the target terminal. - */ -mxConnectionHandler.prototype.validateConnection = function(source, target) -{ - if (!this.isValidTarget(target)) - { - return ''; - } - - return this.graph.getEdgeValidationError(null, source, target); -}; - -/** - * Function: getConnectImage - * - * Hook to return the <mxImage> used for the connection icon of the given - * <mxCellState>. This implementation returns <connectImage>. - * - * Parameters: - * - * state - <mxCellState> whose connect image should be returned. - */ -mxConnectionHandler.prototype.getConnectImage = function(state) -{ - return this.connectImage; -}; - -/** - * Function: isMoveIconToFrontForState - * - * Returns true if the state has a HTML label in the graph's container, otherwise - * it returns <moveIconFront>. - * - * Parameters: - * - * state - <mxCellState> whose connect icons should be returned. - */ -mxConnectionHandler.prototype.isMoveIconToFrontForState = function(state) -{ - if (state.text != null && state.text.node.parentNode == this.graph.container) - { - return true; - } - - return this.moveIconFront; -}; - -/** - * Function: createIcons - * - * Creates the array <mxImageShapes> that represent the connect icons for - * the given <mxCellState>. - * - * Parameters: - * - * state - <mxCellState> whose connect icons should be returned. - */ -mxConnectionHandler.prototype.createIcons = function(state) -{ - var image = this.getConnectImage(state); - - if (image != null && state != null) - { - this.iconState = state; - var icons = []; - - // Cannot use HTML for the connect icons because the icon receives all - // mouse move events in IE, must use VML and SVG instead even if the - // connect-icon appears behind the selection border and the selection - // border consumes the events before the icon gets a chance - var bounds = new mxRectangle(0, 0, image.width, image.height); - var icon = new mxImageShape(bounds, image.src, null, null, 0); - icon.preserveImageAspect = false; - - if (this.isMoveIconToFrontForState(state)) - { - icon.dialect = mxConstants.DIALECT_STRICTHTML; - icon.init(this.graph.container); - } - else - { - icon.dialect = (this.graph.dialect == mxConstants.DIALECT_SVG) ? - mxConstants.DIALECT_SVG : - mxConstants.DIALECT_VML; - icon.init(this.graph.getView().getOverlayPane()); - - // Move the icon back in the overlay pane - if (this.moveIconBack && icon.node.previousSibling != null) - { - icon.node.parentNode.insertBefore(icon.node, icon.node.parentNode.firstChild); - } - } - - icon.node.style.cursor = mxConstants.CURSOR_CONNECT; - - // Events transparency - var getState = mxUtils.bind(this, function() - { - return (this.currentState != null) ? this.currentState : state; - }); - - // Updates the local icon before firing the mouse down event. - var mouseDown = mxUtils.bind(this, function(evt) - { - if (!mxEvent.isConsumed(evt)) - { - this.icon = icon; - this.graph.fireMouseEvent(mxEvent.MOUSE_DOWN, - new mxMouseEvent(evt, getState())); - } - }); - - mxEvent.redirectMouseEvents(icon.node, this.graph, getState, mouseDown); - - icons.push(icon); - this.redrawIcons(icons, this.iconState); - - return icons; - } - - return null; -}; - -/** - * Function: redrawIcons - * - * Redraws the given array of <mxImageShapes>. - * - * Parameters: - * - * icons - Optional array of <mxImageShapes> to be redrawn. - */ -mxConnectionHandler.prototype.redrawIcons = function(icons, state) -{ - if (icons != null && icons[0] != null && state != null) - { - var pos = this.getIconPosition(icons[0], state); - icons[0].bounds.x = pos.x; - icons[0].bounds.y = pos.y; - icons[0].redraw(); - } -}; - -/** - * Function: redrawIcons - * - * Redraws the given array of <mxImageShapes>. - * - * Parameters: - * - * icons - Optional array of <mxImageShapes> to be redrawn. - */ -mxConnectionHandler.prototype.getIconPosition = function(icon, state) -{ - var scale = this.graph.getView().scale; - var cx = state.getCenterX(); - var cy = state.getCenterY(); - - if (this.graph.isSwimlane(state.cell)) - { - var size = this.graph.getStartSize(state.cell); - - cx = (size.width != 0) ? state.x + size.width * scale / 2 : cx; - cy = (size.height != 0) ? state.y + size.height * scale / 2 : cy; - } - - return new mxPoint(cx - icon.bounds.width / 2, - cy - icon.bounds.height / 2); -}; - -/** - * Function: destroyIcons - * - * Destroys the given array of <mxImageShapes>. - * - * Parameters: - * - * icons - Optional array of <mxImageShapes> to be destroyed. - */ -mxConnectionHandler.prototype.destroyIcons = function(icons) -{ - if (icons != null) - { - this.iconState = null; - - for (var i = 0; i < icons.length; i++) - { - icons[i].destroy(); - } - } -}; - -/** - * Function: isStartEvent - * - * Returns true if the given mouse down event should start this handler. The - * This implementation returns true if the event does not force marquee - * selection, and the currentConstraint and currentFocus of the - * <constraintHandler> are not null, or <previous> and <error> are not null and - * <icons> is null or <icons> and <icon> are not null. - */ -mxConnectionHandler.prototype.isStartEvent = function(me) -{ - return !this.graph.isForceMarqueeEvent(me.getEvent()) && - ((this.constraintHandler.currentFocus != null && - this.constraintHandler.currentConstraint != null) || - (this.previous != null && this.error == null && - (this.icons == null || (this.icons != null && this.icon != null)))); -}; - -/** - * Function: mouseDown - * - * Handles the event by initiating a new connection. - */ -mxConnectionHandler.prototype.mouseDown = function(sender, me) -{ - this.mouseDownCounter++; - - if (this.isEnabled() && this.graph.isEnabled() && !me.isConsumed() && - !this.isConnecting() && this.isStartEvent(me)) - { - if (this.constraintHandler.currentConstraint != null && - this.constraintHandler.currentFocus != null && - this.constraintHandler.currentPoint != null) - { - this.sourceConstraint = this.constraintHandler.currentConstraint; - this.previous = this.constraintHandler.currentFocus; - this.first = this.constraintHandler.currentPoint.clone(); - } - else - { - // Stores the location of the initial mousedown - this.first = new mxPoint(me.getGraphX(), me.getGraphY()); - } - - this.edgeState = this.createEdgeState(me); - this.mouseDownCounter = 1; - - if (this.waypointsEnabled && this.shape == null) - { - this.waypoints = null; - this.shape = this.createShape(); - } - - // Stores the starting point in the geometry of the preview - if (this.previous == null && this.edgeState != null) - { - var pt = this.graph.getPointForEvent(me.getEvent()); - this.edgeState.cell.geometry.setTerminalPoint(pt, true); - } - - this.fireEvent(new mxEventObject(mxEvent.START, 'state', this.previous)); - - me.consume(); - } - // Handles connecting via tap and hold - else if (mxClient.IS_TOUCH && this.tapAndHoldEnabled && !this.tapAndHoldInProgress && - this.isEnabled() && this.graph.isEnabled() && !this.isConnecting()) - { - this.tapAndHoldInProgress = true; - this.initialTouchX = me.getX(); - this.initialTouchY = me.getY(); - var state = this.graph.view.getState(this.marker.getCell(me)); - - var handler = function() - { - if (this.tapAndHoldValid) - { - this.tapAndHold(me, state); - } - - this.tapAndHoldInProgress = false; - this.tapAndHoldValid = false; - }; - - if (this.tapAndHoldThread) - { - window.clearTimeout(this.tapAndHoldThread); - } - - this.tapAndHoldThread = window.setTimeout(mxUtils.bind(this, handler), this.tapAndHoldDelay); - this.tapAndHoldValid = true; - } - - this.selectedIcon = this.icon; - this.icon = null; -}; - -/** - * Function: tapAndHold - * - * Handles the <mxMouseEvent> by highlighting the <mxCellState>. - * - * Parameters: - * - * me - <mxMouseEvent> that represents the touch event. - * state - Optional <mxCellState> that is associated with the event. - */ -mxConnectionHandler.prototype.tapAndHold = function(me, state) -{ - if (state != null) - { - this.marker.currentColor = this.marker.validColor; - this.marker.markedState = state; - this.marker.mark(); - - this.first = new mxPoint(me.getGraphX(), me.getGraphY()); - this.edgeState = this.createEdgeState(me); - this.previous = state; - this.fireEvent(new mxEventObject(mxEvent.START, 'state', this.previous)); - } -}; - -/** - * Function: isImmediateConnectSource - * - * Returns true if a tap on the given source state should immediately start - * connecting. This implementation returns true if the state is not movable - * in the graph. - */ -mxConnectionHandler.prototype.isImmediateConnectSource = function(state) -{ - return !this.graph.isCellMovable(state.cell); -}; - -/** - * Function: createEdgeState - * - * Hook to return an <mxCellState> which may be used during the preview. - * This implementation returns null. - * - * Use the following code to create a preview for an existing edge style: - * - * [code] - * graph.connectionHandler.createEdgeState = function(me) - * { - * var edge = graph.createEdge(null, null, null, null, null, 'edgeStyle=elbowEdgeStyle'); - * - * return new mxCellState(this.graph.view, edge, this.graph.getCellStyle(edge)); - * }; - * [/code] - */ -mxConnectionHandler.prototype.createEdgeState = function(me) -{ - return null; -}; - -/** - * Function: updateCurrentState - * - * Updates the current state for a given mouse move event by using - * the <marker>. - */ -mxConnectionHandler.prototype.updateCurrentState = function(me) -{ - var state = this.marker.process(me); - this.constraintHandler.update(me, this.first == null); - this.currentState = state; -}; - -/** - * Function: convertWaypoint - * - * Converts the given point from screen coordinates to model coordinates. - */ -mxConnectionHandler.prototype.convertWaypoint = function(point) -{ - var scale = this.graph.getView().getScale(); - var tr = this.graph.getView().getTranslate(); - - point.x = point.x / scale - tr.x; - point.y = point.y / scale - tr.y; -}; - -/** - * Function: mouseMove - * - * Handles the event by updating the preview edge or by highlighting - * a possible source or target terminal. - */ -mxConnectionHandler.prototype.mouseMove = function(sender, me) -{ - if (this.tapAndHoldValid) - { - this.tapAndHoldValid = - Math.abs(this.initialTouchX - me.getX()) < this.tapAndHoldTolerance && - Math.abs(this.initialTouchY - me.getY()) < this.tapAndHoldTolerance; - } - - if (!me.isConsumed() && (this.ignoreMouseDown || this.first != null || !this.graph.isMouseDown)) - { - // Handles special case when handler is disabled during highlight - if (!this.isEnabled() && this.currentState != null) - { - this.destroyIcons(this.icons); - this.currentState = null; - } - - if (this.first != null || (this.isEnabled() && this.graph.isEnabled())) - { - this.updateCurrentState(me); - } - - if (this.first != null) - { - var view = this.graph.getView(); - var scale = view.scale; - var point = new mxPoint(this.graph.snap(me.getGraphX() / scale) * scale, - this.graph.snap(me.getGraphY() / scale) * scale); - var constraint = null; - var current = point; - - // Uses the current point from the constraint handler if available - if (this.constraintHandler.currentConstraint != null && - this.constraintHandler.currentFocus != null && - this.constraintHandler.currentPoint != null) - { - constraint = this.constraintHandler.currentConstraint; - current = this.constraintHandler.currentPoint.clone(); - } - - var pt2 = this.first; - - // Moves the connect icon with the mouse - if (this.selectedIcon != null) - { - var w = this.selectedIcon.bounds.width; - var h = this.selectedIcon.bounds.height; - - if (this.currentState != null && this.targetConnectImage) - { - var pos = this.getIconPosition(this.selectedIcon, this.currentState); - this.selectedIcon.bounds.x = pos.x; - this.selectedIcon.bounds.y = pos.y; - } - else - { - var bounds = new mxRectangle(me.getGraphX() + this.connectIconOffset.x, - me.getGraphY() + this.connectIconOffset.y, w, h); - this.selectedIcon.bounds = bounds; - } - - this.selectedIcon.redraw(); - } - - // Uses edge state to compute the terminal points - if (this.edgeState != null) - { - this.edgeState.absolutePoints = [null, (this.currentState != null) ? null : current]; - this.graph.view.updateFixedTerminalPoint(this.edgeState, this.previous, true, this.sourceConstraint); - - if (this.currentState != null) - { - if (constraint == null) - { - constraint = this.graph.getConnectionConstraint(this.edgeState, this.previous, false); - } - - this.edgeState.setAbsoluteTerminalPoint(null, false); - this.graph.view.updateFixedTerminalPoint(this.edgeState, this.currentState, false, constraint); - } - - // Scales and translates the waypoints to the model - var realPoints = null; - - if (this.waypoints != null) - { - realPoints = []; - - for (var i = 0; i < this.waypoints.length; i++) - { - var pt = this.waypoints[i].clone(); - this.convertWaypoint(pt); - realPoints[i] = pt; - } - } - - this.graph.view.updatePoints(this.edgeState, realPoints, this.previous, this.currentState); - this.graph.view.updateFloatingTerminalPoints(this.edgeState, this.previous, this.currentState); - current = this.edgeState.absolutePoints[this.edgeState.absolutePoints.length - 1]; - pt2 = this.edgeState.absolutePoints[0]; - } - else - { - if (this.currentState != null) - { - if (this.constraintHandler.currentConstraint == null) - { - var tmp = this.getTargetPerimeterPoint(this.currentState, me); - - if (tmp != null) - { - current = tmp; - } - } - } - - // Computes the source perimeter point - if (this.sourceConstraint == null && this.previous != null) - { - var next = (this.waypoints != null && this.waypoints.length > 0) ? - this.waypoints[0] : current; - var tmp = this.getSourcePerimeterPoint(this.previous, next, me); - - if (tmp != null) - { - pt2 = tmp; - } - } - } - - // Makes sure the cell under the mousepointer can be detected - // by moving the preview shape away from the mouse. This - // makes sure the preview shape does not prevent the detection - // of the cell under the mousepointer even for slow gestures. - if (this.currentState == null && this.movePreviewAway) - { - var tmp = pt2; - - if (this.edgeState != null && this.edgeState.absolutePoints.length > 2) - { - var tmp2 = this.edgeState.absolutePoints[this.edgeState.absolutePoints.length - 2]; - - if (tmp2 != null) - { - tmp = tmp2; - } - } - - var dx = current.x - tmp.x; - var dy = current.y - tmp.y; - - var len = Math.sqrt(dx * dx + dy * dy); - - if (len == 0) - { - return; - } - - current.x -= dx * 4 / len; - current.y -= dy * 4 / len; - } - - // Creates the preview shape (lazy) - if (this.shape == null) - { - var dx = Math.abs(point.x - this.first.x); - var dy = Math.abs(point.y - this.first.y); - - if (dx > this.graph.tolerance || dy > this.graph.tolerance) - { - this.shape = this.createShape(); - - // Revalidates current connection - this.updateCurrentState(me); - } - } - - // Updates the points in the preview edge - if (this.shape != null) - { - if (this.edgeState != null) - { - this.shape.points = this.edgeState.absolutePoints; - } - else - { - var pts = [pt2]; - - if (this.waypoints != null) - { - pts = pts.concat(this.waypoints); - } - - pts.push(current); - this.shape.points = pts; - } - - this.drawPreview(); - } - - mxEvent.consume(me.getEvent()); - me.consume(); - } - else if(!this.isEnabled() || !this.graph.isEnabled()) - { - this.constraintHandler.reset(); - } - else if (this.previous != this.currentState && this.edgeState == null) - { - this.destroyIcons(this.icons); - this.icons = null; - - // Sets the cursor on the current shape - if (this.currentState != null && this.error == null) - { - this.icons = this.createIcons(this.currentState); - - if (this.icons == null) - { - this.currentState.setCursor(mxConstants.CURSOR_CONNECT); - me.consume(); - } - } - - this.previous = this.currentState; - } - else if (this.previous == this.currentState && this.currentState != null && this.icons == null && - !this.graph.isMouseDown) - { - // Makes sure that no cursors are changed - me.consume(); - } - - if (this.constraintHandler.currentConstraint != null) - { - this.marker.reset(); - } - - if (!this.graph.isMouseDown && this.currentState != null && this.icons != null) - { - var hitsIcon = false; - var target = me.getSource(); - - for (var i = 0; i < this.icons.length && !hitsIcon; i++) - { - hitsIcon = target == this.icons[i].node || target.parentNode == this.icons[i].node; - } - - if (!hitsIcon) - { - this.updateIcons(this.currentState, this.icons, me); - } - } - } - else - { - this.constraintHandler.reset(); - } -}; - -/** - * Function: getTargetPerimeterPoint - * - * Returns the perimeter point for the given target state. - * - * Parameters: - * - * state - <mxCellState> that represents the target cell state. - * me - <mxMouseEvent> that represents the mouse move. - */ -mxConnectionHandler.prototype.getTargetPerimeterPoint = function(state, me) -{ - var result = null; - var view = state.view; - var targetPerimeter = view.getPerimeterFunction(state); - - if (targetPerimeter != null) - { - var next = (this.waypoints != null && this.waypoints.length > 0) ? - this.waypoints[this.waypoints.length - 1] : - new mxPoint(this.previous.getCenterX(), this.previous.getCenterY()); - var tmp = targetPerimeter(view.getPerimeterBounds(state), - this.edgeState, next, false); - - if (tmp != null) - { - result = tmp; - } - } - else - { - result = new mxPoint(state.getCenterX(), state.getCenterY()); - } - - return result; -}; - -/** - * Function: getSourcePerimeterPoint - * - * Hook to update the icon position(s) based on a mouseOver event. This is - * an empty implementation. - * - * Parameters: - * - * state - <mxCellState> that represents the target cell state. - * next - <mxPoint> that represents the next point along the previewed edge. - * me - <mxMouseEvent> that represents the mouse move. - */ -mxConnectionHandler.prototype.getSourcePerimeterPoint = function(state, next, me) -{ - var result = null; - var view = state.view; - var sourcePerimeter = view.getPerimeterFunction(state); - - if (sourcePerimeter != null) - { - var tmp = sourcePerimeter(view.getPerimeterBounds(state), state, next, false); - - if (tmp != null) - { - result = tmp; - } - } - else - { - result = new mxPoint(state.getCenterX(), state.getCenterY()); - } - - return result; -}; - - -/** - * Function: updateIcons - * - * Hook to update the icon position(s) based on a mouseOver event. This is - * an empty implementation. - * - * Parameters: - * - * state - <mxCellState> under the mouse. - * icons - Array of currently displayed icons. - * me - <mxMouseEvent> that contains the mouse event. - */ -mxConnectionHandler.prototype.updateIcons = function(state, icons, me) -{ - // empty -}; - -/** - * Function: isStopEvent - * - * Returns true if the given mouse up event should stop this handler. The - * connection will be created if <error> is null. Note that this is only - * called if <waypointsEnabled> is true. This implemtation returns true - * if there is a cell state in the given event. - */ -mxConnectionHandler.prototype.isStopEvent = function(me) -{ - return me.getState() != null; -}; - -/** - * Function: addWaypoint - * - * Adds the waypoint for the given event to <waypoints>. - */ -mxConnectionHandler.prototype.addWaypointForEvent = function(me) -{ - var point = mxUtils.convertPoint(this.graph.container, me.getX(), me.getY()); - var dx = Math.abs(point.x - this.first.x); - var dy = Math.abs(point.y - this.first.y); - var addPoint = this.waypoints != null || (this.mouseDownCounter > 1 && - (dx > this.graph.tolerance || dy > this.graph.tolerance)); - - if (addPoint) - { - if (this.waypoints == null) - { - this.waypoints = []; - } - - var scale = this.graph.view.scale; - var point = new mxPoint(this.graph.snap(me.getGraphX() / scale) * scale, - this.graph.snap(me.getGraphY() / scale) * scale); - this.waypoints.push(point); - } -}; - -/** - * Function: mouseUp - * - * Handles the event by inserting the new connection. - */ -mxConnectionHandler.prototype.mouseUp = function(sender, me) -{ - if (!me.isConsumed() && this.isConnecting()) - { - if (this.waypointsEnabled && !this.isStopEvent(me)) - { - this.addWaypointForEvent(me); - me.consume(); - - return; - } - - // Inserts the edge if no validation error exists - if (this.error == null) - { - var source = (this.previous != null) ? this.previous.cell : null; - var target = null; - - if (this.constraintHandler.currentConstraint != null && - this.constraintHandler.currentFocus != null) - { - target = this.constraintHandler.currentFocus.cell; - } - - if (target == null && this.marker.hasValidState()) - { - target = this.marker.validState.cell; - } - - this.connect(source, target, me.getEvent(), me.getCell()); - } - else - { - // Selects the source terminal for self-references - if (this.previous != null && this.marker.validState != null && - this.previous.cell == this.marker.validState.cell) - { - this.graph.selectCellForEvent(this.marker.source, evt); - } - - // Displays the error message if it is not an empty string, - // for empty error messages, the event is silently dropped - if (this.error.length > 0) - { - this.graph.validationAlert(this.error); - } - } - - // Redraws the connect icons and resets the handler state - this.destroyIcons(this.icons); - me.consume(); - } - - if (this.first != null) - { - this.reset(); - } - - this.tapAndHoldInProgress = false; - this.tapAndHoldValid = false; -}; - -/** - * Function: reset - * - * Resets the state of this handler. - */ -mxConnectionHandler.prototype.reset = function() -{ - if (this.shape != null) - { - this.shape.destroy(); - this.shape = null; - } - - this.destroyIcons(this.icons); - this.icons = null; - this.marker.reset(); - this.constraintHandler.reset(); - this.selectedIcon = null; - this.edgeState = null; - this.previous = null; - this.error = null; - this.sourceConstraint = null; - this.mouseDownCounter = 0; - this.first = null; - this.icon = null; - - this.fireEvent(new mxEventObject(mxEvent.RESET)); -}; - -/** - * Function: drawPreview - * - * Redraws the preview edge using the color and width returned by - * <getEdgeColor> and <getEdgeWidth>. - */ -mxConnectionHandler.prototype.drawPreview = function() -{ - var valid = this.error == null; - var color = this.getEdgeColor(valid); - - if (this.shape.dialect == mxConstants.DIALECT_SVG) - { - this.shape.innerNode.setAttribute('stroke', color); - } - else - { - this.shape.node.strokecolor = color; - } - - this.shape.strokewidth = this.getEdgeWidth(valid); - this.shape.redraw(); - - // Workaround to force a repaint in AppleWebKit - mxUtils.repaintGraph(this.graph, this.shape.points[1]); -}; - -/** - * Function: getEdgeColor - * - * Returns the color used to draw the preview edge. This returns green if - * there is no edge validation error and red otherwise. - * - * Parameters: - * - * valid - Boolean indicating if the color for a valid edge should be - * returned. - */ -mxConnectionHandler.prototype.getEdgeColor = function(valid) -{ - return (valid) ? mxConstants.VALID_COLOR : mxConstants.INVALID_COLOR; -}; - -/** - * Function: getEdgeWidth - * - * Returns the width used to draw the preview edge. This returns 3 if - * there is no edge validation error and 1 otherwise. - * - * Parameters: - * - * valid - Boolean indicating if the width for a valid edge should be - * returned. - */ -mxConnectionHandler.prototype.getEdgeWidth = function(valid) -{ - return (valid) ? 3 : 1; -}; - -/** - * Function: connect - * - * Connects the given source and target using a new edge. This - * implementation uses <createEdge> to create the edge. - * - * Parameters: - * - * source - <mxCell> that represents the source terminal. - * target - <mxCell> that represents the target terminal. - * evt - Mousedown event of the connect gesture. - * dropTarget - <mxCell> that represents the cell under the mouse when it was - * released. - */ -mxConnectionHandler.prototype.connect = function(source, target, evt, dropTarget) -{ - if (target != null || this.isCreateTarget() || this.graph.allowDanglingEdges) - { - // Uses the common parent of source and target or - // the default parent to insert the edge - var model = this.graph.getModel(); - var edge = null; - - model.beginUpdate(); - try - { - if (source != null && target == null && this.isCreateTarget()) - { - target = this.createTargetVertex(evt, source); - - if (target != null) - { - dropTarget = this.graph.getDropTarget([target], evt, dropTarget); - - // Disables edges as drop targets if the target cell was created - // FIXME: Should not shift if vertex was aligned (same in Java) - if (dropTarget == null || !this.graph.getModel().isEdge(dropTarget)) - { - var pstate = this.graph.getView().getState(dropTarget); - - if (pstate != null) - { - var tmp = model.getGeometry(target); - tmp.x -= pstate.origin.x; - tmp.y -= pstate.origin.y; - } - } - else - { - dropTarget = this.graph.getDefaultParent(); - } - - this.graph.addCell(target, dropTarget); - } - } - - var parent = this.graph.getDefaultParent(); - - if (source != null && target != null && - model.getParent(source) == model.getParent(target) && - model.getParent(model.getParent(source)) != model.getRoot()) - { - parent = model.getParent(source); - - if ((source.geometry != null && source.geometry.relative) && - (target.geometry != null && target.geometry.relative)) - { - parent = model.getParent(parent); - } - } - - // Uses the value of the preview edge state for inserting - // the new edge into the graph - var value = null; - var style = null; - - if (this.edgeState != null) - { - value = this.edgeState.cell.value; - style = this.edgeState.cell.style; - } - - edge = this.insertEdge(parent, null, value, source, target, style); - - if (edge != null) - { - // Updates the connection constraints - this.graph.setConnectionConstraint(edge, source, true, this.sourceConstraint); - this.graph.setConnectionConstraint(edge, target, false, this.constraintHandler.currentConstraint); - - // Uses geometry of the preview edge state - if (this.edgeState != null) - { - model.setGeometry(edge, this.edgeState.cell.geometry); - } - - // Makes sure the edge has a non-null, relative geometry - var geo = model.getGeometry(edge); - - if (geo == null) - { - geo = new mxGeometry(); - geo.relative = true; - - model.setGeometry(edge, geo); - } - - // Uses scaled waypoints in geometry - if (this.waypoints != null && this.waypoints.length > 0) - { - var s = this.graph.view.scale; - var tr = this.graph.view.translate; - geo.points = []; - - for (var i = 0; i < this.waypoints.length; i++) - { - var pt = this.waypoints[i]; - geo.points.push(new mxPoint(pt.x / s - tr.x, pt.y / s - tr.y)); - } - } - - if (target == null) - { - var pt = this.graph.getPointForEvent(evt, false); - pt.x -= this.graph.panDx / this.graph.view.scale; - pt.y -= this.graph.panDy / this.graph.view.scale; - geo.setTerminalPoint(pt, false); - } - - this.fireEvent(new mxEventObject(mxEvent.CONNECT, - 'cell', edge, 'event', evt, 'target', dropTarget)); - } - } - catch (e) - { - mxLog.show(); - mxLog.debug(e.message); - } - finally - { - model.endUpdate(); - } - - if (this.select) - { - this.selectCells(edge, target); - } - } -}; - -/** - * Function: selectCells - * - * Selects the given edge after adding a new connection. The target argument - * contains the target vertex if one has been inserted. - */ -mxConnectionHandler.prototype.selectCells = function(edge, target) -{ - this.graph.setSelectionCell(edge); -}; - -/** - * Function: insertEdge - * - * Creates, inserts and returns the new edge for the given parameters. This - * implementation does only use <createEdge> if <factoryMethod> is defined, - * otherwise <mxGraph.insertEdge> will be used. - */ -mxConnectionHandler.prototype.insertEdge = function(parent, id, value, source, target, style) -{ - if (this.factoryMethod == null) - { - return this.graph.insertEdge(parent, id, value, source, target, style); - } - else - { - var edge = this.createEdge(value, source, target, style); - edge = this.graph.addEdge(edge, parent, source, target); - - return edge; - } -}; - -/** - * Function: createTargetVertex - * - * Hook method for creating new vertices on the fly if no target was - * under the mouse. This is only called if <createTarget> is true and - * returns null. - * - * Parameters: - * - * evt - Mousedown event of the connect gesture. - * source - <mxCell> that represents the source terminal. - */ -mxConnectionHandler.prototype.createTargetVertex = function(evt, source) -{ - // Uses the first non-relative source - var geo = this.graph.getCellGeometry(source); - - while (geo != null && geo.relative) - { - source = this.graph.getModel().getParent(source); - geo = this.graph.getCellGeometry(source); - } - - var clone = this.graph.cloneCells([source])[0]; - var geo = this.graph.getModel().getGeometry(clone); - - if (geo != null) - { - var point = this.graph.getPointForEvent(evt); - geo.x = this.graph.snap(point.x - geo.width / 2) - this.graph.panDx / this.graph.view.scale; - geo.y = this.graph.snap(point.y - geo.height / 2) - this.graph.panDy / this.graph.view.scale; - - // Aligns with source if within certain tolerance - if (this.first != null) - { - var sourceState = this.graph.view.getState(source); - - if (sourceState != null) - { - var tol = this.getAlignmentTolerance(); - - if (Math.abs(this.graph.snap(this.first.x) - - this.graph.snap(point.x)) <= tol) - { - geo.x = sourceState.x; - } - else if (Math.abs(this.graph.snap(this.first.y) - - this.graph.snap(point.y)) <= tol) - { - geo.y = sourceState.y; - } - } - } - } - - return clone; -}; - -/** - * Function: getAlignmentTolerance - * - * Returns the tolerance for aligning new targets to sources. - */ -mxConnectionHandler.prototype.getAlignmentTolerance = function() -{ - return (this.graph.isGridEnabled()) ? - this.graph.gridSize : this.graph.tolerance; -}; - -/** - * Function: createEdge - * - * Creates and returns a new edge using <factoryMethod> if one exists. If - * no factory method is defined, then a new default edge is returned. The - * source and target arguments are informal, the actual connection is - * setup later by the caller of this function. - * - * Parameters: - * - * value - Value to be used for creating the edge. - * source - <mxCell> that represents the source terminal. - * target - <mxCell> that represents the target terminal. - * style - Optional style from the preview edge. - */ -mxConnectionHandler.prototype.createEdge = function(value, source, target, style) -{ - var edge = null; - - // Creates a new edge using the factoryMethod - if (this.factoryMethod != null) - { - edge = this.factoryMethod(source, target, style); - } - - if (edge == null) - { - edge = new mxCell(value || ''); - edge.setEdge(true); - edge.setStyle(style); - - var geo = new mxGeometry(); - geo.relative = true; - edge.setGeometry(geo); - } - - return edge; -}; - -/** - * Function: destroy - * - * Destroys the handler and all its resources and DOM nodes. This should be - * called on all instances. It is called automatically for the built-in - * instance created for each <mxGraph>. - */ -mxConnectionHandler.prototype.destroy = function() -{ - this.graph.removeMouseListener(this); - - if (this.shape != null) - { - this.shape.destroy(); - this.shape = null; - } - - if (this.marker != null) - { - this.marker.destroy(); - this.marker = null; - } - - if (this.constraintHandler != null) - { - this.constraintHandler.destroy(); - this.constraintHandler = null; - } - - if (this.changeHandler != null) - { - this.graph.getModel().removeListener(this.changeHandler); - this.graph.getView().removeListener(this.changeHandler); - this.changeHandler = null; - } - - if (this.drillHandler != null) - { - this.graph.removeListener(this.drillHandler); - this.graph.getView().removeListener(this.drillHandler); - this.drillHandler = null; - } -}; diff --git a/src/js/handler/mxConstraintHandler.js b/src/js/handler/mxConstraintHandler.js deleted file mode 100644 index 39b3ab6..0000000 --- a/src/js/handler/mxConstraintHandler.js +++ /dev/null @@ -1,308 +0,0 @@ -/** - * $Id: mxConstraintHandler.js,v 1.15 2012-11-01 16:13:41 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -/** - * Class: mxConstraintHandler - * - * Handles constraints on connection targets. This class is in charge of - * showing fixed points when the mouse is over a vertex and handles constraints - * to establish new connections. - * - * Constructor: mxConstraintHandler - * - * Constructs an new constraint handler. - * - * Parameters: - * - * graph - Reference to the enclosing <mxGraph>. - * factoryMethod - Optional function to create the edge. The function takes - * the source and target <mxCell> as the first and second argument and - * returns the <mxCell> that represents the new edge. - */ -function mxConstraintHandler(graph) -{ - this.graph = graph; -}; - -/** - * Variable: pointImage - * - * <mxImage> to be used as the image for fixed connection points. - */ -mxConstraintHandler.prototype.pointImage = new mxImage(mxClient.imageBasePath + '/point.gif', 5, 5); - -/** - * Variable: graph - * - * Reference to the enclosing <mxGraph>. - */ -mxConstraintHandler.prototype.graph = null; - -/** - * Variable: enabled - * - * Specifies if events are handled. Default is true. - */ -mxConstraintHandler.prototype.enabled = true; - -/** - * Variable: highlightColor - * - * Specifies the color for the highlight. Default is <mxConstants.DEFAULT_VALID_COLOR>. - */ -mxConstraintHandler.prototype.highlightColor = mxConstants.DEFAULT_VALID_COLOR; - -/** - * Function: isEnabled - * - * Returns true if events are handled. This implementation - * returns <enabled>. - */ -mxConstraintHandler.prototype.isEnabled = function() -{ - return this.enabled; -}; - -/** - * Function: setEnabled - * - * Enables or disables event handling. This implementation - * updates <enabled>. - * - * Parameters: - * - * enabled - Boolean that specifies the new enabled state. - */ -mxConstraintHandler.prototype.setEnabled = function(enabled) -{ - this.enabled = enabled; -}; - -/** - * Function: reset - * - * Resets the state of this handler. - */ -mxConstraintHandler.prototype.reset = function() -{ - if (this.focusIcons != null) - { - for (var i = 0; i < this.focusIcons.length; i++) - { - this.focusIcons[i].destroy(); - } - - this.focusIcons = null; - } - - if (this.focusHighlight != null) - { - this.focusHighlight.destroy(); - this.focusHighlight = null; - } - - this.currentConstraint = null; - this.currentFocusArea = null; - this.currentPoint = null; - this.currentFocus = null; - this.focusPoints = null; -}; - -/** - * Function: getTolerance - * - * Returns the tolerance to be used for intersecting connection points. - */ -mxConstraintHandler.prototype.getTolerance = function() -{ - return this.graph.getTolerance(); -}; - -/** - * Function: getImageForConstraint - * - * Returns the tolerance to be used for intersecting connection points. - */ -mxConstraintHandler.prototype.getImageForConstraint = function(state, constraint, point) -{ - return this.pointImage; -}; - -/** - * Function: isEventIgnored - * - * Returns true if the given <mxMouseEvent> should be ignored in <update>. This - * implementation always returns false. - */ -mxConstraintHandler.prototype.isEventIgnored = function(me, source) -{ - return false; -}; - -/** - * Function: update - * - * Updates the state of this handler based on the given <mxMouseEvent>. - * Source is a boolean indicating if the cell is a source or target. - */ -mxConstraintHandler.prototype.update = function(me, source) -{ - if (this.isEnabled() && !this.isEventIgnored(me)) - { - var tol = this.getTolerance(); - var mouse = new mxRectangle(me.getGraphX() - tol, me.getGraphY() - tol, 2 * tol, 2 * tol); - var connectable = (me.getCell() != null) ? this.graph.isCellConnectable(me.getCell()) : false; - - if ((this.currentFocusArea == null || (!mxUtils.intersects(this.currentFocusArea, mouse) || - (me.getState() != null && this.currentFocus != null && connectable)))) - { - this.currentFocusArea = null; - - if (me.getState() != this.currentFocus) - { - this.currentFocus = null; - this.constraints = (me.getState() != null && connectable) ? - this.graph.getAllConnectionConstraints(me.getState(), source) : null; - - // Only uses cells which have constraints - if (this.constraints != null) - { - this.currentFocus = me.getState(); - this.currentFocusArea = new mxRectangle(me.getState().x, me.getState().y, me.getState().width, me.getState().height); - - if (this.focusIcons != null) - { - for (var i = 0; i < this.focusIcons.length; i++) - { - this.focusIcons[i].destroy(); - } - - this.focusIcons = null; - this.focusPoints = null; - } - - this.focusIcons = []; - this.focusPoints = []; - - for (var i = 0; i < this.constraints.length; i++) - { - var cp = this.graph.getConnectionPoint(me.getState(), this.constraints[i]); - var img = this.getImageForConstraint(me.getState(), this.constraints[i], cp); - - var src = img.src; - var bounds = new mxRectangle(cp.x - img.width / 2, - cp.y - img.height / 2, img.width, img.height); - var icon = new mxImageShape(bounds, src); - icon.dialect = (this.graph.dialect == mxConstants.DIALECT_SVG) ? - mxConstants.DIALECT_SVG : - mxConstants.DIALECT_VML; - icon.init(this.graph.getView().getOverlayPane()); - - // Move the icon behind all other overlays - if (icon.node.previousSibling != null) - { - icon.node.parentNode.insertBefore(icon.node, icon.node.parentNode.firstChild); - } - - var getState = mxUtils.bind(this, function() - { - return (this.currentFocus != null) ? this.currentFocus : me.getState(); - }); - - icon.redraw(); - - mxEvent.redirectMouseEvents(icon.node, this.graph, getState); - this.currentFocusArea.add(icon.bounds); - this.focusIcons.push(icon); - this.focusPoints.push(cp); - } - - this.currentFocusArea.grow(tol); - } - else if (this.focusIcons != null) - { - if (this.focusHighlight != null) - { - this.focusHighlight.destroy(); - this.focusHighlight = null; - } - - for (var i = 0; i < this.focusIcons.length; i++) - { - this.focusIcons[i].destroy(); - } - - this.focusIcons = null; - this.focusPoints = null; - } - } - } - - this.currentConstraint = null; - this.currentPoint = null; - - if (this.focusIcons != null && this.constraints != null && - (me.getState() == null || this.currentFocus == me.getState())) - { - for (var i = 0; i < this.focusIcons.length; i++) - { - if (mxUtils.intersects(this.focusIcons[i].bounds, mouse)) - { - this.currentConstraint = this.constraints[i]; - this.currentPoint = this.focusPoints[i]; - - var tmp = this.focusIcons[i].bounds.clone(); - tmp.grow((mxClient.IS_IE) ? 3 : 2); - - if (mxClient.IS_IE) - { - tmp.width -= 1; - tmp.height -= 1; - } - - if (this.focusHighlight == null) - { - var hl = new mxRectangleShape(tmp, null, this.highlightColor, 3); - hl.dialect = (this.graph.dialect == mxConstants.DIALECT_SVG) ? - mxConstants.DIALECT_SVG : - mxConstants.DIALECT_VML; - hl.init(this.graph.getView().getOverlayPane()); - this.focusHighlight = hl; - - var getState = mxUtils.bind(this, function() - { - return (this.currentFocus != null) ? this.currentFocus : me.getState(); - }); - - mxEvent.redirectMouseEvents(hl.node, this.graph, getState/*, mouseDown*/); - } - else - { - this.focusHighlight.bounds = tmp; - this.focusHighlight.redraw(); - } - - break; - } - } - } - - if (this.currentConstraint == null && - this.focusHighlight != null) - { - this.focusHighlight.destroy(); - this.focusHighlight = null; - } - } -}; - -/** - * Function: destroy - * - * Destroy this handler. - */ -mxConstraintHandler.prototype.destroy = function() -{ - this.reset(); -};
\ No newline at end of file diff --git a/src/js/handler/mxEdgeHandler.js b/src/js/handler/mxEdgeHandler.js deleted file mode 100644 index 2028342..0000000 --- a/src/js/handler/mxEdgeHandler.js +++ /dev/null @@ -1,1529 +0,0 @@ -/** - * $Id: mxEdgeHandler.js,v 1.178 2012-09-12 09:16:23 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -/** - * Class: mxEdgeHandler - * - * Graph event handler that reconnects edges and modifies control points and - * the edge label location. Uses <mxTerminalMarker> for finding and - * highlighting new source and target vertices. This handler is automatically - * created in <mxGraph.createHandler> for each selected edge. - * - * To enable adding/removing control points, the following code can be used: - * - * (code) - * mxEdgeHandler.prototype.addEnabled = true; - * mxEdgeHandler.prototype.removeEnabled = true; - * (end) - * - * Note: This experimental feature is not recommended for production use. - * - * Constructor: mxEdgeHandler - * - * Constructs an edge handler for the specified <mxCellState>. - * - * Parameters: - * - * state - <mxCellState> of the cell to be handled. - */ -function mxEdgeHandler(state) -{ - if (state != null) - { - this.state = state; - this.init(); - } -}; - -/** - * Variable: graph - * - * Reference to the enclosing <mxGraph>. - */ -mxEdgeHandler.prototype.graph = null; - -/** - * Variable: state - * - * Reference to the <mxCellState> being modified. - */ -mxEdgeHandler.prototype.state = null; - -/** - * Variable: marker - * - * Holds the <mxTerminalMarker> which is used for highlighting terminals. - */ -mxEdgeHandler.prototype.marker = null; - -/** - * Variable: constraintHandler - * - * Holds the <mxConstraintHandler> used for drawing and highlighting - * constraints. - */ -mxEdgeHandler.prototype.constraintHandler = null; - -/** - * Variable: error - * - * Holds the current validation error while a connection is being changed. - */ -mxEdgeHandler.prototype.error = null; - -/** - * Variable: shape - * - * Holds the <mxShape> that represents the preview edge. - */ -mxEdgeHandler.prototype.shape = null; - -/** - * Variable: bends - * - * Holds the <mxShapes> that represent the points. - */ -mxEdgeHandler.prototype.bends = null; - -/** - * Variable: labelShape - * - * Holds the <mxShape> that represents the label position. - */ -mxEdgeHandler.prototype.labelShape = null; - -/** - * Variable: cloneEnabled - * - * Specifies if cloning by control-drag is enabled. Default is true. - */ -mxEdgeHandler.prototype.cloneEnabled = true; - -/** - * Variable: addEnabled - * - * Specifies if adding bends by shift-click is enabled. Default is false. - * Note: This experimental feature is not recommended for production use. - */ -mxEdgeHandler.prototype.addEnabled = false; - -/** - * Variable: removeEnabled - * - * Specifies if removing bends by shift-click is enabled. Default is false. - * Note: This experimental feature is not recommended for production use. - */ -mxEdgeHandler.prototype.removeEnabled = false; - -/** - * Variable: preferHtml - * - * Specifies if bends should be added to the graph container. This is updated - * in <init> based on whether the edge or one of its terminals has an HTML - * label in the container. - */ -mxEdgeHandler.prototype.preferHtml = false; - -/** - * Variable: allowHandleBoundsCheck - * - * Specifies if the bounds of handles should be used for hit-detection in IE - * Default is true. - */ -mxEdgeHandler.prototype.allowHandleBoundsCheck = true; - -/** - * Variable: snapToTerminals - * - * Specifies if waypoints should snap to the routing centers of terminals. - * Default is false. - */ -mxEdgeHandler.prototype.snapToTerminals = false; - -/** - * Variable: crisp - * - * Specifies if the edge handles should be rendered in crisp mode. Default is - * true. - */ -mxEdgeHandler.prototype.crisp = true; - -/** - * Variable: handleImage - * - * Optional <mxImage> to be used as handles. Default is null. - */ -mxEdgeHandler.prototype.handleImage = null; - -/** - * Variable: tolerance - * - * Optional tolerance for hit-detection in <getHandleForEvent>. Default is 0. - */ -mxEdgeHandler.prototype.tolerance = 0; - -/** - * Function: init - * - * Initializes the shapes required for this edge handler. - */ -mxEdgeHandler.prototype.init = function() -{ - this.graph = this.state.view.graph; - this.marker = this.createMarker(); - this.constraintHandler = new mxConstraintHandler(this.graph); - - // Clones the original points from the cell - // and makes sure at least one point exists - this.points = []; - - // Uses the absolute points of the state - // for the initial configuration and preview - this.abspoints = this.getSelectionPoints(this.state); - this.shape = this.createSelectionShape(this.abspoints); - this.shape.dialect = (this.graph.dialect != mxConstants.DIALECT_SVG) ? - mxConstants.DIALECT_VML : mxConstants.DIALECT_SVG; - this.shape.init(this.graph.getView().getOverlayPane()); - this.shape.node.style.cursor = mxConstants.CURSOR_MOVABLE_EDGE; - - // Event handling - var md = (mxClient.IS_TOUCH) ? 'touchstart' : 'mousedown'; - var mm = (mxClient.IS_TOUCH) ? 'touchmove' : 'mousemove'; - var mu = (mxClient.IS_TOUCH) ? 'touchend' : 'mouseup'; - - mxEvent.addListener(this.shape.node, 'dblclick', - mxUtils.bind(this, function(evt) - { - this.graph.dblClick(evt, this.state.cell); - }) - ); - mxEvent.addListener(this.shape.node, md, - mxUtils.bind(this, function(evt) - { - if (this.addEnabled && this.isAddPointEvent(evt)) - { - this.addPoint(this.state, evt); - } - else - { - this.graph.fireMouseEvent(mxEvent.MOUSE_DOWN, - new mxMouseEvent(evt, this.state)); - } - }) - ); - mxEvent.addListener(this.shape.node, mm, - mxUtils.bind(this, function(evt) - { - var cell = this.state.cell; - - // Finds the cell under the mouse if the edge is being connected - // in which case the edge is never highlighted as it cannot - // be its own source or target terminal (transparent preview) - if (this.index != null) - { - var pt = mxUtils.convertPoint(this.graph.container, - mxEvent.getClientX(evt), mxEvent.getClientY(evt)); - cell = this.graph.getCellAt(pt.x, pt.y); - - // Swimlane content area is transparent in this case - if (this.graph.isSwimlane(cell) && this.graph.hitsSwimlaneContent(cell, pt.x, pt.y)) - { - cell = null; - } - } - - this.graph.fireMouseEvent(mxEvent.MOUSE_MOVE, - new mxMouseEvent(evt, this.graph.getView().getState(cell))); - }) - ); - mxEvent.addListener(this.shape.node, mu, - mxUtils.bind(this, function(evt) - { - this.graph.fireMouseEvent(mxEvent.MOUSE_UP, - new mxMouseEvent(evt, this.state)); - }) - ); - - // Updates preferHtml - this.preferHtml = this.state.text != null && - this.state.text.node.parentNode == this.graph.container; - - if (!this.preferHtml) - { - // Checks source terminal - var sourceState = this.state.getVisibleTerminalState(true); - - if (sourceState != null) - { - this.preferHtml = sourceState.text != null && - sourceState.text.node.parentNode == this.graph.container; - } - - if (!this.preferHtml) - { - // Checks target terminal - var targetState = this.state.getVisibleTerminalState(false); - - if (targetState != null) - { - this.preferHtml = targetState.text != null && - targetState.text.node.parentNode == this.graph.container; - } - } - } - - // Creates bends for the non-routed absolute points - // or bends that don't correspond to points - if (this.graph.getSelectionCount() < mxGraphHandler.prototype.maxCells || - mxGraphHandler.prototype.maxCells <= 0) - { - this.bends = this.createBends(); - } - - // Adds a rectangular handle for the label position - this.label = new mxPoint(this.state.absoluteOffset.x, this.state.absoluteOffset.y); - this.labelShape = new mxRectangleShape(new mxRectangle(), - mxConstants.LABEL_HANDLE_FILLCOLOR, - mxConstants.HANDLE_STROKECOLOR); - this.initBend(this.labelShape); - this.labelShape.node.style.cursor = mxConstants.CURSOR_LABEL_HANDLE; - mxEvent.redirectMouseEvents(this.labelShape.node, this.graph, this.state); - - this.redraw(); -}; - -/** - * Function: isAddPointEvent - * - * Returns true if the given event is a trigger to add a new point. This - * implementation returns true if shift is pressed. - */ -mxEdgeHandler.prototype.isAddPointEvent = function(evt) -{ - return mxEvent.isShiftDown(evt); -}; - -/** - * Function: isRemovePointEvent - * - * Returns true if the given event is a trigger to remove a point. This - * implementation returns true if shift is pressed. - */ -mxEdgeHandler.prototype.isRemovePointEvent = function(evt) -{ - return mxEvent.isShiftDown(evt); -}; - -/** - * Function: getSelectionPoints - * - * Returns the list of points that defines the selection stroke. - */ -mxEdgeHandler.prototype.getSelectionPoints = function(state) -{ - return state.absolutePoints; -}; - -/** - * Function: createSelectionShape - * - * Creates the shape used to draw the selection border. - */ -mxEdgeHandler.prototype.createSelectionShape = function(points) -{ - var shape = new mxPolyline(points, this.getSelectionColor()); - shape.strokewidth = this.getSelectionStrokeWidth(); - shape.isDashed = this.isSelectionDashed(); - - return shape; -}; - -/** - * Function: getSelectionColor - * - * Returns <mxConstants.EDGE_SELECTION_COLOR>. - */ -mxEdgeHandler.prototype.getSelectionColor = function() -{ - return mxConstants.EDGE_SELECTION_COLOR; -}; - -/** - * Function: getSelectionStrokeWidth - * - * Returns <mxConstants.EDGE_SELECTION_STROKEWIDTH>. - */ -mxEdgeHandler.prototype.getSelectionStrokeWidth = function() -{ - return mxConstants.EDGE_SELECTION_STROKEWIDTH; -}; - -/** - * Function: isSelectionDashed - * - * Returns <mxConstants.EDGE_SELECTION_DASHED>. - */ -mxEdgeHandler.prototype.isSelectionDashed = function() -{ - return mxConstants.EDGE_SELECTION_DASHED; -}; - -/** - * Function: isConnectableCell - * - * Returns true if the given cell is connectable. This is a hook to - * disable floating connections. This implementation returns true. - */ -mxEdgeHandler.prototype.isConnectableCell = function(cell) -{ - return true; -}; - -/** - * Function: createMarker - * - * Creates and returns the <mxCellMarker> used in <marker>. - */ -mxEdgeHandler.prototype.createMarker = function() -{ - var marker = new mxCellMarker(this.graph); - var self = this; // closure - - // Only returns edges if they are connectable and never returns - // the edge that is currently being modified - marker.getCell = function(me) - { - var cell = mxCellMarker.prototype.getCell.apply(this, arguments); - - if (!self.isConnectableCell(cell)) - { - return null; - } - - var model = self.graph.getModel(); - - if (cell == self.state.cell || (cell != null && - !self.graph.connectableEdges && model.isEdge(cell))) - { - cell = null; - } - - return cell; - }; - - // Sets the highlight color according to validateConnection - marker.isValidState = function(state) - { - var model = self.graph.getModel(); - var other = self.graph.view.getTerminalPort(state, - self.graph.view.getState(model.getTerminal(self.state.cell, - !self.isSource)), !self.isSource); - var otherCell = (other != null) ? other.cell : null; - var source = (self.isSource) ? state.cell : otherCell; - var target = (self.isSource) ? otherCell : state.cell; - - // Updates the error message of the handler - self.error = self.validateConnection(source, target); - - return self.error == null; - }; - - return marker; -}; - -/** - * Function: validateConnection - * - * Returns the error message or an empty string if the connection for the - * given source, target pair is not valid. Otherwise it returns null. This - * implementation uses <mxGraph.getEdgeValidationError>. - * - * Parameters: - * - * source - <mxCell> that represents the source terminal. - * target - <mxCell> that represents the target terminal. - */ -mxEdgeHandler.prototype.validateConnection = function(source, target) -{ - return this.graph.getEdgeValidationError(this.state.cell, source, target); -}; - -/** - * Function: createBends - * - * Creates and returns the bends used for modifying the edge. This is - * typically an array of <mxRectangleShapes>. - */ - mxEdgeHandler.prototype.createBends = function() - { - var cell = this.state.cell; - var bends = []; - - for (var i = 0; i < this.abspoints.length; i++) - { - if (this.isHandleVisible(i)) - { - var source = i == 0; - var target = i == this.abspoints.length - 1; - var terminal = source || target; - - if (terminal || this.graph.isCellBendable(cell)) - { - var bend = this.createHandleShape(i); - this.initBend(bend); - - if (mxClient.IS_TOUCH) - { - bend.node.setAttribute('pointer-events', 'none'); - } - - if (this.isHandleEnabled(i)) - { - if (mxClient.IS_TOUCH) - { - var getState = mxUtils.bind(this, function(evt) - { - var pt = mxUtils.convertPoint(this.graph.container, mxEvent.getClientX(evt), mxEvent.getClientY(evt)); - - return this.graph.view.getState(this.graph.getCellAt(pt.x, pt.y)); - }); - - mxEvent.redirectMouseEvents(bend.node, this.graph, getState); - } - else - { - bend.node.style.cursor = mxConstants.CURSOR_BEND_HANDLE; - mxEvent.redirectMouseEvents(bend.node, this.graph, this.state); - } - } - - bends.push(bend); - - if (!terminal) - { - this.points.push(new mxPoint(0,0)); - bend.node.style.visibility = 'hidden'; - } - } - } - } - - return bends; -}; -/** - * Function: isHandleEnabled - * - * Creates the shape used to display the given bend. - */ -mxEdgeHandler.prototype.isHandleEnabled = function(index) -{ - return true; -}; - -/** - * Function: isHandleVisible - * - * Returns true if the handle at the given index is visible. - */ -mxEdgeHandler.prototype.isHandleVisible = function(index) -{ - return true; -}; - -/** - * Function: createHandleShape - * - * Creates the shape used to display the given bend. Note that the index may be - * null for special cases, such as when called from - * <mxElbowEdgeHandler.createVirtualBend>. - */ -mxEdgeHandler.prototype.createHandleShape = function(index) -{ - if (this.handleImage != null) - { - return new mxImageShape(new mxRectangle(0, 0, this.handleImage.width, this.handleImage.height), this.handleImage.src); - } - else - { - var s = mxConstants.HANDLE_SIZE; - - if (this.preferHtml) - { - s -= 1; - } - - return new mxRectangleShape(new mxRectangle(0, 0, s, s), mxConstants.HANDLE_FILLCOLOR, mxConstants.HANDLE_STROKECOLOR); - } -}; - -/** - * Function: initBend - * - * Helper method to initialize the given bend. - * - * Parameters: - * - * bend - <mxShape> that represents the bend to be initialized. - */ -mxEdgeHandler.prototype.initBend = function(bend) -{ - bend.crisp = this.crisp; - - if (this.preferHtml) - { - bend.dialect = mxConstants.DIALECT_STRICTHTML; - bend.init(this.graph.container); - } - else - { - bend.dialect = (this.graph.dialect != mxConstants.DIALECT_SVG) ? - mxConstants.DIALECT_VML : mxConstants.DIALECT_SVG; - bend.init(this.graph.getView().getOverlayPane()); - } -}; - -/** - * Function: getHandleForEvent - * - * Returns the index of the handle for the given event. - */ -mxEdgeHandler.prototype.getHandleForEvent = function(me) -{ - // Finds the handle that triggered the event - if (this.bends != null) - { - // Connection highlight may consume events before they reach sizer handle - var tol = this.tolerance; - var hit = (this.allowHandleBoundsCheck && (mxClient.IS_IE || tol > 0)) ? - new mxRectangle(me.getGraphX() - tol, me.getGraphY() - tol, 2 * tol, 2 * tol) : null; - - for (var i = 0; i < this.bends.length; i++) - { - if (me.isSource(this.bends[i]) || (hit != null && - this.bends[i].node.style.visibility != 'hidden' && - mxUtils.intersects(this.bends[i].bounds, hit))) - { - return i; - } - } - } - - if (me.isSource(this.labelShape) || me.isSource(this.state.text)) - { - // Workaround for SELECT element not working in Webkit - if ((!mxClient.IS_SF && !mxClient.IS_GC) || me.getSource().nodeName != 'SELECT') - { - return mxEvent.LABEL_HANDLE; - } - } - - return null; -}; - -/** - * Function: mouseDown - * - * Handles the event by checking if a special element of the handler - * was clicked, in which case the index parameter is non-null. The - * indices may be one of <LABEL_HANDLE> or the number of the respective - * control point. The source and target points are used for reconnecting - * the edge. - */ -mxEdgeHandler.prototype.mouseDown = function(sender, me) -{ - var handle = null; - - // Handles the case where the state in the event points to another - // cell if the cell has a HTML label which sits on top of the handles - // NOTE: Commented out. This should not be required as all HTML labels - // are in order an do not appear behind the handles. - //if (mxClient.IS_SVG || me.getState() == this.state) - { - handle = this.getHandleForEvent(me); - } - - if (handle != null && !me.isConsumed() && this.graph.isEnabled() && - !this.graph.isForceMarqueeEvent(me.getEvent())) - { - if (this.removeEnabled && this.isRemovePointEvent(me.getEvent())) - { - this.removePoint(this.state, handle); - } - else if (handle != mxEvent.LABEL_HANDLE || this.graph.isLabelMovable(me.getCell())) - { - this.start(me.getX(), me.getY(), handle); - } - - me.consume(); - } -}; - -/** - * Function: start - * - * Starts the handling of the mouse gesture. - */ -mxEdgeHandler.prototype.start = function(x, y, index) -{ - this.startX = x; - this.startY = y; - - this.isSource = (this.bends == null) ? false : index == 0; - this.isTarget = (this.bends == null) ? false : index == this.bends.length - 1; - this.isLabel = index == mxEvent.LABEL_HANDLE; - - if (this.isSource || this.isTarget) - { - var cell = this.state.cell; - var terminal = this.graph.model.getTerminal(cell, this.isSource); - - if ((terminal == null && this.graph.isTerminalPointMovable(cell, this.isSource)) || - (terminal != null && this.graph.isCellDisconnectable(cell, terminal, this.isSource))) - { - this.index = index; - } - } - else - { - this.index = index; - } -}; - -/** - * Function: clonePreviewState - * - * Returns a clone of the current preview state for the given point and terminal. - */ -mxEdgeHandler.prototype.clonePreviewState = function(point, terminal) -{ - return this.state.clone(); -}; - -/** - * Function: getSnapToTerminalTolerance - * - * Returns the tolerance for the guides. Default value is - * gridSize * scale / 2. - */ -mxEdgeHandler.prototype.getSnapToTerminalTolerance = function() -{ - return this.graph.gridSize * this.graph.view.scale / 2; -}; - -/** - * Function: getPointForEvent - * - * Returns the point for the given event. - */ -mxEdgeHandler.prototype.getPointForEvent = function(me) -{ - var point = new mxPoint(me.getGraphX(), me.getGraphY()); - - var tt = this.getSnapToTerminalTolerance(); - var view = this.graph.getView(); - var overrideX = false; - var overrideY = false; - - if (this.snapToTerminals && tt > 0) - { - function snapToPoint(pt) - { - if (pt != null) - { - var x = pt.x; - - if (Math.abs(point.x - x) < tt) - { - point.x = x; - overrideX = true; - } - - var y = pt.y; - - if (Math.abs(point.y - y) < tt) - { - point.y = y; - overrideY = true; - } - } - } - - // Temporary function - function snapToTerminal(terminal) - { - if (terminal != null) - { - snapToPoint.call(this, new mxPoint(view.getRoutingCenterX(terminal), - view.getRoutingCenterY(terminal))); - } - }; - - snapToTerminal.call(this, this.state.getVisibleTerminalState(true)); - snapToTerminal.call(this, this.state.getVisibleTerminalState(false)); - - if (this.abspoints != null) - { - for (var i = 0; i < this.abspoints; i++) - { - if (i != this.index) - { - snapToPoint.call(this, this.abspoints[i]); - } - } - } - } - - if (this.graph.isGridEnabledEvent(me.getEvent())) - { - var scale = view.scale; - var tr = view.translate; - - if (!overrideX) - { - point.x = (this.graph.snap(point.x / scale - tr.x) + tr.x) * scale; - } - - if (!overrideY) - { - point.y = (this.graph.snap(point.y / scale - tr.y) + tr.y) * scale; - } - } - - return point; -}; - -/** - * Function: getPreviewTerminalState - * - * Updates the given preview state taking into account the state of the constraint handler. - */ -mxEdgeHandler.prototype.getPreviewTerminalState = function(me) -{ - this.constraintHandler.update(me, this.isSource); - this.marker.process(me); - var currentState = this.marker.getValidState(); - var result = null; - - if (this.constraintHandler.currentFocus != null && - this.constraintHandler.currentConstraint != null) - { - this.marker.reset(); - } - - if (currentState != null) - { - result = currentState; - } - else if (this.constraintHandler.currentConstraint != null && - this.constraintHandler.currentFocus != null) - { - result = this.constraintHandler.currentFocus; - } - - return result; -}; - -/** - * Function: getPreviewPoints - * - * Updates the given preview state taking into account the state of the constraint handler. - */ -mxEdgeHandler.prototype.getPreviewPoints = function(point) -{ - var geometry = this.graph.getCellGeometry(this.state.cell); - var points = (geometry.points != null) ? geometry.points.slice() : null; - - if (!this.isSource && !this.isTarget) - { - this.convertPoint(point, false); - - if (points == null) - { - points = [point]; - } - else - { - points[this.index - 1] = point; - } - } - else if (this.graph.resetEdgesOnConnect) - { - points = null; - } - - return points; -}; - -/** - * Function: updatePreviewState - * - * Updates the given preview state taking into account the state of the constraint handler. - */ -mxEdgeHandler.prototype.updatePreviewState = function(edge, point, terminalState) -{ - // Computes the points for the edge style and terminals - var sourceState = (this.isSource) ? terminalState : this.state.getVisibleTerminalState(true); - var targetState = (this.isTarget) ? terminalState : this.state.getVisibleTerminalState(false); - - var sourceConstraint = this.graph.getConnectionConstraint(edge, sourceState, true); - var targetConstraint = this.graph.getConnectionConstraint(edge, targetState, false); - - var constraint = this.constraintHandler.currentConstraint; - - if (constraint == null) - { - constraint = new mxConnectionConstraint(); - } - - if (this.isSource) - { - sourceConstraint = constraint; - } - else if (this.isTarget) - { - targetConstraint = constraint; - } - - if (!this.isSource || sourceState != null) - { - edge.view.updateFixedTerminalPoint(edge, sourceState, true, sourceConstraint); - } - - if (!this.isTarget || targetState != null) - { - edge.view.updateFixedTerminalPoint(edge, targetState, false, targetConstraint); - } - - if ((this.isSource || this.isTarget) && terminalState == null) - { - edge.setAbsoluteTerminalPoint(point, this.isSource); - - if (this.marker.getMarkedState() == null) - { - this.error = (this.graph.allowDanglingEdges) ? null : ''; - } - } - - edge.view.updatePoints(edge, this.points, sourceState, targetState); - edge.view.updateFloatingTerminalPoints(edge, sourceState, targetState); -}; - -/** - * Function: mouseMove - * - * Handles the event by updating the preview. - */ -mxEdgeHandler.prototype.mouseMove = function(sender, me) -{ - if (this.index != null && this.marker != null) - { - var point = this.getPointForEvent(me); - - if (this.isLabel) - { - this.label.x = point.x; - this.label.y = point.y; - } - else - { - this.points = this.getPreviewPoints(point); - var terminalState = (this.isSource || this.isTarget) ? this.getPreviewTerminalState(me) : null; - var clone = this.clonePreviewState(point, (terminalState != null) ? terminalState.cell : null); - this.updatePreviewState(clone, point, terminalState); - - // Sets the color of the preview to valid or invalid, updates the - // points of the preview and redraws - var color = (this.error == null) ? this.marker.validColor : - this.marker.invalidColor; - this.setPreviewColor(color); - this.abspoints = clone.absolutePoints; - this.active = true; - } - - this.drawPreview(); - mxEvent.consume(me.getEvent()); - me.consume(); - } - // Workaround for disabling the connect highlight when over handle - else if (mxClient.IS_IE && this.getHandleForEvent(me) != null) - { - me.consume(false); - } -}; - -/** - * Function: mouseUp - * - * Handles the event to applying the previewed changes on the edge by - * using <moveLabel>, <connect> or <changePoints>. - */ -mxEdgeHandler.prototype.mouseUp = function(sender, me) -{ - if (this.index != null && this.marker != null) - { - var edge = this.state.cell; - - // Ignores event if mouse has not been moved - if (me.getX() != this.startX || me.getY() != this.startY) - { - // Displays the reason for not carriying out the change - // if there is an error message with non-zero length - if (this.error != null) - { - if (this.error.length > 0) - { - this.graph.validationAlert(this.error); - } - } - else if (this.isLabel) - { - this.moveLabel(this.state, this.label.x, this.label.y); - } - else if (this.isSource || this.isTarget) - { - var terminal = null; - - if (this.constraintHandler.currentConstraint != null && - this.constraintHandler.currentFocus != null) - { - terminal = this.constraintHandler.currentFocus.cell; - } - - if (terminal == null && this.marker.hasValidState()) - { - terminal = this.marker.validState.cell; - } - - if (terminal != null) - { - edge = this.connect(edge, terminal, this.isSource, - this.graph.isCloneEvent(me.getEvent()) && this.cloneEnabled && - this.graph.isCellsCloneable(), me); - } - else if (this.graph.isAllowDanglingEdges()) - { - var pt = this.abspoints[(this.isSource) ? 0 : this.abspoints.length - 1]; - pt.x = pt.x / this.graph.view.scale - this.graph.view.translate.x; - pt.y = pt.y / this.graph.view.scale - this.graph.view.translate.y; - - var pstate = this.graph.getView().getState( - this.graph.getModel().getParent(edge)); - - if (pstate != null) - { - pt.x -= pstate.origin.x; - pt.y -= pstate.origin.y; - } - - pt.x -= this.graph.panDx / this.graph.view.scale; - pt.y -= this.graph.panDy / this.graph.view.scale; - - // Destroys and rectreates this handler - this.changeTerminalPoint(edge, pt, this.isSource); - } - } - else if (this.active) - { - this.changePoints(edge, this.points); - } - else - { - this.graph.getView().invalidate(this.state.cell); - this.graph.getView().revalidate(this.state.cell); - } - } - - // Resets the preview color the state of the handler if this - // handler has not been recreated - if (this.marker != null) - { - this.reset(); - - // Updates the selection if the edge has been cloned - if (edge != this.state.cell) - { - this.graph.setSelectionCell(edge); - } - } - - me.consume(); - } -}; - -/** - * Function: reset - * - * Resets the state of this handler. - */ -mxEdgeHandler.prototype.reset = function() -{ - this.error = null; - this.index = null; - this.label = null; - this.points = null; - this.active = false; - this.isLabel = false; - this.isSource = false; - this.isTarget = false; - this.marker.reset(); - this.constraintHandler.reset(); - this.setPreviewColor(mxConstants.EDGE_SELECTION_COLOR); - this.redraw(); -}; - -/** - * Function: setPreviewColor - * - * Sets the color of the preview to the given value. - */ -mxEdgeHandler.prototype.setPreviewColor = function(color) -{ - if (this.shape != null && this.shape.node != null) - { - if (this.shape.dialect == mxConstants.DIALECT_SVG) - { - this.shape.innerNode.setAttribute('stroke', color); - } - else - { - this.shape.node.strokecolor = color; - } - } -}; - -/** - * Function: convertPoint - * - * Converts the given point in-place from screen to unscaled, untranslated - * graph coordinates and applies the grid. Returns the given, modified - * point instance. - * - * Parameters: - * - * point - <mxPoint> to be converted. - * gridEnabled - Boolean that specifies if the grid should be applied. - */ -mxEdgeHandler.prototype.convertPoint = function(point, gridEnabled) -{ - var scale = this.graph.getView().getScale(); - var tr = this.graph.getView().getTranslate(); - - if (gridEnabled) - { - point.x = this.graph.snap(point.x); - point.y = this.graph.snap(point.y); - } - - point.x = Math.round(point.x / scale - tr.x); - point.y = Math.round(point.y / scale - tr.y); - - var pstate = this.graph.getView().getState( - this.graph.getModel().getParent(this.state.cell)); - - if (pstate != null) - { - point.x -= pstate.origin.x; - point.y -= pstate.origin.y; - } - - return point; -}; - -/** - * Function: moveLabel - * - * Changes the coordinates for the label of the given edge. - * - * Parameters: - * - * edge - <mxCell> that represents the edge. - * x - Integer that specifies the x-coordinate of the new location. - * y - Integer that specifies the y-coordinate of the new location. - */ -mxEdgeHandler.prototype.moveLabel = function(edgeState, x, y) -{ - var model = this.graph.getModel(); - var geometry = model.getGeometry(edgeState.cell); - - if (geometry != null) - { - geometry = geometry.clone(); - - // Resets the relative location stored inside the geometry - var pt = this.graph.getView().getRelativePoint(edgeState, x, y); - geometry.x = pt.x; - geometry.y = pt.y; - - // Resets the offset inside the geometry to find the offset - // from the resulting point - var scale = this.graph.getView().scale; - geometry.offset = new mxPoint(0, 0); - var pt = this.graph.view.getPoint(edgeState, geometry); - geometry.offset = new mxPoint((x - pt.x) / scale, (y - pt.y) / scale); - - model.setGeometry(edgeState.cell, geometry); - } -}; - -/** - * Function: connect - * - * Changes the terminal or terminal point of the given edge in the graph - * model. - * - * Parameters: - * - * edge - <mxCell> that represents the edge to be reconnected. - * terminal - <mxCell> that represents the new terminal. - * isSource - Boolean indicating if the new terminal is the source or - * target terminal. - * isClone - Boolean indicating if the new connection should be a clone of - * the old edge. - * me - <mxMouseEvent> that contains the mouse up event. - */ -mxEdgeHandler.prototype.connect = function(edge, terminal, isSource, isClone, me) -{ - var model = this.graph.getModel(); - var parent = model.getParent(edge); - - model.beginUpdate(); - try - { - // Clones and adds the cell - if (isClone) - { - var clone = edge.clone(); - model.add(parent, clone, model.getChildCount(parent)); - - var other = model.getTerminal(edge, !isSource); - this.graph.connectCell(clone, other, !isSource); - - edge = clone; - } - - var constraint = this.constraintHandler.currentConstraint; - - if (constraint == null) - { - constraint = new mxConnectionConstraint(); - } - - this.graph.connectCell(edge, terminal, isSource, constraint); - } - finally - { - model.endUpdate(); - } - - return edge; -}; - -/** - * Function: changeTerminalPoint - * - * Changes the terminal point of the given edge. - */ -mxEdgeHandler.prototype.changeTerminalPoint = function(edge, point, isSource) -{ - var model = this.graph.getModel(); - var geo = model.getGeometry(edge); - - if (geo != null) - { - model.beginUpdate(); - try - { - geo = geo.clone(); - geo.setTerminalPoint(point, isSource); - model.setGeometry(edge, geo); - this.graph.connectCell(edge, null, isSource, new mxConnectionConstraint()); - } - finally - { - model.endUpdate(); - } - } -}; - -/** - * Function: changePoints - * - * Changes the control points of the given edge in the graph model. - */ -mxEdgeHandler.prototype.changePoints = function(edge, points) -{ - var model = this.graph.getModel(); - var geo = model.getGeometry(edge); - - if (geo != null) - { - geo = geo.clone(); - geo.points = points; - - model.setGeometry(edge, geo); - } -}; - -/** - * Function: addPoint - * - * Adds a control point for the given state and event. - */ -mxEdgeHandler.prototype.addPoint = function(state, evt) -{ - var geo = this.graph.getCellGeometry(state.cell); - - if (geo != null) - { - geo = geo.clone(); - var pt = mxUtils.convertPoint(this.graph.container, mxEvent.getClientX(evt), - mxEvent.getClientY(evt)); - var index = mxUtils.findNearestSegment(state, pt.x, pt.y); - var gridEnabled = this.graph.isGridEnabledEvent(evt); - this.convertPoint(pt, gridEnabled); - - if (geo.points == null) - { - geo.points = [pt]; - } - else - { - geo.points.splice(index, 0, pt); - } - - this.graph.getModel().setGeometry(state.cell, geo); - this.destroy(); - this.init(); - mxEvent.consume(evt); - } -}; - -/** - * Function: removePoint - * - * Removes the control point at the given index from the given state. - */ -mxEdgeHandler.prototype.removePoint = function(state, index) -{ - if (index > 0 && index < this.abspoints.length - 1) - { - var geo = this.graph.getCellGeometry(this.state.cell); - - if (geo != null && - geo.points != null) - { - geo = geo.clone(); - geo.points.splice(index - 1, 1); - this.graph.getModel().setGeometry(state.cell, geo); - this.destroy(); - this.init(); - } - } -}; - -/** - * Function: getHandleFillColor - * - * Returns the fillcolor for the handle at the given index. - */ -mxEdgeHandler.prototype.getHandleFillColor = function(index) -{ - var isSource = index == 0; - var cell = this.state.cell; - var terminal = this.graph.getModel().getTerminal(cell, isSource); - var color = mxConstants.HANDLE_FILLCOLOR; - - if ((terminal != null && !this.graph.isCellDisconnectable(cell, terminal, isSource)) || - (terminal == null && !this.graph.isTerminalPointMovable(cell, isSource))) - { - color = mxConstants.LOCKED_HANDLE_FILLCOLOR; - } - else if (terminal != null && this.graph.isCellDisconnectable(cell, terminal, isSource)) - { - color = mxConstants.CONNECT_HANDLE_FILLCOLOR; - } - - return color; -}; - -/** - * Function: redraw - * - * Redraws the preview, and the bends- and label control points. - */ -mxEdgeHandler.prototype.redraw = function() -{ - this.abspoints = this.state.absolutePoints.slice(); - var cell = this.state.cell; - - // Updates the handle for the label position - var s = mxConstants.LABEL_HANDLE_SIZE; - - this.label = new mxPoint(this.state.absoluteOffset.x, this.state.absoluteOffset.y); - this.labelShape.bounds = new mxRectangle(this.label.x - s / 2, - this.label.y - s / 2, s, s); - this.labelShape.redraw(); - - // Shows or hides the label handle depending on the label - var lab = this.graph.getLabel(cell); - - if (lab != null && lab.length > 0 && this.graph.isLabelMovable(cell)) - { - this.labelShape.node.style.visibility = 'visible'; - } - else - { - this.labelShape.node.style.visibility = 'hidden'; - } - - if (this.bends != null && this.bends.length > 0) - { - var n = this.abspoints.length - 1; - - var p0 = this.abspoints[0]; - var x0 = this.abspoints[0].x; - var y0 = this.abspoints[0].y; - - var b = this.bends[0].bounds; - this.bends[0].bounds = new mxRectangle(x0 - b.width / 2, y0 - b.height / 2, b.width, b.height); - this.bends[0].fill = this.getHandleFillColor(0); - this.bends[0].reconfigure(); - this.bends[0].redraw(); - - var pe = this.abspoints[n]; - var xn = this.abspoints[n].x; - var yn = this.abspoints[n].y; - - var bn = this.bends.length - 1; - b = this.bends[bn].bounds; - this.bends[bn].bounds = new mxRectangle(xn - b.width / 2, yn - b.height / 2, b.width, b.height); - this.bends[bn].fill = this.getHandleFillColor(bn); - this.bends[bn].reconfigure(); - this.bends[bn].redraw(); - - this.redrawInnerBends(p0, pe); - } - - this.drawPreview(); -}; - -/** - * Function: redrawInnerBends - * - * Updates and redraws the inner bends. - * - * Parameters: - * - * p0 - <mxPoint> that represents the location of the first point. - * pe - <mxPoint> that represents the location of the last point. - */ -mxEdgeHandler.prototype.redrawInnerBends = function(p0, pe) -{ - var g = this.graph.getModel().getGeometry(this.state.cell); - var pts = g.points; - - if (pts != null) - { - if (this.points == null) - { - this.points = []; - } - - for (var i = 1; i < this.bends.length-1; i++) - { - if (this.bends[i] != null) - { - if (this.abspoints[i] != null) - { - var x = this.abspoints[i].x; - var y = this.abspoints[i].y; - - var b = this.bends[i].bounds; - this.bends[i].node.style.visibility = 'visible'; - this.bends[i].bounds = new mxRectangle(x - b.width / 2, y - b.height / 2, b.width, b.height); - this.bends[i].redraw(); - - this.points[i - 1] = pts[i - 1]; - } - else - { - this.bends[i].destroy(); - this.bends[i] = null; - } - } - } - } -}; - -/** - * Function: drawPreview - * - * Redraws the preview. - */ -mxEdgeHandler.prototype.drawPreview = function() -{ - if (this.isLabel) - { - var s = mxConstants.LABEL_HANDLE_SIZE; - - var bounds = new mxRectangle(this.label.x - s / 2, this.label.y - s / 2, s, s); - this.labelShape.bounds = bounds; - this.labelShape.redraw(); - } - else - { - this.shape.points = this.abspoints; - this.shape.redraw(); - } - - // Workaround to force a repaint in AppleWebKit - mxUtils.repaintGraph(this.graph, this.shape.points[this.shape.points.length - 1]); -}; - -/** - * Function: destroy - * - * Destroys the handler and all its resources and DOM nodes. This does - * normally not need to be called as handlers are destroyed automatically - * when the corresponding cell is deselected. - */ -mxEdgeHandler.prototype.destroy = function() -{ - if (this.marker != null) - { - this.marker.destroy(); - this.marker = null; - } - - if (this.shape != null) - { - this.shape.destroy(); - this.shape = null; - } - - if (this.labelShape != null) - { - this.labelShape.destroy(); - this.labelShape = null; - } - - if (this.constraintHandler != null) - { - this.constraintHandler.destroy(); - this.constraintHandler = null; - } - - // Destroy the control points for the bends - if (this.bends != null) - { - for (var i = 0; i < this.bends.length; i++) - { - if (this.bends[i] != null) - { - this.bends[i].destroy(); - this.bends[i] = null; - } - } - } -}; diff --git a/src/js/handler/mxEdgeSegmentHandler.js b/src/js/handler/mxEdgeSegmentHandler.js deleted file mode 100644 index e14fde0..0000000 --- a/src/js/handler/mxEdgeSegmentHandler.js +++ /dev/null @@ -1,284 +0,0 @@ -/** - * $Id: mxEdgeSegmentHandler.js,v 1.14 2012-12-17 13:22:49 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -function mxEdgeSegmentHandler(state) -{ - if (state != null) - { - this.state = state; - this.init(); - } -}; - -/** - * Extends mxEdgeHandler. - */ -mxEdgeSegmentHandler.prototype = new mxElbowEdgeHandler(); -mxEdgeSegmentHandler.prototype.constructor = mxEdgeSegmentHandler; - -/** - * Function: getPreviewPoints - * - * Updates the given preview state taking into account the state of the constraint handler. - */ -mxEdgeSegmentHandler.prototype.getPreviewPoints = function(point) -{ - if (this.isSource || this.isTarget) - { - return mxElbowEdgeHandler.prototype.getPreviewPoints.apply(this, arguments); - } - else - { - this.convertPoint(point, false); - var pts = this.state.absolutePoints; - var last = pts[0].clone(); - this.convertPoint(last, false); - var result = []; - - for (var i = 1; i < pts.length; i++) - { - var pt = pts[i].clone(); - this.convertPoint(pt, false); - - if (i == this.index) - { - if (last.x == pt.x) - { - last.x = point.x; - pt.x = point.x; - } - else - { - last.y = point.y; - pt.y = point.y; - } - } - - if (i < pts.length - 1) - { - result.push(pt); - } - - last = pt; - } - - if (result.length == 1) - { - var view = this.state.view; - var source = this.state.getVisibleTerminalState(true); - var target = this.state.getVisibleTerminalState(false); - - if (target != null & source != null) - { - var dx = this.state.origin.x; - var dy = this.state.origin.y; - - if (mxUtils.contains(target, result[0].x + dx, result[0].y + dy)) - { - if (pts[1].y == pts[2].y) - { - result[0].y = view.getRoutingCenterY(source) - dy; - } - else - { - result[0].x = view.getRoutingCenterX(source) - dx; - } - } - else if (mxUtils.contains(source, result[0].x + dx, result[0].y + dy)) - { - if (pts[1].y == pts[0].y) - { - result[0].y = view.getRoutingCenterY(target) - dy; - } - else - { - result[0].x = view.getRoutingCenterX(target) - dx; - } - } - } - } - else if (result.length == 0) - { - result = [point]; - } - - return result; - } -}; - -/** - * Function: createBends - * - * Adds custom bends for the center of each segment. - */ -mxEdgeSegmentHandler.prototype.createBends = function() -{ - var bends = []; - - // Source - var bend = this.createHandleShape(0); - - this.initBend(bend); - bend.node.style.cursor = mxConstants.CURSOR_BEND_HANDLE; - mxEvent.redirectMouseEvents(bend.node, this.graph, this.state); - bends.push(bend); - - if (mxClient.IS_TOUCH) - { - bend.node.setAttribute('pointer-events', 'none'); - } - - var pts = this.state.absolutePoints; - - // Waypoints (segment handles) - if (this.graph.isCellBendable(this.state.cell)) - { - if (this.points == null) - { - this.points = []; - } - - for (var i = 0; i < pts.length - 1; i++) - { - var bend = this.createVirtualBend(); - bends.push(bend); - var horizontal = pts[i].x - pts[i + 1].x == 0; - bend.node.style.cursor = (horizontal) ? 'col-resize' : 'row-resize'; - this.points.push(new mxPoint(0,0)); - - if (mxClient.IS_TOUCH) - { - bend.node.setAttribute('pointer-events', 'none'); - } - } - } - - // Target - var bend = this.createHandleShape(pts.length); - - this.initBend(bend); - bend.node.style.cursor = mxConstants.CURSOR_BEND_HANDLE; - mxEvent.redirectMouseEvents(bend.node, this.graph, this.state); - bends.push(bend); - - if (mxClient.IS_TOUCH) - { - bend.node.setAttribute('pointer-events', 'none'); - } - - return bends; -}; - - -/** - * Function: redrawInnerBends - * - * Updates the position of the custom bends. - */ -mxEdgeSegmentHandler.prototype.redrawInnerBends = function(p0, pe) -{ - if (this.graph.isCellBendable(this.state.cell)) - { - var s = mxConstants.HANDLE_SIZE; - var pts = this.state.absolutePoints; - - if (pts != null && pts.length > 1) - { - for (var i = 0; i < this.state.absolutePoints.length - 1; i++) - { - if (this.bends[i + 1] != null) - { - var p0 = pts[i]; - var pe = pts[i + 1]; - var pt = new mxPoint(p0.x + (pe.x - p0.x) / 2, p0.y + (pe.y - p0.y) / 2); - this.bends[i+1].bounds = new mxRectangle(pt.x - s / 2, pt.y - s / 2, s, s); - this.bends[i+1].reconfigure(); - this.bends[i+1].redraw(); - } - } - } - } -}; - -/** - * Function: connect - * - * Calls <refresh> after <mxEdgeHandler.connect>. - */ -mxEdgeSegmentHandler.prototype.connect = function(edge, terminal, isSource, isClone, me) -{ - mxEdgeHandler.prototype.connect.apply(this, arguments); - this.refresh(); -}; - -/** - * Function: changeTerminalPoint - * - * Calls <refresh> after <mxEdgeHandler.changeTerminalPoint>. - */ -mxEdgeSegmentHandler.prototype.changeTerminalPoint = function(edge, point, isSource) -{ - mxEdgeHandler.prototype.changeTerminalPoint.apply(this, arguments); - this.refresh(); -}; - -/** - * Function: changePoints - * - * Changes the points of the given edge to reflect the current state of the handler. - */ -mxEdgeSegmentHandler.prototype.changePoints = function(edge, points) -{ - points = []; - var pts = this.abspoints; - - if (pts.length > 1) - { - var pt0 = pts[0]; - var pt1 = pts[1]; - - for (var i = 2; i < pts.length; i++) - { - var pt2 = pts[i]; - - if ((Math.round(pt0.x) != Math.round(pt1.x) || - Math.round(pt1.x) != Math.round(pt2.x)) && - (Math.round(pt0.y) != Math.round(pt1.y) || - Math.round(pt1.y) != Math.round(pt2.y))) - { - pt0 = pt1; - pt1 = pt1.clone(); - this.convertPoint(pt1, false); - points.push(pt1); - } - - pt1 = pt2; - } - } - - mxElbowEdgeHandler.prototype.changePoints.apply(this, arguments); - this.refresh(); -}; - -/** - * Function: refresh - * - * Refreshes the bends of this handler. - */ -mxEdgeSegmentHandler.prototype.refresh = function() -{ - if (this.bends != null) - { - for (var i = 0; i < this.bends.length; i++) - { - if (this.bends[i] != null) - { - this.bends[i].destroy(); - this.bends[i] = null; - } - } - - this.bends = this.createBends(); - } -}; diff --git a/src/js/handler/mxElbowEdgeHandler.js b/src/js/handler/mxElbowEdgeHandler.js deleted file mode 100644 index 85fbb06..0000000 --- a/src/js/handler/mxElbowEdgeHandler.js +++ /dev/null @@ -1,248 +0,0 @@ -/** - * $Id: mxElbowEdgeHandler.js,v 1.43 2012-01-06 13:06:01 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -/** - * Class: mxElbowEdgeHandler - * - * Graph event handler that reconnects edges and modifies control points and - * the edge label location. Uses <mxTerminalMarker> for finding and - * highlighting new source and target vertices. This handler is automatically - * created in <mxGraph.createHandler>. It extends <mxEdgeHandler>. - * - * Constructor: mxEdgeHandler - * - * Constructs an edge handler for the specified <mxCellState>. - * - * Parameters: - * - * state - <mxCellState> of the cell to be modified. - */ -function mxElbowEdgeHandler(state) -{ - if (state != null) - { - this.state = state; - this.init(); - } -}; - -/** - * Extends mxEdgeHandler. - */ -mxElbowEdgeHandler.prototype = new mxEdgeHandler(); -mxElbowEdgeHandler.prototype.constructor = mxElbowEdgeHandler; - -/** - * Specifies if a double click on the middle handle should call - * <mxGraph.flipEdge>. Default is true. - */ -mxElbowEdgeHandler.prototype.flipEnabled = true; - -/** - * Variable: doubleClickOrientationResource - * - * Specifies the resource key for the tooltip to be displayed on the single - * control point for routed edges. If the resource for this key does not - * exist then the value is used as the error message. Default is - * 'doubleClickOrientation'. - */ -mxElbowEdgeHandler.prototype.doubleClickOrientationResource = - (mxClient.language != 'none') ? 'doubleClickOrientation' : ''; - -/** - * Function: createBends - * - * Overrides <mxEdgeHandler.createBends> to create custom bends. - */ - mxElbowEdgeHandler.prototype.createBends = function() - { - var bends = []; - - // Source - var bend = this.createHandleShape(0); - - this.initBend(bend); - bend.node.style.cursor = mxConstants.CURSOR_BEND_HANDLE; - mxEvent.redirectMouseEvents(bend.node, this.graph, this.state); - bends.push(bend); - - if (mxClient.IS_TOUCH) - { - bend.node.setAttribute('pointer-events', 'none'); - } - - // Virtual - bends.push(this.createVirtualBend()); - this.points.push(new mxPoint(0,0)); - - // Target - bend = this.createHandleShape(2); - - this.initBend(bend); - bend.node.style.cursor = mxConstants.CURSOR_BEND_HANDLE; - mxEvent.redirectMouseEvents(bend.node, this.graph, this.state); - bends.push(bend); - - if (mxClient.IS_TOUCH) - { - bend.node.setAttribute('pointer-events', 'none'); - } - - return bends; - }; - -/** - * Function: createVirtualBend - * - * Creates a virtual bend that supports double clicking and calls - * <mxGraph.flipEdge>. - */ -mxElbowEdgeHandler.prototype.createVirtualBend = function() -{ - var bend = this.createHandleShape(); - this.initBend(bend); - - var crs = this.getCursorForBend(); - bend.node.style.cursor = crs; - - // Double-click changes edge style - var dblClick = mxUtils.bind(this, function(evt) - { - if (!mxEvent.isConsumed(evt) && - this.flipEnabled) - { - this.graph.flipEdge(this.state.cell, evt); - mxEvent.consume(evt); - } - }); - - mxEvent.redirectMouseEvents(bend.node, this.graph, this.state, - null, null, null, dblClick); - - if (!this.graph.isCellBendable(this.state.cell)) - { - bend.node.style.visibility = 'hidden'; - } - - return bend; -}; - -/** - * Function: getCursorForBend - * - * Returns the cursor to be used for the bend. - */ -mxElbowEdgeHandler.prototype.getCursorForBend = function() -{ - return (this.state.style[mxConstants.STYLE_EDGE] == mxEdgeStyle.TopToBottom || - this.state.style[mxConstants.STYLE_EDGE] == mxConstants.EDGESTYLE_TOPTOBOTTOM || - ((this.state.style[mxConstants.STYLE_EDGE] == mxEdgeStyle.ElbowConnector || - this.state.style[mxConstants.STYLE_EDGE] == mxConstants.EDGESTYLE_ELBOW)&& - this.state.style[mxConstants.STYLE_ELBOW] == mxConstants.ELBOW_VERTICAL)) ? - 'row-resize' : 'col-resize'; -}; - -/** - * Function: getTooltipForNode - * - * Returns the tooltip for the given node. - */ -mxElbowEdgeHandler.prototype.getTooltipForNode = function(node) -{ - var tip = null; - - if (this.bends != null && - this.bends[1] != null && - (node == this.bends[1].node || - node.parentNode == this.bends[1].node)) - { - tip = this.doubleClickOrientationResource; - tip = mxResources.get(tip) || tip; // translate - } - - return tip; -}; - -/** - * Function: convertPoint - * - * Converts the given point in-place from screen to unscaled, untranslated - * graph coordinates and applies the grid. - * - * Parameters: - * - * point - <mxPoint> to be converted. - * gridEnabled - Boolean that specifies if the grid should be applied. - */ -mxElbowEdgeHandler.prototype.convertPoint = function(point, gridEnabled) -{ - var scale = this.graph.getView().getScale(); - var tr = this.graph.getView().getTranslate(); - var origin = this.state.origin; - - if (gridEnabled) - { - point.x = this.graph.snap(point.x); - point.y = this.graph.snap(point.y); - } - - point.x = Math.round(point.x / scale - tr.x - origin.x); - point.y = Math.round(point.y / scale - tr.y - origin.y); -}; - -/** - * Function: redrawInnerBends - * - * Updates and redraws the inner bends. - * - * Parameters: - * - * p0 - <mxPoint> that represents the location of the first point. - * pe - <mxPoint> that represents the location of the last point. - */ -mxElbowEdgeHandler.prototype.redrawInnerBends = function(p0, pe) -{ - var g = this.graph.getModel().getGeometry(this.state.cell); - var pts = g.points; - - var pt = (pts != null) ? pts[0] : null; - - if (pt == null) - { - pt = new mxPoint(p0.x + (pe.x - p0.x) / 2, p0.y + (pe.y - p0.y) / 2); - } - else - { - pt = new mxPoint(this.graph.getView().scale*(pt.x + - this.graph.getView().translate.x + this.state.origin.x), - this.graph.getView().scale*(pt.y + this.graph.getView().translate.y + - this.state.origin.y)); - } - - // Makes handle slightly bigger if the yellow label handle - // exists and intersects this green handle - var b = this.bends[1].bounds; - var w = b.width; - var h = b.height; - - if (this.handleImage == null) - { - w = mxConstants.HANDLE_SIZE; - h = mxConstants.HANDLE_SIZE; - } - - var bounds = new mxRectangle(pt.x - w / 2, pt.y - h / 2, w, h); - - if (this.handleImage == null && this.labelShape.node.style.visibility != 'hidden' && - mxUtils.intersects(bounds, this.labelShape.bounds)) - { - w += 3; - h += 3; - bounds = new mxRectangle(pt.x - w / 2, pt.y - h / 2, w, h); - } - - this.bends[1].bounds = bounds; - this.bends[1].reconfigure(); - this.bends[1].redraw(); -}; diff --git a/src/js/handler/mxGraphHandler.js b/src/js/handler/mxGraphHandler.js deleted file mode 100644 index 57e27a1..0000000 --- a/src/js/handler/mxGraphHandler.js +++ /dev/null @@ -1,916 +0,0 @@ -/** - * $Id: mxGraphHandler.js,v 1.129 2012-04-13 12:53:30 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -/** - * Class: mxGraphHandler - * - * Graph event handler that handles selection. Individual cells are handled - * separately using <mxVertexHandler> or one of the edge handlers. These - * handlers are created using <mxGraph.createHandler> in - * <mxGraphSelectionModel.cellAdded>. - * - * To avoid the container to scroll a moved cell into view, set - * <scrollAfterMove> to false. - * - * Constructor: mxGraphHandler - * - * Constructs an event handler that creates handles for the - * selection cells. - * - * Parameters: - * - * graph - Reference to the enclosing <mxGraph>. - */ -function mxGraphHandler(graph) -{ - this.graph = graph; - this.graph.addMouseListener(this); - - // Repaints the handler after autoscroll - this.panHandler = mxUtils.bind(this, function() - { - this.updatePreviewShape(); - }); - - this.graph.addListener(mxEvent.PAN, this.panHandler); -}; - -/** - * Variable: graph - * - * Reference to the enclosing <mxGraph>. - */ -mxGraphHandler.prototype.graph = null; - -/** - * Variable: maxCells - * - * Defines the maximum number of cells to paint subhandles - * for. Default is 50 for Firefox and 20 for IE. Set this - * to 0 if you want an unlimited number of handles to be - * displayed. This is only recommended if the number of - * cells in the graph is limited to a small number, eg. - * 500. - */ -mxGraphHandler.prototype.maxCells = (mxClient.IS_IE) ? 20 : 50; - -/** - * Variable: enabled - * - * Specifies if events are handled. Default is true. - */ -mxGraphHandler.prototype.enabled = true; - -/** - * Variable: highlightEnabled - * - * Specifies if drop targets under the mouse should be enabled. Default is - * true. - */ -mxGraphHandler.prototype.highlightEnabled = true; - -/** - * Variable: cloneEnabled - * - * Specifies if cloning by control-drag is enabled. Default is true. - */ -mxGraphHandler.prototype.cloneEnabled = true; - -/** - * Variable: moveEnabled - * - * Specifies if moving is enabled. Default is true. - */ -mxGraphHandler.prototype.moveEnabled = true; - -/** - * Variable: guidesEnabled - * - * Specifies if other cells should be used for snapping the right, center or - * left side of the current selection. Default is false. - */ -mxGraphHandler.prototype.guidesEnabled = false; - -/** - * Variable: guide - * - * Holds the <mxGuide> instance that is used for alignment. - */ -mxGraphHandler.prototype.guide = null; - -/** - * Variable: currentDx - * - * Stores the x-coordinate of the current mouse move. - */ -mxGraphHandler.prototype.currentDx = null; - -/** - * Variable: currentDy - * - * Stores the y-coordinate of the current mouse move. - */ -mxGraphHandler.prototype.currentDy = null; - -/** - * Variable: updateCursor - * - * Specifies if a move cursor should be shown if the mouse is ove a movable - * cell. Default is true. - */ -mxGraphHandler.prototype.updateCursor = true; - -/** - * Variable: selectEnabled - * - * Specifies if selecting is enabled. Default is true. - */ -mxGraphHandler.prototype.selectEnabled = true; - -/** - * Variable: removeCellsFromParent - * - * Specifies if cells may be moved out of their parents. Default is true. - */ -mxGraphHandler.prototype.removeCellsFromParent = true; - -/** - * Variable: connectOnDrop - * - * Specifies if drop events are interpreted as new connections if no other - * drop action is defined. Default is false. - */ -mxGraphHandler.prototype.connectOnDrop = false; - -/** - * Variable: scrollOnMove - * - * Specifies if the view should be scrolled so that a moved cell is - * visible. Default is true. - */ -mxGraphHandler.prototype.scrollOnMove = true; - -/** - * Variable: minimumSize - * - * Specifies the minimum number of pixels for the width and height of a - * selection border. Default is 6. - */ -mxGraphHandler.prototype.minimumSize = 6; - -/** - * Variable: previewColor - * - * Specifies the color of the preview shape. Default is black. - */ -mxGraphHandler.prototype.previewColor = 'black'; - -/** - * Variable: htmlPreview - * - * Specifies if the graph container should be used for preview. If this is used - * then drop target detection relies entirely on <mxGraph.getCellAt> because - * the HTML preview does not "let events through". Default is false. - */ -mxGraphHandler.prototype.htmlPreview = false; - -/** - * Variable: shape - * - * Reference to the <mxShape> that represents the preview. - */ -mxGraphHandler.prototype.shape = null; - -/** - * Variable: scaleGrid - * - * Specifies if the grid should be scaled. Default is false. - */ -mxGraphHandler.prototype.scaleGrid = false; - -/** - * Variable: crisp - * - * Specifies if the move preview should be rendered in crisp mode if applicable. - * Default is true. - */ -mxGraphHandler.prototype.crisp = true; - -/** - * Function: isEnabled - * - * Returns <enabled>. - */ -mxGraphHandler.prototype.isEnabled = function() -{ - return this.enabled; -}; - -/** - * Function: setEnabled - * - * Sets <enabled>. - */ -mxGraphHandler.prototype.setEnabled = function(value) -{ - this.enabled = value; -}; - -/** - * Function: isCloneEnabled - * - * Returns <cloneEnabled>. - */ -mxGraphHandler.prototype.isCloneEnabled = function() -{ - return this.cloneEnabled; -}; - -/** - * Function: setCloneEnabled - * - * Sets <cloneEnabled>. - * - * Parameters: - * - * value - Boolean that specifies the new clone enabled state. - */ -mxGraphHandler.prototype.setCloneEnabled = function(value) -{ - this.cloneEnabled = value; -}; - -/** - * Function: isMoveEnabled - * - * Returns <moveEnabled>. - */ -mxGraphHandler.prototype.isMoveEnabled = function() -{ - return this.moveEnabled; -}; - -/** - * Function: setMoveEnabled - * - * Sets <moveEnabled>. - */ -mxGraphHandler.prototype.setMoveEnabled = function(value) -{ - this.moveEnabled = value; -}; - -/** - * Function: isSelectEnabled - * - * Returns <selectEnabled>. - */ -mxGraphHandler.prototype.isSelectEnabled = function() -{ - return this.selectEnabled; -}; - -/** - * Function: setSelectEnabled - * - * Sets <selectEnabled>. - */ -mxGraphHandler.prototype.setSelectEnabled = function(value) -{ - this.selectEnabled = value; -}; - -/** - * Function: isRemoveCellsFromParent - * - * Returns <removeCellsFromParent>. - */ -mxGraphHandler.prototype.isRemoveCellsFromParent = function() -{ - return this.removeCellsFromParent; -}; - -/** - * Function: setRemoveCellsFromParent - * - * Sets <removeCellsFromParent>. - */ -mxGraphHandler.prototype.setRemoveCellsFromParent = function(value) -{ - this.removeCellsFromParent = value; -}; - -/** - * Function: getInitialCellForEvent - * - * Hook to return initial cell for the given event. - */ -mxGraphHandler.prototype.getInitialCellForEvent = function(me) -{ - return me.getCell(); -}; - -/** - * Function: isDelayedSelection - * - * Hook to return true for delayed selections. - */ -mxGraphHandler.prototype.isDelayedSelection = function(cell) -{ - return this.graph.isCellSelected(cell); -}; - -/** - * Function: mouseDown - * - * Handles the event by selecing the given cell and creating a handle for - * it. By consuming the event all subsequent events of the gesture are - * redirected to this handler. - */ -mxGraphHandler.prototype.mouseDown = function(sender, me) -{ - if (!me.isConsumed() && this.isEnabled() && this.graph.isEnabled() && - !this.graph.isForceMarqueeEvent(me.getEvent()) && me.getState() != null) - { - var cell = this.getInitialCellForEvent(me); - this.cell = null; - this.delayedSelection = this.isDelayedSelection(cell); - - if (this.isSelectEnabled() && !this.delayedSelection) - { - this.graph.selectCellForEvent(cell, me.getEvent()); - } - - if (this.isMoveEnabled()) - { - var model = this.graph.model; - var geo = model.getGeometry(cell); - - if (this.graph.isCellMovable(cell) && ((!model.isEdge(cell) || this.graph.getSelectionCount() > 1 || - (geo.points != null && geo.points.length > 0) || model.getTerminal(cell, true) == null || - model.getTerminal(cell, false) == null) || this.graph.allowDanglingEdges || - (this.graph.isCloneEvent(me.getEvent()) && this.graph.isCellsCloneable()))) - { - this.start(cell, me.getX(), me.getY()); - } - - this.cellWasClicked = true; - - // Workaround for SELECT element not working in Webkit, this blocks moving - // of the cell if the select element is clicked in Safari which is needed - // because Safari doesn't seem to route the subsequent mouseUp event via - // this handler which leads to an inconsistent state (no reset called). - // Same for cellWasClicked which will block clearing the selection when - // clicking the background after clicking on the SELECT element in Safari. - if ((!mxClient.IS_SF && !mxClient.IS_GC) || me.getSource().nodeName != 'SELECT') - { - me.consume(); - } - else if (mxClient.IS_SF && me.getSource().nodeName == 'SELECT') - { - this.cellWasClicked = false; - this.first = null; - } - } - } -}; - -/** - * Function: getGuideStates - * - * Creates an array of cell states which should be used as guides. - */ -mxGraphHandler.prototype.getGuideStates = function() -{ - var parent = this.graph.getDefaultParent(); - var model = this.graph.getModel(); - - var filter = mxUtils.bind(this, function(cell) - { - return this.graph.view.getState(cell) != null && - model.isVertex(cell) && - model.getGeometry(cell) != null && - !model.getGeometry(cell).relative; - }); - - return this.graph.view.getCellStates(model.filterDescendants(filter, parent)); -}; - -/** - * Function: getCells - * - * Returns the cells to be modified by this handler. This implementation - * returns all selection cells that are movable, or the given initial cell if - * the given cell is not selected and movable. This handles the case of moving - * unselectable or unselected cells. - * - * Parameters: - * - * initialCell - <mxCell> that triggered this handler. - */ -mxGraphHandler.prototype.getCells = function(initialCell) -{ - if (!this.delayedSelection && this.graph.isCellMovable(initialCell)) - { - return [initialCell]; - } - else - { - return this.graph.getMovableCells(this.graph.getSelectionCells()); - } -}; - -/** - * Function: getPreviewBounds - * - * Returns the <mxRectangle> used as the preview bounds for - * moving the given cells. - */ -mxGraphHandler.prototype.getPreviewBounds = function(cells) -{ - var bounds = this.graph.getView().getBounds(cells); - - if (bounds != null) - { - if (bounds.width < this.minimumSize) - { - var dx = this.minimumSize - bounds.width; - bounds.x -= dx / 2; - bounds.width = this.minimumSize; - } - - if (bounds.height < this.minimumSize) - { - var dy = this.minimumSize - bounds.height; - bounds.y -= dy / 2; - bounds.height = this.minimumSize; - } - } - - return bounds; -}; - -/** - * Function: createPreviewShape - * - * Creates the shape used to draw the preview for the given bounds. - */ -mxGraphHandler.prototype.createPreviewShape = function(bounds) -{ - var shape = new mxRectangleShape(bounds, null, this.previewColor); - shape.isDashed = true; - shape.crisp = this.crisp; - - if (this.htmlPreview) - { - shape.dialect = mxConstants.DIALECT_STRICTHTML; - shape.init(this.graph.container); - } - else - { - // Makes sure to use either VML or SVG shapes in order to implement - // event-transparency on the background area of the rectangle since - // HTML shapes do not let mouseevents through even when transparent - shape.dialect = (this.graph.dialect != mxConstants.DIALECT_SVG) ? - mxConstants.DIALECT_VML : mxConstants.DIALECT_SVG; - shape.init(this.graph.getView().getOverlayPane()); - - // Event-transparency - if (shape.dialect == mxConstants.DIALECT_SVG) - { - shape.node.setAttribute('style', 'pointer-events:none;'); - } - else - { - shape.node.style.background = ''; - } - } - - return shape; -}; - -/** - * Function: start - * - * Starts the handling of the mouse gesture. - */ -mxGraphHandler.prototype.start = function(cell, x, y) -{ - this.cell = cell; - this.first = mxUtils.convertPoint(this.graph.container, x, y); - this.cells = this.getCells(this.cell); - this.bounds = this.getPreviewBounds(this.cells); - - if (this.guidesEnabled) - { - this.guide = new mxGuide(this.graph, this.getGuideStates()); - } -}; - -/** - * Function: useGuidesForEvent - * - * Returns true if the guides should be used for the given <mxMouseEvent>. - * This implementation returns <mxGuide.isEnabledForEvent>. - */ -mxGraphHandler.prototype.useGuidesForEvent = function(me) -{ - return (this.guide != null) ? this.guide.isEnabledForEvent(me.getEvent()) : true; -}; - - -/** - * Function: snap - * - * Snaps the given vector to the grid and returns the given mxPoint instance. - */ -mxGraphHandler.prototype.snap = function(vector) -{ - var scale = (this.scaleGrid) ? this.graph.view.scale : 1; - - vector.x = this.graph.snap(vector.x / scale) * scale; - vector.y = this.graph.snap(vector.y / scale) * scale; - - return vector; -}; - -/** - * Function: mouseMove - * - * Handles the event by highlighting possible drop targets and updating the - * preview. - */ -mxGraphHandler.prototype.mouseMove = function(sender, me) -{ - var graph = this.graph; - - if (!me.isConsumed() && graph.isMouseDown && this.cell != null && - this.first != null && this.bounds != null) - { - var point = mxUtils.convertPoint(graph.container, me.getX(), me.getY()); - var dx = point.x - this.first.x; - var dy = point.y - this.first.y; - var tol = graph.tolerance; - - if (this.shape!= null || Math.abs(dx) > tol || Math.abs(dy) > tol) - { - // Highlight is used for highlighting drop targets - if (this.highlight == null) - { - this.highlight = new mxCellHighlight(this.graph, - mxConstants.DROP_TARGET_COLOR, 3); - } - - if (this.shape == null) - { - this.shape = this.createPreviewShape(this.bounds); - } - - var gridEnabled = graph.isGridEnabledEvent(me.getEvent()); - var hideGuide = true; - - if (this.guide != null && this.useGuidesForEvent(me)) - { - var delta = this.guide.move(this.bounds, new mxPoint(dx, dy), gridEnabled); - hideGuide = false; - dx = delta.x; - dy = delta.y; - } - else if (gridEnabled) - { - var trx = graph.getView().translate; - var scale = graph.getView().scale; - - var tx = this.bounds.x - (graph.snap(this.bounds.x / scale - trx.x) + trx.x) * scale; - var ty = this.bounds.y - (graph.snap(this.bounds.y / scale - trx.y) + trx.y) * scale; - var v = this.snap(new mxPoint(dx, dy)); - - dx = v.x - tx; - dy = v.y - ty; - } - - if (this.guide != null && hideGuide) - { - this.guide.hide(); - } - - // Constrained movement if shift key is pressed - if (graph.isConstrainedEvent(me.getEvent())) - { - if (Math.abs(dx) > Math.abs(dy)) - { - dy = 0; - } - else - { - dx = 0; - } - } - - this.currentDx = dx; - this.currentDy = dy; - this.updatePreviewShape(); - - var target = null; - var cell = me.getCell(); - - if (graph.isDropEnabled() && this.highlightEnabled) - { - // Contains a call to getCellAt to find the cell under the mouse - target = graph.getDropTarget(this.cells, me.getEvent(), cell); - } - - // Checks if parent is dropped into child - var parent = target; - var model = graph.getModel(); - - while (parent != null && parent != this.cells[0]) - { - parent = model.getParent(parent); - } - - var clone = graph.isCloneEvent(me.getEvent()) && graph.isCellsCloneable() && this.isCloneEnabled(); - var state = graph.getView().getState(target); - var highlight = false; - - if (state != null && parent == null && (model.getParent(this.cell) != target || clone)) - { - if (this.target != target) - { - this.target = target; - this.setHighlightColor(mxConstants.DROP_TARGET_COLOR); - } - - highlight = true; - } - else - { - this.target = null; - - if (this.connectOnDrop && cell != null && this.cells.length == 1 && - graph.getModel().isVertex(cell) && graph.isCellConnectable(cell)) - { - state = graph.getView().getState(cell); - - if (state != null) - { - var error = graph.getEdgeValidationError(null, this.cell, cell); - var color = (error == null) ? - mxConstants.VALID_COLOR : - mxConstants.INVALID_CONNECT_TARGET_COLOR; - this.setHighlightColor(color); - highlight = true; - } - } - } - - if (state != null && highlight) - { - this.highlight.highlight(state); - } - else - { - this.highlight.hide(); - } - } - - me.consume(); - - // Cancels the bubbling of events to the container so - // that the droptarget is not reset due to an mouseMove - // fired on the container with no associated state. - mxEvent.consume(me.getEvent()); - } - else if ((this.isMoveEnabled() || this.isCloneEnabled()) && this.updateCursor && - !me.isConsumed() && me.getState() != null && !graph.isMouseDown) - { - var cursor = graph.getCursorForCell(me.getCell()); - - if (cursor == null && graph.isEnabled() && graph.isCellMovable(me.getCell())) - { - if (graph.getModel().isEdge(me.getCell())) - { - cursor = mxConstants.CURSOR_MOVABLE_EDGE; - } - else - { - cursor = mxConstants.CURSOR_MOVABLE_VERTEX; - } - } - - me.getState().setCursor(cursor); - me.consume(); - } -}; - -/** - * Function: updatePreviewShape - * - * Updates the bounds of the preview shape. - */ -mxGraphHandler.prototype.updatePreviewShape = function() -{ - if (this.shape != null) - { - this.shape.bounds = new mxRectangle(this.bounds.x + this.currentDx - this.graph.panDx, - this.bounds.y + this.currentDy - this.graph.panDy, this.bounds.width, this.bounds.height); - this.shape.redraw(); - } -}; - -/** - * Function: setHighlightColor - * - * Sets the color of the rectangle used to highlight drop targets. - * - * Parameters: - * - * color - String that represents the new highlight color. - */ -mxGraphHandler.prototype.setHighlightColor = function(color) -{ - if (this.highlight != null) - { - this.highlight.setHighlightColor(color); - } -}; - -/** - * Function: mouseUp - * - * Handles the event by applying the changes to the selection cells. - */ -mxGraphHandler.prototype.mouseUp = function(sender, me) -{ - if (!me.isConsumed()) - { - var graph = this.graph; - - if (this.cell != null && this.first != null && this.shape != null && - this.currentDx != null && this.currentDy != null) - { - var scale = graph.getView().scale; - var clone = graph.isCloneEvent(me.getEvent()) && graph.isCellsCloneable() && this.isCloneEnabled(); - var dx = this.currentDx / scale; - var dy = this.currentDy / scale; - - var cell = me.getCell(); - - if (this.connectOnDrop && this.target == null && cell != null && graph.getModel().isVertex(cell) && - graph.isCellConnectable(cell) && graph.isEdgeValid(null, this.cell, cell)) - { - graph.connectionHandler.connect(this.cell, cell, me.getEvent()); - } - else - { - var target = this.target; - - if (graph.isSplitEnabled() && graph.isSplitTarget(target, this.cells, me.getEvent())) - { - graph.splitEdge(target, this.cells, null, dx, dy); - } - else - { - this.moveCells(this.cells, dx, dy, clone, this.target, me.getEvent()); - } - } - } - else if (this.isSelectEnabled() && this.delayedSelection && this.cell != null) - { - this.selectDelayed(me); - } - } - - // Consumes the event if a cell was initially clicked - if (this.cellWasClicked) - { - me.consume(); - } - - this.reset(); -}; - -/** - * Function: selectDelayed - * - * Implements the delayed selection for the given mouse event. - */ -mxGraphHandler.prototype.selectDelayed = function(me) -{ - this.graph.selectCellForEvent(this.cell, me.getEvent()); -}; - -/** - * Function: reset - * - * Resets the state of this handler. - */ -mxGraphHandler.prototype.reset = function() -{ - this.destroyShapes(); - this.cellWasClicked = false; - this.delayedSelection = false; - this.currentDx = null; - this.currentDy = null; - this.guides = null; - this.first = null; - this.cell = null; - this.target = null; -}; - -/** - * Function: shouldRemoveCellsFromParent - * - * Returns true if the given cells should be removed from the parent for the specified - * mousereleased event. - */ -mxGraphHandler.prototype.shouldRemoveCellsFromParent = function(parent, cells, evt) -{ - if (this.graph.getModel().isVertex(parent)) - { - var pState = this.graph.getView().getState(parent); - var pt = mxUtils.convertPoint(this.graph.container, - mxEvent.getClientX(evt), mxEvent.getClientY(evt)); - - return pState != null && !mxUtils.contains(pState, pt.x, pt.y); - } - - return false; -}; - -/** - * Function: moveCells - * - * Moves the given cells by the specified amount. - */ -mxGraphHandler.prototype.moveCells = function(cells, dx, dy, clone, target, evt) -{ - if (clone) - { - cells = this.graph.getCloneableCells(cells); - } - - // Removes cells from parent - if (target == null && this.isRemoveCellsFromParent() && - this.shouldRemoveCellsFromParent(this.graph.getModel().getParent(this.cell), cells, evt)) - { - target = this.graph.getDefaultParent(); - } - - // Passes all selected cells in order to correctly clone or move into - // the target cell. The method checks for each cell if its movable. - cells = this.graph.moveCells(cells, dx - this.graph.panDx / this.graph.view.scale, - dy - this.graph.panDy / this.graph.view.scale, clone, target, evt); - - if (this.isSelectEnabled() && this.scrollOnMove) - { - this.graph.scrollCellToVisible(cells[0]); - } - - // Selects the new cells if cells have been cloned - if (clone) - { - this.graph.setSelectionCells(cells); - } -}; - -/** - * Function: destroyShapes - * - * Destroy the preview and highlight shapes. - */ -mxGraphHandler.prototype.destroyShapes = function() -{ - // Destroys the preview dashed rectangle - if (this.shape != null) - { - this.shape.destroy(); - this.shape = null; - } - - if (this.guide != null) - { - this.guide.destroy(); - this.guide = null; - } - - // Destroys the drop target highlight - if (this.highlight != null) - { - this.highlight.destroy(); - this.highlight = null; - } -}; - -/** - * Function: destroy - * - * Destroys the handler and all its resources and DOM nodes. - */ -mxGraphHandler.prototype.destroy = function() -{ - this.graph.removeMouseListener(this); - this.graph.removeListener(this.panHandler); - this.destroyShapes(); -}; diff --git a/src/js/handler/mxKeyHandler.js b/src/js/handler/mxKeyHandler.js deleted file mode 100644 index cc07e51..0000000 --- a/src/js/handler/mxKeyHandler.js +++ /dev/null @@ -1,402 +0,0 @@ -/** - * $Id: mxKeyHandler.js,v 1.48 2012-03-30 08:30:41 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -/** - * Class: mxKeyHandler - * - * Event handler that listens to keystroke events. This is not a singleton, - * however, it is normally only required once if the target is the document - * element (default). - * - * This handler installs a key event listener in the topmost DOM node and - * processes all events that originate from descandants of <mxGraph.container> - * or from the topmost DOM node. The latter means that all unhandled keystrokes - * are handled by this object regardless of the focused state of the <graph>. - * - * Example: - * - * The following example creates a key handler that listens to the delete key - * (46) and deletes the selection cells if the graph is enabled. - * - * (code) - * var keyHandler = new mxKeyHandler(graph); - * keyHandler.bindKey(46, function(evt) - * { - * if (graph.isEnabled()) - * { - * graph.removeCells(); - * } - * }); - * (end) - * - * Keycodes: - * - * See http://tinyurl.com/yp8jgl or http://tinyurl.com/229yqw for a list of - * keycodes or install a key event listener into the document element and print - * the key codes of the respective events to the console. - * - * To support the Command key and the Control key on the Mac, the following - * code can be used. - * - * (code) - * keyHandler.getFunction = function(evt) - * { - * if (evt != null) - * { - * return (mxEvent.isControlDown(evt) || (mxClient.IS_MAC && evt.metaKey)) ? this.controlKeys[evt.keyCode] : this.normalKeys[evt.keyCode]; - * } - * - * return null; - * }; - * (end) - * - * Constructor: mxKeyHandler - * - * Constructs an event handler that executes functions bound to specific - * keystrokes. - * - * Parameters: - * - * graph - Reference to the associated <mxGraph>. - * target - Optional reference to the event target. If null, the document - * element is used as the event target, that is, the object where the key - * event listener is installed. - */ -function mxKeyHandler(graph, target) -{ - if (graph != null) - { - this.graph = graph; - this.target = target || document.documentElement; - - // Creates the arrays to map from keycodes to functions - this.normalKeys = []; - this.shiftKeys = []; - this.controlKeys = []; - this.controlShiftKeys = []; - - // Installs the keystroke listener in the target - mxEvent.addListener(this.target, "keydown", - mxUtils.bind(this, function(evt) - { - this.keyDown(evt); - }) - ); - - // Automatically deallocates memory in IE - if (mxClient.IS_IE) - { - mxEvent.addListener(window, 'unload', - mxUtils.bind(this, function() - { - this.destroy(); - }) - ); - } - } -}; - -/** - * Variable: graph - * - * Reference to the <mxGraph> associated with this handler. - */ -mxKeyHandler.prototype.graph = null; - -/** - * Variable: target - * - * Reference to the target DOM, that is, the DOM node where the key event - * listeners are installed. - */ -mxKeyHandler.prototype.target = null; - -/** - * Variable: normalKeys - * - * Maps from keycodes to functions for non-pressed control keys. - */ -mxKeyHandler.prototype.normalKeys = null; - -/** - * Variable: shiftKeys - * - * Maps from keycodes to functions for pressed shift keys. - */ -mxKeyHandler.prototype.shiftKeys = null; - -/** - * Variable: controlKeys - * - * Maps from keycodes to functions for pressed control keys. - */ -mxKeyHandler.prototype.controlKeys = null; - -/** - * Variable: controlShiftKeys - * - * Maps from keycodes to functions for pressed control and shift keys. - */ -mxKeyHandler.prototype.controlShiftKeys = null; - -/** - * Variable: enabled - * - * Specifies if events are handled. Default is true. - */ -mxKeyHandler.prototype.enabled = true; - -/** - * Function: isEnabled - * - * Returns true if events are handled. This implementation returns - * <enabled>. - */ -mxKeyHandler.prototype.isEnabled = function() -{ - return this.enabled; -}; - -/** - * Function: setEnabled - * - * Enables or disables event handling by updating <enabled>. - * - * Parameters: - * - * enabled - Boolean that specifies the new enabled state. - */ -mxKeyHandler.prototype.setEnabled = function(enabled) -{ - this.enabled = enabled; -}; - -/** - * Function: bindKey - * - * Binds the specified keycode to the given function. This binding is used - * if the control key is not pressed. - * - * Parameters: - * - * code - Integer that specifies the keycode. - * funct - JavaScript function that takes the key event as an argument. - */ -mxKeyHandler.prototype.bindKey = function(code, funct) -{ - this.normalKeys[code] = funct; -}; - -/** - * Function: bindShiftKey - * - * Binds the specified keycode to the given function. This binding is used - * if the shift key is pressed. - * - * Parameters: - * - * code - Integer that specifies the keycode. - * funct - JavaScript function that takes the key event as an argument. - */ -mxKeyHandler.prototype.bindShiftKey = function(code, funct) -{ - this.shiftKeys[code] = funct; -}; - -/** - * Function: bindControlKey - * - * Binds the specified keycode to the given function. This binding is used - * if the control key is pressed. - * - * Parameters: - * - * code - Integer that specifies the keycode. - * funct - JavaScript function that takes the key event as an argument. - */ -mxKeyHandler.prototype.bindControlKey = function(code, funct) -{ - this.controlKeys[code] = funct; -}; - -/** - * Function: bindControlShiftKey - * - * Binds the specified keycode to the given function. This binding is used - * if the control and shift key are pressed. - * - * Parameters: - * - * code - Integer that specifies the keycode. - * funct - JavaScript function that takes the key event as an argument. - */ -mxKeyHandler.prototype.bindControlShiftKey = function(code, funct) -{ - this.controlShiftKeys[code] = funct; -}; - -/** - * Function: isControlDown - * - * Returns true if the control key is pressed. This uses <mxEvent.isControlDown>. - * - * Parameters: - * - * evt - Key event whose control key pressed state should be returned. - */ -mxKeyHandler.prototype.isControlDown = function(evt) -{ - return mxEvent.isControlDown(evt); -}; - -/** - * Function: getFunction - * - * Returns the function associated with the given key event or null if no - * function is associated with the given event. - * - * Parameters: - * - * evt - Key event whose associated function should be returned. - */ -mxKeyHandler.prototype.getFunction = function(evt) -{ - if (evt != null) - { - if (this.isControlDown(evt)) - { - if (mxEvent.isShiftDown(evt)) - { - return this.controlShiftKeys[evt.keyCode]; - } - else - { - return this.controlKeys[evt.keyCode]; - } - } - else - { - if (mxEvent.isShiftDown(evt)) - { - return this.shiftKeys[evt.keyCode]; - } - else - { - return this.normalKeys[evt.keyCode]; - } - } - } - - return null; -}; - -/** - * Function: isGraphEvent - * - * Returns true if the event should be processed by this handler, that is, - * if the event source is either the target, one of its direct children, a - * descendant of the <mxGraph.container>, or the <mxGraph.cellEditor> of the - * <graph>. - * - * Parameters: - * - * evt - Key event that represents the keystroke. - */ -mxKeyHandler.prototype.isGraphEvent = function(evt) -{ - var source = mxEvent.getSource(evt); - - // Accepts events from the target object or - // in-place editing inside graph - if ((source == this.target || source.parentNode == this.target) || - (this.graph.cellEditor != null && source == this.graph.cellEditor.textarea)) - { - return true; - } - - // Accepts events from inside the container - var elt = source; - - while (elt != null) - { - if (elt == this.graph.container) - { - return true; - } - - elt = elt.parentNode; - } - - return false; -}; - -/** - * Function: keyDown - * - * Handles the event by invoking the function bound to the respective - * keystroke if <mxGraph.isEnabled>, <isEnabled> and <isGraphEvent> all - * return true for the given event and <mxGraph.isEditing> returns false. - * If the graph is editing only the <enter> and <escape> cases are handled - * by calling the respective hooks. - * - * Parameters: - * - * evt - Key event that represents the keystroke. - */ -mxKeyHandler.prototype.keyDown = function(evt) -{ - if (this.graph.isEnabled() && !mxEvent.isConsumed(evt) && - this.isGraphEvent(evt) && this.isEnabled()) - { - // Cancels the editing if escape is pressed - if (evt.keyCode == 27 /* Escape */) - { - this.escape(evt); - } - - // Invokes the function for the keystroke - else if (!this.graph.isEditing()) - { - var boundFunction = this.getFunction(evt); - - if (boundFunction != null) - { - boundFunction(evt); - mxEvent.consume(evt); - } - } - } -}; - -/** - * Function: escape - * - * Hook to process ESCAPE keystrokes. This implementation invokes - * <mxGraph.stopEditing> to cancel the current editing, connecting - * and/or other ongoing modifications. - * - * Parameters: - * - * evt - Key event that represents the keystroke. Possible keycode in this - * case is 27 (ESCAPE). - */ -mxKeyHandler.prototype.escape = function(evt) -{ - if (this.graph.isEscapeEnabled()) - { - this.graph.escape(evt); - } -}; - -/** - * Function: destroy - * - * Destroys the handler and all its references into the DOM. This does - * normally not need to be called, it is called automatically when the - * window unloads (in IE). - */ -mxKeyHandler.prototype.destroy = function() -{ - this.target = null; -}; diff --git a/src/js/handler/mxPanningHandler.js b/src/js/handler/mxPanningHandler.js deleted file mode 100644 index b388144..0000000 --- a/src/js/handler/mxPanningHandler.js +++ /dev/null @@ -1,390 +0,0 @@ -/** - * $Id: mxPanningHandler.js,v 1.79 2012-07-17 14:37:41 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -/** - * Class: mxPanningHandler - * - * Event handler that pans and creates popupmenus. To use the left - * mousebutton for panning without interfering with cell moving and - * resizing, use <isUseLeftButton> and <isIgnoreCell>. For grid size - * steps while panning, use <useGrid>. This handler is built-into - * <mxGraph.panningHandler> and enabled using <mxGraph.setPanning>. - * - * Constructor: mxPanningHandler - * - * Constructs an event handler that creates a <mxPopupMenu> - * and pans the graph. - * - * Event: mxEvent.PAN_START - * - * Fires when the panning handler changes its <active> state to true. The - * <code>event</code> property contains the corresponding <mxMouseEvent>. - * - * Event: mxEvent.PAN - * - * Fires while handle is processing events. The <code>event</code> property contains - * the corresponding <mxMouseEvent>. - * - * Event: mxEvent.PAN_END - * - * Fires when the panning handler changes its <active> state to false. The - * <code>event</code> property contains the corresponding <mxMouseEvent>. - */ -function mxPanningHandler(graph, factoryMethod) -{ - if (graph != null) - { - this.graph = graph; - this.factoryMethod = factoryMethod; - this.graph.addMouseListener(this); - this.init(); - } -}; - -/** - * Extends mxPopupMenu. - */ -mxPanningHandler.prototype = new mxPopupMenu(); -mxPanningHandler.prototype.constructor = mxPanningHandler; - -/** - * Variable: graph - * - * Reference to the enclosing <mxGraph>. - */ -mxPanningHandler.prototype.graph = null; - -/** - * Variable: usePopupTrigger - * - * Specifies if the <isPopupTrigger> should also be used for panning. To - * avoid conflicts, the panning is only activated if the mouse was moved - * more than <mxGraph.tolerance>, otherwise, a single click is assumed - * and the popupmenu is displayed. Default is true. - */ -mxPanningHandler.prototype.usePopupTrigger = true; - -/** - * Variable: useLeftButtonForPanning - * - * Specifies if panning should be active for the left mouse button. - * Setting this to true may conflict with <mxRubberband>. Default is false. - */ -mxPanningHandler.prototype.useLeftButtonForPanning = false; - -/** - * Variable: selectOnPopup - * - * Specifies if cells should be selected if a popupmenu is displayed for - * them. Default is true. - */ -mxPanningHandler.prototype.selectOnPopup = true; - -/** - * Variable: clearSelectionOnBackground - * - * Specifies if cells should be deselected if a popupmenu is displayed for - * the diagram background. Default is true. - */ -mxPanningHandler.prototype.clearSelectionOnBackground = true; - -/** - * Variable: ignoreCell - * - * Specifies if panning should be active even if there is a cell under the - * mousepointer. Default is false. - */ -mxPanningHandler.prototype.ignoreCell = false; - -/** - * Variable: previewEnabled - * - * Specifies if the panning should be previewed. Default is true. - */ -mxPanningHandler.prototype.previewEnabled = true; - -/** - * Variable: useGrid - * - * Specifies if the panning steps should be aligned to the grid size. - * Default is false. - */ -mxPanningHandler.prototype.useGrid = false; - -/** - * Variable: panningEnabled - * - * Specifies if panning should be enabled. Default is true. - */ -mxPanningHandler.prototype.panningEnabled = true; - -/** - * Function: isPanningEnabled - * - * Returns <panningEnabled>. - */ -mxPanningHandler.prototype.isPanningEnabled = function() -{ - return this.panningEnabled; -}; - -/** - * Function: setPanningEnabled - * - * Sets <panningEnabled>. - */ -mxPanningHandler.prototype.setPanningEnabled = function(value) -{ - this.panningEnabled = value; -}; - -/** - * Function: init - * - * Initializes the shapes required for this vertex handler. - */ -mxPanningHandler.prototype.init = function() -{ - // Supercall - mxPopupMenu.prototype.init.apply(this); - - // Hides the tooltip if the mouse is over - // the context menu - mxEvent.addListener(this.div, (mxClient.IS_TOUCH) ? 'touchmove' : 'mousemove', - mxUtils.bind(this, function(evt) - { - this.graph.tooltipHandler.hide(); - }) - ); -}; - -/** - * Function: isPanningTrigger - * - * Returns true if the given event is a panning trigger for the optional - * given cell. This returns true if control-shift is pressed or if - * <usePopupTrigger> is true and the event is a popup trigger. - */ -mxPanningHandler.prototype.isPanningTrigger = function(me) -{ - var evt = me.getEvent(); - - return (this.useLeftButtonForPanning && (this.ignoreCell || me.getState() == null) && - mxEvent.isLeftMouseButton(evt)) || (mxEvent.isControlDown(evt) && - mxEvent.isShiftDown(evt)) || (this.usePopupTrigger && - mxEvent.isPopupTrigger(evt)); -}; - -/** - * Function: mouseDown - * - * Handles the event by initiating the panning. By consuming the event all - * subsequent events of the gesture are redirected to this handler. - */ -mxPanningHandler.prototype.mouseDown = function(sender, me) -{ - if (!me.isConsumed() && this.isEnabled()) - { - // Hides the popupmenu if is is being displayed - this.hideMenu(); - - this.dx0 = -this.graph.container.scrollLeft; - this.dy0 = -this.graph.container.scrollTop; - - // Checks the event triggers to panning and popupmenu - this.popupTrigger = this.isPopupTrigger(me); - this.panningTrigger = this.isPanningEnabled() && - this.isPanningTrigger(me); - - // Stores the location of the trigger event - this.startX = me.getX(); - this.startY = me.getY(); - - // Displays popup menu on Mac after the mouse was released - if (this.panningTrigger) - { - this.consumePanningTrigger(me); - } - } -}; - -/** - * Function: consumePanningTrigger - * - * Consumes the given <mxMouseEvent> if it was a panning trigger in - * <mouseDown>. The default is to invoke <mxMouseEvent.consume>. Note that this - * will block any further event processing. If you haven't disabled built-in - * context menus and require immediate selection of the cell on mouseDown in - * Safari and/or on the Mac, then use the following code: - * - * (code) - * mxPanningHandler.prototype.consumePanningTrigger = function(me) - * { - * if (me.evt.preventDefault) - * { - * me.evt.preventDefault(); - * } - * - * // Stops event processing in IE - * me.evt.returnValue = false; - * - * // Sets local consumed state - * if (!mxClient.IS_SF && !mxClient.IS_MAC) - * { - * me.consumed = true; - * } - * }; - * (end) - */ -mxPanningHandler.prototype.consumePanningTrigger = function(me) -{ - me.consume(); -}; - -/** - * Function: mouseMove - * - * Handles the event by updating the panning on the graph. - */ -mxPanningHandler.prototype.mouseMove = function(sender, me) -{ - var dx = me.getX() - this.startX; - var dy = me.getY() - this.startY; - - if (this.active) - { - if (this.previewEnabled) - { - // Applies the grid to the panning steps - if (this.useGrid) - { - dx = this.graph.snap(dx); - dy = this.graph.snap(dy); - } - - this.graph.panGraph(dx + this.dx0, dy + this.dy0); - } - - this.fireEvent(new mxEventObject(mxEvent.PAN, 'event', me)); - me.consume(); - } - else if (this.panningTrigger) - { - var tmp = this.active; - - // Panning is activated only if the mouse is moved - // beyond the graph tolerance - this.active = Math.abs(dx) > this.graph.tolerance || - Math.abs(dy) > this.graph.tolerance; - - if (!tmp && this.active) - { - this.fireEvent(new mxEventObject(mxEvent.PAN_START, 'event', me)); - } - } -}; - -/** - * Function: mouseUp - * - * Handles the event by setting the translation on the view or showing the - * popupmenu. - */ -mxPanningHandler.prototype.mouseUp = function(sender, me) -{ - // Shows popup menu if mouse was not moved - var dx = Math.abs(me.getX() - this.startX); - var dy = Math.abs(me.getY() - this.startY); - - if (this.active) - { - if (!this.graph.useScrollbarsForPanning || !mxUtils.hasScrollbars(this.graph.container)) - { - dx = me.getX() - this.startX; - dy = me.getY() - this.startY; - - // Applies the grid to the panning steps - if (this.useGrid) - { - dx = this.graph.snap(dx); - dy = this.graph.snap(dy); - } - - var scale = this.graph.getView().scale; - var t = this.graph.getView().translate; - - this.graph.panGraph(0, 0); - this.panGraph(t.x + dx / scale, t.y + dy / scale); - } - - this.active = false; - this.fireEvent(new mxEventObject(mxEvent.PAN_END, 'event', me)); - me.consume(); - } - else if (this.popupTrigger) - { - if (dx < this.graph.tolerance && dy < this.graph.tolerance) - { - var cell = this.getCellForPopupEvent(me); - - // Selects the cell for which the context menu is being displayed - if (this.graph.isEnabled() && this.selectOnPopup && - cell != null && !this.graph.isCellSelected(cell)) - { - this.graph.setSelectionCell(cell); - } - else if (this.clearSelectionOnBackground && cell == null) - { - this.graph.clearSelection(); - } - - // Hides the tooltip if there is one - this.graph.tooltipHandler.hide(); - var origin = mxUtils.getScrollOrigin(); - var point = new mxPoint(me.getX() + origin.x, - me.getY() + origin.y); - - // Menu is shifted by 1 pixel so that the mouse up event - // is routed via the underlying shape instead of the DIV - this.popup(point.x + 1, point.y + 1, cell, me.getEvent()); - me.consume(); - } - } - - this.panningTrigger = false; - this.popupTrigger = false; -}; - -/** - * Function: getCellForPopupEvent - * - * Hook to return the cell for the mouse up popup trigger handling. - */ -mxPanningHandler.prototype.getCellForPopupEvent = function(me) -{ - return me.getCell(); -}; - -/** - * Function: panGraph - * - * Pans <graph> by the given amount. - */ -mxPanningHandler.prototype.panGraph = function(dx, dy) -{ - this.graph.getView().setTranslate(dx, dy); -}; - -/** - * Function: destroy - * - * Destroys the handler and all its resources and DOM nodes. - */ -mxPanningHandler.prototype.destroy = function() -{ - this.graph.removeMouseListener(this); - - // Supercall - mxPopupMenu.prototype.destroy.apply(this); -}; diff --git a/src/js/handler/mxRubberband.js b/src/js/handler/mxRubberband.js deleted file mode 100644 index f9e7187..0000000 --- a/src/js/handler/mxRubberband.js +++ /dev/null @@ -1,348 +0,0 @@ -/** - * $Id: mxRubberband.js,v 1.48 2012-04-13 12:53:30 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -/** - * Class: mxRubberband - * - * Event handler that selects rectangular regions. This is not built-into - * <mxGraph>. To enable rubberband selection in a graph, use the following code. - * - * Example: - * - * (code) - * var rubberband = new mxRubberband(graph); - * (end) - * - * Constructor: mxRubberband - * - * Constructs an event handler that selects rectangular regions in the graph - * using rubberband selection. - */ -function mxRubberband(graph) -{ - if (graph != null) - { - this.graph = graph; - this.graph.addMouseListener(this); - - // Repaints the marquee after autoscroll - this.panHandler = mxUtils.bind(this, function() - { - this.repaint(); - }); - - this.graph.addListener(mxEvent.PAN, this.panHandler); - - // Automatic deallocation of memory - if (mxClient.IS_IE) - { - mxEvent.addListener(window, 'unload', - mxUtils.bind(this, function() - { - this.destroy(); - }) - ); - } - } -}; - -/** - * Variable: defaultOpacity - * - * Specifies the default opacity to be used for the rubberband div. Default - * is 20. - */ -mxRubberband.prototype.defaultOpacity = 20; - -/** - * Variable: enabled - * - * Specifies if events are handled. Default is true. - */ -mxRubberband.prototype.enabled = true; - -/** - * Variable: div - * - * Holds the DIV element which is currently visible. - */ -mxRubberband.prototype.div = null; - -/** - * Variable: sharedDiv - * - * Holds the DIV element which is used to display the rubberband. - */ -mxRubberband.prototype.sharedDiv = null; - -/** - * Variable: currentX - * - * Holds the value of the x argument in the last call to <update>. - */ -mxRubberband.prototype.currentX = 0; - -/** - * Variable: currentY - * - * Holds the value of the y argument in the last call to <update>. - */ -mxRubberband.prototype.currentY = 0; - -/** - * Function: isEnabled - * - * Returns true if events are handled. This implementation returns - * <enabled>. - */ -mxRubberband.prototype.isEnabled = function() -{ - return this.enabled; -}; - -/** - * Function: setEnabled - * - * Enables or disables event handling. This implementation updates - * <enabled>. - */ -mxRubberband.prototype.setEnabled = function(enabled) -{ - this.enabled = enabled; -}; - -/** - * Function: mouseDown - * - * Handles the event by initiating a rubberband selection. By consuming the - * event all subsequent events of the gesture are redirected to this - * handler. - */ -mxRubberband.prototype.mouseDown = function(sender, me) -{ - if (!me.isConsumed() && this.isEnabled() && this.graph.isEnabled() && - (this.graph.isForceMarqueeEvent(me.getEvent()) || me.getState() == null)) - { - var offset = mxUtils.getOffset(this.graph.container); - var origin = mxUtils.getScrollOrigin(this.graph.container); - origin.x -= offset.x; - origin.y -= offset.y; - this.start(me.getX() + origin.x, me.getY() + origin.y); - - // Workaround for rubberband stopping if the mouse leaves the - // graph container in Firefox. - if (mxClient.IS_NS && !mxClient.IS_SF && !mxClient.IS_GC) - { - var container = this.graph.container; - - function createMouseEvent(evt) - { - var me = new mxMouseEvent(evt); - var pt = mxUtils.convertPoint(container, me.getX(), me.getY()); - - me.graphX = pt.x; - me.graphY = pt.y; - - return me; - }; - - this.dragHandler = mxUtils.bind(this, function(evt) - { - this.mouseMove(this.graph, createMouseEvent(evt)); - }); - - this.dropHandler = mxUtils.bind(this, function(evt) - { - this.mouseUp(this.graph, createMouseEvent(evt)); - }); - - mxEvent.addListener(document, 'mousemove', this.dragHandler); - mxEvent.addListener(document, 'mouseup', this.dropHandler); - } - - // Does not prevent the default for this event so that the - // event processing chain is still executed even if we start - // rubberbanding. This is required eg. in ExtJs to hide the - // current context menu. In mouseMove we'll make sure we're - // not selecting anything while we're rubberbanding. - me.consume(false); - } -}; - -/** - * Function: start - * - * Sets the start point for the rubberband selection. - */ -mxRubberband.prototype.start = function(x, y) -{ - this.first = new mxPoint(x, y); -}; - -/** - * Function: mouseMove - * - * Handles the event by updating therubberband selection. - */ -mxRubberband.prototype.mouseMove = function(sender, me) -{ - if (!me.isConsumed() && this.first != null) - { - var origin = mxUtils.getScrollOrigin(this.graph.container); - var offset = mxUtils.getOffset(this.graph.container); - origin.x -= offset.x; - origin.y -= offset.y; - var x = me.getX() + origin.x; - var y = me.getY() + origin.y; - var dx = this.first.x - x; - var dy = this.first.y - y; - var tol = this.graph.tolerance; - - if (this.div != null || Math.abs(dx) > tol || Math.abs(dy) > tol) - { - if (this.div == null) - { - this.div = this.createShape(); - } - - // Clears selection while rubberbanding. This is required because - // the event is not consumed in mouseDown. - mxUtils.clearSelection(); - - this.update(x, y); - me.consume(); - } - } -}; - -/** - * Function: createShape - * - * Creates the rubberband selection shape. - */ -mxRubberband.prototype.createShape = function() -{ - if (this.sharedDiv == null) - { - this.sharedDiv = document.createElement('div'); - this.sharedDiv.className = 'mxRubberband'; - mxUtils.setOpacity(this.sharedDiv, this.defaultOpacity); - } - - this.graph.container.appendChild(this.sharedDiv); - - return this.sharedDiv; -}; - -/** - * Function: mouseUp - * - * Handles the event by selecting the region of the rubberband using - * <mxGraph.selectRegion>. - */ -mxRubberband.prototype.mouseUp = function(sender, me) -{ - var execute = this.div != null; - this.reset(); - - if (execute) - { - var rect = new mxRectangle(this.x, this.y, this.width, this.height); - this.graph.selectRegion(rect, me.getEvent()); - me.consume(); - } -}; - -/** - * Function: reset - * - * Resets the state of the rubberband selection. - */ -mxRubberband.prototype.reset = function() -{ - if (this.div != null) - { - this.div.parentNode.removeChild(this.div); - } - - if (this.dragHandler != null) - { - mxEvent.removeListener(document, 'mousemove', this.dragHandler); - this.dragHandler = null; - } - - if (this.dropHandler != null) - { - mxEvent.removeListener(document, 'mouseup', this.dropHandler); - this.dropHandler = null; - } - - this.currentX = 0; - this.currentY = 0; - this.first = null; - this.div = null; -}; - -/** - * Function: update - * - * Sets <currentX> and <currentY> and calls <repaint>. - */ -mxRubberband.prototype.update = function(x, y) -{ - this.currentX = x; - this.currentY = y; - - this.repaint(); -}; - -/** - * Function: repaint - * - * Computes the bounding box and updates the style of the <div>. - */ -mxRubberband.prototype.repaint = function() -{ - if (this.div != null) - { - var x = this.currentX - this.graph.panDx; - var y = this.currentY - this.graph.panDy; - - this.x = Math.min(this.first.x, x); - this.y = Math.min(this.first.y, y); - this.width = Math.max(this.first.x, x) - this.x; - this.height = Math.max(this.first.y, y) - this.y; - - var dx = (mxClient.IS_VML) ? this.graph.panDx : 0; - var dy = (mxClient.IS_VML) ? this.graph.panDy : 0; - - this.div.style.left = (this.x + dx) + 'px'; - this.div.style.top = (this.y + dy) + 'px'; - this.div.style.width = Math.max(1, this.width) + 'px'; - this.div.style.height = Math.max(1, this.height) + 'px'; - } -}; - -/** - * Function: destroy - * - * Destroys the handler and all its resources and DOM nodes. This does - * normally not need to be called, it is called automatically when the - * window unloads. - */ -mxRubberband.prototype.destroy = function() -{ - if (!this.destroyed) - { - this.destroyed = true; - this.graph.removeMouseListener(this); - this.graph.removeListener(this.panHandler); - this.reset(); - - if (this.sharedDiv != null) - { - this.sharedDiv = null; - } - } -}; diff --git a/src/js/handler/mxSelectionCellsHandler.js b/src/js/handler/mxSelectionCellsHandler.js deleted file mode 100644 index 800d718..0000000 --- a/src/js/handler/mxSelectionCellsHandler.js +++ /dev/null @@ -1,260 +0,0 @@ -/** - * $Id: mxSelectionCellsHandler.js,v 1.5 2012-08-10 11:35:06 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -/** - * Class: mxSelectionCellsHandler - * - * An event handler that manages cell handlers and invokes their mouse event - * processing functions. - * - * Group: Events - * - * Event: mxEvent.ADD - * - * Fires if a cell has been added to the selection. The <code>state</code> - * property contains the <mxCellState> that has been added. - * - * Event: mxEvent.REMOVE - * - * Fires if a cell has been remove from the selection. The <code>state</code> - * property contains the <mxCellState> that has been removed. - * - * Parameters: - * - * graph - Reference to the enclosing <mxGraph>. - */ -function mxSelectionCellsHandler(graph) -{ - this.graph = graph; - this.handlers = new mxDictionary(); - this.graph.addMouseListener(this); - - this.refreshHandler = mxUtils.bind(this, function(sender, evt) - { - if (this.isEnabled()) - { - this.refresh(); - } - }); - - this.graph.getSelectionModel().addListener(mxEvent.CHANGE, this.refreshHandler); - this.graph.getModel().addListener(mxEvent.CHANGE, this.refreshHandler); - this.graph.getView().addListener(mxEvent.SCALE, this.refreshHandler); - this.graph.getView().addListener(mxEvent.TRANSLATE, this.refreshHandler); - this.graph.getView().addListener(mxEvent.SCALE_AND_TRANSLATE, this.refreshHandler); - this.graph.getView().addListener(mxEvent.DOWN, this.refreshHandler); - this.graph.getView().addListener(mxEvent.UP, this.refreshHandler); -}; - -/** - * Extends mxEventSource. - */ -mxSelectionCellsHandler.prototype = new mxEventSource(); -mxSelectionCellsHandler.prototype.constructor = mxSelectionCellsHandler; - -/** - * Variable: graph - * - * Reference to the enclosing <mxGraph>. - */ -mxSelectionCellsHandler.prototype.graph = null; - -/** - * Variable: enabled - * - * Specifies if events are handled. Default is true. - */ -mxSelectionCellsHandler.prototype.enabled = true; - -/** - * Variable: refreshHandler - * - * Keeps a reference to an event listener for later removal. - */ -mxSelectionCellsHandler.prototype.refreshHandler = null; - -/** - * Variable: maxHandlers - * - * Defines the maximum number of handlers to paint individually. Default is 100. - */ -mxSelectionCellsHandler.prototype.maxHandlers = 100; - -/** - * Variable: handlers - * - * <mxDictionary> that maps from cells to handlers. - */ -mxSelectionCellsHandler.prototype.handlers = null; - -/** - * Function: isEnabled - * - * Returns <enabled>. - */ -mxSelectionCellsHandler.prototype.isEnabled = function() -{ - return this.enabled; -}; - -/** - * Function: setEnabled - * - * Sets <enabled>. - */ -mxSelectionCellsHandler.prototype.setEnabled = function(value) -{ - this.enabled = value; -}; - -/** - * Function: getHandler - * - * Returns the handler for the given cell. - */ -mxSelectionCellsHandler.prototype.getHandler = function(cell) -{ - return this.handlers.get(cell); -}; - -/** - * Function: reset - * - * Resets all handlers. - */ -mxSelectionCellsHandler.prototype.reset = function() -{ - this.handlers.visit(function(key, handler) - { - handler.reset.apply(handler); - }); -}; - -/** - * Function: refresh - * - * Reloads or updates all handlers. - */ -mxSelectionCellsHandler.prototype.refresh = function() -{ - // Removes all existing handlers - var oldHandlers = this.handlers; - this.handlers = new mxDictionary(); - - // Creates handles for all selection cells - var tmp = this.graph.getSelectionCells(); - - for (var i = 0; i < tmp.length; i++) - { - var state = this.graph.view.getState(tmp[i]); - - if (state != null) - { - var handler = oldHandlers.remove(tmp[i]); - - if (handler != null) - { - if (handler.state != state) - { - handler.destroy(); - handler = null; - } - else - { - handler.redraw(); - } - } - - if (handler == null) - { - handler = this.graph.createHandler(state); - this.fireEvent(new mxEventObject(mxEvent.ADD, 'state', state)); - } - - if (handler != null) - { - this.handlers.put(tmp[i], handler); - } - } - } - - // Destroys all unused handlers - oldHandlers.visit(mxUtils.bind(this, function(key, handler) - { - this.fireEvent(new mxEventObject(mxEvent.REMOVE, 'state', handler.state)); - handler.destroy(); - })); -}; - -/** - * Function: mouseDown - * - * Redirects the given event to the handlers. - */ -mxSelectionCellsHandler.prototype.mouseDown = function(sender, me) -{ - if (this.graph.isEnabled() && this.isEnabled()) - { - var args = [sender, me]; - - this.handlers.visit(function(key, handler) - { - handler.mouseDown.apply(handler, args); - }); - } -}; - -/** - * Function: mouseMove - * - * Redirects the given event to the handlers. - */ -mxSelectionCellsHandler.prototype.mouseMove = function(sender, me) -{ - if (this.graph.isEnabled() && this.isEnabled()) - { - var args = [sender, me]; - - this.handlers.visit(function(key, handler) - { - handler.mouseMove.apply(handler, args); - }); - } -}; - -/** - * Function: mouseUp - * - * Redirects the given event to the handlers. - */ -mxSelectionCellsHandler.prototype.mouseUp = function(sender, me) -{ - if (this.graph.isEnabled() && this.isEnabled()) - { - var args = [sender, me]; - - this.handlers.visit(function(key, handler) - { - handler.mouseUp.apply(handler, args); - }); - } -}; - -/** - * Function: destroy - * - * Destroys the handler and all its resources and DOM nodes. - */ -mxSelectionCellsHandler.prototype.destroy = function() -{ - this.graph.removeMouseListener(this); - - if (this.refreshHandler != null) - { - this.graph.getSelectionModel().removeListener(this.refreshHandler); - this.graph.getModel().removeListener(this.refreshHandler); - this.graph.getView().removeListener(this.refreshHandler); - this.refreshHandler = null; - } -}; diff --git a/src/js/handler/mxTooltipHandler.js b/src/js/handler/mxTooltipHandler.js deleted file mode 100644 index 4e34a13..0000000 --- a/src/js/handler/mxTooltipHandler.js +++ /dev/null @@ -1,317 +0,0 @@ -/** - * $Id: mxTooltipHandler.js,v 1.51 2011-03-31 10:11:17 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -/** - * Class: mxTooltipHandler - * - * Graph event handler that displays tooltips. <mxGraph.getTooltip> is used to - * get the tooltip for a cell or handle. This handler is built-into - * <mxGraph.tooltipHandler> and enabled using <mxGraph.setTooltips>. - * - * Example: - * - * (code> - * new mxTooltipHandler(graph); - * (end) - * - * Constructor: mxTooltipHandler - * - * Constructs an event handler that displays tooltips with the specified - * delay (in milliseconds). If no delay is specified then a default delay - * of 500 ms (0.5 sec) is used. - * - * Parameters: - * - * graph - Reference to the enclosing <mxGraph>. - * delay - Optional delay in milliseconds. - */ -function mxTooltipHandler(graph, delay) -{ - if (graph != null) - { - this.graph = graph; - this.delay = delay || 500; - this.graph.addMouseListener(this); - } -}; - -/** - * Variable: zIndex - * - * Specifies the zIndex for the tooltip and its shadow. Default is 10005. - */ -mxTooltipHandler.prototype.zIndex = 10005; - -/** - * Variable: graph - * - * Reference to the enclosing <mxGraph>. - */ -mxTooltipHandler.prototype.graph = null; - -/** - * Variable: delay - * - * Delay to show the tooltip in milliseconds. Default is 500. - */ -mxTooltipHandler.prototype.delay = null; - -/** - * Variable: hideOnHover - * - * Specifies if the tooltip should be hidden if the mouse is moved over the - * current cell. Default is false. - */ -mxTooltipHandler.prototype.hideOnHover = false; - -/** - * Variable: enabled - * - * Specifies if events are handled. Default is true. - */ -mxTooltipHandler.prototype.enabled = true; - -/** - * Function: isEnabled - * - * Returns true if events are handled. This implementation - * returns <enabled>. - */ -mxTooltipHandler.prototype.isEnabled = function() -{ - return this.enabled; -}; - -/** - * Function: setEnabled - * - * Enables or disables event handling. This implementation - * updates <enabled>. - */ -mxTooltipHandler.prototype.setEnabled = function(enabled) -{ - this.enabled = enabled; -}; - -/** - * Function: isHideOnHover - * - * Returns <hideOnHover>. - */ -mxTooltipHandler.prototype.isHideOnHover = function() -{ - return this.hideOnHover; -}; - -/** - * Function: setHideOnHover - * - * Sets <hideOnHover>. - */ -mxTooltipHandler.prototype.setHideOnHover = function(value) -{ - this.hideOnHover = value; -}; - -/** - * Function: init - * - * Initializes the DOM nodes required for this tooltip handler. - */ -mxTooltipHandler.prototype.init = function() -{ - if (document.body != null) - { - this.div = document.createElement('div'); - this.div.className = 'mxTooltip'; - this.div.style.visibility = 'hidden'; - this.div.style.zIndex = this.zIndex; - - document.body.appendChild(this.div); - - mxEvent.addListener(this.div, 'mousedown', - mxUtils.bind(this, function(evt) - { - this.hideTooltip(); - }) - ); - } -}; - -/** - * Function: mouseDown - * - * Handles the event by initiating a rubberband selection. By consuming the - * event all subsequent events of the gesture are redirected to this - * handler. - */ -mxTooltipHandler.prototype.mouseDown = function(sender, me) -{ - this.reset(me, false); - this.hideTooltip(); -}; - -/** - * Function: mouseMove - * - * Handles the event by updating the rubberband selection. - */ -mxTooltipHandler.prototype.mouseMove = function(sender, me) -{ - if (me.getX() != this.lastX || me.getY() != this.lastY) - { - this.reset(me, true); - - if (this.isHideOnHover() || me.getState() != this.state || (me.getSource() != this.node && - (!this.stateSource || (me.getState() != null && this.stateSource == - (me.isSource(me.getState().shape) || !me.isSource(me.getState().text)))))) - { - this.hideTooltip(); - } - } - - this.lastX = me.getX(); - this.lastY = me.getY(); -}; - -/** - * Function: mouseUp - * - * Handles the event by resetting the tooltip timer or hiding the existing - * tooltip. - */ -mxTooltipHandler.prototype.mouseUp = function(sender, me) -{ - this.reset(me, true); - this.hideTooltip(); -}; - - -/** - * Function: resetTimer - * - * Resets the timer. - */ -mxTooltipHandler.prototype.resetTimer = function() -{ - if (this.thread != null) - { - window.clearTimeout(this.thread); - this.thread = null; - } -}; - -/** - * Function: reset - * - * Resets and/or restarts the timer to trigger the display of the tooltip. - */ -mxTooltipHandler.prototype.reset = function(me, restart) -{ - this.resetTimer(); - - if (restart && this.isEnabled() && me.getState() != null && (this.div == null || - this.div.style.visibility == 'hidden')) - { - var state = me.getState(); - var node = me.getSource(); - var x = me.getX(); - var y = me.getY(); - var stateSource = me.isSource(state.shape) || me.isSource(state.text); - - this.thread = window.setTimeout(mxUtils.bind(this, function() - { - if (!this.graph.isEditing() && !this.graph.panningHandler.isMenuShowing()) - { - // Uses information from inside event cause using the event at - // this (delayed) point in time is not possible in IE as it no - // longer contains the required information (member not found) - var tip = this.graph.getTooltip(state, node, x, y); - this.show(tip, x, y); - this.state = state; - this.node = node; - this.stateSource = stateSource; - } - }), this.delay); - } -}; - -/** - * Function: hide - * - * Hides the tooltip and resets the timer. - */ -mxTooltipHandler.prototype.hide = function() -{ - this.resetTimer(); - this.hideTooltip(); -}; - -/** - * Function: hideTooltip - * - * Hides the tooltip. - */ -mxTooltipHandler.prototype.hideTooltip = function() -{ - if (this.div != null) - { - this.div.style.visibility = 'hidden'; - } -}; - -/** - * Function: show - * - * Shows the tooltip for the specified cell and optional index at the - * specified location (with a vertical offset of 10 pixels). - */ -mxTooltipHandler.prototype.show = function(tip, x, y) -{ - if (tip != null && tip.length > 0) - { - // Initializes the DOM nodes if required - if (this.div == null) - { - this.init(); - } - - var origin = mxUtils.getScrollOrigin(); - - this.div.style.left = (x + origin.x) + 'px'; - this.div.style.top = (y + mxConstants.TOOLTIP_VERTICAL_OFFSET + - origin.y) + 'px'; - - if (!mxUtils.isNode(tip)) - { - this.div.innerHTML = tip.replace(/\n/g, '<br>'); - } - else - { - this.div.innerHTML = ''; - this.div.appendChild(tip); - } - - this.div.style.visibility = ''; - mxUtils.fit(this.div); - } -}; - -/** - * Function: destroy - * - * Destroys the handler and all its resources and DOM nodes. - */ -mxTooltipHandler.prototype.destroy = function() -{ - this.graph.removeMouseListener(this); - mxEvent.release(this.div); - - if (this.div != null && this.div.parentNode != null) - { - this.div.parentNode.removeChild(this.div); - } - - this.div = null; -}; diff --git a/src/js/handler/mxVertexHandler.js b/src/js/handler/mxVertexHandler.js deleted file mode 100644 index 0b12e27..0000000 --- a/src/js/handler/mxVertexHandler.js +++ /dev/null @@ -1,753 +0,0 @@ -/** - * $Id: mxVertexHandler.js,v 1.107 2012-11-20 09:06:07 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -/** - * Class: mxVertexHandler - * - * Event handler for resizing cells. This handler is automatically created in - * <mxGraph.createHandler>. - * - * Constructor: mxVertexHandler - * - * Constructs an event handler that allows to resize vertices - * and groups. - * - * Parameters: - * - * state - <mxCellState> of the cell to be resized. - */ -function mxVertexHandler(state) -{ - if (state != null) - { - this.state = state; - this.init(); - } -}; - -/** - * Variable: graph - * - * Reference to the enclosing <mxGraph>. - */ -mxVertexHandler.prototype.graph = null; - -/** - * Variable: state - * - * Reference to the <mxCellState> being modified. - */ -mxVertexHandler.prototype.state = null; - -/** - * Variable: singleSizer - * - * Specifies if only one sizer handle at the bottom, right corner should be - * used. Default is false. - */ -mxVertexHandler.prototype.singleSizer = false; - -/** - * Variable: index - * - * Holds the index of the current handle. - */ -mxVertexHandler.prototype.index = null; - -/** - * Variable: allowHandleBoundsCheck - * - * Specifies if the bounds of handles should be used for hit-detection in IE - * Default is true. - */ -mxVertexHandler.prototype.allowHandleBoundsCheck = true; - -/** - * Variable: crisp - * - * Specifies if the selection bounds and handles should be rendered in crisp - * mode. Default is true. - */ -mxVertexHandler.prototype.crisp = true; - -/** - * Variable: handleImage - * - * Optional <mxImage> to be used as handles. Default is null. - */ -mxVertexHandler.prototype.handleImage = null; - -/** - * Variable: tolerance - * - * Optional tolerance for hit-detection in <getHandleForEvent>. Default is 0. - */ -mxVertexHandler.prototype.tolerance = 0; - -/** - * Function: init - * - * Initializes the shapes required for this vertex handler. - */ -mxVertexHandler.prototype.init = function() -{ - this.graph = this.state.view.graph; - this.selectionBounds = this.getSelectionBounds(this.state); - this.bounds = new mxRectangle(this.selectionBounds.x, this.selectionBounds.y, - this.selectionBounds.width, this.selectionBounds.height); - this.selectionBorder = this.createSelectionShape(this.bounds); - this.selectionBorder.dialect = - (this.graph.dialect != mxConstants.DIALECT_SVG) ? - mxConstants.DIALECT_VML : mxConstants.DIALECT_SVG; - this.selectionBorder.init(this.graph.getView().getOverlayPane()); - - // Event-transparency - if (this.selectionBorder.dialect == mxConstants.DIALECT_SVG) - { - this.selectionBorder.node.setAttribute('pointer-events', 'none'); - } - else - { - this.selectionBorder.node.style.background = ''; - } - - if (this.graph.isCellMovable(this.state.cell)) - { - this.selectionBorder.node.style.cursor = mxConstants.CURSOR_MOVABLE_VERTEX; - } - - mxEvent.redirectMouseEvents(this.selectionBorder.node, this.graph, this.state); - - // Adds the sizer handles - if (mxGraphHandler.prototype.maxCells <= 0 || - this.graph.getSelectionCount() < mxGraphHandler.prototype.maxCells) - { - var resizable = this.graph.isCellResizable(this.state.cell); - this.sizers = []; - - if (resizable || (this.graph.isLabelMovable(this.state.cell) && - this.state.width >= 2 && this.state.height >= 2)) - { - var i = 0; - - if (resizable) - { - if (!this.singleSizer) - { - this.sizers.push(this.createSizer('nw-resize', i++)); - this.sizers.push(this.createSizer('n-resize', i++)); - this.sizers.push(this.createSizer('ne-resize', i++)); - this.sizers.push(this.createSizer('w-resize', i++)); - this.sizers.push(this.createSizer('e-resize', i++)); - this.sizers.push(this.createSizer('sw-resize', i++)); - this.sizers.push(this.createSizer('s-resize', i++)); - } - - this.sizers.push(this.createSizer('se-resize', i++)); - } - - var geo = this.graph.model.getGeometry(this.state.cell); - - if (geo != null && !geo.relative && !this.graph.isSwimlane(this.state.cell) && - this.graph.isLabelMovable(this.state.cell)) - { - // Marks this as the label handle for getHandleForEvent - this.labelShape = this.createSizer(mxConstants.CURSOR_LABEL_HANDLE, - mxEvent.LABEL_HANDLE, mxConstants.LABEL_HANDLE_SIZE, - mxConstants.LABEL_HANDLE_FILLCOLOR); - this.sizers.push(this.labelShape); - } - } - else if (this.graph.isCellMovable(this.state.cell) && !this.graph.isCellResizable(this.state.cell) && - this.state.width < 2 && this.state.height < 2) - { - this.labelShape = this.createSizer(mxConstants.CURSOR_MOVABLE_VERTEX, - null, null, mxConstants.LABEL_HANDLE_FILLCOLOR); - this.sizers.push(this.labelShape); - } - } - - this.redraw(); -}; - -/** - * Function: getSelectionBounds - * - * Returns the mxRectangle that defines the bounds of the selection - * border. - */ -mxVertexHandler.prototype.getSelectionBounds = function(state) -{ - return new mxRectangle(state.x, state.y, state.width, state.height); -}; - -/** - * Function: createSelectionShape - * - * Creates the shape used to draw the selection border. - */ -mxVertexHandler.prototype.createSelectionShape = function(bounds) -{ - var shape = new mxRectangleShape(bounds, null, this.getSelectionColor()); - shape.strokewidth = this.getSelectionStrokeWidth(); - shape.isDashed = this.isSelectionDashed(); - shape.crisp = this.crisp; - - return shape; -}; - -/** - * Function: getSelectionColor - * - * Returns <mxConstants.VERTEX_SELECTION_COLOR>. - */ -mxVertexHandler.prototype.getSelectionColor = function() -{ - return mxConstants.VERTEX_SELECTION_COLOR; -}; - -/** - * Function: getSelectionStrokeWidth - * - * Returns <mxConstants.VERTEX_SELECTION_STROKEWIDTH>. - */ -mxVertexHandler.prototype.getSelectionStrokeWidth = function() -{ - return mxConstants.VERTEX_SELECTION_STROKEWIDTH; -}; - -/** - * Function: isSelectionDashed - * - * Returns <mxConstants.VERTEX_SELECTION_DASHED>. - */ -mxVertexHandler.prototype.isSelectionDashed = function() -{ - return mxConstants.VERTEX_SELECTION_DASHED; -}; - -/** - * Function: createSizer - * - * Creates a sizer handle for the specified cursor and index and returns - * the new <mxRectangleShape> that represents the handle. - */ -mxVertexHandler.prototype.createSizer = function(cursor, index, size, fillColor) -{ - size = size || mxConstants.HANDLE_SIZE; - - var bounds = new mxRectangle(0, 0, size, size); - var sizer = this.createSizerShape(bounds, index, fillColor); - - if (this.state.text != null && this.state.text.node.parentNode == this.graph.container) - { - sizer.bounds.height -= 1; - sizer.bounds.width -= 1; - sizer.dialect = mxConstants.DIALECT_STRICTHTML; - sizer.init(this.graph.container); - } - else - { - sizer.dialect = (this.graph.dialect != mxConstants.DIALECT_SVG) ? - mxConstants.DIALECT_VML : mxConstants.DIALECT_SVG; - sizer.init(this.graph.getView().getOverlayPane()); - } - - mxEvent.redirectMouseEvents(sizer.node, this.graph, this.state); - - if (this.graph.isEnabled()) - { - sizer.node.style.cursor = cursor; - } - - if (!this.isSizerVisible(index)) - { - sizer.node.style.visibility = 'hidden'; - } - - return sizer; -}; - -/** - * Function: isSizerVisible - * - * Returns true if the sizer for the given index is visible. - * This returns true for all given indices. - */ -mxVertexHandler.prototype.isSizerVisible = function(index) -{ - return true; -}; - -/** - * Function: createSizerShape - * - * Creates the shape used for the sizer handle for the specified bounds and - * index. - */ -mxVertexHandler.prototype.createSizerShape = function(bounds, index, fillColor) -{ - if (this.handleImage != null) - { - bounds.width = this.handleImage.width; - bounds.height = this.handleImage.height; - - return new mxImageShape(bounds, this.handleImage.src); - } - else - { - var shape = new mxRectangleShape(bounds, - fillColor || mxConstants.HANDLE_FILLCOLOR, - mxConstants.HANDLE_STROKECOLOR); - shape.crisp = this.crisp; - - return shape; - } -}; - -/** - * Function: createBounds - * - * Helper method to create an <mxRectangle> around the given centerpoint - * with a width and height of 2*s or 6, if no s is given. - */ -mxVertexHandler.prototype.moveSizerTo = function(shape, x, y) -{ - if (shape != null) - { - shape.bounds.x = x - shape.bounds.width / 2; - shape.bounds.y = y - shape.bounds.height / 2; - shape.redraw(); - } -}; - -/** - * Function: getHandleForEvent - * - * Returns the index of the handle for the given event. This returns the index - * of the sizer from where the event originated or <mxEvent.LABEL_INDEX>. - */ -mxVertexHandler.prototype.getHandleForEvent = function(me) -{ - if (me.isSource(this.labelShape)) - { - return mxEvent.LABEL_HANDLE; - } - - if (this.sizers != null) - { - // Connection highlight may consume events before they reach sizer handle - var tol = this.tolerance; - var hit = (this.allowHandleBoundsCheck && (mxClient.IS_IE || tol > 0)) ? - new mxRectangle(me.getGraphX() - tol, me.getGraphY() - tol, 2 * tol, 2 * tol) : null; - - for (var i = 0; i < this.sizers.length; i++) - { - if (me.isSource(this.sizers[i]) || (hit != null && - this.sizers[i].node.style.visibility != 'hidden' && - mxUtils.intersects(this.sizers[i].bounds, hit))) - { - return i; - } - } - } - - return null; -}; - -/** - * Function: mouseDown - * - * Handles the event if a handle has been clicked. By consuming the - * event all subsequent events of the gesture are redirected to this - * handler. - */ -mxVertexHandler.prototype.mouseDown = function(sender, me) -{ - if (!me.isConsumed() && this.graph.isEnabled() && !this.graph.isForceMarqueeEvent(me.getEvent()) && - (this.tolerance > 0 || me.getState() == this.state)) - { - var handle = this.getHandleForEvent(me); - - if (handle != null) - { - this.start(me.getX(), me.getY(), handle); - me.consume(); - } - } -}; - -/** - * Function: start - * - * Starts the handling of the mouse gesture. - */ -mxVertexHandler.prototype.start = function(x, y, index) -{ - var pt = mxUtils.convertPoint(this.graph.container, x, y); - this.startX = pt.x; - this.startY = pt.y; - this.index = index; - - // Creates a preview that can be on top of any HTML label - this.selectionBorder.node.style.visibility = 'hidden'; - this.preview = this.createSelectionShape(this.bounds); - - if (this.state.text != null && this.state.text.node.parentNode == this.graph.container) - { - this.preview.dialect = mxConstants.DIALECT_STRICTHTML; - this.preview.init(this.graph.container); - } - else - { - this.preview.dialect = (this.graph.dialect != mxConstants.DIALECT_SVG) ? - mxConstants.DIALECT_VML : mxConstants.DIALECT_SVG; - this.preview.init(this.graph.view.getOverlayPane()); - } -}; - -/** - * Function: mouseMove - * - * Handles the event by updating the preview. - */ -mxVertexHandler.prototype.mouseMove = function(sender, me) -{ - if (!me.isConsumed() && this.index != null) - { - var point = new mxPoint(me.getGraphX(), me.getGraphY()); - var gridEnabled = this.graph.isGridEnabledEvent(me.getEvent()); - var scale = this.graph.getView().scale; - - if (this.index == mxEvent.LABEL_HANDLE) - { - if (gridEnabled) - { - point.x = this.graph.snap(point.x / scale) * scale; - point.y = this.graph.snap(point.y / scale) * scale; - } - - this.moveSizerTo(this.sizers[this.sizers.length - 1], point.x, point.y); - me.consume(); - } - else if (this.index != null) - { - var dx = point.x - this.startX; - var dy = point.y - this.startY; - var tr = this.graph.view.translate; - this.bounds = this.union(this.selectionBounds, dx, dy, this.index, gridEnabled, scale, tr); - this.drawPreview(); - me.consume(); - } - } - // Workaround for disabling the connect highlight when over handle - else if (this.getHandleForEvent(me) != null) - { - me.consume(false); - } -}; - -/** - * Function: mouseUp - * - * Handles the event by applying the changes to the geometry. - */ -mxVertexHandler.prototype.mouseUp = function(sender, me) -{ - if (!me.isConsumed() && this.index != null && this.state != null) - { - var point = new mxPoint(me.getGraphX(), me.getGraphY()); - var scale = this.graph.getView().scale; - - var gridEnabled = this.graph.isGridEnabledEvent(me.getEvent()); - var dx = (point.x - this.startX) / scale; - var dy = (point.y - this.startY) / scale; - - this.resizeCell(this.state.cell, dx, dy, this.index, gridEnabled); - this.reset(); - me.consume(); - } -}; - -/** - * Function: reset - * - * Resets the state of this handler. - */ -mxVertexHandler.prototype.reset = function() -{ - this.index = null; - - if (this.preview != null) - { - this.preview.destroy(); - this.preview = null; - } - - // Checks if handler has been destroyed - if (this.selectionBorder != null) - { - this.selectionBounds = this.getSelectionBounds(this.state); - this.selectionBorder.node.style.visibility = 'visible'; - this.bounds = new mxRectangle(this.selectionBounds.x, this.selectionBounds.y, - this.selectionBounds.width, this.selectionBounds.height); - this.drawPreview(); - } -}; - -/** - * Function: resizeCell - * - * Uses the given vector to change the bounds of the given cell - * in the graph using <mxGraph.resizeCell>. - */ -mxVertexHandler.prototype.resizeCell = function(cell, dx, dy, index, gridEnabled) -{ - var geo = this.graph.model.getGeometry(cell); - - if (index == mxEvent.LABEL_HANDLE) - { - var scale = this.graph.view.scale; - dx = (this.labelShape.bounds.getCenterX() - this.startX) / scale; - dy = (this.labelShape.bounds.getCenterY() - this.startY) / scale; - - geo = geo.clone(); - - if (geo.offset == null) - { - geo.offset = new mxPoint(dx, dy); - } - else - { - geo.offset.x += dx; - geo.offset.y += dy; - } - - this.graph.model.setGeometry(cell, geo); - } - else - { - var bounds = this.union(geo, dx, dy, index, gridEnabled, 1, new mxPoint(0, 0)); - this.graph.resizeCell(cell, bounds); - } -}; - -/** - * Function: union - * - * Returns the union of the given bounds and location for the specified - * handle index. - * - * To override this to limit the size of vertex via a minWidth/-Height style, - * the following code can be used. - * - * (code) - * var vertexHandlerUnion = mxVertexHandler.prototype.union; - * mxVertexHandler.prototype.union = function(bounds, dx, dy, index, gridEnabled, scale, tr) - * { - * var result = vertexHandlerUnion.apply(this, arguments); - * - * result.width = Math.max(result.width, mxUtils.getNumber(this.state.style, 'minWidth', 0)); - * result.height = Math.max(result.height, mxUtils.getNumber(this.state.style, 'minHeight', 0)); - * - * return result; - * }; - * (end) - * - * The minWidth/-Height style can then be used as follows: - * - * (code) - * graph.insertVertex(parent, null, 'Hello,', 20, 20, 80, 30, 'minWidth=100;minHeight=100;'); - * (end) - */ -mxVertexHandler.prototype.union = function(bounds, dx, dy, index, gridEnabled, scale, tr) -{ - if (this.singleSizer) - { - var x = bounds.x + bounds.width + dx; - var y = bounds.y + bounds.height + dy; - - if (gridEnabled) - { - x = this.graph.snap(x / scale) * scale; - y = this.graph.snap(y / scale) * scale; - } - - var rect = new mxRectangle(bounds.x, bounds.y, 0, 0); - rect.add(new mxRectangle(x, y, 0, 0)); - - return rect; - } - else - { - var left = bounds.x - tr.x * scale; - var right = left + bounds.width; - var top = bounds.y - tr.y * scale; - var bottom = top + bounds.height; - - if (index > 4 /* Bottom Row */) - { - bottom = bottom + dy; - - if (gridEnabled) - { - bottom = this.graph.snap(bottom / scale) * scale; - } - } - else if (index < 3 /* Top Row */) - { - top = top + dy; - - if (gridEnabled) - { - top = this.graph.snap(top / scale) * scale; - } - } - - if (index == 0 || index == 3 || index == 5 /* Left */) - { - left += dx; - - if (gridEnabled) - { - left = this.graph.snap(left / scale) * scale; - } - } - else if (index == 2 || index == 4 || index == 7 /* Right */) - { - right += dx; - - if (gridEnabled) - { - right = this.graph.snap(right / scale) * scale; - } - } - - var width = right - left; - var height = bottom - top; - - // Flips over left side - if (width < 0) - { - left += width; - width = Math.abs(width); - } - - // Flips over top side - if (height < 0) - { - top += height; - height = Math.abs(height); - } - - return new mxRectangle(left + tr.x * scale, top + tr.y * scale, width, height); - } -}; - -/** - * Function: redraw - * - * Redraws the handles and the preview. - */ -mxVertexHandler.prototype.redraw = function() -{ - this.selectionBounds = this.getSelectionBounds(this.state); - this.bounds = new mxRectangle(this.selectionBounds.x, this.selectionBounds.y, - this.selectionBounds.width, this.selectionBounds.height); - - if (this.sizers != null) - { - var s = this.state; - var r = s.x + s.width; - var b = s.y + s.height; - - if (this.singleSizer) - { - this.moveSizerTo(this.sizers[0], r, b); - } - else - { - var cx = s.x + s.width / 2; - var cy = s.y + s.height / 2; - - if (this.sizers.length > 1) - { - this.moveSizerTo(this.sizers[0], s.x, s.y); - this.moveSizerTo(this.sizers[1], cx, s.y); - this.moveSizerTo(this.sizers[2], r, s.y); - this.moveSizerTo(this.sizers[3], s.x, cy); - this.moveSizerTo(this.sizers[4], r, cy); - this.moveSizerTo(this.sizers[5], s.x, b); - this.moveSizerTo(this.sizers[6], cx, b); - this.moveSizerTo(this.sizers[7], r, b); - this.moveSizerTo(this.sizers[8], - cx + s.absoluteOffset.x, - cy + s.absoluteOffset.y); - } - else if (this.state.width >= 2 && this.state.height >= 2) - { - this.moveSizerTo(this.sizers[0], - cx + s.absoluteOffset.x, - cy + s.absoluteOffset.y); - } - else - { - this.moveSizerTo(this.sizers[0], s.x, s.y); - } - } - } - - this.drawPreview(); -}; - -/** - * Function: drawPreview - * - * Redraws the preview. - */ -mxVertexHandler.prototype.drawPreview = function() -{ - if (this.preview != null) - { - this.preview.bounds = this.bounds; - - if (this.preview.node.parentNode == this.graph.container) - { - this.preview.bounds.width = Math.max(0, this.preview.bounds.width - 1); - this.preview.bounds.height = Math.max(0, this.preview.bounds.height - 1); - } - - this.preview.redraw(); - } - - this.selectionBorder.bounds = this.bounds; - this.selectionBorder.redraw(); -}; - -/** - * Function: destroy - * - * Destroys the handler and all its resources and DOM nodes. - */ -mxVertexHandler.prototype.destroy = function() -{ - if (this.preview != null) - { - this.preview.destroy(); - this.preview = null; - } - - this.selectionBorder.destroy(); - this.selectionBorder = null; - this.labelShape = null; - - if (this.sizers != null) - { - for (var i = 0; i < this.sizers.length; i++) - { - this.sizers[i].destroy(); - this.sizers[i] = null; - } - } -}; diff --git a/src/js/index.txt b/src/js/index.txt deleted file mode 100644 index f3631d6..0000000 --- a/src/js/index.txt +++ /dev/null @@ -1,316 +0,0 @@ -Document: API Specification - -Overview: - - This JavaScript library is divided into 8 packages. The top-level <mxClient> - class includes (or dynamically imports) everything else. The current version - is stored in <mxClient.VERSION>. - - The *editor* package provides the classes required to implement a diagram - editor. The main class in this package is <mxEditor>. - - The *view* and *model* packages implement the graph component, represented - by <mxGraph>. It refers to a <mxGraphModel> which contains <mxCell>s and - caches the state of the cells in a <mxGraphView>. The cells are painted - using a <mxCellRenderer> based on the appearance defined in <mxStylesheet>. - Undo history is implemented in <mxUndoManager>. To display an icon on the - graph, <mxCellOverlay> may be used. Validation rules are defined with - <mxMultiplicity>. - - The *handler*, *layout* and *shape* packages contain event listeners, - layout algorithms and shapes, respectively. The graph event listeners - include <mxRubberband> for rubberband selection, <mxTooltipHandler> - for tooltips and <mxGraphHandler> for basic cell modifications. - <mxCompactTreeLayout> implements a tree layout algorithm, and the - shape package provides various shapes, which are subclasses of - <mxShape>. - - The *util* package provides utility classes including <mxClipboard> for - copy-paste, <mxDatatransfer> for drag-and-drop, <mxConstants> for keys and - values of stylesheets, <mxEvent> and <mxUtils> for cross-browser - event-handling and general purpose functions, <mxResources> for - internationalization and <mxLog> for console output. - - The *io* package implements a generic <mxObjectCodec> for turning - JavaScript objects into XML. The main class is <mxCodec>. - <mxCodecRegistry> is the global registry for custom codecs. - -Events: - - There are three different types of events, namely native DOM events, - <mxEventObjects> which are fired in an <mxEventSource>, and <mxMouseEvents> - which are fired in <mxGraph>. - - Some helper methods for handling native events are provided in <mxEvent>. It - also takes care of resolving cycles between DOM nodes and JavaScript event - handlers, which can lead to memory leaks in IE6. - - Most custom events in mxGraph are implemented using <mxEventSource>. Its - listeners are functions that take a sender and <mxEventObject>. Additionally, - the <mxGraph> class fires special <mxMouseEvents> which are handled using - mouse listeners, which are objects that provide a mousedown, mousemove and - mouseup method. - - Events in <mxEventSource> are fired using <mxEventSource.fireEvent>. - Listeners are added and removed using <mxEventSource.addListener> and - <mxEventSource.removeListener>. <mxMouseEvents> in <mxGraph> are fired using - <mxGraph.fireMouseEvent>. Listeners are added and removed using - <mxGraph.addMouseListener> and <mxGraph.removeMouseListener>, respectively. - -Key bindings: - - The following key bindings are defined for mouse events in the client across - all browsers and platforms: - - - Control-Drag: Duplicates (clones) selected cells - - Shift-Rightlick: Shows the context menu - - Alt-Click: Forces rubberband (aka. marquee) - - Control-Select: Toggles the selection state - - Shift-Drag: Constrains the offset to one direction - - Shift-Control-Drag: Panning (also Shift-Rightdrag) - -Configuration: - - The following global variables may be defined before the client is loaded to - specify its language or base path, respectively. - - - mxBasePath: Specifies the path in <mxClient.basePath>. - - mxImageBasePath: Specifies the path in <mxClient.imageBasePath>. - - mxLanguage: Specifies the language for resources in <mxClient.language>. - - mxDefaultLanguage: Specifies the default language in <mxClient.defaultLanguage>. - - mxLoadResources: Specifies if any resources should be loaded. Default is true. - - mxLoadStylesheets: Specifies if any stylesheets should be loaded. Default is true. - -Reserved Words: - - The mx prefix is used for all classes and objects in mxGraph. The mx prefix - can be seen as the global namespace for all JavaScript code in mxGraph. The - following fieldnames should not be used in objects. - - - *mxObjectId*: If the object is used with mxObjectIdentity - - *as*: If the object is a field of another object - - *id*: If the object is an idref in a codec - - *mxListenerList*: Added to DOM nodes when used with <mxEvent> - - *window._mxDynamicCode*: Temporarily used to load code in Safari and Chrome - (see <mxClient.include>). - - *_mxJavaScriptExpression*: Global variable that is temporarily used to - evaluate code in Safari, Opera, Firefox 3 and IE (see <mxUtils.eval>). - -Files: - - The library contains these relative filenames. All filenames are relative - to <mxClient.basePath>. - -Built-in Images: - - All images are loaded from the <mxClient.imageBasePath>, - which you can change to reflect your environment. The image variables can - also be changed individually. - - - mxGraph.prototype.collapsedImage - - mxGraph.prototype.expandedImage - - mxGraph.prototype.warningImage - - mxWindow.prototype.closeImage - - mxWindow.prototype.minimizeImage - - mxWindow.prototype.normalizeImage - - mxWindow.prototype.maximizeImage - - mxWindow.prototype.resizeImage - - mxPopupMenu.prototype.submenuImage - - mxUtils.errorImage - - mxConstraintHandler.prototype.pointImage - - The basename of the warning image (images/warning without extension) used in - <mxGraph.setCellWarning> is defined in <mxGraph.warningImage>. - -Resources: - - The <mxEditor> and <mxGraph> classes add the following resources to - <mxResources> at class loading time: - - - resources/editor*.properties - - resources/graph*.properties - - By default, the library ships with English and German resource files. - -Images: - - Recommendations for using images. Use GIF images (256 color palette) in HTML - elements (such as the toolbar and context menu), and PNG images (24 bit) for - all images which appear inside the graph component. - - - For PNG images inside HTML elements, Internet Explorer will ignore any - transparency information. - - For GIF images inside the graph, Firefox on the Mac will display strange - colors. Furthermore, only the first image for animated GIFs is displayed - on the Mac. - - For faster image rendering during application runtime, images can be - prefetched using the following code: - - (code) - var image = new Image(); - image.src = url_to_image; - (end) - -Deployment: - - The client is added to the page using the following script tag inside the - head of a document: - - (code) - <script type="text/javascript" src="js/mxClient.js"></script> - (end) - - The deployment version of the mxClient.js file contains all required code - in a single file. For deployment, the complete javascript/src directory is - required. - -Source Code: - - If you are a source code customer and you wish to develop using the - full source code, the commented source code is shipped in the - javascript/devel/source.zip file. It contains one file for each class - in mxGraph. To use the source code the source.zip file must be - uncompressed and the mxClient.js URL in the HTML page must be changed - to reference the uncompressed mxClient.js from the source.zip file. - -Compression: - - When using Apache2 with mod_deflate, you can use the following directive - in src/js/.htaccess to speedup the loading of the JavaScript sources: - - (code) - SetOutputFilter DEFLATE - (end) - -Classes: - - There are two types of "classes" in mxGraph: classes and singletons (where - only one instance exists). Singletons are mapped to global objects where the - variable name equals the classname. For example mxConstants is an object with - all the constants defined as object fields. Normal classes are mapped to a - constructor function and a prototype which defines the instance fields and - methods. For example, <mxEditor> is a function and mxEditor.prototype is the - prototype for the object that the mxEditor function creates. The mx prefix is - a convention that is used for all classes in the mxGraph package to avoid - conflicts with other objects in the global namespace. - -Subclassing: - - For subclassing, the superclass must provide a constructor that is either - parameterless or handles an invocation with no arguments. Furthermore, the - special constructor field must be redefined after extending the prototype. - For example, the superclass of mxEditor is <mxEventSource>. This is - represented in JavaScript by first "inheriting" all fields and methods from - the superclass by assigning the prototype to an instance of the superclass, - eg. mxEditor.prototype = new mxEventSource() and redefining the constructor - field using mxEditor.prototype.constructor = mxEditor. The latter rule is - applied so that the type of an object can be retrieved via the name of it’s - constructor using mxUtils.getFunctionName(obj.constructor). - -Constructor: - - For subclassing in mxGraph, the same scheme should be applied. For example, - for subclassing the <mxGraph> class, first a constructor must be defined for - the new class. The constructor calls the super constructor with any arguments - that it may have using the call function on the mxGraph function object, - passing along explitely each argument: - - (code) - function MyGraph(container) - { - mxGraph.call(this, container); - } - (end) - - The prototype of MyGraph inherits from mxGraph as follows. As usual, the - constructor is redefined after extending the superclass: - - (code) - MyGraph.prototype = new mxGraph(); - MyGraph.prototype.constructor = MyGraph; - (end) - - You may want to define the codec associated for the class after the above - code. This code will be executed at class loading time and makes sure the - same codec is used to encode instances of mxGraph and MyGraph. - - (code) - var codec = mxCodecRegistry.getCodec(mxGraph); - codec.template = new MyGraph(); - mxCodecRegistry.register(codec); - (end) - -Functions: - - In the prototype for MyGraph, functions of mxGraph can then be extended as - follows. - - (code) - MyGraph.prototype.isCellSelectable = function(cell) - { - var selectable = mxGraph.prototype.isSelectable.apply(this, arguments); - - var geo = this.model.getGeometry(cell); - return selectable && (geo == null || !geo.relative); - } - (end) - - The supercall in the first line is optional. It is done using the apply - function on the isSelectable function object of the mxGraph prototype, using - the special this and arguments variables as parameters. Calls to the - superclass function are only possible if the function is not replaced in the - superclass as follows, which is another way of “subclassing” in JavaScript. - - (code) - mxGraph.prototype.isCellSelectable = function(cell) - { - var geo = this.model.getGeometry(cell); - return selectable && - (geo == null || - !geo.relative); - } - (end) - - The above scheme is useful if a function definition needs to be replaced - completely. - - In order to add new functions and fields to the subclass, the following code - is used. The example below adds a new function to return the XML - representation of the graph model: - - (code) - MyGraph.prototype.getXml = function() - { - var enc = new mxCodec(); - return enc.encode(this.getModel()); - } - (end) - -Variables: - - Likewise, a new field is declared and defined as follows. - - (code) - MyGraph.prototype.myField = 'Hello, World!'; - (end) - - Note that the value assigned to myField is created only once, that is, all - instances of MyGraph share the same value. If you require instance-specific - values, then the field must be defined in the constructor instead. - - (code) - function MyGraph(container) - { - mxGraph.call(this, container); - - this.myField = new Array(); - } - (end) - - Finally, a new instance of MyGraph is created using the following code, where - container is a DOM node that acts as a container for the graph view: - - (code) - var graph = new MyGraph(container); - (end) diff --git a/src/js/io/mxCellCodec.js b/src/js/io/mxCellCodec.js deleted file mode 100644 index cbcd651..0000000 --- a/src/js/io/mxCellCodec.js +++ /dev/null @@ -1,170 +0,0 @@ -/** - * $Id: mxCellCodec.js,v 1.22 2010-10-21 07:12:31 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -mxCodecRegistry.register(function() -{ - /** - * Class: mxCellCodec - * - * Codec for <mxCell>s. This class is created and registered - * dynamically at load time and used implicitely via <mxCodec> - * and the <mxCodecRegistry>. - * - * Transient Fields: - * - * - children - * - edges - * - overlays - * - mxTransient - * - * Reference Fields: - * - * - parent - * - source - * - target - * - * Transient fields can be added using the following code: - * - * mxCodecRegistry.getCodec(mxCell).exclude.push('name_of_field'); - */ - var codec = new mxObjectCodec(new mxCell(), - ['children', 'edges', 'overlays', 'mxTransient'], - ['parent', 'source', 'target']); - - /** - * Function: isCellCodec - * - * Returns true since this is a cell codec. - */ - codec.isCellCodec = function() - { - return true; - }; - - /** - * Function: isExcluded - * - * Excludes user objects that are XML nodes. - */ - codec.isExcluded = function(obj, attr, value, isWrite) - { - return mxObjectCodec.prototype.isExcluded.apply(this, arguments) || - (isWrite && attr == 'value' && - value.nodeType == mxConstants.NODETYPE_ELEMENT); - }; - - /** - * Function: afterEncode - * - * Encodes an <mxCell> and wraps the XML up inside the - * XML of the user object (inversion). - */ - codec.afterEncode = function(enc, obj, node) - { - if (obj.value != null && - obj.value.nodeType == mxConstants.NODETYPE_ELEMENT) - { - // Wraps the graphical annotation up in the user object (inversion) - // by putting the result of the default encoding into a clone of the - // user object (node type 1) and returning this cloned user object. - var tmp = node; - node = (mxClient.IS_IE) ? - obj.value.cloneNode(true) : - enc.document.importNode(obj.value, true); - node.appendChild(tmp); - - // Moves the id attribute to the outermost XML node, namely the - // node which denotes the object boundaries in the file. - var id = tmp.getAttribute('id'); - node.setAttribute('id', id); - tmp.removeAttribute('id'); - } - - return node; - }; - - /** - * Function: beforeDecode - * - * Decodes an <mxCell> and uses the enclosing XML node as - * the user object for the cell (inversion). - */ - codec.beforeDecode = function(dec, node, obj) - { - var inner = node; - var classname = this.getName(); - - if (node.nodeName != classname) - { - // Passes the inner graphical annotation node to the - // object codec for further processing of the cell. - var tmp = node.getElementsByTagName(classname)[0]; - - if (tmp != null && - tmp.parentNode == node) - { - mxUtils.removeWhitespace(tmp, true); - mxUtils.removeWhitespace(tmp, false); - tmp.parentNode.removeChild(tmp); - inner = tmp; - } - else - { - inner = null; - } - - // Creates the user object out of the XML node - obj.value = node.cloneNode(true); - var id = obj.value.getAttribute('id'); - - if (id != null) - { - obj.setId(id); - obj.value.removeAttribute('id'); - } - } - else - { - // Uses ID from XML file as ID for cell in model - obj.setId(node.getAttribute('id')); - } - - // Preprocesses and removes all Id-references in order to use the - // correct encoder (this) for the known references to cells (all). - if (inner != null) - { - for (var i = 0; i < this.idrefs.length; i++) - { - var attr = this.idrefs[i]; - var ref = inner.getAttribute(attr); - - if (ref != null) - { - inner.removeAttribute(attr); - var object = dec.objects[ref] || dec.lookup(ref); - - if (object == null) - { - // Needs to decode forward reference - var element = dec.getElementById(ref); - - if (element != null) - { - var decoder = mxCodecRegistry.codecs[element.nodeName] || this; - object = decoder.decode(dec, element); - } - } - - obj[attr] = object; - } - } - } - - return inner; - }; - - // Returns the codec into the registry - return codec; - -}()); diff --git a/src/js/io/mxChildChangeCodec.js b/src/js/io/mxChildChangeCodec.js deleted file mode 100644 index deeb57b..0000000 --- a/src/js/io/mxChildChangeCodec.js +++ /dev/null @@ -1,149 +0,0 @@ -/** - * $Id: mxChildChangeCodec.js,v 1.12 2010-09-15 14:38:52 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -mxCodecRegistry.register(function() -{ - /** - * Class: mxChildChangeCodec - * - * Codec for <mxChildChange>s. This class is created and registered - * dynamically at load time and used implicitely via <mxCodec> and - * the <mxCodecRegistry>. - * - * Transient Fields: - * - * - model - * - previous - * - previousIndex - * - child - * - * Reference Fields: - * - * - parent - */ - var codec = new mxObjectCodec(new mxChildChange(), - ['model', 'child', 'previousIndex'], - ['parent', 'previous']); - - /** - * Function: isReference - * - * Returns true for the child attribute if the child - * cell had a previous parent or if we're reading the - * child as an attribute rather than a child node, in - * which case it's always a reference. - */ - codec.isReference = function(obj, attr, value, isWrite) - { - if (attr == 'child' && - (obj.previous != null || - !isWrite)) - { - return true; - } - - return mxUtils.indexOf(this.idrefs, attr) >= 0; - }; - - /** - * Function: afterEncode - * - * Encodes the child recusively and adds the result - * to the given node. - */ - codec.afterEncode = function(enc, obj, node) - { - if (this.isReference(obj, 'child', obj.child, true)) - { - // Encodes as reference (id) - node.setAttribute('child', enc.getId(obj.child)); - } - else - { - // At this point, the encoder is no longer able to know which cells - // are new, so we have to encode the complete cell hierarchy and - // ignore the ones that are already there at decoding time. Note: - // This can only be resolved by moving the notify event into the - // execute of the edit. - enc.encodeCell(obj.child, node); - } - - return node; - }; - - /** - * Function: beforeDecode - * - * Decodes the any child nodes as using the respective - * codec from the registry. - */ - codec.beforeDecode = function(dec, node, obj) - { - if (node.firstChild != null && - node.firstChild.nodeType == mxConstants.NODETYPE_ELEMENT) - { - // Makes sure the original node isn't modified - node = node.cloneNode(true); - - var tmp = node.firstChild; - obj.child = dec.decodeCell(tmp, false); - - var tmp2 = tmp.nextSibling; - tmp.parentNode.removeChild(tmp); - tmp = tmp2; - - while (tmp != null) - { - tmp2 = tmp.nextSibling; - - if (tmp.nodeType == mxConstants.NODETYPE_ELEMENT) - { - // Ignores all existing cells because those do not need to - // be re-inserted into the model. Since the encoded version - // of these cells contains the new parent, this would leave - // to an inconsistent state on the model (ie. a parent - // change without a call to parentForCellChanged). - var id = tmp.getAttribute('id'); - - if (dec.lookup(id) == null) - { - dec.decodeCell(tmp); - } - } - - tmp.parentNode.removeChild(tmp); - tmp = tmp2; - } - } - else - { - var childRef = node.getAttribute('child'); - obj.child = dec.getObject(childRef); - } - - return node; - }; - - /** - * Function: afterDecode - * - * Restores object state in the child change. - */ - codec.afterDecode = function(dec, node, obj) - { - // Cells are encoded here after a complete transaction so the previous - // parent must be restored on the cell for the case where the cell was - // added. This is needed for the local model to identify the cell as a - // new cell and register the ID. - obj.child.parent = obj.previous; - obj.previous = obj.parent; - obj.previousIndex = obj.index; - - return obj; - }; - - // Returns the codec into the registry - return codec; - -}()); diff --git a/src/js/io/mxCodec.js b/src/js/io/mxCodec.js deleted file mode 100644 index b8bfc6a..0000000 --- a/src/js/io/mxCodec.js +++ /dev/null @@ -1,531 +0,0 @@ -/** - * $Id: mxCodec.js,v 1.48 2012-01-04 10:01:16 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -/** - * Class: mxCodec - * - * XML codec for JavaScript object graphs. See <mxObjectCodec> for a - * description of the general encoding/decoding scheme. This class uses the - * codecs registered in <mxCodecRegistry> for encoding/decoding each object. - * - * References: - * - * In order to resolve references, especially forward references, the mxCodec - * constructor must be given the document that contains the referenced - * elements. - * - * Examples: - * - * The following code is used to encode a graph model. - * - * (code) - * var encoder = new mxCodec(); - * var result = encoder.encode(graph.getModel()); - * var xml = mxUtils.getXml(result); - * (end) - * - * Example: - * - * Using the following code, the selection cells of a graph are encoded and the - * output is displayed in a dialog box. - * - * (code) - * var enc = new mxCodec(); - * var cells = graph.getSelectionCells(); - * mxUtils.alert(mxUtils.getPrettyXml(enc.encode(cells))); - * (end) - * - * Newlines in the XML can be coverted to <br>, in which case a '<br>' argument - * must be passed to <mxUtils.getXml> as the second argument. - * - * Example: - * - * Using the code below, an XML document is decodec into an existing model. The - * document may be obtained using one of the functions in mxUtils for loading - * an XML file, eg. <mxUtils.get>, or using <mxUtils.parseXml> for parsing an - * XML string. - * - * (code) - * var decoder = new mxCodec(doc) - * decoder.decode(doc.documentElement, graph.getModel()); - * (end) - * - * Debugging: - * - * For debugging i/o you can use the following code to get the sequence of - * encoded objects: - * - * (code) - * var oldEncode = mxCodec.prototype.encode; - * mxCodec.prototype.encode = function(obj) - * { - * mxLog.show(); - * mxLog.debug('mxCodec.encode: obj='+mxUtils.getFunctionName(obj.constructor)); - * - * return oldEncode.apply(this, arguments); - * }; - * (end) - * - * Constructor: mxCodec - * - * Constructs an XML encoder/decoder for the specified - * owner document. - * - * Parameters: - * - * document - Optional XML document that contains the data. - * If no document is specified then a new document is created - * using <mxUtils.createXmlDocument>. - */ -function mxCodec(document) -{ - this.document = document || mxUtils.createXmlDocument(); - this.objects = []; -}; - -/** - * Variable: document - * - * The owner document of the codec. - */ -mxCodec.prototype.document = null; - -/** - * Variable: objects - * - * Maps from IDs to objects. - */ -mxCodec.prototype.objects = null; - -/** - * Variable: encodeDefaults - * - * Specifies if default values should be encoded. Default is false. - */ -mxCodec.prototype.encodeDefaults = false; - - -/** - * Function: putObject - * - * Assoiates the given object with the given ID and returns the given object. - * - * Parameters - * - * id - ID for the object to be associated with. - * obj - Object to be associated with the ID. - */ -mxCodec.prototype.putObject = function(id, obj) -{ - this.objects[id] = obj; - - return obj; -}; - -/** - * Function: getObject - * - * Returns the decoded object for the element with the specified ID in - * <document>. If the object is not known then <lookup> is used to find an - * object. If no object is found, then the element with the respective ID - * from the document is parsed using <decode>. - */ -mxCodec.prototype.getObject = function(id) -{ - var obj = null; - - if (id != null) - { - obj = this.objects[id]; - - if (obj == null) - { - obj = this.lookup(id); - - if (obj == null) - { - var node = this.getElementById(id); - - if (node != null) - { - obj = this.decode(node); - } - } - } - } - - return obj; -}; - -/** - * Function: lookup - * - * Hook for subclassers to implement a custom lookup mechanism for cell IDs. - * This implementation always returns null. - * - * Example: - * - * (code) - * var codec = new mxCodec(); - * codec.lookup = function(id) - * { - * return model.getCell(id); - * }; - * (end) - * - * Parameters: - * - * id - ID of the object to be returned. - */ -mxCodec.prototype.lookup = function(id) -{ - return null; -}; - -/** - * Function: getElementById - * - * Returns the element with the given ID from <document>. The optional attr - * argument specifies the name of the ID attribute. Default is "id". The - * XPath expression used to find the element is //*[@attr='arg'] where attr is - * the name of the ID attribute and arg is the given id. - * - * Parameters: - * - * id - String that contains the ID. - * attr - Optional string for the attributename. Default is "id". - */ -mxCodec.prototype.getElementById = function(id, attr) -{ - attr = (attr != null) ? attr : 'id'; - - return mxUtils.findNodeByAttribute(this.document.documentElement, attr, id); -}; - -/** - * Function: getId - * - * Returns the ID of the specified object. This implementation - * calls <reference> first and if that returns null handles - * the object as an <mxCell> by returning their IDs using - * <mxCell.getId>. If no ID exists for the given cell, then - * an on-the-fly ID is generated using <mxCellPath.create>. - * - * Parameters: - * - * obj - Object to return the ID for. - */ -mxCodec.prototype.getId = function(obj) -{ - var id = null; - - if (obj != null) - { - id = this.reference(obj); - - if (id == null && obj instanceof mxCell) - { - id = obj.getId(); - - if (id == null) - { - // Uses an on-the-fly Id - id = mxCellPath.create(obj); - - if (id.length == 0) - { - id = 'root'; - } - } - } - } - - return id; -}; - -/** - * Function: reference - * - * Hook for subclassers to implement a custom method - * for retrieving IDs from objects. This implementation - * always returns null. - * - * Example: - * - * (code) - * var codec = new mxCodec(); - * codec.reference = function(obj) - * { - * return obj.getCustomId(); - * }; - * (end) - * - * Parameters: - * - * obj - Object whose ID should be returned. - */ -mxCodec.prototype.reference = function(obj) -{ - return null; -}; - -/** - * Function: encode - * - * Encodes the specified object and returns the resulting - * XML node. - * - * Parameters: - * - * obj - Object to be encoded. - */ -mxCodec.prototype.encode = function(obj) -{ - var node = null; - - if (obj != null && obj.constructor != null) - { - var enc = mxCodecRegistry.getCodec(obj.constructor); - - if (enc != null) - { - node = enc.encode(this, obj); - } - else - { - if (mxUtils.isNode(obj)) - { - node = (mxClient.IS_IE) ? obj.cloneNode(true) : - this.document.importNode(obj, true); - } - else - { - mxLog.warn('mxCodec.encode: No codec for '+ - mxUtils.getFunctionName(obj.constructor)); - } - } - } - - return node; -}; - -/** - * Function: decode - * - * Decodes the given XML node. The optional "into" - * argument specifies an existing object to be - * used. If no object is given, then a new instance - * is created using the constructor from the codec. - * - * The function returns the passed in object or - * the new instance if no object was given. - * - * Parameters: - * - * node - XML node to be decoded. - * into - Optional object to be decodec into. - */ -mxCodec.prototype.decode = function(node, into) -{ - var obj = null; - - if (node != null && node.nodeType == mxConstants.NODETYPE_ELEMENT) - { - var ctor = null; - - try - { - ctor = eval(node.nodeName); - } - catch (err) - { - // ignore - } - - try - { - var dec = mxCodecRegistry.getCodec(ctor); - - if (dec != null) - { - obj = dec.decode(this, node, into); - } - else - { - obj = node.cloneNode(true); - obj.removeAttribute('as'); - } - } - catch (err) - { - mxLog.debug('Cannot decode '+node.nodeName+': '+err.message); - } - } - - return obj; -}; - -/** - * Function: encodeCell - * - * Encoding of cell hierarchies is built-into the core, but - * is a higher-level function that needs to be explicitely - * used by the respective object encoders (eg. <mxModelCodec>, - * <mxChildChangeCodec> and <mxRootChangeCodec>). This - * implementation writes the given cell and its children as a - * (flat) sequence into the given node. The children are not - * encoded if the optional includeChildren is false. The - * function is in charge of adding the result into the - * given node and has no return value. - * - * Parameters: - * - * cell - <mxCell> to be encoded. - * node - Parent XML node to add the encoded cell into. - * includeChildren - Optional boolean indicating if the - * function should include all descendents. Default is true. - */ -mxCodec.prototype.encodeCell = function(cell, node, includeChildren) -{ - node.appendChild(this.encode(cell)); - - if (includeChildren == null || includeChildren) - { - var childCount = cell.getChildCount(); - - for (var i = 0; i < childCount; i++) - { - this.encodeCell(cell.getChildAt(i), node); - } - } -}; - -/** - * Function: isCellCodec - * - * Returns true if the given codec is a cell codec. This uses - * <mxCellCodec.isCellCodec> to check if the codec is of the - * given type. - */ -mxCodec.prototype.isCellCodec = function(codec) -{ - if (codec != null && typeof(codec.isCellCodec) == 'function') - { - return codec.isCellCodec(); - } - - return false; -}; - -/** - * Function: decodeCell - * - * Decodes cells that have been encoded using inversion, ie. - * where the user object is the enclosing node in the XML, - * and restores the group and graph structure in the cells. - * Returns a new <mxCell> instance that represents the - * given node. - * - * Parameters: - * - * node - XML node that contains the cell data. - * restoreStructures - Optional boolean indicating whether - * the graph structure should be restored by calling insert - * and insertEdge on the parent and terminals, respectively. - * Default is true. - */ -mxCodec.prototype.decodeCell = function(node, restoreStructures) -{ - restoreStructures = (restoreStructures != null) ? restoreStructures : true; - var cell = null; - - if (node != null && node.nodeType == mxConstants.NODETYPE_ELEMENT) - { - // Tries to find a codec for the given node name. If that does - // not return a codec then the node is the user object (an XML node - // that contains the mxCell, aka inversion). - var decoder = mxCodecRegistry.getCodec(node.nodeName); - - // Tries to find the codec for the cell inside the user object. - // This assumes all node names inside the user object are either - // not registered or they correspond to a class for cells. - if (!this.isCellCodec(decoder)) - { - var child = node.firstChild; - - while (child != null && !this.isCellCodec(decoder)) - { - decoder = mxCodecRegistry.getCodec(child.nodeName); - child = child.nextSibling; - } - } - - if (!this.isCellCodec(decoder)) - { - decoder = mxCodecRegistry.getCodec(mxCell); - } - - cell = decoder.decode(this, node); - - if (restoreStructures) - { - this.insertIntoGraph(cell); - } - } - - return cell; -}; - -/** - * Function: insertIntoGraph - * - * Inserts the given cell into its parent and terminal cells. - */ -mxCodec.prototype.insertIntoGraph = function(cell) -{ - var parent = cell.parent; - var source = cell.getTerminal(true); - var target = cell.getTerminal(false); - - // Fixes possible inconsistencies during insert into graph - cell.setTerminal(null, false); - cell.setTerminal(null, true); - cell.parent = null; - - if (parent != null) - { - parent.insert(cell); - } - - if (source != null) - { - source.insertEdge(cell, true); - } - - if (target != null) - { - target.insertEdge(cell, false); - } -}; - -/** - * Function: setAttribute - * - * Sets the attribute on the specified node to value. This is a - * helper method that makes sure the attribute and value arguments - * are not null. - * - * Parameters: - * - * node - XML node to set the attribute for. - * attributes - Attributename to be set. - * value - New value of the attribute. - */ -mxCodec.prototype.setAttribute = function(node, attribute, value) -{ - if (attribute != null && value != null) - { - node.setAttribute(attribute, value); - } -}; diff --git a/src/js/io/mxCodecRegistry.js b/src/js/io/mxCodecRegistry.js deleted file mode 100644 index a0a0f20..0000000 --- a/src/js/io/mxCodecRegistry.js +++ /dev/null @@ -1,137 +0,0 @@ -/** - * $Id: mxCodecRegistry.js,v 1.12 2010-04-30 13:18:21 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -var mxCodecRegistry = -{ - /** - * Class: mxCodecRegistry - * - * Singleton class that acts as a global registry for codecs. - * - * Adding an <mxCodec>: - * - * 1. Define a default codec with a new instance of the - * object to be handled. - * - * (code) - * var codec = new mxObjectCodec(new mxGraphModel()); - * (end) - * - * 2. Define the functions required for encoding and decoding - * objects. - * - * (code) - * codec.encode = function(enc, obj) { ... } - * codec.decode = function(dec, node, into) { ... } - * (end) - * - * 3. Register the codec in the <mxCodecRegistry>. - * - * (code) - * mxCodecRegistry.register(codec); - * (end) - * - * <mxObjectCodec.decode> may be used to either create a new - * instance of an object or to configure an existing instance, - * in which case the into argument points to the existing - * object. In this case, we say the codec "configures" the - * object. - * - * Variable: codecs - * - * Maps from constructor names to codecs. - */ - codecs: [], - - /** - * Variable: aliases - * - * Maps from classnames to codecnames. - */ - aliases: [], - - /** - * Function: register - * - * Registers a new codec and associates the name of the template - * constructor in the codec with the codec object. - * - * Parameters: - * - * codec - <mxObjectCodec> to be registered. - */ - register: function(codec) - { - if (codec != null) - { - var name = codec.getName(); - mxCodecRegistry.codecs[name] = codec; - - var classname = mxUtils.getFunctionName(codec.template.constructor); - - if (classname != name) - { - mxCodecRegistry.addAlias(classname, name); - } - } - - return codec; - }, - - /** - * Function: addAlias - * - * Adds an alias for mapping a classname to a codecname. - */ - addAlias: function(classname, codecname) - { - mxCodecRegistry.aliases[classname] = codecname; - }, - - /** - * Function: getCodec - * - * Returns a codec that handles objects that are constructed - * using the given constructor. - * - * Parameters: - * - * ctor - JavaScript constructor function. - */ - getCodec: function(ctor) - { - var codec = null; - - if (ctor != null) - { - var name = mxUtils.getFunctionName(ctor); - var tmp = mxCodecRegistry.aliases[name]; - - if (tmp != null) - { - name = tmp; - } - - codec = mxCodecRegistry.codecs[name]; - - // Registers a new default codec for the given constructor - // if no codec has been previously defined. - if (codec == null) - { - try - { - codec = new mxObjectCodec(new ctor()); - mxCodecRegistry.register(codec); - } - catch (e) - { - // ignore - } - } - } - - return codec; - } - -}; diff --git a/src/js/io/mxDefaultKeyHandlerCodec.js b/src/js/io/mxDefaultKeyHandlerCodec.js deleted file mode 100644 index 628524a..0000000 --- a/src/js/io/mxDefaultKeyHandlerCodec.js +++ /dev/null @@ -1,88 +0,0 @@ -/** - * $Id: mxDefaultKeyHandlerCodec.js,v 1.5 2010-01-02 09:45:15 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -mxCodecRegistry.register(function() -{ - /** - * Class: mxDefaultKeyHandlerCodec - * - * Custom codec for configuring <mxDefaultKeyHandler>s. This class is created - * and registered dynamically at load time and used implicitely via - * <mxCodec> and the <mxCodecRegistry>. This codec only reads configuration - * data for existing key handlers, it does not encode or create key handlers. - */ - var codec = new mxObjectCodec(new mxDefaultKeyHandler()); - - /** - * Function: encode - * - * Returns null. - */ - codec.encode = function(enc, obj) - { - return null; - }; - - /** - * Function: decode - * - * Reads a sequence of the following child nodes - * and attributes: - * - * Child Nodes: - * - * add - Binds a keystroke to an actionname. - * - * Attributes: - * - * as - Keycode. - * action - Actionname to execute in editor. - * control - Optional boolean indicating if - * the control key must be pressed. - * - * Example: - * - * (code) - * <mxDefaultKeyHandler as="keyHandler"> - * <add as="88" control="true" action="cut"/> - * <add as="67" control="true" action="copy"/> - * <add as="86" control="true" action="paste"/> - * </mxDefaultKeyHandler> - * (end) - * - * The keycodes are for the x, c and v keys. - * - * See also: <mxDefaultKeyHandler.bindAction>, - * http://www.js-examples.com/page/tutorials__key_codes.html - */ - codec.decode = function(dec, node, into) - { - if (into != null) - { - var editor = into.editor; - node = node.firstChild; - - while (node != null) - { - if (!this.processInclude(dec, node, into) && - node.nodeName == 'add') - { - var as = node.getAttribute('as'); - var action = node.getAttribute('action'); - var control = node.getAttribute('control'); - - into.bindAction(as, action, control); - } - - node = node.nextSibling; - } - } - - return into; - }; - - // Returns the codec into the registry - return codec; - -}()); diff --git a/src/js/io/mxDefaultPopupMenuCodec.js b/src/js/io/mxDefaultPopupMenuCodec.js deleted file mode 100644 index 8d949ea..0000000 --- a/src/js/io/mxDefaultPopupMenuCodec.js +++ /dev/null @@ -1,54 +0,0 @@ -/** - * $Id: mxDefaultPopupMenuCodec.js,v 1.6 2010-01-02 09:45:15 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -mxCodecRegistry.register(function() -{ - /** - * Class: mxDefaultPopupMenuCodec - * - * Custom codec for configuring <mxDefaultPopupMenu>s. This class is created - * and registered dynamically at load time and used implicitely via - * <mxCodec> and the <mxCodecRegistry>. This codec only reads configuration - * data for existing popup menus, it does not encode or create menus. Note - * that this codec only passes the configuration node to the popup menu, - * which uses the config to dynamically create menus. See - * <mxDefaultPopupMenu.createMenu>. - */ - var codec = new mxObjectCodec(new mxDefaultPopupMenu()); - - /** - * Function: encode - * - * Returns null. - */ - codec.encode = function(enc, obj) - { - return null; - }; - - /** - * Function: decode - * - * Uses the given node as the config for <mxDefaultPopupMenu>. - */ - codec.decode = function(dec, node, into) - { - var inc = node.getElementsByTagName('include')[0]; - - if (inc != null) - { - this.processInclude(dec, inc, into); - } - else if (into != null) - { - into.config = node; - } - - return into; - }; - - // Returns the codec into the registry - return codec; - -}()); diff --git a/src/js/io/mxDefaultToolbarCodec.js b/src/js/io/mxDefaultToolbarCodec.js deleted file mode 100644 index 6698b9b..0000000 --- a/src/js/io/mxDefaultToolbarCodec.js +++ /dev/null @@ -1,301 +0,0 @@ -/** - * $Id: mxDefaultToolbarCodec.js,v 1.22 2012-04-11 07:00:52 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -mxCodecRegistry.register(function() -{ - /** - * Class: mxDefaultToolbarCodec - * - * Custom codec for configuring <mxDefaultToolbar>s. This class is created - * and registered dynamically at load time and used implicitely via - * <mxCodec> and the <mxCodecRegistry>. This codec only reads configuration - * data for existing toolbars handlers, it does not encode or create toolbars. - */ - var codec = new mxObjectCodec(new mxDefaultToolbar()); - - /** - * Function: encode - * - * Returns null. - */ - codec.encode = function(enc, obj) - { - return null; - }; - - /** - * Function: decode - * - * Reads a sequence of the following child nodes - * and attributes: - * - * Child Nodes: - * - * add - Adds a new item to the toolbar. See below for attributes. - * separator - Adds a vertical separator. No attributes. - * hr - Adds a horizontal separator. No attributes. - * br - Adds a linefeed. No attributes. - * - * Attributes: - * - * as - Resource key for the label. - * action - Name of the action to execute in enclosing editor. - * mode - Modename (see below). - * template - Template name for cell insertion. - * style - Optional style to override the template style. - * icon - Icon (relative/absolute URL). - * pressedIcon - Optional icon for pressed state (relative/absolute URL). - * id - Optional ID to be used for the created DOM element. - * toggle - Optional 0 or 1 to disable toggling of the element. Default is - * 1 (true). - * - * The action, mode and template attributes are mutually exclusive. The - * style can only be used with the template attribute. The add node may - * contain another sequence of add nodes with as and action attributes - * to create a combo box in the toolbar. If the icon is specified then - * a list of the child node is expected to have its template attribute - * set and the action is ignored instead. - * - * Nodes with a specified template may define a function to be used for - * inserting the cloned template into the graph. Here is an example of such - * a node: - * - * (code) - * <add as="Swimlane" template="swimlane" icon="images/swimlane.gif"><![CDATA[ - * function (editor, cell, evt, targetCell) - * { - * var pt = mxUtils.convertPoint( - * editor.graph.container, mxEvent.getClientX(evt), - * mxEvent.getClientY(evt)); - * return editor.addVertex(targetCell, cell, pt.x, pt.y); - * } - * ]]></add> - * (end) - * - * In the above function, editor is the enclosing <mxEditor> instance, cell - * is the clone of the template, evt is the mouse event that represents the - * drop and targetCell is the cell under the mousepointer where the drop - * occurred. The targetCell is retrieved using <mxGraph.getCellAt>. - * - * Futhermore, nodes with the mode attribute may define a function to - * be executed upon selection of the respective toolbar icon. In the - * example below, the default edge style is set when this specific - * connect-mode is activated: - * - * (code) - * <add as="connect" mode="connect"><![CDATA[ - * function (editor) - * { - * if (editor.defaultEdge != null) - * { - * editor.defaultEdge.style = 'straightEdge'; - * } - * } - * ]]></add> - * (end) - * - * Modes: - * - * select - Left mouse button used for rubberband- & cell-selection. - * connect - Allows connecting vertices by inserting new edges. - * pan - Disables selection and switches to panning on the left button. - * - * Example: - * - * To add items to the toolbar: - * - * (code) - * <mxDefaultToolbar as="toolbar"> - * <add as="save" action="save" icon="images/save.gif"/> - * <br/><hr/> - * <add as="select" mode="select" icon="images/select.gif"/> - * <add as="connect" mode="connect" icon="images/connect.gif"/> - * </mxDefaultToolbar> - * (end) - */ - codec.decode = function(dec, node, into) - { - if (into != null) - { - var editor = into.editor; - node = node.firstChild; - - while (node != null) - { - if (node.nodeType == mxConstants.NODETYPE_ELEMENT) - { - if (!this.processInclude(dec, node, into)) - { - if (node.nodeName == 'separator') - { - into.addSeparator(); - } - else if (node.nodeName == 'br') - { - into.toolbar.addBreak(); - } - else if (node.nodeName == 'hr') - { - into.toolbar.addLine(); - } - else if (node.nodeName == 'add') - { - var as = node.getAttribute('as'); - as = mxResources.get(as) || as; - var icon = node.getAttribute('icon'); - var pressedIcon = node.getAttribute('pressedIcon'); - var action = node.getAttribute('action'); - var mode = node.getAttribute('mode'); - var template = node.getAttribute('template'); - var toggle = node.getAttribute('toggle') != '0'; - var text = mxUtils.getTextContent(node); - var elt = null; - - if (action != null) - { - elt = into.addItem(as, icon, action, pressedIcon); - } - else if (mode != null) - { - var funct = mxUtils.eval(text); - elt = into.addMode(as, icon, mode, pressedIcon, funct); - } - else if (template != null || (text != null && text.length > 0)) - { - var cell = editor.templates[template]; - var style = node.getAttribute('style'); - - if (cell != null && style != null) - { - cell = cell.clone(); - cell.setStyle(style); - } - - var insertFunction = null; - - if (text != null && text.length > 0) - { - insertFunction = mxUtils.eval(text); - } - - elt = into.addPrototype(as, icon, cell, pressedIcon, insertFunction, toggle); - } - else - { - var children = mxUtils.getChildNodes(node); - - if (children.length > 0) - { - if (icon == null) - { - var combo = into.addActionCombo(as); - - for (var i=0; i<children.length; i++) - { - var child = children[i]; - - if (child.nodeName == 'separator') - { - into.addOption(combo, '---'); - } - else if (child.nodeName == 'add') - { - var lab = child.getAttribute('as'); - var act = child.getAttribute('action'); - into.addActionOption(combo, lab, act); - } - } - } - else - { - var select = null; - var create = function() - { - var template = editor.templates[select.value]; - - if (template != null) - { - var clone = template.clone(); - var style = select.options[select.selectedIndex].cellStyle; - - if (style != null) - { - clone.setStyle(style); - } - - return clone; - } - else - { - mxLog.warn('Template '+template+' not found'); - } - - return null; - }; - - var img = into.addPrototype(as, icon, create, null, null, toggle); - select = into.addCombo(); - - // Selects the toolbar icon if a selection change - // is made in the corresponding combobox. - mxEvent.addListener(select, 'change', function() - { - into.toolbar.selectMode(img, function(evt) - { - var pt = mxUtils.convertPoint(editor.graph.container, - mxEvent.getClientX(evt), mxEvent.getClientY(evt)); - - return editor.addVertex(null, funct(), pt.x, pt.y); - }); - - into.toolbar.noReset = false; - }); - - // Adds the entries to the combobox - for (var i=0; i<children.length; i++) - { - var child = children[i]; - - if (child.nodeName == 'separator') - { - into.addOption(select, '---'); - } - else if (child.nodeName == 'add') - { - var lab = child.getAttribute('as'); - var tmp = child.getAttribute('template'); - var option = into.addOption(select, lab, tmp || template); - option.cellStyle = child.getAttribute('style'); - } - } - - } - } - } - - // Assigns an ID to the created element to access it later. - if (elt != null) - { - var id = node.getAttribute('id'); - - if (id != null && id.length > 0) - { - elt.setAttribute('id', id); - } - } - } - } - } - - node = node.nextSibling; - } - } - - return into; - }; - - // Returns the codec into the registry - return codec; - -}()); diff --git a/src/js/io/mxEditorCodec.js b/src/js/io/mxEditorCodec.js deleted file mode 100644 index f61bd95..0000000 --- a/src/js/io/mxEditorCodec.js +++ /dev/null @@ -1,246 +0,0 @@ -/** - * $Id: mxEditorCodec.js,v 1.11 2010-01-04 11:18:26 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -mxCodecRegistry.register(function() -{ - /** - * Class: mxEditorCodec - * - * Codec for <mxEditor>s. This class is created and registered - * dynamically at load time and used implicitely via <mxCodec> - * and the <mxCodecRegistry>. - * - * Transient Fields: - * - * - modified - * - lastSnapshot - * - ignoredChanges - * - undoManager - * - graphContainer - * - toolbarContainer - */ - var codec = new mxObjectCodec(new mxEditor(), - ['modified', 'lastSnapshot', 'ignoredChanges', - 'undoManager', 'graphContainer', 'toolbarContainer']); - - /** - * Function: beforeDecode - * - * Decodes the ui-part of the configuration node by reading - * a sequence of the following child nodes and attributes - * and passes the control to the default decoding mechanism: - * - * Child Nodes: - * - * stylesheet - Adds a CSS stylesheet to the document. - * resource - Adds the basename of a resource bundle. - * add - Creates or configures a known UI element. - * - * These elements may appear in any order given that the - * graph UI element is added before the toolbar element - * (see Known Keys). - * - * Attributes: - * - * as - Key for the UI element (see below). - * element - ID for the element in the document. - * style - CSS style to be used for the element or window. - * x - X coordinate for the new window. - * y - Y coordinate for the new window. - * width - Width for the new window. - * height - Optional height for the new window. - * name - Name of the stylesheet (absolute/relative URL). - * basename - Basename of the resource bundle (see <mxResources>). - * - * The x, y, width and height attributes are used to create a new - * <mxWindow> if the element attribute is not specified in an add - * node. The name and basename are only used in the stylesheet and - * resource nodes, respectively. - * - * Known Keys: - * - * graph - Main graph element (see <mxEditor.setGraphContainer>). - * title - Title element (see <mxEditor.setTitleContainer>). - * toolbar - Toolbar element (see <mxEditor.setToolbarContainer>). - * status - Status bar element (see <mxEditor.setStatusContainer>). - * - * Example: - * - * (code) - * <ui> - * <stylesheet name="css/process.css"/> - * <resource basename="resources/mxApplication"/> - * <add as="graph" element="graph" - * style="left:70px;right:20px;top:20px;bottom:40px"/> - * <add as="status" element="status"/> - * <add as="toolbar" x="10" y="20" width="54"/> - * </ui> - * (end) - */ - codec.afterDecode = function(dec, node, obj) - { - // Assigns the specified templates for edges - var defaultEdge = node.getAttribute('defaultEdge'); - - if (defaultEdge != null) - { - node.removeAttribute('defaultEdge'); - obj.defaultEdge = obj.templates[defaultEdge]; - } - - // Assigns the specified templates for groups - var defaultGroup = node.getAttribute('defaultGroup'); - - if (defaultGroup != null) - { - node.removeAttribute('defaultGroup'); - obj.defaultGroup = obj.templates[defaultGroup]; - } - - return obj; - }; - - /** - * Function: decodeChild - * - * Overrides decode child to handle special child nodes. - */ - codec.decodeChild = function(dec, child, obj) - { - if (child.nodeName == 'Array') - { - var role = child.getAttribute('as'); - - if (role == 'templates') - { - this.decodeTemplates(dec, child, obj); - return; - } - } - else if (child.nodeName == 'ui') - { - this.decodeUi(dec, child, obj); - return; - } - - mxObjectCodec.prototype.decodeChild.apply(this, arguments); - }; - - /** - * Function: decodeTemplates - * - * Decodes the cells from the given node as templates. - */ - codec.decodeUi = function(dec, node, editor) - { - var tmp = node.firstChild; - while (tmp != null) - { - if (tmp.nodeName == 'add') - { - var as = tmp.getAttribute('as'); - var elt = tmp.getAttribute('element'); - var style = tmp.getAttribute('style'); - var element = null; - - if (elt != null) - { - element = document.getElementById(elt); - - if (element != null && - style != null) - { - element.style.cssText += ';'+style; - } - } - else - { - var x = parseInt(tmp.getAttribute('x')); - var y = parseInt(tmp.getAttribute('y')); - var width = tmp.getAttribute('width'); - var height = tmp.getAttribute('height'); - - // Creates a new window around the element - element = document.createElement('div'); - element.style.cssText = style; - - var wnd = new mxWindow(mxResources.get(as) || as, - element, x, y, width, height, false, true); - wnd.setVisible(true); - } - - // TODO: Make more generic - if (as == 'graph') - { - editor.setGraphContainer(element); - } - else if (as == 'toolbar') - { - editor.setToolbarContainer(element); - } - else if (as == 'title') - { - editor.setTitleContainer(element); - } - else if (as == 'status') - { - editor.setStatusContainer(element); - } - else if (as == 'map') - { - editor.setMapContainer(element); - } - } - else if (tmp.nodeName == 'resource') - { - mxResources.add(tmp.getAttribute('basename')); - } - else if (tmp.nodeName == 'stylesheet') - { - mxClient.link('stylesheet', tmp.getAttribute('name')); - } - - tmp = tmp.nextSibling; - } - }; - - /** - * Function: decodeTemplates - * - * Decodes the cells from the given node as templates. - */ - codec.decodeTemplates = function(dec, node, editor) - { - if (editor.templates == null) - { - editor.templates = []; - } - - var children = mxUtils.getChildNodes(node); - for (var j=0; j<children.length; j++) - { - var name = children[j].getAttribute('as'); - var child = children[j].firstChild; - - while (child != null && child.nodeType != 1) - { - child = child.nextSibling; - } - - if (child != null) - { - // LATER: Only single cells means you need - // to group multiple cells within another - // cell. This should be changed to support - // arrays of cells, or the wrapper must - // be automatically handled in this class. - editor.templates[name] = dec.decodeCell(child); - } - } - }; - - // Returns the codec into the registry - return codec; - -}()); diff --git a/src/js/io/mxGenericChangeCodec.js b/src/js/io/mxGenericChangeCodec.js deleted file mode 100644 index 8da7789..0000000 --- a/src/js/io/mxGenericChangeCodec.js +++ /dev/null @@ -1,64 +0,0 @@ -/** - * $Id: mxGenericChangeCodec.js,v 1.11 2010-09-13 15:50:36 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -/** - * Class: mxGenericChangeCodec - * - * Codec for <mxValueChange>s, <mxStyleChange>s, <mxGeometryChange>s, - * <mxCollapseChange>s and <mxVisibleChange>s. This class is created - * and registered dynamically at load time and used implicitely - * via <mxCodec> and the <mxCodecRegistry>. - * - * Transient Fields: - * - * - model - * - previous - * - * Reference Fields: - * - * - cell - * - * Constructor: mxGenericChangeCodec - * - * Factory function that creates a <mxObjectCodec> for - * the specified change and fieldname. - * - * Parameters: - * - * obj - An instance of the change object. - * variable - The fieldname for the change data. - */ -var mxGenericChangeCodec = function(obj, variable) -{ - var codec = new mxObjectCodec(obj, ['model', 'previous'], ['cell']); - - /** - * Function: afterDecode - * - * Restores the state by assigning the previous value. - */ - codec.afterDecode = function(dec, node, obj) - { - // Allows forward references in sessions. This is a workaround - // for the sequence of edits in mxGraph.moveCells and cellsAdded. - if (mxUtils.isNode(obj.cell)) - { - obj.cell = dec.decodeCell(obj.cell, false); - } - - obj.previous = obj[variable]; - - return obj; - }; - - return codec; -}; - -// Registers the codecs -mxCodecRegistry.register(mxGenericChangeCodec(new mxValueChange(), 'value')); -mxCodecRegistry.register(mxGenericChangeCodec(new mxStyleChange(), 'style')); -mxCodecRegistry.register(mxGenericChangeCodec(new mxGeometryChange(), 'geometry')); -mxCodecRegistry.register(mxGenericChangeCodec(new mxCollapseChange(), 'collapsed')); -mxCodecRegistry.register(mxGenericChangeCodec(new mxVisibleChange(), 'visible')); -mxCodecRegistry.register(mxGenericChangeCodec(new mxCellAttributeChange(), 'value')); diff --git a/src/js/io/mxGraphCodec.js b/src/js/io/mxGraphCodec.js deleted file mode 100644 index f052e13..0000000 --- a/src/js/io/mxGraphCodec.js +++ /dev/null @@ -1,28 +0,0 @@ -/** - * $Id: mxGraphCodec.js,v 1.8 2010-06-10 06:54:18 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -mxCodecRegistry.register(function() -{ - /** - * Class: mxGraphCodec - * - * Codec for <mxGraph>s. This class is created and registered - * dynamically at load time and used implicitely via <mxCodec> - * and the <mxCodecRegistry>. - * - * Transient Fields: - * - * - graphListeners - * - eventListeners - * - view - * - container - * - cellRenderer - * - editor - * - selection - */ - return new mxObjectCodec(new mxGraph(), - ['graphListeners', 'eventListeners', 'view', 'container', - 'cellRenderer', 'editor', 'selection']); - -}()); diff --git a/src/js/io/mxGraphViewCodec.js b/src/js/io/mxGraphViewCodec.js deleted file mode 100644 index 110b212..0000000 --- a/src/js/io/mxGraphViewCodec.js +++ /dev/null @@ -1,197 +0,0 @@ -/** - * $Id: mxGraphViewCodec.js,v 1.18 2010-12-03 11:05:52 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -mxCodecRegistry.register(function() -{ - /** - * Class: mxGraphViewCodec - * - * Custom encoder for <mxGraphView>s. This class is created - * and registered dynamically at load time and used implicitely via - * <mxCodec> and the <mxCodecRegistry>. This codec only writes views - * into a XML format that can be used to create an image for - * the graph, that is, it contains absolute coordinates with - * computed perimeters, edge styles and cell styles. - */ - var codec = new mxObjectCodec(new mxGraphView()); - - /** - * Function: encode - * - * Encodes the given <mxGraphView> using <encodeCell> - * starting at the model's root. This returns the - * top-level graph node of the recursive encoding. - */ - codec.encode = function(enc, view) - { - return this.encodeCell(enc, view, - view.graph.getModel().getRoot()); - }; - - /** - * Function: encodeCell - * - * Recursively encodes the specifed cell. Uses layer - * as the default nodename. If the cell's parent is - * null, then graph is used for the nodename. If - * <mxGraphModel.isEdge> returns true for the cell, - * then edge is used for the nodename, else if - * <mxGraphModel.isVertex> returns true for the cell, - * then vertex is used for the nodename. - * - * <mxGraph.getLabel> is used to create the label - * attribute for the cell. For graph nodes and vertices - * the bounds are encoded into x, y, width and height. - * For edges the points are encoded into a points - * attribute as a space-separated list of comma-separated - * coordinate pairs (eg. x0,y0 x1,y1 ... xn,yn). All - * values from the cell style are added as attribute - * values to the node. - */ - codec.encodeCell = function(enc, view, cell) - { - var model = view.graph.getModel(); - var state = view.getState(cell); - var parent = model.getParent(cell); - - if (parent == null || state != null) - { - var childCount = model.getChildCount(cell); - var geo = view.graph.getCellGeometry(cell); - var name = null; - - if (parent == model.getRoot()) - { - name = 'layer'; - } - else if (parent == null) - { - name = 'graph'; - } - else if (model.isEdge(cell)) - { - name = 'edge'; - } - else if (childCount > 0 && geo != null) - { - name = 'group'; - } - else if (model.isVertex(cell)) - { - name = 'vertex'; - } - - if (name != null) - { - var node = enc.document.createElement(name); - var lab = view.graph.getLabel(cell); - - if (lab != null) - { - node.setAttribute('label', view.graph.getLabel(cell)); - - if (view.graph.isHtmlLabel(cell)) - { - node.setAttribute('html', true); - } - } - - if (parent == null) - { - var bounds = view.getGraphBounds(); - - if (bounds != null) - { - node.setAttribute('x', Math.round(bounds.x)); - node.setAttribute('y', Math.round(bounds.y)); - node.setAttribute('width', Math.round(bounds.width)); - node.setAttribute('height', Math.round(bounds.height)); - } - - node.setAttribute('scale', view.scale); - } - else if (state != null && geo != null) - { - // Writes each key, value in the style pair to an attribute - for (var i in state.style) - { - var value = state.style[i]; - - // Tries to turn objects and functions into strings - if (typeof(value) == 'function' && - typeof(value) == 'object') - { - value = mxStyleRegistry.getName(value); - } - - if (value != null && - typeof(value) != 'function' && - typeof(value) != 'object') - { - node.setAttribute(i, value); - } - } - - var abs = state.absolutePoints; - - // Writes the list of points into one attribute - if (abs != null && abs.length > 0) - { - var pts = Math.round(abs[0].x) + ',' + Math.round(abs[0].y); - - for (var i=1; i<abs.length; i++) - { - pts += ' ' + Math.round(abs[i].x) + ',' + - Math.round(abs[i].y); - } - - node.setAttribute('points', pts); - } - - // Writes the bounds into 4 attributes - else - { - node.setAttribute('x', Math.round(state.x)); - node.setAttribute('y', Math.round(state.y)); - node.setAttribute('width', Math.round(state.width)); - node.setAttribute('height', Math.round(state.height)); - } - - var offset = state.absoluteOffset; - - // Writes the offset into 2 attributes - if (offset != null) - { - if (offset.x != 0) - { - node.setAttribute('dx', Math.round(offset.x)); - } - - if (offset.y != 0) - { - node.setAttribute('dy', Math.round(offset.y)); - } - } - } - - for (var i=0; i<childCount; i++) - { - var childNode = this.encodeCell(enc, - view, model.getChildAt(cell, i)); - - if (childNode != null) - { - node.appendChild(childNode); - } - } - } - } - - return node; - }; - - // Returns the codec into the registry - return codec; - -}()); diff --git a/src/js/io/mxModelCodec.js b/src/js/io/mxModelCodec.js deleted file mode 100644 index 760a2b1..0000000 --- a/src/js/io/mxModelCodec.js +++ /dev/null @@ -1,80 +0,0 @@ -/** - * $Id: mxModelCodec.js,v 1.11 2010-11-23 08:46:41 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -mxCodecRegistry.register(function() -{ - /** - * Class: mxModelCodec - * - * Codec for <mxGraphModel>s. This class is created and registered - * dynamically at load time and used implicitely via <mxCodec> - * and the <mxCodecRegistry>. - */ - var codec = new mxObjectCodec(new mxGraphModel()); - - /** - * Function: encodeObject - * - * Encodes the given <mxGraphModel> by writing a (flat) XML sequence of - * cell nodes as produced by the <mxCellCodec>. The sequence is - * wrapped-up in a node with the name root. - */ - codec.encodeObject = function(enc, obj, node) - { - var rootNode = enc.document.createElement('root'); - enc.encodeCell(obj.getRoot(), rootNode); - node.appendChild(rootNode); - }; - - /** - * Function: decodeChild - * - * Overrides decode child to handle special child nodes. - */ - codec.decodeChild = function(dec, child, obj) - { - if (child.nodeName == 'root') - { - this.decodeRoot(dec, child, obj); - } - else - { - mxObjectCodec.prototype.decodeChild.apply(this, arguments); - } - }; - - /** - * Function: decodeRoot - * - * Reads the cells into the graph model. All cells - * are children of the root element in the node. - */ - codec.decodeRoot = function(dec, root, model) - { - var rootCell = null; - var tmp = root.firstChild; - - while (tmp != null) - { - var cell = dec.decodeCell(tmp); - - if (cell != null && cell.getParent() == null) - { - rootCell = cell; - } - - tmp = tmp.nextSibling; - } - - // Sets the root on the model if one has been decoded - if (rootCell != null) - { - model.setRoot(rootCell); - } - }; - - // Returns the codec into the registry - return codec; - -}()); diff --git a/src/js/io/mxObjectCodec.js b/src/js/io/mxObjectCodec.js deleted file mode 100644 index 9d2473a..0000000 --- a/src/js/io/mxObjectCodec.js +++ /dev/null @@ -1,983 +0,0 @@ -/** - * $Id: mxObjectCodec.js,v 1.49 2010-12-01 09:19:58 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -/** - * Class: mxObjectCodec - * - * Generic codec for JavaScript objects that implements a mapping between - * JavaScript objects and XML nodes that maps each field or element to an - * attribute or child node, and vice versa. - * - * Atomic Values: - * - * Consider the following example. - * - * (code) - * var obj = new Object(); - * obj.foo = "Foo"; - * obj.bar = "Bar"; - * (end) - * - * This object is encoded into an XML node using the following. - * - * (code) - * var enc = new mxCodec(); - * var node = enc.encode(obj); - * (end) - * - * The output of the encoding may be viewed using <mxLog> as follows. - * - * (code) - * mxLog.show(); - * mxLog.debug(mxUtils.getPrettyXml(node)); - * (end) - * - * Finally, the result of the encoding looks as follows. - * - * (code) - * <Object foo="Foo" bar="Bar"/> - * (end) - * - * In the above output, the foo and bar fields have been mapped to attributes - * with the same names, and the name of the constructor was used for the - * nodename. - * - * Booleans: - * - * Since booleans are numbers in JavaScript, all boolean values are encoded - * into 1 for true and 0 for false. The decoder also accepts the string true - * and false for boolean values. - * - * Objects: - * - * The above scheme is applied to all atomic fields, that is, to all non-object - * fields of an object. For object fields, a child node is created with a - * special attribute that contains the fieldname. This special attribute is - * called "as" and hence, as is a reserved word that should not be used for a - * fieldname. - * - * Consider the following example where foo is an object and bar is an atomic - * property of foo. - * - * (code) - * var obj = {foo: {bar: "Bar"}}; - * (end) - * - * This will be mapped to the following XML structure by mxObjectCodec. - * - * (code) - * <Object> - * <Object bar="Bar" as="foo"/> - * </Object> - * (end) - * - * In the above output, the inner Object node contains the as-attribute that - * specifies the fieldname in the enclosing object. That is, the field foo was - * mapped to a child node with an as-attribute that has the value foo. - * - * Arrays: - * - * Arrays are special objects that are either associative, in which case each - * key, value pair is treated like a field where the key is the fieldname, or - * they are a sequence of atomic values and objects, which is mapped to a - * sequence of child nodes. For object elements, the above scheme is applied - * without the use of the special as-attribute for creating each child. For - * atomic elements, a special add-node is created with the value stored in the - * value-attribute. - * - * For example, the following array contains one atomic value and one object - * with a field called bar. Furthermore it contains two associative entries - * called bar with an atomic value, and foo with an object value. - * - * (code) - * var obj = ["Bar", {bar: "Bar"}]; - * obj["bar"] = "Bar"; - * obj["foo"] = {bar: "Bar"}; - * (end) - * - * This array is represented by the following XML nodes. - * - * (code) - * <Array bar="Bar"> - * <add value="Bar"/> - * <Object bar="Bar"/> - * <Object bar="Bar" as="foo"/> - * </Array> - * (end) - * - * The Array node name is the name of the constructor. The additional - * as-attribute in the last child contains the key of the associative entry, - * whereas the second last child is part of the array sequence and does not - * have an as-attribute. - * - * References: - * - * Objects may be represented as child nodes or attributes with ID values, - * which are used to lookup the object in a table within <mxCodec>. The - * <isReference> function is in charge of deciding if a specific field should - * be encoded as a reference or not. Its default implementation returns true if - * the fieldname is in <idrefs>, an array of strings that is used to configure - * the <mxObjectCodec>. - * - * Using this approach, the mapping does not guarantee that the referenced - * object itself exists in the document. The fields that are encoded as - * references must be carefully chosen to make sure all referenced objects - * exist in the document, or may be resolved by some other means if necessary. - * - * For example, in the case of the graph model all cells are stored in a tree - * whose root is referenced by the model's root field. A tree is a structure - * that is well suited for an XML representation, however, the additional edges - * in the graph model have a reference to a source and target cell, which are - * also contained in the tree. To handle this case, the source and target cell - * of an edge are treated as references, whereas the children are treated as - * objects. Since all cells are contained in the tree and no edge references a - * source or target outside the tree, this setup makes sure all referenced - * objects are contained in the document. - * - * In the case of a tree structure we must further avoid infinite recursion by - * ignoring the parent reference of each child. This is done by returning true - * in <isExcluded>, whose default implementation uses the array of excluded - * fieldnames passed to the mxObjectCodec constructor. - * - * References are only used for cells in mxGraph. For defining other - * referencable object types, the codec must be able to work out the ID of an - * object. This is done by implementing <mxCodec.reference>. For decoding a - * reference, the XML node with the respective id-attribute is fetched from the - * document, decoded, and stored in a lookup table for later reference. For - * looking up external objects, <mxCodec.lookup> may be implemented. - * - * Expressions: - * - * For decoding JavaScript expressions, the add-node may be used with a text - * content that contains the JavaScript expression. For example, the following - * creates a field called foo in the enclosing object and assigns it the value - * of <mxConstants.ALIGN_LEFT>. - * - * (code) - * <Object> - * <add as="foo">mxConstants.ALIGN_LEFT</add> - * </Object> - * (end) - * - * The resulting object has a field called foo with the value "left". Its XML - * representation looks as follows. - * - * (code) - * <Object foo="left"/> - * (end) - * - * This means the expression is evaluated at decoding time and the result of - * the evaluation is stored in the respective field. Valid expressions are all - * JavaScript expressions, including function definitions, which are mapped to - * functions on the resulting object. - * - * Constructor: mxObjectCodec - * - * Constructs a new codec for the specified template object. - * The variables in the optional exclude array are ignored by - * the codec. Variables in the optional idrefs array are - * turned into references in the XML. The optional mapping - * may be used to map from variable names to XML attributes. - * The argument is created as follows: - * - * (code) - * var mapping = new Object(); - * mapping['variableName'] = 'attribute-name'; - * (end) - * - * Parameters: - * - * template - Prototypical instance of the object to be - * encoded/decoded. - * exclude - Optional array of fieldnames to be ignored. - * idrefs - Optional array of fieldnames to be converted to/from - * references. - * mapping - Optional mapping from field- to attributenames. - */ -function mxObjectCodec(template, exclude, idrefs, mapping) -{ - this.template = template; - - this.exclude = (exclude != null) ? exclude : []; - this.idrefs = (idrefs != null) ? idrefs : []; - this.mapping = (mapping != null) ? mapping : []; - - this.reverse = new Object(); - - for (var i in this.mapping) - { - this.reverse[this.mapping[i]] = i; - } -}; - -/** - * Variable: template - * - * Holds the template object associated with this codec. - */ -mxObjectCodec.prototype.template = null; - -/** - * Variable: exclude - * - * Array containing the variable names that should be - * ignored by the codec. - */ -mxObjectCodec.prototype.exclude = null; - -/** - * Variable: idrefs - * - * Array containing the variable names that should be - * turned into or converted from references. See - * <mxCodec.getId> and <mxCodec.getObject>. - */ -mxObjectCodec.prototype.idrefs = null; - -/** - * Variable: mapping - * - * Maps from from fieldnames to XML attribute names. - */ -mxObjectCodec.prototype.mapping = null; - -/** - * Variable: reverse - * - * Maps from from XML attribute names to fieldnames. - */ -mxObjectCodec.prototype.reverse = null; - -/** - * Function: getName - * - * Returns the name used for the nodenames and lookup of the codec when - * classes are encoded and nodes are decoded. For classes to work with - * this the codec registry automatically adds an alias for the classname - * if that is different than what this returns. The default implementation - * returns the classname of the template class. - */ -mxObjectCodec.prototype.getName = function() -{ - return mxUtils.getFunctionName(this.template.constructor); -}; - -/** - * Function: cloneTemplate - * - * Returns a new instance of the template for this codec. - */ -mxObjectCodec.prototype.cloneTemplate = function() -{ - return new this.template.constructor(); -}; - -/** - * Function: getFieldName - * - * Returns the fieldname for the given attributename. - * Looks up the value in the <reverse> mapping or returns - * the input if there is no reverse mapping for the - * given name. - */ -mxObjectCodec.prototype.getFieldName = function(attributename) -{ - if (attributename != null) - { - var mapped = this.reverse[attributename]; - - if (mapped != null) - { - attributename = mapped; - } - } - - return attributename; -}; - -/** - * Function: getAttributeName - * - * Returns the attributename for the given fieldname. - * Looks up the value in the <mapping> or returns - * the input if there is no mapping for the - * given name. - */ -mxObjectCodec.prototype.getAttributeName = function(fieldname) -{ - if (fieldname != null) - { - var mapped = this.mapping[fieldname]; - - if (mapped != null) - { - fieldname = mapped; - } - } - - return fieldname; -}; - -/** - * Function: isExcluded - * - * Returns true if the given attribute is to be ignored by the codec. This - * implementation returns true if the given fieldname is in <exclude> or - * if the fieldname equals <mxObjectIdentity.FIELD_NAME>. - * - * Parameters: - * - * obj - Object instance that contains the field. - * attr - Fieldname of the field. - * value - Value of the field. - * write - Boolean indicating if the field is being encoded or decoded. - * Write is true if the field is being encoded, else it is being decoded. - */ -mxObjectCodec.prototype.isExcluded = function(obj, attr, value, write) -{ - return attr == mxObjectIdentity.FIELD_NAME || - mxUtils.indexOf(this.exclude, attr) >= 0; -}; - -/** - * Function: isReference - * - * Returns true if the given fieldname is to be treated - * as a textual reference (ID). This implementation returns - * true if the given fieldname is in <idrefs>. - * - * Parameters: - * - * obj - Object instance that contains the field. - * attr - Fieldname of the field. - * value - Value of the field. - * write - Boolean indicating if the field is being encoded or decoded. - * Write is true if the field is being encoded, else it is being decoded. - */ -mxObjectCodec.prototype.isReference = function(obj, attr, value, write) -{ - return mxUtils.indexOf(this.idrefs, attr) >= 0; -}; - -/** - * Function: encode - * - * Encodes the specified object and returns a node - * representing then given object. Calls <beforeEncode> - * after creating the node and <afterEncode> with the - * resulting node after processing. - * - * Enc is a reference to the calling encoder. It is used - * to encode complex objects and create references. - * - * This implementation encodes all variables of an - * object according to the following rules: - * - * - If the variable name is in <exclude> then it is ignored. - * - If the variable name is in <idrefs> then <mxCodec.getId> - * is used to replace the object with its ID. - * - The variable name is mapped using <mapping>. - * - If obj is an array and the variable name is numeric - * (ie. an index) then it is not encoded. - * - If the value is an object, then the codec is used to - * create a child node with the variable name encoded into - * the "as" attribute. - * - Else, if <encodeDefaults> is true or the value differs - * from the template value, then ... - * - ... if obj is not an array, then the value is mapped to - * an attribute. - * - ... else if obj is an array, the value is mapped to an - * add child with a value attribute or a text child node, - * if the value is a function. - * - * If no ID exists for a variable in <idrefs> or if an object - * cannot be encoded, a warning is issued using <mxLog.warn>. - * - * Returns the resulting XML node that represents the given - * object. - * - * Parameters: - * - * enc - <mxCodec> that controls the encoding process. - * obj - Object to be encoded. - */ -mxObjectCodec.prototype.encode = function(enc, obj) -{ - var node = enc.document.createElement(this.getName()); - - obj = this.beforeEncode(enc, obj, node); - this.encodeObject(enc, obj, node); - - return this.afterEncode(enc, obj, node); -}; - -/** - * Function: encodeObject - * - * Encodes the value of each member in then given obj into the given node using - * <encodeValue>. - * - * Parameters: - * - * enc - <mxCodec> that controls the encoding process. - * obj - Object to be encoded. - * node - XML node that contains the encoded object. - */ -mxObjectCodec.prototype.encodeObject = function(enc, obj, node) -{ - enc.setAttribute(node, 'id', enc.getId(obj)); - - for (var i in obj) - { - var name = i; - var value = obj[name]; - - if (value != null && !this.isExcluded(obj, name, value, true)) - { - if (mxUtils.isNumeric(name)) - { - name = null; - } - - this.encodeValue(enc, obj, name, value, node); - } - } -}; - -/** - * Function: encodeValue - * - * Converts the given value according to the mappings - * and id-refs in this codec and uses <writeAttribute> - * to write the attribute into the given node. - * - * Parameters: - * - * enc - <mxCodec> that controls the encoding process. - * obj - Object whose property is going to be encoded. - * name - XML node that contains the encoded object. - * value - Value of the property to be encoded. - * node - XML node that contains the encoded object. - */ -mxObjectCodec.prototype.encodeValue = function(enc, obj, - name, value, node) -{ - if (value != null) - { - if (this.isReference(obj, name, value, true)) - { - var tmp = enc.getId(value); - - if (tmp == null) - { - mxLog.warn('mxObjectCodec.encode: No ID for ' + - this.getName() + '.' + name + '=' + value); - return; // exit - } - - value = tmp; - } - - var defaultValue = this.template[name]; - - // Checks if the value is a default value and - // the name is correct - if (name == null || enc.encodeDefaults || - defaultValue != value) - { - name = this.getAttributeName(name); - this.writeAttribute(enc, obj, name, value, node); - } - } -}; - -/** - * Function: writeAttribute - * - * Writes the given value into node using <writePrimitiveAttribute> - * or <writeComplexAttribute> depending on the type of the value. - */ -mxObjectCodec.prototype.writeAttribute = function(enc, obj, - attr, value, node) -{ - if (typeof(value) != 'object' /* primitive type */) - { - this.writePrimitiveAttribute(enc, obj, attr, value, node); - } - else /* complex type */ - { - this.writeComplexAttribute(enc, obj, attr, value, node); - } -}; - -/** - * Function: writePrimitiveAttribute - * - * Writes the given value as an attribute of the given node. - */ -mxObjectCodec.prototype.writePrimitiveAttribute = function(enc, obj, - attr, value, node) -{ - value = this.convertValueToXml(value); - - if (attr == null) - { - var child = enc.document.createElement('add'); - - if (typeof(value) == 'function') - { - child.appendChild( - enc.document.createTextNode(value)); - } - else - { - enc.setAttribute(child, 'value', value); - } - - node.appendChild(child); - } - else if (typeof(value) != 'function') - { - enc.setAttribute(node, attr, value); - } -}; - -/** - * Function: writeComplexAttribute - * - * Writes the given value as a child node of the given node. - */ -mxObjectCodec.prototype.writeComplexAttribute = function(enc, obj, - attr, value, node) -{ - var child = enc.encode(value); - - if (child != null) - { - if (attr != null) - { - child.setAttribute('as', attr); - } - - node.appendChild(child); - } - else - { - mxLog.warn('mxObjectCodec.encode: No node for ' + - this.getName() + '.' + attr + ': ' + value); - } -}; - -/** - * Function: convertValueToXml - * - * Converts true to "1" and false to "0". All other values are ignored. - */ -mxObjectCodec.prototype.convertValueToXml = function(value) -{ - // Makes sure to encode boolean values as numeric values - if (typeof(value.length) == 'undefined' && - (value == true || - value == false)) - { - // Checks if the value is true (do not use the - // value as is, because this would check if the - // value is not null, so 0 would be true! - value = (value == true) ? '1' : '0'; - } - return value; -}; - -/** - * Function: convertValueFromXml - * - * Converts booleans and numeric values to the respective types. - */ -mxObjectCodec.prototype.convertValueFromXml = function(value) -{ - if (mxUtils.isNumeric(value)) - { - value = parseFloat(value); - } - - return value; -}; - -/** - * Function: beforeEncode - * - * Hook for subclassers to pre-process the object before - * encoding. This returns the input object. The return - * value of this function is used in <encode> to perform - * the default encoding into the given node. - * - * Parameters: - * - * enc - <mxCodec> that controls the encoding process. - * obj - Object to be encoded. - * node - XML node to encode the object into. - */ -mxObjectCodec.prototype.beforeEncode = function(enc, obj, node) -{ - return obj; -}; - -/** - * Function: afterEncode - * - * Hook for subclassers to post-process the node - * for the given object after encoding and return the - * post-processed node. This implementation returns - * the input node. The return value of this method - * is returned to the encoder from <encode>. - * - * Parameters: - * - * enc - <mxCodec> that controls the encoding process. - * obj - Object to be encoded. - * node - XML node that represents the default encoding. - */ -mxObjectCodec.prototype.afterEncode = function(enc, obj, node) -{ - return node; -}; - -/** - * Function: decode - * - * Parses the given node into the object or returns a new object - * representing the given node. - * - * Dec is a reference to the calling decoder. It is used to decode - * complex objects and resolve references. - * - * If a node has an id attribute then the object cache is checked for the - * object. If the object is not yet in the cache then it is constructed - * using the constructor of <template> and cached in <mxCodec.objects>. - * - * This implementation decodes all attributes and childs of a node - * according to the following rules: - * - * - If the variable name is in <exclude> or if the attribute name is "id" - * or "as" then it is ignored. - * - If the variable name is in <idrefs> then <mxCodec.getObject> is used - * to replace the reference with an object. - * - The variable name is mapped using a reverse <mapping>. - * - If the value has a child node, then the codec is used to create a - * child object with the variable name taken from the "as" attribute. - * - If the object is an array and the variable name is empty then the - * value or child object is appended to the array. - * - If an add child has no value or the object is not an array then - * the child text content is evaluated using <mxUtils.eval>. - * - * For add nodes where the object is not an array and the variable name - * is defined, the default mechanism is used, allowing to override/add - * methods as follows: - * - * (code) - * <Object> - * <add as="hello"><![CDATA[ - * function(arg1) { - * mxUtils.alert('Hello '+arg1); - * } - * ]]></add> - * </Object> - * (end) - * - * If no object exists for an ID in <idrefs> a warning is issued - * using <mxLog.warn>. - * - * Returns the resulting object that represents the given XML node - * or the object given to the method as the into parameter. - * - * Parameters: - * - * dec - <mxCodec> that controls the decoding process. - * node - XML node to be decoded. - * into - Optional objec to encode the node into. - */ -mxObjectCodec.prototype.decode = function(dec, node, into) -{ - var id = node.getAttribute('id'); - var obj = dec.objects[id]; - - if (obj == null) - { - obj = into || this.cloneTemplate(); - - if (id != null) - { - dec.putObject(id, obj); - } - } - - node = this.beforeDecode(dec, node, obj); - this.decodeNode(dec, node, obj); - - return this.afterDecode(dec, node, obj); -}; - -/** - * Function: decodeNode - * - * Calls <decodeAttributes> and <decodeChildren> for the given node. - */ -mxObjectCodec.prototype.decodeNode = function(dec, node, obj) -{ - if (node != null) - { - this.decodeAttributes(dec, node, obj); - this.decodeChildren(dec, node, obj); - } -}; - -/** - * Function: decodeAttributes - * - * Decodes all attributes of the given node using <decodeAttribute>. - */ -mxObjectCodec.prototype.decodeAttributes = function(dec, node, obj) -{ - var attrs = node.attributes; - - if (attrs != null) - { - for (var i = 0; i < attrs.length; i++) - { - this.decodeAttribute(dec, attrs[i], obj); - } - } -}; - -/** - * Function: decodeAttribute - * - * Reads the given attribute into the specified object. - */ -mxObjectCodec.prototype.decodeAttribute = function(dec, attr, obj) -{ - var name = attr.nodeName; - - if (name != 'as' && name != 'id') - { - // Converts the string true and false to their boolean values. - // This may require an additional check on the obj to see if - // the existing field is a boolean value or uninitialized, in - // which case we may want to convert true and false to a string. - var value = this.convertValueFromXml(attr.nodeValue); - var fieldname = this.getFieldName(name); - - if (this.isReference(obj, fieldname, value, false)) - { - var tmp = dec.getObject(value); - - if (tmp == null) - { - mxLog.warn('mxObjectCodec.decode: No object for ' + - this.getName() + '.' + name + '=' + value); - return; // exit - } - - value = tmp; - } - - if (!this.isExcluded(obj, name, value, false)) - { - //mxLog.debug(mxUtils.getFunctionName(obj.constructor)+'.'+name+'='+value); - obj[name] = value; - } - } -}; - -/** - * Function: decodeChildren - * - * Decodec all children of the given node using <decodeChild>. - */ -mxObjectCodec.prototype.decodeChildren = function(dec, node, obj) -{ - var child = node.firstChild; - - while (child != null) - { - var tmp = child.nextSibling; - - if (child.nodeType == mxConstants.NODETYPE_ELEMENT && - !this.processInclude(dec, child, obj)) - { - this.decodeChild(dec, child, obj); - } - - child = tmp; - } -}; - -/** - * Function: decodeChild - * - * Reads the specified child into the given object. - */ -mxObjectCodec.prototype.decodeChild = function(dec, child, obj) -{ - var fieldname = this.getFieldName(child.getAttribute('as')); - - if (fieldname == null || - !this.isExcluded(obj, fieldname, child, false)) - { - var template = this.getFieldTemplate(obj, fieldname, child); - var value = null; - - if (child.nodeName == 'add') - { - value = child.getAttribute('value'); - - if (value == null) - { - value = mxUtils.eval(mxUtils.getTextContent(child)); - //mxLog.debug('Decoded '+fieldname+' '+mxUtils.getTextContent(child)); - } - } - else - { - value = dec.decode(child, template); - // mxLog.debug('Decoded '+node.nodeName+'.'+fieldname+'='+ - // ((tmp != null) ? tmp.constructor.name : 'null')); - } - - this.addObjectValue(obj, fieldname, value, template); - } -}; - -/** - * Function: getFieldTemplate - * - * Returns the template instance for the given field. This returns the - * value of the field, null if the value is an array or an empty collection - * if the value is a collection. The value is then used to populate the - * field for a new instance. For strongly typed languages it may be - * required to override this to return the correct collection instance - * based on the encoded child. - */ -mxObjectCodec.prototype.getFieldTemplate = function(obj, fieldname, child) -{ - var template = obj[fieldname]; - - // Non-empty arrays are replaced completely - if (template instanceof Array && template.length > 0) - { - template = null; - } - - return template; -}; - -/** - * Function: addObjectValue - * - * Sets the decoded child node as a value of the given object. If the - * object is a map, then the value is added with the given fieldname as a - * key. If the fieldname is not empty, then setFieldValue is called or - * else, if the object is a collection, the value is added to the - * collection. For strongly typed languages it may be required to - * override this with the correct code to add an entry to an object. - */ -mxObjectCodec.prototype.addObjectValue = function(obj, fieldname, value, template) -{ - if (value != null && value != template) - { - if (fieldname != null && fieldname.length > 0) - { - obj[fieldname] = value; - } - else - { - obj.push(value); - } - //mxLog.debug('Decoded '+mxUtils.getFunctionName(obj.constructor)+'.'+fieldname+': '+value); - } -}; - -/** - * Function: processInclude - * - * Returns true if the given node is an include directive and - * executes the include by decoding the XML document. Returns - * false if the given node is not an include directive. - * - * Parameters: - * - * dec - <mxCodec> that controls the encoding/decoding process. - * node - XML node to be checked. - * into - Optional object to pass-thru to the codec. - */ -mxObjectCodec.prototype.processInclude = function(dec, node, into) -{ - if (node.nodeName == 'include') - { - var name = node.getAttribute('name'); - - if (name != null) - { - try - { - var xml = mxUtils.load(name).getDocumentElement(); - - if (xml != null) - { - dec.decode(xml, into); - } - } - catch (e) - { - // ignore - } - } - - return true; - } - - return false; -}; - -/** - * Function: beforeDecode - * - * Hook for subclassers to pre-process the node for - * the specified object and return the node to be - * used for further processing by <decode>. - * The object is created based on the template in the - * calling method and is never null. This implementation - * returns the input node. The return value of this - * function is used in <decode> to perform - * the default decoding into the given object. - * - * Parameters: - * - * dec - <mxCodec> that controls the decoding process. - * node - XML node to be decoded. - * obj - Object to encode the node into. - */ -mxObjectCodec.prototype.beforeDecode = function(dec, node, obj) -{ - return node; -}; - -/** - * Function: afterDecode - * - * Hook for subclassers to post-process the object after - * decoding. This implementation returns the given object - * without any changes. The return value of this method - * is returned to the decoder from <decode>. - * - * Parameters: - * - * enc - <mxCodec> that controls the encoding process. - * node - XML node to be decoded. - * obj - Object that represents the default decoding. - */ -mxObjectCodec.prototype.afterDecode = function(dec, node, obj) -{ - return obj; -}; diff --git a/src/js/io/mxRootChangeCodec.js b/src/js/io/mxRootChangeCodec.js deleted file mode 100644 index fda613a..0000000 --- a/src/js/io/mxRootChangeCodec.js +++ /dev/null @@ -1,83 +0,0 @@ -/** - * $Id: mxRootChangeCodec.js,v 1.6 2010-09-15 14:38:51 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -mxCodecRegistry.register(function() -{ - /** - * Class: mxRootChangeCodec - * - * Codec for <mxRootChange>s. This class is created and registered - * dynamically at load time and used implicitely via <mxCodec> and - * the <mxCodecRegistry>. - * - * Transient Fields: - * - * - model - * - previous - * - root - */ - var codec = new mxObjectCodec(new mxRootChange(), - ['model', 'previous', 'root']); - - /** - * Function: onEncode - * - * Encodes the child recursively. - */ - codec.afterEncode = function(enc, obj, node) - { - enc.encodeCell(obj.root, node); - - return node; - }; - - /** - * Function: beforeDecode - * - * Decodes the optional children as cells - * using the respective decoder. - */ - codec.beforeDecode = function(dec, node, obj) - { - if (node.firstChild != null && - node.firstChild.nodeType == mxConstants.NODETYPE_ELEMENT) - { - // Makes sure the original node isn't modified - node = node.cloneNode(true); - - var tmp = node.firstChild; - obj.root = dec.decodeCell(tmp, false); - - var tmp2 = tmp.nextSibling; - tmp.parentNode.removeChild(tmp); - tmp = tmp2; - - while (tmp != null) - { - tmp2 = tmp.nextSibling; - dec.decodeCell(tmp); - tmp.parentNode.removeChild(tmp); - tmp = tmp2; - } - } - - return node; - }; - - /** - * Function: afterDecode - * - * Restores the state by assigning the previous value. - */ - codec.afterDecode = function(dec, node, obj) - { - obj.previous = obj.root; - - return obj; - }; - - // Returns the codec into the registry - return codec; - -}()); diff --git a/src/js/io/mxStylesheetCodec.js b/src/js/io/mxStylesheetCodec.js deleted file mode 100644 index 7636eb1..0000000 --- a/src/js/io/mxStylesheetCodec.js +++ /dev/null @@ -1,210 +0,0 @@ -/** - * $Id: mxStylesheetCodec.js,v 1.19 2011-06-13 08:18:42 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -mxCodecRegistry.register(function() -{ - /** - * Class: mxStylesheetCodec - * - * Codec for <mxStylesheet>s. This class is created and registered - * dynamically at load time and used implicitely via <mxCodec> - * and the <mxCodecRegistry>. - */ - var codec = new mxObjectCodec(new mxStylesheet()); - - /** - * Function: encode - * - * Encodes a stylesheet. See <decode> for a description of the - * format. - */ - codec.encode = function(enc, obj) - { - var node = enc.document.createElement(this.getName()); - - for (var i in obj.styles) - { - var style = obj.styles[i]; - var styleNode = enc.document.createElement('add'); - - if (i != null) - { - styleNode.setAttribute('as', i); - - for (var j in style) - { - var value = this.getStringValue(j, style[j]); - - if (value != null) - { - var entry = enc.document.createElement('add'); - entry.setAttribute('value', value); - entry.setAttribute('as', j); - styleNode.appendChild(entry); - } - } - - if (styleNode.childNodes.length > 0) - { - node.appendChild(styleNode); - } - } - } - - return node; - }; - - /** - * Function: getStringValue - * - * Returns the string for encoding the given value. - */ - codec.getStringValue = function(key, value) - { - var type = typeof(value); - - if (type == 'function') - { - value = mxStyleRegistry.getName(style[j]); - } - else if (type == 'object') - { - value = null; - } - - return value; - }; - - /** - * Function: decode - * - * Reads a sequence of the following child nodes - * and attributes: - * - * Child Nodes: - * - * add - Adds a new style. - * - * Attributes: - * - * as - Name of the style. - * extend - Name of the style to inherit from. - * - * Each node contains another sequence of add and remove nodes with the following - * attributes: - * - * as - Name of the style (see <mxConstants>). - * value - Value for the style. - * - * Instead of the value-attribute, one can put Javascript expressions into - * the node as follows: - * <add as="perimeter">mxPerimeter.RectanglePerimeter</add> - * - * A remove node will remove the entry with the name given in the as-attribute - * from the style. - * - * Example: - * - * (code) - * <mxStylesheet as="stylesheet"> - * <add as="text"> - * <add as="fontSize" value="12"/> - * </add> - * <add as="defaultVertex" extend="text"> - * <add as="shape" value="rectangle"/> - * </add> - * </mxStylesheet> - * (end) - */ - codec.decode = function(dec, node, into) - { - var obj = into || new this.template.constructor(); - var id = node.getAttribute('id'); - - if (id != null) - { - dec.objects[id] = obj; - } - - node = node.firstChild; - - while (node != null) - { - if (!this.processInclude(dec, node, obj) && - node.nodeName == 'add') - { - var as = node.getAttribute('as'); - - if (as != null) - { - var extend = node.getAttribute('extend'); - var style = (extend != null) ? mxUtils.clone(obj.styles[extend]) : null; - - if (style == null) - { - if (extend != null) - { - mxLog.warn('mxStylesheetCodec.decode: stylesheet ' + - extend + ' not found to extend'); - } - - style = new Object(); - } - - var entry = node.firstChild; - - while (entry != null) - { - if (entry.nodeType == mxConstants.NODETYPE_ELEMENT) - { - var key = entry.getAttribute('as'); - - if (entry.nodeName == 'add') - { - var text = mxUtils.getTextContent(entry); - var value = null; - - if (text != null && - text.length > 0) - { - value = mxUtils.eval(text); - } - else - { - value = entry.getAttribute('value'); - - if (mxUtils.isNumeric(value)) - { - value = parseFloat(value); - } - } - - if (value != null) - { - style[key] = value; - } - } - else if (entry.nodeName == 'remove') - { - delete style[key]; - } - } - - entry = entry.nextSibling; - } - - obj.putCellStyle(as, style); - } - } - - node = node.nextSibling; - } - - return obj; - }; - - // Returns the codec into the registry - return codec; - -}()); diff --git a/src/js/io/mxTerminalChangeCodec.js b/src/js/io/mxTerminalChangeCodec.js deleted file mode 100644 index a51d871..0000000 --- a/src/js/io/mxTerminalChangeCodec.js +++ /dev/null @@ -1,42 +0,0 @@ -/** - * $Id: mxTerminalChangeCodec.js,v 1.7 2010-09-13 15:58:36 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -mxCodecRegistry.register(function() -{ - /** - * Class: mxTerminalChangeCodec - * - * Codec for <mxTerminalChange>s. This class is created and registered - * dynamically at load time and used implicitely via <mxCodec> and - * the <mxCodecRegistry>. - * - * Transient Fields: - * - * - model - * - previous - * - * Reference Fields: - * - * - cell - * - terminal - */ - var codec = new mxObjectCodec(new mxTerminalChange(), - ['model', 'previous'], ['cell', 'terminal']); - - /** - * Function: afterDecode - * - * Restores the state by assigning the previous value. - */ - codec.afterDecode = function(dec, node, obj) - { - obj.previous = obj.terminal; - - return obj; - }; - - // Returns the codec into the registry - return codec; - -}()); diff --git a/src/js/layout/hierarchical/model/mxGraphAbstractHierarchyCell.js b/src/js/layout/hierarchical/model/mxGraphAbstractHierarchyCell.js deleted file mode 100644 index e2fe6a6..0000000 --- a/src/js/layout/hierarchical/model/mxGraphAbstractHierarchyCell.js +++ /dev/null @@ -1,206 +0,0 @@ -/** - * $Id: mxGraphAbstractHierarchyCell.js,v 1.12 2010-01-04 11:18:26 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -/** - * Class: mxGraphAbstractHierarchyCell - * - * An abstraction of an internal hierarchy node or edge - * - * Constructor: mxGraphAbstractHierarchyCell - * - * Constructs a new hierarchical layout algorithm. - * - * Arguments: - * - * graph - Reference to the enclosing <mxGraph>. - * deterministic - Optional boolean that specifies if this layout should be - * deterministic. Default is true. - */ -function mxGraphAbstractHierarchyCell() -{ - this.x = []; - this.y = []; - this.temp = []; -}; - -/** - * Variable: maxRank - * - * The maximum rank this cell occupies. Default is -1. - */ -mxGraphAbstractHierarchyCell.prototype.maxRank = -1; - -/** - * Variable: minRank - * - * The minimum rank this cell occupies. Default is -1. - */ -mxGraphAbstractHierarchyCell.prototype.minRank = -1; - -/** - * Variable: x - * - * The x position of this cell for each layer it occupies - */ -mxGraphAbstractHierarchyCell.prototype.x = null; - -/** - * Variable: y - * - * The y position of this cell for each layer it occupies - */ -mxGraphAbstractHierarchyCell.prototype.y = null; - -/** - * Variable: width - * - * The width of this cell - */ -mxGraphAbstractHierarchyCell.prototype.width = 0; - -/** - * Variable: height - * - * The height of this cell - */ -mxGraphAbstractHierarchyCell.prototype.height = 0; - -/** - * Variable: nextLayerConnectedCells - * - * A cached version of the cells this cell connects to on the next layer up - */ -mxGraphAbstractHierarchyCell.prototype.nextLayerConnectedCells = null; - -/** - * Variable: previousLayerConnectedCells - * - * A cached version of the cells this cell connects to on the next layer down - */ -mxGraphAbstractHierarchyCell.prototype.previousLayerConnectedCells = null; - -/** - * Variable: temp - * - * Temporary variable for general use. Generally, try to avoid - * carrying information between stages. Currently, the longest - * path layering sets temp to the rank position in fixRanks() - * and the crossing reduction uses this. This meant temp couldn't - * be used for hashing the nodes in the model dfs and so hashCode - * was created - */ -mxGraphAbstractHierarchyCell.prototype.temp = null; - -/** - * Function: getNextLayerConnectedCells - * - * Returns the cells this cell connects to on the next layer up - */ -mxGraphAbstractHierarchyCell.prototype.getNextLayerConnectedCells = function(layer) -{ - return null; -}; - -/** - * Function: getPreviousLayerConnectedCells - * - * Returns the cells this cell connects to on the next layer down - */ -mxGraphAbstractHierarchyCell.prototype.getPreviousLayerConnectedCells = function(layer) -{ - return null; -}; - -/** - * Function: isEdge - * - * Returns whether or not this cell is an edge - */ -mxGraphAbstractHierarchyCell.prototype.isEdge = function() -{ - return false; -}; - -/** - * Function: isVertex - * - * Returns whether or not this cell is a node - */ -mxGraphAbstractHierarchyCell.prototype.isVertex = function() -{ - return false; -}; - -/** - * Function: getGeneralPurposeVariable - * - * Gets the value of temp for the specified layer - */ -mxGraphAbstractHierarchyCell.prototype.getGeneralPurposeVariable = function(layer) -{ - return null; -}; - -/** - * Function: setGeneralPurposeVariable - * - * Set the value of temp for the specified layer - */ -mxGraphAbstractHierarchyCell.prototype.setGeneralPurposeVariable = function(layer, value) -{ - return null; -}; - -/** - * Function: setX - * - * Set the value of x for the specified layer - */ -mxGraphAbstractHierarchyCell.prototype.setX = function(layer, value) -{ - if (this.isVertex()) - { - this.x[0] = value; - } - else if (this.isEdge()) - { - this.x[layer - this.minRank - 1] = value; - } -}; - -/** - * Function: getX - * - * Gets the value of x on the specified layer - */ -mxGraphAbstractHierarchyCell.prototype.getX = function(layer) -{ - if (this.isVertex()) - { - return this.x[0]; - } - else if (this.isEdge()) - { - return this.x[layer - this.minRank - 1]; - } - - return 0.0; -}; - -/** - * Function: setY - * - * Set the value of y for the specified layer - */ -mxGraphAbstractHierarchyCell.prototype.setY = function(layer, value) -{ - if (this.isVertex()) - { - this.y[0] = value; - } - else if (this.isEdge()) - { - this.y[layer -this. minRank - 1] = value; - } -}; diff --git a/src/js/layout/hierarchical/model/mxGraphHierarchyEdge.js b/src/js/layout/hierarchical/model/mxGraphHierarchyEdge.js deleted file mode 100644 index 8ba16dd..0000000 --- a/src/js/layout/hierarchical/model/mxGraphHierarchyEdge.js +++ /dev/null @@ -1,174 +0,0 @@ -/** - * $Id: mxGraphHierarchyEdge.js,v 1.15 2012-06-12 20:23:14 david Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -/** - * Class: mxGraphHierarchyEdge - * - * An abstraction of a hierarchical edge for the hierarchy layout - * - * Constructor: mxGraphHierarchyEdge - * - * Constructs a hierarchy edge - * - * Arguments: - * - * edges - a list of real graph edges this abstraction represents - */ -function mxGraphHierarchyEdge(edges) -{ - mxGraphAbstractHierarchyCell.apply(this, arguments); - this.edges = edges; -}; - -/** - * Extends mxGraphAbstractHierarchyCell. - */ -mxGraphHierarchyEdge.prototype = new mxGraphAbstractHierarchyCell(); -mxGraphHierarchyEdge.prototype.constructor = mxGraphHierarchyEdge; - -/** - * Variable: edges - * - * The graph edge(s) this object represents. Parallel edges are all grouped - * together within one hierarchy edge. - */ -mxGraphHierarchyEdge.prototype.edges = null; - -/** - * Variable: source - * - * The node this edge is sourced at - */ -mxGraphHierarchyEdge.prototype.source = null; - -/** - * Variable: target - * - * The node this edge targets - */ -mxGraphHierarchyEdge.prototype.target = null; - -/** - * Variable: isReversed - * - * Whether or not the direction of this edge has been reversed - * internally to create a DAG for the hierarchical layout - */ -mxGraphHierarchyEdge.prototype.isReversed = false; - -/** - * Function: invert - * - * Inverts the direction of this internal edge(s) - */ -mxGraphHierarchyEdge.prototype.invert = function(layer) -{ - var temp = this.source; - this.source = this.target; - this.target = temp; - this.isReversed = !this.isReversed; -}; - -/** - * Function: getNextLayerConnectedCells - * - * Returns the cells this cell connects to on the next layer up - */ -mxGraphHierarchyEdge.prototype.getNextLayerConnectedCells = function(layer) -{ - if (this.nextLayerConnectedCells == null) - { - this.nextLayerConnectedCells = []; - - for (var i = 0; i < this.temp.length; i++) - { - this.nextLayerConnectedCells[i] = []; - - if (i == this.temp.length - 1) - { - this.nextLayerConnectedCells[i].push(this.source); - } - else - { - this.nextLayerConnectedCells[i].push(this); - } - } - } - - return this.nextLayerConnectedCells[layer - this.minRank - 1]; -}; - -/** - * Function: getPreviousLayerConnectedCells - * - * Returns the cells this cell connects to on the next layer down - */ -mxGraphHierarchyEdge.prototype.getPreviousLayerConnectedCells = function(layer) -{ - if (this.previousLayerConnectedCells == null) - { - this.previousLayerConnectedCells = []; - - for (var i = 0; i < this.temp.length; i++) - { - this.previousLayerConnectedCells[i] = []; - - if (i == 0) - { - this.previousLayerConnectedCells[i].push(this.target); - } - else - { - this.previousLayerConnectedCells[i].push(this); - } - } - } - - return this.previousLayerConnectedCells[layer - this.minRank - 1]; -}; - -/** - * Function: isEdge - * - * Returns true. - */ -mxGraphHierarchyEdge.prototype.isEdge = function() -{ - return true; -}; - -/** - * Function: getGeneralPurposeVariable - * - * Gets the value of temp for the specified layer - */ -mxGraphHierarchyEdge.prototype.getGeneralPurposeVariable = function(layer) -{ - return this.temp[layer - this.minRank - 1]; -}; - -/** - * Function: setGeneralPurposeVariable - * - * Set the value of temp for the specified layer - */ -mxGraphHierarchyEdge.prototype.setGeneralPurposeVariable = function(layer, value) -{ - this.temp[layer - this.minRank - 1] = value; -}; - -/** - * Function: getCoreCell - * - * Gets the first core edge associated with this wrapper - */ -mxGraphHierarchyEdge.prototype.getCoreCell = function() -{ - if (this.edges != null && this.edges.length > 0) - { - return this.edges[0]; - } - - return null; -};
\ No newline at end of file diff --git a/src/js/layout/hierarchical/model/mxGraphHierarchyModel.js b/src/js/layout/hierarchical/model/mxGraphHierarchyModel.js deleted file mode 100644 index ca2ba30..0000000 --- a/src/js/layout/hierarchical/model/mxGraphHierarchyModel.js +++ /dev/null @@ -1,685 +0,0 @@ -/** - * $Id: mxGraphHierarchyModel.js,v 1.33 2012-12-18 13:16:43 david Exp $ - * Copyright (c) 2006-2012, JGraph Ltd - */ -/** - * Class: mxGraphHierarchyModel - * - * Internal model of a hierarchical graph. This model stores nodes and edges - * equivalent to the real graph nodes and edges, but also stores the rank of the - * cells, the order within the ranks and the new candidate locations of cells. - * The internal model also reverses edge direction were appropriate , ignores - * self-loop and groups parallels together under one edge object. - * - * Constructor: mxGraphHierarchyModel - * - * Creates an internal ordered graph model using the vertices passed in. If - * there are any, leftward edge need to be inverted in the internal model - * - * Arguments: - * - * graph - the facade describing the graph to be operated on - * vertices - the vertices for this hierarchy - * ordered - whether or not the vertices are already ordered - * deterministic - whether or not this layout should be deterministic on each - * tightenToSource - whether or not to tighten vertices towards the sources - * scanRanksFromSinks - Whether rank assignment is from the sinks or sources. - * usage - */ -function mxGraphHierarchyModel(layout, vertices, roots, parent, tightenToSource) -{ - var graph = layout.getGraph(); - this.tightenToSource = tightenToSource; - this.roots = roots; - this.parent = parent; - - // map of cells to internal cell needed for second run through - // to setup the sink of edges correctly - this.vertexMapper = new Object(); - this.edgeMapper = new Object(); - this.maxRank = 0; - var internalVertices = []; - - if (vertices == null) - { - vertices = this.graph.getChildVertices(parent); - } - - this.maxRank = this.SOURCESCANSTARTRANK; - // map of cells to internal cell needed for second run through - // to setup the sink of edges correctly. Guess size by number - // of edges is roughly same as number of vertices. - this.createInternalCells(layout, vertices, internalVertices); - - // Go through edges set their sink values. Also check the - // ordering if and invert edges if necessary - for (var i = 0; i < vertices.length; i++) - { - var edges = internalVertices[i].connectsAsSource; - - for (var j = 0; j < edges.length; j++) - { - var internalEdge = edges[j]; - var realEdges = internalEdge.edges; - - // Only need to process the first real edge, since - // all the edges connect to the same other vertex - if (realEdges != null && realEdges.length > 0) - { - var realEdge = realEdges[0]; - var targetCell = graph.getView().getVisibleTerminal( - realEdge, false); - var targetCellId = mxCellPath.create(targetCell); - var internalTargetCell = this.vertexMapper[targetCellId]; - - if (internalVertices[i] == internalTargetCell) - { - // The real edge is reversed relative to the internal edge - targetCell = graph.getView().getVisibleTerminal( - realEdge, true); - targetCellId = mxCellPath.create(targetCell); - internalTargetCell = this.vertexMapper[targetCellId]; - } - - if (internalTargetCell != null - && internalVertices[i] != internalTargetCell) - { - internalEdge.target = internalTargetCell; - - if (internalTargetCell.connectsAsTarget.length == 0) - { - internalTargetCell.connectsAsTarget = []; - } - - if (mxUtils.indexOf(internalTargetCell.connectsAsTarget, internalEdge) < 0) - { - internalTargetCell.connectsAsTarget.push(internalEdge); - } - } - } - } - - // Use the temp variable in the internal nodes to mark this - // internal vertex as having been visited. - internalVertices[i].temp[0] = 1; - } -}; - -/** - * Variable: maxRank - * - * Stores the largest rank number allocated - */ -mxGraphHierarchyModel.prototype.maxRank = null; - -/** - * Variable: vertexMapper - * - * Map from graph vertices to internal model nodes. - */ -mxGraphHierarchyModel.prototype.vertexMapper = null; - -/** - * Variable: edgeMapper - * - * Map from graph edges to internal model edges - */ -mxGraphHierarchyModel.prototype.edgeMapper = null; - -/** - * Variable: ranks - * - * Mapping from rank number to actual rank - */ -mxGraphHierarchyModel.prototype.ranks = null; - -/** - * Variable: roots - * - * Store of roots of this hierarchy model, these are real graph cells, not - * internal cells - */ -mxGraphHierarchyModel.prototype.roots = null; - -/** - * Variable: parent - * - * The parent cell whose children are being laid out - */ -mxGraphHierarchyModel.prototype.parent = null; - -/** - * Variable: dfsCount - * - * Count of the number of times the ancestor dfs has been used. - */ -mxGraphHierarchyModel.prototype.dfsCount = 0; - -/** - * Variable: SOURCESCANSTARTRANK - * - * High value to start source layering scan rank value from. - */ -mxGraphHierarchyModel.prototype.SOURCESCANSTARTRANK = 100000000; - -/** - * Variable: tightenToSource - * - * Whether or not to tighten the assigned ranks of vertices up towards - * the source cells. - */ -mxGraphHierarchyModel.prototype.tightenToSource = false; - -/** - * Function: createInternalCells - * - * Creates all edges in the internal model - * - * Parameters: - * - * layout - Reference to the <mxHierarchicalLayout> algorithm. - * vertices - Array of <mxCells> that represent the vertices whom are to - * have an internal representation created. - * internalVertices - The array of <mxGraphHierarchyNodes> to have their - * information filled in using the real vertices. - */ -mxGraphHierarchyModel.prototype.createInternalCells = function(layout, vertices, internalVertices) -{ - var graph = layout.getGraph(); - - // Create internal edges - for (var i = 0; i < vertices.length; i++) - { - internalVertices[i] = new mxGraphHierarchyNode(vertices[i]); - var vertexId = mxCellPath.create(vertices[i]); - this.vertexMapper[vertexId] = internalVertices[i]; - - // If the layout is deterministic, order the cells - //List outgoingCells = graph.getNeighbours(vertices[i], deterministic); - var conns = layout.getEdges(vertices[i]); - var outgoingCells = graph.getOpposites(conns, vertices[i]); - internalVertices[i].connectsAsSource = []; - - // Create internal edges, but don't do any rank assignment yet - // First use the information from the greedy cycle remover to - // invert the leftward edges internally - for (var j = 0; j < outgoingCells.length; j++) - { - var cell = outgoingCells[j]; - - if (cell != vertices[i] && layout.graph.model.isVertex(cell) && - !layout.isVertexIgnored(cell)) - { - // We process all edge between this source and its targets - // If there are edges going both ways, we need to collect - // them all into one internal edges to avoid looping problems - // later. We assume this direction (source -> target) is the - // natural direction if at least half the edges are going in - // that direction. - - // The check below for edges[0] being in the vertex mapper is - // in case we've processed this the other way around - // (target -> source) and the number of edges in each direction - // are the same. All the graph edges will have been assigned to - // an internal edge going the other way, so we don't want to - // process them again - var undirectedEdges = graph.getEdgesBetween(vertices[i], - cell, false); - var directedEdges = graph.getEdgesBetween(vertices[i], - cell, true); - var edgeId = mxCellPath.create(undirectedEdges[0]); - - if (undirectedEdges != null && - undirectedEdges.length > 0 && - this.edgeMapper[edgeId] == null && - directedEdges.length * 2 >= undirectedEdges.length) - { - var internalEdge = new mxGraphHierarchyEdge(undirectedEdges); - - for (var k = 0; k < undirectedEdges.length; k++) - { - var edge = undirectedEdges[k]; - edgeId = mxCellPath.create(edge); - this.edgeMapper[edgeId] = internalEdge; - - // Resets all point on the edge and disables the edge style - // without deleting it from the cell style - graph.resetEdge(edge); - - if (layout.disableEdgeStyle) - { - layout.setEdgeStyleEnabled(edge, false); - layout.setOrthogonalEdge(edge,true); - } - } - - internalEdge.source = internalVertices[i]; - - if (mxUtils.indexOf(internalVertices[i].connectsAsSource, internalEdge) < 0) - { - internalVertices[i].connectsAsSource.push(internalEdge); - } - } - } - } - - // Ensure temp variable is cleared from any previous use - internalVertices[i].temp[0] = 0; - } -}; - -/** - * Function: initialRank - * - * Basic determination of minimum layer ranking by working from from sources - * or sinks and working through each node in the relevant edge direction. - * Starting at the sinks is basically a longest path layering algorithm. -*/ -mxGraphHierarchyModel.prototype.initialRank = function() -{ - var startNodes = []; - - if (this.roots != null) - { - for (var i = 0; i < this.roots.length; i++) - { - var vertexId = mxCellPath.create(this.roots[i]); - var internalNode = this.vertexMapper[vertexId]; - - if (internalNode != null) - { - startNodes.push(internalNode); - } - } - } - - for (var key in this.vertexMapper) - { - var internalNode = this.vertexMapper[key]; - - // Mark the node as not having had a layer assigned - internalNode.temp[0] = -1; - } - - var startNodesCopy = startNodes.slice(); - - while (startNodes.length > 0) - { - var internalNode = startNodes[0]; - var layerDeterminingEdges; - var edgesToBeMarked; - - layerDeterminingEdges = internalNode.connectsAsTarget; - edgesToBeMarked = internalNode.connectsAsSource; - - // flag to keep track of whether or not all layer determining - // edges have been scanned - var allEdgesScanned = true; - - // Work out the layer of this node from the layer determining - // edges. The minimum layer number of any node connected by one of - // the layer determining edges variable - var minimumLayer = this.SOURCESCANSTARTRANK; - - for (var i = 0; i < layerDeterminingEdges.length; i++) - { - var internalEdge = layerDeterminingEdges[i]; - - if (internalEdge.temp[0] == 5270620) - { - // This edge has been scanned, get the layer of the - // node on the other end - var otherNode = internalEdge.source; - minimumLayer = Math.min(minimumLayer, otherNode.temp[0] - 1); - } - else - { - allEdgesScanned = false; - - break; - } - } - - // If all edge have been scanned, assign the layer, mark all - // edges in the other direction and remove from the nodes list - if (allEdgesScanned) - { - internalNode.temp[0] = minimumLayer; - this.maxRank = Math.min(this.maxRank, minimumLayer); - - if (edgesToBeMarked != null) - { - for (var i = 0; i < edgesToBeMarked.length; i++) - { - var internalEdge = edgesToBeMarked[i]; - - // Assign unique stamp ( y/m/d/h ) - internalEdge.temp[0] = 5270620; - - // Add node on other end of edge to LinkedList of - // nodes to be analysed - var otherNode = internalEdge.target; - - // Only add node if it hasn't been assigned a layer - if (otherNode.temp[0] == -1) - { - startNodes.push(otherNode); - - // Mark this other node as neither being - // unassigned nor assigned so it isn't - // added to this list again, but it's - // layer isn't used in any calculation. - otherNode.temp[0] = -2; - } - } - } - - startNodes.shift(); - } - else - { - // Not all the edges have been scanned, get to the back of - // the class and put the dunces cap on - var removedCell = startNodes.shift(); - startNodes.push(internalNode); - - if (removedCell == internalNode && startNodes.length == 1) - { - // This is an error condition, we can't get out of - // this loop. It could happen for more than one node - // but that's a lot harder to detect. Log the error - // TODO make log comment - break; - } - } - } - - // Normalize the ranks down from their large starting value to place - // at least 1 sink on layer 0 - for (var key in this.vertexMapper) - { - var internalNode = this.vertexMapper[key]; - // Mark the node as not having had a layer assigned - internalNode.temp[0] -= this.maxRank; - } - - // Tighten the rank 0 nodes as far as possible - for ( var i = 0; i < startNodesCopy.length; i++) - { - var internalNode = startNodesCopy[i]; - var currentMaxLayer = 0; - var layerDeterminingEdges = internalNode.connectsAsSource; - - for ( var j = 0; j < layerDeterminingEdges.length; j++) - { - var internalEdge = layerDeterminingEdges[j]; - var otherNode = internalEdge.target; - internalNode.temp[0] = Math.max(currentMaxLayer, - otherNode.temp[0] + 1); - currentMaxLayer = internalNode.temp[0]; - } - } - - // Reset the maxRank to that which would be expected for a from-sink - // scan - this.maxRank = this.SOURCESCANSTARTRANK - this.maxRank; -}; - -/** - * Function: fixRanks - * - * Fixes the layer assignments to the values stored in the nodes. Also needs - * to create dummy nodes for edges that cross layers. - */ -mxGraphHierarchyModel.prototype.fixRanks = function() -{ - var rankList = []; - this.ranks = []; - - for (var i = 0; i < this.maxRank + 1; i++) - { - rankList[i] = []; - this.ranks[i] = rankList[i]; - } - - // Perform a DFS to obtain an initial ordering for each rank. - // Without doing this you would end up having to process - // crossings for a standard tree. - var rootsArray = null; - - if (this.roots != null) - { - var oldRootsArray = this.roots; - rootsArray = []; - - for (var i = 0; i < oldRootsArray.length; i++) - { - var cell = oldRootsArray[i]; - var cellId = mxCellPath.create(cell); - var internalNode = this.vertexMapper[cellId]; - rootsArray[i] = internalNode; - } - } - - this.visit(function(parent, node, edge, layer, seen) - { - if (seen == 0 && node.maxRank < 0 && node.minRank < 0) - { - rankList[node.temp[0]].push(node); - node.maxRank = node.temp[0]; - node.minRank = node.temp[0]; - - // Set temp[0] to the nodes position in the rank - node.temp[0] = rankList[node.maxRank].length - 1; - } - - if (parent != null && edge != null) - { - var parentToCellRankDifference = parent.maxRank - node.maxRank; - - if (parentToCellRankDifference > 1) - { - // There are ranks in between the parent and current cell - edge.maxRank = parent.maxRank; - edge.minRank = node.maxRank; - edge.temp = []; - edge.x = []; - edge.y = []; - - for (var i = edge.minRank + 1; i < edge.maxRank; i++) - { - // The connecting edge must be added to the - // appropriate ranks - rankList[i].push(edge); - edge.setGeneralPurposeVariable(i, rankList[i] - .length - 1); - } - } - } - }, rootsArray, false, null); -}; - -/** - * Function: visit - * - * A depth first search through the internal heirarchy model. - * - * Parameters: - * - * visitor - The visitor function pattern to be called for each node. - * trackAncestors - Whether or not the search is to keep track all nodes - * directly above this one in the search path. - */ -mxGraphHierarchyModel.prototype.visit = function(visitor, dfsRoots, trackAncestors, seenNodes) -{ - // Run dfs through on all roots - if (dfsRoots != null) - { - for (var i = 0; i < dfsRoots.length; i++) - { - var internalNode = dfsRoots[i]; - - if (internalNode != null) - { - if (seenNodes == null) - { - seenNodes = new Object(); - } - - if (trackAncestors) - { - // Set up hash code for root - internalNode.hashCode = []; - internalNode.hashCode[0] = this.dfsCount; - internalNode.hashCode[1] = i; - this.extendedDfs(null, internalNode, null, visitor, seenNodes, - internalNode.hashCode, i, 0); - } - else - { - this.dfs(null, internalNode, null, visitor, seenNodes, 0); - } - } - } - - this.dfsCount++; - } -}; - -/** - * Function: dfs - * - * Performs a depth first search on the internal hierarchy model - * - * Parameters: - * - * parent - the parent internal node of the current internal node - * root - the current internal node - * connectingEdge - the internal edge connecting the internal node and the parent - * internal node, if any - * visitor - the visitor pattern to be called for each node - * seen - a set of all nodes seen by this dfs a set of all of the - * ancestor node of the current node - * layer - the layer on the dfs tree ( not the same as the model ranks ) - */ -mxGraphHierarchyModel.prototype.dfs = function(parent, root, connectingEdge, visitor, seen, layer) -{ - if (root != null) - { - var rootId = mxCellPath.create(root.cell); - - if (seen[rootId] == null) - { - seen[rootId] = root; - visitor(parent, root, connectingEdge, layer, 0); - - // Copy the connects as source list so that visitors - // can change the original for edge direction inversions - var outgoingEdges = root.connectsAsSource.slice(); - - for (var i = 0; i< outgoingEdges.length; i++) - { - var internalEdge = outgoingEdges[i]; - var targetNode = internalEdge.target; - - // Root check is O(|roots|) - this.dfs(root, targetNode, internalEdge, visitor, seen, - layer + 1); - } - } - else - { - // Use the int field to indicate this node has been seen - visitor(parent, root, connectingEdge, layer, 1); - } - } -}; - -/** - * Function: extendedDfs - * - * Performs a depth first search on the internal hierarchy model. This dfs - * extends the default version by keeping track of cells ancestors, but it - * should be only used when necessary because of it can be computationally - * intensive for deep searches. - * - * Parameters: - * - * parent - the parent internal node of the current internal node - * root - the current internal node - * connectingEdge - the internal edge connecting the internal node and the parent - * internal node, if any - * visitor - the visitor pattern to be called for each node - * seen - a set of all nodes seen by this dfs - * ancestors - the parent hash code - * childHash - the new hash code for this node - * layer - the layer on the dfs tree ( not the same as the model ranks ) - */ -mxGraphHierarchyModel.prototype.extendedDfs = function(parent, root, connectingEdge, visitor, seen, ancestors, childHash, layer) -{ - // Explanation of custom hash set. Previously, the ancestors variable - // was passed through the dfs as a HashSet. The ancestors were copied - // into a new HashSet and when the new child was processed it was also - // added to the set. If the current node was in its ancestor list it - // meant there is a cycle in the graph and this information is passed - // to the visitor.visit() in the seen parameter. The HashSet clone was - // very expensive on CPU so a custom hash was developed using primitive - // types. temp[] couldn't be used so hashCode[] was added to each node. - // Each new child adds another int to the array, copying the prefix - // from its parent. Child of the same parent add different ints (the - // limit is therefore 2^32 children per parent...). If a node has a - // child with the hashCode already set then the child code is compared - // to the same portion of the current nodes array. If they match there - // is a loop. - // Note that the basic mechanism would only allow for 1 use of this - // functionality, so the root nodes have two ints. The second int is - // incremented through each node root and the first is incremented - // through each run of the dfs algorithm (therefore the dfs is not - // thread safe). The hash code of each node is set if not already set, - // or if the first int does not match that of the current run. - if (root != null) - { - if (parent != null) - { - // Form this nodes hash code if necessary, that is, if the - // hashCode variable has not been initialized or if the - // start of the parent hash code does not equal the start of - // this nodes hash code, indicating the code was set on a - // previous run of this dfs. - if (root.hashCode == null || - root.hashCode[0] != parent.hashCode[0]) - { - var hashCodeLength = parent.hashCode.length + 1; - root.hashCode = parent.hashCode.slice(); - root.hashCode[hashCodeLength - 1] = childHash; - } - } - - var rootId = mxCellPath.create(root.cell); - - if (seen[rootId] == null) - { - seen[rootId] = root; - visitor(parent, root, connectingEdge, layer, 0); - - // Copy the connects as source list so that visitors - // can change the original for edge direction inversions - var outgoingEdges = root.connectsAsSource.slice(); - - for (var i = 0; i < outgoingEdges.length; i++) - { - var internalEdge = outgoingEdges[i]; - var targetNode = internalEdge.target; - - // Root check is O(|roots|) - this.extendedDfs(root, targetNode, internalEdge, visitor, seen, - root.hashCode, i, layer + 1); - } - } - else - { - // Use the int field to indicate this node has been seen - visitor(parent, root, connectingEdge, layer, 1); - } - } -}; diff --git a/src/js/layout/hierarchical/model/mxGraphHierarchyNode.js b/src/js/layout/hierarchical/model/mxGraphHierarchyNode.js deleted file mode 100644 index d901d57..0000000 --- a/src/js/layout/hierarchical/model/mxGraphHierarchyNode.js +++ /dev/null @@ -1,210 +0,0 @@ -/** - * $Id: mxGraphHierarchyNode.js,v 1.13 2012-06-12 20:24:58 david Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -/** - * Class: mxGraphHierarchyNode - * - * An abstraction of a hierarchical edge for the hierarchy layout - * - * Constructor: mxGraphHierarchyNode - * - * Constructs an internal node to represent the specified real graph cell - * - * Arguments: - * - * cell - the real graph cell this node represents - */ -function mxGraphHierarchyNode(cell) -{ - mxGraphAbstractHierarchyCell.apply(this, arguments); - this.cell = cell; -}; - -/** - * Extends mxGraphAbstractHierarchyCell. - */ -mxGraphHierarchyNode.prototype = new mxGraphAbstractHierarchyCell(); -mxGraphHierarchyNode.prototype.constructor = mxGraphHierarchyNode; - -/** - * Variable: cell - * - * The graph cell this object represents. - */ -mxGraphHierarchyNode.prototype.cell = null; - -/** - * Variable: connectsAsTarget - * - * Collection of hierarchy edges that have this node as a target - */ -mxGraphHierarchyNode.prototype.connectsAsTarget = []; - -/** - * Variable: connectsAsSource - * - * Collection of hierarchy edges that have this node as a source - */ -mxGraphHierarchyNode.prototype.connectsAsSource = []; - -/** - * Variable: hashCode - * - * Assigns a unique hashcode for each node. Used by the model dfs instead - * of copying HashSets - */ -mxGraphHierarchyNode.prototype.hashCode = false; - -/** - * Function: getRankValue - * - * Returns the integer value of the layer that this node resides in - */ -mxGraphHierarchyNode.prototype.getRankValue = function(layer) -{ - return this.maxRank; -}; - -/** - * Function: getNextLayerConnectedCells - * - * Returns the cells this cell connects to on the next layer up - */ -mxGraphHierarchyNode.prototype.getNextLayerConnectedCells = function(layer) -{ - if (this.nextLayerConnectedCells == null) - { - this.nextLayerConnectedCells = []; - this.nextLayerConnectedCells[0] = []; - - for (var i = 0; i < this.connectsAsTarget.length; i++) - { - var edge = this.connectsAsTarget[i]; - - if (edge.maxRank == -1 || edge.maxRank == layer + 1) - { - // Either edge is not in any rank or - // no dummy nodes in edge, add node of other side of edge - this.nextLayerConnectedCells[0].push(edge.source); - } - else - { - // Edge spans at least two layers, add edge - this.nextLayerConnectedCells[0].push(edge); - } - } - } - - return this.nextLayerConnectedCells[0]; -}; - -/** - * Function: getPreviousLayerConnectedCells - * - * Returns the cells this cell connects to on the next layer down - */ -mxGraphHierarchyNode.prototype.getPreviousLayerConnectedCells = function(layer) -{ - if (this.previousLayerConnectedCells == null) - { - this.previousLayerConnectedCells = []; - this.previousLayerConnectedCells[0] = []; - - for (var i = 0; i < this.connectsAsSource.length; i++) - { - var edge = this.connectsAsSource[i]; - - if (edge.minRank == -1 || edge.minRank == layer - 1) - { - // No dummy nodes in edge, add node of other side of edge - this.previousLayerConnectedCells[0].push(edge.target); - } - else - { - // Edge spans at least two layers, add edge - this.previousLayerConnectedCells[0].push(edge); - } - } - } - - return this.previousLayerConnectedCells[0]; -}; - -/** - * Function: isVertex - * - * Returns true. - */ -mxGraphHierarchyNode.prototype.isVertex = function() -{ - return true; -}; - -/** - * Function: getGeneralPurposeVariable - * - * Gets the value of temp for the specified layer - */ -mxGraphHierarchyNode.prototype.getGeneralPurposeVariable = function(layer) -{ - return this.temp[0]; -}; - -/** - * Function: setGeneralPurposeVariable - * - * Set the value of temp for the specified layer - */ -mxGraphHierarchyNode.prototype.setGeneralPurposeVariable = function(layer, value) -{ - this.temp[0] = value; -}; - -/** - * Function: isAncestor - */ -mxGraphHierarchyNode.prototype.isAncestor = function(otherNode) -{ - // Firstly, the hash code of this node needs to be shorter than the - // other node - if (otherNode != null && this.hashCode != null && otherNode.hashCode != null - && this.hashCode.length < otherNode.hashCode.length) - { - if (this.hashCode == otherNode.hashCode) - { - return true; - } - - if (this.hashCode == null || this.hashCode == null) - { - return false; - } - - // Secondly, this hash code must match the start of the other - // node's hash code. Arrays.equals cannot be used here since - // the arrays are different length, and we do not want to - // perform another array copy. - for (var i = 0; i < this.hashCode.length; i++) - { - if (this.hashCode[i] != otherNode.hashCode[i]) - { - return false; - } - } - - return true; - } - - return false; -}; - -/** - * Function: getCoreCell - * - * Gets the core vertex associated with this wrapper - */ -mxGraphHierarchyNode.prototype.getCoreCell = function() -{ - return this.cell; -};
\ No newline at end of file diff --git a/src/js/layout/hierarchical/mxHierarchicalLayout.js b/src/js/layout/hierarchical/mxHierarchicalLayout.js deleted file mode 100644 index 6ce0e05..0000000 --- a/src/js/layout/hierarchical/mxHierarchicalLayout.js +++ /dev/null @@ -1,623 +0,0 @@ -/** - * $Id: mxHierarchicalLayout.js,v 1.30 2012-12-18 12:41:06 david Exp $ - * Copyright (c) 2005-2012, JGraph Ltd - */ -/** - * Class: mxHierarchicalLayout - * - * A hierarchical layout algorithm. - * - * Constructor: mxHierarchicalLayout - * - * Constructs a new hierarchical layout algorithm. - * - * Arguments: - * - * graph - Reference to the enclosing <mxGraph>. - * orientation - Optional constant that defines the orientation of this - * layout. - * deterministic - Optional boolean that specifies if this layout should be - * deterministic. Default is true. - */ -function mxHierarchicalLayout(graph, orientation, deterministic) -{ - mxGraphLayout.call(this, graph); - this.orientation = (orientation != null) ? orientation : mxConstants.DIRECTION_NORTH; - this.deterministic = (deterministic != null) ? deterministic : true; -}; - -/** - * Extends mxGraphLayout. - */ -mxHierarchicalLayout.prototype = new mxGraphLayout(); -mxHierarchicalLayout.prototype.constructor = mxHierarchicalLayout; - -/** - * Variable: roots - * - * Holds the array of <mxGraphLayouts> that this layout contains. - */ -mxHierarchicalLayout.prototype.roots = null; - -/** - * Variable: resizeParent - * - * Specifies if the parent should be resized after the layout so that it - * contains all the child cells. Default is false. See also <parentBorder>. - */ -mxHierarchicalLayout.prototype.resizeParent = false; - -/** - * Variable: moveParent - * - * Specifies if the parent should be moved if <resizeParent> is enabled. - * Default is false. - */ -mxHierarchicalLayout.prototype.moveParent = false; - -/** - * Variable: parentBorder - * - * The border to be added around the children if the parent is to be - * resized using <resizeParent>. Default is 0. - */ -mxHierarchicalLayout.prototype.parentBorder = 0; - -/** - * Variable: intraCellSpacing - * - * The spacing buffer added between cells on the same layer. Default is 30. - */ -mxHierarchicalLayout.prototype.intraCellSpacing = 30; - -/** - * Variable: interRankCellSpacing - * - * The spacing buffer added between cell on adjacent layers. Default is 50. - */ -mxHierarchicalLayout.prototype.interRankCellSpacing = 50; - -/** - * Variable: interHierarchySpacing - * - * The spacing buffer between unconnected hierarchies. Default is 60. - */ -mxHierarchicalLayout.prototype.interHierarchySpacing = 60; - -/** - * Variable: parallelEdgeSpacing - * - * The distance between each parallel edge on each ranks for long edges - */ -mxHierarchicalLayout.prototype.parallelEdgeSpacing = 10; - -/** - * Variable: orientation - * - * The position of the root node(s) relative to the laid out graph in. - * Default is <mxConstants.DIRECTION_NORTH>. - */ -mxHierarchicalLayout.prototype.orientation = mxConstants.DIRECTION_NORTH; - -/** - * Variable: fineTuning - * - * Whether or not to perform local optimisations and iterate multiple times - * through the algorithm. Default is true. - */ -mxHierarchicalLayout.prototype.fineTuning = true; - -/** - * - * Variable: tightenToSource - * - * Whether or not to tighten the assigned ranks of vertices up towards - * the source cells. - */ -mxHierarchicalLayout.prototype.tightenToSource = true; - -/** - * Variable: disableEdgeStyle - * - * Specifies if the STYLE_NOEDGESTYLE flag should be set on edges that are - * modified by the result. Default is true. - */ -mxHierarchicalLayout.prototype.disableEdgeStyle = true; - -/** - * Variable: promoteEdges - * - * Whether or not to promote edges that terminate on vertices with - * different but common ancestry to appear connected to the highest - * siblings in the ancestry chains - */ -mxHierarchicalLayout.prototype.promoteEdges = true; - -/** - * Variable: traverseAncestors - * - * Whether or not to navigate edges whose terminal vertices - * have different parents but are in the same ancestry chain - */ -mxHierarchicalLayout.prototype.traverseAncestors = true; - -/** - * Variable: model - * - * The internal <mxGraphHierarchyModel> formed of the layout. - */ -mxHierarchicalLayout.prototype.model = null; - -/** - * Function: getModel - * - * Returns the internal <mxGraphHierarchyModel> for this layout algorithm. - */ -mxHierarchicalLayout.prototype.getModel = function() -{ - return this.model; -}; - -/** - * Function: execute - * - * Executes the layout for the children of the specified parent. - * - * Parameters: - * - * parent - Parent <mxCell> that contains the children to be laid out. - * roots - Optional starting roots of the layout. - */ -mxHierarchicalLayout.prototype.execute = function(parent, roots) -{ - this.parent = parent; - var model = this.graph.model; - - // If the roots are set and the parent is set, only - // use the roots that are some dependent of the that - // parent. - // If just the root are set, use them as-is - // If just the parent is set use it's immediate - // children as the initial set - - if (roots == null && parent == null) - { - // TODO indicate the problem - return; - } - - if (roots != null && parent != null) - { - var rootsCopy = []; - - for (var i = 0; i < roots.length; i++) - { - - if (model.isAncestor(parent, roots[i])) - { - rootsCopy.push(roots[i]); - } - } - - this.roots = rootsCopy; - } - else - { - this.roots = roots; - } - - model.beginUpdate(); - try - { - this.run(parent); - - if (this.resizeParent && - !this.graph.isCellCollapsed(parent)) - { - this.graph.updateGroupBounds([parent], - this.parentBorder, this.moveParent); - } - } - finally - { - model.endUpdate(); - } -}; - -/** - * Function: findRoots - * - * Returns all visible children in the given parent which do not have - * incoming edges. If the result is empty then the children with the - * maximum difference between incoming and outgoing edges are returned. - * This takes into account edges that are being promoted to the given - * root due to invisible children or collapsed cells. - * - * Parameters: - * - * parent - <mxCell> whose children should be checked. - * vertices - array of vertices to limit search to - */ -mxHierarchicalLayout.prototype.findRoots = function(parent, vertices) -{ - var roots = []; - - if (parent != null && vertices != null) - { - var model = this.graph.model; - var best = null; - var maxDiff = -100000; - - for (var i in vertices) - { - var cell = vertices[i]; - - if (model.isVertex(cell) && this.graph.isCellVisible(cell)) - { - var conns = this.getEdges(cell); - var fanOut = 0; - var fanIn = 0; - - for (var k = 0; k < conns.length; k++) - { - var src = this.graph.view.getVisibleTerminal(conns[k], true); - - if (src == cell) - { - fanOut++; - } - else - { - fanIn++; - } - } - - if (fanIn == 0 && fanOut > 0) - { - roots.push(cell); - } - - var diff = fanOut - fanIn; - - if (diff > maxDiff) - { - maxDiff = diff; - best = cell; - } - } - } - - if (roots.length == 0 && best != null) - { - roots.push(best); - } - } - - return roots; -}; - -/** - * Function: getEdges - * - * Returns the connected edges for the given cell. - * - * Parameters: - * - * cell - <mxCell> whose edges should be returned. - */ -mxHierarchicalLayout.prototype.getEdges = function(cell) -{ - var model = this.graph.model; - var edges = []; - var isCollapsed = this.graph.isCellCollapsed(cell); - var childCount = model.getChildCount(cell); - - for (var i = 0; i < childCount; i++) - { - var child = model.getChildAt(cell, i); - - if (isCollapsed || !this.graph.isCellVisible(child)) - { - edges = edges.concat(model.getEdges(child, true, true)); - } - } - - edges = edges.concat(model.getEdges(cell, true, true)); - var result = []; - - for (var i = 0; i < edges.length; i++) - { - var state = this.graph.view.getState(edges[i]); - - var source = (state != null) ? state.getVisibleTerminal(true) : this.graph.view.getVisibleTerminal(edges[i], true); - var target = (state != null) ? state.getVisibleTerminal(false) : this.graph.view.getVisibleTerminal(edges[i], false); - - if ((source == target) || ((source != target) && ((target == cell && (this.parent == null || this.graph.isValidAncestor(source, this.parent, this.traverseAncestors))) || - (source == cell && (this.parent == null || - this.graph.isValidAncestor(target, this.parent, this.traverseAncestors)))))) - { - result.push(edges[i]); - } - } - - return result; -}; - -/** - * Function: run - * - * The API method used to exercise the layout upon the graph description - * and produce a separate description of the vertex position and edge - * routing changes made. It runs each stage of the layout that has been - * created. - */ -mxHierarchicalLayout.prototype.run = function(parent) -{ - // Separate out unconnected hierarchies - var hierarchyVertices = []; - var allVertexSet = []; - - if (this.roots == null && parent != null) - { - var filledVertexSet = this.filterDescendants(parent); - - this.roots = []; - var filledVertexSetEmpty = true; - - // Poor man's isSetEmpty - for (var key in filledVertexSet) - { - if (filledVertexSet[key] != null) - { - filledVertexSetEmpty = false; - break; - } - } - - while (!filledVertexSetEmpty) - { - var candidateRoots = this.findRoots(parent, filledVertexSet); - - for (var i = 0; i < candidateRoots.length; i++) - { - var vertexSet = []; - hierarchyVertices.push(vertexSet); - - this.traverse(candidateRoots[i], true, null, allVertexSet, vertexSet, - hierarchyVertices, filledVertexSet); - } - - for (var i = 0; i < candidateRoots.length; i++) - { - this.roots.push(candidateRoots[i]); - } - - filledVertexSetEmpty = true; - - // Poor man's isSetEmpty - for (var key in filledVertexSet) - { - if (filledVertexSet[key] != null) - { - filledVertexSetEmpty = false; - break; - } - } - } - } - else - { - // Find vertex set as directed traversal from roots - - for (var i = 0; i < roots.length; i++) - { - var vertexSet = []; - hierarchyVertices.push(vertexSet); - - traverse(roots.get(i), true, null, allVertexSet, vertexSet, - hierarchyVertices, null); - } - } - - // Iterate through the result removing parents who have children in this layout - - // Perform a layout for each seperate hierarchy - // Track initial coordinate x-positioning - var initialX = 0; - - for (var i = 0; i < hierarchyVertices.length; i++) - { - var vertexSet = hierarchyVertices[i]; - var tmp = []; - - for (var key in vertexSet) - { - tmp.push(vertexSet[key]); - } - - this.model = new mxGraphHierarchyModel(this, tmp, this.roots, - parent, this.tightenToSource); - - this.cycleStage(parent); - this.layeringStage(); - - this.crossingStage(parent); - initialX = this.placementStage(initialX, parent); - } -}; - -/** - * Function: filterDescendants - * - * Creates an array of descendant cells - */ -mxHierarchicalLayout.prototype.filterDescendants = function(cell) -{ - var model = this.graph.model; - var result = []; - - if (model.isVertex(cell) && cell != this.parent && this.graph.isCellVisible(cell)) - { - result.push(cell); - } - - if (this.traverseAncestors || cell == this.parent - && this.graph.isCellVisible(cell)) - { - var childCount = model.getChildCount(cell); - - for (var i = 0; i < childCount; i++) - { - var child = model.getChildAt(cell, i); - var children = this.filterDescendants(child); - - for (var j = 0; j < children.length; j++) - { - result[mxCellPath.create(children[j])] = children[j]; - } - } - } - - return result; -}; - -/** - * Traverses the (directed) graph invoking the given function for each - * visited vertex and edge. The function is invoked with the current vertex - * and the incoming edge as a parameter. This implementation makes sure - * each vertex is only visited once. The function may return false if the - * traversal should stop at the given vertex. - * - * Parameters: - * - * vertex - <mxCell> that represents the vertex where the traversal starts. - * directed - boolean indicating if edges should only be traversed - * from source to target. Default is true. - * edge - Optional <mxCell> that represents the incoming edge. This is - * null for the first step of the traversal. - * allVertices - Array of cell paths for the visited cells. - */ -mxHierarchicalLayout.prototype.traverse = function(vertex, directed, edge, allVertices, currentComp, - hierarchyVertices, filledVertexSet) -{ - var view = this.graph.view; - var model = this.graph.model; - - if (vertex != null && allVertices != null) - { - // Has this vertex been seen before in any traversal - // And if the filled vertex set is populated, only - // process vertices in that it contains - var vertexID = mxCellPath.create(vertex); - - if ((allVertices[vertexID] == null) - && (filledVertexSet == null ? true : filledVertexSet[vertexID] != null)) - { - if (currentComp[vertexID] == null) - { - currentComp[vertexID] = vertex; - } - if (allVertices[vertexID] == null) - { - allVertices[vertexID] = vertex; - } - - delete filledVertexSet[vertexID]; - - var edgeCount = model.getEdgeCount(vertex); - - if (edgeCount > 0) - { - for (var i = 0; i < edgeCount; i++) - { - var e = model.getEdgeAt(vertex, i); - var isSource = view.getVisibleTerminal(e, true) == vertex; - - if (!directed || isSource) - { - var next = view.getVisibleTerminal(e, !isSource); - currentComp = this.traverse(next, directed, e, allVertices, - currentComp, hierarchyVertices, - filledVertexSet); - } - } - } - } - else - { - if (currentComp[vertexID] == null) - { - // We've seen this vertex before, but not in the current component - // This component and the one it's in need to be merged - - for (var i = 0; i < hierarchyVertices.length; i++) - { - var comp = hierarchyVertices[i]; - - if (comp[vertexID] != null) - { - for (var key in currentComp) - { - comp[key] = currentComp[key]; - } - - // Remove the current component from the hierarchy set - hierarchyVertices.pop(); - return comp; - } - } - } - } - } - - return currentComp; -}; - -/** - * Function: cycleStage - * - * Executes the cycle stage using mxMinimumCycleRemover. - */ -mxHierarchicalLayout.prototype.cycleStage = function(parent) -{ - var cycleStage = new mxMinimumCycleRemover(this); - cycleStage.execute(parent); -}; - -/** - * Function: layeringStage - * - * Implements first stage of a Sugiyama layout. - */ -mxHierarchicalLayout.prototype.layeringStage = function() -{ - this.model.initialRank(); - this.model.fixRanks(); -}; - -/** - * Function: crossingStage - * - * Executes the crossing stage using mxMedianHybridCrossingReduction. - */ -mxHierarchicalLayout.prototype.crossingStage = function(parent) -{ - var crossingStage = new mxMedianHybridCrossingReduction(this); - crossingStage.execute(parent); -}; - -/** - * Function: placementStage - * - * Executes the placement stage using mxCoordinateAssignment. - */ -mxHierarchicalLayout.prototype.placementStage = function(initialX, parent) -{ - var placementStage = new mxCoordinateAssignment(this, this.intraCellSpacing, - this.interRankCellSpacing, this.orientation, initialX, - this.parallelEdgeSpacing); - placementStage.fineTuning = this.fineTuning; - placementStage.execute(parent); - - return placementStage.limitX + this.interHierarchySpacing; -}; diff --git a/src/js/layout/hierarchical/stage/mxCoordinateAssignment.js b/src/js/layout/hierarchical/stage/mxCoordinateAssignment.js deleted file mode 100644 index 8b73ccf..0000000 --- a/src/js/layout/hierarchical/stage/mxCoordinateAssignment.js +++ /dev/null @@ -1,1836 +0,0 @@ -/** - * $Id: mxCoordinateAssignment.js,v 1.29 2012-06-21 14:28:09 david Exp $ - * Copyright (c) 2005-2012, JGraph Ltd - */ -/** - * Class: mxCoordinateAssignment - * - * Sets the horizontal locations of node and edge dummy nodes on each layer. - * Uses median down and up weighings as well as heuristics to straighten edges as - * far as possible. - * - * Constructor: mxCoordinateAssignment - * - * Creates a coordinate assignment. - * - * Arguments: - * - * intraCellSpacing - the minimum buffer between cells on the same rank - * interRankCellSpacing - the minimum distance between cells on adjacent ranks - * orientation - the position of the root node(s) relative to the graph - * initialX - the leftmost coordinate node placement starts at - */ -function mxCoordinateAssignment(layout, intraCellSpacing, interRankCellSpacing, - orientation, initialX, parallelEdgeSpacing) -{ - this.layout = layout; - this.intraCellSpacing = intraCellSpacing; - this.interRankCellSpacing = interRankCellSpacing; - this.orientation = orientation; - this.initialX = initialX; - this.parallelEdgeSpacing = parallelEdgeSpacing; -}; - -var mxHierarchicalEdgeStyle = -{ - ORTHOGONAL: 1, - POLYLINE: 2, - STRAIGHT: 3 -}; - -/** - * Extends mxHierarchicalLayoutStage. - */ -mxCoordinateAssignment.prototype = new mxHierarchicalLayoutStage(); -mxCoordinateAssignment.prototype.constructor = mxCoordinateAssignment; - -/** - * Variable: layout - * - * Reference to the enclosing <mxHierarchicalLayout>. - */ -mxCoordinateAssignment.prototype.layout = null; - -/** - * Variable: intraCellSpacing - * - * The minimum buffer between cells on the same rank. Default is 30. - */ -mxCoordinateAssignment.prototype.intraCellSpacing = 30; - -/** - * Variable: interRankCellSpacing - * - * The minimum distance between cells on adjacent ranks. Default is 10. - */ -mxCoordinateAssignment.prototype.interRankCellSpacing = 10; - -/** - * Variable: parallelEdgeSpacing - * - * The distance between each parallel edge on each ranks for long edges. - * Default is 10. - */ -mxCoordinateAssignment.prototype.parallelEdgeSpacing = 10; - -/** - * Variable: maxIterations - * - * The number of heuristic iterations to run. Default is 8. - */ -mxCoordinateAssignment.prototype.maxIterations = 8; - -/** - * Variable: prefHozEdgeSep - * - * The preferred horizontal distance between edges exiting a vertex - */ -mxCoordinateAssignment.prototype.prefHozEdgeSep = 5; - -/** - * Variable: prefVertEdgeOff - * - * The preferred vertical offset between edges exiting a vertex - */ -mxCoordinateAssignment.prototype.prefVertEdgeOff = 2; - -/** - * Variable: minEdgeJetty - * - * The minimum distance for an edge jetty from a vertex - */ -mxCoordinateAssignment.prototype.minEdgeJetty = 12; - -/** - * Variable: channelBuffer - * - * The size of the vertical buffer in the center of inter-rank channels - * where edge control points should not be placed - */ -mxCoordinateAssignment.prototype.channelBuffer = 4; - -/** - * Variable: jettyPositions - * - * Map of internal edges and (x,y) pair of positions of the start and end jetty - * for that edge where it connects to the source and target vertices. - * Note this should technically be a WeakHashMap, but since JS does not - * have an equivalent, housekeeping must be performed before using. - * i.e. check all edges are still in the model and clear the values. - * Note that the y co-ord is the offset of the jetty, not the - * absolute point - */ -mxCoordinateAssignment.prototype.jettyPositions = null; - -/** - * Variable: orientation - * - * The position of the root ( start ) node(s) relative to the rest of the - * laid out graph. Default is <mxConstants.DIRECTION_NORTH>. - */ -mxCoordinateAssignment.prototype.orientation = mxConstants.DIRECTION_NORTH; - -/** - * Variable: initialX - * - * The minimum x position node placement starts at - */ -mxCoordinateAssignment.prototype.initialX = null; - -/** - * Variable: limitX - * - * The maximum x value this positioning lays up to - */ -mxCoordinateAssignment.prototype.limitX = null; - -/** - * Variable: currentXDelta - * - * The sum of x-displacements for the current iteration - */ -mxCoordinateAssignment.prototype.currentXDelta = null; - -/** - * Variable: widestRank - * - * The rank that has the widest x position - */ -mxCoordinateAssignment.prototype.widestRank = null; - -/** - * Variable: rankTopY - * - * Internal cache of top-most values of Y for each rank - */ -mxCoordinateAssignment.prototype.rankTopY = null; - -/** - * Variable: rankBottomY - * - * Internal cache of bottom-most value of Y for each rank - */ -mxCoordinateAssignment.prototype.rankBottomY = null; - -/** - * Variable: widestRankValue - * - * The X-coordinate of the edge of the widest rank - */ -mxCoordinateAssignment.prototype.widestRankValue = null; - -/** - * Variable: rankWidths - * - * The width of all the ranks - */ -mxCoordinateAssignment.prototype.rankWidths = null; - -/** - * Variable: rankY - * - * The Y-coordinate of all the ranks - */ -mxCoordinateAssignment.prototype.rankY = null; - -/** - * Variable: fineTuning - * - * Whether or not to perform local optimisations and iterate multiple times - * through the algorithm. Default is true. - */ -mxCoordinateAssignment.prototype.fineTuning = true; - -/** - * Variable: edgeStyle - * - * The style to apply between cell layers to edge segments - */ -mxCoordinateAssignment.prototype.edgeStyle = mxHierarchicalEdgeStyle.POLYLINE; - -/** - * Variable: nextLayerConnectedCache - * - * A store of connections to the layer above for speed - */ -mxCoordinateAssignment.prototype.nextLayerConnectedCache = null; - -/** - * Variable: previousLayerConnectedCache - * - * A store of connections to the layer below for speed - */ -mxCoordinateAssignment.prototype.previousLayerConnectedCache = null; - -/** - * Variable: groupPadding - * - * Padding added to resized parents - */ -mxCoordinateAssignment.prototype.groupPadding = 10; - -/** - * Utility method to display current positions - */ -mxCoordinateAssignment.prototype.printStatus = function() -{ - var model = this.layout.getModel(); - mxLog.show(); - - mxLog.writeln('======Coord assignment debug======='); - - for (var j = 0; j < model.ranks.length; j++) - { - mxLog.write('Rank ', j, ' : ' ); - var rank = model.ranks[j]; - - for (var k = 0; k < rank.length; k++) - { - var cell = rank[k]; - - mxLog.write(cell.getGeneralPurposeVariable(j), ' '); - } - mxLog.writeln(); - } - - mxLog.writeln('===================================='); -}; - -/** - * Function: execute - * - * A basic horizontal coordinate assignment algorithm - */ -mxCoordinateAssignment.prototype.execute = function(parent) -{ - this.jettyPositions = []; - var model = this.layout.getModel(); - this.currentXDelta = 0.0; - - this.initialCoords(this.layout.getGraph(), model); - -// this.printStatus(); - - if (this.fineTuning) - { - this.minNode(model); - } - - var bestXDelta = 100000000.0; - - if (this.fineTuning) - { - for (var i = 0; i < this.maxIterations; i++) - { -// this.printStatus(); - - // Median Heuristic - if (i != 0) - { - this.medianPos(i, model); - this.minNode(model); - } - - // if the total offset is less for the current positioning, - // there are less heavily angled edges and so the current - // positioning is used - if (this.currentXDelta < bestXDelta) - { - for (var j = 0; j < model.ranks.length; j++) - { - var rank = model.ranks[j]; - - for (var k = 0; k < rank.length; k++) - { - var cell = rank[k]; - cell.setX(j, cell.getGeneralPurposeVariable(j)); - } - } - - bestXDelta = this.currentXDelta; - } - else - { - // Restore the best positions - for (var j = 0; j < model.ranks.length; j++) - { - var rank = model.ranks[j]; - - for (var k = 0; k < rank.length; k++) - { - var cell = rank[k]; - cell.setGeneralPurposeVariable(j, cell.getX(j)); - } - } - } - - this.minPath(this.layout.getGraph(), model); - - this.currentXDelta = 0; - } - } - - this.setCellLocations(this.layout.getGraph(), model); -}; - -/** - * Function: minNode - * - * Performs one median positioning sweep in both directions - */ -mxCoordinateAssignment.prototype.minNode = function(model) -{ - // Queue all nodes - var nodeList = []; - - // Need to be able to map from cell to cellWrapper - var map = []; - var rank = []; - - for (var i = 0; i <= model.maxRank; i++) - { - rank[i] = model.ranks[i]; - - for (var j = 0; j < rank[i].length; j++) - { - // Use the weight to store the rank and visited to store whether - // or not the cell is in the list - var node = rank[i][j]; - var nodeWrapper = new WeightedCellSorter(node, i); - nodeWrapper.rankIndex = j; - nodeWrapper.visited = true; - nodeList.push(nodeWrapper); - - var cellId = mxCellPath.create(node.getCoreCell()); - map[cellId] = nodeWrapper; - } - } - - // Set a limit of the maximum number of times we will access the queue - // in case a loop appears - var maxTries = nodeList.length * 10; - var count = 0; - - // Don't move cell within this value of their median - var tolerance = 1; - - while (nodeList.length > 0 && count <= maxTries) - { - var cellWrapper = nodeList.shift(); - var cell = cellWrapper.cell; - - var rankValue = cellWrapper.weightedValue; - var rankIndex = parseInt(cellWrapper.rankIndex); - - var nextLayerConnectedCells = cell.getNextLayerConnectedCells(rankValue); - var previousLayerConnectedCells = cell.getPreviousLayerConnectedCells(rankValue); - - var numNextLayerConnected = nextLayerConnectedCells.length; - var numPreviousLayerConnected = previousLayerConnectedCells.length; - - var medianNextLevel = this.medianXValue(nextLayerConnectedCells, - rankValue + 1); - var medianPreviousLevel = this.medianXValue(previousLayerConnectedCells, - rankValue - 1); - - var numConnectedNeighbours = numNextLayerConnected - + numPreviousLayerConnected; - var currentPosition = cell.getGeneralPurposeVariable(rankValue); - var cellMedian = currentPosition; - - if (numConnectedNeighbours > 0) - { - cellMedian = (medianNextLevel * numNextLayerConnected + medianPreviousLevel - * numPreviousLayerConnected) - / numConnectedNeighbours; - } - - // Flag storing whether or not position has changed - var positionChanged = false; - - if (cellMedian < currentPosition - tolerance) - { - if (rankIndex == 0) - { - cell.setGeneralPurposeVariable(rankValue, cellMedian); - positionChanged = true; - } - else - { - var leftCell = rank[rankValue][rankIndex - 1]; - var leftLimit = leftCell - .getGeneralPurposeVariable(rankValue); - leftLimit = leftLimit + leftCell.width / 2 - + this.intraCellSpacing + cell.width / 2; - - if (leftLimit < cellMedian) - { - cell.setGeneralPurposeVariable(rankValue, cellMedian); - positionChanged = true; - } - else if (leftLimit < cell - .getGeneralPurposeVariable(rankValue) - - tolerance) - { - cell.setGeneralPurposeVariable(rankValue, leftLimit); - positionChanged = true; - } - } - } - else if (cellMedian > currentPosition + tolerance) - { - var rankSize = rank[rankValue].length; - - if (rankIndex == rankSize - 1) - { - cell.setGeneralPurposeVariable(rankValue, cellMedian); - positionChanged = true; - } - else - { - var rightCell = rank[rankValue][rankIndex + 1]; - var rightLimit = rightCell - .getGeneralPurposeVariable(rankValue); - rightLimit = rightLimit - rightCell.width / 2 - - this.intraCellSpacing - cell.width / 2; - - if (rightLimit > cellMedian) - { - cell.setGeneralPurposeVariable(rankValue, cellMedian); - positionChanged = true; - } - else if (rightLimit > cell - .getGeneralPurposeVariable(rankValue) - + tolerance) - { - cell.setGeneralPurposeVariable(rankValue, rightLimit); - positionChanged = true; - } - } - } - - if (positionChanged) - { - // Add connected nodes to map and list - for (var i = 0; i < nextLayerConnectedCells.length; i++) - { - var connectedCell = nextLayerConnectedCells[i]; - var connectedCellId = mxCellPath.create(connectedCell.getCoreCell()); - var connectedCellWrapper = map[connectedCellId]; - - if (connectedCellWrapper != null) - { - if (connectedCellWrapper.visited == false) - { - connectedCellWrapper.visited = true; - nodeList.push(connectedCellWrapper); - } - } - } - - // Add connected nodes to map and list - for (var i = 0; i < previousLayerConnectedCells.length; i++) - { - var connectedCell = previousLayerConnectedCells[i]; - var connectedCellId = mxCellPath.create(connectedCell.getCoreCell()); - var connectedCellWrapper = map[connectedCellId]; - - if (connectedCellWrapper != null) - { - if (connectedCellWrapper.visited == false) - { - connectedCellWrapper.visited = true; - nodeList.push(connectedCellWrapper); - } - } - } - } - - cellWrapper.visited = false; - count++; - } -}; - -/** - * Function: medianPos - * - * Performs one median positioning sweep in one direction - * - * Parameters: - * - * i - the iteration of the whole process - * model - an internal model of the hierarchical layout - */ -mxCoordinateAssignment.prototype.medianPos = function(i, model) -{ - // Reverse sweep direction each time through this method - var downwardSweep = (i % 2 == 0); - - if (downwardSweep) - { - for (var j = model.maxRank; j > 0; j--) - { - this.rankMedianPosition(j - 1, model, j); - } - } - else - { - for (var j = 0; j < model.maxRank - 1; j++) - { - this.rankMedianPosition(j + 1, model, j); - } - } -}; - -/** - * Function: rankMedianPosition - * - * Performs median minimisation over one rank. - * - * Parameters: - * - * rankValue - the layer number of this rank - * model - an internal model of the hierarchical layout - * nextRankValue - the layer number whose connected cels are to be laid out - * relative to - */ -mxCoordinateAssignment.prototype.rankMedianPosition = function(rankValue, model, nextRankValue) -{ - var rank = model.ranks[rankValue]; - - // Form an array of the order in which the cell are to be processed - // , the order is given by the weighted sum of the in or out edges, - // depending on whether we're travelling up or down the hierarchy. - var weightedValues = []; - var cellMap = []; - - for (var i = 0; i < rank.length; i++) - { - var currentCell = rank[i]; - weightedValues[i] = new WeightedCellSorter(); - weightedValues[i].cell = currentCell; - weightedValues[i].rankIndex = i; - var currentCellId = mxCellPath.create(currentCell.getCoreCell()); - cellMap[currentCellId] = weightedValues[i]; - var nextLayerConnectedCells = null; - - if (nextRankValue < rankValue) - { - nextLayerConnectedCells = currentCell - .getPreviousLayerConnectedCells(rankValue); - } - else - { - nextLayerConnectedCells = currentCell - .getNextLayerConnectedCells(rankValue); - } - - // Calculate the weighing based on this node type and those this - // node is connected to on the next layer - weightedValues[i].weightedValue = this.calculatedWeightedValue( - currentCell, nextLayerConnectedCells); - } - - weightedValues.sort(WeightedCellSorter.prototype.compare); - - // Set the new position of each node within the rank using - // its temp variable - - for (var i = 0; i < weightedValues.length; i++) - { - var numConnectionsNextLevel = 0; - var cell = weightedValues[i].cell; - var nextLayerConnectedCells = null; - var medianNextLevel = 0; - - if (nextRankValue < rankValue) - { - nextLayerConnectedCells = cell.getPreviousLayerConnectedCells( - rankValue).slice(); - } - else - { - nextLayerConnectedCells = cell.getNextLayerConnectedCells( - rankValue).slice(); - } - - if (nextLayerConnectedCells != null) - { - numConnectionsNextLevel = nextLayerConnectedCells.length; - - if (numConnectionsNextLevel > 0) - { - medianNextLevel = this.medianXValue(nextLayerConnectedCells, - nextRankValue); - } - else - { - // For case of no connections on the next level set the - // median to be the current position and try to be - // positioned there - medianNextLevel = cell.getGeneralPurposeVariable(rankValue); - } - } - - var leftBuffer = 0.0; - var leftLimit = -100000000.0; - - for (var j = weightedValues[i].rankIndex - 1; j >= 0;) - { - var rankId = mxCellPath.create(rank[j].getCoreCell()); - var weightedValue = cellMap[rankId]; - - if (weightedValue != null) - { - var leftCell = weightedValue.cell; - - if (weightedValue.visited) - { - // The left limit is the right hand limit of that - // cell plus any allowance for unallocated cells - // in-between - leftLimit = leftCell - .getGeneralPurposeVariable(rankValue) - + leftCell.width - / 2.0 - + this.intraCellSpacing - + leftBuffer + cell.width / 2.0; - j = -1; - } - else - { - leftBuffer += leftCell.width + this.intraCellSpacing; - j--; - } - } - } - - var rightBuffer = 0.0; - var rightLimit = 100000000.0; - - for (var j = weightedValues[i].rankIndex + 1; j < weightedValues.length;) - { - var rankId = mxCellPath.create(rank[j].getCoreCell()); - var weightedValue = cellMap[rankId]; - - if (weightedValue != null) - { - var rightCell = weightedValue.cell; - - if (weightedValue.visited) - { - // The left limit is the right hand limit of that - // cell plus any allowance for unallocated cells - // in-between - rightLimit = rightCell - .getGeneralPurposeVariable(rankValue) - - rightCell.width - / 2.0 - - this.intraCellSpacing - - rightBuffer - cell.width / 2.0; - j = weightedValues.length; - } - else - { - rightBuffer += rightCell.width + this.intraCellSpacing; - j++; - } - } - } - - if (medianNextLevel >= leftLimit && medianNextLevel <= rightLimit) - { - cell.setGeneralPurposeVariable(rankValue, medianNextLevel); - } - else if (medianNextLevel < leftLimit) - { - // Couldn't place at median value, place as close to that - // value as possible - cell.setGeneralPurposeVariable(rankValue, leftLimit); - this.currentXDelta += leftLimit - medianNextLevel; - } - else if (medianNextLevel > rightLimit) - { - // Couldn't place at median value, place as close to that - // value as possible - cell.setGeneralPurposeVariable(rankValue, rightLimit); - this.currentXDelta += medianNextLevel - rightLimit; - } - - weightedValues[i].visited = true; - } -}; - -/** - * Function: calculatedWeightedValue - * - * Calculates the priority the specified cell has based on the type of its - * cell and the cells it is connected to on the next layer - * - * Parameters: - * - * currentCell - the cell whose weight is to be calculated - * collection - the cells the specified cell is connected to - */ -mxCoordinateAssignment.prototype.calculatedWeightedValue = function(currentCell, collection) -{ - var totalWeight = 0; - - for (var i = 0; i < collection.length; i++) - { - var cell = collection[i]; - - if (currentCell.isVertex() && cell.isVertex()) - { - totalWeight++; - } - else if (currentCell.isEdge() && cell.isEdge()) - { - totalWeight += 8; - } - else - { - totalWeight += 2; - } - } - - return totalWeight; -}; - -/** - * Function: medianXValue - * - * Calculates the median position of the connected cell on the specified - * rank - * - * Parameters: - * - * connectedCells - the cells the candidate connects to on this level - * rankValue - the layer number of this rank - */ -mxCoordinateAssignment.prototype.medianXValue = function(connectedCells, rankValue) -{ - if (connectedCells.length == 0) - { - return 0; - } - - var medianValues = []; - - for (var i = 0; i < connectedCells.length; i++) - { - medianValues[i] = connectedCells[i].getGeneralPurposeVariable(rankValue); - } - - medianValues.sort(function(a,b){return a - b;}); - - if (connectedCells.length % 2 == 1) - { - // For odd numbers of adjacent vertices return the median - return medianValues[Math.floor(connectedCells.length / 2)]; - } - else - { - var medianPoint = connectedCells.length / 2; - var leftMedian = medianValues[medianPoint - 1]; - var rightMedian = medianValues[medianPoint]; - - return ((leftMedian + rightMedian) / 2); - } -}; - -/** - * Function: initialCoords - * - * Sets up the layout in an initial positioning. The ranks are all centered - * as much as possible along the middle vertex in each rank. The other cells - * are then placed as close as possible on either side. - * - * Parameters: - * - * facade - the facade describing the input graph - * model - an internal model of the hierarchical layout - */ -mxCoordinateAssignment.prototype.initialCoords = function(facade, model) -{ - this.calculateWidestRank(facade, model); - - // Sweep up and down from the widest rank - for (var i = this.widestRank; i >= 0; i--) - { - if (i < model.maxRank) - { - this.rankCoordinates(i, facade, model); - } - } - - for (var i = this.widestRank+1; i <= model.maxRank; i++) - { - if (i > 0) - { - this.rankCoordinates(i, facade, model); - } - } -}; - -/** - * Function: rankCoordinates - * - * Sets up the layout in an initial positioning. All the first cells in each - * rank are moved to the left and the rest of the rank inserted as close - * together as their size and buffering permits. This method works on just - * the specified rank. - * - * Parameters: - * - * rankValue - the current rank being processed - * graph - the facade describing the input graph - * model - an internal model of the hierarchical layout - */ -mxCoordinateAssignment.prototype.rankCoordinates = function(rankValue, graph, model) -{ - var rank = model.ranks[rankValue]; - var maxY = 0.0; - var localX = this.initialX + (this.widestRankValue - this.rankWidths[rankValue]) - / 2; - - // Store whether or not any of the cells' bounds were unavailable so - // to only issue the warning once for all cells - var boundsWarning = false; - - for (var i = 0; i < rank.length; i++) - { - var node = rank[i]; - - if (node.isVertex()) - { - var bounds = this.layout.getVertexBounds(node.cell); - - if (bounds != null) - { - if (this.orientation == mxConstants.DIRECTION_NORTH || - this.orientation == mxConstants.DIRECTION_SOUTH) - { - node.width = bounds.width; - node.height = bounds.height; - } - else - { - node.width = bounds.height; - node.height = bounds.width; - } - } - else - { - boundsWarning = true; - } - - maxY = Math.max(maxY, node.height); - } - else if (node.isEdge()) - { - // The width is the number of additional parallel edges - // time the parallel edge spacing - var numEdges = 1; - - if (node.edges != null) - { - numEdges = node.edges.length; - } - else - { - mxLog.warn('edge.edges is null'); - } - - node.width = (numEdges - 1) * this.parallelEdgeSpacing; - } - - // Set the initial x-value as being the best result so far - localX += node.width / 2.0; - node.setX(rankValue, localX); - node.setGeneralPurposeVariable(rankValue, localX); - localX += node.width / 2.0; - localX += this.intraCellSpacing; - } - - if (boundsWarning == true) - { - mxLog.warn('At least one cell has no bounds'); - } -}; - -/** - * Function: calculateWidestRank - * - * Calculates the width rank in the hierarchy. Also set the y value of each - * rank whilst performing the calculation - * - * Parameters: - * - * graph - the facade describing the input graph - * model - an internal model of the hierarchical layout - */ -mxCoordinateAssignment.prototype.calculateWidestRank = function(graph, model) -{ - // Starting y co-ordinate - var y = -this.interRankCellSpacing; - - // Track the widest cell on the last rank since the y - // difference depends on it - var lastRankMaxCellHeight = 0.0; - this.rankWidths = []; - this.rankY = []; - - for (var rankValue = model.maxRank; rankValue >= 0; rankValue--) - { - // Keep track of the widest cell on this rank - var maxCellHeight = 0.0; - var rank = model.ranks[rankValue]; - var localX = this.initialX; - - // Store whether or not any of the cells' bounds were unavailable so - // to only issue the warning once for all cells - var boundsWarning = false; - - for (var i = 0; i < rank.length; i++) - { - var node = rank[i]; - - if (node.isVertex()) - { - var bounds = this.layout.getVertexBounds(node.cell); - - if (bounds != null) - { - if (this.orientation == mxConstants.DIRECTION_NORTH || - this.orientation == mxConstants.DIRECTION_SOUTH) - { - node.width = bounds.width; - node.height = bounds.height; - } - else - { - node.width = bounds.height; - node.height = bounds.width; - } - } - else - { - boundsWarning = true; - } - - maxCellHeight = Math.max(maxCellHeight, node.height); - } - else if (node.isEdge()) - { - // The width is the number of additional parallel edges - // time the parallel edge spacing - var numEdges = 1; - - if (node.edges != null) - { - numEdges = node.edges.length; - } - else - { - mxLog.warn('edge.edges is null'); - } - - node.width = (numEdges - 1) * this.parallelEdgeSpacing; - } - - // Set the initial x-value as being the best result so far - localX += node.width / 2.0; - node.setX(rankValue, localX); - node.setGeneralPurposeVariable(rankValue, localX); - localX += node.width / 2.0; - localX += this.intraCellSpacing; - - if (localX > this.widestRankValue) - { - this.widestRankValue = localX; - this.widestRank = rankValue; - } - - this.rankWidths[rankValue] = localX; - } - - if (boundsWarning == true) - { - mxLog.warn('At least one cell has no bounds'); - } - - this.rankY[rankValue] = y; - var distanceToNextRank = maxCellHeight / 2.0 - + lastRankMaxCellHeight / 2.0 + this.interRankCellSpacing; - lastRankMaxCellHeight = maxCellHeight; - - if (this.orientation == mxConstants.DIRECTION_NORTH || - this.orientation == mxConstants.DIRECTION_WEST) - { - y += distanceToNextRank; - } - else - { - y -= distanceToNextRank; - } - - for (var i = 0; i < rank.length; i++) - { - var cell = rank[i]; - cell.setY(rankValue, y); - } - } -}; - -/** - * Function: minPath - * - * Straightens out chains of virtual nodes where possibleacade to those stored after this layout - * processing step has completed. - * - * Parameters: - * - * graph - the facade describing the input graph - * model - an internal model of the hierarchical layout - */ -mxCoordinateAssignment.prototype.minPath = function(graph, model) -{ - // Work down and up each edge with at least 2 control points - // trying to straighten each one out. If the same number of - // straight segments are formed in both directions, the - // preferred direction used is the one where the final - // control points have the least offset from the connectable - // region of the terminating vertices - var edges = model.edgeMapper; - - for (var key in edges) - { - var cell = edges[key]; - - if (cell.maxRank - cell.minRank - 1 < 1) - { - continue; - } - - // At least two virtual nodes in the edge - // Check first whether the edge is already straight - var referenceX = cell - .getGeneralPurposeVariable(cell.minRank + 1); - var edgeStraight = true; - var refSegCount = 0; - - for (var i = cell.minRank + 2; i < cell.maxRank; i++) - { - var x = cell.getGeneralPurposeVariable(i); - - if (referenceX != x) - { - edgeStraight = false; - referenceX = x; - } - else - { - refSegCount++; - } - } - - if (!edgeStraight) - { - var upSegCount = 0; - var downSegCount = 0; - var upXPositions = []; - var downXPositions = []; - - var currentX = cell.getGeneralPurposeVariable(cell.minRank + 1); - - for (var i = cell.minRank + 1; i < cell.maxRank - 1; i++) - { - // Attempt to straight out the control point on the - // next segment up with the current control point. - var nextX = cell.getX(i + 1); - - if (currentX == nextX) - { - upXPositions[i - cell.minRank - 1] = currentX; - upSegCount++; - } - else if (this.repositionValid(model, cell, i + 1, currentX)) - { - upXPositions[i - cell.minRank - 1] = currentX; - upSegCount++; - // Leave currentX at same value - } - else - { - upXPositions[i - cell.minRank - 1] = nextX; - currentX = nextX; - } - } - - currentX = cell.getX(i); - - for (var i = cell.maxRank - 1; i > cell.minRank + 1; i--) - { - // Attempt to straight out the control point on the - // next segment down with the current control point. - var nextX = cell.getX(i - 1); - - if (currentX == nextX) - { - downXPositions[i - cell.minRank - 2] = currentX; - downSegCount++; - } - else if (this.repositionValid(model, cell, i - 1, currentX)) - { - downXPositions[i - cell.minRank - 2] = currentX; - downSegCount++; - // Leave currentX at same value - } - else - { - downXPositions[i - cell.minRank - 2] = cell.getX(i-1); - currentX = nextX; - } - } - - if (downSegCount > refSegCount || upSegCount > refSegCount) - { - if (downSegCount >= upSegCount) - { - // Apply down calculation values - for (var i = cell.maxRank - 2; i > cell.minRank; i--) - { - cell.setX(i, downXPositions[i - cell.minRank - 1]); - } - } - else if (upSegCount > downSegCount) - { - // Apply up calculation values - for (var i = cell.minRank + 2; i < cell.maxRank; i++) - { - cell.setX(i, upXPositions[i - cell.minRank - 2]); - } - } - else - { - // Neither direction provided a favourable result - // But both calculations are better than the - // existing solution, so apply the one with minimal - // offset to attached vertices at either end. - } - } - } - } -}; - -/** - * Function: repositionValid - * - * Determines whether or not a node may be moved to the specified x - * position on the specified rank - * - * Parameters: - * - * model - the layout model - * cell - the cell being analysed - * rank - the layer of the cell - * position - the x position being sought - */ -mxCoordinateAssignment.prototype.repositionValid = function(model, cell, rank, position) -{ - var rankArray = model.ranks[rank]; - var rankIndex = -1; - - for (var i = 0; i < rankArray.length; i++) - { - if (cell == rankArray[i]) - { - rankIndex = i; - break; - } - } - - if (rankIndex < 0) - { - return false; - } - - var currentX = cell.getGeneralPurposeVariable(rank); - - if (position < currentX) - { - // Trying to move node to the left. - if (rankIndex == 0) - { - // Left-most node, can move anywhere - return true; - } - - var leftCell = rankArray[rankIndex - 1]; - var leftLimit = leftCell.getGeneralPurposeVariable(rank); - leftLimit = leftLimit + leftCell.width / 2 - + this.intraCellSpacing + cell.width / 2; - - if (leftLimit <= position) - { - return true; - } - else - { - return false; - } - } - else if (position > currentX) - { - // Trying to move node to the right. - if (rankIndex == rankArray.length - 1) - { - // Right-most node, can move anywhere - return true; - } - - var rightCell = rankArray[rankIndex + 1]; - var rightLimit = rightCell.getGeneralPurposeVariable(rank); - rightLimit = rightLimit - rightCell.width / 2 - - this.intraCellSpacing - cell.width / 2; - - if (rightLimit >= position) - { - return true; - } - else - { - return false; - } - } - - return true; -}; - -/** - * Function: setCellLocations - * - * Sets the cell locations in the facade to those stored after this layout - * processing step has completed. - * - * Parameters: - * - * graph - the input graph - * model - the layout model - */ -mxCoordinateAssignment.prototype.setCellLocations = function(graph, model) -{ - this.rankTopY = []; - this.rankBottomY = []; - - for (var i = 0; i < model.ranks.length; i++) - { - this.rankTopY[i] = Number.MAX_VALUE; - this.rankBottomY[i] = 0.0; - } - - var parentsChanged = null; - - if (this.layout.resizeParent) - { - parentsChanged = new Object(); - } - - var edges = model.edgeMapper; - var vertices = model.vertexMapper; - - // Process vertices all first, since they define the lower and - // limits of each rank. Between these limits lie the channels - // where the edges can be routed across the graph - - for (var key in vertices) - { - var vertex = vertices[key]; - this.setVertexLocation(vertex); - - if (this.layout.resizeParent) - { - var parent = graph.model.getParent(vertex.cell); - var id = mxCellPath.create(parent); - - // Implements set semantic - if (parentsChanged[id] == null) - { - parentsChanged[id] = parent; - } - } - } - - if (this.layout.resizeParent && parentsChanged != null) - { - this.adjustParents(parentsChanged); - } - - // Post process edge styles. Needs the vertex locations set for initial - // values of the top and bottoms of each rank - if (this.edgeStyle == mxHierarchicalEdgeStyle.ORTHOGONAL - || this.edgeStyle == mxHierarchicalEdgeStyle.POLYLINE) - { - this.localEdgeProcessing(model); - } - - for (var key in edges) - { - this.setEdgePosition(edges[key]); - } -}; - -/** - * Function: adjustParents - * - * Adjust parent cells whose child geometries have changed. The default - * implementation adjusts the group to just fit around the children with - * a padding. - */ -mxCoordinateAssignment.prototype.adjustParents = function(parentsChanged) -{ - var tmp = []; - - for (var id in parentsChanged) - { - tmp.push(parentsChanged[id]); - } - - this.layout.arrangeGroups(mxUtils.sortCells(tmp, true), this.groupPadding); -}; - -/** - * Function: localEdgeProcessing - * - * Separates the x position of edges as they connect to vertices - * - * Parameters: - * - * model - the layout model - */ -mxCoordinateAssignment.prototype.localEdgeProcessing = function(model) -{ - var edgeMapping = model.edgeMapper; - - // Iterate through each vertex, look at the edges connected in - // both directions. - for (var rankIndex = 0; rankIndex < model.ranks.length; rankIndex++) - { - var rank = model.ranks[rankIndex]; - - for (var cellIndex = 0; cellIndex < rank.length; cellIndex++) - { - var cell = rank[cellIndex]; - - if (cell.isVertex()) - { - var currentCells = cell.getPreviousLayerConnectedCells(rankIndex); - - var currentRank = rankIndex - 1; - - // Two loops, last connected cells, and next - for (var k = 0; k < 2; k++) - { - if (currentRank > -1 - && currentRank < model.ranks.length - && currentCells != null - && currentCells.length > 0) - { - var sortedCells = []; - - for (var j = 0; j < currentCells.length; j++) - { - var sorter = new WeightedCellSorter( - currentCells[j], currentCells[j].getX(currentRank)); - sortedCells.push(sorter); - } - - sortedCells.sort(WeightedCellSorter.prototype.compare); - - var leftLimit = cell.x[0] - cell.width / 2; - var rightLimit = leftLimit + cell.width; - - // Connected edge count starts at 1 to allow for buffer - // with edge of vertex - var connectedEdgeCount = 0; - var connectedEdgeGroupCount = 0; - var connectedEdges = []; - // Calculate width requirements for all connected edges - for (var j = 0; j < sortedCells.length; j++) - { - var innerCell = sortedCells[j].cell; - var connections; - - if (innerCell.isVertex()) - { - // Get the connecting edge - if (k == 0) - { - connections = cell.connectsAsSource; - - } - else - { - connections = cell.connectsAsTarget; - } - - for (var connIndex = 0; connIndex < connections.length; connIndex++) - { - if (connections[connIndex].source == innerCell - || connections[connIndex].target == innerCell) - { - connectedEdgeCount += connections[connIndex].edges - .length; - connectedEdgeGroupCount++; - - connectedEdges.push(connections[connIndex]); - } - } - } - else - { - connectedEdgeCount += innerCell.edges.length; - connectedEdgeGroupCount++; - connectedEdges.push(innerCell); - } - } - - var requiredWidth = (connectedEdgeCount + 1) - * this.prefHozEdgeSep; - - // Add a buffer on the edges of the vertex if the edge count allows - if (cell.width > requiredWidth - + (2 * this.prefHozEdgeSep)) - { - leftLimit += this.prefHozEdgeSep; - rightLimit -= this.prefHozEdgeSep; - } - - var availableWidth = rightLimit - leftLimit; - var edgeSpacing = availableWidth / connectedEdgeCount; - - var currentX = leftLimit + edgeSpacing / 2.0; - var currentYOffset = this.minEdgeJetty - this.prefVertEdgeOff; - var maxYOffset = 0; - - for (var j = 0; j < connectedEdges.length; j++) - { - var numActualEdges = connectedEdges[j].edges - .length; - var edgeId = mxCellPath.create(connectedEdges[j].edges[0]); - var pos = this.jettyPositions[edgeId]; - - if (pos == null) - { - pos = []; - this.jettyPositions[edgeId] = pos; - } - - if (j < connectedEdgeCount / 2) - { - currentYOffset += this.prefVertEdgeOff; - } - else if (j > connectedEdgeCount / 2) - { - currentYOffset -= this.prefVertEdgeOff; - } - // Ignore the case if equals, this means the second of 2 - // jettys with the same y (even number of edges) - - for (var m = 0; m < numActualEdges; m++) - { - pos[m * 4 + k * 2] = currentX; - currentX += edgeSpacing; - pos[m * 4 + k * 2 + 1] = currentYOffset; - } - - maxYOffset = Math.max(maxYOffset, - currentYOffset); - } - } - - currentCells = cell.getNextLayerConnectedCells(rankIndex); - - currentRank = rankIndex + 1; - } - } - } - } -}; - -/** - * Function: setEdgePosition - * - * Fixes the control points - */ -mxCoordinateAssignment.prototype.setEdgePosition = function(cell) -{ - // For parallel edges we need to seperate out the points a - // little - var offsetX = 0; - // Only set the edge control points once - - if (cell.temp[0] != 101207) - { - var maxRank = cell.maxRank; - var minRank = cell.minRank; - - if (maxRank == minRank) - { - maxRank = cell.source.maxRank; - minRank = cell.target.minRank; - } - - var parallelEdgeCount = 0; - var edgeId = mxCellPath.create(cell.edges[0]); - var jettys = this.jettyPositions[edgeId]; - - var source = cell.isReversed ? cell.target.cell : cell.source.cell; - - for (var i = 0; i < cell.edges.length; i++) - { - var realEdge = cell.edges[i]; - var realSource = this.layout.graph.view.getVisibleTerminal(realEdge, true); - - //List oldPoints = graph.getPoints(realEdge); - var newPoints = []; - - // Single length reversed edges end up with the jettys in the wrong - // places. Since single length edges only have jettys, not segment - // control points, we just say the edge isn't reversed in this section - var reversed = cell.isReversed; - - if (realSource != source) - { - // The real edges include all core model edges and these can go - // in both directions. If the source of the hierarchical model edge - // isn't the source of the specific real edge in this iteration - // treat if as reversed - reversed = !reversed; - } - - // First jetty of edge - if (jettys != null) - { - var arrayOffset = reversed ? 2 : 0; - var y = reversed ? this.rankTopY[minRank] : this.rankBottomY[maxRank]; - var jetty = jettys[parallelEdgeCount * 4 + 1 + arrayOffset]; - - if (reversed) - { - jetty = -jetty; - } - - y += jetty; - var x = jettys[parallelEdgeCount * 4 + arrayOffset]; - - if (this.orientation == mxConstants.DIRECTION_NORTH - || this.orientation == mxConstants.DIRECTION_SOUTH) - { - newPoints.push(new mxPoint(x, y)); - } - else - { - newPoints.push(new mxPoint(y, x)); - } - } - - // Declare variables to define loop through edge points and - // change direction if edge is reversed - - var loopStart = cell.x.length - 1; - var loopLimit = -1; - var loopDelta = -1; - var currentRank = cell.maxRank - 1; - - if (reversed) - { - loopStart = 0; - loopLimit = cell.x.length; - loopDelta = 1; - currentRank = cell.minRank + 1; - } - // Reversed edges need the points inserted in - // reverse order - for (var j = loopStart; (cell.maxRank != cell.minRank) && j != loopLimit; j += loopDelta) - { - // The horizontal position in a vertical layout - var positionX = cell.x[j] + offsetX; - - // Work out the vertical positions in a vertical layout - // in the edge buffer channels above and below this rank - var topChannelY = (this.rankTopY[currentRank] + this.rankBottomY[currentRank + 1]) / 2.0; - var bottomChannelY = (this.rankTopY[currentRank - 1] + this.rankBottomY[currentRank]) / 2.0; - - if (reversed) - { - var tmp = topChannelY; - topChannelY = bottomChannelY; - bottomChannelY = tmp; - } - - if (this.orientation == mxConstants.DIRECTION_NORTH || - this.orientation == mxConstants.DIRECTION_SOUTH) - { - newPoints.push(new mxPoint(positionX, topChannelY)); - newPoints.push(new mxPoint(positionX, bottomChannelY)); - } - else - { - newPoints.push(new mxPoint(topChannelY, positionX)); - newPoints.push(new mxPoint(bottomChannelY, positionX)); - } - - this.limitX = Math.max(this.limitX, positionX); - currentRank += loopDelta; - } - - // Second jetty of edge - if (jettys != null) - { - var arrayOffset = reversed ? 2 : 0; - var rankY = reversed ? this.rankBottomY[maxRank] : this.rankTopY[minRank]; - var jetty = jettys[parallelEdgeCount * 4 + 3 - arrayOffset]; - - if (reversed) - { - jetty = -jetty; - } - var y = rankY - jetty; - var x = jettys[parallelEdgeCount * 4 + 2 - arrayOffset]; - - if (this.orientation == mxConstants.DIRECTION_NORTH || - this.orientation == mxConstants.DIRECTION_SOUTH) - { - newPoints.push(new mxPoint(x, y)); - } - else - { - newPoints.push(new mxPoint(y, x)); - } - } - - if (cell.isReversed) - { - this.processReversedEdge(cell, realEdge); - } - - this.layout.setEdgePoints(realEdge, newPoints); - - // Increase offset so next edge is drawn next to - // this one - if (offsetX == 0.0) - { - offsetX = this.parallelEdgeSpacing; - } - else if (offsetX > 0) - { - offsetX = -offsetX; - } - else - { - offsetX = -offsetX + this.parallelEdgeSpacing; - } - - parallelEdgeCount++; - } - - cell.temp[0] = 101207; - } -}; - - -/** - * Function: setVertexLocation - * - * Fixes the position of the specified vertex. - * - * Parameters: - * - * cell - the vertex to position - */ -mxCoordinateAssignment.prototype.setVertexLocation = function(cell) -{ - var realCell = cell.cell; - var positionX = cell.x[0] - cell.width / 2; - var positionY = cell.y[0] - cell.height / 2; - - this.rankTopY[cell.minRank] = Math.min(this.rankTopY[cell.minRank], positionY); - this.rankBottomY[cell.minRank] = Math.max(this.rankBottomY[cell.minRank], - positionY + cell.height); - - if (this.orientation == mxConstants.DIRECTION_NORTH || - this.orientation == mxConstants.DIRECTION_SOUTH) - { - this.layout.setVertexLocation(realCell, positionX, positionY); - } - else - { - this.layout.setVertexLocation(realCell, positionY, positionX); - } - - this.limitX = Math.max(this.limitX, positionX + cell.width); -}; - -/** - * Function: processReversedEdge - * - * Hook to add additional processing - * - * Parameters: - * - * edge - the hierarchical model edge - * realEdge - the real edge in the graph - */ -mxCoordinateAssignment.prototype.processReversedEdge = function(graph, model) -{ - // hook for subclassers -}; - -/** - * Class: WeightedCellSorter - * - * A utility class used to track cells whilst sorting occurs on the weighted - * sum of their connected edges. Does not violate (x.compareTo(y)==0) == - * (x.equals(y)) - * - * Constructor: WeightedCellSorter - * - * Constructs a new weighted cell sorted for the given cell and weight. - */ -function WeightedCellSorter(cell, weightedValue) -{ - this.cell = cell; - this.weightedValue = weightedValue; -}; - -/** - * Variable: weightedValue - * - * The weighted value of the cell stored. - */ -WeightedCellSorter.prototype.weightedValue = 0; - -/** - * Variable: nudge - * - * Whether or not to flip equal weight values. - */ -WeightedCellSorter.prototype.nudge = false; - -/** - * Variable: visited - * - * Whether or not this cell has been visited in the current assignment. - */ -WeightedCellSorter.prototype.visited = false; - -/** - * Variable: rankIndex - * - * The index this cell is in the model rank. - */ -WeightedCellSorter.prototype.rankIndex = null; - -/** - * Variable: cell - * - * The cell whose median value is being calculated. - */ -WeightedCellSorter.prototype.cell = null; - -/** - * Function: compare - * - * Compares two WeightedCellSorters. - */ -WeightedCellSorter.prototype.compare = function(a, b) -{ - if (a != null && b != null) - { - if (b.weightedValue > a.weightedValue) - { - return -1; - } - else if (b.weightedValue < a.weightedValue) - { - return 1; - } - else - { - if (b.nudge) - { - return -1; - } - else - { - return 1; - } - } - } - else - { - return 0; - } -}; diff --git a/src/js/layout/hierarchical/stage/mxHierarchicalLayoutStage.js b/src/js/layout/hierarchical/stage/mxHierarchicalLayoutStage.js deleted file mode 100644 index 2e635fc..0000000 --- a/src/js/layout/hierarchical/stage/mxHierarchicalLayoutStage.js +++ /dev/null @@ -1,25 +0,0 @@ -/** - * $Id: mxHierarchicalLayoutStage.js,v 1.8 2010-01-02 09:45:15 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -/** - * Class: mxHierarchicalLayoutStage - * - * The specific layout interface for hierarchical layouts. It adds a - * <code>run</code> method with a parameter for the hierarchical layout model - * that is shared between the layout stages. - * - * Constructor: mxHierarchicalLayoutStage - * - * Constructs a new hierarchical layout stage. - */ -function mxHierarchicalLayoutStage() { }; - -/** - * Function: execute - * - * Takes the graph detail and configuration information within the facade - * and creates the resulting laid out graph within that facade for further - * use. - */ -mxHierarchicalLayoutStage.prototype.execute = function(parent) { }; diff --git a/src/js/layout/hierarchical/stage/mxMedianHybridCrossingReduction.js b/src/js/layout/hierarchical/stage/mxMedianHybridCrossingReduction.js deleted file mode 100644 index 997890e..0000000 --- a/src/js/layout/hierarchical/stage/mxMedianHybridCrossingReduction.js +++ /dev/null @@ -1,674 +0,0 @@ -/** - * $Id: mxMedianHybridCrossingReduction.js,v 1.25 2012-06-07 11:16:41 david Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -/** - * Class: mxMedianHybridCrossingReduction - * - * Sets the horizontal locations of node and edge dummy nodes on each layer. - * Uses median down and up weighings as well heuristic to straighten edges as - * far as possible. - * - * Constructor: mxMedianHybridCrossingReduction - * - * Creates a coordinate assignment. - * - * Arguments: - * - * intraCellSpacing - the minimum buffer between cells on the same rank - * interRankCellSpacing - the minimum distance between cells on adjacent ranks - * orientation - the position of the root node(s) relative to the graph - * initialX - the leftmost coordinate node placement starts at - */ -function mxMedianHybridCrossingReduction(layout) -{ - this.layout = layout; -}; - -/** - * Extends mxMedianHybridCrossingReduction. - */ -mxMedianHybridCrossingReduction.prototype = new mxHierarchicalLayoutStage(); -mxMedianHybridCrossingReduction.prototype.constructor = mxMedianHybridCrossingReduction; - -/** - * Variable: layout - * - * Reference to the enclosing <mxHierarchicalLayout>. - */ -mxMedianHybridCrossingReduction.prototype.layout = null; - -/** - * Variable: maxIterations - * - * The maximum number of iterations to perform whilst reducing edge - * crossings. Default is 24. - */ -mxMedianHybridCrossingReduction.prototype.maxIterations = 24; - -/** - * Variable: nestedBestRanks - * - * Stores each rank as a collection of cells in the best order found for - * each layer so far - */ -mxMedianHybridCrossingReduction.prototype.nestedBestRanks = null; - -/** - * Variable: currentBestCrossings - * - * The total number of crossings found in the best configuration so far - */ -mxMedianHybridCrossingReduction.prototype.currentBestCrossings = 0; - -/** - * Variable: iterationsWithoutImprovement - * - * The total number of crossings found in the best configuration so far - */ -mxMedianHybridCrossingReduction.prototype.iterationsWithoutImprovement = 0; - -/** - * Variable: maxNoImprovementIterations - * - * The total number of crossings found in the best configuration so far - */ -mxMedianHybridCrossingReduction.prototype.maxNoImprovementIterations = 2; - -/** - * Function: execute - * - * Performs a vertex ordering within ranks as described by Gansner et al - * 1993 - */ -mxMedianHybridCrossingReduction.prototype.execute = function(parent) -{ - var model = this.layout.getModel(); - - // Stores initial ordering as being the best one found so far - this.nestedBestRanks = []; - - for (var i = 0; i < model.ranks.length; i++) - { - this.nestedBestRanks[i] = model.ranks[i].slice(); - } - - var iterationsWithoutImprovement = 0; - var currentBestCrossings = this.calculateCrossings(model); - - for (var i = 0; i < this.maxIterations && - iterationsWithoutImprovement < this.maxNoImprovementIterations; i++) - { - this.weightedMedian(i, model); - this.transpose(i, model); - var candidateCrossings = this.calculateCrossings(model); - - if (candidateCrossings < currentBestCrossings) - { - currentBestCrossings = candidateCrossings; - iterationsWithoutImprovement = 0; - - // Store the current rankings as the best ones - for (var j = 0; j < this.nestedBestRanks.length; j++) - { - var rank = model.ranks[j]; - - for (var k = 0; k < rank.length; k++) - { - var cell = rank[k]; - this.nestedBestRanks[j][cell.getGeneralPurposeVariable(j)] = cell; - } - } - } - else - { - // Increase count of iterations where we haven't improved the - // layout - iterationsWithoutImprovement++; - - // Restore the best values to the cells - for (var j = 0; j < this.nestedBestRanks.length; j++) - { - var rank = model.ranks[j]; - - for (var k = 0; k < rank.length; k++) - { - var cell = rank[k]; - cell.setGeneralPurposeVariable(j, k); - } - } - } - - if (currentBestCrossings == 0) - { - // Do nothing further - break; - } - } - - // Store the best rankings but in the model - var ranks = []; - var rankList = []; - - for (var i = 0; i < model.maxRank + 1; i++) - { - rankList[i] = []; - ranks[i] = rankList[i]; - } - - for (var i = 0; i < this.nestedBestRanks.length; i++) - { - for (var j = 0; j < this.nestedBestRanks[i].length; j++) - { - rankList[i].push(this.nestedBestRanks[i][j]); - } - } - - model.ranks = ranks; -}; - - -/** - * Function: calculateCrossings - * - * Calculates the total number of edge crossing in the current graph. - * Returns the current number of edge crossings in the hierarchy graph - * model in the current candidate layout - * - * Parameters: - * - * model - the internal model describing the hierarchy - */ -mxMedianHybridCrossingReduction.prototype.calculateCrossings = function(model) -{ - var numRanks = model.ranks.length; - var totalCrossings = 0; - - for (var i = 1; i < numRanks; i++) - { - totalCrossings += this.calculateRankCrossing(i, model); - } - - return totalCrossings; -}; - -/** - * Function: calculateRankCrossing - * - * Calculates the number of edges crossings between the specified rank and - * the rank below it. Returns the number of edges crossings with the rank - * beneath - * - * Parameters: - * - * i - the topmost rank of the pair ( higher rank value ) - * model - the internal model describing the hierarchy - */ -mxMedianHybridCrossingReduction.prototype.calculateRankCrossing = function(i, model) -{ - var totalCrossings = 0; - var rank = model.ranks[i]; - var previousRank = model.ranks[i - 1]; - - // Create an array of connections between these two levels - var currentRankSize = rank.length; - var previousRankSize = previousRank.length; - var connections = []; - - for (var j = 0; j < currentRankSize; j++) - { - connections[j] = []; - } - - // Iterate over the top rank and fill in the connection information - for (var j = 0; j < rank.length; j++) - { - var node = rank[j]; - var rankPosition = node.getGeneralPurposeVariable(i); - var connectedCells = node.getPreviousLayerConnectedCells(i); - - for (var k = 0; k < connectedCells.length; k++) - { - var connectedNode = connectedCells[k]; - var otherCellRankPosition = connectedNode.getGeneralPurposeVariable(i - 1); - connections[rankPosition][otherCellRankPosition] = 201207; - } - } - - // Iterate through the connection matrix, crossing edges are - // indicated by other connected edges with a greater rank position - // on one rank and lower position on the other - for (var j = 0; j < currentRankSize; j++) - { - for (var k = 0; k < previousRankSize; k++) - { - if (connections[j][k] == 201207) - { - // Draw a grid of connections, crossings are top right - // and lower left from this crossing pair - for (var j2 = j + 1; j2 < currentRankSize; j2++) - { - for (var k2 = 0; k2 < k; k2++) - { - if (connections[j2][k2] == 201207) - { - totalCrossings++; - } - } - } - - for (var j2 = 0; j2 < j; j2++) - { - for (var k2 = k + 1; k2 < previousRankSize; k2++) - { - if (connections[j2][k2] == 201207) - { - totalCrossings++; - } - } - } - - } - } - } - - return totalCrossings / 2; -}; - -/** - * Function: transpose - * - * Takes each possible adjacent cell pair on each rank and checks if - * swapping them around reduces the number of crossing - * - * Parameters: - * - * mainLoopIteration - the iteration number of the main loop - * model - the internal model describing the hierarchy - */ -mxMedianHybridCrossingReduction.prototype.transpose = function(mainLoopIteration, model) -{ - var improved = true; - - // Track the number of iterations in case of looping - var count = 0; - var maxCount = 10; - while (improved && count++ < maxCount) - { - // On certain iterations allow allow swapping of cell pairs with - // equal edge crossings switched or not switched. This help to - // nudge a stuck layout into a lower crossing total. - var nudge = mainLoopIteration % 2 == 1 && count % 2 == 1; - improved = false; - - for (var i = 0; i < model.ranks.length; i++) - { - var rank = model.ranks[i]; - var orderedCells = []; - - for (var j = 0; j < rank.length; j++) - { - var cell = rank[j]; - var tempRank = cell.getGeneralPurposeVariable(i); - - // FIXME: Workaround to avoid negative tempRanks - if (tempRank < 0) - { - tempRank = j; - } - orderedCells[tempRank] = cell; - } - - var leftCellAboveConnections = null; - var leftCellBelowConnections = null; - var rightCellAboveConnections = null; - var rightCellBelowConnections = null; - - var leftAbovePositions = null; - var leftBelowPositions = null; - var rightAbovePositions = null; - var rightBelowPositions = null; - - var leftCell = null; - var rightCell = null; - - for (var j = 0; j < (rank.length - 1); j++) - { - // For each intra-rank adjacent pair of cells - // see if swapping them around would reduce the - // number of edges crossing they cause in total - // On every cell pair except the first on each rank, we - // can save processing using the previous values for the - // right cell on the new left cell - if (j == 0) - { - leftCell = orderedCells[j]; - leftCellAboveConnections = leftCell - .getNextLayerConnectedCells(i); - leftCellBelowConnections = leftCell - .getPreviousLayerConnectedCells(i); - leftAbovePositions = []; - leftBelowPositions = []; - - for (var k = 0; k < leftCellAboveConnections.length; k++) - { - leftAbovePositions[k] = leftCellAboveConnections[k].getGeneralPurposeVariable(i + 1); - } - - for (var k = 0; k < leftCellBelowConnections.length; k++) - { - leftBelowPositions[k] = leftCellBelowConnections[k].getGeneralPurposeVariable(i - 1); - } - } - else - { - leftCellAboveConnections = rightCellAboveConnections; - leftCellBelowConnections = rightCellBelowConnections; - leftAbovePositions = rightAbovePositions; - leftBelowPositions = rightBelowPositions; - leftCell = rightCell; - } - - rightCell = orderedCells[j + 1]; - rightCellAboveConnections = rightCell - .getNextLayerConnectedCells(i); - rightCellBelowConnections = rightCell - .getPreviousLayerConnectedCells(i); - - rightAbovePositions = []; - rightBelowPositions = []; - - for (var k = 0; k < rightCellAboveConnections.length; k++) - { - rightAbovePositions[k] = rightCellAboveConnections[k].getGeneralPurposeVariable(i + 1); - } - - for (var k = 0; k < rightCellBelowConnections.length; k++) - { - rightBelowPositions[k] = rightCellBelowConnections[k].getGeneralPurposeVariable(i - 1); - } - - var totalCurrentCrossings = 0; - var totalSwitchedCrossings = 0; - - for (var k = 0; k < leftAbovePositions.length; k++) - { - for (var ik = 0; ik < rightAbovePositions.length; ik++) - { - if (leftAbovePositions[k] > rightAbovePositions[ik]) - { - totalCurrentCrossings++; - } - - if (leftAbovePositions[k] < rightAbovePositions[ik]) - { - totalSwitchedCrossings++; - } - } - } - - for (var k = 0; k < leftBelowPositions.length; k++) - { - for (var ik = 0; ik < rightBelowPositions.length; ik++) - { - if (leftBelowPositions[k] > rightBelowPositions[ik]) - { - totalCurrentCrossings++; - } - - if (leftBelowPositions[k] < rightBelowPositions[ik]) - { - totalSwitchedCrossings++; - } - } - } - - if ((totalSwitchedCrossings < totalCurrentCrossings) || - (totalSwitchedCrossings == totalCurrentCrossings && - nudge)) - { - var temp = leftCell.getGeneralPurposeVariable(i); - leftCell.setGeneralPurposeVariable(i, rightCell - .getGeneralPurposeVariable(i)); - rightCell.setGeneralPurposeVariable(i, temp); - - // With this pair exchanged we have to switch all of - // values for the left cell to the right cell so the - // next iteration for this rank uses it as the left - // cell again - rightCellAboveConnections = leftCellAboveConnections; - rightCellBelowConnections = leftCellBelowConnections; - rightAbovePositions = leftAbovePositions; - rightBelowPositions = leftBelowPositions; - rightCell = leftCell; - - if (!nudge) - { - // Don't count nudges as improvement or we'll end - // up stuck in two combinations and not finishing - // as early as we should - improved = true; - } - } - } - } - } -}; - -/** - * Function: weightedMedian - * - * Sweeps up or down the layout attempting to minimise the median placement - * of connected cells on adjacent ranks - * - * Parameters: - * - * iteration - the iteration number of the main loop - * model - the internal model describing the hierarchy - */ -mxMedianHybridCrossingReduction.prototype.weightedMedian = function(iteration, model) -{ - // Reverse sweep direction each time through this method - var downwardSweep = (iteration % 2 == 0); - if (downwardSweep) - { - for (var j = model.maxRank - 1; j >= 0; j--) - { - this.medianRank(j, downwardSweep); - } - } - else - { - for (var j = 1; j < model.maxRank; j++) - { - this.medianRank(j, downwardSweep); - } - } -}; - -/** - * Function: medianRank - * - * Attempts to minimise the median placement of connected cells on this rank - * and one of the adjacent ranks - * - * Parameters: - * - * rankValue - the layer number of this rank - * downwardSweep - whether or not this is a downward sweep through the graph - */ -mxMedianHybridCrossingReduction.prototype.medianRank = function(rankValue, downwardSweep) -{ - var numCellsForRank = this.nestedBestRanks[rankValue].length; - var medianValues = []; - var reservedPositions = []; - - for (var i = 0; i < numCellsForRank; i++) - { - var cell = this.nestedBestRanks[rankValue][i]; - var sorterEntry = new MedianCellSorter(); - sorterEntry.cell = cell; - - // Flip whether or not equal medians are flipped on up and down - // sweeps - // TODO re-implement some kind of nudge - // medianValues[i].nudge = !downwardSweep; - var nextLevelConnectedCells; - - if (downwardSweep) - { - nextLevelConnectedCells = cell - .getNextLayerConnectedCells(rankValue); - } - else - { - nextLevelConnectedCells = cell - .getPreviousLayerConnectedCells(rankValue); - } - - var nextRankValue; - - if (downwardSweep) - { - nextRankValue = rankValue + 1; - } - else - { - nextRankValue = rankValue - 1; - } - - if (nextLevelConnectedCells != null - && nextLevelConnectedCells.length != 0) - { - sorterEntry.medianValue = this.medianValue( - nextLevelConnectedCells, nextRankValue); - medianValues.push(sorterEntry); - } - else - { - // Nodes with no adjacent vertices are flagged in the reserved array - // to indicate they should be left in their current position. - reservedPositions[cell.getGeneralPurposeVariable(rankValue)] = true; - } - } - - medianValues.sort(MedianCellSorter.prototype.compare); - - // Set the new position of each node within the rank using - // its temp variable - for (var i = 0; i < numCellsForRank; i++) - { - if (reservedPositions[i] == null) - { - var cell = medianValues.shift().cell; - cell.setGeneralPurposeVariable(rankValue, i); - } - } -}; - -/** - * Function: medianValue - * - * Calculates the median rank order positioning for the specified cell using - * the connected cells on the specified rank. Returns the median rank - * ordering value of the connected cells - * - * Parameters: - * - * connectedCells - the cells on the specified rank connected to the - * specified cell - * rankValue - the rank that the connected cell lie upon - */ -mxMedianHybridCrossingReduction.prototype.medianValue = function(connectedCells, rankValue) -{ - var medianValues = []; - var arrayCount = 0; - - for (var i = 0; i < connectedCells.length; i++) - { - var cell = connectedCells[i]; - medianValues[arrayCount++] = cell.getGeneralPurposeVariable(rankValue); - } - - // Sort() sorts lexicographically by default (i.e. 11 before 9) so force - // numerical order sort - medianValues.sort(function(a,b){return a - b;}); - - if (arrayCount % 2 == 1) - { - // For odd numbers of adjacent vertices return the median - return medianValues[Math.floor(arrayCount / 2)]; - } - else if (arrayCount == 2) - { - return ((medianValues[0] + medianValues[1]) / 2.0); - } - else - { - var medianPoint = arrayCount / 2; - var leftMedian = medianValues[medianPoint - 1] - medianValues[0]; - var rightMedian = medianValues[arrayCount - 1] - - medianValues[medianPoint]; - - return (medianValues[medianPoint - 1] * rightMedian + medianValues[medianPoint] - * leftMedian) - / (leftMedian + rightMedian); - } -}; - -/** - * Class: MedianCellSorter - * - * A utility class used to track cells whilst sorting occurs on the median - * values. Does not violate (x.compareTo(y)==0) == (x.equals(y)) - * - * Constructor: MedianCellSorter - * - * Constructs a new median cell sorter. - */ -function MedianCellSorter() -{ - // empty -}; - -/** - * Variable: medianValue - * - * The weighted value of the cell stored. - */ -MedianCellSorter.prototype.medianValue = 0; - -/** - * Variable: cell - * - * The cell whose median value is being calculated - */ -MedianCellSorter.prototype.cell = false; - -/** - * Function: compare - * - * Compares two MedianCellSorters. - */ -MedianCellSorter.prototype.compare = function(a, b) -{ - if (a != null && b != null) - { - if (b.medianValue > a.medianValue) - { - return -1; - } - else if (b.medianValue < a.medianValue) - { - return 1; - } - else - { - return 0; - } - } - else - { - return 0; - } -}; diff --git a/src/js/layout/hierarchical/stage/mxMinimumCycleRemover.js b/src/js/layout/hierarchical/stage/mxMinimumCycleRemover.js deleted file mode 100644 index 4f18f62..0000000 --- a/src/js/layout/hierarchical/stage/mxMinimumCycleRemover.js +++ /dev/null @@ -1,131 +0,0 @@ -/** - * $Id: mxMinimumCycleRemover.js,v 1.14 2010-01-04 11:18:26 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -/** - * Class: mxMinimumCycleRemover - * - * An implementation of the first stage of the Sugiyama layout. Straightforward - * longest path calculation of layer assignment - * - * Constructor: mxMinimumCycleRemover - * - * Creates a cycle remover for the given internal model. - */ -function mxMinimumCycleRemover(layout) -{ - this.layout = layout; -}; - -/** - * Extends mxHierarchicalLayoutStage. - */ -mxMinimumCycleRemover.prototype = new mxHierarchicalLayoutStage(); -mxMinimumCycleRemover.prototype.constructor = mxMinimumCycleRemover; - -/** - * Variable: layout - * - * Reference to the enclosing <mxHierarchicalLayout>. - */ -mxMinimumCycleRemover.prototype.layout = null; - -/** - * Function: execute - * - * Takes the graph detail and configuration information within the facade - * and creates the resulting laid out graph within that facade for further - * use. - */ -mxMinimumCycleRemover.prototype.execute = function(parent) -{ - var model = this.layout.getModel(); - var seenNodes = new Object(); - var unseenNodes = mxUtils.clone(model.vertexMapper, null, true); - - // Perform a dfs through the internal model. If a cycle is found, - // reverse it. - var rootsArray = null; - - if (model.roots != null) - { - var modelRoots = model.roots; - rootsArray = []; - - for (var i = 0; i < modelRoots.length; i++) - { - var nodeId = mxCellPath.create(modelRoots[i]); - rootsArray[i] = model.vertexMapper[nodeId]; - } - } - - model.visit(function(parent, node, connectingEdge, layer, seen) - { - // Check if the cell is in it's own ancestor list, if so - // invert the connecting edge and reverse the target/source - // relationship to that edge in the parent and the cell - if (node.isAncestor(parent)) - { - connectingEdge.invert(); - mxUtils.remove(connectingEdge, parent.connectsAsSource); - parent.connectsAsTarget.push(connectingEdge); - mxUtils.remove(connectingEdge, node.connectsAsTarget); - node.connectsAsSource.push(connectingEdge); - } - - var cellId = mxCellPath.create(node.cell); - seenNodes[cellId] = node; - delete unseenNodes[cellId]; - }, rootsArray, true, null); - - var possibleNewRoots = null; - - if (unseenNodes.lenth > 0) - { - possibleNewRoots = mxUtils.clone(unseenNodes, null, true); - } - - // If there are any nodes that should be nodes that the dfs can miss - // these need to be processed with the dfs and the roots assigned - // correctly to form a correct internal model - var seenNodesCopy = mxUtils.clone(seenNodes, null, true); - - // Pick a random cell and dfs from it - model.visit(function(parent, node, connectingEdge, layer, seen) - { - // Check if the cell is in it's own ancestor list, if so - // invert the connecting edge and reverse the target/source - // relationship to that edge in the parent and the cell - if (node.isAncestor(parent)) - { - connectingEdge.invert(); - mxUtils.remove(connectingEdge, parent.connectsAsSource); - node.connectsAsSource.push(connectingEdge); - parent.connectsAsTarget.push(connectingEdge); - mxUtils.remove(connectingEdge, node.connectsAsTarget); - } - - var cellId = mxCellPath.create(node.cell); - seenNodes[cellId] = node; - delete unseenNodes[cellId]; - }, unseenNodes, true, seenNodesCopy); - - var graph = this.layout.getGraph(); - - if (possibleNewRoots != null && possibleNewRoots.length > 0) - { - var roots = model.roots; - - for (var i = 0; i < possibleNewRoots.length; i++) - { - var node = possibleNewRoots[i]; - var realNode = node.cell; - var numIncomingEdges = graph.getIncomingEdges(realNode).length; - - if (numIncomingEdges == 0) - { - roots.push(realNode); - } - } - } -}; diff --git a/src/js/layout/mxCircleLayout.js b/src/js/layout/mxCircleLayout.js deleted file mode 100644 index e3e6ec1..0000000 --- a/src/js/layout/mxCircleLayout.js +++ /dev/null @@ -1,203 +0,0 @@ -/** - * $Id: mxCircleLayout.js,v 1.25 2012-08-22 17:26:12 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -/** - * Class: mxCircleLayout - * - * Extends <mxGraphLayout> to implement a circluar layout for a given radius. - * The vertices do not need to be connected for this layout to work and all - * connections between vertices are not taken into account. - * - * Example: - * - * (code) - * var layout = new mxCircleLayout(graph); - * layout.execute(graph.getDefaultParent()); - * (end) - * - * Constructor: mxCircleLayout - * - * Constructs a new circular layout for the specified radius. - * - * Arguments: - * - * graph - <mxGraph> that contains the cells. - * radius - Optional radius as an int. Default is 100. - */ -function mxCircleLayout(graph, radius) -{ - mxGraphLayout.call(this, graph); - this.radius = (radius != null) ? radius : 100; -}; - -/** - * Extends mxGraphLayout. - */ -mxCircleLayout.prototype = new mxGraphLayout(); -mxCircleLayout.prototype.constructor = mxCircleLayout; - -/** - * Variable: radius - * - * Integer specifying the size of the radius. Default is 100. - */ -mxCircleLayout.prototype.radius = null; - -/** - * Variable: moveCircle - * - * Boolean specifying if the circle should be moved to the top, - * left corner specified by <x0> and <y0>. Default is false. - */ -mxCircleLayout.prototype.moveCircle = false; - -/** - * Variable: x0 - * - * Integer specifying the left coordinate of the circle. - * Default is 0. - */ -mxCircleLayout.prototype.x0 = 0; - -/** - * Variable: y0 - * - * Integer specifying the top coordinate of the circle. - * Default is 0. - */ -mxCircleLayout.prototype.y0 = 0; - -/** - * Variable: resetEdges - * - * Specifies if all edge points of traversed edges should be removed. - * Default is true. - */ -mxCircleLayout.prototype.resetEdges = true; - -/** - * Variable: disableEdgeStyle - * - * Specifies if the STYLE_NOEDGESTYLE flag should be set on edges that are - * modified by the result. Default is true. - */ -mxCircleLayout.prototype.disableEdgeStyle = true; - -/** - * Function: execute - * - * Implements <mxGraphLayout.execute>. - */ -mxCircleLayout.prototype.execute = function(parent) -{ - var model = this.graph.getModel(); - - // Moves the vertices to build a circle. Makes sure the - // radius is large enough for the vertices to not - // overlap - model.beginUpdate(); - try - { - // Gets all vertices inside the parent and finds - // the maximum dimension of the largest vertex - var max = 0; - var top = null; - var left = null; - var vertices = []; - var childCount = model.getChildCount(parent); - - for (var i = 0; i < childCount; i++) - { - var cell = model.getChildAt(parent, i); - - if (!this.isVertexIgnored(cell)) - { - vertices.push(cell); - var bounds = this.getVertexBounds(cell); - - if (top == null) - { - top = bounds.y; - } - else - { - top = Math.min(top, bounds.y); - } - - if (left == null) - { - left = bounds.x; - } - else - { - left = Math.min(left, bounds.x); - } - - max = Math.max(max, Math.max(bounds.width, bounds.height)); - } - else if (!this.isEdgeIgnored(cell)) - { - // Resets the points on the traversed edge - if (this.resetEdges) - { - this.graph.resetEdge(cell); - } - - if (this.disableEdgeStyle) - { - this.setEdgeStyleEnabled(cell, false); - } - } - } - - var r = this.getRadius(vertices.length, max); - - // Moves the circle to the specified origin - if (this.moveCircle) - { - left = this.x0; - top = this.y0; - } - - this.circle(vertices, r, left, top); - } - finally - { - model.endUpdate(); - } -}; - -/** - * Function: getRadius - * - * Returns the radius to be used for the given vertex count. Max is the maximum - * width or height of all vertices in the layout. - */ -mxCircleLayout.prototype.getRadius = function(count, max) -{ - return Math.max(count * max / Math.PI, this.radius); -}; - -/** - * Function: circle - * - * Executes the circular layout for the specified array - * of vertices and the given radius. This is called from - * <execute>. - */ -mxCircleLayout.prototype.circle = function(vertices, r, left, top) -{ - var vertexCount = vertices.length; - var phi = 2 * Math.PI / vertexCount; - - for (var i = 0; i < vertexCount; i++) - { - if (this.isVertexMovable(vertices[i])) - { - this.setVertexLocation(vertices[i], - left + r + r * Math.sin(i*phi), - top + r + r * Math.cos(i*phi)); - } - } -}; diff --git a/src/js/layout/mxCompactTreeLayout.js b/src/js/layout/mxCompactTreeLayout.js deleted file mode 100644 index db6324c..0000000 --- a/src/js/layout/mxCompactTreeLayout.js +++ /dev/null @@ -1,995 +0,0 @@ -/** - * $Id: mxCompactTreeLayout.js,v 1.57 2012-05-24 13:09:34 david Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -/** - * Class: mxCompactTreeLayout - * - * Extends <mxGraphLayout> to implement a compact tree (Moen) algorithm. This - * layout is suitable for graphs that have no cycles (trees). Vertices that are - * not connected to the tree will be ignored by this layout. - * - * Example: - * - * (code) - * var layout = new mxCompactTreeLayout(graph); - * layout.execute(graph.getDefaultParent()); - * (end) - * - * Constructor: mxCompactTreeLayout - * - * Constructs a new compact tree layout for the specified graph - * and orientation. - */ -function mxCompactTreeLayout(graph, horizontal, invert) -{ - mxGraphLayout.call(this, graph); - this.horizontal = (horizontal != null) ? horizontal : true; - this.invert = (invert != null) ? invert : false; -}; - -/** - * Extends mxGraphLayout. - */ -mxCompactTreeLayout.prototype = new mxGraphLayout(); -mxCompactTreeLayout.prototype.constructor = mxCompactTreeLayout; - -/** - * Variable: horizontal - * - * Specifies the orientation of the layout. Default is true. - */ -mxCompactTreeLayout.prototype.horizontal = null; - -/** - * Variable: invert - * - * Specifies if edge directions should be inverted. Default is false. - */ -mxCompactTreeLayout.prototype.invert = null; - -/** - * Variable: resizeParent - * - * If the parents should be resized to match the width/height of the - * children. Default is true. - */ -mxCompactTreeLayout.prototype.resizeParent = true; - -/** - * Variable: groupPadding - * - * Padding added to resized parents - */ -mxCompactTreeLayout.prototype.groupPadding = 10; - -/** - * Variable: parentsChanged - * - * A set of the parents that need updating based on children - * process as part of the layout - */ -mxCompactTreeLayout.prototype.parentsChanged = null; - -/** - * Variable: moveTree - * - * Specifies if the tree should be moved to the top, left corner - * if it is inside a top-level layer. Default is false. - */ -mxCompactTreeLayout.prototype.moveTree = false; - -/** - * Variable: levelDistance - * - * Holds the levelDistance. Default is 10. - */ -mxCompactTreeLayout.prototype.levelDistance = 10; - -/** - * Variable: nodeDistance - * - * Holds the nodeDistance. Default is 20. - */ -mxCompactTreeLayout.prototype.nodeDistance = 20; - -/** - * Variable: resetEdges - * - * Specifies if all edge points of traversed edges should be removed. - * Default is true. - */ -mxCompactTreeLayout.prototype.resetEdges = true; - -/** - * Variable: prefHozEdgeSep - * - * The preferred horizontal distance between edges exiting a vertex - */ -mxCompactTreeLayout.prototype.prefHozEdgeSep = 5; - -/** - * Variable: prefVertEdgeOff - * - * The preferred vertical offset between edges exiting a vertex - */ -mxCompactTreeLayout.prototype.prefVertEdgeOff = 4; - -/** - * Variable: minEdgeJetty - * - * The minimum distance for an edge jetty from a vertex - */ -mxCompactTreeLayout.prototype.minEdgeJetty = 8; - -/** - * Variable: channelBuffer - * - * The size of the vertical buffer in the center of inter-rank channels - * where edge control points should not be placed - */ -mxCompactTreeLayout.prototype.channelBuffer = 4; - -/** - * Variable: edgeRouting - * - * Whether or not to apply the internal tree edge routing - */ -mxCompactTreeLayout.prototype.edgeRouting = true; - -/** - * Function: isVertexIgnored - * - * Returns a boolean indicating if the given <mxCell> should be ignored as a - * vertex. This returns true if the cell has no connections. - * - * Parameters: - * - * vertex - <mxCell> whose ignored state should be returned. - */ -mxCompactTreeLayout.prototype.isVertexIgnored = function(vertex) -{ - return mxGraphLayout.prototype.isVertexIgnored.apply(this, arguments) || - this.graph.getConnections(vertex).length == 0; -}; - -/** - * Function: isHorizontal - * - * Returns <horizontal>. - */ -mxCompactTreeLayout.prototype.isHorizontal = function() -{ - return this.horizontal; -}; - -/** - * Function: execute - * - * Implements <mxGraphLayout.execute>. - * - * If the parent has any connected edges, then it is used as the root of - * the tree. Else, <mxGraph.findTreeRoots> will be used to find a suitable - * root node within the set of children of the given parent. - * - * Parameters: - * - * parent - <mxCell> whose children should be laid out. - * root - Optional <mxCell> that will be used as the root of the tree. - */ -mxCompactTreeLayout.prototype.execute = function(parent, root) -{ - this.parent = parent; - var model = this.graph.getModel(); - - if (root == null) - { - // Takes the parent as the root if it has outgoing edges - if (this.graph.getEdges(parent, model.getParent(parent), - this.invert, !this.invert, false).length > 0) - { - root = parent; - } - - // Tries to find a suitable root in the parent's - // children - else - { - var roots = this.graph.findTreeRoots(parent, true, this.invert); - - if (roots.length > 0) - { - for (var i = 0; i < roots.length; i++) - { - if (!this.isVertexIgnored(roots[i]) && - this.graph.getEdges(roots[i], null, - this.invert, !this.invert, false).length > 0) - { - root = roots[i]; - break; - } - } - } - } - } - - if (root != null) - { - if (this.resizeParent) - { - this.parentsChanged = new Object(); - } - else - { - this.parentsChanged = null; - } - - model.beginUpdate(); - - try - { - var node = this.dfs(root, parent); - - if (node != null) - { - this.layout(node); - var x0 = this.graph.gridSize; - var y0 = x0; - - if (!this.moveTree) - { - var g = this.getVertexBounds(root); - - if (g != null) - { - x0 = g.x; - y0 = g.y; - } - } - - var bounds = null; - - if (this.isHorizontal()) - { - bounds = this.horizontalLayout(node, x0, y0); - } - else - { - bounds = this.verticalLayout(node, null, x0, y0); - } - - if (bounds != null) - { - var dx = 0; - var dy = 0; - - if (bounds.x < 0) - { - dx = Math.abs(x0 - bounds.x); - } - - if (bounds.y < 0) - { - dy = Math.abs(y0 - bounds.y); - } - - if (dx != 0 || dy != 0) - { - this.moveNode(node, dx, dy); - } - - if (this.resizeParent) - { - this.adjustParents(); - } - - if (this.edgeRouting) - { - // Iterate through all edges setting their positions - this.localEdgeProcessing(node); - } - } - } - } - finally - { - model.endUpdate(); - } - } -}; - -/** - * Function: moveNode - * - * Moves the specified node and all of its children by the given amount. - */ -mxCompactTreeLayout.prototype.moveNode = function(node, dx, dy) -{ - node.x += dx; - node.y += dy; - this.apply(node); - - var child = node.child; - - while (child != null) - { - this.moveNode(child, dx, dy); - child = child.next; - } -}; - -/** - * Function: dfs - * - * Does a depth first search starting at the specified cell. - * Makes sure the specified parent is never left by the - * algorithm. - */ -mxCompactTreeLayout.prototype.dfs = function(cell, parent, visited) -{ - visited = (visited != null) ? visited : []; - - var id = mxCellPath.create(cell); - var node = null; - - if (cell != null && visited[id] == null && !this.isVertexIgnored(cell)) - { - visited[id] = cell; - node = this.createNode(cell); - - var model = this.graph.getModel(); - var prev = null; - var out = this.graph.getEdges(cell, parent, this.invert, !this.invert, false, true); - var view = this.graph.getView(); - - for (var i = 0; i < out.length; i++) - { - var edge = out[i]; - - if (!this.isEdgeIgnored(edge)) - { - // Resets the points on the traversed edge - if (this.resetEdges) - { - this.setEdgePoints(edge, null); - } - - if (this.edgeRouting) - { - this.setEdgeStyleEnabled(edge, false); - this.setEdgePoints(edge, null); - } - - // Checks if terminal in same swimlane - var state = view.getState(edge); - var target = (state != null) ? state.getVisibleTerminal(this.invert) : view.getVisibleTerminal(edge, this.invert); - var tmp = this.dfs(target, parent, visited); - - if (tmp != null && model.getGeometry(target) != null) - { - if (prev == null) - { - node.child = tmp; - } - else - { - prev.next = tmp; - } - - prev = tmp; - } - } - } - } - - return node; -}; - -/** - * Function: layout - * - * Starts the actual compact tree layout algorithm - * at the given node. - */ -mxCompactTreeLayout.prototype.layout = function(node) -{ - if (node != null) - { - var child = node.child; - - while (child != null) - { - this.layout(child); - child = child.next; - } - - if (node.child != null) - { - this.attachParent(node, this.join(node)); - } - else - { - this.layoutLeaf(node); - } - } -}; - -/** - * Function: horizontalLayout - */ -mxCompactTreeLayout.prototype.horizontalLayout = function(node, x0, y0, bounds) -{ - node.x += x0 + node.offsetX; - node.y += y0 + node.offsetY; - bounds = this.apply(node, bounds); - var child = node.child; - - if (child != null) - { - bounds = this.horizontalLayout(child, node.x, node.y, bounds); - var siblingOffset = node.y + child.offsetY; - var s = child.next; - - while (s != null) - { - bounds = this.horizontalLayout(s, node.x + child.offsetX, siblingOffset, bounds); - siblingOffset += s.offsetY; - s = s.next; - } - } - - return bounds; -}; - -/** - * Function: verticalLayout - */ -mxCompactTreeLayout.prototype.verticalLayout = function(node, parent, x0, y0, bounds) -{ - node.x += x0 + node.offsetY; - node.y += y0 + node.offsetX; - bounds = this.apply(node, bounds); - var child = node.child; - - if (child != null) - { - bounds = this.verticalLayout(child, node, node.x, node.y, bounds); - var siblingOffset = node.x + child.offsetY; - var s = child.next; - - while (s != null) - { - bounds = this.verticalLayout(s, node, siblingOffset, node.y + child.offsetX, bounds); - siblingOffset += s.offsetY; - s = s.next; - } - } - - return bounds; -}; - -/** - * Function: attachParent - */ -mxCompactTreeLayout.prototype.attachParent = function(node, height) -{ - var x = this.nodeDistance + this.levelDistance; - var y2 = (height - node.width) / 2 - this.nodeDistance; - var y1 = y2 + node.width + 2 * this.nodeDistance - height; - - node.child.offsetX = x + node.height; - node.child.offsetY = y1; - - node.contour.upperHead = this.createLine(node.height, 0, - this.createLine(x, y1, node.contour.upperHead)); - node.contour.lowerHead = this.createLine(node.height, 0, - this.createLine(x, y2, node.contour.lowerHead)); -}; - -/** - * Function: layoutLeaf - */ -mxCompactTreeLayout.prototype.layoutLeaf = function(node) -{ - var dist = 2 * this.nodeDistance; - - node.contour.upperTail = this.createLine( - node.height + dist, 0); - node.contour.upperHead = node.contour.upperTail; - node.contour.lowerTail = this.createLine( - 0, -node.width - dist); - node.contour.lowerHead = this.createLine( - node.height + dist, 0, node.contour.lowerTail); -}; - -/** - * Function: join - */ -mxCompactTreeLayout.prototype.join = function(node) -{ - var dist = 2 * this.nodeDistance; - - var child = node.child; - node.contour = child.contour; - var h = child.width + dist; - var sum = h; - child = child.next; - - while (child != null) - { - var d = this.merge(node.contour, child.contour); - child.offsetY = d + h; - child.offsetX = 0; - h = child.width + dist; - sum += d + h; - child = child.next; - } - - return sum; -}; - -/** - * Function: merge - */ -mxCompactTreeLayout.prototype.merge = function(p1, p2) -{ - var x = 0; - var y = 0; - var total = 0; - - var upper = p1.lowerHead; - var lower = p2.upperHead; - - while (lower != null && upper != null) - { - var d = this.offset(x, y, lower.dx, lower.dy, - upper.dx, upper.dy); - y += d; - total += d; - - if (x + lower.dx <= upper.dx) - { - x += lower.dx; - y += lower.dy; - lower = lower.next; - } - else - { - x -= upper.dx; - y -= upper.dy; - upper = upper.next; - } - } - - if (lower != null) - { - var b = this.bridge(p1.upperTail, 0, 0, lower, x, y); - p1.upperTail = (b.next != null) ? p2.upperTail : b; - p1.lowerTail = p2.lowerTail; - } - else - { - var b = this.bridge(p2.lowerTail, x, y, upper, 0, 0); - - if (b.next == null) - { - p1.lowerTail = b; - } - } - - p1.lowerHead = p2.lowerHead; - - return total; -}; - -/** - * Function: offset - */ -mxCompactTreeLayout.prototype.offset = function(p1, p2, a1, a2, b1, b2) -{ - var d = 0; - - if (b1 <= p1 || p1 + a1 <= 0) - { - return 0; - } - - var t = b1 * a2 - a1 * b2; - - if (t > 0) - { - if (p1 < 0) - { - var s = p1 * a2; - d = s / a1 - p2; - } - else if (p1 > 0) - { - var s = p1 * b2; - d = s / b1 - p2; - } - else - { - d = -p2; - } - } - else if (b1 < p1 + a1) - { - var s = (b1 - p1) * a2; - d = b2 - (p2 + s / a1); - } - else if (b1 > p1 + a1) - { - var s = (a1 + p1) * b2; - d = s / b1 - (p2 + a2); - } - else - { - d = b2 - (p2 + a2); - } - - if (d > 0) - { - return d; - } - else - { - return 0; - } -}; - -/** - * Function: bridge - */ -mxCompactTreeLayout.prototype.bridge = function(line1, x1, y1, line2, x2, y2) -{ - var dx = x2 + line2.dx - x1; - var dy = 0; - var s = 0; - - if (line2.dx == 0) - { - dy = line2.dy; - } - else - { - s = dx * line2.dy; - dy = s / line2.dx; - } - - var r = this.createLine(dx, dy, line2.next); - line1.next = this.createLine(0, y2 + line2.dy - dy - y1, r); - - return r; -}; - -/** - * Function: createNode - */ -mxCompactTreeLayout.prototype.createNode = function(cell) -{ - var node = new Object(); - node.cell = cell; - node.x = 0; - node.y = 0; - node.width = 0; - node.height = 0; - - var geo = this.getVertexBounds(cell); - - if (geo != null) - { - if (this.isHorizontal()) - { - node.width = geo.height; - node.height = geo.width; - } - else - { - node.width = geo.width; - node.height = geo.height; - } - } - - node.offsetX = 0; - node.offsetY = 0; - node.contour = new Object(); - - return node; -}; - -/** - * Function: apply - */ -mxCompactTreeLayout.prototype.apply = function(node, bounds) -{ - var model = this.graph.getModel(); - var cell = node.cell; - var g = model.getGeometry(cell); - - if (cell != null && g != null) - { - if (this.isVertexMovable(cell)) - { - g = this.setVertexLocation(cell, node.x, node.y); - - if (this.resizeParent) - { - var parent = model.getParent(cell); - var id = mxCellPath.create(parent); - - // Implements set semantic - if (this.parentsChanged[id] == null) - { - this.parentsChanged[id] = parent; - } - } - } - - if (bounds == null) - { - bounds = new mxRectangle(g.x, g.y, g.width, g.height); - } - else - { - bounds = new mxRectangle(Math.min(bounds.x, g.x), - Math.min(bounds.y, g.y), - Math.max(bounds.x + bounds.width, g.x + g.width), - Math.max(bounds.y + bounds.height, g.y + g.height)); - } - } - - return bounds; -}; - -/** - * Function: createLine - */ -mxCompactTreeLayout.prototype.createLine = function(dx, dy, next) -{ - var line = new Object(); - line.dx = dx; - line.dy = dy; - line.next = next; - - return line; -}; - -/** - * Function: adjustParents - * - * Adjust parent cells whose child geometries have changed. The default - * implementation adjusts the group to just fit around the children with - * a padding. - */ -mxCompactTreeLayout.prototype.adjustParents = function() -{ - var tmp = []; - - for (var id in this.parentsChanged) - { - tmp.push(this.parentsChanged[id]); - } - - this.arrangeGroups(mxUtils.sortCells(tmp, true), this.groupPadding); -}; - -/** - * Function: localEdgeProcessing - * - * Moves the specified node and all of its children by the given amount. - */ -mxCompactTreeLayout.prototype.localEdgeProcessing = function(node) -{ - this.processNodeOutgoing(node); - var child = node.child; - - while (child != null) - { - this.localEdgeProcessing(child); - child = child.next; - } -}; - -/** - * Function: localEdgeProcessing - * - * Separates the x position of edges as they connect to vertices - */ -mxCompactTreeLayout.prototype.processNodeOutgoing = function(node) -{ - var child = node.child; - var parentCell = node.cell; - - var childCount = 0; - var sortedCells = []; - - while (child != null) - { - childCount++; - - var sortingCriterion = child.x; - - if (this.horizontal) - { - sortingCriterion = child.y; - } - - sortedCells.push(new WeightedCellSorter(child, sortingCriterion)); - child = child.next; - } - - sortedCells.sort(WeightedCellSorter.prototype.compare); - - var availableWidth = node.width; - - var requiredWidth = (childCount + 1) * this.prefHozEdgeSep; - - // Add a buffer on the edges of the vertex if the edge count allows - if (availableWidth > requiredWidth + (2 * this.prefHozEdgeSep)) - { - availableWidth -= 2 * this.prefHozEdgeSep; - } - - var edgeSpacing = availableWidth / childCount; - - var currentXOffset = edgeSpacing / 2.0; - - if (availableWidth > requiredWidth + (2 * this.prefHozEdgeSep)) - { - currentXOffset += this.prefHozEdgeSep; - } - - var currentYOffset = this.minEdgeJetty - this.prefVertEdgeOff; - var maxYOffset = 0; - - var parentBounds = this.getVertexBounds(parentCell); - child = node.child; - - for (var j = 0; j < sortedCells.length; j++) - { - var childCell = sortedCells[j].cell.cell; - var childBounds = this.getVertexBounds(childCell); - - var edges = this.graph.getEdgesBetween(parentCell, - childCell, false); - - var newPoints = []; - var x = 0; - var y = 0; - - for (var i = 0; i < edges.length; i++) - { - if (this.horizontal) - { - // Use opposite co-ords, calculation was done for - // - x = parentBounds.x + parentBounds.width; - y = parentBounds.y + currentXOffset; - newPoints.push(new mxPoint(x, y)); - x = parentBounds.x + parentBounds.width - + currentYOffset; - newPoints.push(new mxPoint(x, y)); - y = childBounds.y + childBounds.height / 2.0; - newPoints.push(new mxPoint(x, y)); - this.setEdgePoints(edges[i], newPoints); - } - else - { - x = parentBounds.x + currentXOffset; - y = parentBounds.y + parentBounds.height; - newPoints.push(new mxPoint(x, y)); - y = parentBounds.y + parentBounds.height - + currentYOffset; - newPoints.push(new mxPoint(x, y)); - x = childBounds.x + childBounds.width / 2.0; - newPoints.push(new mxPoint(x, y)); - this.setEdgePoints(edges[i], newPoints); - } - } - - if (j < childCount / 2) - { - currentYOffset += this.prefVertEdgeOff; - } - else if (j > childCount / 2) - { - currentYOffset -= this.prefVertEdgeOff; - } - // Ignore the case if equals, this means the second of 2 - // jettys with the same y (even number of edges) - - // pos[k * 2] = currentX; - currentXOffset += edgeSpacing; - // pos[k * 2 + 1] = currentYOffset; - - maxYOffset = Math.max(maxYOffset, currentYOffset); - } -}; - -/** - * Class: WeightedCellSorter - * - * A utility class used to track cells whilst sorting occurs on the weighted - * sum of their connected edges. Does not violate (x.compareTo(y)==0) == - * (x.equals(y)) - * - * Constructor: WeightedCellSorter - * - * Constructs a new weighted cell sorted for the given cell and weight. - */ -function WeightedCellSorter(cell, weightedValue) -{ - this.cell = cell; - this.weightedValue = weightedValue; -}; - -/** - * Variable: weightedValue - * - * The weighted value of the cell stored. - */ -WeightedCellSorter.prototype.weightedValue = 0; - -/** - * Variable: nudge - * - * Whether or not to flip equal weight values. - */ -WeightedCellSorter.prototype.nudge = false; - -/** - * Variable: visited - * - * Whether or not this cell has been visited in the current assignment. - */ -WeightedCellSorter.prototype.visited = false; - -/** - * Variable: rankIndex - * - * The index this cell is in the model rank. - */ -WeightedCellSorter.prototype.rankIndex = null; - -/** - * Variable: cell - * - * The cell whose median value is being calculated. - */ -WeightedCellSorter.prototype.cell = null; - -/** - * Function: compare - * - * Compares two WeightedCellSorters. - */ -WeightedCellSorter.prototype.compare = function(a, b) -{ - if (a != null && b != null) - { - if (b.weightedValue > a.weightedValue) - { - return 1; - } - else if (b.weightedValue < a.weightedValue) - { - return -1; - } - else - { - if (b.nudge) - { - return 1; - } - else - { - return -1; - } - } - } - else - { - return 0; - } -};
\ No newline at end of file diff --git a/src/js/layout/mxCompositeLayout.js b/src/js/layout/mxCompositeLayout.js deleted file mode 100644 index 2ceb5f5..0000000 --- a/src/js/layout/mxCompositeLayout.js +++ /dev/null @@ -1,101 +0,0 @@ -/** - * $Id: mxCompositeLayout.js,v 1.11 2010-01-02 09:45:15 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -/** - * Class: mxCompositeLayout - * - * Allows to compose multiple layouts into a single layout. The master layout - * is the layout that handles move operations if another layout than the first - * element in <layouts> should be used. The <master> layout is not executed as - * the code assumes that it is part of <layouts>. - * - * Example: - * (code) - * var first = new mxFastOrganicLayout(graph); - * var second = new mxParallelEdgeLayout(graph); - * var layout = new mxCompositeLayout(graph, [first, second], first); - * layout.execute(graph.getDefaultParent()); - * (end) - * - * Constructor: mxCompositeLayout - * - * Constructs a new layout using the given layouts. The graph instance is - * required for creating the transaction that contains all layouts. - * - * Arguments: - * - * graph - Reference to the enclosing <mxGraph>. - * layouts - Array of <mxGraphLayouts>. - * master - Optional layout that handles moves. If no layout is given then - * the first layout of the above array is used to handle moves. - */ -function mxCompositeLayout(graph, layouts, master) -{ - mxGraphLayout.call(this, graph); - this.layouts = layouts; - this.master = master; -}; - -/** - * Extends mxGraphLayout. - */ -mxCompositeLayout.prototype = new mxGraphLayout(); -mxCompositeLayout.prototype.constructor = mxCompositeLayout; - -/** - * Variable: layouts - * - * Holds the array of <mxGraphLayouts> that this layout contains. - */ -mxCompositeLayout.prototype.layouts = null; - -/** - * Variable: layouts - * - * Reference to the <mxGraphLayouts> that handles moves. If this is null - * then the first layout in <layouts> is used. - */ -mxCompositeLayout.prototype.master = null; - -/** - * Function: moveCell - * - * Implements <mxGraphLayout.moveCell> by calling move on <master> or the first - * layout in <layouts>. - */ -mxCompositeLayout.prototype.moveCell = function(cell, x, y) -{ - if (this.master != null) - { - this.master.move.apply(this.master, arguments); - } - else - { - this.layouts[0].move.apply(this.layouts[0], arguments); - } -}; - -/** - * Function: execute - * - * Implements <mxGraphLayout.execute> by executing all <layouts> in a - * single transaction. - */ -mxCompositeLayout.prototype.execute = function(parent) -{ - var model = this.graph.getModel(); - - model.beginUpdate(); - try - { - for (var i = 0; i < this.layouts.length; i++) - { - this.layouts[i].execute.apply(this.layouts[i], arguments); - } - } - finally - { - model.endUpdate(); - } -}; diff --git a/src/js/layout/mxEdgeLabelLayout.js b/src/js/layout/mxEdgeLabelLayout.js deleted file mode 100644 index 2bfb3c2..0000000 --- a/src/js/layout/mxEdgeLabelLayout.js +++ /dev/null @@ -1,165 +0,0 @@ -/** - * $Id: mxEdgeLabelLayout.js,v 1.8 2010-01-04 11:18:25 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -/** - * Class: mxEdgeLabelLayout - * - * Extends <mxGraphLayout> to implement an edge label layout. This layout - * makes use of cell states, which means the graph must be validated in - * a graph view (so that the label bounds are available) before this layout - * can be executed. - * - * Example: - * - * (code) - * var layout = new mxEdgeLabelLayout(graph); - * layout.execute(graph.getDefaultParent()); - * (end) - * - * Constructor: mxEdgeLabelLayout - * - * Constructs a new edge label layout. - * - * Arguments: - * - * graph - <mxGraph> that contains the cells. - */ -function mxEdgeLabelLayout(graph, radius) -{ - mxGraphLayout.call(this, graph); -}; - -/** - * Extends mxGraphLayout. - */ -mxEdgeLabelLayout.prototype = new mxGraphLayout(); -mxEdgeLabelLayout.prototype.constructor = mxEdgeLabelLayout; - -/** - * Function: execute - * - * Implements <mxGraphLayout.execute>. - */ -mxEdgeLabelLayout.prototype.execute = function(parent) -{ - var view = this.graph.view; - var model = this.graph.getModel(); - - // Gets all vertices and edges inside the parent - var edges = []; - var vertices = []; - var childCount = model.getChildCount(parent); - - for (var i = 0; i < childCount; i++) - { - var cell = model.getChildAt(parent, i); - var state = view.getState(cell); - - if (state != null) - { - if (!this.isVertexIgnored(cell)) - { - vertices.push(state); - } - else if (!this.isEdgeIgnored(cell)) - { - edges.push(state); - } - } - } - - this.placeLabels(vertices, edges); -}; - -/** - * Function: placeLabels - * - * Places the labels of the given edges. - */ -mxEdgeLabelLayout.prototype.placeLabels = function(v, e) -{ - var model = this.graph.getModel(); - - // Moves the vertices to build a circle. Makes sure the - // radius is large enough for the vertices to not - // overlap - model.beginUpdate(); - try - { - for (var i = 0; i < e.length; i++) - { - var edge = e[i]; - - if (edge != null && edge.text != null && - edge.text.boundingBox != null) - { - for (var j = 0; j < v.length; j++) - { - var vertex = v[j]; - - if (vertex != null) - { - this.avoid(edge, vertex); - } - } - } - } - } - finally - { - model.endUpdate(); - } -}; - -/** - * Function: avoid - * - * Places the labels of the given edges. - */ -mxEdgeLabelLayout.prototype.avoid = function(edge, vertex) -{ - var model = this.graph.getModel(); - var labRect = edge.text.boundingBox; - - if (mxUtils.intersects(labRect, vertex)) - { - var dy1 = -labRect.y - labRect.height + vertex.y; - var dy2 = -labRect.y + vertex.y + vertex.height; - - var dy = (Math.abs(dy1) < Math.abs(dy2)) ? dy1 : dy2; - - var dx1 = -labRect.x - labRect.width + vertex.x; - var dx2 = -labRect.x + vertex.x + vertex.width; - - var dx = (Math.abs(dx1) < Math.abs(dx2)) ? dx1 : dx2; - - if (Math.abs(dx) < Math.abs(dy)) - { - dy = 0; - } - else - { - dx = 0; - } - - var g = model.getGeometry(edge.cell); - - if (g != null) - { - g = g.clone(); - - if (g.offset != null) - { - g.offset.x += dx; - g.offset.y += dy; - } - else - { - g.offset = new mxPoint(dx, dy); - } - - model.setGeometry(edge.cell, g); - } - } -}; diff --git a/src/js/layout/mxFastOrganicLayout.js b/src/js/layout/mxFastOrganicLayout.js deleted file mode 100644 index d7d6b5d..0000000 --- a/src/js/layout/mxFastOrganicLayout.js +++ /dev/null @@ -1,591 +0,0 @@ -/** - * $Id: mxFastOrganicLayout.js,v 1.37 2011-04-28 13:14:55 david Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -/** - * Class: mxFastOrganicLayout - * - * Extends <mxGraphLayout> to implement a fast organic layout algorithm. - * The vertices need to be connected for this layout to work, vertices - * with no connections are ignored. - * - * Example: - * - * (code) - * var layout = new mxFastOrganicLayout(graph); - * layout.execute(graph.getDefaultParent()); - * (end) - * - * Constructor: mxCompactTreeLayout - * - * Constructs a new fast organic layout for the specified graph. - */ -function mxFastOrganicLayout(graph) -{ - mxGraphLayout.call(this, graph); -}; - -/** - * Extends mxGraphLayout. - */ -mxFastOrganicLayout.prototype = new mxGraphLayout(); -mxFastOrganicLayout.prototype.constructor = mxFastOrganicLayout; - -/** - * Variable: useInputOrigin - * - * Specifies if the top left corner of the input cells should be the origin - * of the layout result. Default is true. - */ -mxFastOrganicLayout.prototype.useInputOrigin = true; - -/** - * Variable: resetEdges - * - * Specifies if all edge points of traversed edges should be removed. - * Default is true. - */ -mxFastOrganicLayout.prototype.resetEdges = true; - -/** - * Variable: disableEdgeStyle - * - * Specifies if the STYLE_NOEDGESTYLE flag should be set on edges that are - * modified by the result. Default is true. - */ -mxFastOrganicLayout.prototype.disableEdgeStyle = true; - -/** - * Variable: forceConstant - * - * The force constant by which the attractive forces are divided and the - * replusive forces are multiple by the square of. The value equates to the - * average radius there is of free space around each node. Default is 50. - */ -mxFastOrganicLayout.prototype.forceConstant = 50; - -/** - * Variable: forceConstantSquared - * - * Cache of <forceConstant>^2 for performance. - */ -mxFastOrganicLayout.prototype.forceConstantSquared = 0; - -/** - * Variable: minDistanceLimit - * - * Minimal distance limit. Default is 2. Prevents of - * dividing by zero. - */ -mxFastOrganicLayout.prototype.minDistanceLimit = 2; - -/** - * Variable: minDistanceLimit - * - * Minimal distance limit. Default is 2. Prevents of - * dividing by zero. - */ -mxFastOrganicLayout.prototype.maxDistanceLimit = 500; - -/** - * Variable: minDistanceLimitSquared - * - * Cached version of <minDistanceLimit> squared. - */ -mxFastOrganicLayout.prototype.minDistanceLimitSquared = 4; - -/** - * Variable: initialTemp - * - * Start value of temperature. Default is 200. - */ -mxFastOrganicLayout.prototype.initialTemp = 200; - -/** - * Variable: temperature - * - * Temperature to limit displacement at later stages of layout. - */ -mxFastOrganicLayout.prototype.temperature = 0; - -/** - * Variable: maxIterations - * - * Total number of iterations to run the layout though. - */ -mxFastOrganicLayout.prototype.maxIterations = 0; - -/** - * Variable: iteration - * - * Current iteration count. - */ -mxFastOrganicLayout.prototype.iteration = 0; - -/** - * Variable: vertexArray - * - * An array of all vertices to be laid out. - */ -mxFastOrganicLayout.prototype.vertexArray; - -/** - * Variable: dispX - * - * An array of locally stored X co-ordinate displacements for the vertices. - */ -mxFastOrganicLayout.prototype.dispX; - -/** - * Variable: dispY - * - * An array of locally stored Y co-ordinate displacements for the vertices. - */ -mxFastOrganicLayout.prototype.dispY; - -/** - * Variable: cellLocation - * - * An array of locally stored co-ordinate positions for the vertices. - */ -mxFastOrganicLayout.prototype.cellLocation; - -/** - * Variable: radius - * - * The approximate radius of each cell, nodes only. - */ -mxFastOrganicLayout.prototype.radius; - -/** - * Variable: radiusSquared - * - * The approximate radius squared of each cell, nodes only. - */ -mxFastOrganicLayout.prototype.radiusSquared; - -/** - * Variable: isMoveable - * - * Array of booleans representing the movable states of the vertices. - */ -mxFastOrganicLayout.prototype.isMoveable; - -/** - * Variable: neighbours - * - * Local copy of cell neighbours. - */ -mxFastOrganicLayout.prototype.neighbours; - -/** - * Variable: indices - * - * Hashtable from cells to local indices. - */ -mxFastOrganicLayout.prototype.indices; - -/** - * Variable: allowedToRun - * - * Boolean flag that specifies if the layout is allowed to run. If this is - * set to false, then the layout exits in the following iteration. - */ -mxFastOrganicLayout.prototype.allowedToRun = true; - -/** - * Function: isVertexIgnored - * - * Returns a boolean indicating if the given <mxCell> should be ignored as a - * vertex. This returns true if the cell has no connections. - * - * Parameters: - * - * vertex - <mxCell> whose ignored state should be returned. - */ -mxFastOrganicLayout.prototype.isVertexIgnored = function(vertex) -{ - return mxGraphLayout.prototype.isVertexIgnored.apply(this, arguments) || - this.graph.getConnections(vertex).length == 0; -}; - -/** - * Function: execute - * - * Implements <mxGraphLayout.execute>. This operates on all children of the - * given parent where <isVertexIgnored> returns false. - */ -mxFastOrganicLayout.prototype.execute = function(parent) -{ - var model = this.graph.getModel(); - this.vertexArray = []; - var cells = this.graph.getChildVertices(parent); - - for (var i = 0; i < cells.length; i++) - { - if (!this.isVertexIgnored(cells[i])) - { - this.vertexArray.push(cells[i]); - } - } - - var initialBounds = (this.useInputOrigin) ? - this.graph.view.getBounds(this.vertexArray) : - null; - var n = this.vertexArray.length; - - this.indices = []; - this.dispX = []; - this.dispY = []; - this.cellLocation = []; - this.isMoveable = []; - this.neighbours = []; - this.radius = []; - this.radiusSquared = []; - - if (this.forceConstant < 0.001) - { - this.forceConstant = 0.001; - } - - this.forceConstantSquared = this.forceConstant * this.forceConstant; - - // Create a map of vertices first. This is required for the array of - // arrays called neighbours which holds, for each vertex, a list of - // ints which represents the neighbours cells to that vertex as - // the indices into vertexArray - for (var i = 0; i < this.vertexArray.length; i++) - { - var vertex = this.vertexArray[i]; - this.cellLocation[i] = []; - - // Set up the mapping from array indices to cells - var id = mxCellPath.create(vertex); - this.indices[id] = i; - var bounds = this.getVertexBounds(vertex); - - // Set the X,Y value of the internal version of the cell to - // the center point of the vertex for better positioning - var width = bounds.width; - var height = bounds.height; - - // Randomize (0, 0) locations - var x = bounds.x; - var y = bounds.y; - - this.cellLocation[i][0] = x + width / 2.0; - this.cellLocation[i][1] = y + height / 2.0; - this.radius[i] = Math.min(width, height); - this.radiusSquared[i] = this.radius[i] * this.radius[i]; - } - - // Moves cell location back to top-left from center locations used in - // algorithm, resetting the edge points is part of the transaction - model.beginUpdate(); - try - { - for (var i = 0; i < n; i++) - { - this.dispX[i] = 0; - this.dispY[i] = 0; - this.isMoveable[i] = this.isVertexMovable(this.vertexArray[i]); - - // Get lists of neighbours to all vertices, translate the cells - // obtained in indices into vertexArray and store as an array - // against the orginial cell index - var edges = this.graph.getConnections(this.vertexArray[i], parent); - var cells = this.graph.getOpposites(edges, this.vertexArray[i]); - this.neighbours[i] = []; - - for (var j = 0; j < cells.length; j++) - { - // Resets the points on the traversed edge - if (this.resetEdges) - { - this.graph.resetEdge(edges[j]); - } - - if (this.disableEdgeStyle) - { - this.setEdgeStyleEnabled(edges[j], false); - } - - // Looks the cell up in the indices dictionary - var id = mxCellPath.create(cells[j]); - var index = this.indices[id]; - - // Check the connected cell in part of the vertex list to be - // acted on by this layout - if (index != null) - { - this.neighbours[i][j] = index; - } - - // Else if index of the other cell doesn't correspond to - // any cell listed to be acted upon in this layout. Set - // the index to the value of this vertex (a dummy self-loop) - // so the attraction force of the edge is not calculated - else - { - this.neighbours[i][j] = i; - } - } - } - this.temperature = this.initialTemp; - - // If max number of iterations has not been set, guess it - if (this.maxIterations == 0) - { - this.maxIterations = 20 * Math.sqrt(n); - } - - // Main iteration loop - for (this.iteration = 0; this.iteration < this.maxIterations; this.iteration++) - { - if (!this.allowedToRun) - { - return; - } - - // Calculate repulsive forces on all vertices - this.calcRepulsion(); - - // Calculate attractive forces through edges - this.calcAttraction(); - - this.calcPositions(); - this.reduceTemperature(); - } - - var minx = null; - var miny = null; - - for (var i = 0; i < this.vertexArray.length; i++) - { - var vertex = this.vertexArray[i]; - - if (this.isVertexMovable(vertex)) - { - var bounds = this.getVertexBounds(vertex); - - if (bounds != null) - { - this.cellLocation[i][0] -= bounds.width / 2.0; - this.cellLocation[i][1] -= bounds.height / 2.0; - - var x = this.graph.snap(this.cellLocation[i][0]); - var y = this.graph.snap(this.cellLocation[i][1]); - - this.setVertexLocation(vertex, x, y); - - if (minx == null) - { - minx = x; - } - else - { - minx = Math.min(minx, x); - } - - if (miny == null) - { - miny = y; - } - else - { - miny = Math.min(miny, y); - } - } - } - } - - // Modifies the cloned geometries in-place. Not needed - // to clone the geometries again as we're in the same - // undoable change. - var dx = -(minx || 0) + 1; - var dy = -(miny || 0) + 1; - - if (initialBounds != null) - { - dx += initialBounds.x; - dy += initialBounds.y; - } - - this.graph.moveCells(this.vertexArray, dx, dy); - } - finally - { - model.endUpdate(); - } -}; - -/** - * Function: calcPositions - * - * Takes the displacements calculated for each cell and applies them to the - * local cache of cell positions. Limits the displacement to the current - * temperature. - */ -mxFastOrganicLayout.prototype.calcPositions = function() -{ - for (var index = 0; index < this.vertexArray.length; index++) - { - if (this.isMoveable[index]) - { - // Get the distance of displacement for this node for this - // iteration - var deltaLength = Math.sqrt(this.dispX[index] * this.dispX[index] + - this.dispY[index] * this.dispY[index]); - - if (deltaLength < 0.001) - { - deltaLength = 0.001; - } - - // Scale down by the current temperature if less than the - // displacement distance - var newXDisp = this.dispX[index] / deltaLength - * Math.min(deltaLength, this.temperature); - - var newYDisp = this.dispY[index] / deltaLength - * Math.min(deltaLength, this.temperature); - - // reset displacements - this.dispX[index] = 0; - this.dispY[index] = 0; - - // Update the cached cell locations - this.cellLocation[index][0] += newXDisp; - this.cellLocation[index][1] += newYDisp; - } - } -}; - -/** - * Function: calcAttraction - * - * Calculates the attractive forces between all laid out nodes linked by - * edges - */ -mxFastOrganicLayout.prototype.calcAttraction = function() -{ - // Check the neighbours of each vertex and calculate the attractive - // force of the edge connecting them - for (var i = 0; i < this.vertexArray.length; i++) - { - for (var k = 0; k < this.neighbours[i].length; k++) - { - // Get the index of the othe cell in the vertex array - var j = this.neighbours[i][k]; - - // Do not proceed self-loops - if (i != j && - this.isMoveable[i] && - this.isMoveable[j]) - { - var xDelta = this.cellLocation[i][0] - this.cellLocation[j][0]; - var yDelta = this.cellLocation[i][1] - this.cellLocation[j][1]; - - // The distance between the nodes - var deltaLengthSquared = xDelta * xDelta + yDelta - * yDelta - this.radiusSquared[i] - this.radiusSquared[j]; - - if (deltaLengthSquared < this.minDistanceLimitSquared) - { - deltaLengthSquared = this.minDistanceLimitSquared; - } - - var deltaLength = Math.sqrt(deltaLengthSquared); - var force = (deltaLengthSquared) / this.forceConstant; - - var displacementX = (xDelta / deltaLength) * force; - var displacementY = (yDelta / deltaLength) * force; - - this.dispX[i] -= displacementX; - this.dispY[i] -= displacementY; - - this.dispX[j] += displacementX; - this.dispY[j] += displacementY; - } - } - } -}; - -/** - * Function: calcRepulsion - * - * Calculates the repulsive forces between all laid out nodes - */ -mxFastOrganicLayout.prototype.calcRepulsion = function() -{ - var vertexCount = this.vertexArray.length; - - for (var i = 0; i < vertexCount; i++) - { - for (var j = i; j < vertexCount; j++) - { - // Exits if the layout is no longer allowed to run - if (!this.allowedToRun) - { - return; - } - - if (j != i && - this.isMoveable[i] && - this.isMoveable[j]) - { - var xDelta = this.cellLocation[i][0] - this.cellLocation[j][0]; - var yDelta = this.cellLocation[i][1] - this.cellLocation[j][1]; - - if (xDelta == 0) - { - xDelta = 0.01 + Math.random(); - } - - if (yDelta == 0) - { - yDelta = 0.01 + Math.random(); - } - - // Distance between nodes - var deltaLength = Math.sqrt((xDelta * xDelta) - + (yDelta * yDelta)); - var deltaLengthWithRadius = deltaLength - this.radius[i] - - this.radius[j]; - - if (deltaLengthWithRadius > this.maxDistanceLimit) - { - // Ignore vertices too far apart - continue; - } - - if (deltaLengthWithRadius < this.minDistanceLimit) - { - deltaLengthWithRadius = this.minDistanceLimit; - } - - var force = this.forceConstantSquared / deltaLengthWithRadius; - - var displacementX = (xDelta / deltaLength) * force; - var displacementY = (yDelta / deltaLength) * force; - - this.dispX[i] += displacementX; - this.dispY[i] += displacementY; - - this.dispX[j] -= displacementX; - this.dispY[j] -= displacementY; - } - } - } -}; - -/** - * Function: reduceTemperature - * - * Reduces the temperature of the layout from an initial setting in a linear - * fashion to zero. - */ -mxFastOrganicLayout.prototype.reduceTemperature = function() -{ - this.temperature = this.initialTemp * (1.0 - this.iteration / this.maxIterations); -}; diff --git a/src/js/layout/mxGraphLayout.js b/src/js/layout/mxGraphLayout.js deleted file mode 100644 index c9f5f32..0000000 --- a/src/js/layout/mxGraphLayout.js +++ /dev/null @@ -1,503 +0,0 @@ -/** - * $Id: mxGraphLayout.js,v 1.48 2012-08-21 17:22:21 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -/** - * Class: mxGraphLayout - * - * Base class for all layout algorithms in mxGraph. Main public functions are - * <move> for handling a moved cell within a layouted parent, and <execute> for - * running the layout on a given parent cell. - * - * Known Subclasses: - * - * <mxCircleLayout>, <mxCompactTreeLayout>, <mxCompositeLayout>, - * <mxFastOrganicLayout>, <mxParallelEdgeLayout>, <mxPartitionLayout>, - * <mxStackLayout> - * - * Constructor: mxGraphLayout - * - * Constructs a new layout using the given layouts. - * - * Arguments: - * - * graph - Enclosing - */ -function mxGraphLayout(graph) -{ - this.graph = graph; -}; - -/** - * Variable: graph - * - * Reference to the enclosing <mxGraph>. - */ -mxGraphLayout.prototype.graph = null; - -/** - * Variable: useBoundingBox - * - * Boolean indicating if the bounding box of the label should be used if - * its available. Default is true. - */ -mxGraphLayout.prototype.useBoundingBox = true; - -/** - * Variable: parent - * - * The parent cell of the layout, if any - */ -mxGraphLayout.prototype.parent = null; - -/** - * Function: moveCell - * - * Notified when a cell is being moved in a parent that has automatic - * layout to update the cell state (eg. index) so that the outcome of the - * layout will position the vertex as close to the point (x, y) as - * possible. - * - * Empty implementation. - * - * Parameters: - * - * cell - <mxCell> which has been moved. - * x - X-coordinate of the new cell location. - * y - Y-coordinate of the new cell location. - */ -mxGraphLayout.prototype.moveCell = function(cell, x, y) { }; - -/** - * Function: execute - * - * Executes the layout algorithm for the children of the given parent. - * - * Parameters: - * - * parent - <mxCell> whose children should be layed out. - */ -mxGraphLayout.prototype.execute = function(parent) { }; - -/** - * Function: getGraph - * - * Returns the graph that this layout operates on. - */ -mxGraphLayout.prototype.getGraph = function() -{ - return this.graph; -}; - -/** - * Function: getConstraint - * - * Returns the constraint for the given key and cell. The optional edge and - * source arguments are used to return inbound and outgoing routing- - * constraints for the given edge and vertex. This implementation always - * returns the value for the given key in the style of the given cell. - * - * Parameters: - * - * key - Key of the constraint to be returned. - * cell - <mxCell> whose constraint should be returned. - * edge - Optional <mxCell> that represents the connection whose constraint - * should be returned. Default is null. - * source - Optional boolean that specifies if the connection is incoming - * or outgoing. Default is null. - */ -mxGraphLayout.prototype.getConstraint = function(key, cell, edge, source) -{ - var state = this.graph.view.getState(cell); - var style = (state != null) ? state.style : this.graph.getCellStyle(cell); - - return (style != null) ? style[key] : null; -}; - -/** - * Function: traverse - * - * Traverses the (directed) graph invoking the given function for each - * visited vertex and edge. The function is invoked with the current vertex - * and the incoming edge as a parameter. This implementation makes sure - * each vertex is only visited once. The function may return false if the - * traversal should stop at the given vertex. - * - * Example: - * - * (code) - * mxLog.show(); - * var cell = graph.getSelectionCell(); - * graph.traverse(cell, false, function(vertex, edge) - * { - * mxLog.debug(graph.getLabel(vertex)); - * }); - * (end) - * - * Parameters: - * - * vertex - <mxCell> that represents the vertex where the traversal starts. - * directed - Optional boolean indicating if edges should only be traversed - * from source to target. Default is true. - * func - Visitor function that takes the current vertex and the incoming - * edge as arguments. The traversal stops if the function returns false. - * edge - Optional <mxCell> that represents the incoming edge. This is - * null for the first step of the traversal. - * visited - Optional array of cell paths for the visited cells. - */ -mxGraphLayout.traverse = function(vertex, directed, func, edge, visited) -{ - if (func != null && vertex != null) - { - directed = (directed != null) ? directed : true; - visited = visited || []; - var id = mxCellPath.create(vertex); - - if (visited[id] == null) - { - visited[id] = vertex; - var result = func(vertex, edge); - - if (result == null || result) - { - var edgeCount = this.graph.model.getEdgeCount(vertex); - - if (edgeCount > 0) - { - for (var i = 0; i < edgeCount; i++) - { - var e = this.graph.model.getEdgeAt(vertex, i); - var isSource = this.graph.model.getTerminal(e, true) == vertex; - - if (!directed || isSource) - { - var next = this.graph.view.getVisibleTerminal(e, !isSource); - this.traverse(next, directed, func, e, visited); - } - } - } - } - } - } -}; - -/** - * Function: isVertexMovable - * - * Returns a boolean indicating if the given <mxCell> is movable or - * bendable by the algorithm. This implementation returns true if the given - * cell is movable in the graph. - * - * Parameters: - * - * cell - <mxCell> whose movable state should be returned. - */ -mxGraphLayout.prototype.isVertexMovable = function(cell) -{ - return this.graph.isCellMovable(cell); -}; - -/** - * Function: isVertexIgnored - * - * Returns a boolean indicating if the given <mxCell> should be ignored by - * the algorithm. This implementation returns false for all vertices. - * - * Parameters: - * - * vertex - <mxCell> whose ignored state should be returned. - */ -mxGraphLayout.prototype.isVertexIgnored = function(vertex) -{ - return !this.graph.getModel().isVertex(vertex) || - !this.graph.isCellVisible(vertex); -}; - -/** - * Function: isEdgeIgnored - * - * Returns a boolean indicating if the given <mxCell> should be ignored by - * the algorithm. This implementation returns false for all vertices. - * - * Parameters: - * - * cell - <mxCell> whose ignored state should be returned. - */ -mxGraphLayout.prototype.isEdgeIgnored = function(edge) -{ - var model = this.graph.getModel(); - - return !model.isEdge(edge) || - !this.graph.isCellVisible(edge) || - model.getTerminal(edge, true) == null || - model.getTerminal(edge, false) == null; -}; - -/** - * Function: setEdgeStyleEnabled - * - * Disables or enables the edge style of the given edge. - */ -mxGraphLayout.prototype.setEdgeStyleEnabled = function(edge, value) -{ - this.graph.setCellStyles(mxConstants.STYLE_NOEDGESTYLE, - (value) ? '0' : '1', [edge]); -}; - -/** - * Function: setOrthogonalEdge - * - * Disables or enables orthogonal end segments of the given edge. - */ -mxGraphLayout.prototype.setOrthogonalEdge = function(edge, value) -{ - this.graph.setCellStyles(mxConstants.STYLE_ORTHOGONAL, - (value) ? '1' : '0', [edge]); -}; - -/** - * Function: getParentOffset - * - * Determines the offset of the given parent to the parent - * of the layout - */ -mxGraphLayout.prototype.getParentOffset = function(parent) -{ - var result = new mxPoint(); - - if (parent != null && parent != this.parent) - { - var model = this.graph.getModel(); - - if (model.isAncestor(this.parent, parent)) - { - var parentGeo = model.getGeometry(parent); - - while (parent != this.parent) - { - result.x = result.x + parentGeo.x; - result.y = result.y + parentGeo.y; - - parent = model.getParent(parent);; - parentGeo = model.getGeometry(parent); - } - } - } - - return result; -}; - -/** - * Function: setEdgePoints - * - * Replaces the array of mxPoints in the geometry of the given edge - * with the given array of mxPoints. - */ -mxGraphLayout.prototype.setEdgePoints = function(edge, points) -{ - if (edge != null) - { - var model = this.graph.model; - var geometry = model.getGeometry(edge); - - if (geometry == null) - { - geometry = new mxGeometry(); - geometry.setRelative(true); - } - else - { - geometry = geometry.clone(); - } - - if (this.parent != null && points != null) - { - var parent = model.getParent(edge); - - var parentOffset = this.getParentOffset(parent); - - for (var i = 0; i < points.length; i++) - { - points[i].x = points[i].x - parentOffset.x; - points[i].y = points[i].y - parentOffset.y; - } - } - - geometry.points = points; - model.setGeometry(edge, geometry); - } -}; - -/** - * Function: setVertexLocation - * - * Sets the new position of the given cell taking into account the size of - * the bounding box if <useBoundingBox> is true. The change is only carried - * out if the new location is not equal to the existing location, otherwise - * the geometry is not replaced with an updated instance. The new or old - * bounds are returned (including overlapping labels). - * - * Parameters: - * - * cell - <mxCell> whose geometry is to be set. - * x - Integer that defines the x-coordinate of the new location. - * y - Integer that defines the y-coordinate of the new location. - */ -mxGraphLayout.prototype.setVertexLocation = function(cell, x, y) -{ - var model = this.graph.getModel(); - var geometry = model.getGeometry(cell); - var result = null; - - if (geometry != null) - { - result = new mxRectangle(x, y, geometry.width, geometry.height); - - // Checks for oversize labels and shifts the result - // TODO: Use mxUtils.getStringSize for label bounds - if (this.useBoundingBox) - { - var state = this.graph.getView().getState(cell); - - if (state != null && state.text != null && state.text.boundingBox != null) - { - var scale = this.graph.getView().scale; - var box = state.text.boundingBox; - - if (state.text.boundingBox.x < state.x) - { - x += (state.x - box.x) / scale; - result.width = box.width; - } - - if (state.text.boundingBox.y < state.y) - { - y += (state.y - box.y) / scale; - result.height = box.height; - } - } - } - - if (this.parent != null) - { - var parent = model.getParent(cell); - - if (parent != null && parent != this.parent) - { - var parentOffset = this.getParentOffset(parent); - - x = x - parentOffset.x; - y = y - parentOffset.y; - } - } - - if (geometry.x != x || geometry.y != y) - { - geometry = geometry.clone(); - geometry.x = x; - geometry.y = y; - - model.setGeometry(cell, geometry); - } - } - - return result; -}; - -/** - * Function: getVertexBounds - * - * Returns an <mxRectangle> that defines the bounds of the given cell or - * the bounding box if <useBoundingBox> is true. - */ -mxGraphLayout.prototype.getVertexBounds = function(cell) -{ - var geo = this.graph.getModel().getGeometry(cell); - - // Checks for oversize label bounding box and corrects - // the return value accordingly - // TODO: Use mxUtils.getStringSize for label bounds - if (this.useBoundingBox) - { - var state = this.graph.getView().getState(cell); - - if (state != null && state.text != null && state.text.boundingBox != null) - { - var scale = this.graph.getView().scale; - var tmp = state.text.boundingBox; - - var dx0 = Math.max(state.x - tmp.x, 0) / scale; - var dy0 = Math.max(state.y - tmp.y, 0) / scale; - var dx1 = Math.max((tmp.x + tmp.width) - (state.x + state.width), 0) / scale; - var dy1 = Math.max((tmp.y + tmp.height) - (state.y + state.height), 0) / scale; - - geo = new mxRectangle(geo.x - dx0, geo.y - dy0, - geo.width + dx0 + dx1, geo.height + dy0 + dy1); - } - } - - if (this.parent != null) - { - var parent = this.graph.getModel().getParent(cell); - geo = geo.clone(); - - if (parent != null && parent != this.parent) - { - var parentOffset = this.getParentOffset(parent); - geo.x = geo.x + parentOffset.x; - geo.y = geo.y + parentOffset.y; - } - } - - return new mxRectangle(geo.x, geo.y, geo.width, geo.height); -}; - -/** - * Function: arrangeGroups - * - * Updates the bounds of the given groups to include all children. Call - * this with the groups in parent to child order, top-most group first, eg. - * - * arrangeGroups(graph, mxUtils.sortCells(Arrays.asList( - * new Object[] { v1, v3 }), true).toArray(), 10); - */ -mxGraphLayout.prototype.arrangeGroups = function(groups, border) -{ - this.graph.getModel().beginUpdate(); - try - { - for (var i = groups.length - 1; i >= 0; i--) - { - var group = groups[i]; - var children = this.graph.getChildVertices(group); - var bounds = this.graph.getBoundingBoxFromGeometry(children); - var geometry = this.graph.getCellGeometry(group); - var left = 0; - var top = 0; - - // Adds the size of the title area for swimlanes - if (this.graph.isSwimlane(group)) - { - var size = this.graph.getStartSize(group); - left = size.width; - top = size.height; - } - - if (bounds != null && geometry != null) - { - geometry = geometry.clone(); - geometry.x = geometry.x + bounds.x - border - left; - geometry.y = geometry.y + bounds.y - border - top; - geometry.width = bounds.width + 2 * border + left; - geometry.height = bounds.height + 2 * border + top; - this.graph.getModel().setGeometry(group, geometry); - this.graph.moveCells(children, border + left - bounds.x, - border + top - bounds.y); - } - } - } - finally - { - this.graph.getModel().endUpdate(); - } -}; diff --git a/src/js/layout/mxParallelEdgeLayout.js b/src/js/layout/mxParallelEdgeLayout.js deleted file mode 100644 index e1ad57c..0000000 --- a/src/js/layout/mxParallelEdgeLayout.js +++ /dev/null @@ -1,198 +0,0 @@ -/** - * $Id: mxParallelEdgeLayout.js,v 1.24 2012-03-27 15:03:34 david Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -/** - * Class: mxParallelEdgeLayout - * - * Extends <mxGraphLayout> for arranging parallel edges. This layout works - * on edges for all pairs of vertices where there is more than one edge - * connecting the latter. - * - * Example: - * - * (code) - * var layout = new mxParallelEdgeLayout(graph); - * layout.execute(graph.getDefaultParent()); - * (end) - * - * Constructor: mxCompactTreeLayout - * - * Constructs a new fast organic layout for the specified graph. - */ -function mxParallelEdgeLayout(graph) -{ - mxGraphLayout.call(this, graph); -}; - -/** - * Extends mxGraphLayout. - */ -mxParallelEdgeLayout.prototype = new mxGraphLayout(); -mxParallelEdgeLayout.prototype.constructor = mxParallelEdgeLayout; - -/** - * Variable: spacing - * - * Defines the spacing between the parallels. Default is 20. - */ -mxParallelEdgeLayout.prototype.spacing = 20; - -/** - * Function: execute - * - * Implements <mxGraphLayout.execute>. - */ -mxParallelEdgeLayout.prototype.execute = function(parent) -{ - var lookup = this.findParallels(parent); - - this.graph.model.beginUpdate(); - try - { - for (var i in lookup) - { - var parallels = lookup[i]; - - if (parallels.length > 1) - { - this.layout(parallels); - } - } - } - finally - { - this.graph.model.endUpdate(); - } -}; - -/** - * Function: findParallels - * - * Finds the parallel edges in the given parent. - */ -mxParallelEdgeLayout.prototype.findParallels = function(parent) -{ - var model = this.graph.getModel(); - var lookup = []; - var childCount = model.getChildCount(parent); - - for (var i = 0; i < childCount; i++) - { - var child = model.getChildAt(parent, i); - - if (!this.isEdgeIgnored(child)) - { - var id = this.getEdgeId(child); - - if (id != null) - { - if (lookup[id] == null) - { - lookup[id] = []; - } - - lookup[id].push(child); - } - } - } - - return lookup; -}; - -/** - * Function: getEdgeId - * - * Returns a unique ID for the given edge. The id is independent of the - * edge direction and is built using the visible terminal of the given - * edge. - */ -mxParallelEdgeLayout.prototype.getEdgeId = function(edge) -{ - var view = this.graph.getView(); - - var state = view.getState(edge); - - var src = (state != null) ? state.getVisibleTerminal(true) : view.getVisibleTerminal(edge, true); - var trg = (state != null) ? state.getVisibleTerminal(false) : view.getVisibleTerminal(edge, false); - - if (src != null && trg != null) - { - src = mxCellPath.create(src); - trg = mxCellPath.create(trg); - - return (src > trg) ? trg+'-'+src : src+'-'+trg; - } - - return null; -}; - -/** - * Function: layout - * - * Lays out the parallel edges in the given array. - */ -mxParallelEdgeLayout.prototype.layout = function(parallels) -{ - var edge = parallels[0]; - var model = this.graph.getModel(); - - var src = model.getGeometry(model.getTerminal(edge, true)); - var trg = model.getGeometry(model.getTerminal(edge, false)); - - // Routes multiple loops - if (src == trg) - { - var x0 = src.x + src.width + this.spacing; - var y0 = src.y + src.height / 2; - - for (var i = 0; i < parallels.length; i++) - { - this.route(parallels[i], x0, y0); - x0 += this.spacing; - } - } - else if (src != null && trg != null) - { - // Routes parallel edges - var scx = src.x + src.width / 2; - var scy = src.y + src.height / 2; - - var tcx = trg.x + trg.width / 2; - var tcy = trg.y + trg.height / 2; - - var dx = tcx - scx; - var dy = tcy - scy; - - var len = Math.sqrt(dx*dx+dy*dy); - - var x0 = scx + dx / 2; - var y0 = scy + dy / 2; - - var nx = dy * this.spacing / len; - var ny = dx * this.spacing / len; - - x0 += nx * (parallels.length - 1) / 2; - y0 -= ny * (parallels.length - 1) / 2; - - for (var i = 0; i < parallels.length; i++) - { - this.route(parallels[i], x0, y0); - x0 -= nx; - y0 += ny; - } - } -}; - -/** - * Function: route - * - * Routes the given edge via the given point. - */ -mxParallelEdgeLayout.prototype.route = function(edge, x, y) -{ - if (this.graph.isCellMovable(edge)) - { - this.setEdgePoints(edge, [new mxPoint(x, y)]); - } -}; diff --git a/src/js/layout/mxPartitionLayout.js b/src/js/layout/mxPartitionLayout.js deleted file mode 100644 index d3592f8..0000000 --- a/src/js/layout/mxPartitionLayout.js +++ /dev/null @@ -1,240 +0,0 @@ -/** - * $Id: mxPartitionLayout.js,v 1.25 2010-01-04 11:18:25 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -/** - * Class: mxPartitionLayout - * - * Extends <mxGraphLayout> for partitioning the parent cell vertically or - * horizontally by filling the complete area with the child cells. A horizontal - * layout partitions the height of the given parent whereas a a non-horizontal - * layout partitions the width. If the parent is a layer (that is, a child of - * the root node), then the current graph size is partitioned. The children do - * not need to be connected for this layout to work. - * - * Example: - * - * (code) - * var layout = new mxPartitionLayout(graph, true, 10, 20); - * layout.execute(graph.getDefaultParent()); - * (end) - * - * Constructor: mxPartitionLayout - * - * Constructs a new stack layout layout for the specified graph, - * spacing, orientation and offset. - */ -function mxPartitionLayout(graph, horizontal, spacing, border) -{ - mxGraphLayout.call(this, graph); - this.horizontal = (horizontal != null) ? horizontal : true; - this.spacing = spacing || 0; - this.border = border || 0; -}; - -/** - * Extends mxGraphLayout. - */ -mxPartitionLayout.prototype = new mxGraphLayout(); -mxPartitionLayout.prototype.constructor = mxPartitionLayout; - -/** - * Variable: horizontal - * - * Boolean indicating the direction in which the space is partitioned. - * Default is true. - */ -mxPartitionLayout.prototype.horizontal = null; - -/** - * Variable: spacing - * - * Integer that specifies the absolute spacing in pixels between the - * children. Default is 0. - */ -mxPartitionLayout.prototype.spacing = null; - -/** - * Variable: border - * - * Integer that specifies the absolute inset in pixels for the parent that - * contains the children. Default is 0. - */ -mxPartitionLayout.prototype.border = null; - -/** - * Variable: resizeVertices - * - * Boolean that specifies if vertices should be resized. Default is true. - */ -mxPartitionLayout.prototype.resizeVertices = true; - -/** - * Function: isHorizontal - * - * Returns <horizontal>. - */ -mxPartitionLayout.prototype.isHorizontal = function() -{ - return this.horizontal; -}; - -/** - * Function: moveCell - * - * Implements <mxGraphLayout.moveCell>. - */ -mxPartitionLayout.prototype.moveCell = function(cell, x, y) -{ - var model = this.graph.getModel(); - var parent = model.getParent(cell); - - if (cell != null && - parent != null) - { - var i = 0; - var last = 0; - var childCount = model.getChildCount(parent); - - // Finds index of the closest swimlane - // TODO: Take into account the orientation - for (i = 0; i < childCount; i++) - { - var child = model.getChildAt(parent, i); - var bounds = this.getVertexBounds(child); - - if (bounds != null) - { - var tmp = bounds.x + bounds.width / 2; - - if (last < x && tmp > x) - { - break; - } - - last = tmp; - } - } - - // Changes child order in parent - var idx = parent.getIndex(cell); - idx = Math.max(0, i - ((i > idx) ? 1 : 0)); - - model.add(parent, cell, idx); - } -}; - -/** - * Function: execute - * - * Implements <mxGraphLayout.execute>. All children where <isVertexIgnored> - * returns false and <isVertexMovable> returns true are modified. - */ -mxPartitionLayout.prototype.execute = function(parent) -{ - var horizontal = this.isHorizontal(); - var model = this.graph.getModel(); - var pgeo = model.getGeometry(parent); - - // Handles special case where the parent is either a layer with no - // geometry or the current root of the view in which case the size - // of the graph's container will be used. - if (this.graph.container != null && - ((pgeo == null && - model.isLayer(parent)) || - parent == this.graph.getView().currentRoot)) - { - var width = this.graph.container.offsetWidth - 1; - var height = this.graph.container.offsetHeight - 1; - pgeo = new mxRectangle(0, 0, width, height); - } - - if (pgeo != null) - { - var children = []; - var childCount = model.getChildCount(parent); - - for (var i = 0; i < childCount; i++) - { - var child = model.getChildAt(parent, i); - - if (!this.isVertexIgnored(child) && - this.isVertexMovable(child)) - { - children.push(child); - } - } - - var n = children.length; - - if (n > 0) - { - var x0 = this.border; - var y0 = this.border; - var other = (horizontal) ? pgeo.height : pgeo.width; - other -= 2 * this.border; - - var size = (this.graph.isSwimlane(parent)) ? - this.graph.getStartSize(parent) : - new mxRectangle(); - - other -= (horizontal) ? size.height : size.width; - x0 = x0 + size.width; - y0 = y0 + size.height; - - var tmp = this.border + (n - 1) * this.spacing; - var value = (horizontal) ? - ((pgeo.width - x0 - tmp) / n) : - ((pgeo.height - y0 - tmp) / n); - - // Avoids negative values, that is values where the sum of the - // spacing plus the border is larger then the available space - if (value > 0) - { - model.beginUpdate(); - try - { - for (var i = 0; i < n; i++) - { - var child = children[i]; - var geo = model.getGeometry(child); - - if (geo != null) - { - geo = geo.clone(); - geo.x = x0; - geo.y = y0; - - if (horizontal) - { - if (this.resizeVertices) - { - geo.width = value; - geo.height = other; - } - - x0 += value + this.spacing; - } - else - { - if (this.resizeVertices) - { - geo.height = value; - geo.width = other; - } - - y0 += value + this.spacing; - } - - model.setGeometry(child, geo); - } - } - } - finally - { - model.endUpdate(); - } - } - } - } -}; diff --git a/src/js/layout/mxStackLayout.js b/src/js/layout/mxStackLayout.js deleted file mode 100644 index 7f5cd47..0000000 --- a/src/js/layout/mxStackLayout.js +++ /dev/null @@ -1,381 +0,0 @@ -/** - * $Id: mxStackLayout.js,v 1.47 2012-12-14 08:54:34 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -/** - * Class: mxStackLayout - * - * Extends <mxGraphLayout> to create a horizontal or vertical stack of the - * child vertices. The children do not need to be connected for this layout - * to work. - * - * Example: - * - * (code) - * var layout = new mxStackLayout(graph, true); - * layout.execute(graph.getDefaultParent()); - * (end) - * - * Constructor: mxStackLayout - * - * Constructs a new stack layout layout for the specified graph, - * spacing, orientation and offset. - */ -function mxStackLayout(graph, horizontal, spacing, x0, y0, border) -{ - mxGraphLayout.call(this, graph); - this.horizontal = (horizontal != null) ? horizontal : true; - this.spacing = (spacing != null) ? spacing : 0; - this.x0 = (x0 != null) ? x0 : 0; - this.y0 = (y0 != null) ? y0 : 0; - this.border = (border != null) ? border : 0; -}; - -/** - * Extends mxGraphLayout. - */ -mxStackLayout.prototype = new mxGraphLayout(); -mxStackLayout.prototype.constructor = mxStackLayout; - -/** - * Variable: horizontal - * - * Specifies the orientation of the layout. Default is true. - */ -mxStackLayout.prototype.horizontal = null; - -/** - * Variable: spacing - * - * Specifies the spacing between the cells. Default is 0. - */ -mxStackLayout.prototype.spacing = null; - -/** - * Variable: x0 - * - * Specifies the horizontal origin of the layout. Default is 0. - */ -mxStackLayout.prototype.x0 = null; - -/** - * Variable: y0 - * - * Specifies the vertical origin of the layout. Default is 0. - */ -mxStackLayout.prototype.y0 = null; - -/** - * Variable: border - * - * Border to be added if fill is true. Default is 0. - */ -mxStackLayout.prototype.border = 0; - -/** - * Variable: keepFirstLocation - * - * Boolean indicating if the location of the first cell should be - * kept, that is, it will not be moved to x0 or y0. - */ -mxStackLayout.prototype.keepFirstLocation = false; - -/** - * Variable: fill - * - * Boolean indicating if dimension should be changed to fill out the parent - * cell. Default is false. - */ -mxStackLayout.prototype.fill = false; - -/** - * Variable: resizeParent - * - * If the parent should be resized to match the width/height of the - * stack. Default is false. - */ -mxStackLayout.prototype.resizeParent = false; - -/** - * Variable: resizeLast - * - * If the last element should be resized to fill out the parent. Default is - * false. If <resizeParent> is true then this is ignored. - */ -mxStackLayout.prototype.resizeLast = false; - -/** - * Variable: wrap - * - * Value at which a new column or row should be created. Default is null. - */ -mxStackLayout.prototype.wrap = null; - -/** - * Function: isHorizontal - * - * Returns <horizontal>. - */ -mxStackLayout.prototype.isHorizontal = function() -{ - return this.horizontal; -}; - -/** - * Function: moveCell - * - * Implements <mxGraphLayout.moveCell>. - */ -mxStackLayout.prototype.moveCell = function(cell, x, y) -{ - var model = this.graph.getModel(); - var parent = model.getParent(cell); - var horizontal = this.isHorizontal(); - - if (cell != null && parent != null) - { - var i = 0; - var last = 0; - var childCount = model.getChildCount(parent); - var value = (horizontal) ? x : y; - var pstate = this.graph.getView().getState(parent); - - if (pstate != null) - { - value -= (horizontal) ? pstate.x : pstate.y; - } - - for (i = 0; i < childCount; i++) - { - var child = model.getChildAt(parent, i); - - if (child != cell) - { - var bounds = model.getGeometry(child); - - if (bounds != null) - { - var tmp = (horizontal) ? - bounds.x + bounds.width / 2 : - bounds.y + bounds.height / 2; - - if (last < value && tmp > value) - { - break; - } - - last = tmp; - } - } - } - - // Changes child order in parent - var idx = parent.getIndex(cell); - idx = Math.max(0, i - ((i > idx) ? 1 : 0)); - - model.add(parent, cell, idx); - } -}; - -/** - * Function: getParentSize - * - * Returns the size for the parent container or the size of the graph - * container if the parent is a layer or the root of the model. - */ -mxStackLayout.prototype.getParentSize = function(parent) -{ - var model = this.graph.getModel(); - var pgeo = model.getGeometry(parent); - - // Handles special case where the parent is either a layer with no - // geometry or the current root of the view in which case the size - // of the graph's container will be used. - if (this.graph.container != null && ((pgeo == null && - model.isLayer(parent)) || parent == this.graph.getView().currentRoot)) - { - var width = this.graph.container.offsetWidth - 1; - var height = this.graph.container.offsetHeight - 1; - pgeo = new mxRectangle(0, 0, width, height); - } - - return pgeo; -}; - -/** - * Function: execute - * - * Implements <mxGraphLayout.execute>. - * - * Only children where <isVertexIgnored> returns false are taken into - * account. - */ -mxStackLayout.prototype.execute = function(parent) -{ - if (parent != null) - { - var horizontal = this.isHorizontal(); - var model = this.graph.getModel(); - var pgeo = this.getParentSize(parent); - - var fillValue = 0; - - if (pgeo != null) - { - fillValue = (horizontal) ? pgeo.height : pgeo.width; - } - - fillValue -= 2 * this.spacing + 2 * this.border; - var x0 = this.x0 + this.border; - var y0 = this.y0 + this.border; - - // Handles swimlane start size - if (this.graph.isSwimlane(parent)) - { - // Uses computed style to get latest - var style = this.graph.getCellStyle(parent); - var start = mxUtils.getValue(style, mxConstants.STYLE_STARTSIZE, mxConstants.DEFAULT_STARTSIZE); - var horz = mxUtils.getValue(style, mxConstants.STYLE_HORIZONTAL, true); - - if (horizontal == horz) - { - fillValue -= start; - } - - if (horizontal) - { - y0 += start; - } - else - { - x0 += start; - } - } - - model.beginUpdate(); - try - { - var tmp = 0; - var last = null; - var childCount = model.getChildCount(parent); - - for (var i = 0; i < childCount; i++) - { - var child = model.getChildAt(parent, i); - - if (!this.isVertexIgnored(child) && this.isVertexMovable(child)) - { - var geo = model.getGeometry(child); - - if (geo != null) - { - geo = geo.clone(); - - if (this.wrap != null && last != null) - { - if ((horizontal && last.x + last.width + - geo.width + 2 * this.spacing > this.wrap) || - (!horizontal && last.y + last.height + - geo.height + 2 * this.spacing > this.wrap)) - { - last = null; - - if (horizontal) - { - y0 += tmp + this.spacing; - } - else - { - x0 += tmp + this.spacing; - } - - tmp = 0; - } - } - - tmp = Math.max(tmp, (horizontal) ? geo.height : geo.width); - - if (last != null) - { - if (horizontal) - { - geo.x = last.x + last.width + this.spacing; - } - else - { - geo.y = last.y + last.height + this.spacing; - } - } - else if (!this.keepFirstLocation) - { - if (horizontal) - { - geo.x = x0; - } - else - { - geo.y = y0; - } - } - - if (horizontal) - { - geo.y = y0; - } - else - { - geo.x = x0; - } - - if (this.fill && fillValue > 0) - { - if (horizontal) - { - geo.height = fillValue; - } - else - { - geo.width = fillValue; - } - } - - model.setGeometry(child, geo); - last = geo; - } - } - } - - if (this.resizeParent && pgeo != null && last != null && - !this.graph.isCellCollapsed(parent)) - { - pgeo = pgeo.clone(); - - if (horizontal) - { - pgeo.width = last.x + last.width + this.spacing; - } - else - { - pgeo.height = last.y + last.height + this.spacing; - } - - model.setGeometry(parent, pgeo); - } - else if (this.resizeLast && pgeo != null && last != null) - { - if (horizontal) - { - last.width = pgeo.width - last.x - this.spacing; - } - else - { - last.height = pgeo.height - last.y - this.spacing; - } - } - } - finally - { - model.endUpdate(); - } - } -}; diff --git a/src/js/model/mxCell.js b/src/js/model/mxCell.js deleted file mode 100644 index cb5eb9f..0000000 --- a/src/js/model/mxCell.js +++ /dev/null @@ -1,806 +0,0 @@ -/** - * $Id: mxCell.js,v 1.36 2011-06-17 13:45:08 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -/** - * Class: mxCell - * - * Cells are the elements of the graph model. They represent the state - * of the groups, vertices and edges in a graph. - * - * Custom attributes: - * - * For custom attributes we recommend using an XML node as the value of a cell. - * The following code can be used to create a cell with an XML node as the - * value: - * - * (code) - * var doc = mxUtils.createXmlDocument(); - * var node = doc.createElement('MyNode') - * node.setAttribute('label', 'MyLabel'); - * node.setAttribute('attribute1', 'value1'); - * graph.insertVertex(graph.getDefaultParent(), null, node, 40, 40, 80, 30); - * (end) - * - * For the label to work, <mxGraph.convertValueToString> and - * <mxGraph.cellLabelChanged> should be overridden as follows: - * - * (code) - * graph.convertValueToString = function(cell) - * { - * if (mxUtils.isNode(cell.value)) - * { - * return cell.getAttribute('label', '') - * } - * }; - * - * var cellLabelChanged = graph.cellLabelChanged; - * graph.cellLabelChanged = function(cell, newValue, autoSize) - * { - * if (mxUtils.isNode(cell.value)) - * { - * // Clones the value for correct undo/redo - * var elt = cell.value.cloneNode(true); - * elt.setAttribute('label', newValue); - * newValue = elt; - * } - * - * cellLabelChanged.apply(this, arguments); - * }; - * (end) - * - * Callback: onInit - * - * Called from within the constructor. - * - * Constructor: mxCell - * - * Constructs a new cell to be used in a graph model. - * This method invokes <onInit> upon completion. - * - * Parameters: - * - * value - Optional object that represents the cell value. - * geometry - Optional <mxGeometry> that specifies the geometry. - * style - Optional formatted string that defines the style. - */ -function mxCell(value, geometry, style) -{ - this.value = value; - this.setGeometry(geometry); - this.setStyle(style); - - if (this.onInit != null) - { - this.onInit(); - } -}; - -/** - * Variable: id - * - * Holds the Id. Default is null. - */ -mxCell.prototype.id = null; - -/** - * Variable: value - * - * Holds the user object. Default is null. - */ -mxCell.prototype.value = null; - -/** - * Variable: geometry - * - * Holds the <mxGeometry>. Default is null. - */ -mxCell.prototype.geometry = null; - -/** - * Variable: style - * - * Holds the style as a string of the form [(stylename|key=value);]. Default is - * null. - */ -mxCell.prototype.style = null; - -/** - * Variable: vertex - * - * Specifies whether the cell is a vertex. Default is false. - */ -mxCell.prototype.vertex = false; - -/** - * Variable: edge - * - * Specifies whether the cell is an edge. Default is false. - */ -mxCell.prototype.edge = false; - -/** - * Variable: connectable - * - * Specifies whether the cell is connectable. Default is true. - */ -mxCell.prototype.connectable = true; - -/** - * Variable: visible - * - * Specifies whether the cell is visible. Default is true. - */ -mxCell.prototype.visible = true; - -/** - * Variable: collapsed - * - * Specifies whether the cell is collapsed. Default is false. - */ -mxCell.prototype.collapsed = false; - -/** - * Variable: parent - * - * Reference to the parent cell. - */ -mxCell.prototype.parent = null; - -/** - * Variable: source - * - * Reference to the source terminal. - */ -mxCell.prototype.source = null; - -/** - * Variable: target - * - * Reference to the target terminal. - */ -mxCell.prototype.target = null; - -/** - * Variable: children - * - * Holds the child cells. - */ -mxCell.prototype.children = null; - -/** - * Variable: edges - * - * Holds the edges. - */ -mxCell.prototype.edges = null; - -/** - * Variable: mxTransient - * - * List of members that should not be cloned inside <clone>. This field is - * passed to <mxUtils.clone> and is not made persistent in <mxCellCodec>. - * This is not a convention for all classes, it is only used in this class - * to mark transient fields since transient modifiers are not supported by - * the language. - */ -mxCell.prototype.mxTransient = ['id', 'value', 'parent', 'source', - 'target', 'children', 'edges']; - -/** - * Function: getId - * - * Returns the Id of the cell as a string. - */ -mxCell.prototype.getId = function() -{ - return this.id; -}; - -/** - * Function: setId - * - * Sets the Id of the cell to the given string. - */ -mxCell.prototype.setId = function(id) -{ - this.id = id; -}; - -/** - * Function: getValue - * - * Returns the user object of the cell. The user - * object is stored in <value>. - */ -mxCell.prototype.getValue = function() -{ - return this.value; -}; - -/** - * Function: setValue - * - * Sets the user object of the cell. The user object - * is stored in <value>. - */ -mxCell.prototype.setValue = function(value) -{ - this.value = value; -}; - -/** - * Function: valueChanged - * - * Changes the user object after an in-place edit - * and returns the previous value. This implementation - * replaces the user object with the given value and - * returns the old user object. - */ -mxCell.prototype.valueChanged = function(newValue) -{ - var previous = this.getValue(); - this.setValue(newValue); - - return previous; -}; - -/** - * Function: getGeometry - * - * Returns the <mxGeometry> that describes the <geometry>. - */ -mxCell.prototype.getGeometry = function() -{ - return this.geometry; -}; - -/** - * Function: setGeometry - * - * Sets the <mxGeometry> to be used as the <geometry>. - */ -mxCell.prototype.setGeometry = function(geometry) -{ - this.geometry = geometry; -}; - -/** - * Function: getStyle - * - * Returns a string that describes the <style>. - */ -mxCell.prototype.getStyle = function() -{ - return this.style; -}; - -/** - * Function: setStyle - * - * Sets the string to be used as the <style>. - */ -mxCell.prototype.setStyle = function(style) -{ - this.style = style; -}; - -/** - * Function: isVertex - * - * Returns true if the cell is a vertex. - */ -mxCell.prototype.isVertex = function() -{ - return this.vertex; -}; - -/** - * Function: setVertex - * - * Specifies if the cell is a vertex. This should only be assigned at - * construction of the cell and not be changed during its lifecycle. - * - * Parameters: - * - * vertex - Boolean that specifies if the cell is a vertex. - */ -mxCell.prototype.setVertex = function(vertex) -{ - this.vertex = vertex; -}; - -/** - * Function: isEdge - * - * Returns true if the cell is an edge. - */ -mxCell.prototype.isEdge = function() -{ - return this.edge; -}; - -/** - * Function: setEdge - * - * Specifies if the cell is an edge. This should only be assigned at - * construction of the cell and not be changed during its lifecycle. - * - * Parameters: - * - * edge - Boolean that specifies if the cell is an edge. - */ -mxCell.prototype.setEdge = function(edge) -{ - this.edge = edge; -}; - -/** - * Function: isConnectable - * - * Returns true if the cell is connectable. - */ -mxCell.prototype.isConnectable = function() -{ - return this.connectable; -}; - -/** - * Function: setConnectable - * - * Sets the connectable state. - * - * Parameters: - * - * connectable - Boolean that specifies the new connectable state. - */ -mxCell.prototype.setConnectable = function(connectable) -{ - this.connectable = connectable; -}; - -/** - * Function: isVisible - * - * Returns true if the cell is visibile. - */ -mxCell.prototype.isVisible = function() -{ - return this.visible; -}; - -/** - * Function: setVisible - * - * Specifies if the cell is visible. - * - * Parameters: - * - * visible - Boolean that specifies the new visible state. - */ -mxCell.prototype.setVisible = function(visible) -{ - this.visible = visible; -}; - -/** - * Function: isCollapsed - * - * Returns true if the cell is collapsed. - */ -mxCell.prototype.isCollapsed = function() -{ - return this.collapsed; -}; - -/** - * Function: setCollapsed - * - * Sets the collapsed state. - * - * Parameters: - * - * collapsed - Boolean that specifies the new collapsed state. - */ -mxCell.prototype.setCollapsed = function(collapsed) -{ - this.collapsed = collapsed; -}; - -/** - * Function: getParent - * - * Returns the cell's parent. - */ -mxCell.prototype.getParent = function() -{ - return this.parent; -}; - -/** - * Function: setParent - * - * Sets the parent cell. - * - * Parameters: - * - * parent - <mxCell> that represents the new parent. - */ -mxCell.prototype.setParent = function(parent) -{ - this.parent = parent; -}; - -/** - * Function: getTerminal - * - * Returns the source or target terminal. - * - * Parameters: - * - * source - Boolean that specifies if the source terminal should be - * returned. - */ -mxCell.prototype.getTerminal = function(source) -{ - return (source) ? this.source : this.target; -}; - -/** - * Function: setTerminal - * - * Sets the source or target terminal and returns the new terminal. - * - * Parameters: - * - * terminal - <mxCell> that represents the new source or target terminal. - * isSource - Boolean that specifies if the source or target terminal - * should be set. - */ -mxCell.prototype.setTerminal = function(terminal, isSource) -{ - if (isSource) - { - this.source = terminal; - } - else - { - this.target = terminal; - } - - return terminal; -}; - -/** - * Function: getChildCount - * - * Returns the number of child cells. - */ -mxCell.prototype.getChildCount = function() -{ - return (this.children == null) ? 0 : this.children.length; -}; - -/** - * Function: getIndex - * - * Returns the index of the specified child in the child array. - * - * Parameters: - * - * child - Child whose index should be returned. - */ -mxCell.prototype.getIndex = function(child) -{ - return mxUtils.indexOf(this.children, child); -}; - -/** - * Function: getChildAt - * - * Returns the child at the specified index. - * - * Parameters: - * - * index - Integer that specifies the child to be returned. - */ -mxCell.prototype.getChildAt = function(index) -{ - return (this.children == null) ? null : this.children[index]; -}; - -/** - * Function: insert - * - * Inserts the specified child into the child array at the specified index - * and updates the parent reference of the child. If not childIndex is - * specified then the child is appended to the child array. Returns the - * inserted child. - * - * Parameters: - * - * child - <mxCell> to be inserted or appended to the child array. - * index - Optional integer that specifies the index at which the child - * should be inserted into the child array. - */ -mxCell.prototype.insert = function(child, index) -{ - if (child != null) - { - if (index == null) - { - index = this.getChildCount(); - - if (child.getParent() == this) - { - index--; - } - } - - child.removeFromParent(); - child.setParent(this); - - if (this.children == null) - { - this.children = []; - this.children.push(child); - } - else - { - this.children.splice(index, 0, child); - } - } - - return child; -}; - -/** - * Function: remove - * - * Removes the child at the specified index from the child array and - * returns the child that was removed. Will remove the parent reference of - * the child. - * - * Parameters: - * - * index - Integer that specifies the index of the child to be - * removed. - */ -mxCell.prototype.remove = function(index) -{ - var child = null; - - if (this.children != null && index >= 0) - { - child = this.getChildAt(index); - - if (child != null) - { - this.children.splice(index, 1); - child.setParent(null); - } - } - - return child; -}; - -/** - * Function: removeFromParent - * - * Removes the cell from its parent. - */ -mxCell.prototype.removeFromParent = function() -{ - if (this.parent != null) - { - var index = this.parent.getIndex(this); - this.parent.remove(index); - } -}; - -/** - * Function: getEdgeCount - * - * Returns the number of edges in the edge array. - */ -mxCell.prototype.getEdgeCount = function() -{ - return (this.edges == null) ? 0 : this.edges.length; -}; - -/** - * Function: getEdgeIndex - * - * Returns the index of the specified edge in <edges>. - * - * Parameters: - * - * edge - <mxCell> whose index in <edges> should be returned. - */ -mxCell.prototype.getEdgeIndex = function(edge) -{ - return mxUtils.indexOf(this.edges, edge); -}; - -/** - * Function: getEdgeAt - * - * Returns the edge at the specified index in <edges>. - * - * Parameters: - * - * index - Integer that specifies the index of the edge to be returned. - */ -mxCell.prototype.getEdgeAt = function(index) -{ - return (this.edges == null) ? null : this.edges[index]; -}; - -/** - * Function: insertEdge - * - * Inserts the specified edge into the edge array and returns the edge. - * Will update the respective terminal reference of the edge. - * - * Parameters: - * - * edge - <mxCell> to be inserted into the edge array. - * isOutgoing - Boolean that specifies if the edge is outgoing. - */ -mxCell.prototype.insertEdge = function(edge, isOutgoing) -{ - if (edge != null) - { - edge.removeFromTerminal(isOutgoing); - edge.setTerminal(this, isOutgoing); - - if (this.edges == null || - edge.getTerminal(!isOutgoing) != this || - mxUtils.indexOf(this.edges, edge) < 0) - { - if (this.edges == null) - { - this.edges = []; - } - - this.edges.push(edge); - } - } - - return edge; -}; - -/** - * Function: removeEdge - * - * Removes the specified edge from the edge array and returns the edge. - * Will remove the respective terminal reference from the edge. - * - * Parameters: - * - * edge - <mxCell> to be removed from the edge array. - * isOutgoing - Boolean that specifies if the edge is outgoing. - */ -mxCell.prototype.removeEdge = function(edge, isOutgoing) -{ - if (edge != null) - { - if (edge.getTerminal(!isOutgoing) != this && - this.edges != null) - { - var index = this.getEdgeIndex(edge); - - if (index >= 0) - { - this.edges.splice(index, 1); - } - } - - edge.setTerminal(null, isOutgoing); - } - - return edge; -}; - -/** - * Function: removeFromTerminal - * - * Removes the edge from its source or target terminal. - * - * Parameters: - * - * isSource - Boolean that specifies if the edge should be removed from its - * source or target terminal. - */ -mxCell.prototype.removeFromTerminal = function(isSource) -{ - var terminal = this.getTerminal(isSource); - - if (terminal != null) - { - terminal.removeEdge(this, isSource); - } -}; - -/** - * Function: getAttribute - * - * Returns the specified attribute from the user object if it is an XML - * node. - * - * Parameters: - * - * name - Name of the attribute whose value should be returned. - * defaultValue - Optional default value to use if the attribute has no - * value. - */ -mxCell.prototype.getAttribute = function(name, defaultValue) -{ - var userObject = this.getValue(); - - var val = (userObject != null && - userObject.nodeType == mxConstants.NODETYPE_ELEMENT) ? - userObject.getAttribute(name) : null; - - return val || defaultValue; -}; - -/** - * Function: setAttribute - * - * Sets the specified attribute on the user object if it is an XML node. - * - * Parameters: - * - * name - Name of the attribute whose value should be set. - * value - New value of the attribute. - */ -mxCell.prototype.setAttribute = function(name, value) -{ - var userObject = this.getValue(); - - if (userObject != null && - userObject.nodeType == mxConstants.NODETYPE_ELEMENT) - { - userObject.setAttribute(name, value); - } -}; - -/** - * Function: clone - * - * Returns a clone of the cell. Uses <cloneValue> to clone - * the user object. All fields in <mxTransient> are ignored - * during the cloning. - */ -mxCell.prototype.clone = function() -{ - var clone = mxUtils.clone(this, this.mxTransient); - clone.setValue(this.cloneValue()); - - return clone; -}; - -/** - * Function: cloneValue - * - * Returns a clone of the cell's user object. - */ -mxCell.prototype.cloneValue = function() -{ - var value = this.getValue(); - - if (value != null) - { - if (typeof(value.clone) == 'function') - { - value = value.clone(); - } - else if (!isNaN(value.nodeType)) - { - value = value.cloneNode(true); - } - } - - return value; -}; diff --git a/src/js/model/mxCellPath.js b/src/js/model/mxCellPath.js deleted file mode 100644 index 71a379e..0000000 --- a/src/js/model/mxCellPath.js +++ /dev/null @@ -1,163 +0,0 @@ -/** - * $Id: mxCellPath.js,v 1.12 2010-01-02 09:45:15 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -var mxCellPath = -{ - - /** - * Class: mxCellPath - * - * Implements a mechanism for temporary cell Ids. - * - * Variable: PATH_SEPARATOR - * - * Defines the separator between the path components. Default is ".". - */ - PATH_SEPARATOR: '.', - - /** - * Function: create - * - * Creates the cell path for the given cell. The cell path is a - * concatenation of the indices of all ancestors on the (finite) path to - * the root, eg. "0.0.0.1". - * - * Parameters: - * - * cell - Cell whose path should be returned. - */ - create: function(cell) - { - var result = ''; - - if (cell != null) - { - var parent = cell.getParent(); - - while (parent != null) - { - var index = parent.getIndex(cell); - result = index + mxCellPath.PATH_SEPARATOR + result; - - cell = parent; - parent = cell.getParent(); - } - } - - // Removes trailing separator - var n = result.length; - - if (n > 1) - { - result = result.substring(0, n - 1); - } - - return result; - }, - - /** - * Function: getParentPath - * - * Returns the path for the parent of the cell represented by the given - * path. Returns null if the given path has no parent. - * - * Parameters: - * - * path - Path whose parent path should be returned. - */ - getParentPath: function(path) - { - if (path != null) - { - var index = path.lastIndexOf(mxCellPath.PATH_SEPARATOR); - - if (index >= 0) - { - return path.substring(0, index); - } - else if (path.length > 0) - { - return ''; - } - } - - return null; - }, - - /** - * Function: resolve - * - * Returns the cell for the specified cell path using the given root as the - * root of the path. - * - * Parameters: - * - * root - Root cell of the path to be resolved. - * path - String that defines the path. - */ - resolve: function(root, path) - { - var parent = root; - - if (path != null) - { - var tokens = path.split(mxCellPath.PATH_SEPARATOR); - - for (var i=0; i<tokens.length; i++) - { - parent = parent.getChildAt(parseInt(tokens[i])); - } - } - - return parent; - }, - - /** - * Function: compare - * - * Compares the given cell paths and returns -1 if p1 is smaller, 0 if - * p1 is equal and 1 if p1 is greater than p2. - */ - compare: function(p1, p2) - { - var min = Math.min(p1.length, p2.length); - var comp = 0; - - for (var i = 0; i < min; i++) - { - if (p1[i] != p2[i]) - { - if (p1[i].length == 0 || - p2[i].length == 0) - { - comp = (p1[i] == p2[i]) ? 0 : ((p1[i] > p2[i]) ? 1 : -1); - } - else - { - var t1 = parseInt(p1[i]); - var t2 = parseInt(p2[i]); - - comp = (t1 == t2) ? 0 : ((t1 > t2) ? 1 : -1); - } - - break; - } - } - - // Compares path length if both paths are equal to this point - if (comp == 0) - { - var t1 = p1.length; - var t2 = p2.length; - - if (t1 != t2) - { - comp = (t1 > t2) ? 1 : -1; - } - } - - return comp; - } - -}; diff --git a/src/js/model/mxGeometry.js b/src/js/model/mxGeometry.js deleted file mode 100644 index 51a7d3b..0000000 --- a/src/js/model/mxGeometry.js +++ /dev/null @@ -1,277 +0,0 @@ -/** - * $Id: mxGeometry.js,v 1.26 2010-01-02 09:45:15 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -/** - * Class: mxGeometry - * - * Extends <mxRectangle> to represent the geometry of a cell. - * - * For vertices, the geometry consists of the x- and y-location, and the width - * and height. For edges, the geometry consists of the optional terminal- and - * control points. The terminal points are only required if an edge is - * unconnected, and are stored in the sourcePoint> and <targetPoint> - * variables, respectively. - * - * Example: - * - * If an edge is unconnected, that is, it has no source or target terminal, - * then a geometry with terminal points for a new edge can be defined as - * follows. - * - * (code) - * geometry.setTerminalPoint(new mxPoint(x1, y1), true); - * geometry.points = [new mxPoint(x2, y2)]; - * geometry.setTerminalPoint(new mxPoint(x3, y3), false); - * (end) - * - * Control points are used regardless of the connected state of an edge and may - * be ignored or interpreted differently depending on the edge's <mxEdgeStyle>. - * - * To disable automatic reset of control points after a cell has been moved or - * resized, the the <mxGraph.resizeEdgesOnMove> and - * <mxGraph.resetEdgesOnResize> may be used. - * - * Edge Labels: - * - * Using the x- and y-coordinates of a cell's geometry, it is possible to - * position the label on edges on a specific location on the actual edge shape - * as it appears on the screen. The x-coordinate of an edge's geometry is used - * to describe the distance from the center of the edge from -1 to 1 with 0 - * being the center of the edge and the default value. The y-coordinate of an - * edge's geometry is used to describe the absolute, orthogonal distance in - * pixels from that point. In addition, the <mxGeometry.offset> is used as an - * absolute offset vector from the resulting point. - * - * This coordinate system is applied if <relative> is true, otherwise the - * offset defines the absolute vector from the edge's center point to the - * label. - * - * Ports: - * - * The term "port" refers to a relatively positioned, connectable child cell, - * which is used to specify the connection between the parent and another cell - * in the graph. Ports are typically modeled as vertices with relative - * geometries. - * - * Offsets: - * - * The <offset> field is interpreted in 3 different ways, depending on the cell - * and the geometry. For edges, the offset defines the absolute offset for the - * edge label. For relative geometries, the offset defines the absolute offset - * for the origin (top, left corner) of the vertex, otherwise the offset - * defines the absolute offset for the label inside the vertex or group. - * - * Constructor: mxGeometry - * - * Constructs a new object to describe the size and location of a vertex or - * the control points of an edge. - */ -function mxGeometry(x, y, width, height) -{ - mxRectangle.call(this, x, y, width, height); -}; - -/** - * Extends mxRectangle. - */ -mxGeometry.prototype = new mxRectangle(); -mxGeometry.prototype.constructor = mxGeometry; - -/** - * Variable: TRANSLATE_CONTROL_POINTS - * - * Global switch to translate the points in translate. Default is true. - */ -mxGeometry.prototype.TRANSLATE_CONTROL_POINTS = true; - -/** - * Variable: alternateBounds - * - * Stores alternate values for x, y, width and height in a rectangle. See - * <swap> to exchange the values. Default is null. - */ -mxGeometry.prototype.alternateBounds = null; - -/** - * Variable: sourcePoint - * - * Defines the source <mxPoint> of the edge. This is used if the - * corresponding edge does not have a source vertex. Otherwise it is - * ignored. Default is null. - */ -mxGeometry.prototype.sourcePoint = null; - -/** - * Variable: targetPoint - * - * Defines the target <mxPoint> of the edge. This is used if the - * corresponding edge does not have a target vertex. Otherwise it is - * ignored. Default is null. - */ -mxGeometry.prototype.targetPoint = null; - -/** - * Variable: points - * - * Array of <mxPoints> which specifies the control points along the edge. - * These points are the intermediate points on the edge, for the endpoints - * use <targetPoint> and <sourcePoint> or set the terminals of the edge to - * a non-null value. Default is null. - */ -mxGeometry.prototype.points = null; - -/** - * Variable: offset - * - * For edges, this holds the offset (in pixels) from the position defined - * by <x> and <y> on the edge. For relative geometries (for vertices), this - * defines the absolute offset from the point defined by the relative - * coordinates. For absolute geometries (for vertices), this defines the - * offset for the label. Default is null. - */ -mxGeometry.prototype.offset = null; - -/** - * Variable: relative - * - * Specifies if the coordinates in the geometry are to be interpreted as - * relative coordinates. For edges, this is used to define the location of - * the edge label relative to the edge as rendered on the display. For - * vertices, this specifies the relative location inside the bounds of the - * parent cell. - * - * If this is false, then the coordinates are relative to the origin of the - * parent cell or, for edges, the edge label position is relative to the - * center of the edge as rendered on screen. - * - * Default is false. - */ -mxGeometry.prototype.relative = false; - -/** - * Function: swap - * - * Swaps the x, y, width and height with the values stored in - * <alternateBounds> and puts the previous values into <alternateBounds> as - * a rectangle. This operation is carried-out in-place, that is, using the - * existing geometry instance. If this operation is called during a graph - * model transactional change, then the geometry should be cloned before - * calling this method and setting the geometry of the cell using - * <mxGraphModel.setGeometry>. - */ -mxGeometry.prototype.swap = function() -{ - if (this.alternateBounds != null) - { - var old = new mxRectangle( - this.x, this.y, this.width, this.height); - - this.x = this.alternateBounds.x; - this.y = this.alternateBounds.y; - this.width = this.alternateBounds.width; - this.height = this.alternateBounds.height; - - this.alternateBounds = old; - } -}; - -/** - * Function: getTerminalPoint - * - * Returns the <mxPoint> representing the source or target point of this - * edge. This is only used if the edge has no source or target vertex. - * - * Parameters: - * - * isSource - Boolean that specifies if the source or target point - * should be returned. - */ -mxGeometry.prototype.getTerminalPoint = function(isSource) -{ - return (isSource) ? this.sourcePoint : this.targetPoint; -}; - -/** - * Function: setTerminalPoint - * - * Sets the <sourcePoint> or <targetPoint> to the given <mxPoint> and - * returns the new point. - * - * Parameters: - * - * point - Point to be used as the new source or target point. - * isSource - Boolean that specifies if the source or target point - * should be set. - */ -mxGeometry.prototype.setTerminalPoint = function(point, isSource) -{ - if (isSource) - { - this.sourcePoint = point; - } - else - { - this.targetPoint = point; - } - - return point; -}; - -/** - * Function: translate - * - * Translates the geometry by the specified amount. That is, <x> and <y> - * of the geometry, the <sourcePoint>, <targetPoint> and all elements of - * <points> are translated by the given amount. <x> and <y> are only - * translated if <relative> is false. If <TRANSLATE_CONTROL_POINTS> is - * false, then <points> are not modified by this function. - * - * Parameters: - * - * dx - Integer that specifies the x-coordinate of the translation. - * dy - Integer that specifies the y-coordinate of the translation. - */ -mxGeometry.prototype.translate = function(dx, dy) -{ - var clone = this.clone(); - - // Translates the geometry - if (!this.relative) - { - this.x += dx; - this.y += dy; - } - - // Translates the source point - if (this.sourcePoint != null) - { - this.sourcePoint.x += dx; - this.sourcePoint.y += dy; - } - - // Translates the target point - if (this.targetPoint != null) - { - this.targetPoint.x += dx; - this.targetPoint.y += dy; - } - - // Translate the control points - if (this.TRANSLATE_CONTROL_POINTS && - this.points != null) - { - var count = this.points.length; - - for (var i = 0; i < count; i++) - { - var pt = this.points[i]; - - if (pt != null) - { - pt.x += dx; - pt.y += dy; - } - } - } -}; diff --git a/src/js/model/mxGraphModel.js b/src/js/model/mxGraphModel.js deleted file mode 100644 index c65c0e1..0000000 --- a/src/js/model/mxGraphModel.js +++ /dev/null @@ -1,2622 +0,0 @@ -/** - * $Id: mxGraphModel.js,v 1.125 2012-04-16 10:48:43 david Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -/** - * Class: mxGraphModel - * - * Extends <mxEventSource> to implement a graph model. The graph model acts as - * a wrapper around the cells which are in charge of storing the actual graph - * datastructure. The model acts as a transactional wrapper with event - * notification for all changes, whereas the cells contain the atomic - * operations for updating the actual datastructure. - * - * Layers: - * - * The cell hierarchy in the model must have a top-level root cell which - * contains the layers (typically one default layer), which in turn contain the - * top-level cells of the layers. This means each cell is contained in a layer. - * If no layers are required, then all new cells should be added to the default - * layer. - * - * Layers are useful for hiding and showing groups of cells, or for placing - * groups of cells on top of other cells in the display. To identify a layer, - * the <isLayer> function is used. It returns true if the parent of the given - * cell is the root of the model. - * - * Encoding the model: - * - * To encode a graph model, use the following code: - * - * (code) - * var enc = new mxCodec(); - * var node = enc.encode(graph.getModel()); - * (end) - * - * This will create an XML node that contains all the model information. - * - * Encoding and decoding changes: - * - * For the encoding of changes, a graph model listener is required that encodes - * each change from the given array of changes. - * - * (code) - * model.addListener(mxEvent.CHANGE, function(sender, evt) - * { - * var changes = evt.getProperty('edit').changes; - * var nodes = []; - * var codec = new mxCodec(); - * - * for (var i = 0; i < changes.length; i++) - * { - * nodes.push(codec.encode(changes[i])); - * } - * // do something with the nodes - * }); - * (end) - * - * For the decoding and execution of changes, the codec needs a lookup function - * that allows it to resolve cell IDs as follows: - * - * (code) - * var codec = new mxCodec(); - * codec.lookup = function(id) - * { - * return model.getCell(id); - * } - * (end) - * - * For each encoded change (represented by a node), the following code can be - * used to carry out the decoding and create a change object. - * - * (code) - * var changes = []; - * var change = codec.decode(node); - * change.model = model; - * change.execute(); - * changes.push(change); - * (end) - * - * The changes can then be dispatched using the model as follows. - * - * (code) - * var edit = new mxUndoableEdit(model, false); - * edit.changes = changes; - * - * edit.notify = function() - * { - * edit.source.fireEvent(new mxEventObject(mxEvent.CHANGE, - * 'edit', edit, 'changes', edit.changes)); - * edit.source.fireEvent(new mxEventObject(mxEvent.NOTIFY, - * 'edit', edit, 'changes', edit.changes)); - * } - * - * model.fireEvent(new mxEventObject(mxEvent.UNDO, 'edit', edit)); - * model.fireEvent(new mxEventObject(mxEvent.CHANGE, - * 'edit', edit, 'changes', changes)); - * (end) - * - * Event: mxEvent.CHANGE - * - * Fires when an undoable edit is dispatched. The <code>edit</code> property - * contains the <mxUndoableEdit>. The <code>changes</code> property contains - * the array of atomic changes inside the undoable edit. The changes property - * is <strong>deprecated</strong>, please use edit.changes instead. - * - * Example: - * - * For finding newly inserted cells, the following code can be used: - * - * (code) - * graph.model.addListener(mxEvent.CHANGE, function(sender, evt) - * { - * var changes = evt.getProperty('edit').changes; - * - * for (var i = 0; i < changes.length; i++) - * { - * var change = changes[i]; - * - * if (change instanceof mxChildChange && - * change.change.previous == null) - * { - * graph.startEditingAtCell(change.child); - * break; - * } - * } - * }); - * (end) - * - * - * Event: mxEvent.NOTIFY - * - * Same as <mxEvent.CHANGE>, this event can be used for classes that need to - * implement a sync mechanism between this model and, say, a remote model. In - * such a setup, only local changes should trigger a notify event and all - * changes should trigger a change event. - * - * Event: mxEvent.EXECUTE - * - * Fires between begin- and endUpdate and after an atomic change was executed - * in the model. The <code>change</code> property contains the atomic change - * that was executed. - * - * Event: mxEvent.BEGIN_UPDATE - * - * Fires after the <updateLevel> was incremented in <beginUpdate>. This event - * contains no properties. - * - * Event: mxEvent.END_UPDATE - * - * Fires after the <updateLevel> was decreased in <endUpdate> but before any - * notification or change dispatching. The <code>edit</code> property contains - * the <currentEdit>. - * - * Event: mxEvent.BEFORE_UNDO - * - * Fires before the change is dispatched after the update level has reached 0 - * in <endUpdate>. The <code>edit</code> property contains the <curreneEdit>. - * - * Event: mxEvent.UNDO - * - * Fires after the change was dispatched in <endUpdate>. The <code>edit</code> - * property contains the <currentEdit>. - * - * Constructor: mxGraphModel - * - * Constructs a new graph model. If no root is specified then a new root - * <mxCell> with a default layer is created. - * - * Parameters: - * - * root - <mxCell> that represents the root cell. - */ -function mxGraphModel(root) -{ - this.currentEdit = this.createUndoableEdit(); - - if (root != null) - { - this.setRoot(root); - } - else - { - this.clear(); - } -}; - -/** - * Extends mxEventSource. - */ -mxGraphModel.prototype = new mxEventSource(); -mxGraphModel.prototype.constructor = mxGraphModel; - -/** - * Variable: root - * - * Holds the root cell, which in turn contains the cells that represent the - * layers of the diagram as child cells. That is, the actual elements of the - * diagram are supposed to live in the third generation of cells and below. - */ -mxGraphModel.prototype.root = null; - -/** - * Variable: cells - * - * Maps from Ids to cells. - */ -mxGraphModel.prototype.cells = null; - -/** - * Variable: maintainEdgeParent - * - * Specifies if edges should automatically be moved into the nearest common - * ancestor of their terminals. Default is true. - */ -mxGraphModel.prototype.maintainEdgeParent = true; - -/** - * Variable: createIds - * - * Specifies if the model should automatically create Ids for new cells. - * Default is true. - */ -mxGraphModel.prototype.createIds = true; - -/** - * Variable: prefix - * - * Defines the prefix of new Ids. Default is an empty string. - */ -mxGraphModel.prototype.prefix = ''; - -/** - * Variable: postfix - * - * Defines the postfix of new Ids. Default is an empty string. - */ -mxGraphModel.prototype.postfix = ''; - -/** - * Variable: nextId - * - * Specifies the next Id to be created. Initial value is 0. - */ -mxGraphModel.prototype.nextId = 0; - -/** - * Variable: currentEdit - * - * Holds the changes for the current transaction. If the transaction is - * closed then a new object is created for this variable using - * <createUndoableEdit>. - */ -mxGraphModel.prototype.currentEdit = null; - -/** - * Variable: updateLevel - * - * Counter for the depth of nested transactions. Each call to <beginUpdate> - * will increment this number and each call to <endUpdate> will decrement - * it. When the counter reaches 0, the transaction is closed and the - * respective events are fired. Initial value is 0. - */ -mxGraphModel.prototype.updateLevel = 0; - -/** - * Variable: endingUpdate - * - * True if the program flow is currently inside endUpdate. - */ -mxGraphModel.prototype.endingUpdate = false; - -/** - * Function: clear - * - * Sets a new root using <createRoot>. - */ -mxGraphModel.prototype.clear = function() -{ - this.setRoot(this.createRoot()); -}; - -/** - * Function: isCreateIds - * - * Returns <createIds>. - */ -mxGraphModel.prototype.isCreateIds = function() -{ - return this.createIds; -}; - -/** - * Function: setCreateIds - * - * Sets <createIds>. - */ -mxGraphModel.prototype.setCreateIds = function(value) -{ - this.createIds = value; -}; - -/** - * Function: createRoot - * - * Creates a new root cell with a default layer (child 0). - */ -mxGraphModel.prototype.createRoot = function() -{ - var cell = new mxCell(); - cell.insert(new mxCell()); - - return cell; -}; - -/** - * Function: getCell - * - * Returns the <mxCell> for the specified Id or null if no cell can be - * found for the given Id. - * - * Parameters: - * - * id - A string representing the Id of the cell. - */ -mxGraphModel.prototype.getCell = function(id) -{ - return (this.cells != null) ? this.cells[id] : null; -}; - -/** - * Function: filterCells - * - * Returns the cells from the given array where the fiven filter function - * returns true. - */ -mxGraphModel.prototype.filterCells = function(cells, filter) -{ - var result = null; - - if (cells != null) - { - result = []; - - for (var i = 0; i < cells.length; i++) - { - if (filter(cells[i])) - { - result.push(cells[i]); - } - } - } - - return result; -}; - -/** - * Function: getDescendants - * - * Returns all descendants of the given cell and the cell itself in an array. - * - * Parameters: - * - * parent - <mxCell> whose descendants should be returned. - */ -mxGraphModel.prototype.getDescendants = function(parent) -{ - return this.filterDescendants(null, parent); -}; - -/** - * Function: filterDescendants - * - * Visits all cells recursively and applies the specified filter function - * to each cell. If the function returns true then the cell is added - * to the resulting array. The parent and result paramters are optional. - * If parent is not specified then the recursion starts at <root>. - * - * Example: - * The following example extracts all vertices from a given model: - * (code) - * var filter = function(cell) - * { - * return model.isVertex(cell); - * } - * var vertices = model.filterDescendants(filter); - * (code) - * - * Parameters: - * - * filter - JavaScript function that takes an <mxCell> as an argument - * and returns a boolean. - * parent - Optional <mxCell> that is used as the root of the recursion. - */ -mxGraphModel.prototype.filterDescendants = function(filter, parent) -{ - // Creates a new array for storing the result - var result = []; - - // Recursion starts at the root of the model - parent = parent || this.getRoot(); - - // Checks if the filter returns true for the cell - // and adds it to the result array - if (filter == null || filter(parent)) - { - result.push(parent); - } - - // Visits the children of the cell - var childCount = this.getChildCount(parent); - - for (var i = 0; i < childCount; i++) - { - var child = this.getChildAt(parent, i); - result = result.concat(this.filterDescendants(filter, child)); - } - - return result; -}; - -/** - * Function: getRoot - * - * Returns the root of the model or the topmost parent of the given cell. - * - * Parameters: - * - * cell - Optional <mxCell> that specifies the child. - */ -mxGraphModel.prototype.getRoot = function(cell) -{ - var root = cell || this.root; - - if (cell != null) - { - while (cell != null) - { - root = cell; - cell = this.getParent(cell); - } - } - - return root; -}; - -/** - * Function: setRoot - * - * Sets the <root> of the model using <mxRootChange> and adds the change to - * the current transaction. This resets all datastructures in the model and - * is the preferred way of clearing an existing model. Returns the new - * root. - * - * Example: - * - * (code) - * var root = new mxCell(); - * root.insert(new mxCell()); - * model.setRoot(root); - * (end) - * - * Parameters: - * - * root - <mxCell> that specifies the new root. - */ -mxGraphModel.prototype.setRoot = function(root) -{ - this.execute(new mxRootChange(this, root)); - - return root; -}; - -/** - * Function: rootChanged - * - * Inner callback to change the root of the model and update the internal - * datastructures, such as <cells> and <nextId>. Returns the previous root. - * - * Parameters: - * - * root - <mxCell> that specifies the new root. - */ -mxGraphModel.prototype.rootChanged = function(root) -{ - var oldRoot = this.root; - this.root = root; - - // Resets counters and datastructures - this.nextId = 0; - this.cells = null; - this.cellAdded(root); - - return oldRoot; -}; - -/** - * Function: isRoot - * - * Returns true if the given cell is the root of the model and a non-null - * value. - * - * Parameters: - * - * cell - <mxCell> that represents the possible root. - */ -mxGraphModel.prototype.isRoot = function(cell) -{ - return cell != null && this.root == cell; -}; - -/** - * Function: isLayer - * - * Returns true if <isRoot> returns true for the parent of the given cell. - * - * Parameters: - * - * cell - <mxCell> that represents the possible layer. - */ -mxGraphModel.prototype.isLayer = function(cell) -{ - return this.isRoot(this.getParent(cell)); -}; - -/** - * Function: isAncestor - * - * Returns true if the given parent is an ancestor of the given child. - * - * Parameters: - * - * parent - <mxCell> that specifies the parent. - * child - <mxCell> that specifies the child. - */ -mxGraphModel.prototype.isAncestor = function(parent, child) -{ - while (child != null && child != parent) - { - child = this.getParent(child); - } - - return child == parent; -}; - -/** - * Function: contains - * - * Returns true if the model contains the given <mxCell>. - * - * Parameters: - * - * cell - <mxCell> that specifies the cell. - */ -mxGraphModel.prototype.contains = function(cell) -{ - return this.isAncestor(this.root, cell); -}; - -/** - * Function: getParent - * - * Returns the parent of the given cell. - * - * Parameters: - * - * cell - <mxCell> whose parent should be returned. - */ -mxGraphModel.prototype.getParent = function(cell) -{ - return (cell != null) ? cell.getParent() : null; -}; - -/** - * Function: add - * - * Adds the specified child to the parent at the given index using - * <mxChildChange> and adds the change to the current transaction. If no - * index is specified then the child is appended to the parent's array of - * children. Returns the inserted child. - * - * Parameters: - * - * parent - <mxCell> that specifies the parent to contain the child. - * child - <mxCell> that specifies the child to be inserted. - * index - Optional integer that specifies the index of the child. - */ -mxGraphModel.prototype.add = function(parent, child, index) -{ - if (child != parent && parent != null && child != null) - { - // Appends the child if no index was specified - if (index == null) - { - index = this.getChildCount(parent); - } - - var parentChanged = parent != this.getParent(child); - this.execute(new mxChildChange(this, parent, child, index)); - - // Maintains the edges parents by moving the edges - // into the nearest common ancestor of its - // terminals - if (this.maintainEdgeParent && parentChanged) - { - this.updateEdgeParents(child); - } - } - - return child; -}; - -/** - * Function: cellAdded - * - * Inner callback to update <cells> when a cell has been added. This - * implementation resolves collisions by creating new Ids. To change the - * ID of a cell after it was inserted into the model, use the following - * code: - * - * (code - * delete model.cells[cell.getId()]; - * cell.setId(newId); - * model.cells[cell.getId()] = cell; - * (end) - * - * If the change of the ID should be part of the command history, then the - * cell should be removed from the model and a clone with the new ID should - * be reinserted into the model instead. - * - * Parameters: - * - * cell - <mxCell> that specifies the cell that has been added. - */ -mxGraphModel.prototype.cellAdded = function(cell) -{ - if (cell != null) - { - // Creates an Id for the cell if not Id exists - if (cell.getId() == null && this.createIds) - { - cell.setId(this.createId(cell)); - } - - if (cell.getId() != null) - { - var collision = this.getCell(cell.getId()); - - if (collision != cell) - { - // Creates new Id for the cell - // as long as there is a collision - while (collision != null) - { - cell.setId(this.createId(cell)); - collision = this.getCell(cell.getId()); - } - - // Lazily creates the cells dictionary - if (this.cells == null) - { - this.cells = new Object(); - } - - this.cells[cell.getId()] = cell; - } - } - - // Makes sure IDs of deleted cells are not reused - if (mxUtils.isNumeric(cell.getId())) - { - this.nextId = Math.max(this.nextId, cell.getId()); - } - - // Recursively processes child cells - var childCount = this.getChildCount(cell); - - for (var i=0; i<childCount; i++) - { - this.cellAdded(this.getChildAt(cell, i)); - } - } -}; - -/** - * Function: createId - * - * Hook method to create an Id for the specified cell. This implementation - * concatenates <prefix>, id and <postfix> to create the Id and increments - * <nextId>. The cell is ignored by this implementation, but can be used in - * overridden methods to prefix the Ids with eg. the cell type. - * - * Parameters: - * - * cell - <mxCell> to create the Id for. - */ -mxGraphModel.prototype.createId = function(cell) -{ - var id = this.nextId; - this.nextId++; - - return this.prefix + id + this.postfix; -}; - -/** - * Function: updateEdgeParents - * - * Updates the parent for all edges that are connected to cell or one of - * its descendants using <updateEdgeParent>. - */ -mxGraphModel.prototype.updateEdgeParents = function(cell, root) -{ - // Gets the topmost node of the hierarchy - root = root || this.getRoot(cell); - - // Updates edges on children first - var childCount = this.getChildCount(cell); - - for (var i = 0; i < childCount; i++) - { - var child = this.getChildAt(cell, i); - this.updateEdgeParents(child, root); - } - - // Updates the parents of all connected edges - var edgeCount = this.getEdgeCount(cell); - var edges = []; - - for (var i = 0; i < edgeCount; i++) - { - edges.push(this.getEdgeAt(cell, i)); - } - - for (var i = 0; i < edges.length; i++) - { - var edge = edges[i]; - - // Updates edge parent if edge and child have - // a common root node (does not need to be the - // model root node) - if (this.isAncestor(root, edge)) - { - this.updateEdgeParent(edge, root); - } - } -}; - -/** - * Function: updateEdgeParent - * - * Inner callback to update the parent of the specified <mxCell> to the - * nearest-common-ancestor of its two terminals. - * - * Parameters: - * - * edge - <mxCell> that specifies the edge. - * root - <mxCell> that represents the current root of the model. - */ -mxGraphModel.prototype.updateEdgeParent = function(edge, root) -{ - var source = this.getTerminal(edge, true); - var target = this.getTerminal(edge, false); - var cell = null; - - // Uses the first non-relative descendants of the source terminal - while (source != null && !this.isEdge(source) && - source.geometry != null && source.geometry.relative) - { - source = this.getParent(source); - } - - // Uses the first non-relative descendants of the target terminal - while (target != null && !this.isEdge(target) && - target.geometry != null && target.geometry.relative) - { - target = this.getParent(target); - } - - if (this.isAncestor(root, source) && this.isAncestor(root, target)) - { - if (source == target) - { - cell = this.getParent(source); - } - else - { - cell = this.getNearestCommonAncestor(source, target); - } - - if (cell != null && (this.getParent(cell) != this.root || - this.isAncestor(cell, edge)) && this.getParent(edge) != cell) - { - var geo = this.getGeometry(edge); - - if (geo != null) - { - var origin1 = this.getOrigin(this.getParent(edge)); - var origin2 = this.getOrigin(cell); - - var dx = origin2.x - origin1.x; - var dy = origin2.y - origin1.y; - - geo = geo.clone(); - geo.translate(-dx, -dy); - this.setGeometry(edge, geo); - } - - this.add(cell, edge, this.getChildCount(cell)); - } - } -}; - -/** - * Function: getOrigin - * - * Returns the absolute, accumulated origin for the children inside the - * given parent as an <mxPoint>. - */ -mxGraphModel.prototype.getOrigin = function(cell) -{ - var result = null; - - if (cell != null) - { - result = this.getOrigin(this.getParent(cell)); - - if (!this.isEdge(cell)) - { - var geo = this.getGeometry(cell); - - if (geo != null) - { - result.x += geo.x; - result.y += geo.y; - } - } - } - else - { - result = new mxPoint(); - } - - return result; -}; - -/** - * Function: getNearestCommonAncestor - * - * Returns the nearest common ancestor for the specified cells. - * - * Parameters: - * - * cell1 - <mxCell> that specifies the first cell in the tree. - * cell2 - <mxCell> that specifies the second cell in the tree. - */ -mxGraphModel.prototype.getNearestCommonAncestor = function(cell1, cell2) -{ - if (cell1 != null && cell2 != null) - { - // Creates the cell path for the second cell - var path = mxCellPath.create(cell2); - - if (path != null && path.length > 0) - { - // Bubbles through the ancestors of the first - // cell to find the nearest common ancestor. - var cell = cell1; - var current = mxCellPath.create(cell); - - // Inverts arguments - if (path.length < current.length) - { - cell = cell2; - var tmp = current; - current = path; - path = tmp; - } - - while (cell != null) - { - var parent = this.getParent(cell); - - // Checks if the cell path is equal to the beginning of the given cell path - if (path.indexOf(current + mxCellPath.PATH_SEPARATOR) == 0 && parent != null) - { - return cell; - } - - current = mxCellPath.getParentPath(current); - cell = parent; - } - } - } - - return null; -}; - -/** - * Function: remove - * - * Removes the specified cell from the model using <mxChildChange> and adds - * the change to the current transaction. This operation will remove the - * cell and all of its children from the model. Returns the removed cell. - * - * Parameters: - * - * cell - <mxCell> that should be removed. - */ -mxGraphModel.prototype.remove = function(cell) -{ - if (cell == this.root) - { - this.setRoot(null); - } - else if (this.getParent(cell) != null) - { - this.execute(new mxChildChange(this, null, cell)); - } - - return cell; -}; - -/** - * Function: cellRemoved - * - * Inner callback to update <cells> when a cell has been removed. - * - * Parameters: - * - * cell - <mxCell> that specifies the cell that has been removed. - */ -mxGraphModel.prototype.cellRemoved = function(cell) -{ - if (cell != null && this.cells != null) - { - // Recursively processes child cells - var childCount = this.getChildCount(cell); - - for (var i = childCount - 1; i >= 0; i--) - { - this.cellRemoved(this.getChildAt(cell, i)); - } - - // Removes the dictionary entry for the cell - if (this.cells != null && cell.getId() != null) - { - delete this.cells[cell.getId()]; - } - } -}; - -/** - * Function: parentForCellChanged - * - * Inner callback to update the parent of a cell using <mxCell.insert> - * on the parent and return the previous parent. - * - * Parameters: - * - * cell - <mxCell> to update the parent for. - * parent - <mxCell> that specifies the new parent of the cell. - * index - Optional integer that defines the index of the child - * in the parent's child array. - */ -mxGraphModel.prototype.parentForCellChanged = function(cell, parent, index) -{ - var previous = this.getParent(cell); - - if (parent != null) - { - if (parent != previous || previous.getIndex(cell) != index) - { - parent.insert(cell, index); - } - } - else if (previous != null) - { - var oldIndex = previous.getIndex(cell); - previous.remove(oldIndex); - } - - // Checks if the previous parent was already in the - // model and avoids calling cellAdded if it was. - if (!this.contains(previous) && parent != null) - { - this.cellAdded(cell); - } - else if (parent == null) - { - this.cellRemoved(cell); - } - - return previous; -}; - -/** - * Function: getChildCount - * - * Returns the number of children in the given cell. - * - * Parameters: - * - * cell - <mxCell> whose number of children should be returned. - */ -mxGraphModel.prototype.getChildCount = function(cell) -{ - return (cell != null) ? cell.getChildCount() : 0; -}; - -/** - * Function: getChildAt - * - * Returns the child of the given <mxCell> at the given index. - * - * Parameters: - * - * cell - <mxCell> that represents the parent. - * index - Integer that specifies the index of the child to be returned. - */ -mxGraphModel.prototype.getChildAt = function(cell, index) -{ - return (cell != null) ? cell.getChildAt(index) : null; -}; - -/** - * Function: getChildren - * - * Returns all children of the given <mxCell> as an array of <mxCells>. The - * return value should be only be read. - * - * Parameters: - * - * cell - <mxCell> the represents the parent. - */ -mxGraphModel.prototype.getChildren = function(cell) -{ - return (cell != null) ? cell.children : null; -}; - -/** - * Function: getChildVertices - * - * Returns the child vertices of the given parent. - * - * Parameters: - * - * cell - <mxCell> whose child vertices should be returned. - */ -mxGraphModel.prototype.getChildVertices = function(parent) -{ - return this.getChildCells(parent, true, false); -}; - -/** - * Function: getChildEdges - * - * Returns the child edges of the given parent. - * - * Parameters: - * - * cell - <mxCell> whose child edges should be returned. - */ -mxGraphModel.prototype.getChildEdges = function(parent) -{ - return this.getChildCells(parent, false, true); -}; - -/** - * Function: getChildCells - * - * Returns the children of the given cell that are vertices and/or edges - * depending on the arguments. - * - * Parameters: - * - * cell - <mxCell> the represents the parent. - * vertices - Boolean indicating if child vertices should be returned. - * Default is false. - * edges - Boolean indicating if child edges should be returned. - * Default is false. - */ -mxGraphModel.prototype.getChildCells = function(parent, vertices, edges) -{ - vertices = (vertices != null) ? vertices : false; - edges = (edges != null) ? edges : false; - - var childCount = this.getChildCount(parent); - var result = []; - - for (var i = 0; i < childCount; i++) - { - var child = this.getChildAt(parent, i); - - if ((!edges && !vertices) || (edges && this.isEdge(child)) || - (vertices && this.isVertex(child))) - { - result.push(child); - } - } - - return result; -}; - -/** - * Function: getTerminal - * - * Returns the source or target <mxCell> of the given edge depending on the - * value of the boolean parameter. - * - * Parameters: - * - * edge - <mxCell> that specifies the edge. - * isSource - Boolean indicating which end of the edge should be returned. - */ -mxGraphModel.prototype.getTerminal = function(edge, isSource) -{ - return (edge != null) ? edge.getTerminal(isSource) : null; -}; - -/** - * Function: setTerminal - * - * Sets the source or target terminal of the given <mxCell> using - * <mxTerminalChange> and adds the change to the current transaction. - * This implementation updates the parent of the edge using <updateEdgeParent> - * if required. - * - * Parameters: - * - * edge - <mxCell> that specifies the edge. - * terminal - <mxCell> that specifies the new terminal. - * isSource - Boolean indicating if the terminal is the new source or - * target terminal of the edge. - */ -mxGraphModel.prototype.setTerminal = function(edge, terminal, isSource) -{ - var terminalChanged = terminal != this.getTerminal(edge, isSource); - this.execute(new mxTerminalChange(this, edge, terminal, isSource)); - - if (this.maintainEdgeParent && terminalChanged) - { - this.updateEdgeParent(edge, this.getRoot()); - } - - return terminal; -}; - -/** - * Function: setTerminals - * - * Sets the source and target <mxCell> of the given <mxCell> in a single - * transaction using <setTerminal> for each end of the edge. - * - * Parameters: - * - * edge - <mxCell> that specifies the edge. - * source - <mxCell> that specifies the new source terminal. - * target - <mxCell> that specifies the new target terminal. - */ -mxGraphModel.prototype.setTerminals = function(edge, source, target) -{ - this.beginUpdate(); - try - { - this.setTerminal(edge, source, true); - this.setTerminal(edge, target, false); - } - finally - { - this.endUpdate(); - } -}; - -/** - * Function: terminalForCellChanged - * - * Inner helper function to update the terminal of the edge using - * <mxCell.insertEdge> and return the previous terminal. - * - * Parameters: - * - * edge - <mxCell> that specifies the edge to be updated. - * terminal - <mxCell> that specifies the new terminal. - * isSource - Boolean indicating if the terminal is the new source or - * target terminal of the edge. - */ -mxGraphModel.prototype.terminalForCellChanged = function(edge, terminal, isSource) -{ - var previous = this.getTerminal(edge, isSource); - - if (terminal != null) - { - terminal.insertEdge(edge, isSource); - } - else if (previous != null) - { - previous.removeEdge(edge, isSource); - } - - return previous; -}; - -/** - * Function: getEdgeCount - * - * Returns the number of distinct edges connected to the given cell. - * - * Parameters: - * - * cell - <mxCell> that represents the vertex. - */ -mxGraphModel.prototype.getEdgeCount = function(cell) -{ - return (cell != null) ? cell.getEdgeCount() : 0; -}; - -/** - * Function: getEdgeAt - * - * Returns the edge of cell at the given index. - * - * Parameters: - * - * cell - <mxCell> that specifies the vertex. - * index - Integer that specifies the index of the edge - * to return. - */ -mxGraphModel.prototype.getEdgeAt = function(cell, index) -{ - return (cell != null) ? cell.getEdgeAt(index) : null; -}; - -/** - * Function: getDirectedEdgeCount - * - * Returns the number of incoming or outgoing edges, ignoring the given - * edge. - * - * Parameters: - * - * cell - <mxCell> whose edge count should be returned. - * outgoing - Boolean that specifies if the number of outgoing or - * incoming edges should be returned. - * ignoredEdge - <mxCell> that represents an edge to be ignored. - */ -mxGraphModel.prototype.getDirectedEdgeCount = function(cell, outgoing, ignoredEdge) -{ - var count = 0; - var edgeCount = this.getEdgeCount(cell); - - for (var i = 0; i < edgeCount; i++) - { - var edge = this.getEdgeAt(cell, i); - - if (edge != ignoredEdge && this.getTerminal(edge, outgoing) == cell) - { - count++; - } - } - - return count; -}; - -/** - * Function: getConnections - * - * Returns all edges of the given cell without loops. - * - * Parameters: - * - * cell - <mxCell> whose edges should be returned. - * - */ -mxGraphModel.prototype.getConnections = function(cell) -{ - return this.getEdges(cell, true, true, false); -}; - -/** - * Function: getIncomingEdges - * - * Returns the incoming edges of the given cell without loops. - * - * Parameters: - * - * cell - <mxCell> whose incoming edges should be returned. - * - */ -mxGraphModel.prototype.getIncomingEdges = function(cell) -{ - return this.getEdges(cell, true, false, false); -}; - -/** - * Function: getOutgoingEdges - * - * Returns the outgoing edges of the given cell without loops. - * - * Parameters: - * - * cell - <mxCell> whose outgoing edges should be returned. - * - */ -mxGraphModel.prototype.getOutgoingEdges = function(cell) -{ - return this.getEdges(cell, false, true, false); -}; - -/** - * Function: getEdges - * - * Returns all distinct edges connected to this cell as a new array of - * <mxCells>. If at least one of incoming or outgoing is true, then loops - * are ignored, otherwise if both are false, then all edges connected to - * the given cell are returned including loops. - * - * Parameters: - * - * cell - <mxCell> that specifies the cell. - * incoming - Optional boolean that specifies if incoming edges should be - * returned. Default is true. - * outgoing - Optional boolean that specifies if outgoing edges should be - * returned. Default is true. - * includeLoops - Optional boolean that specifies if loops should be returned. - * Default is true. - */ -mxGraphModel.prototype.getEdges = function(cell, incoming, outgoing, includeLoops) -{ - incoming = (incoming != null) ? incoming : true; - outgoing = (outgoing != null) ? outgoing : true; - includeLoops = (includeLoops != null) ? includeLoops : true; - - var edgeCount = this.getEdgeCount(cell); - var result = []; - - for (var i = 0; i < edgeCount; i++) - { - var edge = this.getEdgeAt(cell, i); - var source = this.getTerminal(edge, true); - var target = this.getTerminal(edge, false); - - if ((includeLoops && source == target) || ((source != target) && ((incoming && target == cell) || - (outgoing && source == cell)))) - { - result.push(edge); - } - } - - return result; -}; - -/** - * Function: getEdgesBetween - * - * Returns all edges between the given source and target pair. If directed - * is true, then only edges from the source to the target are returned, - * otherwise, all edges between the two cells are returned. - * - * Parameters: - * - * source - <mxCell> that defines the source terminal of the edge to be - * returned. - * target - <mxCell> that defines the target terminal of the edge to be - * returned. - * directed - Optional boolean that specifies if the direction of the - * edge should be taken into account. Default is false. - */ -mxGraphModel.prototype.getEdgesBetween = function(source, target, directed) -{ - directed = (directed != null) ? directed : false; - - var tmp1 = this.getEdgeCount(source); - var tmp2 = this.getEdgeCount(target); - - // Assumes the source has less connected edges - var terminal = source; - var edgeCount = tmp1; - - // Uses the smaller array of connected edges - // for searching the edge - if (tmp2 < tmp1) - { - edgeCount = tmp2; - terminal = target; - } - - var result = []; - - // Checks if the edge is connected to the correct - // cell and returns the first match - for (var i = 0; i < edgeCount; i++) - { - var edge = this.getEdgeAt(terminal, i); - var src = this.getTerminal(edge, true); - var trg = this.getTerminal(edge, false); - var directedMatch = (src == source) && (trg == target); - var oppositeMatch = (trg == source) && (src == target); - - if (directedMatch || (!directed && oppositeMatch)) - { - result.push(edge); - } - } - - return result; -}; - -/** - * Function: getOpposites - * - * Returns all opposite vertices wrt terminal for the given edges, only - * returning sources and/or targets as specified. The result is returned - * as an array of <mxCells>. - * - * Parameters: - * - * edges - Array of <mxCells> that contain the edges to be examined. - * terminal - <mxCell> that specifies the known end of the edges. - * sources - Boolean that specifies if source terminals should be contained - * in the result. Default is true. - * targets - Boolean that specifies if target terminals should be contained - * in the result. Default is true. - */ -mxGraphModel.prototype.getOpposites = function(edges, terminal, sources, targets) -{ - sources = (sources != null) ? sources : true; - targets = (targets != null) ? targets : true; - - var terminals = []; - - if (edges != null) - { - for (var i = 0; i < edges.length; i++) - { - var source = this.getTerminal(edges[i], true); - var target = this.getTerminal(edges[i], false); - - // Checks if the terminal is the source of - // the edge and if the target should be - // stored in the result - if (source == terminal && target != null && target != terminal && targets) - { - terminals.push(target); - } - - // Checks if the terminal is the taget of - // the edge and if the source should be - // stored in the result - else if (target == terminal && source != null && source != terminal && sources) - { - terminals.push(source); - } - } - } - - return terminals; -}; - -/** - * Function: getTopmostCells - * - * Returns the topmost cells of the hierarchy in an array that contains no - * descendants for each <mxCell> that it contains. Duplicates should be - * removed in the cells array to improve performance. - * - * Parameters: - * - * cells - Array of <mxCells> whose topmost ancestors should be returned. - */ -mxGraphModel.prototype.getTopmostCells = function(cells) -{ - var tmp = []; - - for (var i = 0; i < cells.length; i++) - { - var cell = cells[i]; - var topmost = true; - var parent = this.getParent(cell); - - while (parent != null) - { - if (mxUtils.indexOf(cells, parent) >= 0) - { - topmost = false; - break; - } - - parent = this.getParent(parent); - } - - if (topmost) - { - tmp.push(cell); - } - } - - return tmp; -}; - -/** - * Function: isVertex - * - * Returns true if the given cell is a vertex. - * - * Parameters: - * - * cell - <mxCell> that represents the possible vertex. - */ -mxGraphModel.prototype.isVertex = function(cell) -{ - return (cell != null) ? cell.isVertex() : false; -}; - -/** - * Function: isEdge - * - * Returns true if the given cell is an edge. - * - * Parameters: - * - * cell - <mxCell> that represents the possible edge. - */ -mxGraphModel.prototype.isEdge = function(cell) -{ - return (cell != null) ? cell.isEdge() : false; -}; - -/** - * Function: isConnectable - * - * Returns true if the given <mxCell> is connectable. If <edgesConnectable> - * is false, then this function returns false for all edges else it returns - * the return value of <mxCell.isConnectable>. - * - * Parameters: - * - * cell - <mxCell> whose connectable state should be returned. - */ -mxGraphModel.prototype.isConnectable = function(cell) -{ - return (cell != null) ? cell.isConnectable() : false; -}; - -/** - * Function: getValue - * - * Returns the user object of the given <mxCell> using <mxCell.getValue>. - * - * Parameters: - * - * cell - <mxCell> whose user object should be returned. - */ -mxGraphModel.prototype.getValue = function(cell) -{ - return (cell != null) ? cell.getValue() : null; -}; - -/** - * Function: setValue - * - * Sets the user object of then given <mxCell> using <mxValueChange> - * and adds the change to the current transaction. - * - * Parameters: - * - * cell - <mxCell> whose user object should be changed. - * value - Object that defines the new user object. - */ -mxGraphModel.prototype.setValue = function(cell, value) -{ - this.execute(new mxValueChange(this, cell, value)); - - return value; -}; - -/** - * Function: valueForCellChanged - * - * Inner callback to update the user object of the given <mxCell> - * using <mxCell.valueChanged> and return the previous value, - * that is, the return value of <mxCell.valueChanged>. - * - * To change a specific attribute in an XML node, the following code can be - * used. - * - * (code) - * graph.getModel().valueForCellChanged = function(cell, value) - * { - * var previous = cell.value.getAttribute('label'); - * cell.value.setAttribute('label', value); - * - * return previous; - * }; - * (end) - */ -mxGraphModel.prototype.valueForCellChanged = function(cell, value) -{ - return cell.valueChanged(value); -}; - -/** - * Function: getGeometry - * - * Returns the <mxGeometry> of the given <mxCell>. - * - * Parameters: - * - * cell - <mxCell> whose geometry should be returned. - */ -mxGraphModel.prototype.getGeometry = function(cell, geometry) -{ - return (cell != null) ? cell.getGeometry() : null; -}; - -/** - * Function: setGeometry - * - * Sets the <mxGeometry> of the given <mxCell>. The actual update - * of the cell is carried out in <geometryForCellChanged>. The - * <mxGeometryChange> action is used to encapsulate the change. - * - * Parameters: - * - * cell - <mxCell> whose geometry should be changed. - * geometry - <mxGeometry> that defines the new geometry. - */ -mxGraphModel.prototype.setGeometry = function(cell, geometry) -{ - if (geometry != this.getGeometry(cell)) - { - this.execute(new mxGeometryChange(this, cell, geometry)); - } - - return geometry; -}; - -/** - * Function: geometryForCellChanged - * - * Inner callback to update the <mxGeometry> of the given <mxCell> using - * <mxCell.setGeometry> and return the previous <mxGeometry>. - */ -mxGraphModel.prototype.geometryForCellChanged = function(cell, geometry) -{ - var previous = this.getGeometry(cell); - cell.setGeometry(geometry); - - return previous; -}; - -/** - * Function: getStyle - * - * Returns the style of the given <mxCell>. - * - * Parameters: - * - * cell - <mxCell> whose style should be returned. - */ -mxGraphModel.prototype.getStyle = function(cell) -{ - return (cell != null) ? cell.getStyle() : null; -}; - -/** - * Function: setStyle - * - * Sets the style of the given <mxCell> using <mxStyleChange> and - * adds the change to the current transaction. - * - * Parameters: - * - * cell - <mxCell> whose style should be changed. - * style - String of the form [stylename;|key=value;] to specify - * the new cell style. - */ -mxGraphModel.prototype.setStyle = function(cell, style) -{ - if (style != this.getStyle(cell)) - { - this.execute(new mxStyleChange(this, cell, style)); - } - - return style; -}; - -/** - * Function: styleForCellChanged - * - * Inner callback to update the style of the given <mxCell> - * using <mxCell.setStyle> and return the previous style. - * - * Parameters: - * - * cell - <mxCell> that specifies the cell to be updated. - * style - String of the form [stylename;|key=value;] to specify - * the new cell style. - */ -mxGraphModel.prototype.styleForCellChanged = function(cell, style) -{ - var previous = this.getStyle(cell); - cell.setStyle(style); - - return previous; -}; - -/** - * Function: isCollapsed - * - * Returns true if the given <mxCell> is collapsed. - * - * Parameters: - * - * cell - <mxCell> whose collapsed state should be returned. - */ -mxGraphModel.prototype.isCollapsed = function(cell) -{ - return (cell != null) ? cell.isCollapsed() : false; -}; - -/** - * Function: setCollapsed - * - * Sets the collapsed state of the given <mxCell> using <mxCollapseChange> - * and adds the change to the current transaction. - * - * Parameters: - * - * cell - <mxCell> whose collapsed state should be changed. - * collapsed - Boolean that specifies the new collpased state. - */ -mxGraphModel.prototype.setCollapsed = function(cell, collapsed) -{ - if (collapsed != this.isCollapsed(cell)) - { - this.execute(new mxCollapseChange(this, cell, collapsed)); - } - - return collapsed; -}; - -/** - * Function: collapsedStateForCellChanged - * - * Inner callback to update the collapsed state of the - * given <mxCell> using <mxCell.setCollapsed> and return - * the previous collapsed state. - * - * Parameters: - * - * cell - <mxCell> that specifies the cell to be updated. - * collapsed - Boolean that specifies the new collpased state. - */ -mxGraphModel.prototype.collapsedStateForCellChanged = function(cell, collapsed) -{ - var previous = this.isCollapsed(cell); - cell.setCollapsed(collapsed); - - return previous; -}; - -/** - * Function: isVisible - * - * Returns true if the given <mxCell> is visible. - * - * Parameters: - * - * cell - <mxCell> whose visible state should be returned. - */ -mxGraphModel.prototype.isVisible = function(cell) -{ - return (cell != null) ? cell.isVisible() : false; -}; - -/** - * Function: setVisible - * - * Sets the visible state of the given <mxCell> using <mxVisibleChange> and - * adds the change to the current transaction. - * - * Parameters: - * - * cell - <mxCell> whose visible state should be changed. - * visible - Boolean that specifies the new visible state. - */ -mxGraphModel.prototype.setVisible = function(cell, visible) -{ - if (visible != this.isVisible(cell)) - { - this.execute(new mxVisibleChange(this, cell, visible)); - } - - return visible; -}; - -/** - * Function: visibleStateForCellChanged - * - * Inner callback to update the visible state of the - * given <mxCell> using <mxCell.setCollapsed> and return - * the previous visible state. - * - * Parameters: - * - * cell - <mxCell> that specifies the cell to be updated. - * visible - Boolean that specifies the new visible state. - */ -mxGraphModel.prototype.visibleStateForCellChanged = function(cell, visible) -{ - var previous = this.isVisible(cell); - cell.setVisible(visible); - - return previous; -}; - -/** - * Function: execute - * - * Executes the given edit and fires events if required. The edit object - * requires an execute function which is invoked. The edit is added to the - * <currentEdit> between <beginUpdate> and <endUpdate> calls, so that - * events will be fired if this execute is an individual transaction, that - * is, if no previous <beginUpdate> calls have been made without calling - * <endUpdate>. This implementation fires an <execute> event before - * executing the given change. - * - * Parameters: - * - * change - Object that described the change. - */ -mxGraphModel.prototype.execute = function(change) -{ - change.execute(); - this.beginUpdate(); - this.currentEdit.add(change); - this.fireEvent(new mxEventObject(mxEvent.EXECUTE, 'change', change)); - this.endUpdate(); -}; - -/** - * Function: beginUpdate - * - * Increments the <updateLevel> by one. The event notification - * is queued until <updateLevel> reaches 0 by use of - * <endUpdate>. - * - * All changes on <mxGraphModel> are transactional, - * that is, they are executed in a single undoable change - * on the model (without transaction isolation). - * Therefore, if you want to combine any - * number of changes into a single undoable change, - * you should group any two or more API calls that - * modify the graph model between <beginUpdate> - * and <endUpdate> calls as shown here: - * - * (code) - * var model = graph.getModel(); - * var parent = graph.getDefaultParent(); - * var index = model.getChildCount(parent); - * model.beginUpdate(); - * try - * { - * model.add(parent, v1, index); - * model.add(parent, v2, index+1); - * } - * finally - * { - * model.endUpdate(); - * } - * (end) - * - * Of course there is a shortcut for appending a - * sequence of cells into the default parent: - * - * (code) - * graph.addCells([v1, v2]). - * (end) - */ -mxGraphModel.prototype.beginUpdate = function() -{ - this.updateLevel++; - this.fireEvent(new mxEventObject(mxEvent.BEGIN_UPDATE)); -}; - -/** - * Function: endUpdate - * - * Decrements the <updateLevel> by one and fires an <undo> - * event if the <updateLevel> reaches 0. This function - * indirectly fires a <change> event by invoking the notify - * function on the <currentEdit> und then creates a new - * <currentEdit> using <createUndoableEdit>. - * - * The <undo> event is fired only once per edit, whereas - * the <change> event is fired whenever the notify - * function is invoked, that is, on undo and redo of - * the edit. - */ -mxGraphModel.prototype.endUpdate = function() -{ - this.updateLevel--; - - if (!this.endingUpdate) - { - this.endingUpdate = this.updateLevel == 0; - this.fireEvent(new mxEventObject(mxEvent.END_UPDATE, 'edit', this.currentEdit)); - - try - { - if (this.endingUpdate && !this.currentEdit.isEmpty()) - { - this.fireEvent(new mxEventObject(mxEvent.BEFORE_UNDO, 'edit', this.currentEdit)); - var tmp = this.currentEdit; - this.currentEdit = this.createUndoableEdit(); - tmp.notify(); - this.fireEvent(new mxEventObject(mxEvent.UNDO, 'edit', tmp)); - } - } - finally - { - this.endingUpdate = false; - } - } -}; - -/** - * Function: createUndoableEdit - * - * Creates a new <mxUndoableEdit> that implements the - * notify function to fire a <change> and <notify> event - * through the <mxUndoableEdit>'s source. - */ -mxGraphModel.prototype.createUndoableEdit = function() -{ - var edit = new mxUndoableEdit(this, true); - - edit.notify = function() - { - // LATER: Remove changes property (deprecated) - edit.source.fireEvent(new mxEventObject(mxEvent.CHANGE, - 'edit', edit, 'changes', edit.changes)); - edit.source.fireEvent(new mxEventObject(mxEvent.NOTIFY, - 'edit', edit, 'changes', edit.changes)); - }; - - return edit; -}; - -/** - * Function: mergeChildren - * - * Merges the children of the given cell into the given target cell inside - * this model. All cells are cloned unless there is a corresponding cell in - * the model with the same id, in which case the source cell is ignored and - * all edges are connected to the corresponding cell in this model. Edges - * are considered to have no identity and are always cloned unless the - * cloneAllEdges flag is set to false, in which case edges with the same - * id in the target model are reconnected to reflect the terminals of the - * source edges. - */ -mxGraphModel.prototype.mergeChildren = function(from, to, cloneAllEdges) -{ - cloneAllEdges = (cloneAllEdges != null) ? cloneAllEdges : true; - - this.beginUpdate(); - try - { - var mapping = new Object(); - this.mergeChildrenImpl(from, to, cloneAllEdges, mapping); - - // Post-processes all edges in the mapping and - // reconnects the terminals to the corresponding - // cells in the target model - for (var key in mapping) - { - var cell = mapping[key]; - var terminal = this.getTerminal(cell, true); - - if (terminal != null) - { - terminal = mapping[mxCellPath.create(terminal)]; - this.setTerminal(cell, terminal, true); - } - - terminal = this.getTerminal(cell, false); - - if (terminal != null) - { - terminal = mapping[mxCellPath.create(terminal)]; - this.setTerminal(cell, terminal, false); - } - } - } - finally - { - this.endUpdate(); - } -}; - -/** - * Function: mergeChildren - * - * Clones the children of the source cell into the given target cell in - * this model and adds an entry to the mapping that maps from the source - * cell to the target cell with the same id or the clone of the source cell - * that was inserted into this model. - */ -mxGraphModel.prototype.mergeChildrenImpl = function(from, to, cloneAllEdges, mapping) -{ - this.beginUpdate(); - try - { - var childCount = from.getChildCount(); - - for (var i = 0; i < childCount; i++) - { - var cell = from.getChildAt(i); - - if (typeof(cell.getId) == 'function') - { - var id = cell.getId(); - var target = (id != null && (!this.isEdge(cell) || !cloneAllEdges)) ? - this.getCell(id) : null; - - // Clones and adds the child if no cell exists for the id - if (target == null) - { - var clone = cell.clone(); - clone.setId(id); - - // Sets the terminals from the original cell to the clone - // because the lookup uses strings not cells in JS - clone.setTerminal(cell.getTerminal(true), true); - clone.setTerminal(cell.getTerminal(false), false); - - // Do *NOT* use model.add as this will move the edge away - // from the parent in updateEdgeParent if maintainEdgeParent - // is enabled in the target model - target = to.insert(clone); - this.cellAdded(target); - } - - // Stores the mapping for later reconnecting edges - mapping[mxCellPath.create(cell)] = target; - - // Recurses - this.mergeChildrenImpl(cell, target, cloneAllEdges, mapping); - } - } - } - finally - { - this.endUpdate(); - } -}; - -/** - * Function: getParents - * - * Returns an array that represents the set (no duplicates) of all parents - * for the given array of cells. - * - * Parameters: - * - * cells - Array of cells whose parents should be returned. - */ -mxGraphModel.prototype.getParents = function(cells) -{ - var parents = []; - - if (cells != null) - { - var hash = new Object(); - - for (var i = 0; i < cells.length; i++) - { - var parent = this.getParent(cells[i]); - - if (parent != null) - { - var id = mxCellPath.create(parent); - - if (hash[id] == null) - { - hash[id] = parent; - parents.push(parent); - } - } - } - } - - return parents; -}; - -// -// Cell Cloning -// - -/** - * Function: cloneCell - * - * Returns a deep clone of the given <mxCell> (including - * the children) which is created using <cloneCells>. - * - * Parameters: - * - * cell - <mxCell> to be cloned. - */ -mxGraphModel.prototype.cloneCell = function(cell) -{ - if (cell != null) - { - return this.cloneCells([cell], true)[0]; - } - - return null; -}; - -/** - * Function: cloneCells - * - * Returns an array of clones for the given array of <mxCells>. - * Depending on the value of includeChildren, a deep clone is created for - * each cell. Connections are restored based if the corresponding - * cell is contained in the passed in array. - * - * Parameters: - * - * cells - Array of <mxCell> to be cloned. - * includeChildren - Boolean indicating if the cells should be cloned - * with all descendants. - */ -mxGraphModel.prototype.cloneCells = function(cells, includeChildren) -{ - var mapping = new Object(); - var clones = []; - - for (var i = 0; i < cells.length; i++) - { - if (cells[i] != null) - { - clones.push(this.cloneCellImpl(cells[i], mapping, includeChildren)); - } - else - { - clones.push(null); - } - } - - for (var i = 0; i < clones.length; i++) - { - if (clones[i] != null) - { - this.restoreClone(clones[i], cells[i], mapping); - } - } - - return clones; -}; - -/** - * Function: cloneCellImpl - * - * Inner helper method for cloning cells recursively. - */ -mxGraphModel.prototype.cloneCellImpl = function(cell, mapping, includeChildren) -{ - var clone = this.cellCloned(cell); - - // Stores the clone in the lookup under the - // cell path for the original cell - mapping[mxObjectIdentity.get(cell)] = clone; - - if (includeChildren) - { - var childCount = this.getChildCount(cell); - - for (var i = 0; i < childCount; i++) - { - var cloneChild = this.cloneCellImpl( - this.getChildAt(cell, i), mapping, true); - clone.insert(cloneChild); - } - } - - return clone; -}; - -/** - * Function: cellCloned - * - * Hook for cloning the cell. This returns cell.clone() or - * any possible exceptions. - */ -mxGraphModel.prototype.cellCloned = function(cell) -{ - return cell.clone(); -}; - -/** - * Function: restoreClone - * - * Inner helper method for restoring the connections in - * a network of cloned cells. - */ -mxGraphModel.prototype.restoreClone = function(clone, cell, mapping) -{ - var source = this.getTerminal(cell, true); - - if (source != null) - { - var tmp = mapping[mxObjectIdentity.get(source)]; - - if (tmp != null) - { - tmp.insertEdge(clone, true); - } - } - - var target = this.getTerminal(cell, false); - - if (target != null) - { - var tmp = mapping[mxObjectIdentity.get(target)]; - - if (tmp != null) - { - tmp.insertEdge(clone, false); - } - } - - var childCount = this.getChildCount(clone); - - for (var i = 0; i < childCount; i++) - { - this.restoreClone(this.getChildAt(clone, i), - this.getChildAt(cell, i), mapping); - } -}; - -// -// Atomic changes -// - -/** - * Class: mxRootChange - * - * Action to change the root in a model. - * - * Constructor: mxRootChange - * - * Constructs a change of the root in the - * specified model. - */ -function mxRootChange(model, root) -{ - this.model = model; - this.root = root; - this.previous = root; -}; - -/** - * Function: execute - * - * Carries out a change of the root using - * <mxGraphModel.rootChanged>. - */ -mxRootChange.prototype.execute = function() -{ - this.root = this.previous; - this.previous = this.model.rootChanged(this.previous); -}; - -/** - * Class: mxChildChange - * - * Action to add or remove a child in a model. - * - * Constructor: mxChildChange - * - * Constructs a change of a child in the - * specified model. - */ -function mxChildChange(model, parent, child, index) -{ - this.model = model; - this.parent = parent; - this.previous = parent; - this.child = child; - this.index = index; - this.previousIndex = index; -}; - -/** - * Function: execute - * - * Changes the parent of <child> using - * <mxGraphModel.parentForCellChanged> and - * removes or restores the cell's - * connections. - */ -mxChildChange.prototype.execute = function() -{ - var tmp = this.model.getParent(this.child); - var tmp2 = (tmp != null) ? tmp.getIndex(this.child) : 0; - - if (this.previous == null) - { - this.connect(this.child, false); - } - - tmp = this.model.parentForCellChanged( - this.child, this.previous, this.previousIndex); - - if (this.previous != null) - { - this.connect(this.child, true); - } - - this.parent = this.previous; - this.previous = tmp; - this.index = this.previousIndex; - this.previousIndex = tmp2; -}; - -/** - * Function: disconnect - * - * Disconnects the given cell recursively from its - * terminals and stores the previous terminal in the - * cell's terminals. - */ -mxChildChange.prototype.connect = function(cell, isConnect) -{ - isConnect = (isConnect != null) ? isConnect : true; - - var source = cell.getTerminal(true); - var target = cell.getTerminal(false); - - if (source != null) - { - if (isConnect) - { - this.model.terminalForCellChanged(cell, source, true); - } - else - { - this.model.terminalForCellChanged(cell, null, true); - } - } - - if (target != null) - { - if (isConnect) - { - this.model.terminalForCellChanged(cell, target, false); - } - else - { - this.model.terminalForCellChanged(cell, null, false); - } - } - - cell.setTerminal(source, true); - cell.setTerminal(target, false); - - var childCount = this.model.getChildCount(cell); - - for (var i=0; i<childCount; i++) - { - this.connect(this.model.getChildAt(cell, i), isConnect); - } -}; - -/** - * Class: mxTerminalChange - * - * Action to change a terminal in a model. - * - * Constructor: mxTerminalChange - * - * Constructs a change of a terminal in the - * specified model. - */ -function mxTerminalChange(model, cell, terminal, source) -{ - this.model = model; - this.cell = cell; - this.terminal = terminal; - this.previous = terminal; - this.source = source; -}; - -/** - * Function: execute - * - * Changes the terminal of <cell> to <previous> using - * <mxGraphModel.terminalForCellChanged>. - */ -mxTerminalChange.prototype.execute = function() -{ - this.terminal = this.previous; - this.previous = this.model.terminalForCellChanged( - this.cell, this.previous, this.source); -}; - -/** - * Class: mxValueChange - * - * Action to change a user object in a model. - * - * Constructor: mxValueChange - * - * Constructs a change of a user object in the - * specified model. - */ -function mxValueChange(model, cell, value) -{ - this.model = model; - this.cell = cell; - this.value = value; - this.previous = value; -}; - -/** - * Function: execute - * - * Changes the value of <cell> to <previous> using - * <mxGraphModel.valueForCellChanged>. - */ -mxValueChange.prototype.execute = function() -{ - this.value = this.previous; - this.previous = this.model.valueForCellChanged( - this.cell, this.previous); -}; - -/** - * Class: mxStyleChange - * - * Action to change a cell's style in a model. - * - * Constructor: mxStyleChange - * - * Constructs a change of a style in the - * specified model. - */ -function mxStyleChange(model, cell, style) -{ - this.model = model; - this.cell = cell; - this.style = style; - this.previous = style; -}; - -/** - * Function: execute - * - * Changes the style of <cell> to <previous> using - * <mxGraphModel.styleForCellChanged>. - */ -mxStyleChange.prototype.execute = function() -{ - this.style = this.previous; - this.previous = this.model.styleForCellChanged( - this.cell, this.previous); -}; - -/** - * Class: mxGeometryChange - * - * Action to change a cell's geometry in a model. - * - * Constructor: mxGeometryChange - * - * Constructs a change of a geometry in the - * specified model. - */ -function mxGeometryChange(model, cell, geometry) -{ - this.model = model; - this.cell = cell; - this.geometry = geometry; - this.previous = geometry; -}; - -/** - * Function: execute - * - * Changes the geometry of <cell> ro <previous> using - * <mxGraphModel.geometryForCellChanged>. - */ -mxGeometryChange.prototype.execute = function() -{ - this.geometry = this.previous; - this.previous = this.model.geometryForCellChanged( - this.cell, this.previous); -}; - -/** - * Class: mxCollapseChange - * - * Action to change a cell's collapsed state in a model. - * - * Constructor: mxCollapseChange - * - * Constructs a change of a collapsed state in the - * specified model. - */ -function mxCollapseChange(model, cell, collapsed) -{ - this.model = model; - this.cell = cell; - this.collapsed = collapsed; - this.previous = collapsed; -}; - -/** - * Function: execute - * - * Changes the collapsed state of <cell> to <previous> using - * <mxGraphModel.collapsedStateForCellChanged>. - */ -mxCollapseChange.prototype.execute = function() -{ - this.collapsed = this.previous; - this.previous = this.model.collapsedStateForCellChanged( - this.cell, this.previous); -}; - -/** - * Class: mxVisibleChange - * - * Action to change a cell's visible state in a model. - * - * Constructor: mxVisibleChange - * - * Constructs a change of a visible state in the - * specified model. - */ -function mxVisibleChange(model, cell, visible) -{ - this.model = model; - this.cell = cell; - this.visible = visible; - this.previous = visible; -}; - -/** - * Function: execute - * - * Changes the visible state of <cell> to <previous> using - * <mxGraphModel.visibleStateForCellChanged>. - */ -mxVisibleChange.prototype.execute = function() -{ - this.visible = this.previous; - this.previous = this.model.visibleStateForCellChanged( - this.cell, this.previous); -}; - -/** - * Class: mxCellAttributeChange - * - * Action to change the attribute of a cell's user object. - * There is no method on the graph model that uses this - * action. To use the action, you can use the code shown - * in the example below. - * - * Example: - * - * To change the attributeName in the cell's user object - * to attributeValue, use the following code: - * - * (code) - * model.beginUpdate(); - * try - * { - * var edit = new mxCellAttributeChange( - * cell, attributeName, attributeValue); - * model.execute(edit); - * } - * finally - * { - * model.endUpdate(); - * } - * (end) - * - * Constructor: mxCellAttributeChange - * - * Constructs a change of a attribute of the DOM node - * stored as the value of the given <mxCell>. - */ -function mxCellAttributeChange(cell, attribute, value) -{ - this.cell = cell; - this.attribute = attribute; - this.value = value; - this.previous = value; -}; - -/** - * Function: execute - * - * Changes the attribute of the cell's user object by - * using <mxCell.setAttribute>. - */ -mxCellAttributeChange.prototype.execute = function() -{ - var tmp = this.cell.getAttribute(this.attribute); - - if (this.previous == null) - { - this.cell.value.removeAttribute(this.attribute); - } - else - { - this.cell.setAttribute(this.attribute, this.previous); - } - - this.previous = tmp; -}; diff --git a/src/js/mxClient.js b/src/js/mxClient.js deleted file mode 100644 index a23b5fc..0000000 --- a/src/js/mxClient.js +++ /dev/null @@ -1,643 +0,0 @@ -/** - * $Id: mxClient.js,v 1.203 2012-07-19 15:19:07 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -var mxClient = -{ - - /** - * Class: mxClient - * - * Bootstrapping mechanism for the mxGraph thin client. The production version - * of this file contains all code required to run the mxGraph thin client, as - * well as global constants to identify the browser and operating system in - * use. You may have to load chrome://global/content/contentAreaUtils.js in - * your page to disable certain security restrictions in Mozilla. - * - * Variable: VERSION - * - * Contains the current version of the mxGraph library. The strings that - * communicate versions of mxGraph use the following format. - * - * versionMajor.versionMinor.buildNumber.revisionNumber - * - * Current version is 1.10.4.1. - */ - VERSION: '1.10.4.1', - - /** - * Variable: IS_IE - * - * True if the current browser is Internet Explorer. - */ - IS_IE: navigator.userAgent.indexOf('MSIE') >= 0, - - /** - * Variable: IS_IE6 - * - * True if the current browser is Internet Explorer 6.x. - */ - IS_IE6: navigator.userAgent.indexOf('MSIE 6') >= 0, - - /** - * Variable: IS_QUIRKS - * - * True if the current browser is Internet Explorer and it is in quirks mode. - */ - IS_QUIRKS: navigator.userAgent.indexOf('MSIE') >= 0 && (document.documentMode == null || document.documentMode == 5), - - /** - * Variable: IS_NS - * - * True if the current browser is Netscape (including Firefox). - */ - IS_NS: navigator.userAgent.indexOf('Mozilla/') >= 0 && - navigator.userAgent.indexOf('MSIE') < 0, - - /** - * Variable: IS_OP - * - * True if the current browser is Opera. - */ - IS_OP: navigator.userAgent.indexOf('Opera/') >= 0, - - /** - * Variable: IS_OT - * - * True if -o-transform is available as a CSS style. This is the case - * for Opera browsers that use Presto/2.5 and later. - */ - IS_OT: navigator.userAgent.indexOf('Presto/2.4.') < 0 && - navigator.userAgent.indexOf('Presto/2.3.') < 0 && - navigator.userAgent.indexOf('Presto/2.2.') < 0 && - navigator.userAgent.indexOf('Presto/2.1.') < 0 && - navigator.userAgent.indexOf('Presto/2.0.') < 0 && - navigator.userAgent.indexOf('Presto/1.') < 0, - - /** - * Variable: IS_SF - * - * True if the current browser is Safari. - */ - IS_SF: navigator.userAgent.indexOf('AppleWebKit/') >= 0 && - navigator.userAgent.indexOf('Chrome/') < 0, - - /** - * Variable: IS_GC - * - * True if the current browser is Google Chrome. - */ - IS_GC: navigator.userAgent.indexOf('Chrome/') >= 0, - - /** - * Variable: IS_MT - * - * True if -moz-transform is available as a CSS style. This is the case - * for all Firefox-based browsers newer than or equal 3, such as Camino, - * Iceweasel, Seamonkey and Iceape. - */ - IS_MT: (navigator.userAgent.indexOf('Firefox/') >= 0 && - navigator.userAgent.indexOf('Firefox/1.') < 0 && - navigator.userAgent.indexOf('Firefox/2.') < 0) || - (navigator.userAgent.indexOf('Iceweasel/') >= 0 && - navigator.userAgent.indexOf('Iceweasel/1.') < 0 && - navigator.userAgent.indexOf('Iceweasel/2.') < 0) || - (navigator.userAgent.indexOf('SeaMonkey/') >= 0 && - navigator.userAgent.indexOf('SeaMonkey/1.') < 0) || - (navigator.userAgent.indexOf('Iceape/') >= 0 && - navigator.userAgent.indexOf('Iceape/1.') < 0), - - /** - * Variable: IS_SVG - * - * True if the browser supports SVG. - */ - IS_SVG: navigator.userAgent.indexOf('Firefox/') >= 0 || // FF and Camino - navigator.userAgent.indexOf('Iceweasel/') >= 0 || // Firefox on Debian - navigator.userAgent.indexOf('Seamonkey/') >= 0 || // Firefox-based - navigator.userAgent.indexOf('Iceape/') >= 0 || // Seamonkey on Debian - navigator.userAgent.indexOf('Galeon/') >= 0 || // Gnome Browser (old) - navigator.userAgent.indexOf('Epiphany/') >= 0 || // Gnome Browser (new) - navigator.userAgent.indexOf('AppleWebKit/') >= 0 || // Safari/Google Chrome - navigator.userAgent.indexOf('Gecko/') >= 0 || // Netscape/Gecko - navigator.userAgent.indexOf('Opera/') >= 0, - - - /** - * Variable: NO_FO - * - * True if foreignObject support is not available. This is the case for - * Opera and older SVG-based browsers. IE does not require this type - * of tag. - */ - NO_FO: navigator.userAgent.indexOf('Firefox/1.') >= 0 || - navigator.userAgent.indexOf('Iceweasel/1.') >= 0 || - navigator.userAgent.indexOf('Firefox/2.') >= 0 || - navigator.userAgent.indexOf('Iceweasel/2.') >= 0 || - navigator.userAgent.indexOf('SeaMonkey/1.') >= 0 || - navigator.userAgent.indexOf('Iceape/1.') >= 0 || - navigator.userAgent.indexOf('Camino/1.') >= 0 || - navigator.userAgent.indexOf('Epiphany/2.') >= 0 || - navigator.userAgent.indexOf('Opera/') >= 0 || - navigator.userAgent.indexOf('MSIE') >= 0 || - navigator.userAgent.indexOf('Mozilla/2.') >= 0, // Safari/Google Chrome - - /** - * Variable: IS_VML - * - * True if the browser supports VML. - */ - IS_VML: navigator.appName.toUpperCase() == 'MICROSOFT INTERNET EXPLORER', - - /** - * Variable: IS_MAC - * - * True if the client is a Mac. - */ - IS_MAC: navigator.userAgent.toUpperCase().indexOf('MACINTOSH') > 0, - - /** - * Variable: IS_TOUCH - * - * True if this client uses a touch interface (no mouse). Currently this - * detects IPads, IPods, IPhones and Android devices. - */ - IS_TOUCH: navigator.userAgent.toUpperCase().indexOf('IPAD') > 0 || - navigator.userAgent.toUpperCase().indexOf('IPOD') > 0 || - navigator.userAgent.toUpperCase().indexOf('IPHONE') > 0 || - navigator.userAgent.toUpperCase().indexOf('ANDROID') > 0, - - /** - * Variable: IS_LOCAL - * - * True if the documents location does not start with http:// or https://. - */ - IS_LOCAL: document.location.href.indexOf('http://') < 0 && - document.location.href.indexOf('https://') < 0, - - /** - * Function: isBrowserSupported - * - * Returns true if the current browser is supported, that is, if - * <mxClient.IS_VML> or <mxClient.IS_SVG> is true. - * - * Example: - * - * (code) - * if (!mxClient.isBrowserSupported()) - * { - * mxUtils.error('Browser is not supported!', 200, false); - * } - * (end) - */ - isBrowserSupported: function() - { - return mxClient.IS_VML || mxClient.IS_SVG; - }, - - /** - * Function: link - * - * Adds a link node to the head of the document. Use this - * to add a stylesheet to the page as follows: - * - * (code) - * mxClient.link('stylesheet', filename); - * (end) - * - * where filename is the (relative) URL of the stylesheet. The charset - * is hardcoded to ISO-8859-1 and the type is text/css. - * - * Parameters: - * - * rel - String that represents the rel attribute of the link node. - * href - String that represents the href attribute of the link node. - * doc - Optional parent document of the link node. - */ - link: function(rel, href, doc) - { - doc = doc || document; - - // Workaround for Operation Aborted in IE6 if base tag is used in head - if (mxClient.IS_IE6) - { - doc.write('<link rel="'+rel+'" href="'+href+'" charset="ISO-8859-1" type="text/css"/>'); - } - else - { - var link = doc.createElement('link'); - - link.setAttribute('rel', rel); - link.setAttribute('href', href); - link.setAttribute('charset', 'ISO-8859-1'); - link.setAttribute('type', 'text/css'); - - var head = doc.getElementsByTagName('head')[0]; - head.appendChild(link); - } - }, - - /** - * Function: include - * - * Dynamically adds a script node to the document header. - * - * In production environments, the includes are resolved in the mxClient.js - * file to reduce the number of requests required for client startup. This - * function should only be used in development environments, but not in - * production systems. - */ - include: function(src) - { - document.write('<script src="'+src+'"></script>'); - }, - - /** - * Function: dispose - * - * Frees up memory in IE by resolving cyclic dependencies between the DOM - * and the JavaScript objects. This is always invoked in IE when the page - * unloads. - */ - dispose: function() - { - // Cleans all objects where listeners have been added - for (var i = 0; i < mxEvent.objects.length; i++) - { - if (mxEvent.objects[i].mxListenerList != null) - { - mxEvent.removeAllListeners(mxEvent.objects[i]); - } - } - } - -}; - -/** - * Variable: mxLoadResources - * - * Optional global config variable to toggle loading of the two resource files - * in <mxGraph> and <mxEditor>. Default is true. NOTE: This is a global variable, - * not a variable of mxClient. - * - * (code) - * <script type="text/javascript"> - * var mxLoadResources = false; - * </script> - * <script type="text/javascript" src="/path/to/core/directory/js/mxClient.js"></script> - * (end) - */ -if (typeof(mxLoadResources) == 'undefined') -{ - mxLoadResources = true; -} - -/** - * Variable: mxLoadStylesheets - * - * Optional global config variable to toggle loading of the CSS files when - * the library is initialized. Default is true. NOTE: This is a global variable, - * not a variable of mxClient. - * - * (code) - * <script type="text/javascript"> - * var mxLoadStylesheets = false; - * </script> - * <script type="text/javascript" src="/path/to/core/directory/js/mxClient.js"></script> - * (end) - */ -if (typeof(mxLoadStylesheets) == 'undefined') -{ - mxLoadStylesheets = true; -} - -/** - * Variable: basePath - * - * Basepath for all URLs in the core without trailing slash. Default is '.'. - * Set mxBasePath prior to loading the mxClient library as follows to override - * this setting: - * - * (code) - * <script type="text/javascript"> - * mxBasePath = '/path/to/core/directory'; - * </script> - * <script type="text/javascript" src="/path/to/core/directory/js/mxClient.js"></script> - * (end) - * - * When using a relative path, the path is relative to the URL of the page that - * contains the assignment. Trailing slashes are automatically removed. - */ -if (typeof(mxBasePath) != 'undefined' && mxBasePath.length > 0) -{ - // Adds a trailing slash if required - if (mxBasePath.substring(mxBasePath.length - 1) == '/') - { - mxBasePath = mxBasePath.substring(0, mxBasePath.length - 1); - } - - mxClient.basePath = mxBasePath; -} -else -{ - mxClient.basePath = '.'; -} - -/** - * Variable: imageBasePath - * - * Basepath for all images URLs in the core without trailing slash. Default is - * <mxClient.basePath> + '/images'. Set mxImageBasePath prior to loading the - * mxClient library as follows to override this setting: - * - * (code) - * <script type="text/javascript"> - * mxImageBasePath = '/path/to/image/directory'; - * </script> - * <script type="text/javascript" src="/path/to/core/directory/js/mxClient.js"></script> - * (end) - * - * When using a relative path, the path is relative to the URL of the page that - * contains the assignment. Trailing slashes are automatically removed. - */ -if (typeof(mxImageBasePath) != 'undefined' && mxImageBasePath.length > 0) -{ - // Adds a trailing slash if required - if (mxImageBasePath.substring(mxImageBasePath.length - 1) == '/') - { - mxImageBasePath = mxImageBasePath.substring(0, mxImageBasePath.length - 1); - } - - mxClient.imageBasePath = mxImageBasePath; -} -else -{ - mxClient.imageBasePath = mxClient.basePath + '/images'; -} - -/** - * Variable: language - * - * Defines the language of the client, eg. en for english, de for german etc. - * The special value 'none' will disable all built-in internationalization and - * resource loading. See <mxResources.getSpecialBundle> for handling identifiers - * with and without a dash. - * - * Set mxLanguage prior to loading the mxClient library as follows to override - * this setting: - * - * (code) - * <script type="text/javascript"> - * mxLanguage = 'en'; - * </script> - * <script type="text/javascript" src="js/mxClient.js"></script> - * (end) - * - * If internationalization is disabled, then the following variables should be - * overridden to reflect the current language of the system. These variables are - * cleared when i18n is disabled. - * <mxEditor.askZoomResource>, <mxEditor.lastSavedResource>, - * <mxEditor.currentFileResource>, <mxEditor.propertiesResource>, - * <mxEditor.tasksResource>, <mxEditor.helpResource>, <mxEditor.outlineResource>, - * <mxElbowEdgeHandler.doubleClickOrientationResource>, <mxUtils.errorResource>, - * <mxUtils.closeResource>, <mxGraphSelectionModel.doneResource>, - * <mxGraphSelectionModel.updatingSelectionResource>, <mxGraphView.doneResource>, - * <mxGraphView.updatingDocumentResource>, <mxCellRenderer.collapseExpandResource>, - * <mxGraph.containsValidationErrorsResource> and - * <mxGraph.alreadyConnectedResource>. - */ -if (typeof(mxLanguage) != 'undefined') -{ - mxClient.language = mxLanguage; -} -else -{ - mxClient.language = (mxClient.IS_IE) ? navigator.userLanguage : navigator.language; -} - -/** - * Variable: defaultLanguage - * - * Defines the default language which is used in the common resource files. Any - * resources for this language will only load the common resource file, but not - * the language-specific resource file. Default is 'en'. - * - * Set mxDefaultLanguage prior to loading the mxClient library as follows to override - * this setting: - * - * (code) - * <script type="text/javascript"> - * mxDefaultLanguage = 'de'; - * </script> - * <script type="text/javascript" src="js/mxClient.js"></script> - * (end) - */ -if (typeof(mxDefaultLanguage) != 'undefined') -{ - mxClient.defaultLanguage = mxDefaultLanguage; -} -else -{ - mxClient.defaultLanguage = 'en'; -} - -// Adds all required stylesheets and namespaces -if (mxLoadStylesheets) -{ - mxClient.link('stylesheet', mxClient.basePath + '/css/common.css'); -} - -/** - * Variable: languages - * - * Defines the optional array of all supported language extensions. The default - * language does not have to be part of this list. See - * <mxResources.isLanguageSupported>. - * - * (code) - * <script type="text/javascript"> - * mxLanguages = ['de', 'it', 'fr']; - * </script> - * <script type="text/javascript" src="js/mxClient.js"></script> - * (end) - * - * This is used to avoid unnecessary requests to language files, ie. if a 404 - * will be returned. - */ -if (typeof(mxLanguages) != 'undefined') -{ - mxClient.languages = mxLanguages; -} - -if (mxClient.IS_IE) -{ - // IE9/10 standards mode uses SVG (VML is broken) - if (document.documentMode >= 9) - { - mxClient.IS_VML = false; - mxClient.IS_SVG = true; - } - else - { - // Enables support for IE8 standards mode. Note that this requires all attributes for VML - // elements to be set using direct notation, ie. node.attr = value. The use of setAttribute - // is not possible. See mxShape.init for more code to handle this specific document mode. - if (document.documentMode == 8) - { - document.namespaces.add('v', 'urn:schemas-microsoft-com:vml', '#default#VML'); - document.namespaces.add('o', 'urn:schemas-microsoft-com:office:office', '#default#VML'); - } - else - { - document.namespaces.add('v', 'urn:schemas-microsoft-com:vml'); - document.namespaces.add('o', 'urn:schemas-microsoft-com:office:office'); - } - - var ss = document.createStyleSheet(); - ss.cssText = 'v\\:*{behavior:url(#default#VML)}o\\:*{behavior:url(#default#VML)}'; - - if (mxLoadStylesheets) - { - mxClient.link('stylesheet', mxClient.basePath + '/css/explorer.css'); - } - } - - // Cleans up resources when the application terminates - window.attachEvent('onunload', mxClient.dispose); -} - -mxClient.include(mxClient.basePath+'/js/util/mxLog.js'); -mxClient.include(mxClient.basePath+'/js/util/mxObjectIdentity.js'); -mxClient.include(mxClient.basePath+'/js/util/mxDictionary.js'); -mxClient.include(mxClient.basePath+'/js/util/mxResources.js'); -mxClient.include(mxClient.basePath+'/js/util/mxPoint.js'); -mxClient.include(mxClient.basePath+'/js/util/mxRectangle.js'); -mxClient.include(mxClient.basePath+'/js/util/mxEffects.js'); -mxClient.include(mxClient.basePath+'/js/util/mxUtils.js'); -mxClient.include(mxClient.basePath+'/js/util/mxConstants.js'); -mxClient.include(mxClient.basePath+'/js/util/mxEventObject.js'); -mxClient.include(mxClient.basePath+'/js/util/mxMouseEvent.js'); -mxClient.include(mxClient.basePath+'/js/util/mxEventSource.js'); -mxClient.include(mxClient.basePath+'/js/util/mxEvent.js'); -mxClient.include(mxClient.basePath+'/js/util/mxXmlRequest.js'); -mxClient.include(mxClient.basePath+'/js/util/mxClipboard.js'); -mxClient.include(mxClient.basePath+'/js/util/mxWindow.js'); -mxClient.include(mxClient.basePath+'/js/util/mxForm.js'); -mxClient.include(mxClient.basePath+'/js/util/mxImage.js'); -mxClient.include(mxClient.basePath+'/js/util/mxDivResizer.js'); -mxClient.include(mxClient.basePath+'/js/util/mxDragSource.js'); -mxClient.include(mxClient.basePath+'/js/util/mxToolbar.js'); -mxClient.include(mxClient.basePath+'/js/util/mxSession.js'); -mxClient.include(mxClient.basePath+'/js/util/mxUndoableEdit.js'); -mxClient.include(mxClient.basePath+'/js/util/mxUndoManager.js'); -mxClient.include(mxClient.basePath+'/js/util/mxUrlConverter.js'); -mxClient.include(mxClient.basePath+'/js/util/mxPanningManager.js'); -mxClient.include(mxClient.basePath+'/js/util/mxPath.js'); -mxClient.include(mxClient.basePath+'/js/util/mxPopupMenu.js'); -mxClient.include(mxClient.basePath+'/js/util/mxAutoSaveManager.js'); -mxClient.include(mxClient.basePath+'/js/util/mxAnimation.js'); -mxClient.include(mxClient.basePath+'/js/util/mxMorphing.js'); -mxClient.include(mxClient.basePath+'/js/util/mxImageBundle.js'); -mxClient.include(mxClient.basePath+'/js/util/mxImageExport.js'); -mxClient.include(mxClient.basePath+'/js/util/mxXmlCanvas2D.js'); -mxClient.include(mxClient.basePath+'/js/util/mxSvgCanvas2D.js'); -mxClient.include(mxClient.basePath+'/js/util/mxGuide.js'); -mxClient.include(mxClient.basePath+'/js/shape/mxShape.js'); -mxClient.include(mxClient.basePath+'/js/shape/mxStencil.js'); -mxClient.include(mxClient.basePath+'/js/shape/mxStencilRegistry.js'); -mxClient.include(mxClient.basePath+'/js/shape/mxStencilShape.js'); -mxClient.include(mxClient.basePath+'/js/shape/mxMarker.js'); -mxClient.include(mxClient.basePath+'/js/shape/mxActor.js'); -mxClient.include(mxClient.basePath+'/js/shape/mxCloud.js'); -mxClient.include(mxClient.basePath+'/js/shape/mxRectangleShape.js'); -mxClient.include(mxClient.basePath+'/js/shape/mxEllipse.js'); -mxClient.include(mxClient.basePath+'/js/shape/mxDoubleEllipse.js'); -mxClient.include(mxClient.basePath+'/js/shape/mxRhombus.js'); -mxClient.include(mxClient.basePath+'/js/shape/mxPolyline.js'); -mxClient.include(mxClient.basePath+'/js/shape/mxArrow.js'); -mxClient.include(mxClient.basePath+'/js/shape/mxText.js'); -mxClient.include(mxClient.basePath+'/js/shape/mxTriangle.js'); -mxClient.include(mxClient.basePath+'/js/shape/mxHexagon.js'); -mxClient.include(mxClient.basePath+'/js/shape/mxLine.js'); -mxClient.include(mxClient.basePath+'/js/shape/mxImageShape.js'); -mxClient.include(mxClient.basePath+'/js/shape/mxLabel.js'); -mxClient.include(mxClient.basePath+'/js/shape/mxCylinder.js'); -mxClient.include(mxClient.basePath+'/js/shape/mxConnector.js'); -mxClient.include(mxClient.basePath+'/js/shape/mxSwimlane.js'); -mxClient.include(mxClient.basePath+'/js/layout/mxGraphLayout.js'); -mxClient.include(mxClient.basePath+'/js/layout/mxStackLayout.js'); -mxClient.include(mxClient.basePath+'/js/layout/mxPartitionLayout.js'); -mxClient.include(mxClient.basePath+'/js/layout/mxCompactTreeLayout.js'); -mxClient.include(mxClient.basePath+'/js/layout/mxFastOrganicLayout.js'); -mxClient.include(mxClient.basePath+'/js/layout/mxCircleLayout.js'); -mxClient.include(mxClient.basePath+'/js/layout/mxParallelEdgeLayout.js'); -mxClient.include(mxClient.basePath+'/js/layout/mxCompositeLayout.js'); -mxClient.include(mxClient.basePath+'/js/layout/mxEdgeLabelLayout.js'); -mxClient.include(mxClient.basePath+'/js/layout/hierarchical/model/mxGraphAbstractHierarchyCell.js'); -mxClient.include(mxClient.basePath+'/js/layout/hierarchical/model/mxGraphHierarchyNode.js'); -mxClient.include(mxClient.basePath+'/js/layout/hierarchical/model/mxGraphHierarchyEdge.js'); -mxClient.include(mxClient.basePath+'/js/layout/hierarchical/model/mxGraphHierarchyModel.js'); -mxClient.include(mxClient.basePath+'/js/layout/hierarchical/stage/mxHierarchicalLayoutStage.js'); -mxClient.include(mxClient.basePath+'/js/layout/hierarchical/stage/mxMedianHybridCrossingReduction.js'); -mxClient.include(mxClient.basePath+'/js/layout/hierarchical/stage/mxMinimumCycleRemover.js'); -mxClient.include(mxClient.basePath+'/js/layout/hierarchical/stage/mxCoordinateAssignment.js'); -mxClient.include(mxClient.basePath+'/js/layout/hierarchical/mxHierarchicalLayout.js'); -mxClient.include(mxClient.basePath+'/js/model/mxGraphModel.js'); -mxClient.include(mxClient.basePath+'/js/model/mxCell.js'); -mxClient.include(mxClient.basePath+'/js/model/mxGeometry.js'); -mxClient.include(mxClient.basePath+'/js/model/mxCellPath.js'); -mxClient.include(mxClient.basePath+'/js/view/mxPerimeter.js'); -mxClient.include(mxClient.basePath+'/js/view/mxPrintPreview.js'); -mxClient.include(mxClient.basePath+'/js/view/mxStylesheet.js'); -mxClient.include(mxClient.basePath+'/js/view/mxCellState.js'); -mxClient.include(mxClient.basePath+'/js/view/mxGraphSelectionModel.js'); -mxClient.include(mxClient.basePath+'/js/view/mxCellEditor.js'); -mxClient.include(mxClient.basePath+'/js/view/mxCellRenderer.js'); -mxClient.include(mxClient.basePath+'/js/view/mxEdgeStyle.js'); -mxClient.include(mxClient.basePath+'/js/view/mxStyleRegistry.js'); -mxClient.include(mxClient.basePath+'/js/view/mxGraphView.js'); -mxClient.include(mxClient.basePath+'/js/view/mxGraph.js'); -mxClient.include(mxClient.basePath+'/js/view/mxCellOverlay.js'); -mxClient.include(mxClient.basePath+'/js/view/mxOutline.js'); -mxClient.include(mxClient.basePath+'/js/view/mxMultiplicity.js'); -mxClient.include(mxClient.basePath+'/js/view/mxLayoutManager.js'); -mxClient.include(mxClient.basePath+'/js/view/mxSpaceManager.js'); -mxClient.include(mxClient.basePath+'/js/view/mxSwimlaneManager.js'); -mxClient.include(mxClient.basePath+'/js/view/mxTemporaryCellStates.js'); -mxClient.include(mxClient.basePath+'/js/view/mxCellStatePreview.js'); -mxClient.include(mxClient.basePath+'/js/view/mxConnectionConstraint.js'); -mxClient.include(mxClient.basePath+'/js/handler/mxGraphHandler.js'); -mxClient.include(mxClient.basePath+'/js/handler/mxPanningHandler.js'); -mxClient.include(mxClient.basePath+'/js/handler/mxCellMarker.js'); -mxClient.include(mxClient.basePath+'/js/handler/mxSelectionCellsHandler.js'); -mxClient.include(mxClient.basePath+'/js/handler/mxConnectionHandler.js'); -mxClient.include(mxClient.basePath+'/js/handler/mxConstraintHandler.js'); -mxClient.include(mxClient.basePath+'/js/handler/mxRubberband.js'); -mxClient.include(mxClient.basePath+'/js/handler/mxVertexHandler.js'); -mxClient.include(mxClient.basePath+'/js/handler/mxEdgeHandler.js'); -mxClient.include(mxClient.basePath+'/js/handler/mxElbowEdgeHandler.js'); -mxClient.include(mxClient.basePath+'/js/handler/mxEdgeSegmentHandler.js'); -mxClient.include(mxClient.basePath+'/js/handler/mxKeyHandler.js'); -mxClient.include(mxClient.basePath+'/js/handler/mxTooltipHandler.js'); -mxClient.include(mxClient.basePath+'/js/handler/mxCellTracker.js'); -mxClient.include(mxClient.basePath+'/js/handler/mxCellHighlight.js'); -mxClient.include(mxClient.basePath+'/js/editor/mxDefaultKeyHandler.js'); -mxClient.include(mxClient.basePath+'/js/editor/mxDefaultPopupMenu.js'); -mxClient.include(mxClient.basePath+'/js/editor/mxDefaultToolbar.js'); -mxClient.include(mxClient.basePath+'/js/editor/mxEditor.js'); -mxClient.include(mxClient.basePath+'/js/io/mxCodecRegistry.js'); -mxClient.include(mxClient.basePath+'/js/io/mxCodec.js'); -mxClient.include(mxClient.basePath+'/js/io/mxObjectCodec.js'); -mxClient.include(mxClient.basePath+'/js/io/mxCellCodec.js'); -mxClient.include(mxClient.basePath+'/js/io/mxModelCodec.js'); -mxClient.include(mxClient.basePath+'/js/io/mxRootChangeCodec.js'); -mxClient.include(mxClient.basePath+'/js/io/mxChildChangeCodec.js'); -mxClient.include(mxClient.basePath+'/js/io/mxTerminalChangeCodec.js'); -mxClient.include(mxClient.basePath+'/js/io/mxGenericChangeCodec.js'); -mxClient.include(mxClient.basePath+'/js/io/mxGraphCodec.js'); -mxClient.include(mxClient.basePath+'/js/io/mxGraphViewCodec.js'); -mxClient.include(mxClient.basePath+'/js/io/mxStylesheetCodec.js'); -mxClient.include(mxClient.basePath+'/js/io/mxDefaultKeyHandlerCodec.js'); -mxClient.include(mxClient.basePath+'/js/io/mxDefaultToolbarCodec.js'); -mxClient.include(mxClient.basePath+'/js/io/mxDefaultPopupMenuCodec.js'); -mxClient.include(mxClient.basePath+'/js/io/mxEditorCodec.js'); diff --git a/src/js/shape/mxActor.js b/src/js/shape/mxActor.js deleted file mode 100644 index e6a0765..0000000 --- a/src/js/shape/mxActor.js +++ /dev/null @@ -1,183 +0,0 @@ -/** - * $Id: mxActor.js,v 1.35 2012-07-31 11:46:53 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -/** - * Class: mxActor - * - * Extends <mxShape> to implement an actor shape. If a custom shape with one - * filled area is needed, then this shape's <redrawPath> should be overridden. - * - * Example: - * - * (code) - * function SampleShape() { } - * - * SampleShape.prototype = new mxActor(); - * SampleShape.prototype.constructor = vsAseShape; - * - * mxCellRenderer.prototype.defaultShapes['sample'] = SampleShape; - * SampleShape.prototype.redrawPath = function(path, x, y, w, h) - * { - * path.moveTo(0, 0); - * path.lineTo(w, h); - * // ... - * path.close(); - * } - * (end) - * - * This shape is registered under <mxConstants.SHAPE_ACTOR> in - * <mxCellRenderer>. - * - * Constructor: mxActor - * - * Constructs a new actor shape. - * - * Parameters: - * - * bounds - <mxRectangle> that defines the bounds. This is stored in - * <mxShape.bounds>. - * fill - String that defines the fill color. This is stored in <fill>. - * stroke - String that defines the stroke color. This is stored in <stroke>. - * strokewidth - Optional integer that defines the stroke width. Default is - * 1. This is stored in <strokewidth>. - */ -function mxActor(bounds, fill, stroke, strokewidth) -{ - this.bounds = bounds; - this.fill = fill; - this.stroke = stroke; - this.strokewidth = (strokewidth != null) ? strokewidth : 1; -}; - -/** - * Extends mxShape. - */ -mxActor.prototype = new mxShape(); -mxActor.prototype.constructor = mxActor; - -/** - * Variable: mixedModeHtml - * - * Overrides the parent value with false, meaning it will - * draw in VML in mixed Html mode. - */ -mxActor.prototype.mixedModeHtml = false; - -/** - * Variable: preferModeHtml - * - * Overrides the parent value with false, meaning it will - * draw as VML in prefer Html mode. - */ -mxActor.prototype.preferModeHtml = false; - -/** - * Variable: vmlScale - * - * Renders VML with a scale of 2. - */ -mxActor.prototype.vmlScale = 2; - -/** - * Function: createVml - * - * Creates and returns the VML node(s) to represent this shape. - */ -mxActor.prototype.createVml = function() -{ - var node = document.createElement('v:shape'); - node.style.position = 'absolute'; - this.configureVmlShape(node); - - return node; -}; - -/** - * Function: redrawVml - * - * Updates the VML node(s) to reflect the latest bounds and scale. - */ -mxActor.prototype.redrawVml = function() -{ - this.updateVmlShape(this.node); - this.node.path = this.createPath(); -}; - -/** - * Function: createSvg - * - * Creates and returns the SVG node(s) to represent this shape. - */ -mxActor.prototype.createSvg = function() -{ - return this.createSvgGroup('path'); -}; - -/** - * Function: redrawSvg - * - * Updates the SVG node(s) to reflect the latest bounds and scale. - */ -mxActor.prototype.redrawSvg = function() -{ - var strokeWidth = Math.round(Math.max(1, this.strokewidth * this.scale)); - this.innerNode.setAttribute('stroke-width', strokeWidth); - this.innerNode.setAttribute('stroke-linejoin', 'round'); - - if (this.crisp && (this.rotation == null || this.rotation == 0)) - { - this.innerNode.setAttribute('shape-rendering', 'crispEdges'); - } - else - { - this.innerNode.removeAttribute('shape-rendering'); - } - - var d = this.createPath(); - - if (d.length > 0) - { - this.innerNode.setAttribute('d', d); - - if (this.shadowNode != null) - { - this.shadowNode.setAttribute('transform', this.getSvgShadowTransform() + - (this.innerNode.getAttribute('transform') || '')); - this.shadowNode.setAttribute('stroke-width', strokeWidth); - this.shadowNode.setAttribute('d', d); - } - } - else - { - this.innerNode.removeAttribute('d'); - - if (this.shadowNode != null) - { - this.shadowNode.removeAttribute('d'); - } - } - - if (this.isDashed) - { - var phase = Math.max(1, Math.round(3 * this.scale * this.strokewidth)); - this.innerNode.setAttribute('stroke-dasharray', phase + ' ' + phase); - } -}; - -/** - * Function: redrawPath - * - * Draws the path for this shape. This method uses the <mxPath> - * abstraction to paint the shape for VML and SVG. - */ -mxActor.prototype.redrawPath = function(path, x, y, w, h) -{ - var width = w/3; - path.moveTo(0, h); - path.curveTo(0, 3 * h / 5, 0, 2 * h / 5, w / 2, 2 * h / 5); - path.curveTo(w / 2 - width, 2 * h / 5, w / 2 - width, 0, w / 2, 0); - path.curveTo(w / 2 + width, 0, w / 2 + width, 2 * h / 5, w / 2, 2 * h / 5); - path.curveTo(w, 2 * h / 5, w, 3 * h / 5, w, h); - path.close(); -}; diff --git a/src/js/shape/mxArrow.js b/src/js/shape/mxArrow.js deleted file mode 100644 index 93777d8..0000000 --- a/src/js/shape/mxArrow.js +++ /dev/null @@ -1,226 +0,0 @@ -/** - * $Id: mxArrow.js,v 1.31 2012-05-23 19:09:22 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -/** - * Class: mxArrow - * - * Extends <mxShape> to implement an arrow shape. (The shape - * is used to represent edges, not vertices.) - * This shape is registered under <mxConstants.SHAPE_ARROW> - * in <mxCellRenderer>. - * - * Constructor: mxArrow - * - * Constructs a new arrow shape. - * - * Parameters: - * - * points - Array of <mxPoints> that define the points. This is stored in - * <mxShape.points>. - * fill - String that defines the fill color. This is stored in <fill>. - * stroke - String that defines the stroke color. This is stored in <stroke>. - * strokewidth - Optional integer that defines the stroke width. Default is - * 1. This is stored in <strokewidth>. - * arrowWidth - Optional integer that defines the arrow width. Default is - * <mxConstants.ARROW_WIDTH>. This is stored in <arrowWidth>. - * spacing - Optional integer that defines the spacing between the arrow shape - * and its endpoints. Default is <mxConstants.ARROW_SPACING>. This is stored in - * <spacing>. - * endSize - Optional integer that defines the size of the arrowhead. Default - * is <mxConstants.ARROW_SIZE>. This is stored in <endSize>. - */ -function mxArrow(points, fill, stroke, strokewidth, arrowWidth, spacing, endSize) -{ - this.points = points; - this.fill = fill; - this.stroke = stroke; - this.strokewidth = (strokewidth != null) ? strokewidth : 1; - this.arrowWidth = (arrowWidth != null) ? arrowWidth : mxConstants.ARROW_WIDTH; - this.spacing = (spacing != null) ? spacing : mxConstants.ARROW_SPACING; - this.endSize = (endSize != null) ? endSize : mxConstants.ARROW_SIZE; -}; - -/** - * Extends <mxActor>. - */ -mxArrow.prototype = new mxActor(); -mxArrow.prototype.constructor = mxArrow; - -/** - * Variable: addPipe - * - * Specifies if a SVG path should be created around any path to increase the - * tolerance for mouse events. Default is false since this shape is filled. - */ -mxArrow.prototype.addPipe = false; - -/** - * Variable: enableFill - * - * Specifies if fill colors should be ignored. This must be set to true for - * shapes that are stroked only. Default is true since this shape is filled. - */ -mxArrow.prototype.enableFill = true; - -/** - * Function: configureTransparentBackground - * - * Overidden to remove transparent background. - */ -mxArrow.prototype.configureTransparentBackground = function(node) -{ - // do nothing -}; - -/** - * Function: updateBoundingBox - * - * Updates the <boundingBox> for this shape. - */ -mxArrow.prototype.augmentBoundingBox = function(bbox) -{ - // FIXME: Fix precision, share math and cache results with painting code - bbox.grow(Math.max(this.arrowWidth / 2, this.endSize / 2) * this.scale); - - mxShape.prototype.augmentBoundingBox.apply(this, arguments); -}; - -/** - * Function: createVml - * - * Extends <mxShape.createVml> to ignore fill if <enableFill> is false. - */ -mxArrow.prototype.createVml = function() -{ - if (!this.enableFill) - { - this.fill = null; - } - - return mxActor.prototype.createVml.apply(this, arguments); -}; - -/** - * Function: createSvg - * - * Extends <mxActor.createSvg> to ignore fill if <enableFill> is false and - * create an event handling shape if <this.addPipe> is true. - */ -mxArrow.prototype.createSvg = function() -{ - if (!this.enableFill) - { - this.fill = null; - } - - var g = mxActor.prototype.createSvg.apply(this, arguments); - - // Creates an invisible shape around the path for easier - // selection with the mouse. Note: Firefox does not ignore - // the value of the stroke attribute for pointer-events: stroke, - // it does, however, ignore the visibility attribute. - if (this.addPipe) - { - this.pipe = this.createSvgPipe(); - g.appendChild(this.pipe); - } - - return g; -}; - -/** - * Function: reconfigure - * - * Extends <mxActor.reconfigure> to ignore fill if <enableFill> is false. - */ -mxArrow.prototype.reconfigure = function() -{ - if (!this.enableFill) - { - this.fill = null; - } - - mxActor.prototype.reconfigure.apply(this, arguments); -}; - -/** - * Function: redrawSvg - * - * Extends <mxActor.redrawSvg> to update the event handling shape if one - * exists. - */ -mxArrow.prototype.redrawSvg = function() -{ - mxActor.prototype.redrawSvg.apply(this, arguments); - - if (this.pipe != null) - { - var d = this.innerNode.getAttribute('d'); - - if (d != null) - { - this.pipe.setAttribute('d', this.innerNode.getAttribute('d')); - var strokeWidth = Math.round(this.strokewidth * this.scale); - this.pipe.setAttribute('stroke-width', strokeWidth + mxShape.prototype.SVG_STROKE_TOLERANCE); - } - } -}; - -/** - * Function: redrawPath - * - * Draws the path for this shape. This method uses the <mxPath> - * abstraction to paint the shape for VML and SVG. - */ -mxArrow.prototype.redrawPath = function(path, x, y, w, h) -{ - // All points are offset - path.translate.x -= x; - path.translate.y -= y; - - // Geometry of arrow - var spacing = this.spacing * this.scale; - var width = this.arrowWidth * this.scale; - var arrow = this.endSize * this.scale; - - // Base vector (between end points) - var p0 = this.points[0]; - var pe = this.points[this.points.length - 1]; - - var dx = pe.x - p0.x; - var dy = pe.y - p0.y; - var dist = Math.sqrt(dx * dx + dy * dy); - var length = dist - 2 * spacing - arrow; - - // Computes the norm and the inverse norm - var nx = dx / dist; - var ny = dy / dist; - var basex = length * nx; - var basey = length * ny; - var floorx = width * ny/3; - var floory = -width * nx/3; - - // Computes points - var p0x = p0.x - floorx / 2 + spacing * nx; - var p0y = p0.y - floory / 2 + spacing * ny; - var p1x = p0x + floorx; - var p1y = p0y + floory; - var p2x = p1x + basex; - var p2y = p1y + basey; - var p3x = p2x + floorx; - var p3y = p2y + floory; - // p4 not necessary - var p5x = p3x - 3 * floorx; - var p5y = p3y - 3 * floory; - - path.moveTo(p0x, p0y); - path.lineTo(p1x, p1y); - path.lineTo(p2x, p2y); - path.lineTo(p3x, p3y); - path.lineTo(pe.x - spacing * nx, pe.y - spacing * ny); - path.lineTo(p5x, p5y); - path.lineTo(p5x + floorx, p5y + floory); - path.lineTo(p0x, p0y); - path.close(); -}; diff --git a/src/js/shape/mxCloud.js b/src/js/shape/mxCloud.js deleted file mode 100644 index 3893a1b..0000000 --- a/src/js/shape/mxCloud.js +++ /dev/null @@ -1,56 +0,0 @@ -/** - * $Id: mxCloud.js,v 1.12 2011-06-24 11:27:30 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -/** - * Class: mxCloud - * - * Extends <mxActor> to implement a cloud shape. - * - * This shape is registered under <mxConstants.SHAPE_CLOUD> in - * <mxCellRenderer>. - * - * Constructor: mxCloud - * - * Constructs a new cloud shape. - * - * Parameters: - * - * bounds - <mxRectangle> that defines the bounds. This is stored in - * <mxShape.bounds>. - * fill - String that defines the fill color. This is stored in <fill>. - * stroke - String that defines the stroke color. This is stored in <stroke>. - * strokewidth - Optional integer that defines the stroke width. Default is - * 1. This is stored in <strokewidth>. - */ -function mxCloud(bounds, fill, stroke, strokewidth) -{ - this.bounds = bounds; - this.fill = fill; - this.stroke = stroke; - this.strokewidth = (strokewidth != null) ? strokewidth : 1; -}; - -/** - * Extends mxActor. - */ -mxCloud.prototype = new mxActor(); -mxCloud.prototype.constructor = mxActor; - -/** - * Function: redrawPath - * - * Draws the path for this shape. This method uses the <mxPath> - * abstraction to paint the shape for VML and SVG. - */ -mxCloud.prototype.redrawPath = function(path, x, y, w, h) -{ - path.moveTo(0.25 * w, 0.25 * h); - path.curveTo(0.05 * w, 0.25 * h, 0, 0.5 * h, 0.16 * w, 0.55 * h); - path.curveTo(0, 0.66 * h, 0.18 * w, 0.9 * h, 0.31 * w, 0.8 * h); - path.curveTo(0.4 * w, h, 0.7 * w, h, 0.8 * w, 0.8 * h); - path.curveTo(w, 0.8 * h, w, 0.6 * h, 0.875 * w, 0.5 * h); - path.curveTo(w, 0.3 * h, 0.8 * w, 0.1 * h, 0.625 * w, 0.2 * h); - path.curveTo(0.5 * w, 0.05 * h, 0.3 * w, 0.05 * h, 0.25 * w, 0.25 * h); - path.close(); -}; diff --git a/src/js/shape/mxConnector.js b/src/js/shape/mxConnector.js deleted file mode 100644 index 092bf79..0000000 --- a/src/js/shape/mxConnector.js +++ /dev/null @@ -1,446 +0,0 @@ -/** - * $Id: mxConnector.js,v 1.80 2012-05-24 12:00:45 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -/** - * Class: mxConnector - * - * Extends <mxShape> to implement a connector shape. The connector - * shape allows for arrow heads on either side. - * - * This shape is registered under <mxConstants.SHAPE_CONNECTOR> in - * <mxCellRenderer>. - * - * Constructor: mxConnector - * - * Constructs a new connector shape. - * - * Parameters: - * - * points - Array of <mxPoints> that define the points. This is stored in - * <mxShape.points>. - * stroke - String that defines the stroke color. This is stored in <stroke>. - * Default is 'black'. - * strokewidth - Optional integer that defines the stroke width. Default is - * 1. This is stored in <strokewidth>. - */ -function mxConnector(points, stroke, strokewidth) -{ - this.points = points; - this.stroke = stroke; - this.strokewidth = (strokewidth != null) ? strokewidth : 1; -}; - -/** - * Extends mxShape. - */ -mxConnector.prototype = new mxShape(); -mxConnector.prototype.constructor = mxConnector; - -/** - * Variable: vmlNodes - * - * Adds local references to <mxShape.vmlNodes>. - */ -mxConnector.prototype.vmlNodes = mxConnector.prototype.vmlNodes.concat([ - 'shapeNode', 'start', 'end', 'startStroke', 'endStroke', 'startFill', 'endFill']); - -/** - * Variable: mixedModeHtml - * - * Overrides the parent value with false, meaning it will - * draw in VML in mixed Html mode. - */ -mxConnector.prototype.mixedModeHtml = false; - -/** - * Variable: preferModeHtml - * - * Overrides the parent value with false, meaning it will - * draw as VML in prefer Html mode. - */ -mxConnector.prototype.preferModeHtml = false; - -/** - * Variable: allowCrispMarkers - * - * Specifies if <mxShape.crisp> should be allowed for markers. Default is false. - */ -mxConnector.prototype.allowCrispMarkers = false; - -/** - * Variable: addPipe - * - * Specifies if a SVG path should be created around any path to increase the - * tolerance for mouse events. Default is false since this shape is filled. - */ -mxConnector.prototype.addPipe = true; - -/** - * Function: configureHtmlShape - * - * Overrides <mxShape.configureHtmlShape> to clear the border and background. - */ -mxConnector.prototype.configureHtmlShape = function(node) -{ - mxShape.prototype.configureHtmlShape.apply(this, arguments); - node.style.borderStyle = ''; - node.style.background = ''; -}; - -/** - * Function: createVml - * - * Creates and returns the VML node to represent this shape. - */ -mxConnector.prototype.createVml = function() -{ - var node = document.createElement('v:group'); - node.style.position = 'absolute'; - this.shapeNode = document.createElement('v:shape'); - this.updateVmlStrokeColor(this.shapeNode); - this.updateVmlStrokeNode(this.shapeNode); - node.appendChild(this.shapeNode); - this.shapeNode.filled = 'false'; - - if (this.isShadow) - { - this.createVmlShadow(this.shapeNode); - } - - // Creates the start arrow as an additional child path - if (this.startArrow != null) - { - this.start = document.createElement('v:shape'); - this.start.style.position = 'absolute'; - - // Only required for opacity and joinstyle - this.startStroke = document.createElement('v:stroke'); - this.startStroke.joinstyle = 'miter'; - this.start.appendChild(this.startStroke); - - this.startFill = document.createElement('v:fill'); - this.start.appendChild(this.startFill); - - node.appendChild(this.start); - } - - // Creates the end arrows as an additional child path - if (this.endArrow != null) - { - this.end = document.createElement('v:shape'); - this.end.style.position = 'absolute'; - - // Only required for opacity and joinstyle - this.endStroke = document.createElement('v:stroke'); - this.endStroke.joinstyle = 'miter'; - this.end.appendChild(this.endStroke); - - this.endFill = document.createElement('v:fill'); - this.end.appendChild(this.endFill); - - node.appendChild(this.end); - } - - this.updateVmlMarkerOpacity(); - - return node; -}; - -/** - * Function: updateVmlMarkerOpacity - * - * Updates the opacity for the markers in VML. - */ -mxConnector.prototype.updateVmlMarkerOpacity = function() -{ - var op = (this.opacity != null) ? (this.opacity + '%') : '100%'; - - if (this.start != null) - { - this.startFill.opacity = op; - this.startStroke.opacity = op; - } - - if (this.end != null) - { - this.endFill.opacity = op; - this.endStroke.opacity = op; - } -}; - -/** - * Function: redrawVml - * - * Redraws this VML shape by invoking <updateVmlShape> on this.node. - */ -mxConnector.prototype.reconfigure = function() -{ - // Never fill a connector - this.fill = null; - - if (mxUtils.isVml(this.node)) - { - // Updates the style of the given shape - // LATER: Check if this can be replaced with redrawVml and - // updating the color, dash pattern and shadow. - this.node.style.visibility = 'hidden'; - this.configureVmlShape(this.shapeNode); - this.updateVmlMarkerOpacity(); - this.node.style.visibility = 'visible'; - } - else - { - mxShape.prototype.reconfigure.apply(this, arguments); - } -}; - -/** - * Function: redrawVml - * - * Redraws this VML shape by invoking <updateVmlShape> on this.node. - */ -mxConnector.prototype.redrawVml = function() -{ - if (this.node != null && this.points != null && this.bounds != null && - !isNaN(this.bounds.x) && !isNaN(this.bounds.y) && - !isNaN(this.bounds.width) && !isNaN(this.bounds.height)) - { - var w = Math.max(0, Math.round(this.bounds.width)); - var h = Math.max(0, Math.round(this.bounds.height)); - var cs = w + ',' + h; - w += 'px'; - h += 'px'; - - // Computes the marker paths before the main path is updated so - // that offsets can be taken into account - if (this.start != null) - { - this.start.style.width = w; - this.start.style.height = h; - this.start.coordsize = cs; - - var p0 = this.points[1]; - var pe = this.points[0]; - - var size = mxUtils.getNumber(this.style, mxConstants.STYLE_STARTSIZE, mxConstants.DEFAULT_MARKERSIZE); - this.startOffset = this.redrawMarker(this.start, this.startArrow, p0, pe, this.stroke, size); - } - - if (this.end != null) - { - this.end.style.width = w; - this.end.style.height = h; - this.end.coordsize = cs; - - var n = this.points.length; - var p0 = this.points[n - 2]; - var pe = this.points[n - 1]; - - var size = mxUtils.getNumber(this.style, mxConstants.STYLE_ENDSIZE, mxConstants.DEFAULT_MARKERSIZE); - this.endOffset = this.redrawMarker(this.end, this.endArrow, p0, pe, this.stroke, size); - } - - this.updateVmlShape(this.node); - this.updateVmlShape(this.shapeNode); - this.shapeNode.filled = 'false'; - - // Adds custom dash pattern - if (this.isDashed) - { - var pat = mxUtils.getValue(this.style, 'dashStyle', null); - - if (pat != null) - { - this.strokeNode.dashstyle = pat; - } - - if (this.shadowStrokeNode != null) - { - this.shadowStrokeNode.dashstyle = this.strokeNode.dashstyle; - } - } - } -}; - -/** - * Function: createSvg - * - * Creates and returns the SVG node to represent this shape. - */ -mxConnector.prototype.createSvg = function() -{ - this.fill = null; - var g = this.createSvgGroup('path'); - - // Creates the start arrow as an additional child path - if (this.startArrow != null) - { - this.start = document.createElementNS(mxConstants.NS_SVG, 'path'); - g.appendChild(this.start); - } - - // Creates the end arrows as an additional child path - if (this.endArrow != null) - { - this.end = document.createElementNS(mxConstants.NS_SVG, 'path'); - g.appendChild(this.end); - } - - // Creates an invisible shape around the path for easier - // selection with the mouse. Note: Firefox does not ignore - // the value of the stroke attribute for pointer-events: stroke, - // it does, however, ignore the visibility attribute. - if (this.addPipe) - { - this.pipe = this.createSvgPipe(); - g.appendChild(this.pipe); - } - - return g; -}; - -/** - * Function: redrawSvg - * - * Updates the SVG node(s) to reflect the latest bounds and scale. - */ -mxConnector.prototype.redrawSvg = function() -{ - // Computes the markers first which modifies the coordinates of the - // endpoints to not overlap with the painted marker then updates the actual - // shape for the edge to take the modified endpoints into account. - if (this.points != null && this.points[0] != null) - { - var color = this.innerNode.getAttribute('stroke'); - - // Draws the start marker - if (this.start != null) - { - var p0 = this.points[1]; - var pe = this.points[0]; - - var size = mxUtils.getNumber(this.style, mxConstants.STYLE_STARTSIZE, - mxConstants.DEFAULT_MARKERSIZE); - this.startOffset = this.redrawMarker(this.start, - this.startArrow, p0, pe, color, size); - - if (this.allowCrispMarkers && this.crisp) - { - this.start.setAttribute('shape-rendering', 'crispEdges'); - } - else - { - this.start.removeAttribute('shape-rendering'); - } - } - - // Draws the end marker - if (this.end != null) - { - var n = this.points.length; - - var p0 = this.points[n - 2]; - var pe = this.points[n - 1]; - - var size = mxUtils.getNumber(this.style, mxConstants.STYLE_ENDSIZE, - mxConstants.DEFAULT_MARKERSIZE); - this.endOffset = this.redrawMarker(this.end, - this.endArrow, p0, pe, color, size); - - if (this.allowCrispMarkers && this.crisp) - { - this.end.setAttribute('shape-rendering', 'crispEdges'); - } - else - { - this.end.removeAttribute('shape-rendering'); - } - } - } - - this.updateSvgShape(this.innerNode); - var d = this.innerNode.getAttribute('d'); - - if (d != null) - { - var strokeWidth = Math.round(this.strokewidth * this.scale); - - // Updates the tolerance of the invisible shape for event handling - if (this.pipe != null) - { - this.pipe.setAttribute('d', this.innerNode.getAttribute('d')); - this.pipe.setAttribute('stroke-width', strokeWidth + mxShape.prototype.SVG_STROKE_TOLERANCE); - } - - // Updates the shadow - if (this.shadowNode != null) - { - this.shadowNode.setAttribute('transform', this.getSvgShadowTransform()); - this.shadowNode.setAttribute('d', d); - this.shadowNode.setAttribute('stroke-width', strokeWidth); - } - } - - // Adds custom dash pattern - if (this.isDashed) - { - var pat = this.createDashPattern(this.scale * this.strokewidth); - - if (pat != null) - { - this.innerNode.setAttribute('stroke-dasharray', pat); - } - } - - // Updates the shadow - if (this.shadowNode != null) - { - var pat = this.innerNode.getAttribute('stroke-dasharray'); - - if (pat != null) - { - this.shadowNode.setAttribute('stroke-dasharray', pat); - } - } -}; - -/** - * Function: createDashPattern - * - * Creates a dash pattern for the given factor. - */ -mxConnector.prototype.createDashPattern = function(factor) -{ - var value = mxUtils.getValue(this.style, 'dashPattern', null); - - if (value != null) - { - var tmp = value.split(' '); - var pat = []; - - for (var i = 0; i < tmp.length; i++) - { - if (tmp[i].length > 0) - { - pat.push(Math.round(Number(tmp[i]) * factor)); - } - } - - return pat.join(' '); - } - - return null; -}; - -/** - * Function: redrawMarker - * - * Updates the given SVG or VML marker. - */ -mxConnector.prototype.redrawMarker = function(node, type, p0, pe, color, size) -{ - return mxMarker.paintMarker(node, type, p0, pe, color, this.strokewidth, - size, this.scale, this.bounds.x, this.bounds.y, this.start == node, - this.style); -}; diff --git a/src/js/shape/mxCylinder.js b/src/js/shape/mxCylinder.js deleted file mode 100644 index 9a45760..0000000 --- a/src/js/shape/mxCylinder.js +++ /dev/null @@ -1,319 +0,0 @@ -/** - * $Id: mxCylinder.js,v 1.38 2012-07-31 11:46:53 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -/** - * Class: mxCylinder - * - * Extends <mxShape> to implement an cylinder shape. If a - * custom shape with one filled area and an overlay path is - * needed, then this shape's <redrawPath> should be overridden. - * This shape is registered under <mxConstants.SHAPE_CYLINDER> - * in <mxCellRenderer>. - * - * Constructor: mxCylinder - * - * Constructs a new cylinder shape. - * - * Parameters: - * - * bounds - <mxRectangle> that defines the bounds. This is stored in - * <mxShape.bounds>. - * fill - String that defines the fill color. This is stored in <fill>. - * stroke - String that defines the stroke color. This is stored in <stroke>. - * strokewidth - Optional integer that defines the stroke width. Default is - * 1. This is stored in <strokewidth>. - */ -function mxCylinder(bounds, fill, stroke, strokewidth) -{ - this.bounds = bounds; - this.fill = fill; - this.stroke = stroke; - this.strokewidth = (strokewidth != null) ? strokewidth : 1; -}; - -/** - * Extends mxShape. - */ -mxCylinder.prototype = new mxShape(); -mxCylinder.prototype.constructor = mxCylinder; - -/** - * Variable: vmlNodes - * - * Adds local references to <mxShape.vmlNodes>. - */ -mxCylinder.prototype.vmlNodes = mxCylinder.prototype.vmlNodes.concat(['background', 'foreground']); - -/** - * Variable: mixedModeHtml - * - * Overrides the parent value with false, meaning it will - * draw in VML in mixed Html mode. - */ -mxCylinder.prototype.mixedModeHtml = false; - -/** - * Variable: preferModeHtml - * - * Overrides the parent value with false, meaning it will - * draw as VML in prefer Html mode. - */ -mxCylinder.prototype.preferModeHtml = false; - -/** - * Variable: addPipe - * - * Specifies if a SVG path should be created around the background for better - * hit detection. Default is false. - */ -mxCylinder.prototype.addPipe = false; - -/** - * Variable: strokedBackground - * - * Specifies if the background should be stroked. Default is true. - */ -mxCylinder.prototype.strokedBackground = true; - -/** - * Variable: maxHeight - * - * Defines the maximum height of the top and bottom part - * of the cylinder shape. - */ -mxCylinder.prototype.maxHeight = 40; - -/** - * Variable: vmlScale - * - * Renders VML with a scale of 2. - */ -mxCylinder.prototype.vmlScale = 2; - -/** - * Function: create - * - * Overrides the method to make sure the <stroke> is never - * null. If it is null is will be assigned the <fill> color. - */ -mxCylinder.prototype.create = function(container) -{ - if (this.stroke == null) - { - this.stroke = this.fill; - } - - // Calls superclass implementation of create - return mxShape.prototype.create.apply(this, arguments); -}; - -/** - * Function: reconfigure - * - * Overrides the method to make sure the <stroke> is applied to the foreground. - */ -mxCylinder.prototype.reconfigure = function() -{ - if (this.dialect == mxConstants.DIALECT_SVG) - { - this.configureSvgShape(this.foreground); - this.foreground.setAttribute('fill', 'none'); - } - else if (mxUtils.isVml(this.node)) - { - this.configureVmlShape(this.background); - this.configureVmlShape(this.foreground); - } - - mxShape.prototype.reconfigure.apply(this); -}; - -/** - * Function: createVml - * - * Creates and returns the VML node to represent this shape. - */ -mxCylinder.prototype.createVml = function() -{ - var node = document.createElement('v:group'); - - // Draws the background - this.background = document.createElement('v:shape'); - this.label = this.background; - this.configureVmlShape(this.background); - node.appendChild(this.background); - - // Ignores values that only apply to the background - this.fill = null; - this.isShadow = false; - this.configureVmlShape(node); - - // Draws the foreground - this.foreground = document.createElement('v:shape'); - this.configureVmlShape(this.foreground); - - // To match SVG defaults jointsyle miter, miterlimit 4 - this.fgStrokeNode = document.createElement('v:stroke'); - this.fgStrokeNode.joinstyle = 'miter'; - this.fgStrokeNode.miterlimit = 4; - this.foreground.appendChild(this.fgStrokeNode); - - node.appendChild(this.foreground); - - return node; -}; - -/** - * Function: redrawVml - * - * Updates the VML node(s) to reflect the latest bounds and scale. - */ -mxCylinder.prototype.redrawVml = function() -{ - this.updateVmlShape(this.node); - this.updateVmlShape(this.background); - this.updateVmlShape(this.foreground); - this.background.path = this.createPath(false); - this.foreground.path = this.createPath(true); - - this.fgStrokeNode.dashstyle = this.strokeNode.dashstyle; -}; - -/** - * Function: createSvg - * - * Creates and returns the SVG node(s) to represent this shape. - */ -mxCylinder.prototype.createSvg = function() -{ - var g = this.createSvgGroup('path'); - this.foreground = document.createElementNS(mxConstants.NS_SVG, 'path'); - - if (this.stroke != null && this.stroke != mxConstants.NONE) - { - this.foreground.setAttribute('stroke', this.stroke); - } - else - { - this.foreground.setAttribute('stroke', 'none'); - } - - this.foreground.setAttribute('fill', 'none'); - g.appendChild(this.foreground); - - if (this.addPipe) - { - this.pipe = this.createSvgPipe(); - g.appendChild(this.pipe); - } - - return g; -}; - -/** - * Function: redrawSvg - * - * Updates the SVG node(s) to reflect the latest bounds and scale. - */ -mxCylinder.prototype.redrawSvg = function() -{ - var strokeWidth = Math.round(Math.max(1, this.strokewidth * this.scale)); - this.innerNode.setAttribute('stroke-width', strokeWidth); - - if (this.crisp && (this.rotation == null || this.rotation == 0)) - { - this.innerNode.setAttribute('shape-rendering', 'crispEdges'); - this.foreground.setAttribute('shape-rendering', 'crispEdges'); - } - else - { - this.innerNode.removeAttribute('shape-rendering'); - this.foreground.removeAttribute('shape-rendering'); - } - - // Paints background - var d = this.createPath(false); - - if (d.length > 0) - { - this.innerNode.setAttribute('d', d); - - // Updates event handling element - if (this.pipe != null) - { - this.pipe.setAttribute('d', d); - this.pipe.setAttribute('stroke-width', strokeWidth + mxShape.prototype.SVG_STROKE_TOLERANCE); - this.pipe.setAttribute('transform', (this.innerNode.getAttribute('transform') || '')); - } - } - else - { - this.innerNode.removeAttribute('d'); - - // Updates event handling element - if (this.pipe != null) - { - this.pipe.removeAttribute('d'); - } - } - - // Stroked background - if (!this.strokedBackground) - { - this.innerNode.setAttribute('stroke', 'none'); - } - - // Paints shadow - if (this.shadowNode != null) - { - this.shadowNode.setAttribute('stroke-width', strokeWidth); - this.shadowNode.setAttribute('d', d); - this.shadowNode.setAttribute('transform', this.getSvgShadowTransform()); - } - - // Paints foreground - d = this.createPath(true); - - if (d.length > 0) - { - this.foreground.setAttribute('stroke-width', strokeWidth); - this.foreground.setAttribute('d', d); - } - else - { - this.foreground.removeAttribute('d'); - } - - if (this.isDashed) - { - var phase = Math.max(1, Math.round(3 * this.scale * this.strokewidth)); - this.innerNode.setAttribute('stroke-dasharray', phase + ' ' + phase); - this.foreground.setAttribute('stroke-dasharray', phase + ' ' + phase); - } -}; - -/** - * Function: redrawPath - * - * Draws the path for this shape. This method uses the <mxPath> - * abstraction to paint the shape for VML and SVG. - */ -mxCylinder.prototype.redrawPath = function(path, x, y, w, h, isForeground) -{ - var dy = Math.min(this.maxHeight, Math.round(h / 5)); - - if (isForeground) - { - path.moveTo(0, dy); - path.curveTo(0, 2 * dy, w, 2 * dy, w, dy); - } - else - { - path.moveTo(0, dy); - path.curveTo(0, -dy / 3, w, -dy / 3, w, dy); - path.lineTo(w, h - dy); - path.curveTo(w, h + dy / 3, 0, h + dy / 3, 0, h - dy); - path.close(); - } -}; diff --git a/src/js/shape/mxDoubleEllipse.js b/src/js/shape/mxDoubleEllipse.js deleted file mode 100644 index 7854851..0000000 --- a/src/js/shape/mxDoubleEllipse.js +++ /dev/null @@ -1,203 +0,0 @@ -/** - * $Id: mxDoubleEllipse.js,v 1.19 2012-05-21 18:27:17 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -/** - * Class: mxDoubleEllipse - * - * Extends <mxShape> to implement a double ellipse shape. - * This shape is registered under <mxConstants.SHAPE_DOUBLE_ELLIPSE> - * in <mxCellRenderer>. - * - * Constructor: mxDoubleEllipse - * - * Constructs a new ellipse shape. - * - * Parameters: - * - * bounds - <mxRectangle> that defines the bounds. This is stored in - * <mxShape.bounds>. - * fill - String that defines the fill color. This is stored in <fill>. - * stroke - String that defines the stroke color. This is stored in <stroke>. - * strokewidth - Optional integer that defines the stroke width. Default is - * 1. This is stored in <strokewidth>. - */ -function mxDoubleEllipse(bounds, fill, stroke, strokewidth) -{ - this.bounds = bounds; - this.fill = fill; - this.stroke = stroke; - this.strokewidth = (strokewidth != null) ? strokewidth : 1; -}; - -/** - * Extends mxShape. - */ -mxDoubleEllipse.prototype = new mxShape(); -mxDoubleEllipse.prototype.constructor = mxDoubleEllipse; - -/** - * Variable: vmlNodes - * - * Adds local references to <mxShape.vmlNodes>. - */ -mxDoubleEllipse.prototype.vmlNodes = mxDoubleEllipse.prototype.vmlNodes.concat(['background', 'foreground']); - -/** - * Variable: mixedModeHtml - * - * Overrides the parent value with false, meaning it will - * draw in VML in mixed Html mode. - */ -mxDoubleEllipse.prototype.mixedModeHtml = false; - -/** - * Variable: preferModeHtml - * - * Overrides the parent value with false, meaning it will - * draw as VML in prefer Html mode. - */ -mxDoubleEllipse.prototype.preferModeHtml = false; - -/** - * Variable: vmlScale - * - * Renders VML with a scale of 2. - */ -mxDoubleEllipse.prototype.vmlScale = 2; - -/** - * Function: createVml - * - * Creates and returns the VML node to represent this shape. - */ -mxDoubleEllipse.prototype.createVml = function() -{ - var node = document.createElement('v:group'); - - // Draws the background - this.background = document.createElement('v:arc'); - this.background.startangle = '0'; - this.background.endangle = '360'; - this.configureVmlShape(this.background); - - node.appendChild(this.background); - - // Ignores values that only apply to the background - this.label = this.background; - this.isShadow = false; - this.fill = null; - - // Draws the foreground - this.foreground = document.createElement('v:oval'); - this.configureVmlShape(this.foreground); - - node.appendChild(this.foreground); - - this.stroke = null; - this.configureVmlShape(node); - - return node; -}; - -/** - * Function: redrawVml - * - * Updates the VML node(s) to reflect the latest bounds and scale. - */ -mxDoubleEllipse.prototype.redrawVml = function() -{ - this.updateVmlShape(this.node); - this.updateVmlShape(this.background); - this.updateVmlShape(this.foreground); - - var inset = Math.round((this.strokewidth + 3) * this.scale) * this.vmlScale; - var w = Math.round(this.bounds.width * this.vmlScale); - var h = Math.round(this.bounds.height * this.vmlScale); - - this.foreground.style.top = inset + 'px'; // relative - this.foreground.style.left = inset + 'px'; // relative - this.foreground.style.width = Math.max(0, w - 2 * inset) + 'px'; - this.foreground.style.height = Math.max(0, h - 2 * inset) + 'px'; -}; - -/** - * Function: createSvg - * - * Creates and returns the SVG node(s) to represent this shape. - */ -mxDoubleEllipse.prototype.createSvg = function() -{ - var g = this.createSvgGroup('ellipse'); - this.foreground = document.createElementNS(mxConstants.NS_SVG, 'ellipse'); - - if (this.stroke != null) - { - this.foreground.setAttribute('stroke', this.stroke); - } - else - { - this.foreground.setAttribute('stroke', 'none'); - } - - this.foreground.setAttribute('fill', 'none'); - g.appendChild(this.foreground); - - return g; -}; - -/** - * Function: redrawSvg - * - * Updates the SVG node(s) to reflect the latest bounds and scale. - */ -mxDoubleEllipse.prototype.redrawSvg = function() -{ - if (this.crisp) - { - this.innerNode.setAttribute('shape-rendering', 'crispEdges'); - this.foreground.setAttribute('shape-rendering', 'crispEdges'); - } - else - { - this.innerNode.removeAttribute('shape-rendering'); - this.foreground.removeAttribute('shape-rendering'); - } - - this.updateSvgNode(this.innerNode); - this.updateSvgNode(this.shadowNode); - this.updateSvgNode(this.foreground, (this.strokewidth + 3) * this.scale); - - if (this.isDashed) - { - var phase = Math.max(1, Math.round(3 * this.scale * this.strokewidth)); - this.innerNode.setAttribute('stroke-dasharray', phase + ' ' + phase); - } -}; - -/** - * Function: updateSvgNode - * - * Updates the given node to reflect the new <bounds> and <scale>. - */ -mxDoubleEllipse.prototype.updateSvgNode = function(node, inset) -{ - inset = (inset != null) ? inset : 0; - - if (node != null) - { - var strokeWidth = Math.round(Math.max(1, this.strokewidth * this.scale)); - node.setAttribute('stroke-width', strokeWidth); - - node.setAttribute('cx', this.bounds.x + this.bounds.width / 2); - node.setAttribute('cy', this.bounds.y + this.bounds.height / 2); - node.setAttribute('rx', Math.max(0, this.bounds.width / 2 - inset)); - node.setAttribute('ry', Math.max(0, this.bounds.height / 2 - inset)); - - // Updates the transform of the shadow - if (this.shadowNode != null) - { - this.shadowNode.setAttribute('transform', this.getSvgShadowTransform()); - } - } -}; diff --git a/src/js/shape/mxEllipse.js b/src/js/shape/mxEllipse.js deleted file mode 100644 index f3882cf..0000000 --- a/src/js/shape/mxEllipse.js +++ /dev/null @@ -1,132 +0,0 @@ -/** - * $Id: mxEllipse.js,v 1.20 2012-04-04 07:34:50 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -/** - * Class: mxEllipse - * - * Extends <mxShape> to implement an ellipse shape. - * This shape is registered under <mxConstants.SHAPE_ELLIPSE> - * in <mxCellRenderer>. - * - * Constructor: mxEllipse - * - * Constructs a new ellipse shape. - * - * Parameters: - * - * bounds - <mxRectangle> that defines the bounds. This is stored in - * <mxShape.bounds>. - * fill - String that defines the fill color. This is stored in <fill>. - * stroke - String that defines the stroke color. This is stored in <stroke>. - * strokewidth - Optional integer that defines the stroke width. Default is - * 1. This is stored in <strokewidth>. - */ -function mxEllipse(bounds, fill, stroke, strokewidth) -{ - this.bounds = bounds; - this.fill = fill; - this.stroke = stroke; - this.strokewidth = (strokewidth != null) ? strokewidth : 1; -}; - -/** - * Extends mxShape. - */ -mxEllipse.prototype = new mxShape(); -mxEllipse.prototype.constructor = mxEllipse; - -/** - * Variable: mixedModeHtml - * - * Overrides the parent value with false, meaning it will - * draw in VML in mixed Html mode. - */ -mxEllipse.prototype.mixedModeHtml = false; - -/** - * Variable: preferModeHtml - * - * Overrides the parent value with false, meaning it will - * draw as VML in prefer Html mode. - */ -mxEllipse.prototype.preferModeHtml = false; - -/** - * Function: createVml - * - * Creates and returns the VML node to represent this shape. - */ -mxEllipse.prototype.createVml = function() -{ - // Uses an arc not an oval to make sure the - // textbox fills out the outer bounds of the - // circle, not just the inner rectangle - var node = document.createElement('v:arc'); - node.startangle = '0'; - node.endangle = '360'; - this.configureVmlShape(node); - - return node; -}; - -/** - * Function: createSvg - * - * Creates and returns the SVG node(s) to represent this shape. - */ -mxEllipse.prototype.createSvg = function() -{ - return this.createSvgGroup('ellipse'); -}; - -/** - * Function: redrawSvg - * - * Updates the SVG node(s) to reflect the latest bounds and scale. - */ -mxEllipse.prototype.redrawSvg = function() -{ - if (this.crisp) - { - this.innerNode.setAttribute('shape-rendering', 'crispEdges'); - } - else - { - this.innerNode.removeAttribute('shape-rendering'); - } - - this.updateSvgNode(this.innerNode); - this.updateSvgNode(this.shadowNode); -}; - -/** - * Function: updateSvgNode - * - * Updates the given node to reflect the new <bounds> and <scale>. - */ -mxEllipse.prototype.updateSvgNode = function(node) -{ - if (node != null) - { - var strokeWidth = Math.round(Math.max(1, this.strokewidth * this.scale)); - node.setAttribute('stroke-width', strokeWidth); - - node.setAttribute('cx', this.bounds.x + this.bounds.width / 2); - node.setAttribute('cy', this.bounds.y + this.bounds.height / 2); - node.setAttribute('rx', this.bounds.width / 2); - node.setAttribute('ry', this.bounds.height / 2); - - // Updates the shadow offset - if (this.shadowNode != null) - { - this.shadowNode.setAttribute('transform', this.getSvgShadowTransform()); - } - - if (this.isDashed) - { - var phase = Math.max(1, Math.round(3 * this.scale * this.strokewidth)); - node.setAttribute('stroke-dasharray', phase + ' ' + phase); - } - } -}; diff --git a/src/js/shape/mxHexagon.js b/src/js/shape/mxHexagon.js deleted file mode 100644 index 7fa45a3..0000000 --- a/src/js/shape/mxHexagon.js +++ /dev/null @@ -1,37 +0,0 @@ -/** - * $Id: mxHexagon.js,v 1.8 2011-09-02 10:01:00 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -/** - * Class: mxHexagon - * - * Implementation of the hexagon shape. - * - * Constructor: mxHexagon - * - * Constructs a new hexagon shape. - */ -function mxHexagon() { }; - -/** - * Extends <mxActor>. - */ -mxHexagon.prototype = new mxActor(); -mxHexagon.prototype.constructor = mxHexagon; - -/** - * Function: redrawPath - * - * Draws the path for this shape. This method uses the <mxPath> - * abstraction to paint the shape for VML and SVG. - */ -mxHexagon.prototype.redrawPath = function(path, x, y, w, h) -{ - path.moveTo(0.25 * w, 0); - path.lineTo(0.75 * w, 0); - path.lineTo(w, 0.5 * h); - path.lineTo(0.75 * w, h); - path.lineTo(0.25 * w, h); - path.lineTo(0, 0.5 * h); - path.close(); -}; diff --git a/src/js/shape/mxImageShape.js b/src/js/shape/mxImageShape.js deleted file mode 100644 index 2f1eab0..0000000 --- a/src/js/shape/mxImageShape.js +++ /dev/null @@ -1,405 +0,0 @@ -/** - * $Id: mxImageShape.js,v 1.67 2012-04-22 10:16:23 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -/** - * Class: mxImageShape - * - * Extends <mxShape> to implement an image shape. This shape is registered - * under <mxConstants.SHAPE_IMAGE> in <mxCellRenderer>. - * - * Constructor: mxImageShape - * - * Constructs a new image shape. - * - * Parameters: - * - * bounds - <mxRectangle> that defines the bounds. This is stored in - * <mxShape.bounds>. - * image - String that specifies the URL of the image. This is stored in - * <image>. - * fill - String that defines the fill color. This is stored in <fill>. - * stroke - String that defines the stroke color. This is stored in <stroke>. - * strokewidth - Optional integer that defines the stroke width. Default is - * 0. This is stored in <strokewidth>. - */ -function mxImageShape(bounds, image, fill, stroke, strokewidth) -{ - this.bounds = bounds; - this.image = (image != null) ? image : ''; - this.fill = fill; - this.stroke = stroke; - this.strokewidth = (strokewidth != null) ? strokewidth : 1; - this.isShadow = false; -}; - -/** - * Extends mxShape. - */ -mxImageShape.prototype = new mxShape(); -mxImageShape.prototype.constructor = mxImageShape; - -/** - * Variable: crisp - * - * Disables crisp rendering via attributes. Image quality defines the rendering - * quality. Default is false. - */ -mxImageShape.prototype.crisp = false; - -/** - * Variable: preserveImageAspect - * - * Switch to preserve image aspect. Default is true. - */ -mxImageShape.prototype.preserveImageAspect = true; - -/** - * Function: apply - * - * Overrides <mxShape.apply> to replace the fill and stroke colors with the - * respective values from <mxConstants.STYLE_IMAGE_BACKGROUND> and - * <mxConstants.STYLE_IMAGE_BORDER>. - * - * Applies the style of the given <mxCellState> to the shape. This - * implementation assigns the following styles to local fields: - * - * - <mxConstants.STYLE_IMAGE_BACKGROUND> => fill - * - <mxConstants.STYLE_IMAGE_BORDER> => stroke - * - * Parameters: - * - * state - <mxCellState> of the corresponding cell. - */ -mxImageShape.prototype.apply = function(state) -{ - mxShape.prototype.apply.apply(this, arguments); - - this.fill = null; - this.stroke = null; - - if (this.style != null) - { - this.fill = mxUtils.getValue(this.style, mxConstants.STYLE_IMAGE_BACKGROUND); - this.stroke = mxUtils.getValue(this.style, mxConstants.STYLE_IMAGE_BORDER); - this.preserveImageAspect = mxUtils.getNumber(this.style, mxConstants.STYLE_IMAGE_ASPECT, 1) == 1; - this.gradient = null; - } -}; - -/** - * Function: create - * - * Override to create HTML regardless of gradient and - * rounded property. - */ -mxImageShape.prototype.create = function() -{ - var node = null; - - if (this.dialect == mxConstants.DIALECT_SVG) - { - // Workaround: To avoid control-click on images in Firefox to - // open the image in a new window, this image needs to be placed - // inside a group with a rectangle in the foreground which has a - // fill property but no visibility and absorbs all events. - // The image in turn must have all pointer-events disabled. - node = this.createSvgGroup('rect'); - this.innerNode.setAttribute('visibility', 'hidden'); - this.innerNode.setAttribute('pointer-events', 'fill'); - - this.imageNode = document.createElementNS(mxConstants.NS_SVG, 'image'); - this.imageNode.setAttributeNS(mxConstants.NS_XLINK, 'xlink:href', this.image); - this.imageNode.setAttribute('style', 'pointer-events:none'); - this.configureSvgShape(this.imageNode); - - // Removes invalid attributes on the image node - this.imageNode.removeAttribute('stroke'); - this.imageNode.removeAttribute('fill'); - node.insertBefore(this.imageNode, this.innerNode); - - // Inserts node for background and border color rendering - if ((this.fill != null && this.fill != mxConstants.NONE) || - (this.stroke != null && this.stroke != mxConstants.NONE)) - { - this.bg = document.createElementNS(mxConstants.NS_SVG, 'rect'); - node.insertBefore(this.bg, node.firstChild); - } - - // Preserves image aspect as default - if (!this.preserveImageAspect) - { - this.imageNode.setAttribute('preserveAspectRatio', 'none'); - } - } - else - { - // Uses VML image for all non-embedded images in IE to support better - // image flipping quality and avoid workarounds for event redirection - var flipH = mxUtils.getValue(this.style, mxConstants.STYLE_IMAGE_FLIPH, 0) == 1; - var flipV = mxUtils.getValue(this.style, mxConstants.STYLE_IMAGE_FLIPV, 0) == 1; - var img = this.image.toUpperCase(); - - // Handles non-flipped embedded images in IE6 - if (mxClient.IS_IE && !flipH && !flipV && img.substring(0, 6) == 'MHTML:') - { - // LATER: Check if outer DIV is required or if aspect can be implemented - // by adding an offset to the image loading or the background via CSS. - this.imageNode = document.createElement('DIV'); - this.imageNode.style.filter = 'progid:DXImageTransform.Microsoft.AlphaImageLoader ' + - '(src=\'' + this.image + '\', sizingMethod=\'scale\')'; - - node = document.createElement('DIV'); - this.configureHtmlShape(node); - node.appendChild(this.imageNode); - } - // Handles all data URL images and HTML images for IE9 with no VML support (in SVG mode) - else if (!mxClient.IS_IE || img.substring(0, 5) == 'DATA:' || document.documentMode >= 9) - { - this.imageNode = document.createElement('img'); - this.imageNode.setAttribute('src', this.image); - this.imageNode.setAttribute('border', '0'); - this.imageNode.style.position = 'absolute'; - this.imageNode.style.width = '100%'; - this.imageNode.style.height = '100%'; - - node = document.createElement('DIV'); - this.configureHtmlShape(node); - node.appendChild(this.imageNode); - } - else - { - this.imageNode = document.createElement('v:image'); - this.imageNode.style.position = 'absolute'; - this.imageNode.src = this.image; - - // Needed to draw the background and border but known - // to cause problems in print preview with https - node = document.createElement('DIV'); - this.configureHtmlShape(node); - - // Workaround for cropped images in IE7/8 - node.style.overflow = 'visible'; - node.appendChild(this.imageNode); - } - } - - return node; -}; - -/** - * Function: updateAspect - * - * Updates the aspect of the image for the given image width and height. - */ -mxImageShape.prototype.updateAspect = function(w, h) -{ - var s = Math.min(this.bounds.width / w, this.bounds.height / h); - w = Math.max(0, Math.round(w * s)); - h = Math.max(0, Math.round(h * s)); - var x0 = Math.max(0, Math.round((this.bounds.width - w) / 2)); - var y0 = Math.max(0, Math.round((this.bounds.height - h) / 2)); - var st = this.imageNode.style; - - // Positions the child node relative to the parent node - if (this.imageNode.parentNode == this.node) - { - // Workaround for duplicate offset in VML in IE8 is - // to use parent padding instead of left and top - this.node.style.paddingLeft = x0 + 'px'; - this.node.style.paddingTop = y0 + 'px'; - } - else - { - st.left = (Math.round(this.bounds.x) + x0) + 'px'; - st.top = (Math.round(this.bounds.y) + y0) + 'px'; - } - - st.width = w + 'px'; - st.height = h + 'px'; -}; - -/** - * Function: scheduleUpdateAspect - * - * Schedules an asynchronous <updateAspect> using the current <image>. - */ -mxImageShape.prototype.scheduleUpdateAspect = function() -{ - var img = new Image(); - - img.onload = mxUtils.bind(this, function() - { - mxImageShape.prototype.updateAspect.call(this, img.width, img.height); - }); - - img.src = this.image; -}; - -/** - * Function: redraw - * - * Overrides <mxShape.redraw> to preserve the aspect ratio of images. - */ -mxImageShape.prototype.redraw = function() -{ - mxShape.prototype.redraw.apply(this, arguments); - - if (this.imageNode != null && this.bounds != null) - { - // Horizontal and vertical flipping - var flipH = mxUtils.getValue(this.style, mxConstants.STYLE_IMAGE_FLIPH, 0) == 1; - var flipV = mxUtils.getValue(this.style, mxConstants.STYLE_IMAGE_FLIPV, 0) == 1; - - if (this.dialect == mxConstants.DIALECT_SVG) - { - var sx = 1; - var sy = 1; - var dx = 0; - var dy = 0; - - if (flipH) - { - sx = -1; - dx = -this.bounds.width - 2 * this.bounds.x; - } - - if (flipV) - { - sy = -1; - dy = -this.bounds.height - 2 * this.bounds.y; - } - - // Adds image tansformation to existing transforms - var transform = (this.imageNode.getAttribute('transform') || '') + - ' scale('+sx+' '+sy+')'+ ' translate('+dx+' '+dy+')'; - this.imageNode.setAttribute('transform', transform); - } - else - { - // Sets default size (no aspect) - if (this.imageNode.nodeName != 'DIV') - { - this.imageNode.style.width = Math.max(0, Math.round(this.bounds.width)) + 'px'; - this.imageNode.style.height = Math.max(0, Math.round(this.bounds.height)) + 'px'; - } - - // Preserves image aspect - if (this.preserveImageAspect) - { - this.scheduleUpdateAspect(); - } - - if (flipH || flipV) - { - if (mxUtils.isVml(this.imageNode)) - { - if (flipH && flipV) - { - this.imageNode.style.rotation = '180'; - } - else if (flipH) - { - this.imageNode.style.flip = 'x'; - } - else - { - this.imageNode.style.flip = 'y'; - } - } - else - { - var filter = (this.imageNode.nodeName == 'DIV') ? 'progid:DXImageTransform.Microsoft.AlphaImageLoader ' + - '(src=\'' + this.image + '\', sizingMethod=\'scale\')' : ''; - - if (flipH && flipV) - { - filter += 'progid:DXImageTransform.Microsoft.BasicImage(rotation=2)'; - } - else if (flipH) - { - filter += 'progid:DXImageTransform.Microsoft.BasicImage(mirror=1)'; - } - else - { - filter += 'progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)'; - } - - if (this.imageNode.style.filter != filter) - { - this.imageNode.style.filter = filter; - } - } - } - } - } -}; - -/** - * Function: configureTransparentBackground - * - * Workaround for security warning in IE if this is used in the overlay pane - * of a diagram. - */ -mxImageShape.prototype.configureTransparentBackground = function(node) -{ - // do nothing -}; - -/** - * Function: redrawSvg - * - * Updates the SVG node(s) to reflect the latest bounds and scale. - */ -mxImageShape.prototype.redrawSvg = function() -{ - this.updateSvgShape(this.innerNode); - this.updateSvgShape(this.imageNode); - - if (this.bg != null) - { - this.updateSvgShape(this.bg); - - if (this.fill != null) - { - this.bg.setAttribute('fill', this.fill); - } - else - { - this.bg.setAttribute('fill', 'none'); - } - - if (this.stroke != null) - { - this.bg.setAttribute('stroke', this.stroke); - } - else - { - this.bg.setAttribute('stroke', 'none'); - } - - this.bg.setAttribute('shape-rendering', 'crispEdges'); - } -}; - -/** - * Function: configureSvgShape - * - * Extends method to set opacity on images. - */ -mxImageShape.prototype.configureSvgShape = function(node) -{ - mxShape.prototype.configureSvgShape.apply(this, arguments); - - if (this.imageNode != null) - { - if (this.opacity != null) - { - this.imageNode.setAttribute('opacity', this.opacity / 100); - } - else - { - this.imageNode.removeAttribute('opacity'); - } - } -}; diff --git a/src/js/shape/mxLabel.js b/src/js/shape/mxLabel.js deleted file mode 100644 index c31f3bf..0000000 --- a/src/js/shape/mxLabel.js +++ /dev/null @@ -1,427 +0,0 @@ -/** - * $Id: mxLabel.js,v 1.40 2012-05-22 16:10:12 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -/** - * Class: mxLabel - * - * Extends <mxShape> to implement an image shape with a label. - * This shape is registered under <mxConstants.SHAPE_LABEL> in - * <mxCellRenderer>. - * - * Constructor: mxLabel - * - * Constructs a new label shape. - * - * Parameters: - * - * bounds - <mxRectangle> that defines the bounds. This is stored in - * <mxShape.bounds>. - * fill - String that defines the fill color. This is stored in <fill>. - * stroke - String that defines the stroke color. This is stored in <stroke>. - * strokewidth - Optional integer that defines the stroke width. Default is - * 1. This is stored in <strokewidth>. - */ -function mxLabel(bounds, fill, stroke, strokewidth) -{ - this.bounds = bounds; - this.fill = fill; - this.stroke = stroke; - this.strokewidth = (strokewidth != null) ? strokewidth : 1; -}; - -/** - * Extends mxShape. - */ -mxLabel.prototype = new mxShape(); -mxLabel.prototype.constructor = mxLabel; - -/** - * Variable: vmlNodes - * - * Adds local references to <mxShape.vmlNodes>. - */ -mxLabel.prototype.vmlNodes = mxLabel.prototype.vmlNodes.concat(['label', 'imageNode', 'indicatorImageNode', 'rectNode']); - -/** - * Variable: imageSize - * - * Default width and height for the image. Default is - * <mxConstants.DEFAULT_IMAGESIZE>. - */ -mxLabel.prototype.imageSize = mxConstants.DEFAULT_IMAGESIZE; - -/** - * Variable: spacing - * - * Default value for spacing. Default is 2. - */ -mxLabel.prototype.spacing = 2; - -/** - * Variable: indicatorSize - * - * Default width and height for the indicicator. Default is - * 10. - */ -mxLabel.prototype.indicatorSize = 10; - -/** - * Variable: indicatorSpacing - * - * Default spacing between image and indicator. Default is 2. - */ -mxLabel.prototype.indicatorSpacing = 2; - -/** - * Variable: opaqueVmlImages - * - * Specifies if all VML images should be rendered without transparency, that - * is, if the current opacity should be ignored for images. Default is false. - */ -mxLabel.prototype.opaqueVmlImages = false; - -/** - * Function: init - * - * Initializes the shape and adds it to the container. This function is - * overridden so that the node is already in the DOM when the indicator - * is added. This is required to access the ownerSVGelement of the - * container in the init function of the indicator. - */ -mxLabel.prototype.init = function(container) -{ - mxShape.prototype.init.apply(this, arguments); - - // Creates the indicator shape after the node was added to the DOM - if (this.indicatorColor != null && this.indicatorShape != null) - { - this.indicator = new this.indicatorShape(); - this.indicator.dialect = this.dialect; - this.indicator.bounds = this.bounds; - this.indicator.fill = this.indicatorColor; - this.indicator.stroke = this.indicatorColor; - this.indicator.gradient = this.indicatorGradientColor; - this.indicator.direction = this.indicatorDirection; - this.indicator.init(this.node); - this.indicatorShape = null; - } -}; - -/** - * Function: reconfigure - * - * Reconfigures this shape. This will update the colors of the indicator - * and reconfigure it if required. - */ -mxLabel.prototype.reconfigure = function() -{ - mxShape.prototype.reconfigure.apply(this); - - if (this.indicator != null) - { - this.indicator.fill = this.indicatorColor; - this.indicator.stroke = this.indicatorColor; - this.indicator.gradient = this.indicatorGradientColor; - this.indicator.direction = this.indicatorDirection; - this.indicator.reconfigure(); - } -}; - -/** - * Function: createHtml - * - * Creates and returns the HTML node to represent this shape. - */ -mxLabel.prototype.createHtml = function() -{ - var name = 'DIV'; - var node = document.createElement(name); - this.configureHtmlShape(node); - - // Adds a small subshape inside this shape - if (this.indicatorImage != null) - { - this.indicatorImageNode = mxUtils.createImage(this.indicatorImage); - this.indicatorImageNode.style.position = 'absolute'; - node.appendChild(this.indicatorImageNode); - } - - // Adds an image node to the div - if (this.image != null) - { - this.imageNode = mxUtils.createImage(this.image); - this.stroke = null; - this.configureHtmlShape(this.imageNode); - mxUtils.setOpacity(this.imageNode, '100'); - node.appendChild(this.imageNode); - } - - return node; -}; - -/** - * Function: createVml - * - * Creates and returns the VML node to represent this shape. - */ -mxLabel.prototype.createVml = function() -{ - var node = document.createElement('v:group'); - - // Background - var name = (this.isRounded) ? 'v:roundrect' : 'v:rect'; - this.rectNode = document.createElement(name); - this.configureVmlShape(this.rectNode); - - // Disables the shadow and configures the enclosing group - this.isShadow = false; - this.configureVmlShape(node); - node.coordorigin = '0,0'; - node.appendChild(this.rectNode); - - // Adds a small subshape inside this shape - if (this.indicatorImage != null) - { - this.indicatorImageNode = this.createVmlImage(this.indicatorImage, (this.opaqueVmlImages) ? null : this.opacity); - node.appendChild(this.indicatorImageNode); - } - - // Adds an image node to the div - if (this.image != null) - { - this.imageNode = this.createVmlImage(this.image, (this.opaqueVmlImages) ? null : this.opacity); - node.appendChild(this.imageNode); - } - - // Container for the label on top of everything - this.label = document.createElement('v:rect'); - this.label.style.top = '0px'; // relative - this.label.style.left = '0px'; // relative - this.label.filled = 'false'; - this.label.stroked = 'false'; - node.appendChild(this.label); - - return node; -}; - -/** - * Function: createVmlImage - * - * Creates an image node for the given image src and opacity to be used in VML. - */ -mxLabel.prototype.createVmlImage = function(src, opacity) -{ - var result = null; - - // Workaround for data URIs not supported in VML and for added - // border around images if opacity is used (not needed in IE9, - // but IMG node is probably better and faster anyway). - if (src.substring(0, 5) == 'data:' || opacity != null) - { - result = document.createElement('img'); - mxUtils.setOpacity(result, opacity); - result.setAttribute('border', '0'); - result.style.position = 'absolute'; - result.setAttribute('src', src); - } - else - { - result = document.createElement('v:image'); - result.src = src; - } - - return result; -}; - -/** - * Function: createSvg - * - * Creates and returns the SVG node to represent this shape. - */ -mxLabel.prototype.createSvg = function() -{ - var g = this.createSvgGroup('rect'); - - // Adds a small subshape to the svg group - if (this.indicatorImage != null) - { - this.indicatorImageNode = document.createElementNS(mxConstants.NS_SVG, 'image'); - this.indicatorImageNode.setAttributeNS(mxConstants.NS_XLINK, 'href', this.indicatorImage); - g.appendChild(this.indicatorImageNode); - - if (this.opacity != null) - { - this.indicatorImageNode.setAttribute('opacity', this.opacity / 100); - } - } - - // Adds an image to the svg group - if (this.image != null) - { - this.imageNode = document.createElementNS(mxConstants.NS_SVG, 'image'); - this.imageNode.setAttributeNS(mxConstants.NS_XLINK, 'href', this.image); - - if (this.opacity != null) - { - this.imageNode.setAttribute('opacity', this.opacity / 100); - } - - // Disables control-click and alt-click in Firefox - this.imageNode.setAttribute('style', 'pointer-events:none'); - this.configureSvgShape(this.imageNode); - g.appendChild(this.imageNode); - } - - return g; -}; - -/** - * Function: redraw - * - * Overrides redraw to define a unified implementation for redrawing - * all supported dialects. - */ -mxLabel.prototype.redraw = function() -{ - this.updateBoundingBox(); - var isSvg = (this.dialect == mxConstants.DIALECT_SVG); - var isVml = mxUtils.isVml(this.node); - - // Updates the bounds of the outermost shape - if (isSvg) - { - this.updateSvgShape(this.innerNode); - - if (this.shadowNode != null) - { - this.updateSvgShape(this.shadowNode); - } - - this.updateSvgGlassPane(); - } - else if (isVml) - { - this.updateVmlShape(this.node); - this.updateVmlShape(this.rectNode); - this.label.style.width = this.node.style.width; - this.label.style.height = this.node.style.height; - - this.updateVmlGlassPane(); - } - else - { - this.updateHtmlShape(this.node); - } - - // Updates the imagewidth and imageheight - var imageWidth = 0; - var imageHeight = 0; - - if (this.imageNode != null) - { - imageWidth = (this.style[mxConstants.STYLE_IMAGE_WIDTH] || - this.imageSize) * this.scale; - imageHeight = (this.style[mxConstants.STYLE_IMAGE_HEIGHT] || - this.imageSize) * this.scale; - } - - // Updates the subshape size and location - var indicatorSpacing = 0; - var indicatorWidth = 0; - var indicatorHeight = 0; - - if (this.indicator != null || this.indicatorImageNode != null) - { - indicatorSpacing = (this.style[mxConstants.STYLE_INDICATOR_SPACING] || - this.indicatorSpacing) * this.scale; - indicatorWidth = (this.style[mxConstants.STYLE_INDICATOR_WIDTH] || - this.indicatorSize) * this.scale; - indicatorHeight = (this.style[mxConstants.STYLE_INDICATOR_HEIGHT] || - this.indicatorSize) * this.scale; - } - - var align = this.style[mxConstants.STYLE_IMAGE_ALIGN]; - var valign = this.style[mxConstants.STYLE_IMAGE_VERTICAL_ALIGN]; - - var inset = this.spacing * this.scale + 5; - var width = Math.max(imageWidth, indicatorWidth); - var height = imageHeight + indicatorSpacing + indicatorHeight; - - var x = (isSvg) ? this.bounds.x : 0; - - if (align == mxConstants.ALIGN_RIGHT) - { - x += this.bounds.width - width - inset; - } - else if (align == mxConstants.ALIGN_CENTER) - { - x += (this.bounds.width - width) / 2; - } - else // default is left - { - x += inset; - } - - var y = (isSvg) ? this.bounds.y : 0; - - if (valign == mxConstants.ALIGN_BOTTOM) - { - y += this.bounds.height - height - inset; - } - else if (valign == mxConstants.ALIGN_TOP) - { - y += inset; - } - else // default is middle - { - y += (this.bounds.height - height) / 2; - } - - // Updates the imagenode - if (this.imageNode != null) - { - if (isSvg) - { - this.imageNode.setAttribute('x', (x + (width - imageWidth) / 2) + 'px'); - this.imageNode.setAttribute('y', y + 'px'); - this.imageNode.setAttribute('width', imageWidth + 'px'); - this.imageNode.setAttribute('height', imageHeight + 'px'); - } - else - { - this.imageNode.style.left = (x + width - imageWidth) + 'px'; - this.imageNode.style.top = y + 'px'; - this.imageNode.style.width = imageWidth + 'px'; - this.imageNode.style.height = imageHeight + 'px'; - this.imageNode.stroked = 'false'; - } - } - - // Updates the subshapenode (aka. indicator) - if (this.indicator != null) - { - this.indicator.bounds = new mxRectangle( - x + (width - indicatorWidth) / 2, - y + imageHeight + indicatorSpacing, - indicatorWidth, indicatorHeight); - this.indicator.redraw(); - } - else if (this.indicatorImageNode != null) - { - if (isSvg) - { - this.indicatorImageNode.setAttribute('x', (x + (width - indicatorWidth) / 2) + 'px'); - this.indicatorImageNode.setAttribute('y', (y + imageHeight + indicatorSpacing) + 'px'); - this.indicatorImageNode.setAttribute('width', indicatorWidth + 'px'); - this.indicatorImageNode.setAttribute('height', indicatorHeight + 'px'); - } - else - { - this.indicatorImageNode.style.left = (x + (width - indicatorWidth) / 2) + 'px'; - this.indicatorImageNode.style.top = (y + imageHeight + indicatorSpacing) + 'px'; - this.indicatorImageNode.style.width = indicatorWidth + 'px'; - this.indicatorImageNode.style.height = indicatorHeight + 'px'; - } - } -}; diff --git a/src/js/shape/mxLine.js b/src/js/shape/mxLine.js deleted file mode 100644 index 5ef3eb0..0000000 --- a/src/js/shape/mxLine.js +++ /dev/null @@ -1,217 +0,0 @@ -/** - * $Id: mxLine.js,v 1.36 2012-03-30 04:44:59 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -/** - * Class: mxLine - * - * Extends <mxShape> to implement a horizontal line shape. - * This shape is registered under <mxConstants.SHAPE_LINE> in - * <mxCellRenderer>. - * - * Constructor: mxLine - * - * Constructs a new line shape. - * - * Parameters: - * - * bounds - <mxRectangle> that defines the bounds. This is stored in - * <mxShape.bounds>. - * stroke - String that defines the stroke color. Default is 'black'. This is - * stored in <stroke>. - * strokewidth - Optional integer that defines the stroke width. Default is - * 1. This is stored in <strokewidth>. - */ -function mxLine(bounds, stroke, strokewidth) -{ - this.bounds = bounds; - this.stroke = stroke; - this.strokewidth = (strokewidth != null) ? strokewidth : 1; -}; - -/** - * Extends mxShape. - */ -mxLine.prototype = new mxShape(); -mxLine.prototype.constructor = mxLine; - -/** - * Variable: vmlNodes - * - * Adds local references to <mxShape.vmlNodes>. - */ -mxLine.prototype.vmlNodes = mxLine.prototype.vmlNodes.concat(['label', 'innerNode']); - -/** - * Variable: mixedModeHtml - * - * Overrides the parent value with false, meaning it will - * draw in VML in mixed Html mode. - */ -mxLine.prototype.mixedModeHtml = false; - -/** - * Variable: preferModeHtml - * - * Overrides the parent value with false, meaning it will - * draw as VML in prefer Html mode. - */ -mxLine.prototype.preferModeHtml = false; - -/** - * Function: clone - * - * Overrides the clone method to add special fields. - */ -mxLine.prototype.clone = function() -{ - var clone = new mxLine(this.bounds, - this.stroke, this.strokewidth); - clone.isDashed = this.isDashed; - - return clone; -}; - -/** - * Function: createVml - * - * Creates and returns the VML node to represent this shape. - */ -mxLine.prototype.createVml = function() -{ - var node = document.createElement('v:group'); - node.style.position = 'absolute'; - - // Represents the text label container - this.label = document.createElement('v:rect'); - this.label.style.position = 'absolute'; - this.label.stroked = 'false'; - this.label.filled = 'false'; - node.appendChild(this.label); - - // Represents the straight line shape - this.innerNode = document.createElement('v:shape'); - this.configureVmlShape(this.innerNode); - node.appendChild(this.innerNode); - - return node; -}; - -/** - * Function: redrawVml - * - * Redraws this VML shape by invoking <updateVmlShape> on this.node. - */ -mxLine.prototype.reconfigure = function() -{ - if (mxUtils.isVml(this.node)) - { - this.configureVmlShape(this.innerNode); - } - else - { - mxShape.prototype.reconfigure.apply(this, arguments); - } -}; - -/** - * Function: redrawVml - * - * Updates the VML node(s) to reflect the latest bounds and scale. - */ -mxLine.prototype.redrawVml = function() -{ - this.updateVmlShape(this.node); - this.updateVmlShape(this.label); - - this.innerNode.coordsize = this.node.coordsize; - this.innerNode.strokeweight = (this.strokewidth * this.scale) + 'px'; - this.innerNode.style.width = this.node.style.width; - this.innerNode.style.height = this.node.style.height; - - var w = this.bounds.width; - var h =this.bounds.height; - - if (this.direction == mxConstants.DIRECTION_NORTH || - this.direction == mxConstants.DIRECTION_SOUTH) - { - this.innerNode.path = 'm ' + Math.round(w / 2) + ' 0' + - ' l ' + Math.round(w / 2) + ' ' + Math.round(h) + ' e'; - } - else - { - this.innerNode.path = 'm 0 ' + Math.round(h / 2) + - ' l ' + Math.round(w) + ' ' + Math.round(h / 2) + ' e'; - } -}; - -/** - * Function: createSvg - * - * Creates and returns the SVG node(s) to represent this shape. - */ -mxLine.prototype.createSvg = function() -{ - var g = this.createSvgGroup('path'); - - // Creates an invisible shape around the path for easier - // selection with the mouse. Note: Firefox does not ignore - // the value of the stroke attribute for pointer-events: stroke. - // It does, however, ignore the visibility attribute. - this.pipe = this.createSvgPipe(); - g.appendChild(this.pipe); - - return g; -}; - -/** - * Function: redrawSvg - * - * Updates the SVG node(s) to reflect the latest bounds and scale. - */ -mxLine.prototype.redrawSvg = function() -{ - var strokeWidth = Math.round(Math.max(1, this.strokewidth * this.scale)); - this.innerNode.setAttribute('stroke-width', strokeWidth); - - if (this.bounds != null) - { - var x = this.bounds.x; - var y = this.bounds.y; - var w = this.bounds.width; - var h = this.bounds.height; - - var d = null; - - if (this.direction == mxConstants.DIRECTION_NORTH || this.direction == mxConstants.DIRECTION_SOUTH) - { - d = 'M ' + Math.round(x + w / 2) + ' ' + Math.round(y) + ' L ' + Math.round(x + w / 2) + ' ' + Math.round(y + h); - } - else - { - d = 'M ' + Math.round(x) + ' ' + Math.round(y + h / 2) + ' L ' + Math.round(x + w) + ' ' + Math.round(y + h / 2); - } - - this.innerNode.setAttribute('d', d); - this.pipe.setAttribute('d', d); - this.pipe.setAttribute('stroke-width', this.strokewidth + mxShape.prototype.SVG_STROKE_TOLERANCE); - - this.updateSvgTransform(this.innerNode, false); - this.updateSvgTransform(this.pipe, false); - - if (this.crisp) - { - this.innerNode.setAttribute('shape-rendering', 'crispEdges'); - } - else - { - this.innerNode.removeAttribute('shape-rendering'); - } - - if (this.isDashed) - { - var phase = Math.max(1, Math.round(3 * this.scale * this.strokewidth)); - this.innerNode.setAttribute('stroke-dasharray', phase + ' ' + phase); - } - } -}; diff --git a/src/js/shape/mxMarker.js b/src/js/shape/mxMarker.js deleted file mode 100644 index cfd6f66..0000000 --- a/src/js/shape/mxMarker.js +++ /dev/null @@ -1,267 +0,0 @@ -/** - * $Id: mxMarker.js,v 1.19 2012-03-30 12:51:58 david Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -var mxMarker = -{ - /** - * Class: mxMarker - * - * A static class that implements all markers for VML and SVG using a - * registry. NOTE: The signatures in this class will change. - * - * Variable: markers - * - * Maps from markers names to functions to paint the markers. - */ - markers: [], - - /** - * Function: paintMarker - * - * Paints the given marker. - */ - paintMarker: function(node, type, p0, pe, color, strokewidth, size, scale, x0, y0, source, style) - { - var marker = mxMarker.markers[type]; - var result = null; - - if (marker != null) - { - var isVml = mxUtils.isVml(node); - - // Computes the norm and the inverse norm - var dx = pe.x - p0.x; - var dy = pe.y - p0.y; - - if (isNaN(dx) || isNaN(dy)) - { - return; - } - - var dist = Math.max(1, Math.sqrt(dx * dx + dy * dy)); - var nx = dx * scale / dist; - var ny = dy * scale / dist; - - pe = pe.clone(); - - if (isVml) - { - pe.x -= x0; - pe.y -= y0; - } - - // Handles start-/endFill style - var filled = true; - var key = (source) ? mxConstants.STYLE_STARTFILL : mxConstants.STYLE_ENDFILL; - - if (style[key] == 0) - { - filled = false; - } - - if (isVml) - { - // Opacity is updated in reconfigure, use nf in path for no fill - node.strokecolor = color; - - if (filled) - { - node.fillcolor = color; - } - else - { - node.filled = 'false'; - } - } - else - { - node.setAttribute('stroke', color); - - var op = (style.opacity != null) ? style.opacity / 100 : 1; - node.setAttribute('stroke-opacity', op); - - if (filled) - { - node.setAttribute('fill', color); - node.setAttribute('fill-opacity', op); - } - else - { - node.setAttribute('fill', 'none'); - } - } - - result = marker.call(this, node, type, pe, nx, ny, strokewidth, size, scale, isVml); - } - - return result; - } - -}; - -(function() -{ - /** - * Drawing of the classic and block arrows. - */ - var tmp = function(node, type, pe, nx, ny, strokewidth, size, scale, isVml) - { - // The angle of the forward facing arrow sides against the x axis is - // 26.565 degrees, 1/sin(26.565) = 2.236 / 2 = 1.118 ( / 2 allows for - // only half the strokewidth is processed ). - var endOffsetX = nx * strokewidth * 1.118; - var endOffsetY = ny * strokewidth * 1.118; - pe.x -= endOffsetX; - pe.y -= endOffsetY; - - nx = nx * (size + strokewidth); - ny = ny * (size + strokewidth); - - if (isVml) - { - node.path = 'm' + Math.round(pe.x) + ',' + Math.round(pe.y) + - ' l' + Math.round(pe.x - nx - ny / 2) + ' ' + Math.round(pe.y - ny + nx / 2) + - ((type != mxConstants.ARROW_CLASSIC) ? '' : - ' ' + Math.round(pe.x - nx * 3 / 4) + ' ' + Math.round(pe.y - ny * 3 / 4)) + - ' ' + Math.round(pe.x + ny / 2 - nx) + ' ' + Math.round(pe.y - ny - nx / 2) + - ' x e'; - node.setAttribute('strokeweight', (strokewidth * scale) + 'px'); - } - else - { - node.setAttribute('d', 'M ' + pe.x + ' ' + pe.y + - ' L ' + (pe.x - nx - ny / 2) + ' ' + (pe.y - ny + nx / 2) + - ((type != mxConstants.ARROW_CLASSIC) ? '' : - ' L ' + (pe.x - nx * 3 / 4) + ' ' + (pe.y - ny * 3 / 4)) + - ' L ' + (pe.x + ny / 2 - nx) + ' ' + (pe.y - ny - nx / 2) + - ' z'); - node.setAttribute('stroke-width', strokewidth * scale); - } - - var f = (type != mxConstants.ARROW_CLASSIC) ? 1 : 3 / 4; - return new mxPoint(-nx * f - endOffsetX, -ny * f - endOffsetY); - }; - - mxMarker.markers[mxConstants.ARROW_CLASSIC] = tmp; - mxMarker.markers[mxConstants.ARROW_BLOCK] = tmp; -}()); - -mxMarker.markers[mxConstants.ARROW_OPEN] = function(node, type, pe, nx, ny, strokewidth, size, scale, isVml) -{ - // The angle of the forward facing arrow sides against the x axis is - // 26.565 degrees, 1/sin(26.565) = 2.236 / 2 = 1.118 ( / 2 allows for - // only half the strokewidth is processed ). - var endOffsetX = nx * strokewidth * 1.118; - var endOffsetY = ny * strokewidth * 1.118; - pe.x -= endOffsetX; - pe.y -= endOffsetY; - - nx = nx * (size + strokewidth); - ny = ny * (size + strokewidth); - - if (isVml) - { - node.path = 'm' + Math.round(pe.x - nx - ny / 2) + ' ' + Math.round(pe.y - ny + nx / 2) + - ' l' + Math.round(pe.x) + ' ' + Math.round(pe.y) + - ' ' + Math.round(pe.x + ny / 2 - nx) + ' ' + Math.round(pe.y - ny - nx / 2) + - ' e nf'; - node.setAttribute('strokeweight', (strokewidth * scale) + 'px'); - } - else - { - node.setAttribute('d', 'M ' + (pe.x - nx - ny / 2) + ' ' + (pe.y - ny + nx / 2) + - ' L ' + (pe.x) + ' ' + (pe.y) + - ' L ' + (pe.x + ny / 2 - nx) + ' ' + (pe.y - ny - nx / 2)); - node.setAttribute('stroke-width', strokewidth * scale); - node.setAttribute('fill', 'none'); - } - - return new mxPoint(-endOffsetX * 2, -endOffsetY * 2); -}; - -mxMarker.markers[mxConstants.ARROW_OVAL] = function(node, type, pe, nx, ny, strokewidth, size, scale, isVml) -{ - nx *= size; - ny *= size; - - nx *= 0.5 + strokewidth / 2; - ny *= 0.5 + strokewidth / 2; - - var absSize = size * scale; - var radius = absSize / 2; - - if (isVml) - { - node.path = 'm' + Math.round(pe.x + radius) + ' ' + Math.round(pe.y) + - ' at ' + Math.round(pe.x - radius) + ' ' + Math.round(pe.y - radius) + - ' ' + Math.round(pe.x + radius) + ' ' + Math.round(pe.y + radius) + - ' ' + Math.round(pe.x + radius) + ' ' + Math.round(pe.y) + - ' ' + Math.round(pe.x + radius) + ' ' + Math.round(pe.y) + - ' x e'; - - node.setAttribute('strokeweight', (strokewidth * scale) + 'px'); - } - else - { - node.setAttribute('d', 'M ' + (pe.x - radius) + ' ' + (pe.y) + - ' a ' + (radius) + ' ' + (radius) + - ' 0 1,1 ' + (absSize) + ' 0' + - ' a ' + (radius) + ' ' + (radius) + - ' 0 1,1 ' + (-absSize) + ' 0 z'); - node.setAttribute('stroke-width', strokewidth * scale); - } - - return new mxPoint(-nx / (2 + strokewidth), -ny / (2 + strokewidth)); -}; - -(function() - { - /** - * Drawing of the diamond and thin diamond markers - */ - var tmp_diamond = function(node, type, pe, nx, ny, strokewidth, size, scale, isVml) - { - // The angle of the forward facing arrow sides against the x axis is - // 45 degrees, 1/sin(45) = 1.4142 / 2 = 0.7071 ( / 2 allows for - // only half the strokewidth is processed ). Or 0.9862 for thin diamond. - // Note these values and the tk variable below are dependent, update - // both together (saves trig hard coding it). - var swFactor = (type == mxConstants.ARROW_DIAMOND) ? 0.7071 : 0.9862; - var endOffsetX = nx * strokewidth * swFactor; - var endOffsetY = ny * strokewidth * swFactor; - - nx = nx * (size + strokewidth); - ny = ny * (size + strokewidth); - - pe.x -= endOffsetX + nx / 2; - pe.y -= endOffsetY + ny / 2; - - // thickness factor for diamond - var tk = ((type == mxConstants.ARROW_DIAMOND) ? 2 : 3.4); - - if (isVml) - { - node.path = 'm' + Math.round(pe.x + nx / 2) + ' ' + Math.round(pe.y + ny / 2) + - ' l' + Math.round(pe.x - ny / tk) + ' ' + Math.round(pe.y + nx / tk) + - ' ' + Math.round(pe.x - nx / 2) + ' ' + Math.round(pe.y - ny / 2) + - ' ' + Math.round(pe.x + ny / tk) + ' ' + Math.round(pe.y - nx / tk) + - ' x e'; - node.setAttribute('strokeweight', (strokewidth * scale) + 'px'); - } - else - { - node.setAttribute('d', 'M ' + (pe.x + nx / 2) + ' ' + (pe.y + ny / 2) + - ' L ' + (pe.x - ny / tk) + ' ' + (pe.y + nx / tk) + - ' L ' + (pe.x - nx / 2) + ' ' + (pe.y - ny / 2) + - ' L ' + (pe.x + ny / tk) + ' ' + (pe.y - nx / tk) + - ' z'); - node.setAttribute('stroke-width', strokewidth * scale); - } - - return new mxPoint(-endOffsetX - nx, -endOffsetY - ny); - }; - - mxMarker.markers[mxConstants.ARROW_DIAMOND] = tmp_diamond; - mxMarker.markers[mxConstants.ARROW_DIAMOND_THIN] = tmp_diamond; - }()); diff --git a/src/js/shape/mxPolyline.js b/src/js/shape/mxPolyline.js deleted file mode 100644 index 2d64323..0000000 --- a/src/js/shape/mxPolyline.js +++ /dev/null @@ -1,146 +0,0 @@ -/** - * $Id: mxPolyline.js,v 1.31 2012-05-24 12:00:45 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -/** - * Class: mxPolyline - * - * Extends <mxShape> to implement a polyline (a line with multiple points). - * This shape is registered under <mxConstants.SHAPE_POLYLINE> in - * <mxCellRenderer>. - * - * Constructor: mxPolyline - * - * Constructs a new polyline shape. - * - * Parameters: - * - * points - Array of <mxPoints> that define the points. This is stored in - * <mxShape.points>. - * stroke - String that defines the stroke color. Default is 'black'. This is - * stored in <stroke>. - * strokewidth - Optional integer that defines the stroke width. Default is - * 1. This is stored in <strokewidth>. - */ -function mxPolyline(points, stroke, strokewidth) -{ - this.points = points; - this.stroke = stroke; - this.strokewidth = (strokewidth != null) ? strokewidth : 1; -}; - -/** - * Extends mxShape. - */ -mxPolyline.prototype = new mxShape(); -mxPolyline.prototype.constructor = mxPolyline; - -/** - * Variable: addPipe - * - * Specifies if a SVG path should be created around any path to increase the - * tolerance for mouse events. Default is false since this shape is filled. - */ -mxPolyline.prototype.addPipe = true; - -/** - * Function: create - * - * Override to create HTML regardless of gradient and - * rounded property. - */ -mxPolyline.prototype.create = function() -{ - var node = null; - - if (this.dialect == mxConstants.DIALECT_SVG) - { - node = this.createSvg(); - } - else if (this.dialect == mxConstants.DIALECT_STRICTHTML || - (this.dialect == mxConstants.DIALECT_PREFERHTML && - this.points != null && this.points.length > 0)) - { - node = document.createElement('DIV'); - this.configureHtmlShape(node); - node.style.borderStyle = ''; - node.style.background = ''; - } - else - { - node = document.createElement('v:shape'); - this.configureVmlShape(node); - var strokeNode = document.createElement('v:stroke'); - - if (this.opacity != null) - { - strokeNode.opacity = this.opacity + '%'; - } - - node.appendChild(strokeNode); - } - - return node; -}; - -/** - * Function: redrawVml - * - * Overrides the method to update the bounds if they have not been - * assigned. - */ -mxPolyline.prototype.redrawVml = function() -{ - // Updates the bounds based on the points - if (this.points != null && this.points.length > 0 && this.points[0] != null) - { - this.bounds = new mxRectangle(this.points[0].x,this.points[0].y, 0, 0); - - for (var i = 1; i < this.points.length; i++) - { - this.bounds.add(new mxRectangle(this.points[i].x,this.points[i].y, 0, 0)); - } - } - - mxShape.prototype.redrawVml.apply(this, arguments); -}; - -/** - * Function: createSvg - * - * Creates and returns the SVG node(s) to represent this shape. - */ -mxPolyline.prototype.createSvg = function() -{ - var g = this.createSvgGroup('path'); - - // Creates an invisible shape around the path for easier - // selection with the mouse. Note: Firefox does not ignore - // the value of the stroke attribute for pointer-events: stroke, - // it does, however, ignore the visibility attribute. - if (this.addPipe) - { - this.pipe = this.createSvgPipe(); - g.appendChild(this.pipe); - } - - return g; -}; - -/** - * Function: redrawSvg - * - * Updates the SVG node(s) to reflect the latest bounds and scale. - */ -mxPolyline.prototype.redrawSvg = function() -{ - this.updateSvgShape(this.innerNode); - var d = this.innerNode.getAttribute('d'); - - if (d != null && this.pipe != null) - { - this.pipe.setAttribute('d', d); - var strokeWidth = Math.round(Math.max(1, this.strokewidth * this.scale)); - this.pipe.setAttribute('stroke-width', strokeWidth + mxShape.prototype.SVG_STROKE_TOLERANCE); - } -}; diff --git a/src/js/shape/mxRectangleShape.js b/src/js/shape/mxRectangleShape.js deleted file mode 100644 index 26688c3..0000000 --- a/src/js/shape/mxRectangleShape.js +++ /dev/null @@ -1,61 +0,0 @@ -/** - * $Id: mxRectangleShape.js,v 1.17 2012-09-26 07:51:29 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -/** - * Class: mxRectangleShape - * - * Extends <mxShape> to implement a rectangle shape. - * This shape is registered under <mxConstants.SHAPE_RECTANGLE> - * in <mxCellRenderer>. - * - * Constructor: mxRectangleShape - * - * Constructs a new rectangle shape. - * - * Parameters: - * - * bounds - <mxRectangle> that defines the bounds. This is stored in - * <mxShape.bounds>. - * fill - String that defines the fill color. This is stored in <fill>. - * stroke - String that defines the stroke color. This is stored in <stroke>. - * strokewidth - Optional integer that defines the stroke width. Default is - * 1. This is stored in <strokewidth>. - */ -function mxRectangleShape(bounds, fill, stroke, strokewidth) -{ - this.bounds = bounds; - this.fill = fill; - this.stroke = stroke; - this.strokewidth = (strokewidth != null) ? strokewidth : 1; -}; - -/** - * Extends mxShape. - */ -mxRectangleShape.prototype = new mxShape(); -mxRectangleShape.prototype.constructor = mxRectangleShape; - -/** - * Function: createVml - * - * Creates and returns the VML node to represent this shape. - */ -mxRectangleShape.prototype.createVml = function() -{ - var name = (this.isRounded) ? 'v:roundrect' : 'v:rect'; - var node = document.createElement(name); - this.configureVmlShape(node); - - return node; -}; - -/** - * Function: createSvg - * - * Creates and returns the SVG node to represent this shape. - */ -mxRectangleShape.prototype.createSvg = function() -{ - return this.createSvgGroup('rect'); -}; diff --git a/src/js/shape/mxRhombus.js b/src/js/shape/mxRhombus.js deleted file mode 100644 index 37e35ec..0000000 --- a/src/js/shape/mxRhombus.js +++ /dev/null @@ -1,172 +0,0 @@ -/** - * $Id: mxRhombus.js,v 1.25 2012-04-04 07:34:50 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -/** - * Class: mxRhombus - * - * Extends <mxShape> to implement a rhombus (aka diamond) shape. - * This shape is registered under <mxConstants.SHAPE_RHOMBUS> - * in <mxCellRenderer>. - * - * Constructor: mxRhombus - * - * Constructs a new rhombus shape. - * - * Parameters: - * - * bounds - <mxRectangle> that defines the bounds. This is stored in - * <mxShape.bounds>. - * fill - String that defines the fill color. This is stored in <fill>. - * stroke - String that defines the stroke color. This is stored in <stroke>. - * strokewidth - Optional integer that defines the stroke width. Default is - * 1. This is stored in <strokewidth>. - */ -function mxRhombus(bounds, fill, stroke, strokewidth) -{ - this.bounds = bounds; - this.fill = fill; - this.stroke = stroke; - this.strokewidth = (strokewidth != null) ? strokewidth : 1; -}; - -/** - * Extends mxShape. - */ -mxRhombus.prototype = new mxShape(); -mxRhombus.prototype.constructor = mxRhombus; - -/** - * Variable: mixedModeHtml - * - * Overrides the parent value with false, meaning it will - * draw in VML in mixed Html mode. - */ -mxRhombus.prototype.mixedModeHtml = false; - -/** - * Variable: preferModeHtml - * - * Overrides the parent value with false, meaning it will - * draw as VML in prefer Html mode. - */ -mxRhombus.prototype.preferModeHtml = false; - -/** - * Function: createHtml - * - * Creates and returns the HTML node to represent this shape. - */ -mxRhombus.prototype.createHtml = function() -{ - var node = document.createElement('DIV'); - this.configureHtmlShape(node); - - return node; -}; - -/** - * Function: createVml - * - * Creates and returns the VML node(s) to represent this shape. - */ -mxRhombus.prototype.createVml = function() -{ - var node = document.createElement('v:shape'); - this.configureVmlShape(node); - - return node; -}; - -/** - * Function: createSvg - * - * Creates and returns the SVG node(s) to represent this shape. - */ -mxRhombus.prototype.createSvg = function() -{ - return this.createSvgGroup('path'); -}; - -// TODO: When used as an indicator, this.node.points is null -// so we use a path object for building general diamonds. -//mxRhombus.prototype.redraw = function() { -// this.node.setAttribute('strokeweight', (this.strokewidth * this.scale) + 'px'); -// var x = this.bounds.x; -// var y = this.bounds.y; -// var w = this.bounds.width; -// var h = this.bounds.height; -// this.node.points.value = (x+w/2)+','+y+' '+(x+w)+','+(y+h/2)+ -// ' '+(x+w/2)+','+(y+h)+' '+x+','+(y+h/2)+' '+ -// (x+w/2)+','+y; -//} - -/** - * Function: redrawVml - * - * Updates the VML node(s) to reflect the latest bounds and scale. - */ -mxRhombus.prototype.redrawVml = function() -{ - this.updateVmlShape(this.node); - var x = 0; - var y = 0; - var w = Math.round(this.bounds.width); - var h = Math.round(this.bounds.height); - - this.node.path = 'm ' + Math.round(x + w / 2) + ' ' + y + - ' l ' + (x + w) + ' ' + Math.round(y + h / 2) + - ' l ' + Math.round(x + w / 2) + ' ' + (y + h) + - ' l ' + x + ' ' + Math.round(y + h / 2) + ' x e'; -}; - -/** - * Function: redrawHtml - * - * Updates the HTML node(s) to reflect the latest bounds and scale. - */ -mxRhombus.prototype.redrawHtml = function() -{ - this.updateHtmlShape(this.node); -}; - -/** - * Function: redrawSvg - * - * Updates the SVG node(s) to reflect the latest bounds and scale. - */ -mxRhombus.prototype.redrawSvg = function() -{ - this.updateSvgNode(this.innerNode); - - if (this.shadowNode != null) - { - this.updateSvgNode(this.shadowNode); - } -}; - -/** - * Function: createSvgSpan - * - * Updates the path for the given SVG node. - */ -mxRhombus.prototype.updateSvgNode = function(node) -{ - var strokeWidth = Math.round(Math.max(1, this.strokewidth * this.scale)); - node.setAttribute('stroke-width', strokeWidth); - var x = this.bounds.x; - var y = this.bounds.y; - var w = this.bounds.width; - var h = this.bounds.height; - var d = 'M ' + Math.round(x + w / 2) + ' ' + Math.round(y) + ' L ' + Math.round(x + w) + ' ' + Math.round(y + h / 2) + - ' L ' + Math.round(x + w / 2) + ' ' + Math.round(y + h) + ' L ' + Math.round(x) + ' ' + Math.round(y + h / 2) + - ' Z '; - node.setAttribute('d', d); - this.updateSvgTransform(node, node == this.shadowNode); - - if (this.isDashed) - { - var phase = Math.max(1, Math.round(3 * this.scale * this.strokewidth)); - node.setAttribute('stroke-dasharray', phase + ' ' + phase); - } -}; diff --git a/src/js/shape/mxShape.js b/src/js/shape/mxShape.js deleted file mode 100644 index 44ba3e7..0000000 --- a/src/js/shape/mxShape.js +++ /dev/null @@ -1,2045 +0,0 @@ -/** - * $Id: mxShape.js,v 1.173 2012-07-31 11:46:53 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -/** - * Class: mxShape - * - * Base class for all shapes. A shape in mxGraph is a - * separate implementation for SVG, VML and HTML. Which - * implementation to use is controlled by the <dialect> - * property which is assigned from within the <mxCellRenderer> - * when the shape is created. The dialect must be assigned - * for a shape, and it does normally depend on the browser and - * the confiuration of the graph (see <mxGraph> rendering hint). - * - * For each supported shape in SVG and VML, a corresponding - * shape exists in mxGraph, namely for text, image, rectangle, - * rhombus, ellipse and polyline. The other shapes are a - * combination of these shapes (eg. label and swimlane) - * or they consist of one or more (filled) path objects - * (eg. actor and cylinder). The HTML implementation is - * optional but may be required for a HTML-only view of - * the graph. - * - * Custom Shapes: - * - * To extend from this class, the basic code looks as follows. - * In the special case where the custom shape consists only of - * one filled region or one filled region and an additional stroke - * the <mxActor> and <mxCylinder> should be subclassed, - * respectively. These implement <redrawPath> in order to create - * the path expression for VML and SVG via a unified API (see - * <mxPath>). <mxCylinder.redrawPath> has an additional boolean - * argument to draw the foreground and background separately. - * - * (code) - * function CustomShape() { } - * - * CustomShape.prototype = new mxShape(); - * CustomShape.prototype.constructor = CustomShape; - * (end) - * - * To register a custom shape in an existing graph instance, - * one must register the shape under a new name in the graph's - * cell renderer as follows: - * - * (code) - * graph.cellRenderer.registerShape('customShape', CustomShape); - * (end) - * - * The second argument is the name of the constructor. - * - * In order to use the shape you can refer to the given name above - * in a stylesheet. For example, to change the shape for the default - * vertex style, the following code is used: - * - * (code) - * var style = graph.getStylesheet().getDefaultVertexStyle(); - * style[mxConstants.STYLE_SHAPE] = 'customShape'; - * (end) - * - * Constructor: mxShape - * - * Constructs a new shape. - */ -function mxShape() { }; - -/** - * Variable: SVG_STROKE_TOLERANCE - * - * Event-tolerance for SVG strokes (in px). Default is 8. - */ -mxShape.prototype.SVG_STROKE_TOLERANCE = 8; - -/** - * Variable: scale - * - * Holds the scale in which the shape is being painted. - */ -mxShape.prototype.scale = 1; - -/** - * Variable: dialect - * - * Holds the dialect in which the shape is to be painted. - * This can be one of the DIALECT constants in <mxConstants>. - */ -mxShape.prototype.dialect = null; - -/** - * Variable: crisp - * - * Special attribute for SVG rendering to set the shape-rendering attribute to - * crispEdges in the output. This is ignored in IE. Default is false. To - * disable antialias in IE, the explorer.css file can be changed as follows: - * - * [code] - * v\:* { - * behavior: url(#default#VML); - * antialias: false; - * } - * [/code] - */ -mxShape.prototype.crisp = false; - -/** - * Variable: roundedCrispSvg - * - * Specifies if crisp rendering should be enabled for rounded shapes. - * Default is true. - */ -mxShape.prototype.roundedCrispSvg = true; - -/** - * Variable: mixedModeHtml - * - * Specifies if <createHtml> should be used in mixed Html mode. - * Default is true. - */ -mxShape.prototype.mixedModeHtml = true; - -/** - * Variable: preferModeHtml - * - * Specifies if <createHtml> should be used in prefer Html mode. - * Default is true. - */ -mxShape.prototype.preferModeHtml = true; - -/** - * Variable: bounds - * - * Holds the <mxRectangle> that specifies the bounds of this shape. - */ -mxShape.prototype.bounds = null; - -/** - * Variable: points - * - * Holds the array of <mxPoints> that specify the points of this shape. - */ -mxShape.prototype.points = null; - -/** - * Variable: node - * - * Holds the outermost DOM node that represents this shape. - */ -mxShape.prototype.node = null; - -/** - * Variable: label - * - * Reference to the DOM node that should contain the label. This is null - * if the label should be placed inside <node> or <innerNode>. - */ -mxShape.prototype.label = null; - -/** - * Variable: innerNode - * - * Holds the DOM node that graphically represents this shape. This may be - * null if the outermost DOM <node> represents this shape. - */ -mxShape.prototype.innerNode = null; - -/** - * Variable: style - * - * Holds the style of the cell state that corresponds to this shape. This may - * be null if the shape is used directly, without a cell state. - */ -mxShape.prototype.style = null; - -/** - * Variable: startOffset - * - * Specifies the offset in pixels from the first point in <points> and - * the actual start of the shape. - */ -mxShape.prototype.startOffset = null; - -/** - * Variable: endOffset - * - * Specifies the offset in pixels from the last point in <points> and - * the actual start of the shape. - */ -mxShape.prototype.endOffset = null; - -/** - * Variable: boundingBox - * - * Contains the bounding box of the shape, that is, the smallest rectangle - * that includes all pixels of the shape. - */ -mxShape.prototype.boundingBox = null; - -/** - * Variable: vmlNodes - * - * Array if VML node names to fix in IE8 standards mode. - */ -mxShape.prototype.vmlNodes = ['node', 'strokeNode', 'fillNode', 'shadowNode']; - -/** - * Variable: vmlScale - * - * Internal scaling for VML using coordsize for better precision. - */ -mxShape.prototype.vmlScale = 1; - -/** - * Variable: strokewidth - * - * Holds the current strokewidth. Default is 1. - */ -mxShape.prototype.strokewidth = 1; - -/** - * Function: setCursor - * - * Sets the cursor on the given shape. - * - * Parameters: - * - * cursor - The cursor to be used. - */ -mxShape.prototype.setCursor = function(cursor) -{ - if (cursor == null) - { - cursor = ''; - } - - this.cursor = cursor; - - if (this.innerNode != null) - { - this.innerNode.style.cursor = cursor; - } - - if (this.node != null) - { - this.node.style.cursor = cursor; - } - - if (this.pipe != null) - { - this.pipe.style.cursor = cursor; - } -}; - -/** - * Function: getCursor - * - * Returns the current cursor. - */ -mxShape.prototype.getCursor = function() -{ - return this.cursor; -}; - -/** - * Function: init - * - * Initializes the shape by creaing the DOM node using <create> - * and adding it into the given container. - * - * Parameters: - * - * container - DOM node that will contain the shape. - */ -mxShape.prototype.init = function(container) -{ - if (this.node == null) - { - this.node = this.create(container); - - if (container != null) - { - container.appendChild(this.node); - - // Workaround for broken VML in IE8 standards mode. This gives an ID to - // each element that is referenced from this instance. After adding the - // DOM to the document, the outerHTML is overwritten to fix the VML - // rendering and the references are restored. - if (document.documentMode == 8 && mxUtils.isVml(this.node)) - { - this.reparseVml(); - } - } - } - - // Gradients are inserted late when the owner SVG element is known - if (this.insertGradientNode != null) - { - this.insertGradient(this.insertGradientNode); - this.insertGradientNode = null; - } -}; - -/** - * Function: reparseVml - * - * Forces a parsing of the outerHTML of this node and restores all references specified in <vmlNodes>. - * This is a workaround for the VML rendering bug in IE8 standards mode. - */ -mxShape.prototype.reparseVml = function() -{ - // Assigns temporary IDs to VML nodes so that references can be restored when - // inserted into the DOM as a string - for (var i = 0; i < this.vmlNodes.length; i++) - { - if (this[this.vmlNodes[i]] != null) - { - this[this.vmlNodes[i]].setAttribute('id', 'mxTemporaryReference-' + this.vmlNodes[i]); - } - } - - this.node.outerHTML = this.node.outerHTML; - - // Restores references to the actual DOM nodes - for (var i = 0; i < this.vmlNodes.length; i++) - { - if (this[this.vmlNodes[i]] != null) - { - this[this.vmlNodes[i]] = this.node.ownerDocument.getElementById('mxTemporaryReference-' + this.vmlNodes[i]); - this[this.vmlNodes[i]].removeAttribute('id'); - } - } -}; - -/** - * Function: insertGradient - * - * Inserts the given gradient node. - */ -mxShape.prototype.insertGradient = function(node) -{ - // Gradients are inserted late when the owner SVG element is known - if (node != null) - { - // Checks if the given gradient already exists inside the SVG element - // that also contains the node that represents this shape. If the gradient - // with the same ID exists in another SVG element, then this will add - // a copy of the gradient with a different ID to the SVG element and update - // the reference accordingly. This is required in Firefox because if the - // referenced fill element is removed from the DOM the shape appears black. - var count = 0; - var id = node.getAttribute('id'); - var gradient = document.getElementById(id); - - while (gradient != null && gradient.ownerSVGElement != this.node.ownerSVGElement) - { - count++; - id = node.getAttribute('id') + '-' + count; - gradient = document.getElementById(id); - } - - // According to specification, gradients should be put in a defs - // section in the first child of the owner SVG element. However, - // it turns out that gradients only work when added as follows. - if (gradient == null) - { - node.setAttribute('id', id); - this.node.ownerSVGElement.appendChild(node); - gradient = node; - } - - if (gradient != null) - { - var ref = 'url(#' + id + ')'; - var tmp = (this.innerNode != null) ? this.innerNode : this.node; - - if (tmp != null && tmp.getAttribute('fill') != ref) - { - tmp.setAttribute('fill', ref); - } - } - } -}; - -/** - * Function: isMixedModeHtml - * - * Used to determine if a shape can be rendered using <createHtml> in mixed - * mode Html without compromising the display accuracy. The default - * implementation will check if the shape is not rounded or rotated and has - * no gradient, and will use a DIV if that is the case. It will also check - * if <mxShape.mixedModeHtml> is true, which is the default settings. - * Subclassers can either override <mixedModeHtml> or this function if the - * result depends on dynamic values. The graph's dialect is available via - * <dialect>. - */ -mxShape.prototype.isMixedModeHtml = function() -{ - return this.mixedModeHtml && !this.isRounded && !this.isShadow && this.gradient == null && - mxUtils.getValue(this.style, mxConstants.STYLE_GLASS, 0) == 0 && - mxUtils.getValue(this.style, mxConstants.STYLE_ROTATION, 0) == 0; -}; - -/** - * Function: create - * - * Creates and returns the DOM node(s) for the shape in - * the given container. This implementation invokes - * <createSvg>, <createHtml> or <createVml> depending - * on the <dialect> and style settings. - * - * Parameters: - * - * container - DOM node that will contain the shape. - */ -mxShape.prototype.create = function(container) -{ - var node = null; - - if (this.dialect == mxConstants.DIALECT_SVG) - { - node = this.createSvg(); - } - else if (this.dialect == mxConstants.DIALECT_STRICTHTML || - (this.preferModeHtml && this.dialect == mxConstants.DIALECT_PREFERHTML) || - (this.isMixedModeHtml() && this.dialect == mxConstants.DIALECT_MIXEDHTML)) - { - node = this.createHtml(); - } - else - { - node = this.createVml(); - } - - return node; -}; - -/** - * Function: createHtml - * - * Creates and returns the HTML DOM node(s) to represent - * this shape. This implementation falls back to <createVml> - * so that the HTML creation is optional. - */ -mxShape.prototype.createHtml = function() -{ - var node = document.createElement('DIV'); - this.configureHtmlShape(node); - - return node; -}; - -/** - * Function: destroy - * - * Destroys the shape by removing it from the DOM and releasing the DOM - * node associated with the shape using <mxEvent.release>. - */ -mxShape.prototype.destroy = function() -{ - if (this.node != null) - { - mxEvent.release(this.node); - - if (this.node.parentNode != null) - { - this.node.parentNode.removeChild(this.node); - } - - if (this.node.glassOverlay) - { - this.node.glassOverlay.parentNode.removeChild(this.node.glassOverlay); - this.node.glassOverlay = null; - } - - this.node = null; - } -}; - -/** - * Function: apply - * - * Applies the style of the given <mxCellState> to the shape. This - * implementation assigns the following styles to local fields: - * - * - <mxConstants.STYLE_FILLCOLOR> => fill - * - <mxConstants.STYLE_GRADIENTCOLOR> => gradient - * - <mxConstants.STYLE_GRADIENT_DIRECTION> => gradientDirection - * - <mxConstants.STYLE_OPACITY> => opacity - * - <mxConstants.STYLE_STROKECOLOR> => stroke - * - <mxConstants.STYLE_STROKEWIDTH> => strokewidth - * - <mxConstants.STYLE_SHADOW> => isShadow - * - <mxConstants.STYLE_DASHED> => isDashed - * - <mxConstants.STYLE_SPACING> => spacing - * - <mxConstants.STYLE_STARTSIZE> => startSize - * - <mxConstants.STYLE_ENDSIZE> => endSize - * - <mxConstants.STYLE_ROUNDED> => isRounded - * - <mxConstants.STYLE_STARTARROW> => startArrow - * - <mxConstants.STYLE_ENDARROW> => endArrow - * - <mxConstants.STYLE_ROTATION> => rotation - * - <mxConstants.STYLE_DIRECTION> => direction - * - * This keeps a reference to the <style>. If you need to keep a reference to - * the cell, you can override this method and store a local reference to - * state.cell or the <mxCellState> itself. - * - * Parameters: - * - * state - <mxCellState> of the corresponding cell. - */ -mxShape.prototype.apply = function(state) -{ - var style = state.style; - this.style = style; - - if (style != null) - { - this.fill = mxUtils.getValue(style, mxConstants.STYLE_FILLCOLOR, this.fill); - this.gradient = mxUtils.getValue(style, mxConstants.STYLE_GRADIENTCOLOR, this.gradient); - this.gradientDirection = mxUtils.getValue(style, mxConstants.STYLE_GRADIENT_DIRECTION, this.gradientDirection); - this.opacity = mxUtils.getValue(style, mxConstants.STYLE_OPACITY, this.opacity); - this.stroke = mxUtils.getValue(style, mxConstants.STYLE_STROKECOLOR, this.stroke); - this.strokewidth = mxUtils.getNumber(style, mxConstants.STYLE_STROKEWIDTH, this.strokewidth); - this.isShadow = mxUtils.getValue(style, mxConstants.STYLE_SHADOW, this.isShadow); - this.isDashed = mxUtils.getValue(style, mxConstants.STYLE_DASHED, this.isDashed); - this.spacing = mxUtils.getValue(style, mxConstants.STYLE_SPACING, this.spacing); - this.startSize = mxUtils.getNumber(style, mxConstants.STYLE_STARTSIZE, this.startSize); - this.endSize = mxUtils.getNumber(style, mxConstants.STYLE_ENDSIZE, this.endSize); - this.isRounded = mxUtils.getValue(style, mxConstants.STYLE_ROUNDED, this.isRounded); - this.startArrow = mxUtils.getValue(style, mxConstants.STYLE_STARTARROW, this.startArrow); - this.endArrow = mxUtils.getValue(style, mxConstants.STYLE_ENDARROW, this.endArrow); - this.rotation = mxUtils.getValue(style, mxConstants.STYLE_ROTATION, this.rotation); - this.direction = mxUtils.getValue(style, mxConstants.STYLE_DIRECTION, this.direction); - - if (this.fill == 'none') - { - this.fill = null; - } - - if (this.gradient == 'none') - { - this.gradient = null; - } - - if (this.stroke == 'none') - { - this.stroke = null; - } - } -}; - -/** - * Function: createSvgGroup - * - * Creates a SVG group element and adds the given shape as a child of the - * element. The child is stored in <innerNode> for later access. - */ -mxShape.prototype.createSvgGroup = function(shape) -{ - var g = document.createElementNS(mxConstants.NS_SVG, 'g'); - - // Creates the shape inside an svg group - this.innerNode = document.createElementNS(mxConstants.NS_SVG, shape); - this.configureSvgShape(this.innerNode); - - // Avoids anti-aliasing for non-rounded rectangles with a - // strokewidth of 1 or more pixels - if (shape == 'rect' && this.strokewidth * this.scale >= 1 && !this.isRounded) - { - this.innerNode.setAttribute('shape-rendering', 'optimizeSpeed'); - } - - // Creates the shadow - this.shadowNode = this.createSvgShadow(this.innerNode); - - if (this.shadowNode != null) - { - g.appendChild(this.shadowNode); - } - - // Appends the main shape after the shadow - g.appendChild(this.innerNode); - - return g; -}; - -/** - * Function: createSvgShadow - * - * Creates a clone of the given node and configures the node's color - * to use <mxConstants.SHADOWCOLOR>. - */ -mxShape.prototype.createSvgShadow = function(node) -{ - if (this.isShadow) - { - var shadow = node.cloneNode(true); - shadow.setAttribute('opacity', mxConstants.SHADOW_OPACITY); - - if (this.fill != null && this.fill != mxConstants.NONE) - { - shadow.setAttribute('fill', mxConstants.SHADOWCOLOR); - } - - if (this.stroke != null && this.stroke != mxConstants.NONE) - { - shadow.setAttribute('stroke', mxConstants.SHADOWCOLOR); - } - - return shadow; - } - - return null; -}; - -/** - * Function: configureHtmlShape - * - * Configures the specified HTML node by applying the current color, - * bounds, shadow, opacity etc. - */ -mxShape.prototype.configureHtmlShape = function(node) -{ - if (mxUtils.isVml(node)) - { - this.configureVmlShape(node); - } - else - { - node.style.position = 'absolute'; - node.style.overflow = 'hidden'; - var color = this.stroke; - - if (color != null && color != mxConstants.NONE) - { - node.style.borderColor = color; - - if (this.isDashed) - { - node.style.borderStyle = 'dashed'; - } - else if (this.strokewidth > 0) - { - node.style.borderStyle = 'solid'; - } - - node.style.borderWidth = Math.ceil(this.strokewidth * this.scale) + 'px'; - } - else - { - node.style.borderWidth = '0px'; - } - - color = this.fill; - node.style.background = ''; - - if (color != null && color != mxConstants.NONE) - { - node.style.backgroundColor = color; - } - else if (this.points == null) - { - this.configureTransparentBackground(node); - } - - if (this.opacity != null) - { - mxUtils.setOpacity(node, this.opacity); - } - } -}; - -/** - * Function: updateVmlFill - * - * Updates the given VML fill node. - */ -mxShape.prototype.updateVmlFill = function(node, c1, c2, dir, alpha) -{ - node.color = c1; - - if (alpha != null && alpha != 100) - { - node.opacity = alpha + '%'; - - if (c2 != null) - { - // LATER: Set namespaced attribute without using setAttribute - // which is required for updating the value in IE8 standards. - node.setAttribute('o:opacity2', alpha + '%'); - } - } - - if (c2 != null) - { - node.type = 'gradient'; - node.color2 = c2; - var angle = '180'; - - if (this.gradientDirection == mxConstants.DIRECTION_EAST) - { - angle = '270'; - } - else if (this.gradientDirection == mxConstants.DIRECTION_WEST) - { - angle = '90'; - } - else if (this.gradientDirection == mxConstants.DIRECTION_NORTH) - { - angle = '0'; - } - - node.angle = angle; - } -}; - -/** - * Function: updateVmlStrokeNode - * - * Creates the stroke node for VML. - */ -mxShape.prototype.updateVmlStrokeNode = function(parent) -{ - // Stroke node is always needed to specify defaults that match SVG output - if (this.strokeNode == null) - { - this.strokeNode = document.createElement('v:stroke'); - - // To math SVG defaults jointsyle miter and miterlimit 4 - this.strokeNode.joinstyle = 'miter'; - this.strokeNode.miterlimit = 4; - - parent.appendChild(this.strokeNode); - } - - if (this.opacity != null) - { - this.strokeNode.opacity = this.opacity + '%'; - } - - this.updateVmlDashStyle(); -}; - -/** - * Function: updateVmlStrokeColor - * - * Updates the VML stroke color for the given node. - */ -mxShape.prototype.updateVmlStrokeColor = function(node) -{ - var color = this.stroke; - - if (color != null && color != mxConstants.NONE) - { - node.stroked = 'true'; - node.strokecolor = color; - } - else - { - node.stroked = 'false'; - } -}; - -/** - * Function: configureVmlShape - * - * Configures the specified VML node by applying the current color, - * bounds, shadow, opacity etc. - */ -mxShape.prototype.configureVmlShape = function(node) -{ - node.style.position = 'absolute'; - this.updateVmlStrokeColor(node); - node.style.background = ''; - var color = this.fill; - - if (color != null && color != mxConstants.NONE) - { - if (this.fillNode == null) - { - this.fillNode = document.createElement('v:fill'); - node.appendChild(this.fillNode); - } - - this.updateVmlFill(this.fillNode, color, this.gradient, this.gradientDirection, this.opacity); - } - else - { - node.filled = 'false'; - - if (this.points == null) - { - this.configureTransparentBackground(node); - } - } - - this.updateVmlStrokeNode(node); - - if (this.isShadow) - { - this.createVmlShadow(node); - } - - // Fixes possible hang in IE when arcsize is set on non-rects - if (node.nodeName == 'roundrect') - { - // Workaround for occasional "member not found" error - try - { - var f = mxConstants.RECTANGLE_ROUNDING_FACTOR * 100; - - if (this.style != null) - { - f = mxUtils.getValue(this.style, mxConstants.STYLE_ARCSIZE, f); - } - - node.setAttribute('arcsize', String(f) + '%'); - } - catch (e) - { - // ignore - } - } -}; - -/** - * Function: createVmlShadow - * - * Creates the VML shadow node. - */ -mxShape.prototype.createVmlShadow = function(node) -{ - // Adds a shadow only once per shape - if (this.shadowNode == null) - { - this.shadowNode = document.createElement('v:shadow'); - this.shadowNode.on = 'true'; - this.shadowNode.color = mxConstants.SHADOWCOLOR; - this.shadowNode.opacity = (mxConstants.SHADOW_OPACITY * 100) + '%'; - - this.shadowStrokeNode = document.createElement('v:stroke'); - this.shadowNode.appendChild(this.shadowStrokeNode); - - node.appendChild(this.shadowNode); - } -}; - -/** - * Function: configureTransparentBackground - * - * Hook to make the background of a shape transparent. This hook was added as - * a workaround for the "display non secure items" warning dialog in IE which - * appears if the background:url(transparent.gif) is used in the overlay pane - * of a diagram. Since only mxImageShapes currently exist in the overlay pane - * this function is only overridden in mxImageShape. - */ -mxShape.prototype.configureTransparentBackground = function(node) -{ - node.style.background = 'url(\'' + mxClient.imageBasePath + '/transparent.gif\')'; -}; - -/** - * Function: configureSvgShape - * - * Configures the specified SVG node by applying the current color, - * bounds, shadow, opacity etc. - */ -mxShape.prototype.configureSvgShape = function(node) -{ - var color = this.stroke; - - if (color != null && color != mxConstants.NONE) - { - node.setAttribute('stroke', color); - } - else - { - node.setAttribute('stroke', 'none'); - } - - color = this.fill; - - if (color != null && color != mxConstants.NONE) - { - // Fetches a reference to a shared gradient - if (this.gradient != null) - { - var id = this.getGradientId(color, this.gradient); - - if (this.gradientNode != null && this.gradientNode.getAttribute('id') != id) - { - this.gradientNode = null; - node.setAttribute('fill', ''); - } - - if (this.gradientNode == null) - { - this.gradientNode = this.createSvgGradient(id, - color, this.gradient, node); - node.setAttribute('fill', 'url(#'+id+')'); - } - } - else - { - // TODO: Remove gradient from document if no longer shared - this.gradientNode = null; - node.setAttribute('fill', color); - } - } - else - { - node.setAttribute('fill', 'none'); - } - - if (this.opacity != null) - { - // Improves opacity performance in Firefox - node.setAttribute('fill-opacity', this.opacity / 100); - node.setAttribute('stroke-opacity', this.opacity / 100); - } -}; - -/** - * Function: getGradientId - * - * Creates a unique ID for the gradient of this shape. - */ -mxShape.prototype.getGradientId = function(start, end) -{ - // Removes illegal characters from gradient ID - if (start.charAt(0) == '#') - { - start = start.substring(1); - } - - if (end.charAt(0) == '#') - { - end = end.substring(1); - } - - // Workaround for gradient IDs not working in Safari 5 / Chrome 6 - // if they contain uppercase characters - start = start.toLowerCase(); - end = end.toLowerCase(); - - var dir = null; - - if (this.gradientDirection == null || - this.gradientDirection == mxConstants.DIRECTION_SOUTH) - { - dir = 'south'; - } - else if (this.gradientDirection == mxConstants.DIRECTION_EAST) - { - dir = 'east'; - } - else - { - var tmp = start; - start = end; - end = tmp; - - if (this.gradientDirection == mxConstants.DIRECTION_NORTH) - { - dir = 'south'; - } - else if (this.gradientDirection == mxConstants.DIRECTION_WEST) - { - dir = 'east'; - } - } - - return 'mx-gradient-'+start+'-'+end+'-'+dir; -}; - -/** - * Function: createSvgPipe - * - * Creates an invisible path which is used to increase the hit detection for - * edges in SVG. - */ -mxShape.prototype.createSvgPipe = function(id, start, end, node) -{ - var pipe = document.createElementNS(mxConstants.NS_SVG, 'path'); - pipe.setAttribute('pointer-events', 'stroke'); - pipe.setAttribute('fill', 'none'); - pipe.setAttribute('visibility', 'hidden'); - // Workaround for Opera ignoring the visiblity attribute above while - // other browsers need a stroke color to perform the hit-detection but - // do not ignore the visibility attribute. Side-effect is that Opera's - // hit detection for horizontal/vertical edges seems to ignore the pipe. - pipe.setAttribute('stroke', (mxClient.IS_OP) ? 'none' : 'white'); - - return pipe; -}; - -/** - * Function: createSvgGradient - * - * Creates a gradient object for SVG using the specified startcolor, - * endcolor and opacity. - */ -mxShape.prototype.createSvgGradient = function(id, start, end, node) -{ - var gradient = this.insertGradientNode; - - if (gradient == null) - { - gradient = document.createElementNS(mxConstants.NS_SVG, 'linearGradient'); - gradient.setAttribute('id', id); - gradient.setAttribute('x1', '0%'); - gradient.setAttribute('y1', '0%'); - gradient.setAttribute('x2', '0%'); - gradient.setAttribute('y2', '0%'); - - if (this.gradientDirection == null || - this.gradientDirection == mxConstants.DIRECTION_SOUTH) - { - gradient.setAttribute('y2', '100%'); - } - else if (this.gradientDirection == mxConstants.DIRECTION_EAST) - { - gradient.setAttribute('x2', '100%'); - } - else if (this.gradientDirection == mxConstants.DIRECTION_NORTH) - { - gradient.setAttribute('y1', '100%'); - } - else if (this.gradientDirection == mxConstants.DIRECTION_WEST) - { - gradient.setAttribute('x1', '100%'); - } - - var stop = document.createElementNS(mxConstants.NS_SVG, 'stop'); - stop.setAttribute('offset', '0%'); - stop.setAttribute('style', 'stop-color:'+start); - gradient.appendChild(stop); - - stop = document.createElementNS(mxConstants.NS_SVG, 'stop'); - stop.setAttribute('offset', '100%'); - stop.setAttribute('style', 'stop-color:'+end); - gradient.appendChild(stop); - } - - // Inserted later when the owner SVG element is known - this.insertGradientNode = gradient; - - return gradient; -}; - -/** - * Function: createPoints - * - * Creates a path expression using the specified commands for this.points. - * If <isRounded> is true, then the path contains curves for the corners. - */ -mxShape.prototype.createPoints = function(moveCmd, lineCmd, curveCmd, isRelative) -{ - var offsetX = (isRelative) ? this.bounds.x : 0; - var offsetY = (isRelative) ? this.bounds.y : 0; - - // Workaround for crisp shape-rendering in IE9 - var crisp = (this.crisp && this.dialect == mxConstants.DIALECT_SVG && mxClient.IS_IE) ? 0.5 : 0; - - if (isNaN(this.points[0].x) || isNaN(this.points[0].y)) - { - return null; - } - - var size = mxConstants.LINE_ARCSIZE * this.scale; - var p0 = this.points[0]; - - if (this.startOffset != null) - { - p0 = p0.clone(); - p0.x += this.startOffset.x; - p0.y += this.startOffset.y; - } - - var points = moveCmd + ' ' + (Math.round(p0.x - offsetX) + crisp) + ' ' + - (Math.round(p0.y - offsetY) + crisp) + ' '; - - for (var i = 1; i < this.points.length; i++) - { - p0 = this.points[i - 1]; - var pt = this.points[i]; - - if (isNaN(pt.x) || isNaN(pt.y)) - { - return null; - } - - if (i == this.points.length - 1 && this.endOffset != null) - { - pt = pt.clone(); - pt.x += this.endOffset.x; - pt.y += this.endOffset.y; - } - - var dx = p0.x - pt.x; - var dy = p0.y - pt.y; - - if ((this.isRounded && i < this.points.length - 1) && - (dx != 0 || dy != 0) && this.scale > 0.3) - { - // Draws a line from the last point to the current point with a spacing - // of size off the current point into direction of the last point - var dist = Math.sqrt(dx * dx + dy * dy); - var nx1 = dx * Math.min(size, dist / 2) / dist; - var ny1 = dy * Math.min(size, dist / 2) / dist; - points += lineCmd + ' ' + (Math.round(pt.x + nx1 - offsetX) + crisp) + ' ' + - (Math.round(pt.y + ny1 - offsetY) + crisp) + ' '; - - // Draws a curve from the last point to the current point with a spacing - // of size off the current point into direction of the next point - var pe = this.points[i+1]; - dx = pe.x - pt.x; - dy = pe.y - pt.y; - - dist = Math.max(1, Math.sqrt(dx * dx + dy * dy)); - - if (dist != 0) - { - var nx2 = dx * Math.min(size, dist / 2) / dist; - var ny2 = dy * Math.min(size, dist / 2) / dist; - - points += curveCmd + ' ' + Math.round(pt.x - offsetX) + ' '+ - Math.round(pt.y - offsetY) + ' ' + Math.round(pt.x - offsetX) + ',' + - Math.round(pt.y - offsetY) + ' ' + (Math.round(pt.x + nx2 - offsetX) + crisp) + ' ' + - (Math.round(pt.y + ny2 - offsetY) + crisp) + ' '; - } - } - else - { - points += lineCmd + ' ' + (Math.round(pt.x - offsetX) + crisp) + ' ' + (Math.round(pt.y - offsetY) + crisp) + ' '; - } - } - - return points; -}; - -/** - * Function: updateHtmlShape - * - * Updates the bounds or points of the specified HTML node and - * updates the inner children to reflect the changes. - */ -mxShape.prototype.updateHtmlShape = function(node) -{ - if (node != null) - { - if (mxUtils.isVml(node)) - { - this.updateVmlShape(node); - } - else - { - var sw = Math.ceil(this.strokewidth * this.scale); - node.style.borderWidth = Math.max(1, sw) + 'px'; - - if (this.bounds != null && !isNaN(this.bounds.x) && !isNaN(this.bounds.y) && - !isNaN(this.bounds.width) && !isNaN(this.bounds.height)) - { - node.style.left = Math.round(this.bounds.x - sw / 2) + 'px'; - node.style.top = Math.round(this.bounds.y - sw / 2) + 'px'; - - if (document.compatMode == 'CSS1Compat') - { - sw = -sw; - } - - node.style.width = Math.round(Math.max(0, this.bounds.width + sw)) + 'px'; - node.style.height = Math.round(Math.max(0, this.bounds.height + sw)) + 'px'; - - if (this.bounds.width == 0 || this.bounds.height == 0) - { - node.style.visibility = 'hidden'; - } - else - { - node.style.visibility = 'visible'; - } - } - } - - if (this.points != null && this.bounds != null && !mxUtils.isVml(node)) - { - if (this.divContainer == null) - { - this.divContainer = node; - } - - while (this.divContainer.firstChild != null) - { - mxEvent.release(this.divContainer.firstChild); - this.divContainer.removeChild(this.divContainer.firstChild); - } - - node.style.borderStyle = ''; - node.style.background = ''; - - if (this.points.length == 2) - { - var p0 = this.points[0]; - var pe = this.points[1]; - - var dx = pe.x - p0.x; - var dy = pe.y - p0.y; - - if (dx == 0 || dy == 0) - { - node.style.borderStyle = 'solid'; - } - else - { - node.style.width = Math.round(this.bounds.width + 1) + 'px'; - node.style.height = Math.round(this.bounds.height + 1) + 'px'; - - var length = Math.sqrt(dx * dx + dy * dy); - var dotCount = 1 + (length / (8 * this.scale)); - - var nx = dx / dotCount; - var ny = dy / dotCount; - var x = p0.x - this.bounds.x; - var y = p0.y - this.bounds.y; - - for (var i = 0; i < dotCount; i++) - { - var tmp = document.createElement('DIV'); - - tmp.style.position = 'absolute'; - tmp.style.overflow = 'hidden'; - - tmp.style.left = Math.round(x) + 'px'; - tmp.style.top = Math.round(y) + 'px'; - tmp.style.width = Math.max(1, 2 * this.scale) + 'px'; - tmp.style.height = Math.max(1, 2 * this.scale) + 'px'; - - tmp.style.backgroundColor = this.stroke; - this.divContainer.appendChild(tmp); - - x += nx; - y += ny; - } - } - } - else if (this.points.length == 3) - { - var mid = this.points[1]; - - var n = '0'; - var s = '1'; - var w = '0'; - var e = '1'; - - if (mid.x == this.bounds.x) - { - e = '0'; - w = '1'; - } - - if (mid.y == this.bounds.y) - { - n = '1'; - s = '0'; - } - - node.style.borderStyle = 'solid'; - node.style.borderWidth = n + ' ' + e + ' ' + s + ' ' + w + 'px'; - } - else - { - node.style.width = Math.round(this.bounds.width + 1) + 'px'; - node.style.height = Math.round(this.bounds.height + 1) + 'px'; - var last = this.points[0]; - - for (var i = 1; i < this.points.length; i++) - { - var next = this.points[i]; - - // TODO: Use one div for multiple lines - var tmp = document.createElement('DIV'); - - tmp.style.position = 'absolute'; - tmp.style.overflow = 'hidden'; - - tmp.style.borderColor = this.stroke; - tmp.style.borderStyle = 'solid'; - tmp.style.borderWidth = '1 0 0 1px'; - - var x = Math.min(next.x, last.x) - this.bounds.x; - var y = Math.min(next.y, last.y) - this.bounds.y; - var w = Math.max(1, Math.abs(next.x - last.x)); - var h = Math.max(1, Math.abs(next.y - last.y)); - - tmp.style.left = x + 'px'; - tmp.style.top = y + 'px'; - tmp.style.width = w + 'px'; - tmp.style.height = h + 'px'; - - this.divContainer.appendChild(tmp); - last = next; - } - } - } - } -}; - -/** - * Function: updateVmlDashStyle - * - * Updates the dashstyle in the stroke node. - */ -mxShape.prototype.updateVmlDashStyle = function() -{ - if (this.isDashed) - { - if (this.strokeNode.dashstyle != 'dash') - { - this.strokeNode.dashstyle = 'dash'; - } - } - else if (this.strokeNode.dashstyle != 'solid') - { - this.strokeNode.dashstyle = 'solid'; - } -}; - -/** - * Function: updateVmlShape - * - * Updates the bounds or points of the specified VML node and - * updates the inner children to reflect the changes. - */ -mxShape.prototype.updateVmlShape = function(node) -{ - node.strokeweight = (this.strokewidth * this.scale) + 'px'; - - // Dash pattern needs updating as it depends on strokeweight in VML - if (this.strokeNode != null) - { - this.updateVmlDashStyle(); - } - - // Updates the offset of the shadow - if (this.shadowNode != null) - { - var dx = Math.round(mxConstants.SHADOW_OFFSET_X * this.scale); - var dy = Math.round(mxConstants.SHADOW_OFFSET_Y * this.scale); - this.shadowNode.offset = dx + 'px,' + dy + 'px'; - } - - if (this.bounds != null && !isNaN(this.bounds.x) && !isNaN(this.bounds.y) && - !isNaN(this.bounds.width) && !isNaN(this.bounds.height)) - { - var f = 1; - - var w = Math.max(0, Math.round(this.bounds.width)); - var h = Math.max(0, Math.round(this.bounds.height)); - - // Groups and shapes need a coordsize - if (this.points != null || node.nodeName == 'shape' || node.nodeName == 'group') - { - var tmp = (node.parentNode.nodeName == 'group') ? 1 : this.vmlScale; - node.coordsize = (w * tmp) + ',' + (h * tmp); - } - else if (node.parentNode.nodeName == 'group') - { - f = this.vmlScale; - } - - // Only top-level nodes are non-relative and rotated - if (node.parentNode != this.node) - { - node.style.left = Math.round(this.bounds.x * f) + 'px'; - node.style.top = Math.round(this.bounds.y * f) + 'px'; - - if (this.points == null) - { - if (this.rotation != null && this.rotation != 0) - { - node.style.rotation = this.rotation; - } - else if (node.style.rotation != null) - { - node.style.rotation = ''; - } - } - } - - node.style.width = (w * f) + 'px'; - node.style.height = (h * f) + 'px'; - } - - if (this.points != null && node.nodeName != 'group') - { - if (node.nodeName == 'polyline' && node.points != null) - { - var points = ''; - - for (var i = 0; i < this.points.length; i++) - { - points += this.points[i].x + ',' + this.points[i].y + ' '; - } - - node.points.value = points; - - node.style.left = null; - node.style.top = null; - node.style.width = null; - node.style.height = null; - } - else if (this.bounds != null) - { - var points = this.createPoints('m', 'l', 'c', true); - - // Smooth style for VML (experimental) - if (this.style != null && this.style[mxConstants.STYLE_SMOOTH]) - { - var pts = this.points; - var n = pts.length; - - if (n > 3) - { - var x0 = this.bounds.x; - var y0 = this.bounds.y; - points = 'm ' + Math.round(pts[0].x - x0) + ' ' + Math.round(pts[0].y - y0) + ' qb'; - - for (var i = 1; i < n - 1; i++) - { - points += ' ' + Math.round(pts[i].x - x0) + ' ' + Math.round(pts[i].y - y0); - } - - points += ' nf l ' + Math.round(pts[n - 1].x - x0) + ' ' + Math.round(pts[n - 1].y - y0); - } - } - - node.path = points + ' e'; - } - } -}; - -/** - * Function: updateSvgBounds - * - * Updates the bounds of the given node using <bounds>. - */ -mxShape.prototype.updateSvgBounds = function(node) -{ - var w = this.bounds.width; - var h = this.bounds.height; - - if (this.isRounded && !(this.crisp && mxClient.IS_IE)) - { - node.setAttribute('x', this.bounds.x); - node.setAttribute('y', this.bounds.y); - node.setAttribute('width', w); - node.setAttribute('height', h); - } - else - { - // Workaround for crisp shape-rendering in IE9 - var dd = (this.crisp && mxClient.IS_IE) ? 0.5 : 0; - node.setAttribute('x', Math.round(this.bounds.x) + dd); - node.setAttribute('y', Math.round(this.bounds.y) + dd); - - w = Math.round(w); - h = Math.round(h); - - node.setAttribute('width', w); - node.setAttribute('height', h); - } - - if (this.isRounded) - { - var f = mxConstants.RECTANGLE_ROUNDING_FACTOR * 100; - - if (this.style != null) - { - f = mxUtils.getValue(this.style, mxConstants.STYLE_ARCSIZE, f) / 100; - } - - var r = Math.min(w * f, h * f); - node.setAttribute('rx', r); - node.setAttribute('ry', r); - } - - this.updateSvgTransform(node, node == this.shadowNode); -}; - -/** - * Function: updateSvgPath - * - * Updates the path of the given node using <points>. - */ -mxShape.prototype.updateSvgPath = function(node) -{ - var d = this.createPoints('M', 'L', 'C', false); - - if (d != null) - { - node.setAttribute('d', d); - - // Smooth style for SVG (experimental) - if (this.style != null && this.style[mxConstants.STYLE_SMOOTH]) - { - var pts = this.points; - var n = pts.length; - - if (n > 3) - { - var points = 'M '+pts[0].x+' '+pts[0].y+' '; - points += ' Q '+pts[1].x + ' ' + pts[1].y + ' ' + - ' '+pts[2].x + ' ' + pts[2].y; - - for (var i = 3; i < n; i++) - { - points += ' T ' + pts[i].x + ' ' + pts[i].y; - } - - node.setAttribute('d', points); - } - } - - node.removeAttribute('x'); - node.removeAttribute('y'); - node.removeAttribute('width'); - node.removeAttribute('height'); - } -}; - -/** - * Function: updateSvgScale - * - * Updates the properties of the given node that depend on the scale and checks - * the crisp rendering attribute. - */ -mxShape.prototype.updateSvgScale = function(node) -{ - node.setAttribute('stroke-width', Math.round(Math.max(1, this.strokewidth * this.scale))); - - if (this.isDashed) - { - var phase = Math.max(1, Math.round(3 * this.scale * this.strokewidth)); - node.setAttribute('stroke-dasharray', phase + ' ' + phase); - } - - if (this.crisp && (this.roundedCrispSvg || this.isRounded != true) && - (this.rotation == null || this.rotation == 0)) - { - node.setAttribute('shape-rendering', 'crispEdges'); - } - else - { - node.removeAttribute('shape-rendering'); - } -}; - -/** - * Function: updateSvgShape - * - * Updates the bounds or points of the specified SVG node and - * updates the inner children to reflect the changes. - */ -mxShape.prototype.updateSvgShape = function(node) -{ - if (this.points != null && this.points[0] != null) - { - this.updateSvgPath(node); - } - else if (this.bounds != null) - { - this.updateSvgBounds(node); - } - - this.updateSvgScale(node); -}; - -/** - * Function: getSvgShadowTransform - * - * Returns the current transformation for SVG shadows. - */ -mxShape.prototype.getSvgShadowTransform = function(node, shadow) -{ - var dx = mxConstants.SHADOW_OFFSET_X * this.scale; - var dy = mxConstants.SHADOW_OFFSET_Y * this.scale; - - return 'translate(' + dx + ' ' + dy + ')'; -}; - -/** - * Function: updateSvgTransform - * - * Updates the tranform of the given node. - */ -mxShape.prototype.updateSvgTransform = function(node, shadow) -{ - var st = (shadow) ? this.getSvgShadowTransform() : ''; - - if (this.rotation != null && this.rotation != 0) - { - var cx = this.bounds.x + this.bounds.width / 2; - var cy = this.bounds.y + this.bounds.height / 2; - node.setAttribute('transform', 'rotate(' + this.rotation + ',' + cx + ',' + cy + ') ' + st); - } - else - { - if (shadow) - { - node.setAttribute('transform', st); - } - else - { - node.removeAttribute('transform'); - } - } -}; - -/** - * Function: reconfigure - * - * Reconfigures this shape. This will update the colors etc in - * addition to the bounds or points. - */ -mxShape.prototype.reconfigure = function() -{ - if (this.dialect == mxConstants.DIALECT_SVG) - { - if (this.innerNode != null) - { - this.configureSvgShape(this.innerNode); - } - else - { - this.configureSvgShape(this.node); - } - - if (this.insertGradientNode != null) - { - this.insertGradient(this.insertGradientNode); - this.insertGradientNode = null; - } - } - else if (mxUtils.isVml(this.node)) - { - this.node.style.visibility = 'hidden'; - this.configureVmlShape(this.node); - this.node.style.visibility = 'visible'; - } - else - { - this.node.style.visibility = 'hidden'; - this.configureHtmlShape(this.node); - this.node.style.visibility = 'visible'; - } -}; - -/** - * Function: redraw - * - * Invokes <redrawSvg>, <redrawVml> or <redrawHtml> depending on the - * dialect of the shape. - */ -mxShape.prototype.redraw = function() -{ - this.updateBoundingBox(); - - if (this.dialect == mxConstants.DIALECT_SVG) - { - this.redrawSvg(); - } - else if (mxUtils.isVml(this.node)) - { - this.node.style.visibility = 'hidden'; - this.redrawVml(); - this.node.style.visibility = 'visible'; - } - else - { - this.redrawHtml(); - } -}; - -/** - * Function: updateBoundingBox - * - * Updates the <boundingBox> for this shape using <createBoundingBox> and - * <augmentBoundingBox> and stores the result in <boundingBox>. - */ -mxShape.prototype.updateBoundingBox = function() -{ - if (this.bounds != null) - { - var bbox = this.createBoundingBox(); - this.augmentBoundingBox(bbox); - - var rot = Number(mxUtils.getValue(this.style, mxConstants.STYLE_ROTATION, 0)); - - if (rot != 0) - { - bbox = mxUtils.getBoundingBox(bbox, rot); - } - - bbox.x = Math.floor(bbox.x); - bbox.y = Math.floor(bbox.y); - // TODO: Fix rounding errors - bbox.width = Math.ceil(bbox.width); - bbox.height = Math.ceil(bbox.height); - - this.boundingBox = bbox; - } -}; - -/** - * Function: createBoundingBox - * - * Returns a new rectangle that represents the bounding box of the bare shape - * with no shadows or strokewidths. - */ -mxShape.prototype.createBoundingBox = function() -{ - return this.bounds.clone(); -}; - -/** - * Function: augmentBoundingBox - * - * Augments the bounding box with the strokewidth and shadow offsets. - */ -mxShape.prototype.augmentBoundingBox = function(bbox) -{ - if (this.isShadow) - { - bbox.width += Math.ceil(mxConstants.SHADOW_OFFSET_X * this.scale); - bbox.height += Math.ceil(mxConstants.SHADOW_OFFSET_Y * this.scale); - } - - // Adds strokeWidth - var sw = Math.ceil(this.strokewidth * this.scale); - bbox.grow(Math.ceil(sw / 2)); -}; - -/** - * Function: redrawSvg - * - * Redraws this SVG shape by invoking <updateSvgShape> on this.node, - * this.innerNode and this.shadowNode. - */ -mxShape.prototype.redrawSvg = function() -{ - if (this.innerNode != null) - { - this.updateSvgShape(this.innerNode); - - if (this.shadowNode != null) - { - this.updateSvgShape(this.shadowNode); - } - } - else - { - this.updateSvgShape(this.node); - - // Updates the transform of the shadow - if (this.shadowNode != null) - { - this.shadowNode.setAttribute('transform', this.getSvgShadowTransform()); - } - } - - this.updateSvgGlassPane(); -}; - -/** - * Function: updateVmlGlassPane - * - * Draws the glass overlay if mxConstants.STYLE_GLASS is 1. - */ -mxShape.prototype.updateVmlGlassPane = function() -{ - // Currently only used in mxLabel. Most shapes would have to be changed to use - // a group node in VML which might affect performance for glass-less cells. - if (this.bounds != null && this.node.nodeName == 'group' && this.style != null && - mxUtils.getValue(this.style, mxConstants.STYLE_GLASS, 0) == 1) - { - // Glass overlay - if (this.node.glassOverlay == null) - { - // Creates glass overlay - this.node.glassOverlay = document.createElement('v:shape'); - this.node.glassOverlay.setAttribute('filled', 'true'); - this.node.glassOverlay.setAttribute('fillcolor', 'white'); - this.node.glassOverlay.setAttribute('stroked', 'false'); - - var fillNode = document.createElement('v:fill'); - fillNode.setAttribute('type', 'gradient'); - fillNode.setAttribute('color', 'white'); - fillNode.setAttribute('color2', 'white'); - fillNode.setAttribute('opacity', '90%'); - fillNode.setAttribute('o:opacity2', '15%'); - fillNode.setAttribute('angle', '180'); - - this.node.glassOverlay.appendChild(fillNode); - this.node.appendChild(this.node.glassOverlay); - } - - var size = 0.4; - - // TODO: Mask with rectangle or rounded rectangle of label - var b = this.bounds; - var sw = Math.ceil(this.strokewidth * this.scale / 2 + 1); - var d = 'm ' + (-sw) + ' ' + (-sw) + ' l ' + (-sw) + ' ' + Math.round(b.height * size) + - ' c ' + Math.round(b.width * 0.3) + ' ' + Math.round(b.height * 0.6) + - ' ' + Math.round(b.width * 0.7) + ' ' + Math.round(b.height * 0.6) + - ' ' + Math.round(b.width + sw) + ' ' + Math.round(b.height * size) + - ' l '+Math.round(b.width + sw)+' ' + (-sw) + ' x e'; - this.node.glassOverlay.style.position = 'absolute'; - this.node.glassOverlay.style.width = b.width + 'px'; - this.node.glassOverlay.style.height = b.height + 'px'; - this.node.glassOverlay.setAttribute('coordsize', - Math.round(this.bounds.width) + ',' + - Math.round(this.bounds.height)); - this.node.glassOverlay.setAttribute('path', d); - } - else if (this.node.glassOverlay != null) - { - this.node.glassOverlay.parentNode.removeChild(this.node.glassOverlay); - this.node.glassOverlay = null; - } -}; - -/** - * Function: updateSvgGlassPane - * - * Draws the glass overlay if mxConstants.STYLE_GLASS is 1. - */ -mxShape.prototype.updateSvgGlassPane = function() -{ - if (this.node.nodeName == 'g' && this.style != null && - mxUtils.getValue(this.style, mxConstants.STYLE_GLASS, 0) == 1) - { - // Glass overlay - if (this.node.glassOverlay == null) - { - // Glass overlay gradient - if (this.node.ownerSVGElement.glassGradient == null) - { - // Creates glass overlay gradient - var glassGradient = document.createElementNS(mxConstants.NS_SVG, 'linearGradient'); - glassGradient.setAttribute('x1', '0%'); - glassGradient.setAttribute('y1', '0%'); - glassGradient.setAttribute('x2', '0%'); - glassGradient.setAttribute('y2', '100%'); - - var stop1 = document.createElementNS(mxConstants.NS_SVG, 'stop'); - stop1.setAttribute('offset', '0%'); - stop1.setAttribute('style', 'stop-color:#ffffff;stop-opacity:0.9'); - glassGradient.appendChild(stop1); - - var stop2 = document.createElementNS(mxConstants.NS_SVG, 'stop'); - stop2.setAttribute('offset', '100%'); - stop2.setAttribute('style', 'stop-color:#ffffff;stop-opacity:0.1'); - glassGradient.appendChild(stop2); - - // Finds a unique ID for the gradient - var prefix = 'mx-glass-gradient-'; - var counter = 0; - - while (document.getElementById(prefix+counter) != null) - { - counter++; - } - - glassGradient.setAttribute('id', prefix+counter); - this.node.ownerSVGElement.appendChild(glassGradient); - this.node.ownerSVGElement.glassGradient = glassGradient; - } - - // Creates glass overlay - this.node.glassOverlay = document.createElementNS(mxConstants.NS_SVG, 'path'); - // LATER: Not sure what the behaviour is for mutiple SVG elements in page. - // Probably its possible that this points to an element in another SVG - // node which when removed will result in an undefined background. - var id = this.node.ownerSVGElement.glassGradient.getAttribute('id'); - this.node.glassOverlay.setAttribute('style', 'fill:url(#'+id+');'); - this.node.appendChild(this.node.glassOverlay); - } - - var size = 0.4; - - // TODO: Mask with rectangle or rounded rectangle of label - var b = this.bounds; - var sw = Math.ceil(this.strokewidth * this.scale / 2); - var d = 'm ' + (b.x - sw) + ',' + (b.y - sw) + - ' L ' + (b.x - sw) + ',' + (b.y + b.height * size) + - ' Q '+ (b.x + b.width * 0.5) + ',' + (b.y + b.height * 0.7) + ' '+ - (b.x + b.width + sw) + ',' + (b.y + b.height * size) + - ' L ' + (b.x + b.width + sw) + ',' + (b.y - sw) + ' z'; - this.node.glassOverlay.setAttribute('d', d); - } - else if (this.node.glassOverlay != null) - { - this.node.glassOverlay.parentNode.removeChild(this.node.glassOverlay); - this.node.glassOverlay = null; - } -}; - -/** - * Function: redrawVml - * - * Redraws this VML shape by invoking <updateVmlShape> on this.node. - */ -mxShape.prototype.redrawVml = function() -{ - this.node.style.visibility = 'hidden'; - this.updateVmlShape(this.node); - this.updateVmlGlassPane(); - this.node.style.visibility = 'visible'; -}; - -/** - * Function: redrawHtml - * - * Redraws this HTML shape by invoking <updateHtmlShape> on this.node. - */ -mxShape.prototype.redrawHtml = function() -{ - this.updateHtmlShape(this.node); -}; - -/** - * Function: getRotation - * - * Returns the current rotation including direction. - */ -mxShape.prototype.getRotation = function() -{ - var rot = this.rotation || 0; - - // Default direction is east (ignored if rotation exists) - if (this.direction != null) - { - if (this.direction == 'north') - { - rot += 270; - } - else if (this.direction == 'west') - { - rot += 180; - } - else if (this.direction == 'south') - { - rot += 90; - } - } - - return rot; -}; - -/** - * Function: createPath - * - * Creates an <mxPath> for the specified format and origin. The path object is - * then passed to <redrawPath> and <mxPath.getPath> is returned. - */ -mxShape.prototype.createPath = function(arg) -{ - var x = this.bounds.x; - var y = this.bounds.y; - var w = this.bounds.width; - var h = this.bounds.height; - var dx = 0; - var dy = 0; - - // Inverts bounds for stencils which are rotated 90 or 270 degrees - if (this.direction == 'north' || this.direction == 'south') - { - dx = (w - h) / 2; - dy = (h - w) / 2; - x += dx; - y += dy; - var tmp = w; - w = h; - h = tmp; - } - - var rotation = this.getRotation(); - var path = null; - - if (this.dialect == mxConstants.DIALECT_SVG) - { - path = new mxPath('svg'); - path.setTranslate(x, y); - - // Adds rotation as a separate transform - if (rotation != 0) - { - var cx = this.bounds.getCenterX(); - var cy = this.bounds.getCenterY(); - var transform = 'rotate(' + rotation + ' ' + cx + ' ' + cy + ')'; - - if (this.innerNode != null) - { - this.innerNode.setAttribute('transform', transform); - } - - if (this.foreground != null) - { - this.foreground.setAttribute('transform', transform); - } - - // Shadow needs different transform so that it ends up on the correct side - if (this.shadowNode != null) - { - this.shadowNode.setAttribute('transform', this.getSvgShadowTransform() + ' ' + transform); - } - } - } - else - { - path = new mxPath('vml'); - path.setTranslate(dx, -dx); - path.scale = this.vmlScale; - - if (rotation != 0) - { - this.node.style.rotation = rotation; - } - } - - this.redrawPath(path, x, y, w, h, arg); - - return path.getPath(); -}; - -/** - * Function: redrawPath - * - * Draws the path for this shape. This implementation is empty. See - * <mxActor> and <mxCylinder> for implementations. - */ -mxShape.prototype.redrawPath = function(path, x, y, w, h) -{ - // do nothing -}; diff --git a/src/js/shape/mxStencil.js b/src/js/shape/mxStencil.js deleted file mode 100644 index d0e1a63..0000000 --- a/src/js/shape/mxStencil.js +++ /dev/null @@ -1,1585 +0,0 @@ -/** - * $Id: mxStencil.js,v 1.91 2012-07-16 10:22:44 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -/** - * Class: mxStencil - * - * Implements a generic shape which is based on a XML node as a description. - * The node contains a background and a foreground node, which contain the - * definition to render the respective part of the shape. Note that the - * fill, stroke or fillstroke of the background is be the first statement - * of the foreground. This is because the content of the background node - * maybe used to not only render the shape itself, but also its shadow and - * other elements which do not require a fill, stroke or fillstroke. - * - * The shape uses a coordinate system with a width of 100 and a height of - * 100 by default. This can be changed by setting the w and h attribute of - * the shape element. The aspect attribute can be set to "variable" (default) - * or "fixed". If fixed is used, then the aspect which is defined via the w - * and h attribute is kept constant while the shape is scaled. - * - * The possible contents of the background and foreground elements are rect, - * ellipse, roundrect, text, image, include-shape or paths. A path element - * contains move, line, curve, quad, arc and close elements. The rect, ellipse - * and roundrect elements may be thought of as special path elements. All these - * path elements must be followed by either fill, stroke or fillstroke (note - * that text, image and include-shape or not path elements). - * - * The background element can be empty or contain at most one path element. It - * should not contain a text, image or include-shape element. If the background - * element is empty, then no shadow or glass effect will be rendered. If the - * background element is non-empty, then the corresponding fill, stroke or - * fillstroke should be the first element in the subsequent foreground element. - * - * The format of the XML is "a simplified HTML 5 Canvas". Each command changes - * the "current" state, so eg. a linecap, linejoin will be used for all - * subsequent line drawing, unless a save/restore appears, which saves/restores - * a state in a stack. - * - * The connections section contains the fixed connection points for a stencil. - * The perimeter attribute of the constraint element should have a value of 0 - * or 1 (default), where 1 (true) specifies that the given point should be - * projected into the perimeter of the given shape. - * - * The x- and y-coordinates are typically between 0 and 1 and define the - * location of the connection point relative to the width and height of the - * shape. - * - * The dashpattern directive sets the current dashpattern. The format for the - * pattern attribute is a space-separated sequence of numbers, eg. 5 5 5 5, - * that specifies the lengths of alternating dashes and spaces in dashed lines. - * The dashpattern should be used together with the dashed directive to - * enabled/disable the dashpattern. The default dashpattern is 3 3. - * - * The strokewidth attribute defines a fixed strokewidth for the shape. It - * can contain a numeric value or the keyword "inherit", which means that the - * strokeWidth from the cell's style will be used and muliplied with the shape's - * scale. If numeric values are used, those are multiplied with the minimum - * scale used to render the stencil inside the shape's bounds. - * - * Constructor: mxStencilShape - * - * Constructs a new generic shape by setting <desc> to the given XML node and - * invoking <parseDescription> and <parseConstraints>. - * - * Parameters: - * - * desc - XML node that contains the stencil description. - */ -function mxStencil(desc) -{ - this.desc = desc; - this.parseDescription(); - this.parseConstraints(); -}; - -/** - * Variable: desc - * - * Holds the XML node with the stencil description. - */ -mxStencil.prototype.desc = null; - -/** - * Variable: constraints - * - * Holds an array of <mxConnectionConstraints> as defined in the shape. - */ -mxStencil.prototype.constraints = null; - -/** - * Variable: aspect - * - * Holds the aspect of the shape. Default is 'auto'. - */ -mxStencil.prototype.aspect = null; - -/** - * Variable: w0 - * - * Holds the width of the shape. Default is 100. - */ -mxStencil.prototype.w0 = null; - -/** - * Variable: h0 - * - * Holds the height of the shape. Default is 100. - */ -mxStencil.prototype.h0 = null; - -/** - * Variable: bgNodes - * - * Holds the XML node with the stencil description. - */ -mxStencil.prototype.bgNode = null; - -/** - * Variable: fgNodes - * - * Holds the XML node with the stencil description. - */ -mxStencil.prototype.fgNode = null; - -/** - * Variable: strokewidth - * - * Holds the strokewidth direction from the description. - */ -mxStencil.prototype.strokewidth = null; - -/** - * Function: parseDescription - * - * Reads <w0>, <h0>, <aspect>, <bgNodes> and <fgNodes> from <desc>. - */ -mxStencil.prototype.parseDescription = function() -{ - // LATER: Preprocess nodes for faster painting - this.fgNode = this.desc.getElementsByTagName('foreground')[0]; - this.bgNode = this.desc.getElementsByTagName('background')[0]; - this.w0 = Number(this.desc.getAttribute('w') || 100); - this.h0 = Number(this.desc.getAttribute('h') || 100); - - // Possible values for aspect are: variable and fixed where - // variable means fill the available space and fixed means - // use w0 and h0 to compute the aspect. - var aspect = this.desc.getAttribute('aspect'); - this.aspect = (aspect != null) ? aspect : 'variable'; - - // Possible values for strokewidth are all numbers and "inherit" - // where the inherit means take the value from the style (ie. the - // user-defined stroke-width). Note that the strokewidth is scaled - // by the minimum scaling that is used to draw the shape (sx, sy). - var sw = this.desc.getAttribute('strokewidth'); - this.strokewidth = (sw != null) ? sw : '1'; -}; - -/** - * Function: parseConstraints - * - * Reads the constraints from <desc> into <constraints> using - * <parseConstraint>. - */ -mxStencil.prototype.parseConstraints = function() -{ - var conns = this.desc.getElementsByTagName('connections')[0]; - - if (conns != null) - { - var tmp = mxUtils.getChildNodes(conns); - - if (tmp != null && tmp.length > 0) - { - this.constraints = []; - - for (var i = 0; i < tmp.length; i++) - { - this.constraints.push(this.parseConstraint(tmp[i])); - } - } - } -}; - -/** - * Function: parseConstraint - * - * Parses the given XML node and returns its <mxConnectionConstraint>. - */ -mxStencil.prototype.parseConstraint = function(node) -{ - var x = Number(node.getAttribute('x')); - var y = Number(node.getAttribute('y')); - var perimeter = node.getAttribute('perimeter') == '1'; - - return new mxConnectionConstraint(new mxPoint(x, y), perimeter); -}; - -/** - * Function: evaluateAttribute - * - * Gets the attribute for the given name from the given node. If the attribute - * does not exist then the text content of the node is evaluated and if it is - * a function it is invoked with <state> as the only argument and the return - * value is used as the attribute value to be returned. - */ -mxStencil.prototype.evaluateAttribute = function(node, attribute, state) -{ - var result = node.getAttribute(attribute); - - if (result == null) - { - var text = mxUtils.getTextContent(node); - - if (text != null) - { - var funct = mxUtils.eval(text); - - if (typeof(funct) == 'function') - { - result = funct(state); - } - } - } - - return result; -}; - -/** - * Function: renderDom - * - * Updates the SVG or VML shape. - */ -mxStencil.prototype.renderDom = function(shape, bounds, parentNode, state) -{ - var vml = shape.dialect != mxConstants.DIALECT_SVG; - var vmlScale = (document.documentMode == 8) ? 1 : shape.vmlScale; - var rotation = shape.rotation || 0; - var inverse = false; - - // New styles for shape flipping the stencil - var flipH = shape.style[mxConstants.STYLE_STENCIL_FLIPH]; - var flipV = shape.style[mxConstants.STYLE_STENCIL_FLIPV]; - - if (flipH ? !flipV : flipV) - { - rotation *= -1; - } - - // Default direction is east (ignored if rotation exists) - if (shape.direction != null) - { - if (shape.direction == 'north') - { - rotation += 270; - } - else if (shape.direction == 'west') - { - rotation += 180; - } - else if (shape.direction == 'south') - { - rotation += 90; - } - - inverse = (shape.direction == 'north' || shape.direction == 'south'); - } - - if (flipH && flipV) - { - rotation += 180; - flipH = false; - flipV = false; - } - - // SVG transform should be applied on all child shapes - var svgTransform = ''; - - // Implements direction style and vertical/horizontal flip - // via container transformation. - if (vml) - { - if (flipH) - { - parentNode.style.flip = 'x'; - } - else if (flipV) - { - parentNode.style.flip = 'y'; - } - - if (rotation != 0) - { - parentNode.style.rotation = rotation; - } - } - else - { - if (flipH || flipV) - { - var sx = 1; - var sy = 1; - var dx = 0; - var dy = 0; - - if (flipH) - { - sx = -1; - dx = -bounds.width - 2 * bounds.x; - } - - if (flipV) - { - sy = -1; - dy = -bounds.height - 2 * bounds.y; - } - - svgTransform = 'scale(' + sx + ' ' + sy + ') translate(' + dx + ' ' + dy + ')'; - } - - // Adds rotation as a separate transform - if (rotation != 0) - { - var cx = bounds.getCenterX(); - var cy = bounds.getCenterY(); - svgTransform += ' rotate(' + rotation + ' ' + cx + ' ' + cy + ')'; - } - } - - var background = (state == null); - - if (this.bgNode != null || this.fgNode != null) - { - var x0 = (vml && state == null) ? 0 : bounds.x; - var y0 = (vml && state == null) ? 0 : bounds.y; - var sx = bounds.width / this.w0; - var sy = bounds.height / this.h0; - - // Stores current location inside path - this.lastMoveX = 0; - this.lastMoveY = 0; - - if (inverse) - { - sy = bounds.width / this.h0; - sx = bounds.height / this.w0; - - var delta = (bounds.width - bounds.height) / 2; - - x0 += delta; - y0 -= delta; - } - - if (this.aspect == 'fixed') - { - sy = Math.min(sx, sy); - sx = sy; - - // Centers the shape inside the available space - if (inverse) - { - x0 += (bounds.height - this.w0 * sx) / 2; - y0 += (bounds.width - this.h0 * sy) / 2; - } - else - { - x0 += (bounds.width - this.w0 * sx) / 2; - y0 += (bounds.height - this.h0 * sy) / 2; - } - } - - // Workaround to improve VML rendering precision. - if (vml) - { - sx *= vmlScale; - sy *= vmlScale; - x0 *= vmlScale; - y0 *= vmlScale; - } - - var minScale = Math.min(sx, sy); - - // Stack of states for save/restore ops - var stack = []; - - var currentState = (state != null) ? state : - { - fillColorAssigned: false, - fill: shape.fill, - stroke: shape.stroke, - strokeWidth: (this.strokewidth == 'inherit') ? - Number(shape.strokewidth) * shape.scale : - Number(this.strokewidth) * minScale / ((vml) ? vmlScale : 1), - dashed: shape.isDashed, - dashpattern: [3, 3], - alpha: shape.opacity, - linejoin: 'miter', - fontColor: '#000000', - fontSize: mxConstants.DEFAULT_FONTSIZE, - fontFamily: mxConstants.DEFAULT_FONTFAMILY, - fontStyle: 0 - }; - - var currentPath = null; - var currentPoints = null; - - var configurePath = function(path, state) - { - var sw = Math.max(1, state.strokeWidth); - - if (vml) - { - path.strokeweight = Math.round(sw) + 'px'; - - if (state.fill != null) - { - // Gradient in foregrounds not supported because special gradients - // with bounds must be created for each element in graphics-canvases - var gradient = (!state.fillColorAssigned) ? shape.gradient : null; - var fill = document.createElement('v:fill'); - shape.updateVmlFill(fill, state.fill, gradient, shape.gradientDirection, state.alpha); - path.appendChild(fill); - } - else - { - path.filled = 'false'; - } - - if (state.stroke != null) - { - path.stroked = 'true'; - path.strokecolor = state.stroke; - } - else - { - path.stroked = 'false'; - } - - path.style.position = 'absolute'; - } - else - { - path.setAttribute('stroke-width', sw); - - if (state.fill != null && state.fillColorAssigned) - { - path.setAttribute('fill', state.fill); - } - - if (state.stroke != null) - { - path.setAttribute('stroke', state.stroke); - } - } - }; - - var addToPath = function(s) - { - if (currentPath != null && currentPoints != null) - { - currentPoints.push(s); - } - }; - - var round = function(value) - { - return (vml) ? Math.round(value) : value; - }; - - // Will be moved to a hook later for example to set text values - var renderNode = function(node) - { - var name = node.nodeName; - - var fillOp = name == 'fill'; - var strokeOp = name == 'stroke'; - var fillStrokeOp = name == 'fillstroke'; - - if (name == 'save') - { - stack.push(currentState); - currentState = mxUtils.clone(currentState); - } - else if (name == 'restore') - { - currentState = stack.pop(); - } - else if (name == 'path') - { - currentPoints = []; - - if (vml) - { - currentPath = document.createElement('v:shape'); - configurePath.call(this, currentPath, currentState); - var w = Math.round(bounds.width) * vmlScale; - var h = Math.round(bounds.height) * vmlScale; - currentPath.style.width = w + 'px'; - currentPath.style.height = h + 'px'; - currentPath.coordsize = w + ',' + h; - } - else - { - currentPath = document.createElementNS(mxConstants.NS_SVG, 'path'); - configurePath.call(this, currentPath, currentState); - - if (svgTransform.length > 0) - { - currentPath.setAttribute('transform', svgTransform); - } - - if (node.getAttribute('crisp') == '1') - { - currentPath.setAttribute('shape-rendering', 'crispEdges'); - } - } - - // Renders the elements inside the given path - var childNode = node.firstChild; - - while (childNode != null) - { - if (childNode.nodeType == mxConstants.NODETYPE_ELEMENT) - { - renderNode.call(this, childNode); - } - - childNode = childNode.nextSibling; - } - - // Ends the current path - if (vml) - { - addToPath('e'); - currentPath.path = currentPoints.join(''); - } - else - { - currentPath.setAttribute('d', currentPoints.join('')); - } - } - else if (name == 'move') - { - var op = (vml) ? 'm' : 'M'; - this.lastMoveX = round(x0 + Number(node.getAttribute('x')) * sx); - this.lastMoveY = round(y0 + Number(node.getAttribute('y')) * sy); - addToPath(op + ' ' + this.lastMoveX + ' ' + this.lastMoveY); - } - else if (name == 'line') - { - var op = (vml) ? 'l' : 'L'; - this.lastMoveX = round(x0 + Number(node.getAttribute('x')) * sx); - this.lastMoveY = round(y0 + Number(node.getAttribute('y')) * sy); - addToPath(op + ' ' + this.lastMoveX + ' ' + this.lastMoveY); - } - else if (name == 'quad') - { - if (vml) - { - var cpx0 = this.lastMoveX; - var cpy0 = this.lastMoveY; - var qpx1 = x0 + Number(node.getAttribute('x1')) * sx; - var qpy1 = y0 + Number(node.getAttribute('y1')) * sy; - var cpx3 = x0 + Number(node.getAttribute('x2')) * sx; - var cpy3 = y0 + Number(node.getAttribute('y2')) * sy; - - var cpx1 = cpx0 + 2/3 * (qpx1 - cpx0); - var cpy1 = cpy0 + 2/3 * (qpy1 - cpy0); - - var cpx2 = cpx3 + 2/3 * (qpx1 - cpx3); - var cpy2 = cpy3 + 2/3 * (qpy1 - cpy3); - - addToPath('c ' + Math.round(cpx1) + ' ' + Math.round(cpy1) + ' ' + - Math.round(cpx2) + ' ' + Math.round(cpy2) + ' ' + - Math.round(cpx3) + ' ' + Math.round(cpy3)); - - this.lastMoveX = cpx3; - this.lastMoveY = cpy3; - } - else - { - this.lastMoveX = x0 + Number(node.getAttribute('x2')) * sx; - this.lastMoveY = y0 + Number(node.getAttribute('y2')) * sy; - - addToPath('Q ' + (x0 + Number(node.getAttribute('x1')) * sx) + ' ' + - (y0 + Number(node.getAttribute('y1')) * sy) + ' ' + - this.lastMoveX + ' ' + this.lastMoveY); - } - } - else if (name == 'curve') - { - var op = (vml) ? 'c' : 'C'; - this.lastMoveX = round(x0 + Number(node.getAttribute('x3')) * sx); - this.lastMoveY = round(y0 + Number(node.getAttribute('y3')) * sy); - - addToPath(op + ' ' + round(x0 + Number(node.getAttribute('x1')) * sx) + ' ' + - round(y0 + Number(node.getAttribute('y1')) * sy) + ' ' + - round(x0 + Number(node.getAttribute('x2')) * sx) + ' ' + - round(y0 + Number(node.getAttribute('y2')) * sy) + ' ' + - this.lastMoveX + ' ' + this.lastMoveY); - } - else if (name == 'close') - { - addToPath((vml) ? 'x' : 'Z'); - } - else if (name == 'rect' || name == 'roundrect') - { - var rounded = name == 'roundrect'; - var x = round(x0 + Number(node.getAttribute('x')) * sx); - var y = round(y0 + Number(node.getAttribute('y')) * sy); - var w = round(Number(node.getAttribute('w')) * sx); - var h = round(Number(node.getAttribute('h')) * sy); - - var arcsize = node.getAttribute('arcsize'); - - if (arcsize == 0) - { - arcsize = mxConstants.RECTANGLE_ROUNDING_FACTOR * 100; - } - - if (vml) - { - // LATER: Use HTML for non-rounded, gradientless rectangles - currentPath = document.createElement((rounded) ? 'v:roundrect' : 'v:rect'); - currentPath.style.left = x + 'px'; - currentPath.style.top = y + 'px'; - currentPath.style.width = w + 'px'; - currentPath.style.height = h + 'px'; - - if (rounded) - { - currentPath.setAttribute('arcsize', String(arcsize) + '%'); - } - } - else - { - currentPath = document.createElementNS(mxConstants.NS_SVG, 'rect'); - currentPath.setAttribute('x', x); - currentPath.setAttribute('y', y); - currentPath.setAttribute('width', w); - currentPath.setAttribute('height', h); - - if (rounded) - { - var factor = Number(arcsize) / 100; - var r = Math.min(w * factor, h * factor); - currentPath.setAttribute('rx', r); - currentPath.setAttribute('ry', r); - } - - if (svgTransform.length > 0) - { - currentPath.setAttribute('transform', svgTransform); - } - - if (node.getAttribute('crisp') == '1') - { - currentPath.setAttribute('shape-rendering', 'crispEdges'); - } - } - - configurePath.call(this, currentPath, currentState); - } - else if (name == 'ellipse') - { - var x = round(x0 + Number(node.getAttribute('x')) * sx); - var y = round(y0 + Number(node.getAttribute('y')) * sy); - var w = round(Number(node.getAttribute('w')) * sx); - var h = round(Number(node.getAttribute('h')) * sy); - - if (vml) - { - currentPath = document.createElement('v:arc'); - currentPath.startangle = '0'; - currentPath.endangle = '360'; - currentPath.style.left = x + 'px'; - currentPath.style.top = y + 'px'; - currentPath.style.width = w + 'px'; - currentPath.style.height = h + 'px'; - } - else - { - currentPath = document.createElementNS(mxConstants.NS_SVG, 'ellipse'); - currentPath.setAttribute('cx', x + w / 2); - currentPath.setAttribute('cy', y + h / 2); - currentPath.setAttribute('rx', w / 2); - currentPath.setAttribute('ry', h / 2); - - if (svgTransform.length > 0) - { - currentPath.setAttribute('transform', svgTransform); - } - } - - configurePath.call(this, currentPath, currentState); - } - else if (name == 'arc') - { - var r1 = Number(node.getAttribute('rx')) * sx; - var r2 = Number(node.getAttribute('ry')) * sy; - var angle = Number(node.getAttribute('x-axis-rotation')); - var largeArcFlag = Number(node.getAttribute('large-arc-flag')); - var sweepFlag = Number(node.getAttribute('sweep-flag')); - var x = x0 + Number(node.getAttribute('x')) * sx; - var y = y0 + Number(node.getAttribute('y')) * sy; - - if (vml) - { - var curves = mxUtils.arcToCurves(this.lastMoveX, this.lastMoveY, r1, r2, angle, largeArcFlag, sweepFlag, x, y); - - for (var i = 0; i < curves.length; i += 6) - { - addToPath('c' + ' ' + Math.round(curves[i]) + ' ' + Math.round(curves[i + 1]) + ' ' + - Math.round(curves[i + 2]) + ' ' + Math.round(curves[i + 3]) + ' ' + - Math.round(curves[i + 4]) + ' ' + Math.round(curves[i + 5])); - - this.lastMoveX = curves[i + 4]; - this.lastMoveY = curves[i + 5]; - } - } - else - { - addToPath('A ' + r1 + ',' + r2 + ' ' + angle + ' ' + largeArcFlag + ',' + sweepFlag + ' ' + x + ',' + y); - this.lastMoveX = x0 + x; - this.lastMoveY = y0 + y; - } - } - else if (name == 'image') - { - var src = this.evaluateAttribute(node, 'src', shape.state); - - if (src != null) - { - var x = round(x0 + Number(node.getAttribute('x')) * sx); - var y = round(y0 + Number(node.getAttribute('y')) * sy); - var w = round(Number(node.getAttribute('w')) * sx); - var h = round(Number(node.getAttribute('h')) * sy); - - // TODO: _Not_ providing an aspect in the shapes format has the advantage - // of not needing a callback to adjust the image in VML. Since the shape - // developer can specify the aspect via width and height this should OK. - //var aspect = node.getAttribute('aspect') != '0'; - var aspect = false; - var flipH = node.getAttribute('flipH') == '1'; - var flipV = node.getAttribute('flipV') == '1'; - - if (vml) - { - currentPath = document.createElement('v:image'); - currentPath.style.filter = 'alpha(opacity=' + currentState.alpha + ')'; - currentPath.style.left = x + 'px'; - currentPath.style.top = y + 'px'; - currentPath.style.width = w + 'px'; - currentPath.style.height = h + 'px'; - currentPath.src = src; - - if (flipH && flipV) - { - currentPath.style.rotation = '180'; - } - else if (flipH) - { - currentPath.style.flip = 'x'; - } - else if (flipV) - { - currentPath.style.flip = 'y'; - } - } - else - { - currentPath = document.createElementNS(mxConstants.NS_SVG, 'image'); - currentPath.setAttributeNS(mxConstants.NS_XLINK, 'xlink:href', src); - currentPath.setAttribute('opacity', currentState.alpha / 100); - currentPath.setAttribute('x', x); - currentPath.setAttribute('y', y); - currentPath.setAttribute('width', w); - currentPath.setAttribute('height', h); - - if (!aspect) - { - currentPath.setAttribute('preserveAspectRatio', 'none'); - } - - if (flipH || flipV) - { - var scx = 1; - var scy = 1; - var dx = 0; - var dy = 0; - - if (flipH) - { - scx = -1; - dx = -w - 2 * x; - } - - if (flipV) - { - scy = -1; - dy = -h - 2 * y; - } - - currentPath.setAttribute('transform', svgTransform + 'scale(' + scx + ' ' + scy + ')' + - ' translate('+dx+' '+dy+') '); - } - else - { - currentPath.setAttribute('transform', svgTransform); - } - } - - parentNode.appendChild(currentPath); - } - } - else if (name == 'include-shape') - { - var stencil = mxStencilRegistry.getStencil(node.getAttribute('name')); - - if (stencil != null) - { - var x = x0 + Number(node.getAttribute('x')) * sx; - var y = y0 + Number(node.getAttribute('y')) * sy; - var w = Number(node.getAttribute('w')) * sx; - var h = Number(node.getAttribute('h')) * sy; - - stencil.renderDom(shape, new mxRectangle(x, y, w, h), parentNode, currentState); - } - } - // Additional labels are currently disabled. Needs fixing of VML - // text positon, SVG text rotation and ignored baseline in FF - else if (name == 'text') - { - var str = this.evaluateAttribute(node, 'str', shape.state); - - if (str != null) - { - var x = round(x0 + Number(node.getAttribute('x')) * sx); - var y = round(y0 + Number(node.getAttribute('y')) * sy); - var align = node.getAttribute('align') || 'left'; - var valign = node.getAttribute('valign') || 'top'; - - if (vml) - { - // Renders a single line of text with full rotation support - currentPath = document.createElement('v:shape'); - currentPath.style.position = 'absolute'; - currentPath.style.width = '1px'; - currentPath.style.height = '1px'; - currentPath.style.left = x + 'px'; - currentPath.style.top = y + 'px'; - - var fill = document.createElement('v:fill'); - fill.color = currentState.fontColor; - fill.on = 'true'; - currentPath.appendChild(fill); - - var stroke = document.createElement('v:stroke'); - stroke.on = 'false'; - currentPath.appendChild(stroke); - - var path = document.createElement('v:path'); - path.textpathok = 'true'; - path.v = 'm ' + x + ' ' + y + ' l ' + (x + 1) + ' ' + y; - - currentPath.appendChild(path); - - var tp = document.createElement('v:textpath'); - tp.style.cssText = 'v-text-align:' + align; - tp.style.fontSize = Math.round(currentState.fontSize / vmlScale) + 'px'; - - // FIXME: Font-family seems to be ignored for textpath - tp.style.fontFamily = currentState.fontFamily; - tp.string = str; - tp.on = 'true'; - - // Bold - if ((currentState.fontStyle & mxConstants.FONT_BOLD) == mxConstants.FONT_BOLD) - { - tp.style.fontWeight = 'bold'; - } - - // Italic - if ((currentState.fontStyle & mxConstants.FONT_ITALIC) == mxConstants.FONT_ITALIC) - { - tp.style.fontStyle = 'italic'; - } - - // FIXME: Text decoration not supported in textpath - if ((currentState.fontStyle & mxConstants.FONT_UNDERLINE) == mxConstants.FONT_UNDERLINE) - { - tp.style.textDecoration = 'underline'; - } - - // LATER: Find vertical center for div via CSS if possible - if (valign == 'top') - { - currentPath.style.top = (y + currentState.fontSize / 2) + 'px'; - } - else if (valign == 'bottom') - { - currentPath.style.top = (y - currentState.fontSize / 3) + 'px'; - } - - currentPath.appendChild(tp); - } - else - { - currentPath = document.createElementNS(mxConstants.NS_SVG, 'text'); - currentPath.setAttribute('fill', currentState.fontColor); - currentPath.setAttribute('font-family', currentState.fontFamily); - currentPath.setAttribute('font-size', currentState.fontSize); - currentPath.setAttribute('stroke', 'none'); - currentPath.setAttribute('x', x); - currentPath.appendChild(document.createTextNode(str)); - - // Bold - if ((currentState.fontStyle & mxConstants.FONT_BOLD) == mxConstants.FONT_BOLD) - { - currentPath.setAttribute('font-weight', 'bold'); - } - - // Italic - if ((currentState.fontStyle & mxConstants.FONT_ITALIC) == mxConstants.FONT_ITALIC) - { - currentPath.setAttribute('font-style', 'italic'); - } - - // Underline - if ((currentState.fontStyle & mxConstants.FONT_UNDERLINE) == mxConstants.FONT_UNDERLINE) - { - currentPath.setAttribute('text-decoration', uline); - } - - // Horizontal alignment - if (align == 'left') - { - align = 'start'; - } - else if (align == 'center') - { - align = 'middle'; - } - else if (align == 'right') - { - align = 'end'; - } - - currentPath.setAttribute('text-anchor', align); - - // Vertical alignment - // Uses dy because FF ignores alignment-baseline - if (valign == 'top') - { - currentPath.setAttribute('y', y + currentState.fontSize / 5); - currentPath.setAttribute('dy', '1ex'); - } - else if (valign == 'middle') - { - currentPath.setAttribute('y', y + currentState.fontSize / 8); - currentPath.setAttribute('dy', '0.5ex'); - } - else - { - currentPath.setAttribute('y', y); - } - - if (svgTransform.length > 0) - { - currentPath.setAttribute('transform', svgTransform); - } - } - - parentNode.appendChild(currentPath); - } - } - else if (fillOp || strokeOp || fillStrokeOp) - { - if (currentPath != null) - { - var pattern = null; - - if (currentState.dashed) - { - var f = (vml) ? minScale : Number(currentPath.getAttribute('stroke-width')); - var pat = []; - - for (var i = 0; i < currentState.dashpattern.length; i++) - { - pat.push(Math.max(1, Math.round(Number(currentState.dashpattern[i]) * f))); - } - - pattern = pat.join(' '); - } - - if (strokeOp || fillStrokeOp) - { - if (vml) - { - var stroke = document.createElement('v:stroke'); - stroke.endcap = currentState.linecap || 'flat'; - stroke.joinstyle = currentState.linejoin || 'miter'; - stroke.miterlimit = currentState.miterlimit || '10'; - currentPath.appendChild(stroke); - - // TODO: Dashpattern support in VML is limited, we should - // map this to VML or allow for a separate VML dashstyle. - if (pattern != null) - { - stroke.dashstyle = pattern; - } - } - else - { - if (currentState.linejoin != null) - { - currentPath.setAttribute('stroke-linejoin', currentState.linejoin); - } - - if (currentState.linecap != null) - { - // flat is called butt in SVG - var value = currentState.linecap; - - if (value == 'flat') - { - value = 'butt'; - } - - currentPath.setAttribute('stroke-linecap', value); - } - - if (currentState.miterlimit != null) - { - currentPath.setAttribute('stroke-miterlimit', currentState.miterlimit); - } - - // Handles dash pattern - if (pattern != null) - { - currentPath.setAttribute('stroke-dasharray', pattern); - } - } - } - - // Adds the shadow - if (background && shape.isShadow) - { - var dx = mxConstants.SHADOW_OFFSET_X * shape.scale; - var dy = mxConstants.SHADOW_OFFSET_Y * shape.scale; - - // Adds the shadow - if (vml) - { - var shadow = document.createElement('v:shadow'); - shadow.setAttribute('on', 'true'); - shadow.setAttribute('color', mxConstants.SHADOWCOLOR); - shadow.setAttribute('offset', Math.round(dx) + 'px,' + Math.round(dy) + 'px'); - shadow.setAttribute('opacity', (mxConstants.SHADOW_OPACITY * 100) + '%'); - - var stroke = document.createElement('v:stroke'); - stroke.endcap = currentState.linecap || 'flat'; - stroke.joinstyle = currentState.linejoin || 'miter'; - stroke.miterlimit = currentState.miterlimit || '10'; - - if (pattern != null) - { - stroke.dashstyle = pattern; - } - - shadow.appendChild(stroke); - currentPath.appendChild(shadow); - } - else - { - var shadow = currentPath.cloneNode(true); - shadow.setAttribute('stroke', mxConstants.SHADOWCOLOR); - - if (currentState.fill != null && (fillOp || fillStrokeOp)) - { - shadow.setAttribute('fill', mxConstants.SHADOWCOLOR); - } - else - { - shadow.setAttribute('fill', 'none'); - } - - shadow.setAttribute('transform', 'translate(' + dx + ' ' + dy + ') ' + - (shadow.getAttribute('transform') || '')); - shadow.setAttribute('opacity', mxConstants.SHADOW_OPACITY); - parentNode.appendChild(shadow); - } - } - - if (fillOp) - { - if (vml) - { - currentPath.stroked = 'false'; - } - else - { - currentPath.setAttribute('stroke', 'none'); - } - } - else if (strokeOp) - { - if (vml) - { - currentPath.filled = 'false'; - } - else - { - currentPath.setAttribute('fill', 'none'); - } - } - - parentNode.appendChild(currentPath); - } - - // Background was painted - if (background) - { - background = false; - } - } - else if (name == 'linecap') - { - currentState.linecap = node.getAttribute('cap'); - } - else if (name == 'linejoin') - { - currentState.linejoin = node.getAttribute('join'); - } - else if (name == 'miterlimit') - { - currentState.miterlimit = node.getAttribute('limit'); - } - else if (name == 'dashed') - { - currentState.dashed = node.getAttribute('dashed') == '1'; - } - else if (name == 'dashpattern') - { - var value = node.getAttribute('pattern'); - - if (value != null && value.length > 0) - { - currentState.dashpattern = value.split(' '); - } - } - else if (name == 'strokewidth') - { - currentState.strokeWidth = node.getAttribute('width') * minScale; - - if (vml) - { - currentState.strokeWidth /= vmlScale; - } - } - else if (name == 'strokecolor') - { - currentState.stroke = node.getAttribute('color'); - } - else if (name == 'fillcolor') - { - currentState.fill = node.getAttribute('color'); - currentState.fillColorAssigned = true; - } - else if (name == 'alpha') - { - currentState.alpha = Number(node.getAttribute('alpha')); - } - else if (name == 'fontcolor') - { - currentState.fontColor = node.getAttribute('color'); - } - else if (name == 'fontsize') - { - currentState.fontSize = Number(node.getAttribute('size')) * minScale; - } - else if (name == 'fontfamily') - { - currentState.fontFamily = node.getAttribute('family'); - } - else if (name == 'fontstyle') - { - currentState.fontStyle = Number(node.getAttribute('style')); - } - }; - - // Adds a transparent rectangle in the background for hit-detection in SVG - if (!vml) - { - var rect = document.createElementNS(mxConstants.NS_SVG, 'rect'); - rect.setAttribute('x', bounds.x); - rect.setAttribute('y', bounds.y); - rect.setAttribute('width', bounds.width); - rect.setAttribute('height', bounds.height); - rect.setAttribute('fill', 'none'); - rect.setAttribute('stroke', 'none'); - parentNode.appendChild(rect); - } - - // Background switches to false after fill/stroke of the background - if (this.bgNode != null) - { - var tmp = this.bgNode.firstChild; - - while (tmp != null) - { - if (tmp.nodeType == mxConstants.NODETYPE_ELEMENT) - { - renderNode.call(this, tmp); - } - - tmp = tmp.nextSibling; - } - } - else - { - background = false; - } - - if (this.fgNode != null) - { - var tmp = this.fgNode.firstChild; - - while (tmp != null) - { - if (tmp.nodeType == mxConstants.NODETYPE_ELEMENT) - { - renderNode.call(this, tmp); - } - - tmp = tmp.nextSibling; - } - } - } -}; - -/** - * Function: drawShape - * - * Draws this stencil inside the given bounds. - */ -mxStencil.prototype.drawShape = function(canvas, state, bounds, background) -{ - // TODO: Unify with renderDom, check performance of pluggable shape, - // internal structure (array of special structs?), relative and absolute - // coordinates (eg. note shape, process vs star, actor etc.), text rendering - // and non-proportional scaling, how to implement pluggable edge shapes - // (start, segment, end blocks), pluggable markers, how to implement - // swimlanes (title area) with this API, add icon, horizontal/vertical - // label, indicator for all shapes, rotation - var node = (background) ? this.bgNode : this.fgNode; - - if (node != null) - { - var direction = mxUtils.getValue(state.style, mxConstants.STYLE_DIRECTION, null); - var aspect = this.computeAspect(state, bounds, direction); - var minScale = Math.min(aspect.width, aspect.height); - var sw = (this.strokewidth == 'inherit') ? - Number(mxUtils.getNumber(state.style, mxConstants.STYLE_STROKEWIDTH, 1)) * state.view.scale : - Number(this.strokewidth) * minScale; - this.lastMoveX = 0; - this.lastMoveY = 0; - canvas.setStrokeWidth(sw); - - var tmp = node.firstChild; - - while (tmp != null) - { - if (tmp.nodeType == mxConstants.NODETYPE_ELEMENT) - { - this.drawNode(canvas, state, tmp, aspect); - } - - tmp = tmp.nextSibling; - } - - return true; - } - - return false; -}; - -/** - * Function: computeAspect - * - * Returns a rectangle that contains the offset in x and y and the horizontal - * and vertical scale in width and height used to draw this shape inside the - * given <mxRectangle>. - * - * Parameters: - * - * state - <mxCellState> for which the shape should be drawn. - * bounds - <mxRectangle> that should contain the stencil. - * direction - Optional direction of the shape to be darwn. - */ -mxStencil.prototype.computeAspect = function(state, bounds, direction) -{ - var x0 = bounds.x; - var y0 = bounds.y; - var sx = bounds.width / this.w0; - var sy = bounds.height / this.h0; - - var inverse = (direction == 'north' || direction == 'south'); - - if (inverse) - { - sy = bounds.width / this.h0; - sx = bounds.height / this.w0; - - var delta = (bounds.width - bounds.height) / 2; - - x0 += delta; - y0 -= delta; - } - - if (this.aspect == 'fixed') - { - sy = Math.min(sx, sy); - sx = sy; - - // Centers the shape inside the available space - if (inverse) - { - x0 += (bounds.height - this.w0 * sx) / 2; - y0 += (bounds.width - this.h0 * sy) / 2; - } - else - { - x0 += (bounds.width - this.w0 * sx) / 2; - y0 += (bounds.height - this.h0 * sy) / 2; - } - } - - return new mxRectangle(x0, y0, sx, sy); -}; - -/** - * Function: drawNode - * - * Draws this stencil inside the given bounds. - */ -mxStencil.prototype.drawNode = function(canvas, state, node, aspect) -{ - var name = node.nodeName; - var x0 = aspect.x; - var y0 = aspect.y; - var sx = aspect.width; - var sy = aspect.height; - var minScale = Math.min(sx, sy); - - // LATER: Move to lookup table - if (name == 'save') - { - canvas.save(); - } - else if (name == 'restore') - { - canvas.restore(); - } - else if (name == 'path') - { - canvas.begin(); - - // Renders the elements inside the given path - var childNode = node.firstChild; - - while (childNode != null) - { - if (childNode.nodeType == mxConstants.NODETYPE_ELEMENT) - { - this.drawNode(canvas, state, childNode, aspect); - } - - childNode = childNode.nextSibling; - } - } - else if (name == 'close') - { - canvas.close(); - } - else if (name == 'move') - { - this.lastMoveX = x0 + Number(node.getAttribute('x')) * sx; - this.lastMoveY = y0 + Number(node.getAttribute('y')) * sy; - canvas.moveTo(this.lastMoveX, this.lastMoveY); - } - else if (name == 'line') - { - this.lastMoveX = x0 + Number(node.getAttribute('x')) * sx; - this.lastMoveY = y0 + Number(node.getAttribute('y')) * sy; - canvas.lineTo(this.lastMoveX, this.lastMoveY); - } - else if (name == 'quad') - { - this.lastMoveX = x0 + Number(node.getAttribute('x2')) * sx; - this.lastMoveY = y0 + Number(node.getAttribute('y2')) * sy; - canvas.quadTo(x0 + Number(node.getAttribute('x1')) * sx, - y0 + Number(node.getAttribute('y1')) * sy, - this.lastMoveX, this.lastMoveY); - } - else if (name == 'curve') - { - this.lastMoveX = x0 + Number(node.getAttribute('x3')) * sx; - this.lastMoveY = y0 + Number(node.getAttribute('y3')) * sy; - canvas.curveTo(x0 + Number(node.getAttribute('x1')) * sx, - y0 + Number(node.getAttribute('y1')) * sy, - x0 + Number(node.getAttribute('x2')) * sx, - y0 + Number(node.getAttribute('y2')) * sy, - this.lastMoveX, this.lastMoveY); - } - else if (name == 'arc') - { - // Arc from stencil is turned into curves in image output - var r1 = Number(node.getAttribute('rx')) * sx; - var r2 = Number(node.getAttribute('ry')) * sy; - var angle = Number(node.getAttribute('x-axis-rotation')); - var largeArcFlag = Number(node.getAttribute('large-arc-flag')); - var sweepFlag = Number(node.getAttribute('sweep-flag')); - var x = x0 + Number(node.getAttribute('x')) * sx; - var y = y0 + Number(node.getAttribute('y')) * sy; - - var curves = mxUtils.arcToCurves(this.lastMoveX, this.lastMoveY, r1, r2, angle, largeArcFlag, sweepFlag, x, y); - - for (var i = 0; i < curves.length; i += 6) - { - canvas.curveTo(curves[i], curves[i + 1], curves[i + 2], - curves[i + 3], curves[i + 4], curves[i + 5]); - - this.lastMoveX = curves[i + 4]; - this.lastMoveY = curves[i + 5]; - } - } - else if (name == 'rect') - { - canvas.rect(x0 + Number(node.getAttribute('x')) * sx, - y0 + Number(node.getAttribute('y')) * sy, - Number(node.getAttribute('w')) * sx, - Number(node.getAttribute('h')) * sy); - } - else if (name == 'roundrect') - { - var arcsize = node.getAttribute('arcsize'); - - if (arcsize == 0) - { - arcsize = mxConstants.RECTANGLE_ROUNDING_FACTOR * 100; - } - - var w = Number(node.getAttribute('w')) * sx; - var h = Number(node.getAttribute('h')) * sy; - var factor = Number(arcsize) / 100; - var r = Math.min(w * factor, h * factor); - - canvas.roundrect(x0 + Number(node.getAttribute('x')) * sx, - y0 + Number(node.getAttribute('y')) * sy, - w, h, r, r); - } - else if (name == 'ellipse') - { - canvas.ellipse(x0 + Number(node.getAttribute('x')) * sx, - y0 + Number(node.getAttribute('y')) * sy, - Number(node.getAttribute('w')) * sx, - Number(node.getAttribute('h')) * sy); - } - else if (name == 'image') - { - var src = this.evaluateAttribute(node, 'src', state); - - canvas.image(x0 + Number(node.getAttribute('x')) * sx, - y0 + Number(node.getAttribute('y')) * sy, - Number(node.getAttribute('w')) * sx, - Number(node.getAttribute('h')) * sy, - src, false, node.getAttribute('flipH') == '1', - node.getAttribute('flipV') == '1'); - } - else if (name == 'text') - { - var str = this.evaluateAttribute(node, 'str', state); - - canvas.text(x0 + Number(node.getAttribute('x')) * sx, - y0 + Number(node.getAttribute('y')) * sy, - 0, 0, str, node.getAttribute('align'), - node.getAttribute('valign'), - node.getAttribute('vertical')); - } - else if (name == 'include-shape') - { - var stencil = mxStencilRegistry.getStencil(node.getAttribute('name')); - - if (stencil != null) - { - var x = x0 + Number(node.getAttribute('x')) * sx; - var y = y0 + Number(node.getAttribute('y')) * sy; - var w = Number(node.getAttribute('w')) * sx; - var h = Number(node.getAttribute('h')) * sy; - - var tmp = new mxRectangle(x, y, w, h); - stencil.drawShape(canvas, state, tmp, true); - stencil.drawShape(canvas, state, tmp, false); - } - } - else if (name == 'fillstroke') - { - canvas.fillAndStroke(); - } - else if (name == 'fill') - { - canvas.fill(); - } - else if (name == 'stroke') - { - canvas.stroke(); - } - else if (name == 'strokewidth') - { - canvas.setStrokeWidth(Number(node.getAttribute('width')) * minScale); - } - else if (name == 'dashed') - { - canvas.setDashed(node.getAttribute('dashed') == '1'); - } - else if (name == 'dashpattern') - { - var value = node.getAttribute('pattern'); - - if (value != null) - { - var tmp = value.split(' '); - var pat = []; - - for (var i = 0; i < tmp.length; i++) - { - if (tmp[i].length > 0) - { - pat.push(Number(tmp[i]) * minScale); - } - } - - value = pat.join(' '); - canvas.setDashPattern(value); - } - } - else if (name == 'strokecolor') - { - canvas.setStrokeColor(node.getAttribute('color')); - } - else if (name == 'linecap') - { - canvas.setLineCap(node.getAttribute('cap')); - } - else if (name == 'linejoin') - { - canvas.setLineJoin(node.getAttribute('join')); - } - else if (name == 'miterlimit') - { - canvas.setMiterLimit(Number(node.getAttribute('limit'))); - } - else if (name == 'fillcolor') - { - canvas.setFillColor(node.getAttribute('color')); - } - else if (name == 'fontcolor') - { - canvas.setFontColor(node.getAttribute('color')); - } - else if (name == 'fontstyle') - { - canvas.setFontStyle(node.getAttribute('style')); - } - else if (name == 'fontfamily') - { - canvas.setFontFamily(node.getAttribute('family')); - } - else if (name == 'fontsize') - { - canvas.setFontSize(Number(node.getAttribute('size')) * minScale); - } -}; diff --git a/src/js/shape/mxStencilRegistry.js b/src/js/shape/mxStencilRegistry.js deleted file mode 100644 index 7621573..0000000 --- a/src/js/shape/mxStencilRegistry.js +++ /dev/null @@ -1,53 +0,0 @@ -/** - * $Id: mxStencilRegistry.js,v 1.2 2011-07-15 12:57:50 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - * - * Code to add stencils. - * - * (code) - * var req = mxUtils.load('test/stencils.xml'); - * var root = req.getDocumentElement(); - * var shape = root.firstChild; - * - * while (shape != null) - * { - * if (shape.nodeType == mxConstants.NODETYPE_ELEMENT) - * { - * mxStencilRegistry.addStencil(shape.getAttribute('name'), new mxStencil(shape)); - * } - * - * shape = shape.nextSibling; - * } - * (end) - */ -var mxStencilRegistry = -{ - /** - * Class: mxStencilRegistry - * - * A singleton class that provides a registry for stencils and the methods - * for painting those stencils onto a canvas or into a DOM. - */ - stencils: [], - - /** - * Function: addStencil - * - * Adds the given <mxStencil>. - */ - addStencil: function(name, stencil) - { - mxStencilRegistry.stencils[name] = stencil; - }, - - /** - * Function: getStencil - * - * Returns the <mxStencil> for the given name. - */ - getStencil: function(name) - { - return mxStencilRegistry.stencils[name]; - } - -}; diff --git a/src/js/shape/mxStencilShape.js b/src/js/shape/mxStencilShape.js deleted file mode 100644 index 9c95f8b..0000000 --- a/src/js/shape/mxStencilShape.js +++ /dev/null @@ -1,209 +0,0 @@ -/** - * $Id: mxStencilShape.js,v 1.10 2012-07-16 10:22:44 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -/** - * Class: mxStencilShape - * - * Implements a shape based on a <mxStencil>. - * - * Constructor: mxStencilShape - * - * Constructs a new generic shape. - */ -function mxStencilShape(stencil) -{ - this.stencil = stencil; -}; - -/** - * Extends mxShape. - */ -mxStencilShape.prototype = new mxShape(); -mxStencilShape.prototype.constructor = mxStencilShape; - -/** - * Variable: mixedModeHtml - * - * Always prefers VML in mixed mode for stencil shapes. Default is false. - */ -mxStencilShape.prototype.mixedModeHtml = false; - -/** - * Variable: preferModeHtml - * - * Always prefers VML in prefer HTML mode for stencil shapes. Default is false. - */ -mxStencilShape.prototype.preferModeHtml = false; - -/** - * Variable: stencil - * - * Holds the <mxStencil> that defines the shape. - */ -mxStencilShape.prototype.stencil = null; - -/** - * Variable: state - * - * Holds the <mxCellState> associated with this shape. - */ -mxStencilShape.prototype.state = null; - -/** - * Variable: vmlScale - * - * Renders VML with a scale of 4. - */ -mxStencilShape.prototype.vmlScale = 4; - -/** - * Function: apply - * - * Extends <mxShape> apply to keep a reference to the <mxCellState>. - * - * Parameters: - * - * state - <mxCellState> of the corresponding cell. - */ -mxStencilShape.prototype.apply = function(state) -{ - this.state = state; - mxShape.prototype.apply.apply(this, arguments); -}; - -/** - * Function: createSvg - * - * Creates and returns the SVG node(s) to represent this shape. - */ -mxStencilShape.prototype.createSvg = function() -{ - var node = document.createElementNS(mxConstants.NS_SVG, 'g'); - this.configureSvgShape(node); - - return node; -}; - -/** - * Function: configureHtmlShape - * - * Overrides method to set the overflow style to visible. - */ -mxStencilShape.prototype.configureHtmlShape = function(node) -{ - mxShape.prototype.configureHtmlShape.apply(this, arguments); - - if (!mxUtils.isVml(node)) - { - node.style.overflow = 'visible'; - } -}; - -/** - * Function: createVml - * - * Creates and returns the VML node to represent this shape. - */ -mxStencilShape.prototype.createVml = function() -{ - var name = (document.documentMode == 8) ? 'div' : 'v:group'; - var node = document.createElement(name); - this.configureTransparentBackground(node); - node.style.position = 'absolute'; - - return node; -}; - -/** - * Function: configureVmlShape - * - * Configures the specified VML node by applying the current color, - * bounds, shadow, opacity etc. - */ -mxStencilShape.prototype.configureVmlShape = function(node) -{ - // do nothing -}; - -/** - * Function: redraw - * - * Creates and returns the SVG node(s) to represent this shape. - */ -mxStencilShape.prototype.redraw = function() -{ - this.updateBoundingBox(); - - if (this.dialect == mxConstants.DIALECT_SVG) - { - this.redrawShape(); - } - else - { - this.node.style.visibility = 'hidden'; - this.redrawShape(); - this.node.style.visibility = 'visible'; - } -}; - -/** - * Function: redrawShape - * - * Updates the SVG or VML shape. - */ -mxStencilShape.prototype.redrawShape = function() -{ - // LATER: Update existing DOM nodes to improve repaint performance - if (this.dialect != mxConstants.DIALECT_SVG) - { - this.node.style.left = Math.round(this.bounds.x) + 'px'; - this.node.style.top = Math.round(this.bounds.y) + 'px'; - var w = Math.round(this.bounds.width); - var h = Math.round(this.bounds.height); - this.node.style.width = w + 'px'; - this.node.style.height = h + 'px'; - - var node = this.node; - - // Workaround for VML rendering bug in IE8 standards mode where all VML must be - // parsed via assigning the innerHTML of the parent HTML node to keep all event - // handlers referencing node and support rotation via v:group parent element. - if (this.node.nodeName == 'DIV') - { - node = document.createElement('v:group'); - node.style.position = 'absolute'; - node.style.left = '0px'; - node.style.top = '0px'; - node.style.width = w + 'px'; - node.style.height = h + 'px'; - } - else - { - node.innerHTML = ''; - } - - if (mxUtils.isVml(node)) - { - var s = (document.documentMode != 8) ? this.vmlScale : 1; - node.coordsize = (w * s) + ',' + (h * s); - } - - this.stencil.renderDom(this, this.bounds, node); - - if(this.node != node) - { - // Forces parsing in IE8 standards mode - this.node.innerHTML = node.outerHTML; - } - } - else - { - while (this.node.firstChild != null) - { - this.node.removeChild(this.node.firstChild); - } - - this.stencil.renderDom(this, this.bounds, this.node); - } -}; diff --git a/src/js/shape/mxSwimlane.js b/src/js/shape/mxSwimlane.js deleted file mode 100644 index 22720fd..0000000 --- a/src/js/shape/mxSwimlane.js +++ /dev/null @@ -1,553 +0,0 @@ -/** - * $Id: mxSwimlane.js,v 1.43 2011-11-04 13:54:50 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -/** - * Class: mxSwimlane - * - * Extends <mxShape> to implement a swimlane shape. - * This shape is registered under <mxConstants.SHAPE_SWIMLANE> - * in <mxCellRenderer>. - * - * Constructor: mxSwimlane - * - * Constructs a new swimlane shape. - * - * Parameters: - * - * bounds - <mxRectangle> that defines the bounds. This is stored in - * <mxShape.bounds>. - * fill - String that defines the fill color. This is stored in <fill>. - * stroke - String that defines the stroke color. This is stored in <stroke>. - * strokewidth - Optional integer that defines the stroke width. Default is - * 1. This is stored in <strokewidth>. - */ -function mxSwimlane(bounds, fill, stroke, strokewidth) -{ - this.bounds = bounds; - this.fill = fill; - this.stroke = stroke; - this.strokewidth = (strokewidth != null) ? strokewidth : 1; -}; - -/** - * Extends mxShape. - */ -mxSwimlane.prototype = new mxShape(); -mxSwimlane.prototype.constructor = mxSwimlane; - -/** - * Variable: vmlNodes - * - * Adds local references to <mxShape.vmlNodes>. - */ -mxSwimlane.prototype.vmlNodes = mxSwimlane.prototype.vmlNodes.concat(['label', 'content', 'imageNode', 'separator']); - -/** - * Variable: imageSize - * - * Default imagewidth and imageheight if an image but no imagewidth - * and imageheight are defined in the style. Value is 16. - */ -mxSwimlane.prototype.imageSize = 16; - -/** - * Variable: mixedModeHtml - * - * Overrides the parent value with false, meaning it will - * draw in VML in mixed Html mode. This is for better - * handling of event-transparency of the content area. - */ -mxSwimlane.prototype.mixedModeHtml = false; - -/** - * Variable: preferModeHtml - * - * Overrides the parent value with false, meaning it will - * draw as VML in prefer Html mode. This is for better - * handling of event-transparency of the content area. - */ -mxRhombus.prototype.preferModeHtml = false; - -/** - * Function: createHtml - * - * Creates and returns the HTML node to represent this shape. - */ -mxSwimlane.prototype.createHtml = function() -{ - var node = document.createElement('DIV'); - this.configureHtmlShape(node); - node.style.background = ''; - node.style.backgroundColor = ''; - node.style.borderStyle = 'none'; - - // Adds a node that will contain the text label - this.label = document.createElement('DIV'); - this.configureHtmlShape(this.label); - node.appendChild(this.label); - - // Adds a node for the content area of the swimlane - this.content = document.createElement('DIV'); - this.configureHtmlShape(this.content); - this.content.style.backgroundColor = ''; - - // Sets border styles depending on orientation - if (mxUtils.getValue(this.style, mxConstants.STYLE_HORIZONTAL, true)) - { - this.content.style.borderTopStyle = 'none'; - } - else - { - this.content.style.borderLeftStyle = 'none'; - } - - this.content.style.cursor = 'default'; - node.appendChild(this.content); - - // Adds a node for the separator - var color = this.style[mxConstants.STYLE_SEPARATORCOLOR]; - - if (color != null) - { - this.separator = document.createElement('DIV'); - this.separator.style.borderColor = color; - this.separator.style.borderLeftStyle = 'dashed'; - node.appendChild(this.separator); - } - - // Adds a node for the image - if (this.image != null) - { - this.imageNode = mxUtils.createImage(this.image); - this.configureHtmlShape(this.imageNode); - this.imageNode.style.borderStyle = 'none'; - node.appendChild(this.imageNode); - } - - return node; -}; - -/** - * Function: reconfigure - * - * Overrides to avoid filled content area in HTML and updates the shadow - * in SVG. - */ -mxSwimlane.prototype.reconfigure = function(node) -{ - mxShape.prototype.reconfigure.apply(this, arguments); - - if (this.dialect == mxConstants.DIALECT_SVG) - { - if (this.shadowNode != null) - { - this.updateSvgShape(this.shadowNode); - - if (mxUtils.getValue(this.style, mxConstants.STYLE_HORIZONTAL, true)) - { - this.shadowNode.setAttribute('height', this.startSize*this.scale); - } - else - { - this.shadowNode.setAttribute('width', this.startSize*this.scale); - } - } - } - else if (!mxUtils.isVml(this.node)) - { - this.node.style.background = ''; - this.node.style.backgroundColor = ''; - } -}; - -/** - * Function: redrawHtml - * - * Updates the HTML node(s) to reflect the latest bounds and scale. - */ -mxSwimlane.prototype.redrawHtml = function() -{ - this.updateHtmlShape(this.node); - this.node.style.background = ''; - this.node.style.backgroundColor = ''; - this.startSize = parseInt(mxUtils.getValue(this.style, - mxConstants.STYLE_STARTSIZE, mxConstants.DEFAULT_STARTSIZE)); - this.updateHtmlShape(this.label); - this.label.style.top = '0px'; - this.label.style.left = '0px'; - - if (mxUtils.getValue(this.style, mxConstants.STYLE_HORIZONTAL, true)) - { - this.startSize = Math.min(this.startSize, this.bounds.height); - this.label.style.height = (this.startSize * this.scale)+'px'; // relative - this.updateHtmlShape(this.content); - this.content.style.background = ''; - this.content.style.backgroundColor = ''; - - var h = this.startSize*this.scale; - - this.content.style.top = h+'px'; - this.content.style.left = '0px'; - this.content.style.height = Math.max(1, this.bounds.height - h)+'px'; - - if (this.separator != null) - { - this.separator.style.left = Math.round(this.bounds.width)+'px'; - this.separator.style.top = Math.round(this.startSize*this.scale)+'px'; - this.separator.style.width = '1px'; - this.separator.style.height = Math.round(this.bounds.height)+'px'; - this.separator.style.borderWidth = Math.round(this.scale)+'px'; - } - - if (this.imageNode != null) - { - this.imageNode.style.left = (this.bounds.width-this.imageSize-4)+'px'; - this.imageNode.style.top = '0px'; - // TODO: Use imageWidth and height from style if available - this.imageNode.style.width = Math.round(this.imageSize*this.scale)+'px'; - this.imageNode.style.height = Math.round(this.imageSize*this.scale)+'px'; - } - } - else - { - this.startSize = Math.min(this.startSize, this.bounds.width); - this.label.style.width = (this.startSize * this.scale)+'px'; // relative - this.updateHtmlShape(this.content); - this.content.style.background = ''; - this.content.style.backgroundColor = ''; - - var w = this.startSize*this.scale; - - this.content.style.top = '0px'; - this.content.style.left = w+'px'; - this.content.style.width = Math.max(0, this.bounds.width - w)+'px'; - - if (this.separator != null) - { - this.separator.style.left = Math.round(this.startSize*this.scale)+'px'; - this.separator.style.top = Math.round(this.bounds.height)+'px'; - this.separator.style.width = Math.round(this.bounds.width)+'px'; - this.separator.style.height = '1px'; - } - - if (this.imageNode != null) - { - this.imageNode.style.left = (this.bounds.width-this.imageSize-4)+'px'; - this.imageNode.style.top = '0px'; - this.imageNode.style.width = this.imageSize*this.scale+'px'; - this.imageNode.style.height = this.imageSize*this.scale+'px'; - } - } -}; - -/** - * Function: createVml - * - * Creates and returns the VML node(s) to represent this shape. - */ -mxSwimlane.prototype.createVml = function() -{ - var node = document.createElement('v:group'); - var name = (this.isRounded) ? 'v:roundrect' : 'v:rect'; - this.label = document.createElement(name); - - // First configure the label with all settings - this.configureVmlShape(this.label); - - if (this.isRounded) - { - this.label.setAttribute('arcsize', '20%'); - } - - // Disables stuff and configures the rest - this.isShadow = false; - this.configureVmlShape(node); - node.coordorigin = '0,0'; - node.appendChild(this.label); - - this.content = document.createElement(name); - - var tmp = this.fill; - this.fill = null; - - this.configureVmlShape(this.content); - node.style.background = ''; - - if (this.isRounded) - { - this.content.setAttribute('arcsize', '4%'); - } - - this.fill = tmp; - this.content.style.borderBottom = '0px'; - - node.appendChild(this.content); - - var color = this.style[mxConstants.STYLE_SEPARATORCOLOR]; - - if (color != null) - { - this.separator = document.createElement('v:shape'); - this.separator.style.position = 'absolute'; - this.separator.strokecolor = color; - - var strokeNode = document.createElement('v:stroke'); - strokeNode.dashstyle = '2 2'; - this.separator.appendChild(strokeNode); - - node.appendChild(this.separator); - } - - if (this.image != null) - { - this.imageNode = document.createElement('v:image'); - this.imageNode.src = this.image; - this.configureVmlShape(this.imageNode); - this.imageNode.stroked = 'false'; - - node.appendChild(this.imageNode); - } - - return node; -}; - -/** - * Function: redrawVml - * - * Updates the VML node(s) to reflect the latest bounds and scale. - */ -mxSwimlane.prototype.redrawVml = function() -{ - var x = Math.round(this.bounds.x); - var y = Math.round(this.bounds.y); - var w = Math.round(this.bounds.width); - var h = Math.round(this.bounds.height); - - this.updateVmlShape(this.node); - this.node.coordsize = w + ',' + h; - - this.updateVmlShape(this.label); - this.label.style.top = '0px'; - this.label.style.left = '0px'; - this.label.style.rotation = null; - - this.startSize = parseInt(mxUtils.getValue(this.style, - mxConstants.STYLE_STARTSIZE, mxConstants.DEFAULT_STARTSIZE)); - var start = Math.round(this.startSize * this.scale); - - if (this.separator != null) - { - this.separator.coordsize = w + ',' + h; - this.separator.style.left = x + 'px'; - this.separator.style.top = y + 'px'; - this.separator.style.width = w + 'px'; - this.separator.style.height = h + 'px'; - } - - if (mxUtils.getValue(this.style, mxConstants.STYLE_HORIZONTAL, true)) - { - start = Math.min(start, this.bounds.height); - this.label.style.height = start + 'px'; // relative - this.updateVmlShape(this.content); - this.content.style.background = ''; - this.content.style.top = start + 'px'; - this.content.style.left = '0px'; - this.content.style.height = Math.max(0, h - start)+'px'; - - if (this.separator != null) - { - var d = 'm ' + (w - x) + ' ' + (start - y) + - ' l ' + (w - x) + ' ' + (h - y) + ' e'; - this.separator.path = d; - } - - if (this.imageNode != null) - { - var img = Math.round(this.imageSize*this.scale); - - this.imageNode.style.left = (w-img-4)+'px'; - this.imageNode.style.top = '0px'; - this.imageNode.style.width = img + 'px'; - this.imageNode.style.height = img + 'px'; - } - } - else - { - start = Math.min(start, this.bounds.width); - this.label.style.width = start + 'px'; // relative - this.updateVmlShape(this.content); - this.content.style.background = ''; - this.content.style.top = '0px'; - this.content.style.left = start + 'px'; - this.content.style.width = Math.max(0, w - start) + 'px'; - - if (this.separator != null) - { - var d = 'm ' + (start - x) + ' ' + (h - y) + - ' l ' + (w - x) + ' ' + (h - y) + ' e'; - this.separator.path = d; - } - - if (this.imageNode != null) - { - var img = Math.round(this.imageSize * this.scale); - - this.imageNode.style.left = (w - img - 4)+'px'; - this.imageNode.style.top = '0px'; - this.imageNode.style.width = img + 'px'; - this.imageNode.style.height = img + 'px'; - } - } - - this.content.style.rotation = null; -}; - -/** - * Function: createSvg - * - * Creates and returns the SVG node(s) to represent this shape. - */ -mxSwimlane.prototype.createSvg = function() -{ - var node = this.createSvgGroup('rect'); - - if (this.isRounded) - { - this.innerNode.setAttribute('rx', 10); - this.innerNode.setAttribute('ry', 10); - } - - this.content = document.createElementNS(mxConstants.NS_SVG, 'path'); - this.configureSvgShape(this.content); - this.content.setAttribute('fill', 'none'); - - if (this.isRounded) - { - this.content.setAttribute('rx', 10); - this.content.setAttribute('ry', 10); - } - - node.appendChild(this.content); - var color = this.style[mxConstants.STYLE_SEPARATORCOLOR]; - - if (color != null) - { - this.separator = document.createElementNS(mxConstants.NS_SVG, 'line'); - - this.separator.setAttribute('stroke', color); - this.separator.setAttribute('fill', 'none'); - this.separator.setAttribute('stroke-dasharray', '2, 2'); - - node.appendChild(this.separator); - } - - if (this.image != null) - { - this.imageNode = document.createElementNS(mxConstants.NS_SVG, 'image'); - - this.imageNode.setAttributeNS(mxConstants.NS_XLINK, 'href', this.image); - this.configureSvgShape(this.imageNode); - - node.appendChild(this.imageNode); - } - - return node; -}; - -/** - * Function: redrawSvg - * - * Updates the SVG node(s) to reflect the latest bounds and scale. - */ -mxSwimlane.prototype.redrawSvg = function() -{ - var tmp = this.isRounded; - this.isRounded = false; - - this.updateSvgShape(this.innerNode); - this.updateSvgShape(this.content); - var horizontal = mxUtils.getValue(this.style, mxConstants.STYLE_HORIZONTAL, true); - this.startSize = parseInt(mxUtils.getValue(this.style, - mxConstants.STYLE_STARTSIZE, mxConstants.DEFAULT_STARTSIZE)); - var ss = this.startSize * this.scale; - - // Updates the size of the shadow node - if (this.shadowNode != null) - { - this.updateSvgShape(this.shadowNode); - - if (horizontal) - { - this.shadowNode.setAttribute('height', ss); - } - else - { - this.shadowNode.setAttribute('width', ss); - } - } - - this.isRounded = tmp; - - this.content.removeAttribute('x'); - this.content.removeAttribute('y'); - this.content.removeAttribute('width'); - this.content.removeAttribute('height'); - - var crisp = (this.crisp && mxClient.IS_IE) ? 0.5 : 0; - var x = Math.round(this.bounds.x) + crisp; - var y = Math.round(this.bounds.y) + crisp; - var w = Math.round(this.bounds.width); - var h = Math.round(this.bounds.height); - - if (horizontal) - { - ss = Math.min(ss, h); - this.innerNode.setAttribute('height', ss); - var points = 'M ' + x + ' ' + (y + ss) + - ' l 0 ' + (h - ss) + ' l ' + w + ' 0' + - ' l 0 ' + (ss - h); - this.content.setAttribute('d', points); - - if (this.separator != null) - { - this.separator.setAttribute('x1', x + w); - this.separator.setAttribute('y1', y + ss); - this.separator.setAttribute('x2', x + w); - this.separator.setAttribute('y2', y + h); - } - - if (this.imageNode != null) - { - this.imageNode.setAttribute('x', x + w - this.imageSize - 4); - this.imageNode.setAttribute('y', y); - this.imageNode.setAttribute('width', this.imageSize * this.scale + 'px'); - this.imageNode.setAttribute('height', this.imageSize * this.scale + 'px'); - } - } - else - { - ss = Math.min(ss, w); - this.innerNode.setAttribute('width', ss); - var points = 'M ' + (x + ss) + ' ' + y + - ' l ' + (w - ss) + ' 0' + ' l 0 ' + h + - ' l ' + (ss - w) + ' 0'; - this.content.setAttribute('d', points); - - if (this.separator != null) - { - this.separator.setAttribute('x1', x + ss); - this.separator.setAttribute('y1', y + h); - this.separator.setAttribute('x2', x + w); - this.separator.setAttribute('y2', y + h); - } - - if (this.imageNode != null) - { - this.imageNode.setAttribute('x', x + w - this.imageSize - 4); - this.imageNode.setAttribute('y', y); - this.imageNode.setAttribute('width', this.imageSize * this.scale + 'px'); - this.imageNode.setAttribute('height', this.imageSize * this.scale + 'px'); - } - } -}; diff --git a/src/js/shape/mxText.js b/src/js/shape/mxText.js deleted file mode 100644 index de44b59..0000000 --- a/src/js/shape/mxText.js +++ /dev/null @@ -1,1811 +0,0 @@ -/** - * $Id: mxText.js,v 1.174 2012-09-27 10:20:30 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -/** - * Class: mxText - * - * Extends <mxShape> to implement a text shape. To change vertical text from - * bottom to top to top to bottom, the following code can be used: - * - * (code) - * mxText.prototype.ieVerticalFilter = 'progid:DXImageTransform.Microsoft.BasicImage(rotation=1)'; - * mxText.prototype.verticalTextDegree = 90; - * - * mxText.prototype.getVerticalOffset = function(offset) - * { - * return new mxPoint(-offset.y, offset.x); - * }; - * (end) - * - * Constructor: mxText - * - * Constructs a new text shape. - * - * Parameters: - * - * value - String that represents the text to be displayed. This is stored in - * <value>. - * bounds - <mxRectangle> that defines the bounds. This is stored in - * <mxShape.bounds>. - * align - Specifies the horizontal alignment. Default is ''. This is stored in - * <align>. - * valign - Specifies the vertical alignment. Default is ''. This is stored in - * <valign>. - * color - String that specifies the text color. Default is 'black'. This is - * stored in <color>. - * family - String that specifies the font family. Default is - * <mxConstants.DEFAULT_FONTFAMILY>. This is stored in <family>. - * size - Integer that specifies the font size. Default is - * <mxConstants.DEFAULT_FONTSIZE>. This is stored in <size>. - * fontStyle - Specifies the font style. Default is 0. This is stored in - * <fontStyle>. - * spacing - Integer that specifies the global spacing. Default is 2. This is - * stored in <spacing>. - * spacingTop - Integer that specifies the top spacing. Default is 0. The - * sum of the spacing and this is stored in <spacingTop>. - * spacingRight - Integer that specifies the right spacing. Default is 0. The - * sum of the spacing and this is stored in <spacingRight>. - * spacingBottom - Integer that specifies the bottom spacing. Default is 0.The - * sum of the spacing and this is stored in <spacingBottom>. - * spacingLeft - Integer that specifies the left spacing. Default is 0. The - * sum of the spacing and this is stored in <spacingLeft>. - * horizontal - Boolean that specifies if the label is horizontal. Default is - * true. This is stored in <horizontal>. - * background - String that specifies the background color. Default is null. - * This is stored in <background>. - * border - String that specifies the label border color. Default is null. - * This is stored in <border>. - * wrap - Specifies if word-wrapping should be enabled. Default is false. - * This is stored in <wrap>. - * clipped - Specifies if the label should be clipped. Default is false. - * This is stored in <clipped>. - * overflow - Value of the overflow style. Default is 'visible'. - */ -function mxText(value, bounds, align, valign, color, - family, size, fontStyle, spacing, spacingTop, spacingRight, - spacingBottom, spacingLeft, horizontal, background, border, - wrap, clipped, overflow, labelPadding) -{ - this.value = value; - this.bounds = bounds; - this.color = (color != null) ? color : 'black'; - this.align = (align != null) ? align : ''; - this.valign = (valign != null) ? valign : ''; - this.family = (family != null) ? family : mxConstants.DEFAULT_FONTFAMILY; - this.size = (size != null) ? size : mxConstants.DEFAULT_FONTSIZE; - this.fontStyle = (fontStyle != null) ? fontStyle : 0; - this.spacing = parseInt(spacing || 2); - this.spacingTop = this.spacing + parseInt(spacingTop || 0); - this.spacingRight = this.spacing + parseInt(spacingRight || 0); - this.spacingBottom = this.spacing + parseInt(spacingBottom || 0); - this.spacingLeft = this.spacing + parseInt(spacingLeft || 0); - this.horizontal = (horizontal != null) ? horizontal : true; - this.background = background; - this.border = border; - this.wrap = (wrap != null) ? wrap : false; - this.clipped = (clipped != null) ? clipped : false; - this.overflow = (overflow != null) ? overflow : 'visible'; - this.labelPadding = (labelPadding != null) ? labelPadding : 0; -}; - -/** - * Extends mxShape. - */ -mxText.prototype = new mxShape(); -mxText.prototype.constructor = mxText; - -/** - * Variable: replaceLinefeeds - * - * Specifies if linefeeds in HTML labels should be replaced with BR tags. - * Default is true. This is also used in <mxImageExport> to export the label. - */ -mxText.prototype.replaceLinefeeds = true; - -/** - * Variable: ieVerticalFilter - * - * Holds the filter definition for vertical text in IE. Default is - * progid:DXImageTransform.Microsoft.BasicImage(rotation=3). - */ -mxText.prototype.ieVerticalFilter = 'progid:DXImageTransform.Microsoft.BasicImage(rotation=3)'; - -/** - * Variable: verticalTextDegree - * - * Specifies the degree to be used for vertical text. Default is -90. - */ -mxText.prototype.verticalTextDegree = -90; - -/** - * Variable: forceIgnoreStringSize - * - * Specifies if the string size should always be ignored. Default is false. - * This can be used to improve rendering speed in slow browsers. This can be - * used if all labels are smaller than the vertex width. String sizes are - * ignored by default for labels which are left aligned with no background and - * border or if the overflow is set to fill. - */ -mxText.prototype.forceIgnoreStringSize = false; - -/** - * Function: isStyleSet - * - * Returns true if the given font style (bold, italic etc) - * is true in this shape's fontStyle. - * - * Parameters: - * - * style - Fontstyle constant from <mxConstants>. - */ -mxText.prototype.isStyleSet = function(style) -{ - return (this.fontStyle & style) == style; -}; - -/** - * Function: create - * - * Override to create HTML regardless of gradient and - * rounded property. - */ -mxText.prototype.create = function(container) -{ - var node = null; - - if (this.dialect == mxConstants.DIALECT_SVG) - { - node = this.createSvg(); - } - else if (this.dialect == mxConstants.DIALECT_STRICTHTML || - this.dialect == mxConstants.DIALECT_PREFERHTML || - !mxUtils.isVml(container)) - { - if (mxClient.IS_SVG && !mxClient.NO_FO) - { - node = this.createForeignObject(); - } - else - { - node = this.createHtml(); - } - } - else - { - node = this.createVml(); - } - - return node; -}; - -/** - * Function: updateBoundingBox - * - * Overrides method to do nothing. - */ -mxText.prototype.updateBoundingBox = function() -{ - // do nothing -}; - -/** - * Function: createForeignObject - * - * Creates and returns the foreignObject node to represent this shape. - */ -mxText.prototype.createForeignObject = function() -{ - var node = document.createElementNS(mxConstants.NS_SVG, 'g'); - - var fo = document.createElementNS(mxConstants.NS_SVG, 'foreignObject'); - fo.setAttribute('pointer-events', 'fill'); - - // Ignored in FF - if (this.overflow == 'hidden') - { - fo.style.overflow = 'hidden'; - } - else - { - // Fill and default are visible - fo.style.overflow = 'visible'; - } - - var body = document.createElement('div'); - body.style.margin = '0px'; - body.style.height = '100%'; - - fo.appendChild(body); - node.appendChild(fo); - - return node; -}; - -/** - * Function: createHtml - * - * Creates and returns the HTML node to represent this shape. - */ -mxText.prototype.createHtml = function() -{ - var table = this.createHtmlTable(); - table.style.position = 'absolute'; - - return table; -}; - -/** - * Function: createVml - * - * Creates and returns the VML node(s) to represent this shape. - */ -mxText.prototype.createVml = function() -{ - return document.createElement('v:textbox'); -}; - -/** - * Function: redrawHtml - * - * Updates the HTML node(s) to reflect the latest bounds and scale. - */ -mxText.prototype.redrawHtml = function() -{ - this.redrawVml(); -}; - -/** - * Function: getOffset - * - * Returns the description of the space between the <bounds> size and the label - * size as an <mxPoint>. - */ -mxText.prototype.getOffset = function(outerWidth, outerHeight, actualWidth, actualHeight, horizontal) -{ - horizontal = (horizontal != null) ? horizontal : this.horizontal; - - var tmpalign = (horizontal) ? this.align : this.valign; - var tmpvalign = (horizontal) ? this.valign : this.align; - var dx = actualWidth - outerWidth; - var dy = actualHeight - outerHeight; - - if (tmpalign == mxConstants.ALIGN_CENTER || tmpalign == mxConstants.ALIGN_MIDDLE) - { - dx = Math.round(dx / 2); - } - else if (tmpalign == mxConstants.ALIGN_LEFT || tmpalign === mxConstants.ALIGN_TOP) - { - dx = (horizontal) ? 0 : (actualWidth - actualHeight) / 2; - } - else if (!horizontal) // BOTTOM - { - dx = (actualWidth + actualHeight) / 2 - outerWidth; - } - - if (tmpvalign == mxConstants.ALIGN_MIDDLE || tmpvalign == mxConstants.ALIGN_CENTER) - { - dy = Math.round(dy / 2); - } - else if (tmpvalign == mxConstants.ALIGN_TOP || tmpvalign == mxConstants.ALIGN_LEFT) - { - dy = (horizontal) ? 0 : (actualHeight + actualWidth) / 2 - outerHeight; - } - else if (!horizontal) // RIGHT - { - dy = (actualHeight - actualWidth) / 2; - } - - return new mxPoint(dx, dy); -}; - -/** - * Function: getSpacing - * - * Returns the spacing as an <mxPoint>. - */ -mxText.prototype.getSpacing = function(horizontal) -{ - horizontal = (horizontal != null) ? horizontal : this.horizontal; - - var dx = 0; - var dy = 0; - - if (this.align == mxConstants.ALIGN_CENTER) - { - dx = (this.spacingLeft - this.spacingRight) / 2; - } - else if (this.align == mxConstants.ALIGN_RIGHT) - { - dx = -this.spacingRight; - } - else - { - dx = this.spacingLeft; - } - - if (this.valign == mxConstants.ALIGN_MIDDLE) - { - dy = (this.spacingTop - this.spacingBottom) / 2; - } - else if (this.valign == mxConstants.ALIGN_BOTTOM) - { - dy = -this.spacingBottom; - } - else - { - dy = this.spacingTop; - } - - return (horizontal) ? new mxPoint(dx, dy) : new mxPoint(dy, dx); -}; - -/** - * Function: createHtmlTable - * - * Creates and returns a HTML table with a table body and a single row with a - * single cell. - */ -mxText.prototype.createHtmlTable = function() -{ - var table = document.createElement('table'); - table.style.borderCollapse = 'collapse'; - var tbody = document.createElement('tbody'); - var tr = document.createElement('tr'); - var td = document.createElement('td'); - - // Workaround for ignored table height in IE9 standards mode - if (document.documentMode >= 9) - { - // FIXME: Ignored in print preview for IE9 standards mode - td.style.height = '100%'; - } - - tr.appendChild(td); - tbody.appendChild(tr); - table.appendChild(tbody); - - return table; -}; - -/** - * Function: updateTableStyle - * - * Updates the style of the given HTML table and the value - * within the table. - */ -mxText.prototype.updateHtmlTable = function(table, scale) -{ - scale = (scale != null) ? scale : 1; - var td = table.firstChild.firstChild.firstChild; - - // Reset of width required to measure actual width after word wrap - if (this.wrap) - { - table.style.width = ''; - } - - // Updates the value - if (mxUtils.isNode(this.value)) - { - if (td.firstChild != this.value) - { - if (td.firstChild != null) - { - td.removeChild(td.firstChild); - } - - td.appendChild(this.value); - } - } - else - { - if (this.lastValue != this.value) - { - td.innerHTML = (this.replaceLinefeeds) ? this.value.replace(/\n/g, '<br/>') : this.value; - this.lastValue = this.value; - } - } - - // Font style - var fontSize = Math.round(this.size * scale); - - if (fontSize <= 0) - { - table.style.visibility = 'hidden'; - } - else - { - // Do not use visible here as it will clone - // all labels while panning in IE - table.style.visibility = ''; - } - - table.style.fontSize = fontSize + 'px'; - table.style.color = this.color; - table.style.fontFamily = this.family; - - // Bold - if (this.isStyleSet(mxConstants.FONT_BOLD)) - { - table.style.fontWeight = 'bold'; - } - else - { - table.style.fontWeight = 'normal'; - } - - // Italic - if (this.isStyleSet(mxConstants.FONT_ITALIC)) - { - table.style.fontStyle = 'italic'; - } - else - { - table.style.fontStyle = ''; - } - - // Underline - if (this.isStyleSet(mxConstants.FONT_UNDERLINE)) - { - table.style.textDecoration = 'underline'; - } - else - { - table.style.textDecoration = ''; - } - - // Font shadow (only available in IE) - if (mxClient.IS_IE) - { - if (this.isStyleSet(mxConstants.FONT_SHADOW)) - { - td.style.filter = 'Shadow(Color=#666666,'+'Direction=135,Strength=%)'; - } - else - { - td.style.removeAttribute('filter'); - } - } - - // Horizontal and vertical alignment - td.style.textAlign = - (this.align == mxConstants.ALIGN_RIGHT) ? 'right' : - ((this.align == mxConstants.ALIGN_CENTER) ? 'center' : - 'left'); - td.style.verticalAlign = - (this.valign == mxConstants.ALIGN_BOTTOM) ? 'bottom' : - ((this.valign == mxConstants.ALIGN_MIDDLE) ? 'middle' : - 'top'); - - // Background style (Must use TD not TABLE for Firefox when rotated) - if (this.value.length > 0 && this.background != null) - { - td.style.background = this.background; - } - else - { - td.style.background = ''; - } - - td.style.padding = this.labelPadding + 'px'; - - if (this.value.length > 0 && this.border != null) - { - table.style.borderColor = this.border; - table.style.borderWidth = '1px'; - table.style.borderStyle = 'solid'; - } - else - { - table.style.borderStyle = 'none'; - } -}; - -/** - * Function: getTableSize - * - * Returns the actual size of the table. - */ -mxText.prototype.getTableSize = function(table) -{ - return new mxRectangle(0, 0, table.offsetWidth, table.offsetHeight); -}; - -/** - * Function: updateTableWidth - * - * Updates the width of the given HTML table. - */ -mxText.prototype.updateTableWidth = function(table) -{ - var td = table.firstChild.firstChild.firstChild; - - // Word-wrap for vertices (not edges) and only if not - // just getting the bounding box in SVG - if (this.wrap && this.bounds.width > 0 && this.dialect != mxConstants.DIALECT_SVG) - { - // Makes sure the label is not wrapped when measuring full length - td.style.whiteSpace = 'nowrap'; - var size = this.getTableSize(table); - var space = Math.min(size.width, ((this.horizontal || mxUtils.isVml(this.node)) ? - this.bounds.width : this.bounds.height) / this.scale); - - // Opera needs the new width to be scaled - if (mxClient.IS_OP) - { - space *= this.scale; - } - - table.style.width = Math.round(space) + 'px'; - td.style.whiteSpace = 'normal'; - } - else - { - table.style.width = ''; - } - - if (!this.wrap) - { - td.style.whiteSpace = 'nowrap'; - } - else - { - td.style.whiteSpace = 'normal'; - } -}; - -/** - * Function: redrawVml - * - * Updates the VML node(s) to reflect the latest bounds and scale. - */ -mxText.prototype.redrawVml = function() -{ - if (this.node.nodeName == 'g') - { - this.redrawForeignObject(); - } - else if (mxUtils.isVml(this.node)) - { - this.redrawTextbox(); - } - else - { - this.redrawHtmlTable(); - } -}; - -/** - * Function: redrawTextbox - * - * Redraws the textbox for this text. This is only used in IE in exact - * rendering mode. - */ -mxText.prototype.redrawTextbox = function() -{ - // Gets VML textbox - var textbox = this.node; - - // Creates HTML container on the fly - if (textbox.firstChild == null) - { - textbox.appendChild(this.createHtmlTable()); - } - - // Updates the table style and value - var table = textbox.firstChild; - this.updateHtmlTable(table); - this.updateTableWidth(table); - - // Opacity - if (this.opacity != null) - { - mxUtils.setOpacity(table, this.opacity); - } - - table.style.filter = ''; - textbox.inset = '0px,0px,0px,0px'; - - if (this.overflow != 'fill') - { - // Only tables can be used to work out the actual size of the markup - var size = this.getTableSize(table); - var w = size.width * this.scale; - var h = size.height * this.scale; - var offset = this.getOffset(this.bounds.width, this.bounds.height, w, h); - - // Rotates the label (IE only) - if (!this.horizontal) - { - table.style.filter = this.ieVerticalFilter; - } - - // Adds horizontal/vertical spacing - var spacing = this.getSpacing(); - var x = this.bounds.x - offset.x + spacing.x * this.scale; - var y = this.bounds.y - offset.y + spacing.y * this.scale; - - // Textboxes are always relative to their parent shape's top, left corner so - // we use the inset for absolute positioning as they allow negative values - // except for edges where the bounds are used to find the shape center - var x0 = this.bounds.x; - var y0 = this.bounds.y; - var ow = this.bounds.width; - var oh = this.bounds.height; - - // Insets are given as left, top, right, bottom - if (this.horizontal) - { - var tx = Math.round(x - x0); - var ty = Math.round(y - y0); - - var r = Math.min(0, Math.round(x0 + ow - x - w - 1)); - var b = Math.min(0, Math.round(y0 + oh - y - h - 1)); - textbox.inset = tx + 'px,' + ty + 'px,' + r + 'px,' + b + 'px'; - } - else - { - var t = 0; - var l = 0; - var r = 0; - var b = 0; - - if (this.align == mxConstants.ALIGN_CENTER) - { - t = (oh - w) / 2; - b = t; - } - else if (this.align == mxConstants.ALIGN_LEFT) - { - t = oh - w; - } - else - { - b = oh - w; - } - - if (this.valign == mxConstants.ALIGN_MIDDLE) - { - l = (ow - h) / 2; - r = l; - } - else if (this.valign == mxConstants.ALIGN_BOTTOM) - { - l = ow - h; - } - else - { - r = ow - h; - } - - textbox.inset = l + 'px,' + t + 'px,' + r + 'px,' + b + 'px'; - } - - textbox.style.zoom = this.scale; - - // Clipping - if (this.clipped && this.bounds.width > 0 && this.bounds.height > 0) - { - this.boundingBox = this.bounds.clone(); - var dx = Math.round(x0 - x); - var dy = Math.round(y0 - y); - - textbox.style.clip = 'rect(' + (dy / this.scale) + ' ' + - ((dx + this.bounds.width) / this.scale) + ' ' + - ((dy + this.bounds.height) / this.scale) + ' ' + - (dx / this.scale) + ')'; - } - else - { - this.boundingBox = new mxRectangle(x, y, w, h); - } - } - else - { - this.boundingBox = this.bounds.clone(); - } -}; - -/** - * Function: redrawHtmlTable - * - * Redraws the HTML table. This is used for HTML labels in all modes except - * exact in IE and if NO_FO is false for the browser. - */ -mxText.prototype.redrawHtmlTable = function() -{ - if (isNaN(this.bounds.x) || isNaN(this.bounds.y) || - isNaN(this.bounds.width) || isNaN(this.bounds.height)) - { - return; - } - - // Gets table - var table = this.node; - var td = table.firstChild.firstChild.firstChild; - - // Un-rotates for computing the actual size - // TODO: Check if the result can be tweaked instead in getActualSize - // and only do this if actual rotation did change - var oldBrowser = false; - var fallbackScale = 1; - - if (mxClient.IS_IE) - { - table.style.removeAttribute('filter'); - } - else if (mxClient.IS_SF || mxClient.IS_GC) - { - table.style.WebkitTransform = ''; - } - else if (mxClient.IS_MT) - { - table.style.MozTransform = ''; - td.style.MozTransform = ''; - } - else - { - if (mxClient.IS_OT) - { - table.style.OTransform = ''; - } - - fallbackScale = this.scale; - oldBrowser = true; - } - - // Resets the current zoom for text measuring - td.style.zoom = ''; - - // Updates the table style and value - this.updateHtmlTable(table, fallbackScale); - this.updateTableWidth(table); - - // Opacity - if (this.opacity != null) - { - mxUtils.setOpacity(table, this.opacity); - } - - // Resets the bounds for computing the actual size - table.style.left = ''; - table.style.top = ''; - table.style.height = ''; - - // Workaround for multiple zoom even if CSS style is reset here - var currentZoom = parseFloat(td.style.zoom) || 1; - - // Only tables can be used to work out the actual size of the markup - // NOTE: offsetWidth and offsetHeight are very slow in quirks and IE 8 standards mode - var w = this.bounds.width; - var h = this.bounds.height; - - var ignoreStringSize = this.forceIgnoreStringSize || this.overflow == 'fill' || - (this.align == mxConstants.ALIGN_LEFT && this.background == null && this.border == null); - - if (!ignoreStringSize) - { - var size = this.getTableSize(table); - w = size.width / currentZoom; - h = size.height / currentZoom; - } - - var offset = this.getOffset(this.bounds.width / this.scale, - this.bounds.height / this.scale, w, h, - oldBrowser || this.horizontal); - - // Adds horizontal/vertical spacing - var spacing = this.getSpacing(oldBrowser || this.horizontal); - var x = this.bounds.x / this.scale - offset.x + spacing.x; - var y = this.bounds.y / this.scale - offset.y + spacing.y; - - // Updates the table bounds and stores the scale to be used for - // defining the table width and height, as well as an offset - var s = this.scale; - var s2 = 1; - var shiftX = 0; - var shiftY = 0; - - // Rotates the label and adds offset - if (!this.horizontal) - { - if (mxClient.IS_IE && mxClient.IS_SVG) - { - table.style.msTransform = 'rotate(' + this.verticalTextDegree + 'deg)'; - } - else if (mxClient.IS_IE) - { - table.style.filter = this.ieVerticalFilter; - shiftX = (w - h) / 2; - shiftY = -shiftX; - } - else if (mxClient.IS_SF || mxClient.IS_GC) - { - table.style.WebkitTransform = 'rotate(' + this.verticalTextDegree + 'deg)'; - } - else if (mxClient.IS_OT) - { - table.style.OTransform = 'rotate(' + this.verticalTextDegree + 'deg)'; - } - else if (mxClient.IS_MT) - { - // Firefox paints background and border only if background is on TD - // and border is on TABLE and both are rotated, just the TD with a - // rotation of zero (don't remove the 0-rotate CSS style) - table.style.MozTransform = 'rotate(' + this.verticalTextDegree + 'deg)'; - td.style.MozTransform = 'rotate(0deg)'; - - s2 = 1 / this.scale; - s = 1; - } - } - - // Sets the zoom - var correction = true; - - if (mxClient.IS_MT || oldBrowser) - { - if (mxClient.IS_MT) - { - table.style.MozTransform += ' scale(' + this.scale + ')'; - s2 = 1 / this.scale; - } - else if (mxClient.IS_OT) - { - td.style.OTransform = 'scale(' + this.scale + ')'; - table.style.borderWidth = Math.round(this.scale * parseInt(table.style.borderWidth)) + 'px'; - } - } - else if (!oldBrowser) - { - // Workaround for unsupported zoom CSS in IE9 standards mode - if (document.documentMode >= 9) - { - td.style.msTransform = 'scale(' + this.scale + ')'; - } - // Uses transform in Webkit for better HTML scaling - else if (mxClient.IS_SF || mxClient.IS_GC) - { - td.style.WebkitTransform = 'scale(' + this.scale + ')'; - } - else - { - td.style.zoom = this.scale; - - // Fixes scaling of border width - if (table.style.borderWidth != '' && document.documentMode != 8) - { - table.style.borderWidth = Math.round(this.scale * parseInt(table.style.borderWidth)) + 'px'; - } - - // Workaround for wrong scale in IE8 standards mode - if (document.documentMode == 8 || !mxClient.IS_IE) - { - s = 1; - } - - correction = false; - } - } - - if (correction) - { - // Workaround for scaled TD position - shiftX = (this.scale - 1) * w / (2 * this.scale); - shiftY = (this.scale - 1) * h / (2 * this.scale); - s = 1; - } - - if (this.overflow != 'fill') - { - var rect = new mxRectangle(Math.round((x + shiftX) * this.scale), - Math.round((y + shiftY) * this.scale), Math.round(w * s), Math.round(h * s)); - table.style.left = rect.x + 'px'; - table.style.top = rect.y + 'px'; - table.style.width = rect.width + 'px'; - table.style.height = rect.height + 'px'; - - // Workaround for wrong scale in border and background rendering for table and td in IE8/9 standards mode - if ((this.background != null || this.border != null) && document.documentMode >= 8) - { - var html = (this.replaceLinefeeds) ? this.value.replace(/\n/g, '<br/>') : this.value; - td.innerHTML = '<div style="padding:' + this.labelPadding + 'px;background:' + td.style.background + ';border:' + table.style.border + '">' + html + '</div>'; - td.style.padding = '0px'; - td.style.background = ''; - table.style.border = ''; - } - - // Clipping - if (this.clipped && this.bounds.width > 0 && this.bounds.height > 0) - { - this.boundingBox = this.bounds.clone(); - - // Clipping without rotation or for older browsers - if (this.horizontal || (oldBrowser && !mxClient.IS_OT)) - { - var dx = Math.max(0, offset.x * s); - var dy = Math.max(0, offset.y * s); - - // TODO: Fix clipping for Opera - table.style.clip = 'rect(' + (dy) + 'px ' + (dx + this.bounds.width * s2) + - 'px ' + (dy + this.bounds.height * s2) + 'px ' + (dx) + 'px)'; - } - else - { - // Workaround for IE clip using top, right, bottom, left (un-rotated) - if (mxClient.IS_IE) - { - var uw = this.bounds.width; - var uh = this.bounds.height; - var dx = 0; - var dy = 0; - - if (this.align == mxConstants.ALIGN_LEFT) - { - dx = Math.max(0, w - uh / this.scale) * this.scale; - } - else if (this.align == mxConstants.ALIGN_CENTER) - { - dx = Math.max(0, w - uh / this.scale) * this.scale / 2; - } - - if (this.valign == mxConstants.ALIGN_BOTTOM) - { - dy = Math.max(0, h - uw / this.scale) * this.scale; - } - else if (this.valign == mxConstants.ALIGN_MIDDLE) - { - dy = Math.max(0, h - uw / this.scale) * this.scale / 2; - } - - table.style.clip = 'rect(' + (dx) + 'px ' + (dy + uw - 1) + - 'px ' + (dx + uh - 1) + 'px ' + (dy) + 'px)'; - } - else - { - var uw = this.bounds.width / this.scale; - var uh = this.bounds.height / this.scale; - - if (mxClient.IS_OT) - { - uw = this.bounds.width; - uh = this.bounds.height; - } - - var dx = 0; - var dy = 0; - - if (this.align == mxConstants.ALIGN_RIGHT) - { - dx = Math.max(0, w - uh); - } - else if (this.align == mxConstants.ALIGN_CENTER) - { - dx = Math.max(0, w - uh) / 2; - } - - if (this.valign == mxConstants.ALIGN_BOTTOM) - { - dy = Math.max(0, h - uw); - } - else if (this.valign == mxConstants.ALIGN_MIDDLE) - { - dy = Math.max(0, h - uw) / 2; - } - - if (mxClient.IS_GC || mxClient.IS_SF) - { - dx *= this.scale; - dy *= this.scale; - uw *= this.scale; - uh *= this.scale; - } - - table.style.clip = 'rect(' + (dy) + ' ' + (dx + uh) + - ' ' + (dy + uw) + ' ' + (dx) + ')'; - } - } - } - else - { - this.boundingBox = rect; - } - } - else - { - this.boundingBox = this.bounds.clone(); - - if (document.documentMode >= 9 || mxClient.IS_SVG) - { - table.style.left = Math.round(this.bounds.x + this.scale / 2 + shiftX) + 'px'; - table.style.top = Math.round(this.bounds.y + this.scale / 2 + shiftY) + 'px'; - table.style.width = Math.round((this.bounds.width - this.scale) / this.scale) + 'px'; - table.style.height = Math.round((this.bounds.height - this.scale) / this.scale) + 'px'; - } - else - { - s = (document.documentMode == 8) ? this.scale : 1; - table.style.left = Math.round(this.bounds.x + this.scale / 2) + 'px'; - table.style.top = Math.round(this.bounds.y + this.scale / 2) + 'px'; - table.style.width = Math.round((this.bounds.width - this.scale) / s) + 'px'; - table.style.height = Math.round((this.bounds.height - this.scale) / s) + 'px'; - } - } -}; - -/** - * Function: getVerticalOffset - * - * Returns the factors for the offset to be added to the text vertical - * text rotation. This implementation returns (offset.y, -offset.x). - */ -mxText.prototype.getVerticalOffset = function(offset) -{ - return new mxPoint(offset.y, -offset.x); -}; - -/** - * Function: redrawForeignObject - * - * Redraws the foreign object for this text. - */ -mxText.prototype.redrawForeignObject = function() -{ - // Gets SVG group with foreignObject - var group = this.node; - var fo = group.firstChild; - - // Searches the table which appears behind the background - while (fo == this.backgroundNode) - { - fo = fo.nextSibling; - } - - var body = fo.firstChild; - - // Creates HTML container on the fly - if (body.firstChild == null) - { - body.appendChild(this.createHtmlTable()); - } - - // Updates the table style and value - var table = body.firstChild; - this.updateHtmlTable(table); - - // Workaround for bug in Google Chrome where the text is moved to origin if opacity - // is set on the table, so we set the opacity on the foreignObject instead. - if (this.opacity != null) - { - fo.setAttribute('opacity', this.opacity / 100); - } - - // Workaround for table background not appearing above the shape that is - // behind the label in Safari. To solve this, we add a background rect that - // paints the background instead. - if (mxClient.IS_SF) - { - table.style.borderStyle = 'none'; - table.firstChild.firstChild.firstChild.style.background = ''; - - if (this.backgroundNode == null && (this.background != null || this.border != null)) - { - this.backgroundNode = document.createElementNS(mxConstants.NS_SVG, 'rect'); - group.insertBefore(this.backgroundNode, group.firstChild); - } - else if (this.backgroundNode != null && this.background == null && this.border == null) - { - this.backgroundNode.parentNode.removeChild(this.backgroundNode); - this.backgroundNode = null; - } - - if (this.backgroundNode != null) - { - if (this.background != null) - { - this.backgroundNode.setAttribute('fill', this.background); - } - else - { - this.backgroundNode.setAttribute('fill', 'none'); - } - - if (this.border != null) - { - this.backgroundNode.setAttribute('stroke', this.border); - } - else - { - this.backgroundNode.setAttribute('stroke', 'none'); - } - } - } - - var tr = ''; - - if (this.overflow != 'fill') - { - // Resets the bounds for computing the actual size - fo.removeAttribute('width'); - fo.removeAttribute('height'); - fo.style.width = ''; - fo.style.height = ''; - fo.style.clip = ''; - - // Workaround for size of table not updated if inside foreignObject - if (this.wrap || (!mxClient.IS_GC && !mxClient.IS_SF)) - { - document.body.appendChild(table); - } - - this.updateTableWidth(table); - - // Only tables can be used to work out the actual size of the markup - var size = this.getTableSize(table); - var w = size.width; - var h = size.height; - - if (table.parentNode != body) - { - body.appendChild(table); - } - - // Adds horizontal/vertical spacing - var spacing = this.getSpacing(); - - var x = this.bounds.x / this.scale + spacing.x; - var y = this.bounds.y / this.scale + spacing.y; - var uw = this.bounds.width / this.scale; - var uh = this.bounds.height / this.scale; - var offset = this.getOffset(uw, uh, w, h); - - // Rotates the label and adds offset - if (this.horizontal) - { - x -= offset.x; - y -= offset.y; - - tr = 'scale(' + this.scale + ')'; - } - else - { - var x0 = x + w / 2; - var y0 = y + h / 2; - - tr = 'scale(' + this.scale + ') rotate(' + this.verticalTextDegree + ' ' + x0 + ' ' + y0 + ')'; - - var tmp = this.getVerticalOffset(offset); - x += tmp.x; - y += tmp.y; - } - - // Must use translate instead of x- and y-attribute on FO for iOS - tr += ' translate(' + x + ' ' + y + ')'; - - // Updates the bounds of the background node in Webkit - if (this.backgroundNode != null) - { - this.backgroundNode.setAttribute('width', w); - this.backgroundNode.setAttribute('height', h); - } - - // Updates the foreignObject size - fo.setAttribute('width', w); - fo.setAttribute('height', h); - - // Clipping - // TODO: Fix/check clipping for foreignObjects in Chrome 5.0 - if clipPath - // is used in the group then things can no longer be moved around - if (this.clipped && this.bounds.width > 0 && this.bounds.height > 0) - { - this.boundingBox = this.bounds.clone(); - var dx = Math.max(0, offset.x); - var dy = Math.max(0, offset.y); - - if (this.horizontal) - { - fo.style.clip = 'rect(' + dy + 'px,' + (dx + uw) + - 'px,' + (dy + uh) + 'px,' + (dx) + 'px)'; - } - else - { - var dx = 0; - var dy = 0; - - if (this.align == mxConstants.ALIGN_RIGHT) - { - dx = Math.max(0, w - uh); - } - else if (this.align == mxConstants.ALIGN_CENTER) - { - dx = Math.max(0, w - uh) / 2; - } - - if (this.valign == mxConstants.ALIGN_BOTTOM) - { - dy = Math.max(0, h - uw); - } - else if (this.valign == mxConstants.ALIGN_MIDDLE) - { - dy = Math.max(0, h - uw) / 2; - } - - fo.style.clip = 'rect(' + (dy) + 'px,' + (dx + uh) + - 'px,' + (dy + uw) + 'px,' + (dx) + 'px)'; - } - - // Clipping for the background node in Chrome - if (this.backgroundNode != null) - { - x = this.bounds.x / this.scale; - y = this.bounds.y / this.scale; - - if (!this.horizontal) - { - x += (h + w) / 2 - uh; - y += (h - w) / 2; - - var tmp = uw; - uw = uh; - uh = tmp; - } - - // No clipping in Chome available due to bug - if (!mxClient.IS_GC) - { - var clip = this.getSvgClip(this.node.ownerSVGElement, x, y, uw, uh); - - if (clip != this.clip) - { - this.releaseSvgClip(); - this.clip = clip; - clip.refCount++; - } - - this.backgroundNode.setAttribute('clip-path', 'url(#' + clip.getAttribute('id') + ')'); - } - } - } - else - { - // Removes clipping from background and cleans up the clip - this.releaseSvgClip(); - - if (this.backgroundNode != null) - { - this.backgroundNode.removeAttribute('clip-path'); - } - - if (this.horizontal) - { - this.boundingBox = new mxRectangle(x * this.scale, y * this.scale, w * this.scale, h * this.scale); - } - else - { - this.boundingBox = new mxRectangle(x * this.scale, y * this.scale, h * this.scale, w * this.scale); - } - } - } - else - { - this.boundingBox = this.bounds.clone(); - - var s = this.scale; - var w = this.bounds.width / s; - var h = this.bounds.height / s; - - // Updates the foreignObject and table bounds - fo.setAttribute('width', w); - fo.setAttribute('height', h); - table.style.width = w + 'px'; - table.style.height = h + 'px'; - - // Updates the bounds of the background node in Webkit - if (this.backgroundNode != null) - { - this.backgroundNode.setAttribute('width', table.clientWidth); - this.backgroundNode.setAttribute('height', table.offsetHeight); - } - - // Must use translate instead of x- and y-attribute on FO for iOS - tr = 'scale(' + s + ') translate(' + (this.bounds.x / s) + - ' ' + (this.bounds.y / s) + ')'; - - if (!this.wrap) - { - var td = table.firstChild.firstChild.firstChild; - td.style.whiteSpace = 'nowrap'; - } - } - - group.setAttribute('transform', tr); -}; - -/** - * Function: createSvg - * - * Creates and returns the SVG node(s) to represent this shape. - */ -mxText.prototype.createSvg = function() -{ - // Creates a group so that shapes inside are rendered properly, if this is - // a text node then the background rectangle is not rendered in Webkit. - var node = document.createElementNS(mxConstants.NS_SVG, 'g'); - - var uline = this.isStyleSet(mxConstants.FONT_UNDERLINE) ? 'underline' : 'none'; - var weight = this.isStyleSet(mxConstants.FONT_BOLD) ? 'bold' : 'normal'; - var s = this.isStyleSet(mxConstants.FONT_ITALIC) ? 'italic' : null; - - // Underline is not implemented in FF, see - // https://bugzilla.mozilla.org/show_bug.cgi?id=317196 - node.setAttribute('text-decoration', uline); - node.setAttribute('font-family', this.family); - node.setAttribute('font-weight', weight); - node.setAttribute('font-size', Math.round(this.size * this.scale) + 'px'); - node.setAttribute('fill', this.color); - var align = (this.align == mxConstants.ALIGN_RIGHT) ? 'end' : - (this.align == mxConstants.ALIGN_CENTER) ? 'middle' : - 'start'; - node.setAttribute('text-anchor', align); - - if (s != null) - { - node.setAttribute('font-style', s); - } - - // Adds a rectangle for the background color - if (this.background != null || this.border != null) - { - this.backgroundNode = document.createElementNS(mxConstants.NS_SVG, 'rect'); - this.backgroundNode.setAttribute('shape-rendering', 'crispEdges'); - - if (this.background != null) - { - this.backgroundNode.setAttribute('fill', this.background); - } - else - { - this.backgroundNode.setAttribute('fill', 'none'); - } - - if (this.border != null) - { - this.backgroundNode.setAttribute('stroke', this.border); - } - else - { - this.backgroundNode.setAttribute('stroke', 'none'); - } - } - - this.updateSvgValue(node); - - return node; -}; - -/** - * Updates the text represented by the SVG DOM nodes. - */ -mxText.prototype.updateSvgValue = function(node) -{ - if (this.currentValue != this.value) - { - // Removes all existing children - while (node.firstChild != null) - { - node.removeChild(node.firstChild); - } - - if (this.value != null) - { - // Adds tspan elements for the lines - var uline = this.isStyleSet(mxConstants.FONT_UNDERLINE) ? 'underline' : 'none'; - var lines = this.value.split('\n'); - - // Workaround for empty lines breaking the return value of getBBox - // for the enclosing g element so we avoid adding empty lines - // but still count them as a linefeed - this.textNodes = new Array(lines.length); - - for (var i = 0; i < lines.length; i++) - { - if (!this.isEmptyString(lines[i])) - { - var tspan = this.createSvgSpan(lines[i]); - node.appendChild(tspan); - this.textNodes[i] = tspan; - - // Requires either 'inherit' in Webkit or explicit setting - // to work in Webkit and IE9 standards mode. Both, inherit - // and underline do not work in FF. This is a known bug in - // FF (see above). - tspan.setAttribute('text-decoration', uline); - } - else - { - this.textNodes[i] = null; - } - } - } - - this.currentValue = this.value; - } -}; - -/** - * Function: redrawSvg - * - * Updates the SVG node(s) to reflect the latest bounds and scale. - */ -mxText.prototype.redrawSvg = function() -{ - if (this.node.nodeName == 'foreignObject') - { - this.redrawHtml(); - - return; - } - - var fontSize = Math.round(this.size * this.scale); - - if (fontSize <= 0) - { - this.node.setAttribute('visibility', 'hidden'); - } - else - { - this.node.removeAttribute('visibility'); - } - - this.updateSvgValue(this.node); - this.node.setAttribute('font-size', fontSize + 'px'); - - if (this.opacity != null) - { - // Improves opacity performance in Firefox - this.node.setAttribute('fill-opacity', this.opacity/100); - this.node.setAttribute('stroke-opacity', this.opacity/100); - } - - // Workaround to avoid the use of getBBox to find the size - // of the label. A temporary HTML table is created instead. - var previous = this.value; - var table = this.createHtmlTable(); - - // Makes sure the table is updated and replaces all HTML entities - this.lastValue = null; - this.value = mxUtils.htmlEntities(this.value, false); - this.updateHtmlTable(table); - - // Adds the table to the DOM to find the actual size - document.body.appendChild(table); - var w = table.offsetWidth * this.scale; - var h = table.offsetHeight * this.scale; - - // Cleans up the DOM and restores the original value - table.parentNode.removeChild(table); - this.value = previous; - - // Sets the bounding box for the unclipped case so that - // the full background can be painted using it, the initial - // value for dx and the +4 in the width below are for - // error correction of the HTML and SVG text width - var dx = 2 * this.scale; - - if (this.align == mxConstants.ALIGN_CENTER) - { - dx += w / 2; - } - else if (this.align == mxConstants.ALIGN_RIGHT) - { - dx += w; - } - - var dy = Math.round(fontSize * 1.3); - var childCount = this.node.childNodes.length; - var lineCount = (this.textNodes != null) ? this.textNodes.length : 0; - - if (this.backgroundNode != null) - { - childCount--; - } - - var x = this.bounds.x; - var y = this.bounds.y; - - x += (this.align == mxConstants.ALIGN_RIGHT) ? - ((this.horizontal) ? this.bounds.width : this.bounds.height)- - this.spacingRight * this.scale : - (this.align == mxConstants.ALIGN_CENTER) ? - this.spacingLeft * this.scale + - (((this.horizontal) ? this.bounds.width : this.bounds.height) - - this.spacingLeft * this.scale - this.spacingRight * this.scale) / 2 : - this.spacingLeft * this.scale + 1; - - // Makes sure the alignment is like in VML and HTML - y += (this.valign == mxConstants.ALIGN_BOTTOM) ? - ((this.horizontal) ? this.bounds.height : this.bounds.width) - - (lineCount - 1) * dy - this.spacingBottom * this.scale - 4 : - (this.valign == mxConstants.ALIGN_MIDDLE) ? - (this.spacingTop * this.scale + - ((this.horizontal) ? this.bounds.height : this.bounds.width) - - this.spacingBottom * this.scale - - (lineCount - 1.5) * dy) / 2 : - this.spacingTop * this.scale + dy; - - if (this.overflow == 'fill') - { - if (this.align == mxConstants.ALIGN_CENTER) - { - x = Math.max(this.bounds.x + w / 2, x); - } - - y = Math.max(this.bounds.y + fontSize, y); - - this.boundingBox = new mxRectangle(x - dx, y - dy, - w + 4 * this.scale, h + 1 * this.scale); - this.boundingBox.x = Math.min(this.bounds.x, this.boundingBox.x); - this.boundingBox.y = Math.min(this.bounds.y, this.boundingBox.y); - this.boundingBox.width = Math.max(this.bounds.width, this.boundingBox.width); - this.boundingBox.height = Math.max(this.bounds.height, this.boundingBox.height); - } - else - { - this.boundingBox = new mxRectangle(x - dx, y - dy, - w + 4 * this.scale, h + 1 * this.scale); - } - - if (!this.horizontal) - { - var cx = this.bounds.x + this.bounds.width / 2; - var cy = this.bounds.y + this.bounds.height / 2; - - var offsetX = (this.bounds.width - this.bounds.height) / 2; - var offsetY = (this.bounds.height - this.bounds.width) / 2; - - this.node.setAttribute('transform', - 'rotate(' + this.verticalTextDegree + ' ' + cx + ' ' + cy + ') ' + - 'translate(' + (-offsetY) + ' ' + (-offsetX) + ')'); - } - - // TODO: Font-shadow - this.redrawSvgTextNodes(x, y, dy); - - /* - * FIXME: Bounding box is not rotated. This seems to be a problem for - * all vertical text boxes. Workaround is in mxImageExport. - if (!this.horizontal) - { - var b = this.bounds.y + this.bounds.height; - var cx = this.boundingBox.getCenterX() - this.bounds.x; - var cy = this.boundingBox.getCenterY() - this.bounds.y; - - var y = b - cx - this.bounds.height / 2; - this.boundingBox.x = this.bounds.x + cy - this.boundingBox.width / 2; - this.boundingBox.y = y; - } - */ - - // Updates the bounds of the background node if one exists - if (this.value.length > 0 && this.backgroundNode != null && this.node.firstChild != null) - { - if (this.node.firstChild != this.backgroundNode) - { - this.node.insertBefore(this.backgroundNode, this.node.firstChild); - } - - // FIXME: For larger font sizes the linespacing between HTML and SVG - // seems to be different and hence the bounding box isn't accurate. - // Also in Firefox the background box is slighly offset. - this.backgroundNode.setAttribute('x', this.boundingBox.x + this.scale / 2 + 1 * this.scale); - this.backgroundNode.setAttribute('y', this.boundingBox.y + this.scale / 2 + 2 * this.scale - this.labelPadding); - this.backgroundNode.setAttribute('width', this.boundingBox.width - this.scale - 2 * this.scale); - this.backgroundNode.setAttribute('height', this.boundingBox.height - this.scale); - - var strokeWidth = Math.round(Math.max(1, this.scale)); - this.backgroundNode.setAttribute('stroke-width', strokeWidth); - } - - // Adds clipping and updates the bounding box - if (this.clipped && this.bounds.width > 0 && this.bounds.height > 0) - { - this.boundingBox = this.bounds.clone(); - - if (!this.horizontal) - { - this.boundingBox.width = this.bounds.height; - this.boundingBox.height = this.bounds.width; - } - - x = this.bounds.x; - y = this.bounds.y; - - if (this.horizontal) - { - w = this.bounds.width; - h = this.bounds.height; - } - else - { - w = this.bounds.height; - h = this.bounds.width; - } - - var clip = this.getSvgClip(this.node.ownerSVGElement, x, y, w, h); - - if (clip != this.clip) - { - this.releaseSvgClip(); - this.clip = clip; - clip.refCount++; - } - - this.node.setAttribute('clip-path', 'url(#' + clip.getAttribute('id') + ')'); - } - else - { - this.releaseSvgClip(); - this.node.removeAttribute('clip-path'); - } -}; - -/** - * Function: redrawSvgTextNodes - * - * Hook to update the position of the SVG text nodes. - */ -mxText.prototype.redrawSvgTextNodes = function(x, y, dy) -{ - if (this.textNodes != null) - { - var currentY = y; - - for (var i = 0; i < this.textNodes.length; i++) - { - var node = this.textNodes[i]; - - if (node != null) - { - node.setAttribute('x', x); - node.setAttribute('y', currentY); - - // Triggers an update in Firefox 1.5.0.x (don't add a semicolon!) - node.setAttribute('style', 'pointer-events: all'); - } - - currentY += dy; - } - } -}; - -/** - * Function: releaseSvgClip - * - * Releases the given SVG clip removing it from the DOM if required. - */ -mxText.prototype.releaseSvgClip = function() -{ - if (this.clip != null) - { - this.clip.refCount--; - - if (this.clip.refCount == 0) - { - this.clip.parentNode.removeChild(this.clip); - } - - this.clip = null; - } -}; - -/** - * Function: getSvgClip - * - * Returns a new or existing SVG clip path which is a descendant of the given - * SVG node with a unique ID. - */ -mxText.prototype.getSvgClip = function(svg, x, y, w, h) -{ - x = Math.round(x); - y = Math.round(y); - w = Math.round(w); - h = Math.round(h); - - var id = 'mx-clip-' + x + '-' + y + '-' + w + '-' + h; - - // Quick access - if (this.clip != null && this.clip.ident == id) - { - return this.clip; - } - - var counter = 0; - var tmp = id + '-' + counter; - var clip = document.getElementById(tmp); - - // Tries to find an existing clip in the given SVG - while (clip != null) - { - if (clip.ownerSVGElement == svg) - { - return clip; - } - - counter++; - tmp = id + '-' + counter; - clip = document.getElementById(tmp); - } - - // Creates a new clip node and adds it to the DOM - if (clip != null) - { - clip = clip.cloneNode(true); - counter++; - } - else - { - clip = document.createElementNS(mxConstants.NS_SVG, 'clipPath'); - - var rect = document.createElementNS(mxConstants.NS_SVG, 'rect'); - rect.setAttribute('x', x); - rect.setAttribute('y', y); - rect.setAttribute('width', w); - rect.setAttribute('height', h); - - clip.appendChild(rect); - } - - clip.setAttribute('id', id + '-' + counter); - clip.ident = id; // For quick access above - svg.appendChild(clip); - clip.refCount = 0; - - return clip; -}; - -/** - * Function: isEmptyString - * - * Returns true if the given string is empty or - * contains only whitespace. - */ -mxText.prototype.isEmptyString = function(text) -{ - return text.replace(/ /g, '').length == 0; -}; - -/** - * Function: createSvgSpan - * - * Creats an SVG tspan node for the given text. - */ -mxText.prototype.createSvgSpan = function(text) -{ - // Creates a text node since there is no enclosing text element but - // rather a group, which is required to render the background rectangle - // in Webkit. This can be changed to tspan if the enclosing node is - // a text but this leads to an hidden background in Webkit. - var node = document.createElementNS(mxConstants.NS_SVG, 'text'); - // Needed to preserve multiple white spaces, but ignored in IE9 plus white-space:pre - // is ignored in HTML output for VML, so better to not use this for SVG labels - // node.setAttributeNS('http://www.w3.org/XML/1998/namespace', 'xml:space', 'preserve') - // Alternative idea is to replace all spaces with to fix HTML in IE, but - // IE9/10 with SVG will still ignore the xml:space preserve tag as discussed here: - // http://stackoverflow.com/questions/8086292/significant-whitespace-in-svg-embedded-in-html - // Could replace spaces with in text but HTML tags must be scaped first. - mxUtils.write(node, text); - - return node; -}; - -/** - * Function: destroy - * - * Extends destroy to remove any allocated SVG clips. - */ -mxText.prototype.destroy = function() -{ - this.releaseSvgClip(); - mxShape.prototype.destroy.apply(this, arguments); -}; diff --git a/src/js/shape/mxTriangle.js b/src/js/shape/mxTriangle.js deleted file mode 100644 index 3a48db2..0000000 --- a/src/js/shape/mxTriangle.js +++ /dev/null @@ -1,34 +0,0 @@ -/** - * $Id: mxTriangle.js,v 1.10 2011-09-02 10:01:00 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -/** - * Class: mxTriangle - * - * Implementation of the triangle shape. - * - * Constructor: mxTriangle - * - * Constructs a new triangle shape. - */ -function mxTriangle() { }; - -/** - * Extends <mxActor>. - */ -mxTriangle.prototype = new mxActor(); -mxTriangle.prototype.constructor = mxTriangle; - -/** - * Function: redrawPath - * - * Draws the path for this shape. This method uses the <mxPath> - * abstraction to paint the shape for VML and SVG. - */ -mxTriangle.prototype.redrawPath = function(path, x, y, w, h) -{ - path.moveTo(0, 0); - path.lineTo(w, 0.5 * h); - path.lineTo(0, h); - path.close(); -}; diff --git a/src/js/util/mxAnimation.js b/src/js/util/mxAnimation.js deleted file mode 100644 index 80901ef..0000000 --- a/src/js/util/mxAnimation.js +++ /dev/null @@ -1,82 +0,0 @@ -/** - * $Id: mxAnimation.js,v 1.2 2010-03-19 12:53:29 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -/** - * - * Class: mxAnimation - * - * Implements a basic animation in JavaScript. - * - * Constructor: mxAnimation - * - * Constructs an animation. - * - * Parameters: - * - * graph - Reference to the enclosing <mxGraph>. - */ -function mxAnimation(delay) -{ - this.delay = (delay != null) ? delay : 20; -}; - -/** - * Extends mxEventSource. - */ -mxAnimation.prototype = new mxEventSource(); -mxAnimation.prototype.constructor = mxAnimation; - -/** - * Variable: delay - * - * Specifies the delay between the animation steps. Defaul is 30ms. - */ -mxAnimation.prototype.delay = null; - -/** - * Variable: thread - * - * Reference to the thread while the animation is running. - */ -mxAnimation.prototype.thread = null; - -/** - * Function: startAnimation - * - * Starts the animation by repeatedly invoking updateAnimation. - */ -mxAnimation.prototype.startAnimation = function() -{ - if (this.thread == null) - { - this.thread = window.setInterval(mxUtils.bind(this, this.updateAnimation), this.delay); - } -}; - -/** - * Function: updateAnimation - * - * Hook for subclassers to implement the animation. Invoke stopAnimation - * when finished, startAnimation to resume. This is called whenever the - * timer fires and fires an mxEvent.EXECUTE event with no properties. - */ -mxAnimation.prototype.updateAnimation = function() -{ - this.fireEvent(new mxEventObject(mxEvent.EXECUTE)); -}; - -/** - * Function: stopAnimation - * - * Stops the animation by deleting the timer and fires an <mxEvent.DONE>. - */ -mxAnimation.prototype.stopAnimation = function() -{ - if (this.thread != null) - { - window.clearInterval(this.thread); - this.thread = null; - this.fireEvent(new mxEventObject(mxEvent.DONE)); - } -}; diff --git a/src/js/util/mxAutoSaveManager.js b/src/js/util/mxAutoSaveManager.js deleted file mode 100644 index 85c23dc..0000000 --- a/src/js/util/mxAutoSaveManager.js +++ /dev/null @@ -1,213 +0,0 @@ -/** - * $Id: mxAutoSaveManager.js,v 1.9 2010-09-16 09:10:21 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -/** - * Class: mxAutoSaveManager - * - * Manager for automatically saving diagrams. The <save> hook must be - * implemented. - * - * Example: - * - * (code) - * var mgr = new mxAutoSaveManager(editor.graph); - * mgr.save = function() - * { - * mxLog.show(); - * mxLog.debug('save'); - * }; - * (end) - * - * Constructor: mxAutoSaveManager - * - * Constructs a new automatic layout for the given graph. - * - * Arguments: - * - * graph - Reference to the enclosing graph. - */ -function mxAutoSaveManager(graph) -{ - // Notifies the manager of a change - this.changeHandler = mxUtils.bind(this, function(sender, evt) - { - if (this.isEnabled()) - { - this.graphModelChanged(evt.getProperty('edit').changes); - } - }); - - this.setGraph(graph); -}; - -/** - * Extends mxEventSource. - */ -mxAutoSaveManager.prototype = new mxEventSource(); -mxAutoSaveManager.prototype.constructor = mxAutoSaveManager; - -/** - * Variable: graph - * - * Reference to the enclosing <mxGraph>. - */ -mxAutoSaveManager.prototype.graph = null; - -/** - * Variable: autoSaveDelay - * - * Minimum amount of seconds between two consecutive autosaves. Eg. a - * value of 1 (s) means the graph is not stored more than once per second. - * Default is 10. - */ -mxAutoSaveManager.prototype.autoSaveDelay = 10; - -/** - * Variable: autoSaveThrottle - * - * Minimum amount of seconds between two consecutive autosaves triggered by - * more than <autoSaveThreshhold> changes within a timespan of less than - * <autoSaveDelay> seconds. Eg. a value of 1 (s) means the graph is not - * stored more than once per second even if there are more than - * <autoSaveThreshold> changes within that timespan. Default is 2. - */ -mxAutoSaveManager.prototype.autoSaveThrottle = 2; - -/** - * Variable: autoSaveThreshold - * - * Minimum amount of ignored changes before an autosave. Eg. a value of 2 - * means after 2 change of the graph model the autosave will trigger if the - * condition below is true. Default is 5. - */ -mxAutoSaveManager.prototype.autoSaveThreshold = 5; - -/** - * Variable: ignoredChanges - * - * Counter for ignored changes in autosave. - */ -mxAutoSaveManager.prototype.ignoredChanges = 0; - -/** - * Variable: lastSnapshot - * - * Used for autosaving. See <autosave>. - */ -mxAutoSaveManager.prototype.lastSnapshot = 0; - -/** - * Variable: enabled - * - * Specifies if event handling is enabled. Default is true. - */ -mxAutoSaveManager.prototype.enabled = true; - -/** - * Variable: changeHandler - * - * Holds the function that handles graph model changes. - */ -mxAutoSaveManager.prototype.changeHandler = null; - -/** - * Function: isEnabled - * - * Returns true if events are handled. This implementation - * returns <enabled>. - */ -mxAutoSaveManager.prototype.isEnabled = function() -{ - return this.enabled; -}; - -/** - * Function: setEnabled - * - * Enables or disables event handling. This implementation - * updates <enabled>. - * - * Parameters: - * - * enabled - Boolean that specifies the new enabled state. - */ -mxAutoSaveManager.prototype.setEnabled = function(value) -{ - this.enabled = value; -}; - -/** - * Function: setGraph - * - * Sets the graph that the layouts operate on. - */ -mxAutoSaveManager.prototype.setGraph = function(graph) -{ - if (this.graph != null) - { - this.graph.getModel().removeListener(this.changeHandler); - } - - this.graph = graph; - - if (this.graph != null) - { - this.graph.getModel().addListener(mxEvent.CHANGE, this.changeHandler); - } -}; - -/** - * Function: save - * - * Empty hook that is called if the graph should be saved. - */ -mxAutoSaveManager.prototype.save = function() -{ - // empty -}; - -/** - * Function: graphModelChanged - * - * Invoked when the graph model has changed. - */ -mxAutoSaveManager.prototype.graphModelChanged = function(changes) -{ - var now = new Date().getTime(); - var dt = (now - this.lastSnapshot) / 1000; - - if (dt > this.autoSaveDelay || - (this.ignoredChanges >= this.autoSaveThreshold && - dt > this.autoSaveThrottle)) - { - this.save(); - this.reset(); - } - else - { - // Increments the number of ignored changes - this.ignoredChanges++; - } -}; - -/** - * Function: reset - * - * Resets all counters. - */ -mxAutoSaveManager.prototype.reset = function() -{ - this.lastSnapshot = new Date().getTime(); - this.ignoredChanges = 0; -}; - -/** - * Function: destroy - * - * Removes all handlers from the <graph> and deletes the reference to it. - */ -mxAutoSaveManager.prototype.destroy = function() -{ - this.setGraph(null); -}; diff --git a/src/js/util/mxClipboard.js b/src/js/util/mxClipboard.js deleted file mode 100644 index e9fec6b..0000000 --- a/src/js/util/mxClipboard.js +++ /dev/null @@ -1,144 +0,0 @@ -/** - * $Id: mxClipboard.js,v 1.29 2010-01-02 09:45:14 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -var mxClipboard = -{ - /** - * Class: mxClipboard - * - * Singleton that implements a clipboard for graph cells. - * - * Example: - * - * (code) - * mxClipboard.copy(graph); - * mxClipboard.paste(graph2); - * (end) - * - * This copies the selection cells from the graph to the - * clipboard and pastes them into graph2. - * - * For fine-grained control of the clipboard data the <mxGraph.canExportCell> - * and <mxGraph.canImportCell> functions can be overridden. - * - * Variable: STEPSIZE - * - * Defines the step size to offset the cells - * after each paste operation. Default is 10. - */ - STEPSIZE: 10, - - /** - * Variable: insertCount - * - * Counts the number of times the clipboard data has been inserted. - */ - insertCount: 1, - - /** - * Variable: cells - * - * Holds the array of <mxCells> currently in the clipboard. - */ - cells: null, - - /** - * Function: isEmpty - * - * Returns true if the clipboard currently has not data stored. - */ - isEmpty: function() - { - return mxClipboard.cells == null; - }, - - /** - * Function: cut - * - * Cuts the given array of <mxCells> from the specified graph. - * If cells is null then the selection cells of the graph will - * be used. Returns the cells that have been cut from the graph. - * - * Parameters: - * - * graph - <mxGraph> that contains the cells to be cut. - * cells - Optional array of <mxCells> to be cut. - */ - cut: function(graph, cells) - { - cells = mxClipboard.copy(graph, cells); - mxClipboard.insertCount = 0; - mxClipboard.removeCells(graph, cells); - - return cells; - }, - - /** - * Function: removeCells - * - * Hook to remove the given cells from the given graph after - * a cut operation. - * - * Parameters: - * - * graph - <mxGraph> that contains the cells to be cut. - * cells - Array of <mxCells> to be cut. - */ - removeCells: function(graph, cells) - { - graph.removeCells(cells); - }, - - /** - * Function: copy - * - * Copies the given array of <mxCells> from the specified - * graph to <cells>.Returns the original array of cells that has - * been cloned. - * - * Parameters: - * - * graph - <mxGraph> that contains the cells to be copied. - * cells - Optional array of <mxCells> to be copied. - */ - copy: function(graph, cells) - { - cells = cells || graph.getSelectionCells(); - var result = graph.getExportableCells(cells); - mxClipboard.insertCount = 1; - mxClipboard.cells = graph.cloneCells(result); - - return result; - }, - - /** - * Function: paste - * - * Pastes the <cells> into the specified graph restoring - * the relation to <parents>, if possible. If the parents - * are no longer in the graph or invisible then the - * cells are added to the graph's default or into the - * swimlane under the cell's new location if one exists. - * The cells are added to the graph using <mxGraph.importCells>. - * - * Parameters: - * - * graph - <mxGraph> to paste the <cells> into. - */ - paste: function(graph) - { - if (mxClipboard.cells != null) - { - var cells = graph.getImportableCells(mxClipboard.cells); - var delta = mxClipboard.insertCount * mxClipboard.STEPSIZE; - var parent = graph.getDefaultParent(); - cells = graph.importCells(cells, delta, delta, parent); - - // Increments the counter and selects the inserted cells - mxClipboard.insertCount++; - graph.setSelectionCells(cells); - } - } - -}; diff --git a/src/js/util/mxConstants.js b/src/js/util/mxConstants.js deleted file mode 100644 index 8d11dc1..0000000 --- a/src/js/util/mxConstants.js +++ /dev/null @@ -1,1911 +0,0 @@ -/** - * $Id: mxConstants.js,v 1.127 2012-11-20 09:06:07 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ - var mxConstants = - { - /** - * Class: mxConstants - * - * Defines various global constants. - * - * Variable: DEFAULT_HOTSPOT - * - * Defines the portion of the cell which is to be used as a connectable - * region. Default is 0.3. Possible values are 0 < x <= 1. - */ - DEFAULT_HOTSPOT: 0.3, - - /** - * Variable: MIN_HOTSPOT_SIZE - * - * Defines the minimum size in pixels of the portion of the cell which is - * to be used as a connectable region. Default is 8. - */ - MIN_HOTSPOT_SIZE: 8, - - /** - * Variable: MAX_HOTSPOT_SIZE - * - * Defines the maximum size in pixels of the portion of the cell which is - * to be used as a connectable region. Use 0 for no maximum. Default is 0. - */ - MAX_HOTSPOT_SIZE: 0, - - /** - * Variable: RENDERING_HINT_EXACT - * - * Defines the exact rendering hint. - */ - RENDERING_HINT_EXACT: 'exact', - - /** - * Variable: RENDERING_HINT_FASTER - * - * Defines the faster rendering hint. - */ - RENDERING_HINT_FASTER: 'faster', - - /** - * Variable: RENDERING_HINT_FASTEST - * - * Defines the fastest rendering hint. - */ - RENDERING_HINT_FASTEST: 'fastest', - - /** - * Variable: DIALECT_SVG - * - * Defines the SVG display dialect name. - */ - DIALECT_SVG: 'svg', - - /** - * Variable: DIALECT_VML - * - * Defines the VML display dialect name. - */ - DIALECT_VML: 'vml', - - /** - * Variable: DIALECT_MIXEDHTML - * - * Defines the mixed HTML display dialect name. - */ - DIALECT_MIXEDHTML: 'mixedHtml', - - /** - * Variable: DIALECT_PREFERHTML - * - * Defines the preferred HTML display dialect name. - */ - DIALECT_PREFERHTML: 'preferHtml', - - /** - * Variable: DIALECT_STRICTHTML - * - * Defines the strict HTML display dialect. - */ - DIALECT_STRICTHTML: 'strictHtml', - - /** - * Variable: NS_SVG - * - * Defines the SVG namespace. - */ - NS_SVG: 'http://www.w3.org/2000/svg', - - /** - * Variable: NS_XHTML - * - * Defines the XHTML namespace. - */ - NS_XHTML: 'http://www.w3.org/1999/xhtml', - - /** - * Variable: NS_XLINK - * - * Defines the XLink namespace. - */ - NS_XLINK: 'http://www.w3.org/1999/xlink', - - /** - * Variable: SHADOWCOLOR - * - * Defines the color to be used to draw shadows in shapes and windows. - * Default is gray. - */ - SHADOWCOLOR: 'gray', - - /** - * Variable: SHADOW_OFFSET_X - * - * Specifies the x-offset of the shadow. Default is 2. - */ - SHADOW_OFFSET_X: 2, - - /** - * Variable: SHADOW_OFFSET_Y - * - * Specifies the y-offset of the shadow. Default is 3. - */ - SHADOW_OFFSET_Y: 3, - - /** - * Variable: SHADOW_OPACITY - * - * Defines the opacity for shadows. Default is 1. - */ - SHADOW_OPACITY: 1, - - /** - * Variable: NODETYPE_ELEMENT - * - * DOM node of type ELEMENT. - */ - NODETYPE_ELEMENT: 1, - - /** - * Variable: NODETYPE_ATTRIBUTE - * - * DOM node of type ATTRIBUTE. - */ - NODETYPE_ATTRIBUTE: 2, - - /** - * Variable: NODETYPE_TEXT - * - * DOM node of type TEXT. - */ - NODETYPE_TEXT: 3, - - /** - * Variable: NODETYPE_CDATA - * - * DOM node of type CDATA. - */ - NODETYPE_CDATA: 4, - - /** - * Variable: NODETYPE_ENTITY_REFERENCE - * - * DOM node of type ENTITY_REFERENCE. - */ - NODETYPE_ENTITY_REFERENCE: 5, - - /** - * Variable: NODETYPE_ENTITY - * - * DOM node of type ENTITY. - */ - NODETYPE_ENTITY: 6, - - /** - * Variable: NODETYPE_PROCESSING_INSTRUCTION - * - * DOM node of type PROCESSING_INSTRUCTION. - */ - NODETYPE_PROCESSING_INSTRUCTION: 7, - - /** - * Variable: NODETYPE_COMMENT - * - * DOM node of type COMMENT. - */ - NODETYPE_COMMENT: 8, - - /** - * Variable: NODETYPE_DOCUMENT - * - * DOM node of type DOCUMENT. - */ - NODETYPE_DOCUMENT: 9, - - /** - * Variable: NODETYPE_DOCUMENTTYPE - * - * DOM node of type DOCUMENTTYPE. - */ - NODETYPE_DOCUMENTTYPE: 10, - - /** - * Variable: NODETYPE_DOCUMENT_FRAGMENT - * - * DOM node of type DOCUMENT_FRAGMENT. - */ - NODETYPE_DOCUMENT_FRAGMENT: 11, - - /** - * Variable: NODETYPE_NOTATION - * - * DOM node of type NOTATION. - */ - NODETYPE_NOTATION: 12, - - /** - * Variable: TOOLTIP_VERTICAL_OFFSET - * - * Defines the vertical offset for the tooltip. - * Default is 16. - */ - TOOLTIP_VERTICAL_OFFSET: 16, - - /** - * Variable: DEFAULT_VALID_COLOR - * - * Specifies the default valid colorr. Default is #0000FF. - */ - DEFAULT_VALID_COLOR: '#00FF00', - - /** - * Variable: DEFAULT_INVALID_COLOR - * - * Specifies the default invalid color. Default is #FF0000. - */ - DEFAULT_INVALID_COLOR: '#FF0000', - - /** - * Variable: HIGHLIGHT_STROKEWIDTH - * - * Defines the strokewidth to be used for the highlights. - * Default is 3. - */ - HIGHLIGHT_STROKEWIDTH: 3, - - /** - * Variable: CURSOR_MOVABLE_VERTEX - * - * Defines the cursor for a movable vertex. Default is 'move'. - */ - CURSOR_MOVABLE_VERTEX: 'move', - - /** - * Variable: CURSOR_MOVABLE_EDGE - * - * Defines the cursor for a movable edge. Default is 'move'. - */ - CURSOR_MOVABLE_EDGE: 'move', - - /** - * Variable: CURSOR_LABEL_HANDLE - * - * Defines the cursor for a movable label. Default is 'default'. - */ - CURSOR_LABEL_HANDLE: 'default', - - /** - * Variable: CURSOR_BEND_HANDLE - * - * Defines the cursor for a movable bend. Default is 'pointer'. - */ - CURSOR_BEND_HANDLE: 'pointer', - - /** - * Variable: CURSOR_CONNECT - * - * Defines the cursor for a connectable state. Default is 'pointer'. - */ - CURSOR_CONNECT: 'pointer', - - /** - * Variable: HIGHLIGHT_COLOR - * - * Defines the color to be used for the cell highlighting. - * Use 'none' for no color. Default is #00FF00. - */ - HIGHLIGHT_COLOR: '#00FF00', - - /** - * Variable: TARGET_HIGHLIGHT_COLOR - * - * Defines the color to be used for highlighting a target cell for a new - * or changed connection. Note that this may be either a source or - * target terminal in the graph. Use 'none' for no color. - * Default is #0000FF. - */ - CONNECT_TARGET_COLOR: '#0000FF', - - /** - * Variable: INVALID_CONNECT_TARGET_COLOR - * - * Defines the color to be used for highlighting a invalid target cells - * for a new or changed connections. Note that this may be either a source - * or target terminal in the graph. Use 'none' for no color. Default is - * #FF0000. - */ - INVALID_CONNECT_TARGET_COLOR: '#FF0000', - - /** - * Variable: DROP_TARGET_COLOR - * - * Defines the color to be used for the highlighting target parent cells - * (for drag and drop). Use 'none' for no color. Default is #0000FF. - */ - DROP_TARGET_COLOR: '#0000FF', - - /** - * Variable: VALID_COLOR - * - * Defines the color to be used for the coloring valid connection - * previews. Use 'none' for no color. Default is #FF0000. - */ - VALID_COLOR: '#00FF00', - - /** - * Variable: INVALID_COLOR - * - * Defines the color to be used for the coloring invalid connection - * previews. Use 'none' for no color. Default is #FF0000. - */ - INVALID_COLOR: '#FF0000', - - /** - * Variable: EDGE_SELECTION_COLOR - * - * Defines the color to be used for the selection border of edges. Use - * 'none' for no color. Default is #00FF00. - */ - EDGE_SELECTION_COLOR: '#00FF00', - - /** - * Variable: VERTEX_SELECTION_COLOR - * - * Defines the color to be used for the selection border of vertices. Use - * 'none' for no color. Default is #00FF00. - */ - VERTEX_SELECTION_COLOR: '#00FF00', - - /** - * Variable: VERTEX_SELECTION_STROKEWIDTH - * - * Defines the strokewidth to be used for vertex selections. - * Default is 1. - */ - VERTEX_SELECTION_STROKEWIDTH: 1, - - /** - * Variable: EDGE_SELECTION_STROKEWIDTH - * - * Defines the strokewidth to be used for edge selections. - * Default is 1. - */ - EDGE_SELECTION_STROKEWIDTH: 1, - - /** - * Variable: SELECTION_DASHED - * - * Defines the dashed state to be used for the vertex selection - * border. Default is true. - */ - VERTEX_SELECTION_DASHED: true, - - /** - * Variable: SELECTION_DASHED - * - * Defines the dashed state to be used for the edge selection - * border. Default is true. - */ - EDGE_SELECTION_DASHED: true, - - /** - * Variable: GUIDE_COLOR - * - * Defines the color to be used for the guidelines in mxGraphHandler. - * Default is #FF0000. - */ - GUIDE_COLOR: '#FF0000', - - /** - * Variable: GUIDE_STROKEWIDTH - * - * Defines the strokewidth to be used for the guidelines in mxGraphHandler. - * Default is 1. - */ - GUIDE_STROKEWIDTH: 1, - - /** - * Variable: OUTLINE_COLOR - * - * Defines the color to be used for the outline rectangle - * border. Use 'none' for no color. Default is #0099FF. - */ - OUTLINE_COLOR: '#0099FF', - - /** - * Variable: OUTLINE_STROKEWIDTH - * - * Defines the strokewidth to be used for the outline rectangle - * stroke width. Default is 3. - */ - OUTLINE_STROKEWIDTH: (mxClient.IS_IE) ? 2 : 3, - - /** - * Variable: HANDLE_SIZE - * - * Defines the default size for handles. Default is 7. - */ - HANDLE_SIZE: 7, - - /** - * Variable: LABEL_HANDLE_SIZE - * - * Defines the default size for label handles. Default is 4. - */ - LABEL_HANDLE_SIZE: 4, - - /** - * Variable: HANDLE_FILLCOLOR - * - * Defines the color to be used for the handle fill color. Use 'none' for - * no color. Default is #00FF00 (green). - */ - HANDLE_FILLCOLOR: '#00FF00', - - /** - * Variable: HANDLE_STROKECOLOR - * - * Defines the color to be used for the handle stroke color. Use 'none' for - * no color. Default is black. - */ - HANDLE_STROKECOLOR: 'black', - - /** - * Variable: LABEL_HANDLE_FILLCOLOR - * - * Defines the color to be used for the label handle fill color. Use 'none' - * for no color. Default is yellow. - */ - LABEL_HANDLE_FILLCOLOR: 'yellow', - - /** - * Variable: CONNECT_HANDLE_FILLCOLOR - * - * Defines the color to be used for the connect handle fill color. Use - * 'none' for no color. Default is #0000FF (blue). - */ - CONNECT_HANDLE_FILLCOLOR: '#0000FF', - - /** - * Variable: LOCKED_HANDLE_FILLCOLOR - * - * Defines the color to be used for the locked handle fill color. Use - * 'none' for no color. Default is #FF0000 (red). - */ - LOCKED_HANDLE_FILLCOLOR: '#FF0000', - - /** - * Variable: OUTLINE_HANDLE_FILLCOLOR - * - * Defines the color to be used for the outline sizer fill color. Use - * 'none' for no color. Default is #00FFFF. - */ - OUTLINE_HANDLE_FILLCOLOR: '#00FFFF', - - /** - * Variable: OUTLINE_HANDLE_STROKECOLOR - * - * Defines the color to be used for the outline sizer stroke color. Use - * 'none' for no color. Default is #0033FF. - */ - OUTLINE_HANDLE_STROKECOLOR: '#0033FF', - - /** - * Variable: DEFAULT_FONTFAMILY - * - * Defines the default family for all fonts in points. Default is - * Arial,Helvetica. - */ - DEFAULT_FONTFAMILY: 'Arial,Helvetica', - - /** - * Variable: DEFAULT_FONTSIZE - * - * Defines the default size for all fonts in points. Default is 11. - */ - DEFAULT_FONTSIZE: 11, - - /** - * Variable: DEFAULT_STARTSIZE - * - * Defines the default start size for swimlanes. Default is 40. - */ - DEFAULT_STARTSIZE: 40, - - /** - * Variable: DEFAULT_MARKERSIZE - * - * Defines the default size for all markers. Default is 6. - */ - DEFAULT_MARKERSIZE: 6, - - /** - * Variable: DEFAULT_IMAGESIZE - * - * Defines the default width and height for images used in the - * label shape. Default is 24. - */ - DEFAULT_IMAGESIZE: 24, - - /** - * Variable: ENTITY_SEGMENT - * - * Defines the length of the horizontal segment of an Entity Relation. - * This can be overridden using <mxConstants.STYLE_SEGMENT> style. - * Default is 30. - */ - ENTITY_SEGMENT: 30, - - /** - * Variable: RECTANGLE_ROUNDING_FACTOR - * - * Defines the rounding factor for rounded rectangles in percent between - * 0 and 1. Values should be smaller than 0.5. Default is 0.15. - */ - RECTANGLE_ROUNDING_FACTOR: 0.15, - - /** - * Variable: LINE_ARCSIZE - * - * Defines the size of the arcs for rounded edges. Default is 20. - */ - LINE_ARCSIZE: 20, - - /** - * Variable: ARROW_SPACING - * - * Defines the spacing between the arrow shape and its terminals. Default - * is 10. - */ - ARROW_SPACING: 10, - - /** - * Variable: ARROW_WIDTH - * - * Defines the width of the arrow shape. Default is 30. - */ - ARROW_WIDTH: 30, - - /** - * Variable: ARROW_SIZE - * - * Defines the size of the arrowhead in the arrow shape. Default is 30. - */ - ARROW_SIZE: 30, - - /** - * Variable: PAGE_FORMAT_A4_PORTRAIT - * - * Defines the rectangle for the A4 portrait page format. The dimensions - * of this page format are 826x1169 pixels. - */ - PAGE_FORMAT_A4_PORTRAIT: new mxRectangle(0, 0, 826, 1169), - - /** - * Variable: PAGE_FORMAT_A4_PORTRAIT - * - * Defines the rectangle for the A4 portrait page format. The dimensions - * of this page format are 826x1169 pixels. - */ - PAGE_FORMAT_A4_LANDSCAPE: new mxRectangle(0, 0, 1169, 826), - - /** - * Variable: PAGE_FORMAT_LETTER_PORTRAIT - * - * Defines the rectangle for the Letter portrait page format. The - * dimensions of this page format are 850x1100 pixels. - */ - PAGE_FORMAT_LETTER_PORTRAIT: new mxRectangle(0, 0, 850, 1100), - - /** - * Variable: PAGE_FORMAT_LETTER_PORTRAIT - * - * Defines the rectangle for the Letter portrait page format. The dimensions - * of this page format are 850x1100 pixels. - */ - PAGE_FORMAT_LETTER_LANDSCAPE: new mxRectangle(0, 0, 1100, 850), - - /** - * Variable: NONE - * - * Defines the value for none. Default is "none". - */ - NONE: 'none', - - /** - * Variable: STYLE_PERIMETER - * - * Defines the key for the perimeter style. This is a function that defines - * the perimeter around a particular shape. Possible values are the - * functions defined in <mxPerimeter>. Alternatively, the constants in this - * class that start with <code>PERIMETER_</code> may be used to access - * perimeter styles in <mxStyleRegistry>. - */ - STYLE_PERIMETER: 'perimeter', - - /** - * Variable: STYLE_SOURCE_PORT - * - * Defines the ID of the cell that should be used for computing the - * perimeter point of the source for an edge. This allows for graphically - * connecting to a cell while keeping the actual terminal of the edge. - */ - STYLE_SOURCE_PORT: 'sourcePort', - - /** - * Variable: STYLE_TARGET_PORT - * - * Defines the ID of the cell that should be used for computing the - * perimeter point of the target for an edge. This allows for graphically - * connecting to a cell while keeping the actual terminal of the edge. - */ - STYLE_TARGET_PORT: 'targetPort', - - /** - * Variable: STYLE_PORT_CONSTRAINT - * - * Defines the direction(s) that edges are allowed to connect to cells in. - * Possible values are <code>DIRECTION_NORTH, DIRECTION_SOUTH, - * DIRECTION_EAST</code> and <code>DIRECTION_WEST</code>. - */ - STYLE_PORT_CONSTRAINT: 'portConstraint', - - /** - * Variable: STYLE_OPACITY - * - * Defines the key for the opacity style. The type of the value is - * numeric and the possible range is 0-100. - */ - STYLE_OPACITY: 'opacity', - - /** - * Variable: STYLE_TEXT_OPACITY - * - * Defines the key for the text opacity style. The type of the value is - * numeric and the possible range is 0-100. - */ - STYLE_TEXT_OPACITY: 'textOpacity', - - /** - * Variable: STYLE_OVERFLOW - * - * Defines the key for the overflow style. Possible values are 'visible', - * 'hidden' and 'fill'. The default value is 'visible'. This value - * specifies how overlapping vertex labels are handled. A value of - * 'visible' will show the complete label. A value of 'hidden' will clip - * the label so that it does not overlap the vertex bounds. A value of - * 'fill' will use the vertex bounds for the label. See - * <mxGraph.isLabelClipped>. - */ - STYLE_OVERFLOW: 'overflow', - - /** - * Variable: STYLE_ORTHOGONAL - * - * Defines if the connection points on either end of the edge should be - * computed so that the edge is vertical or horizontal if possible and - * if the point is not at a fixed location. Default is false. This is - * used in <mxGraph.isOrthogonal>, which also returns true if the edgeStyle - * of the edge is an elbow or entity. - */ - STYLE_ORTHOGONAL: 'orthogonal', - - /** - * Variable: STYLE_EXIT_X - * - * Defines the key for the horizontal relative coordinate connection point - * of an edge with its source terminal. - */ - STYLE_EXIT_X: 'exitX', - - /** - * Variable: STYLE_EXIT_Y - * - * Defines the key for the vertical relative coordinate connection point - * of an edge with its source terminal. - */ - STYLE_EXIT_Y: 'exitY', - - /** - * Variable: STYLE_EXIT_PERIMETER - * - * Defines if the perimeter should be used to find the exact entry point - * along the perimeter of the source. Possible values are 0 (false) and - * 1 (true). Default is 1 (true). - */ - STYLE_EXIT_PERIMETER: 'exitPerimeter', - - /** - * Variable: STYLE_ENTRY_X - * - * Defines the key for the horizontal relative coordinate connection point - * of an edge with its target terminal. - */ - STYLE_ENTRY_X: 'entryX', - - /** - * Variable: STYLE_ENTRY_Y - * - * Defines the key for the vertical relative coordinate connection point - * of an edge with its target terminal. - */ - STYLE_ENTRY_Y: 'entryY', - - /** - * Variable: STYLE_ENTRY_PERIMETER - * - * Defines if the perimeter should be used to find the exact entry point - * along the perimeter of the target. Possible values are 0 (false) and - * 1 (true). Default is 1 (true). - */ - STYLE_ENTRY_PERIMETER: 'entryPerimeter', - - /** - * Variable: STYLE_WHITE_SPACE - * - * Defines the key for the white-space style. Possible values are 'nowrap' - * and 'wrap'. The default value is 'nowrap'. This value specifies how - * white-space inside a HTML vertex label should be handled. A value of - * 'nowrap' means the text will never wrap to the next line until a - * linefeed is encountered. A value of 'wrap' means text will wrap when - * necessary. This style is only used for HTML labels. - * See <mxGraph.isWrapping>. - */ - STYLE_WHITE_SPACE: 'whiteSpace', - - /** - * Variable: STYLE_ROTATION - * - * Defines the key for the rotation style. The type of the value is - * numeric and the possible range is 0-360. - */ - STYLE_ROTATION: 'rotation', - - /** - * Variable: STYLE_FILLCOLOR - * - * Defines the key for the fill color. Possible values are all HTML color - * names or HEX codes, as well as special keywords such as 'swimlane, - * 'inherit' or 'indicated' to use the color code of a related cell or the - * indicator shape. - */ - STYLE_FILLCOLOR: 'fillColor', - - /** - * Variable: STYLE_GRADIENTCOLOR - * - * Defines the key for the gradient color. Possible values are all HTML color - * names or HEX codes, as well as special keywords such as 'swimlane, - * 'inherit' or 'indicated' to use the color code of a related cell or the - * indicator shape. This is ignored if no fill color is defined. - */ - STYLE_GRADIENTCOLOR: 'gradientColor', - - /** - * Variable: STYLE_GRADIENT_DIRECTION - * - * Defines the key for the gradient direction. Possible values are - * <DIRECTION_EAST>, <DIRECTION_WEST>, <DIRECTION_NORTH> and - * <DIRECTION_SOUTH>. Default is <DIRECTION_SOUTH>. Generally, and by - * default in mxGraph, gradient painting is done from the value of - * <STYLE_FILLCOLOR> to the value of <STYLE_GRADIENTCOLOR>. Taking the - * example of <DIRECTION_NORTH>, this means <STYLE_FILLCOLOR> color at the - * bottom of paint pattern and <STYLE_GRADIENTCOLOR> at top, with a - * gradient in-between. - */ - STYLE_GRADIENT_DIRECTION: 'gradientDirection', - - /** - * Variable: STYLE_STROKECOLOR - * - * Defines the key for the strokeColor style. Possible values are all HTML - * color names or HEX codes, as well as special keywords such as 'swimlane, - * 'inherit', 'indicated' to use the color code of a related cell or the - * indicator shape or 'none' for no color. - */ - STYLE_STROKECOLOR: 'strokeColor', - - /** - * Variable: STYLE_SEPARATORCOLOR - * - * Defines the key for the separatorColor style. Possible values are all - * HTML color names or HEX codes. This style is only used for - * <SHAPE_SWIMLANE> shapes. - */ - STYLE_SEPARATORCOLOR: 'separatorColor', - - /** - * Variable: STYLE_STROKEWIDTH - * - * Defines the key for the strokeWidth style. The type of the value is - * numeric and the possible range is any non-negative value larger or equal - * to 1. The value defines the stroke width in pixels. Note: To hide a - * stroke use strokeColor none. - */ - STYLE_STROKEWIDTH: 'strokeWidth', - - /** - * Variable: STYLE_ALIGN - * - * Defines the key for the align style. Possible values are <ALIGN_LEFT>, - * <ALIGN_CENTER> and <ALIGN_RIGHT>. This value defines how the lines of - * the label are horizontally aligned. <ALIGN_LEFT> mean label text lines - * are aligned to left of the label bounds, <ALIGN_RIGHT> to the right of - * the label bounds and <ALIGN_CENTER> means the center of the text lines - * are aligned in the center of the label bounds. Note this value doesn't - * affect the positioning of the overall label bounds relative to the - * vertex, to move the label bounds horizontally, use - * <STYLE_LABEL_POSITION>. - */ - STYLE_ALIGN: 'align', - - /** - * Variable: STYLE_VERTICAL_ALIGN - * - * Defines the key for the verticalAlign style. Possible values are - * <ALIGN_TOP>, <ALIGN_MIDDLE> and <ALIGN_BOTTOM>. This value defines how - * the lines of the label are vertically aligned. <ALIGN_TOP> means the - * topmost label text line is aligned against the top of the label bounds, - * <ALIGN_BOTTOM> means the bottom-most label text line is aligned against - * the bottom of the label bounds and <ALIGN_MIDDLE> means there is equal - * spacing between the topmost text label line and the top of the label - * bounds and the bottom-most text label line and the bottom of the label - * bounds. Note this value doesn't affect the positioning of the overall - * label bounds relative to the vertex, to move the label bounds - * vertically, use <STYLE_VERTICAL_LABEL_POSITION>. - */ - STYLE_VERTICAL_ALIGN: 'verticalAlign', - - /** - * Variable: STYLE_LABEL_POSITION - * - * Defines the key for the horizontal label position of vertices. Possible - * values are <ALIGN_LEFT>, <ALIGN_CENTER> and <ALIGN_RIGHT>. Default is - * <ALIGN_CENTER>. The label align defines the position of the label - * relative to the cell. <ALIGN_LEFT> means the entire label bounds is - * placed completely just to the left of the vertex, <ALIGN_RIGHT> means - * adjust to the right and <ALIGN_CENTER> means the label bounds are - * vertically aligned with the bounds of the vertex. Note this value - * doesn't affect the positioning of label within the label bounds, to move - * the label horizontally within the label bounds, use <STYLE_ALIGN>. - */ - STYLE_LABEL_POSITION: 'labelPosition', - - /** - * Variable: STYLE_VERTICAL_LABEL_POSITION - * - * Defines the key for the vertical label position of vertices. Possible - * values are <ALIGN_TOP>, <ALIGN_BOTTOM> and <ALIGN_MIDDLE>. Default is - * <ALIGN_MIDDLE>. The label align defines the position of the label - * relative to the cell. <ALIGN_TOP> means the entire label bounds is - * placed completely just on the top of the vertex, <ALIGN_BOTTOM> means - * adjust on the bottom and <ALIGN_MIDDLE> means the label bounds are - * horizontally aligned with the bounds of the vertex. Note this value - * doesn't affect the positioning of label within the label bounds, to move - * the label vertically within the label bounds, use - * <STYLE_VERTICAL_ALIGN>. - */ - STYLE_VERTICAL_LABEL_POSITION: 'verticalLabelPosition', - - /** - * Variable: STYLE_IMAGE_ASPECT - * - * Defines the key for the image aspect style. Possible values are 0 (do - * not preserve aspect) or 1 (keep aspect). This is only used in - * <mxImageShape>. Default is 1. - */ - STYLE_IMAGE_ASPECT: 'imageAspect', - - /** - * Variable: STYLE_IMAGE_ALIGN - * - * Defines the key for the align style. Possible values are <ALIGN_LEFT>, - * <ALIGN_CENTER> and <ALIGN_RIGHT>. The value defines how any image in the - * vertex label is aligned horizontally within the label bounds of a - * <SHAPE_LABEL> shape. - */ - STYLE_IMAGE_ALIGN: 'imageAlign', - - /** - * Variable: STYLE_IMAGE_VERTICAL_ALIGN - * - * Defines the key for the verticalAlign style. Possible values are - * <ALIGN_TOP>, <ALIGN_MIDDLE> and <ALIGN_BOTTOM>. The value defines how - * any image in the vertex label is aligned vertically within the label - * bounds of a <SHAPE_LABEL> shape. - */ - STYLE_IMAGE_VERTICAL_ALIGN: 'imageVerticalAlign', - - /** - * Variable: STYLE_GLASS - * - * Defines the key for the glass style. Possible values are 0 (disabled) and - * 1(enabled). The default value is 0. This is used in <mxLabel>. - */ - STYLE_GLASS: 'glass', - - /** - * Variable: STYLE_IMAGE - * - * Defines the key for the image style. Possible values are any image URL, - * the type of the value is String. This is the path to the image to image - * that is to be displayed within the label of a vertex. Data URLs should - * use the following format: data:image/png,xyz where xyz is the base64 - * encoded data (without the "base64"-prefix). Note that Data URLs are only - * supported in modern browsers. - */ - STYLE_IMAGE: 'image', - - /** - * Variable: STYLE_IMAGE_WIDTH - * - * Defines the key for the imageWidth style. The type of this value is - * int, the value is the image width in pixels and must be greater than 0. - */ - STYLE_IMAGE_WIDTH: 'imageWidth', - - /** - * Variable: STYLE_IMAGE_HEIGHT - * - * Defines the key for the imageHeight style. The type of this value is - * int, the value is the image height in pixels and must be greater than 0. - */ - STYLE_IMAGE_HEIGHT: 'imageHeight', - - /** - * Variable: STYLE_IMAGE_BACKGROUND - * - * Defines the key for the image background color. This style is only used - * in <mxImageShape>. Possible values are all HTML color names or HEX - * codes. - */ - STYLE_IMAGE_BACKGROUND: 'imageBackground', - - /** - * Variable: STYLE_IMAGE_BORDER - * - * Defines the key for the image border color. This style is only used in - * <mxImageShape>. Possible values are all HTML color names or HEX codes. - */ - STYLE_IMAGE_BORDER: 'imageBorder', - - /** - * Variable: STYLE_IMAGE_FLIPH - * - * Defines the key for the horizontal image flip. This style is only used - * in <mxImageShape>. Possible values are 0 and 1. Default is 0. - */ - STYLE_IMAGE_FLIPH: 'imageFlipH', - - /** - * Variable: STYLE_IMAGE_FLIPV - * - * Defines the key for the vertical image flip. This style is only used - * in <mxImageShape>. Possible values are 0 and 1. Default is 0. - */ - STYLE_IMAGE_FLIPV: 'imageFlipV', - - /** - * Variable: STYLE_STENCIL_FLIPH - * - * Defines the key for the horizontal stencil flip. This style is only used - * for <mxStencilShape>. Possible values are 0 and 1. Default is 0. - */ - STYLE_STENCIL_FLIPH: 'stencilFlipH', - - /** - * Variable: STYLE_STENCIL_FLIPV - * - * Defines the key for the vertical stencil flip. This style is only used - * for <mxStencilShape>. Possible values are 0 and 1. Default is 0. - */ - STYLE_STENCIL_FLIPV: 'stencilFlipV', - - /** - * Variable: STYLE_NOLABEL - * - * Defines the key for the noLabel style. If this is - * true then no label is visible for a given cell. - * Possible values are true or false (1 or 0). - * Default is false. - */ - STYLE_NOLABEL: 'noLabel', - - /** - * Variable: STYLE_NOEDGESTYLE - * - * Defines the key for the noEdgeStyle style. If this is - * true then no edge style is applied for a given edge. - * Possible values are true or false (1 or 0). - * Default is false. - */ - STYLE_NOEDGESTYLE: 'noEdgeStyle', - - /** - * Variable: STYLE_LABEL_BACKGROUNDCOLOR - * - * Defines the key for the label background color. Possible values are all - * HTML color names or HEX codes. - */ - STYLE_LABEL_BACKGROUNDCOLOR: 'labelBackgroundColor', - - /** - * Variable: STYLE_LABEL_BORDERCOLOR - * - * Defines the key for the label border color. Possible values are all - * HTML color names or HEX codes. - */ - STYLE_LABEL_BORDERCOLOR: 'labelBorderColor', - - /** - * Variable: STYLE_LABEL_PADDING - * - * Defines the key for the label padding, ie. the space between the label - * border and the label. - */ - STYLE_LABEL_PADDING: 'labelPadding', - - /** - * Variable: STYLE_INDICATOR_SHAPE - * - * Defines the key for the indicator shape used within an <mxLabel>. - * Possible values are all SHAPE_* constants or the names of any new - * shapes. The indicatorShape has precedence over the indicatorImage. - */ - STYLE_INDICATOR_SHAPE: 'indicatorShape', - - /** - * Variable: STYLE_INDICATOR_IMAGE - * - * Defines the key for the indicator image used within an <mxLabel>. - * Possible values are all image URLs. The indicatorShape has - * precedence over the indicatorImage. - */ - STYLE_INDICATOR_IMAGE: 'indicatorImage', - - /** - * Variable: STYLE_INDICATOR_COLOR - * - * Defines the key for the indicatorColor style. Possible values are all - * HTML color names or HEX codes, as well as the special 'swimlane' keyword - * to refer to the color of the parent swimlane if one exists. - */ - STYLE_INDICATOR_COLOR: 'indicatorColor', - - /** - * Variable: STYLE_INDICATOR_STROKECOLOR - * - * Defines the key for the indicator stroke color in <mxLabel>. - * Possible values are all color codes. - */ - STYLE_INDICATOR_STROKECOLOR: 'indicatorStrokeColor', - - /** - * Variable: STYLE_INDICATOR_GRADIENTCOLOR - * - * Defines the key for the indicatorGradientColor style. Possible values - * are all HTML color names or HEX codes. This style is only supported in - * <SHAPE_LABEL> shapes. - */ - STYLE_INDICATOR_GRADIENTCOLOR: 'indicatorGradientColor', - - /** - * Variable: STYLE_INDICATOR_SPACING - * - * The defines the key for the spacing between the label and the - * indicator in <mxLabel>. Possible values are in pixels. - */ - STYLE_INDICATOR_SPACING: 'indicatorSpacing', - - /** - * Variable: STYLE_INDICATOR_WIDTH - * - * Defines the key for the indicator width. - * Possible values start at 0 (in pixels). - */ - STYLE_INDICATOR_WIDTH: 'indicatorWidth', - - /** - * Variable: STYLE_INDICATOR_HEIGHT - * - * Defines the key for the indicator height. - * Possible values start at 0 (in pixels). - */ - STYLE_INDICATOR_HEIGHT: 'indicatorHeight', - - /** - * Variable: STYLE_INDICATOR_DIRECTION - * - * Defines the key for the indicatorDirection style. The direction style is - * used to specify the direction of certain shapes (eg. <mxTriangle>). - * Possible values are <DIRECTION_EAST> (default), <DIRECTION_WEST>, - * <DIRECTION_NORTH> and <DIRECTION_SOUTH>. - */ - STYLE_INDICATOR_DIRECTION: 'indicatorDirection', - - /** - * Variable: STYLE_SHADOW - * - * Defines the key for the shadow style. The type of the value is Boolean. - */ - STYLE_SHADOW: 'shadow', - - /** - * Variable: STYLE_SEGMENT - * - * Defines the key for the segment style. The type of this value is - * float and the value represents the size of the horizontal - * segment of the entity relation style. Default is ENTITY_SEGMENT. - */ - STYLE_SEGMENT: 'segment', - - /** - * Variable: STYLE_ENDARROW - * - * Defines the key for the end arrow marker. - * Possible values are all constants with an ARROW-prefix. - * This is only used in <mxConnector>. - * - * Example: - * (code) - * style[mxConstants.STYLE_ENDARROW] = mxConstants.ARROW_CLASSIC; - * (end) - */ - STYLE_ENDARROW: 'endArrow', - - /** - * Variable: STYLE_STARTARROW - * - * Defines the key for the start arrow marker. - * Possible values are all constants with an ARROW-prefix. - * This is only used in <mxConnector>. - * See <STYLE_ENDARROW>. - */ - STYLE_STARTARROW: 'startArrow', - - /** - * Variable: STYLE_ENDSIZE - * - * Defines the key for the endSize style. The type of this value is numeric - * and the value represents the size of the end marker in pixels. - */ - STYLE_ENDSIZE: 'endSize', - - /** - * Variable: STYLE_STARTSIZE - * - * Defines the key for the startSize style. The type of this value is - * numeric and the value represents the size of the start marker or the - * size of the swimlane title region depending on the shape it is used for. - */ - STYLE_STARTSIZE: 'startSize', - - /** - * Variable: STYLE_ENDFILL - * - * Defines the key for the endFill style. Use 0 for no fill or 1 - * (default) for fill. (This style is only exported via <mxImageExport>.) - */ - STYLE_ENDFILL: 'endFill', - - /** - * Variable: STYLE_STARTFILL - * - * Defines the key for the startFill style. Use 0 for no fill or 1 - * (default) for fill. (This style is only exported via <mxImageExport>.) - */ - STYLE_STARTFILL: 'startFill', - - /** - * Variable: STYLE_DASHED - * - * Defines the key for the dashed style. Use 0 (default) for non-dashed or 1 - * for dashed. - */ - STYLE_DASHED: 'dashed', - - /** - * Defines the key for the dashed pattern style in SVG and image exports. - * The type of this value is a space separated list of numbers that specify - * a custom-defined dash pattern. Dash styles are defined in terms of the - * length of the dash (the drawn part of the stroke) and the length of the - * space between the dashes. The lengths are relative to the line width: a - * length of "1" is equal to the line width. VML ignores this style and - * uses dashStyle instead as defined in the VML specification. This style - * is only used in the <mxConnector> shape. - */ - STYLE_DASH_PATTERN: 'dashPattern', - - /** - * Variable: STYLE_ROUNDED - * - * Defines the key for the rounded style. The type of this value is - * Boolean. For edges this determines whether or not joins between edges - * segments are smoothed to a rounded finish. For vertices that have the - * rectangle shape, this determines whether or not the rectangle is - * rounded. - */ - STYLE_ROUNDED: 'rounded', - - /** - * Variable: STYLE_ARCSIZE - * - * Defines the rounding factor for a rounded rectangle in percent (without - * the percent sign). Possible values are between 0 and 100. If this value - * is not specified then RECTANGLE_ROUNDING_FACTOR * 100 is used. - * (This style is only exported via <mxImageExport>.) - */ - STYLE_ARCSIZE: 'arcSize', - - /** - * Variable: STYLE_SMOOTH - * - * An experimental style for edges. This style is currently not available - * in the backends and is implemented differently for VML and SVG. The use - * of this style is currently only recommended for VML. - */ - STYLE_SMOOTH: 'smooth', - - /** - * Variable: STYLE_SOURCE_PERIMETER_SPACING - * - * Defines the key for the source perimeter spacing. The type of this value - * is numeric. This is the distance between the source connection point of - * an edge and the perimeter of the source vertex in pixels. This style - * only applies to edges. - */ - STYLE_SOURCE_PERIMETER_SPACING: 'sourcePerimeterSpacing', - - /** - * Variable: STYLE_TARGET_PERIMETER_SPACING - * - * Defines the key for the target perimeter spacing. The type of this value - * is numeric. This is the distance between the target connection point of - * an edge and the perimeter of the target vertex in pixels. This style - * only applies to edges. - */ - STYLE_TARGET_PERIMETER_SPACING: 'targetPerimeterSpacing', - - /** - * Variable: STYLE_PERIMETER_SPACING - * - * Defines the key for the perimeter spacing. This is the distance between - * the connection point and the perimeter in pixels. When used in a vertex - * style, this applies to all incoming edges to floating ports (edges that - * terminate on the perimeter of the vertex). When used in an edge style, - * this spacing applies to the source and target separately, if they - * terminate in floating ports (on the perimeter of the vertex). - */ - STYLE_PERIMETER_SPACING: 'perimeterSpacing', - - /** - * Variable: STYLE_SPACING - * - * Defines the key for the spacing. The value represents the spacing, in - * pixels, added to each side of a label in a vertex (style applies to - * vertices only). - */ - STYLE_SPACING: 'spacing', - - /** - * Variable: STYLE_SPACING_TOP - * - * Defines the key for the spacingTop style. The value represents the - * spacing, in pixels, added to the top side of a label in a vertex (style - * applies to vertices only). - */ - STYLE_SPACING_TOP: 'spacingTop', - - /** - * Variable: STYLE_SPACING_LEFT - * - * Defines the key for the spacingLeft style. The value represents the - * spacing, in pixels, added to the left side of a label in a vertex (style - * applies to vertices only). - */ - STYLE_SPACING_LEFT: 'spacingLeft', - - /** - * Variable: STYLE_SPACING_BOTTOM - * - * Defines the key for the spacingBottom style The value represents the - * spacing, in pixels, added to the bottom side of a label in a vertex - * (style applies to vertices only). - */ - STYLE_SPACING_BOTTOM: 'spacingBottom', - - /** - * Variable: STYLE_SPACING_RIGHT - * - * Defines the key for the spacingRight style The value represents the - * spacing, in pixels, added to the right side of a label in a vertex (style - * applies to vertices only). - */ - STYLE_SPACING_RIGHT: 'spacingRight', - - /** - * Variable: STYLE_HORIZONTAL - * - * Defines the key for the horizontal style. Possible values are - * true or false. This value only applies to vertices. If the <STYLE_SHAPE> - * is <code>SHAPE_SWIMLANE</code> a value of false indicates that the - * swimlane should be drawn vertically, true indicates to draw it - * horizontally. If the shape style does not indicate that this vertex is a - * swimlane, this value affects only whether the label is drawn - * horizontally or vertically. - */ - STYLE_HORIZONTAL: 'horizontal', - - /** - * Variable: STYLE_DIRECTION - * - * Defines the key for the direction style. The direction style is used - * to specify the direction of certain shapes (eg. <mxTriangle>). - * Possible values are <DIRECTION_EAST> (default), <DIRECTION_WEST>, - * <DIRECTION_NORTH> and <DIRECTION_SOUTH>. - */ - STYLE_DIRECTION: 'direction', - - /** - * Variable: STYLE_ELBOW - * - * Defines the key for the elbow style. Possible values are - * <ELBOW_HORIZONTAL> and <ELBOW_VERTICAL>. Default is <ELBOW_HORIZONTAL>. - * This defines how the three segment orthogonal edge style leaves its - * terminal vertices. The vertical style leaves the terminal vertices at - * the top and bottom sides. - */ - STYLE_ELBOW: 'elbow', - - /** - * Variable: STYLE_FONTCOLOR - * - * Defines the key for the fontColor style. Possible values are all HTML - * color names or HEX codes. - */ - STYLE_FONTCOLOR: 'fontColor', - - /** - * Variable: STYLE_FONTFAMILY - * - * Defines the key for the fontFamily style. Possible values are names such - * as Arial; Dialog; Verdana; Times New Roman. The value is of type String. - */ - STYLE_FONTFAMILY: 'fontFamily', - - /** - * Variable: STYLE_FONTSIZE - * - * Defines the key for the fontSize style (in points). The type of the value - * is int. - */ - STYLE_FONTSIZE: 'fontSize', - - /** - * Variable: STYLE_FONTSTYLE - * - * Defines the key for the fontStyle style. Values may be any logical AND - * (sum) of <FONT_BOLD>, <FONT_ITALIC>, <FONT_UNDERLINE> and <FONT_SHADOW>. - * The type of the value is int. - */ - STYLE_FONTSTYLE: 'fontStyle', - - /** - * Variable: STYLE_AUTOSIZE - * - * Defines the key for the autosize style. This specifies if a cell should be - * resized automatically if the value has changed. Possible values are 0 or 1. - * Default is 0. See <mxGraph.isAutoSizeCell>. This is normally combined with - * <STYLE_RESIZABLE> to disable manual sizing. - */ - STYLE_AUTOSIZE: 'autosize', - - /** - * Variable: STYLE_FOLDABLE - * - * Defines the key for the foldable style. This specifies if a cell is foldable - * using a folding icon. Possible values are 0 or 1. Default is 1. See - * <mxGraph.isCellFoldable>. - */ - STYLE_FOLDABLE: 'foldable', - - /** - * Variable: STYLE_EDITABLE - * - * Defines the key for the editable style. This specifies if the value of - * a cell can be edited using the in-place editor. Possible values are 0 or - * 1. Default is 1. See <mxGraph.isCellEditable>. - */ - STYLE_EDITABLE: 'editable', - - /** - * Variable: STYLE_BENDABLE - * - * Defines the key for the bendable style. This specifies if the control - * points of an edge can be moved. Possible values are 0 or 1. Default is - * 1. See <mxGraph.isCellBendable>. - */ - STYLE_BENDABLE: 'bendable', - - /** - * Variable: STYLE_MOVABLE - * - * Defines the key for the movable style. This specifies if a cell can - * be moved. Possible values are 0 or 1. Default is 1. See - * <mxGraph.isCellMovable>. - */ - STYLE_MOVABLE: 'movable', - - /** - * Variable: STYLE_RESIZABLE - * - * Defines the key for the resizable style. This specifies if a cell can - * be resized. Possible values are 0 or 1. Default is 1. See - * <mxGraph.isCellResizable>. - */ - STYLE_RESIZABLE: 'resizable', - - /** - * Variable: STYLE_CLONEABLE - * - * Defines the key for the cloneable style. This specifies if a cell can - * be cloned. Possible values are 0 or 1. Default is 1. See - * <mxGraph.isCellCloneable>. - */ - STYLE_CLONEABLE: 'cloneable', - - /** - * Variable: STYLE_DELETABLE - * - * Defines the key for the deletable style. This specifies if a cell can be - * deleted. Possible values are 0 or 1. Default is 1. See - * <mxGraph.isCellDeletable>. - */ - STYLE_DELETABLE: 'deletable', - - /** - * Variable: STYLE_SHAPE - * - * Defines the key for the shape. Possible values are all constants - * with a SHAPE-prefix or any newly defined shape names. - */ - STYLE_SHAPE: 'shape', - - /** - * Variable: STYLE_EDGE - * - * Defines the key for the edge style. Possible values are the functions - * defined in <mxEdgeStyle>. - */ - STYLE_EDGE: 'edgeStyle', - - /** - * Variable: STYLE_LOOP - * - * Defines the key for the loop style. Possible values are the functions - * defined in <mxEdgeStyle>. - */ - STYLE_LOOP: 'loopStyle', - - /** - * Variable: STYLE_ROUTING_CENTER_X - * - * Defines the key for the horizontal routing center. Possible values are - * between -0.5 and 0.5. This is the relative offset from the center used - * for connecting edges. The type of this value is numeric. - */ - STYLE_ROUTING_CENTER_X: 'routingCenterX', - - /** - * Variable: STYLE_ROUTING_CENTER_Y - * - * Defines the key for the vertical routing center. Possible values are - * between -0.5 and 0.5. This is the relative offset from the center used - * for connecting edges. The type of this value is numeric. - */ - STYLE_ROUTING_CENTER_Y: 'routingCenterY', - - /** - * Variable: FONT_BOLD - * - * Constant for bold fonts. Default is 1. - */ - FONT_BOLD: 1, - - /** - * Variable: FONT_ITALIC - * - * Constant for italic fonts. Default is 2. - */ - FONT_ITALIC: 2, - - /** - * Variable: FONT_UNDERLINE - * - * Constant for underlined fonts. Default is 4. - */ - FONT_UNDERLINE: 4, - - /** - * Variable: FONT_SHADOW - * - * Constant for fonts with a shadow. Default is 8. - */ - FONT_SHADOW: 8, - - /** - * Variable: SHAPE_RECTANGLE - * - * Name under which <mxRectangleShape> is registered - * in <mxCellRenderer>. Default is rectangle. - */ - SHAPE_RECTANGLE: 'rectangle', - - /** - * Variable: SHAPE_ELLIPSE - * - * Name under which <mxEllipse> is registered - * in <mxCellRenderer>. Default is ellipse. - */ - SHAPE_ELLIPSE: 'ellipse', - - /** - * Variable: SHAPE_DOUBLE_ELLIPSE - * - * Name under which <mxDoubleEllipse> is registered - * in <mxCellRenderer>. Default is doubleEllipse. - */ - SHAPE_DOUBLE_ELLIPSE: 'doubleEllipse', - - /** - * Variable: SHAPE_RHOMBUS - * - * Name under which <mxRhombus> is registered - * in <mxCellRenderer>. Default is rhombus. - */ - SHAPE_RHOMBUS: 'rhombus', - - /** - * Variable: SHAPE_LINE - * - * Name under which <mxLine> is registered - * in <mxCellRenderer>. Default is line. - */ - SHAPE_LINE: 'line', - - /** - * Variable: SHAPE_IMAGE - * - * Name under which <mxImageShape> is registered - * in <mxCellRenderer>. Default is image. - */ - SHAPE_IMAGE: 'image', - - /** - * Variable: SHAPE_ARROW - * - * Name under which <mxArrow> is registered - * in <mxCellRenderer>. Default is arrow. - */ - SHAPE_ARROW: 'arrow', - - /** - * Variable: SHAPE_LABEL - * - * Name under which <mxLabel> is registered - * in <mxCellRenderer>. Default is label. - */ - SHAPE_LABEL: 'label', - - /** - * Variable: SHAPE_CYLINDER - * - * Name under which <mxCylinder> is registered - * in <mxCellRenderer>. Default is cylinder. - */ - SHAPE_CYLINDER: 'cylinder', - - /** - * Variable: SHAPE_SWIMLANE - * - * Name under which <mxSwimlane> is registered - * in <mxCellRenderer>. Default is swimlane. - */ - SHAPE_SWIMLANE: 'swimlane', - - /** - * Variable: SHAPE_CONNECTOR - * - * Name under which <mxConnector> is registered - * in <mxCellRenderer>. Default is connector. - */ - SHAPE_CONNECTOR: 'connector', - - /** - * Variable: SHAPE_ACTOR - * - * Name under which <mxActor> is registered - * in <mxCellRenderer>. Default is actor. - */ - SHAPE_ACTOR: 'actor', - - /** - * Variable: SHAPE_CLOUD - * - * Name under which <mxCloud> is registered - * in <mxCellRenderer>. Default is cloud. - */ - SHAPE_CLOUD: 'cloud', - - /** - * Variable: SHAPE_TRIANGLE - * - * Name under which <mxTriangle> is registered - * in <mxCellRenderer>. Default is triangle. - */ - SHAPE_TRIANGLE: 'triangle', - - /** - * Variable: SHAPE_HEXAGON - * - * Name under which <mxHexagon> is registered - * in <mxCellRenderer>. Default is hexagon. - */ - SHAPE_HEXAGON: 'hexagon', - - /** - * Variable: ARROW_CLASSIC - * - * Constant for classic arrow markers. - */ - ARROW_CLASSIC: 'classic', - - /** - * Variable: ARROW_BLOCK - * - * Constant for block arrow markers. - */ - ARROW_BLOCK: 'block', - - /** - * Variable: ARROW_OPEN - * - * Constant for open arrow markers. - */ - ARROW_OPEN: 'open', - - /** - * Variable: ARROW_OVAL - * - * Constant for oval arrow markers. - */ - ARROW_OVAL: 'oval', - - /** - * Variable: ARROW_DIAMOND - * - * Constant for diamond arrow markers. - */ - ARROW_DIAMOND: 'diamond', - - /** - * Variable: ARROW_DIAMOND - * - * Constant for diamond arrow markers. - */ - ARROW_DIAMOND_THIN: 'diamondThin', - - /** - * Variable: ALIGN_LEFT - * - * Constant for left horizontal alignment. Default is left. - */ - ALIGN_LEFT: 'left', - - /** - * Variable: ALIGN_CENTER - * - * Constant for center horizontal alignment. Default is center. - */ - ALIGN_CENTER: 'center', - - /** - * Variable: ALIGN_RIGHT - * - * Constant for right horizontal alignment. Default is right. - */ - ALIGN_RIGHT: 'right', - - /** - * Variable: ALIGN_TOP - * - * Constant for top vertical alignment. Default is top. - */ - ALIGN_TOP: 'top', - - /** - * Variable: ALIGN_MIDDLE - * - * Constant for middle vertical alignment. Default is middle. - */ - ALIGN_MIDDLE: 'middle', - - /** - * Variable: ALIGN_BOTTOM - * - * Constant for bottom vertical alignment. Default is bottom. - */ - ALIGN_BOTTOM: 'bottom', - - /** - * Variable: DIRECTION_NORTH - * - * Constant for direction north. Default is north. - */ - DIRECTION_NORTH: 'north', - - /** - * Variable: DIRECTION_SOUTH - * - * Constant for direction south. Default is south. - */ - DIRECTION_SOUTH: 'south', - - /** - * Variable: DIRECTION_EAST - * - * Constant for direction east. Default is east. - */ - DIRECTION_EAST: 'east', - - /** - * Variable: DIRECTION_WEST - * - * Constant for direction west. Default is west. - */ - DIRECTION_WEST: 'west', - - /** - * Variable: DIRECTION_MASK_NONE - * - * Constant for no direction. - */ - DIRECTION_MASK_NONE: 0, - - /** - * Variable: DIRECTION_MASK_WEST - * - * Bitwise mask for west direction. - */ - DIRECTION_MASK_WEST: 1, - - /** - * Variable: DIRECTION_MASK_NORTH - * - * Bitwise mask for north direction. - */ - DIRECTION_MASK_NORTH: 2, - - /** - * Variable: DIRECTION_MASK_SOUTH - * - * Bitwise mask for south direction. - */ - DIRECTION_MASK_SOUTH: 4, - - /** - * Variable: DIRECTION_MASK_EAST - * - * Bitwise mask for east direction. - */ - DIRECTION_MASK_EAST: 8, - - /** - * Variable: DIRECTION_MASK_ALL - * - * Bitwise mask for all directions. - */ - DIRECTION_MASK_ALL: 15, - - /** - * Variable: ELBOW_VERTICAL - * - * Constant for elbow vertical. Default is horizontal. - */ - ELBOW_VERTICAL: 'vertical', - - /** - * Variable: ELBOW_HORIZONTAL - * - * Constant for elbow horizontal. Default is horizontal. - */ - ELBOW_HORIZONTAL: 'horizontal', - - /** - * Variable: EDGESTYLE_ELBOW - * - * Name of the elbow edge style. Can be used as a string value - * for the STYLE_EDGE style. - */ - EDGESTYLE_ELBOW: 'elbowEdgeStyle', - - /** - * Variable: EDGESTYLE_ENTITY_RELATION - * - * Name of the entity relation edge style. Can be used as a string value - * for the STYLE_EDGE style. - */ - EDGESTYLE_ENTITY_RELATION: 'entityRelationEdgeStyle', - - /** - * Variable: EDGESTYLE_LOOP - * - * Name of the loop edge style. Can be used as a string value - * for the STYLE_EDGE style. - */ - EDGESTYLE_LOOP: 'loopEdgeStyle', - - /** - * Variable: EDGESTYLE_SIDETOSIDE - * - * Name of the side to side edge style. Can be used as a string value - * for the STYLE_EDGE style. - */ - EDGESTYLE_SIDETOSIDE: 'sideToSideEdgeStyle', - - /** - * Variable: EDGESTYLE_TOPTOBOTTOM - * - * Name of the top to bottom edge style. Can be used as a string value - * for the STYLE_EDGE style. - */ - EDGESTYLE_TOPTOBOTTOM: 'topToBottomEdgeStyle', - - /** - * Variable: EDGESTYLE_ORTHOGONAL - * - * Name of the generic orthogonal edge style. Can be used as a string value - * for the STYLE_EDGE style. - */ - EDGESTYLE_ORTHOGONAL: 'orthogonalEdgeStyle', - - /** - * Variable: EDGESTYLE_SEGMENT - * - * Name of the generic segment edge style. Can be used as a string value - * for the STYLE_EDGE style. - */ - EDGESTYLE_SEGMENT: 'segmentEdgeStyle', - - /** - * Variable: PERIMETER_ELLIPSE - * - * Name of the ellipse perimeter. Can be used as a string value - * for the STYLE_PERIMETER style. - */ - PERIMETER_ELLIPSE: 'ellipsePerimeter', - - /** - * Variable: PERIMETER_RECTANGLE - * - * Name of the rectangle perimeter. Can be used as a string value - * for the STYLE_PERIMETER style. - */ - PERIMETER_RECTANGLE: 'rectanglePerimeter', - - /** - * Variable: PERIMETER_RHOMBUS - * - * Name of the rhombus perimeter. Can be used as a string value - * for the STYLE_PERIMETER style. - */ - PERIMETER_RHOMBUS: 'rhombusPerimeter', - - /** - * Variable: PERIMETER_TRIANGLE - * - * Name of the triangle perimeter. Can be used as a string value - * for the STYLE_PERIMETER style. - */ - PERIMETER_TRIANGLE: 'trianglePerimeter' - -}; diff --git a/src/js/util/mxDictionary.js b/src/js/util/mxDictionary.js deleted file mode 100644 index a2e503a..0000000 --- a/src/js/util/mxDictionary.js +++ /dev/null @@ -1,130 +0,0 @@ -/** - * $Id: mxDictionary.js,v 1.12 2012-04-26 08:08:54 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -/** - * Class: mxDictionary - * - * A wrapper class for an associative array with object keys. Note: This - * implementation uses <mxObjectIdentitiy> to turn object keys into strings. - * - * Constructor: mxEventSource - * - * Constructs a new dictionary which allows object to be used as keys. - */ -function mxDictionary() -{ - this.clear(); -}; - -/** - * Function: map - * - * Stores the (key, value) pairs in this dictionary. - */ -mxDictionary.prototype.map = null; - -/** - * Function: clear - * - * Clears the dictionary. - */ -mxDictionary.prototype.clear = function() -{ - this.map = {}; -}; - -/** - * Function: get - * - * Returns the value for the given key. - */ -mxDictionary.prototype.get = function(key) -{ - var id = mxObjectIdentity.get(key); - - return this.map[id]; -}; - -/** - * Function: put - * - * Stores the value under the given key and returns the previous - * value for that key. - */ -mxDictionary.prototype.put = function(key, value) -{ - var id = mxObjectIdentity.get(key); - var previous = this.map[id]; - this.map[id] = value; - - return previous; -}; - -/** - * Function: remove - * - * Removes the value for the given key and returns the value that - * has been removed. - */ -mxDictionary.prototype.remove = function(key) -{ - var id = mxObjectIdentity.get(key); - var previous = this.map[id]; - delete this.map[id]; - - return previous; -}; - -/** - * Function: getKeys - * - * Returns all keys as an array. - */ -mxDictionary.prototype.getKeys = function() -{ - var result = []; - - for (var key in this.map) - { - result.push(key); - } - - return result; -}; - -/** - * Function: getValues - * - * Returns all values as an array. - */ -mxDictionary.prototype.getValues = function() -{ - var result = []; - - for (var key in this.map) - { - result.push(this.map[key]); - } - - return result; -}; - -/** - * Function: visit - * - * Visits all entries in the dictionary using the given function with the - * following signature: function(key, value) where key is a string and - * value is an object. - * - * Parameters: - * - * visitor - A function that takes the key and value as arguments. - */ -mxDictionary.prototype.visit = function(visitor) -{ - for (var key in this.map) - { - visitor(key, this.map[key]); - } -}; diff --git a/src/js/util/mxDivResizer.js b/src/js/util/mxDivResizer.js deleted file mode 100644 index 2a2e4eb..0000000 --- a/src/js/util/mxDivResizer.js +++ /dev/null @@ -1,151 +0,0 @@ -/** - * $Id: mxDivResizer.js,v 1.22 2010-01-02 09:45:14 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -/** - * Class: mxDivResizer - * - * Maintains the size of a div element in Internet Explorer. This is a - * workaround for the right and bottom style being ignored in IE. - * - * If you need a div to cover the scrollwidth and -height of a document, - * then you can use this class as follows: - * - * (code) - * var resizer = new mxDivResizer(background); - * resizer.getDocumentHeight = function() - * { - * return document.body.scrollHeight; - * } - * resizer.getDocumentWidth = function() - * { - * return document.body.scrollWidth; - * } - * resizer.resize(); - * (end) - * - * Constructor: mxDivResizer - * - * Constructs an object that maintains the size of a div - * element when the window is being resized. This is only - * required for Internet Explorer as it ignores the respective - * stylesheet information for DIV elements. - * - * Parameters: - * - * div - Reference to the DOM node whose size should be maintained. - * container - Optional Container that contains the div. Default is the - * window. - */ -function mxDivResizer(div, container) -{ - if (div.nodeName.toLowerCase() == 'div') - { - if (container == null) - { - container = window; - } - - this.div = div; - var style = mxUtils.getCurrentStyle(div); - - if (style != null) - { - this.resizeWidth = style.width == 'auto'; - this.resizeHeight = style.height == 'auto'; - } - - mxEvent.addListener(container, 'resize', - mxUtils.bind(this, function(evt) - { - if (!this.handlingResize) - { - this.handlingResize = true; - this.resize(); - this.handlingResize = false; - } - }) - ); - - this.resize(); - } -}; - -/** - * Function: resizeWidth - * - * Boolean specifying if the width should be updated. - */ -mxDivResizer.prototype.resizeWidth = true; - -/** - * Function: resizeHeight - * - * Boolean specifying if the height should be updated. - */ -mxDivResizer.prototype.resizeHeight = true; - -/** - * Function: handlingResize - * - * Boolean specifying if the width should be updated. - */ -mxDivResizer.prototype.handlingResize = false; - -/** - * Function: resize - * - * Updates the style of the DIV after the window has been resized. - */ -mxDivResizer.prototype.resize = function() -{ - var w = this.getDocumentWidth(); - var h = this.getDocumentHeight(); - - var l = parseInt(this.div.style.left); - var r = parseInt(this.div.style.right); - var t = parseInt(this.div.style.top); - var b = parseInt(this.div.style.bottom); - - if (this.resizeWidth && - !isNaN(l) && - !isNaN(r) && - l >= 0 && - r >= 0 && - w - r - l > 0) - { - this.div.style.width = (w - r - l)+'px'; - } - - if (this.resizeHeight && - !isNaN(t) && - !isNaN(b) && - t >= 0 && - b >= 0 && - h - t - b > 0) - { - this.div.style.height = (h - t - b)+'px'; - } -}; - -/** - * Function: getDocumentWidth - * - * Hook for subclassers to return the width of the document (without - * scrollbars). - */ -mxDivResizer.prototype.getDocumentWidth = function() -{ - return document.body.clientWidth; -}; - -/** - * Function: getDocumentHeight - * - * Hook for subclassers to return the height of the document (without - * scrollbars). - */ -mxDivResizer.prototype.getDocumentHeight = function() -{ - return document.body.clientHeight; -}; diff --git a/src/js/util/mxDragSource.js b/src/js/util/mxDragSource.js deleted file mode 100644 index d0cafdf..0000000 --- a/src/js/util/mxDragSource.js +++ /dev/null @@ -1,594 +0,0 @@ -/** - * $Id: mxDragSource.js,v 1.14 2012-12-05 21:43:16 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -/** - * Class: mxDragSource - * - * Wrapper to create a drag source from a DOM element so that the element can - * be dragged over a graph and dropped into the graph as a new cell. - * - * TODO: Problem is that in the dropHandler the current preview location is - * not available, so the preview and the dropHandler must match. - * - * Constructor: mxDragSource - * - * Constructs a new drag source for the given element. - */ -function mxDragSource(element, dropHandler) -{ - this.element = element; - this.dropHandler = dropHandler; - - // Handles a drag gesture on the element - var md = (mxClient.IS_TOUCH) ? 'touchstart' : 'mousedown'; - mxEvent.addListener(element, md, mxUtils.bind(this, this.mouseDown)); -}; - -/** - * Variable: element - * - * Reference to the DOM node which was made draggable. - */ -mxDragSource.prototype.element = null; - -/** - * Variable: dropHandler - * - * Holds the DOM node that is used to represent the drag preview. If this is - * null then the source element will be cloned and used for the drag preview. - */ -mxDragSource.prototype.dropHandler = null; - -/** - * Variable: dragOffset - * - * <mxPoint> that specifies the offset of the <dragElement>. Default is null. - */ -mxDragSource.prototype.dragOffset = null; - -/** - * Variable: dragElement - * - * Holds the DOM node that is used to represent the drag preview. If this is - * null then the source element will be cloned and used for the drag preview. - */ -mxDragSource.prototype.dragElement = null; - -/** - * Variable: previewElement - * - * Optional <mxRectangle> that specifies the unscaled size of the preview. - */ -mxDragSource.prototype.previewElement = null; - -/** - * Variable: enabled - * - * Specifies if this drag source is enabled. Default is true. - */ -mxDragSource.prototype.enabled = true; - -/** - * Variable: currentGraph - * - * Reference to the <mxGraph> that is the current drop target. - */ -mxDragSource.prototype.currentGraph = null; - -/** - * Variable: currentDropTarget - * - * Holds the current drop target under the mouse. - */ -mxDragSource.prototype.currentDropTarget = null; - -/** - * Variable: currentPoint - * - * Holds the current drop location. - */ -mxDragSource.prototype.currentPoint = null; - -/** - * Variable: currentGuide - * - * Holds an <mxGuide> for the <currentGraph> if <dragPreview> is not null. - */ -mxDragSource.prototype.currentGuide = null; - -/** - * Variable: currentGuide - * - * Holds an <mxGuide> for the <currentGraph> if <dragPreview> is not null. - */ -mxDragSource.prototype.currentHighlight = null; - -/** - * Variable: autoscroll - * - * Specifies if the graph should scroll automatically. Default is true. - */ -mxDragSource.prototype.autoscroll = true; - -/** - * Variable: guidesEnabled - * - * Specifies if <mxGuide> should be enabled. Default is true. - */ -mxDragSource.prototype.guidesEnabled = true; - -/** - * Variable: gridEnabled - * - * Specifies if the grid should be allowed. Default is true. - */ -mxDragSource.prototype.gridEnabled = true; - -/** - * Variable: highlightDropTargets - * - * Specifies if drop targets should be highlighted. Default is true. - */ -mxDragSource.prototype.highlightDropTargets = true; - -/** - * Variable: dragElementZIndex - * - * ZIndex for the drag element. Default is 100. - */ -mxDragSource.prototype.dragElementZIndex = 100; - -/** - * Variable: dragElementOpacity - * - * Opacity of the drag element in %. Default is 70. - */ -mxDragSource.prototype.dragElementOpacity = 70; - -/** - * Function: isEnabled - * - * Returns <enabled>. - */ -mxDragSource.prototype.isEnabled = function() -{ - return this.enabled; -}; - -/** - * Function: setEnabled - * - * Sets <enabled>. - */ -mxDragSource.prototype.setEnabled = function(value) -{ - this.enabled = value; -}; - -/** - * Function: isGuidesEnabled - * - * Returns <guidesEnabled>. - */ -mxDragSource.prototype.isGuidesEnabled = function() -{ - return this.guidesEnabled; -}; - -/** - * Function: setGuidesEnabled - * - * Sets <guidesEnabled>. - */ -mxDragSource.prototype.setGuidesEnabled = function(value) -{ - this.guidesEnabled = value; -}; - -/** - * Function: isGridEnabled - * - * Returns <gridEnabled>. - */ -mxDragSource.prototype.isGridEnabled = function() -{ - return this.gridEnabled; -}; - -/** - * Function: setGridEnabled - * - * Sets <gridEnabled>. - */ -mxDragSource.prototype.setGridEnabled = function(value) -{ - this.gridEnabled = value; -}; - -/** - * Function: getGraphForEvent - * - * Returns the graph for the given mouse event. This implementation returns - * null. - */ -mxDragSource.prototype.getGraphForEvent = function(evt) -{ - return null; -}; - -/** - * Function: getDropTarget - * - * Returns the drop target for the given graph and coordinates. This - * implementation uses <mxGraph.getCellAt>. - */ -mxDragSource.prototype.getDropTarget = function(graph, x, y) -{ - return graph.getCellAt(x, y); -}; - -/** - * Function: createDragElement - * - * Creates and returns a clone of the <dragElementPrototype> or the <element> - * if the former is not defined. - */ -mxDragSource.prototype.createDragElement = function(evt) -{ - return this.element.cloneNode(true); -}; - -/** - * Function: createPreviewElement - * - * Creates and returns an element which can be used as a preview in the given - * graph. - */ -mxDragSource.prototype.createPreviewElement = function(graph) -{ - return null; -}; - -/** - * Function: mouseDown - * - * Returns the drop target for the given graph and coordinates. This - * implementation uses <mxGraph.getCellAt>. - */ -mxDragSource.prototype.mouseDown = function(evt) -{ - if (this.enabled && !mxEvent.isConsumed(evt) && this.mouseMoveHandler == null) - { - this.startDrag(evt); - - var mm = (mxClient.IS_TOUCH) ? 'touchmove' : 'mousemove'; - var mu = (mxClient.IS_TOUCH) ? 'touchend' : 'mouseup'; - - this.mouseMoveHandler = mxUtils.bind(this, this.mouseMove); - mxEvent.addListener(document, mm, this.mouseMoveHandler); - this.mouseUpHandler = mxUtils.bind(this, this.mouseUp); - mxEvent.addListener(document, mu, this.mouseUpHandler); - - // Prevents default action (native DnD for images in FF 10) - // but does not stop event propagation - mxEvent.consume(evt, true, false); - } -}; - -/** - * Function: startDrag - * - * Creates the <dragElement> using <createDragElement>. - */ -mxDragSource.prototype.startDrag = function(evt) -{ - this.dragElement = this.createDragElement(evt); - this.dragElement.style.position = 'absolute'; - this.dragElement.style.zIndex = this.dragElementZIndex; - mxUtils.setOpacity(this.dragElement, this.dragElementOpacity); -}; - - -/** - * Function: stopDrag - * - * Removes and destroys the <dragElement>. - */ -mxDragSource.prototype.stopDrag = function(evt) -{ - if (this.dragElement != null) - { - if (this.dragElement.parentNode != null) - { - this.dragElement.parentNode.removeChild(this.dragElement); - } - - this.dragElement = null; - } -}; - -/** - * Function: graphContainsEvent - * - * Returns true if the given graph contains the given event. - */ -mxDragSource.prototype.graphContainsEvent = function(graph, evt) -{ - var x = mxEvent.getClientX(evt); - var y = mxEvent.getClientY(evt); - var offset = mxUtils.getOffset(graph.container); - var origin = mxUtils.getScrollOrigin(); - - // Checks if event is inside the bounds of the graph container - return x >= offset.x - origin.x && y >= offset.y - origin.y && - x <= offset.x - origin.x + graph.container.offsetWidth && - y <= offset.y - origin.y + graph.container.offsetHeight; -}; - -/** - * Function: mouseMove - * - * Gets the graph for the given event using <getGraphForEvent>, updates the - * <currentGraph>, calling <dragEnter> and <dragExit> on the new and old graph, - * respectively, and invokes <dragOver> if <currentGraph> is not null. - */ -mxDragSource.prototype.mouseMove = function(evt) -{ - var graph = this.getGraphForEvent(evt); - - // Checks if event is inside the bounds of the graph container - if (graph != null && !this.graphContainsEvent(graph, evt)) - { - graph = null; - } - - if (graph != this.currentGraph) - { - if (this.currentGraph != null) - { - this.dragExit(this.currentGraph); - } - - this.currentGraph = graph; - - if (this.currentGraph != null) - { - this.dragEnter(this.currentGraph); - } - } - - if (this.currentGraph != null) - { - this.dragOver(this.currentGraph, evt); - } - - if (this.dragElement != null && (this.previewElement == null || this.previewElement.style.visibility != 'visible')) - { - var x = mxEvent.getClientX(evt); - var y = mxEvent.getClientY(evt); - - if (this.dragElement.parentNode == null) - { - document.body.appendChild(this.dragElement); - } - - this.dragElement.style.visibility = 'visible'; - - if (this.dragOffset != null) - { - x += this.dragOffset.x; - y += this.dragOffset.y; - } - - x += document.body.scrollLeft || document.documentElement.scrollLeft; - y += document.body.scrollTop || document.documentElement.scrollTop; - this.dragElement.style.left = x + 'px'; - this.dragElement.style.top = y + 'px'; - } - else if (this.dragElement != null) - { - this.dragElement.style.visibility = 'hidden'; - } - - mxEvent.consume(evt); -}; - -/** - * Function: mouseUp - * - * Processes the mouse up event and invokes <drop>, <dragExit> and <stopDrag> - * as required. - */ -mxDragSource.prototype.mouseUp = function(evt) -{ - if (this.currentGraph != null) - { - if (this.currentPoint != null && (this.previewElement == null || - this.previewElement.style.visibility != 'hidden')) - { - var scale = this.currentGraph.view.scale; - var tr = this.currentGraph.view.translate; - var x = this.currentPoint.x / scale - tr.x; - var y = this.currentPoint.y / scale - tr.y; - - this.drop(this.currentGraph, evt, this.currentDropTarget, x, y); - } - - this.dragExit(this.currentGraph); - } - - this.stopDrag(evt); - - this.currentGraph = null; - - if (this.mouseMoveHandler != null) - { - var mm = (mxClient.IS_TOUCH) ? 'touchmove' : 'mousemove'; - mxEvent.removeListener(document, mm, this.mouseMoveHandler); - this.mouseMoveHandler = null; - } - - if (this.mouseUpHandler != null) - { - var mu = (mxClient.IS_TOUCH) ? 'touchend' : 'mouseup'; - mxEvent.removeListener(document, mu, this.mouseUpHandler); - this.mouseUpHandler = null; - } - - mxEvent.consume(evt); -}; - -/** - * Function: dragEnter - * - * Actives the given graph as a drop target. - */ -mxDragSource.prototype.dragEnter = function(graph) -{ - graph.isMouseDown = true; - this.previewElement = this.createPreviewElement(graph); - - // Guide is only needed if preview element is used - if (this.isGuidesEnabled() && this.previewElement != null) - { - this.currentGuide = new mxGuide(graph, graph.graphHandler.getGuideStates()); - } - - if (this.highlightDropTargets) - { - this.currentHighlight = new mxCellHighlight(graph, mxConstants.DROP_TARGET_COLOR); - } -}; - -/** - * Function: dragExit - * - * Deactivates the given graph as a drop target. - */ -mxDragSource.prototype.dragExit = function(graph) -{ - this.currentDropTarget = null; - this.currentPoint = null; - graph.isMouseDown = false; - - if (this.previewElement != null) - { - if (this.previewElement.parentNode != null) - { - this.previewElement.parentNode.removeChild(this.previewElement); - } - - this.previewElement = null; - } - - if (this.currentGuide != null) - { - this.currentGuide.destroy(); - this.currentGuide = null; - } - - if (this.currentHighlight != null) - { - this.currentHighlight.destroy(); - this.currentHighlight = null; - } -}; - -/** - * Function: dragOver - * - * Implements autoscroll, updates the <currentPoint>, highlights any drop - * targets and updates the preview. - */ -mxDragSource.prototype.dragOver = function(graph, evt) -{ - var offset = mxUtils.getOffset(graph.container); - var origin = mxUtils.getScrollOrigin(graph.container); - var x = mxEvent.getClientX(evt) - offset.x + origin.x; - var y = mxEvent.getClientY(evt) - offset.y + origin.y; - - if (graph.autoScroll && (this.autoscroll == null || this.autoscroll)) - { - graph.scrollPointToVisible(x, y, graph.autoExtend); - } - - // Highlights the drop target under the mouse - if (this.currentHighlight != null && graph.isDropEnabled()) - { - this.currentDropTarget = this.getDropTarget(graph, x, y); - var state = graph.getView().getState(this.currentDropTarget); - this.currentHighlight.highlight(state); - } - - // Updates the location of the preview - if (this.previewElement != null) - { - if (this.previewElement.parentNode == null) - { - graph.container.appendChild(this.previewElement); - - this.previewElement.style.zIndex = '3'; - this.previewElement.style.position = 'absolute'; - } - - var gridEnabled = this.isGridEnabled() && graph.isGridEnabledEvent(evt); - var hideGuide = true; - - // Grid and guides - if (this.currentGuide != null && this.currentGuide.isEnabledForEvent(evt)) - { - // LATER: HTML preview appears smaller than SVG preview - var w = parseInt(this.previewElement.style.width); - var h = parseInt(this.previewElement.style.height); - var bounds = new mxRectangle(0, 0, w, h); - var delta = new mxPoint(x, y); - delta = this.currentGuide.move(bounds, delta, gridEnabled); - hideGuide = false; - x = delta.x; - y = delta.y; - } - else if (gridEnabled) - { - var scale = graph.view.scale; - var tr = graph.view.translate; - var off = graph.gridSize / 2; - x = (graph.snap(x / scale - tr.x - off) + tr.x) * scale; - y = (graph.snap(y / scale - tr.y - off) + tr.y) * scale; - } - - if (this.currentGuide != null && hideGuide) - { - this.currentGuide.hide(); - } - - if (this.previewOffset != null) - { - x += this.previewOffset.x; - y += this.previewOffset.y; - } - - this.previewElement.style.left = Math.round(x) + 'px'; - this.previewElement.style.top = Math.round(y) + 'px'; - this.previewElement.style.visibility = 'visible'; - } - - this.currentPoint = new mxPoint(x, y); -}; - -/** - * Function: drop - * - * Returns the drop target for the given graph and coordinates. This - * implementation uses <mxGraph.getCellAt>. - */ -mxDragSource.prototype.drop = function(graph, evt, dropTarget, x, y) -{ - this.dropHandler(graph, evt, dropTarget, x, y); - - // Had to move this to after the insert because it will - // affect the scrollbars of the window in IE to try and - // make the complete container visible. - // LATER: Should be made optional. - graph.container.focus(); -}; diff --git a/src/js/util/mxEffects.js b/src/js/util/mxEffects.js deleted file mode 100644 index 89d6a71..0000000 --- a/src/js/util/mxEffects.js +++ /dev/null @@ -1,214 +0,0 @@ -/** - * $Id: mxEffects.js,v 1.6 2012-01-04 10:01:16 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -var mxEffects = -{ - - /** - * Class: mxEffects - * - * Provides animation effects. - */ - - /** - * Function: animateChanges - * - * Asynchronous animated move operation. See also: <mxMorphing>. - * - * Example: - * - * (code) - * graph.model.addListener(mxEvent.CHANGE, function(sender, evt) - * { - * var changes = evt.getProperty('edit').changes; - * - * if (changes.length < 10) - * { - * mxEffects.animateChanges(graph, changes); - * } - * }); - * (end) - * - * Parameters: - * - * graph - <mxGraph> that received the changes. - * changes - Array of changes to be animated. - * done - Optional function argument that is invoked after the - * last step of the animation. - */ - animateChanges: function(graph, changes, done) - { - var maxStep = 10; - var step = 0; - - var animate = function() - { - var isRequired = false; - - for (var i = 0; i < changes.length; i++) - { - var change = changes[i]; - - if (change instanceof mxGeometryChange || - change instanceof mxTerminalChange || - change instanceof mxValueChange || - change instanceof mxChildChange || - change instanceof mxStyleChange) - { - var state = graph.getView().getState(change.cell || change.child, false); - - if (state != null) - { - isRequired = true; - - if (change.constructor != mxGeometryChange || graph.model.isEdge(change.cell)) - { - mxUtils.setOpacity(state.shape.node, 100 * step / maxStep); - } - else - { - var scale = graph.getView().scale; - - var dx = (change.geometry.x - change.previous.x) * scale; - var dy = (change.geometry.y - change.previous.y) * scale; - - var sx = (change.geometry.width - change.previous.width) * scale; - var sy = (change.geometry.height - change.previous.height) * scale; - - if (step == 0) - { - state.x -= dx; - state.y -= dy; - state.width -= sx; - state.height -= sy; - } - else - { - state.x += dx / maxStep; - state.y += dy / maxStep; - state.width += sx / maxStep; - state.height += sy / maxStep; - } - - graph.cellRenderer.redraw(state); - - // Fades all connected edges and children - mxEffects.cascadeOpacity(graph, change.cell, 100 * step / maxStep); - } - } - } - } - - // Workaround to force a repaint in AppleWebKit - mxUtils.repaintGraph(graph, new mxPoint(1, 1)); - - if (step < maxStep && isRequired) - { - step++; - window.setTimeout(animate, delay); - } - else if (done != null) - { - done(); - } - }; - - var delay = 30; - animate(); - }, - - /** - * Function: cascadeOpacity - * - * Sets the opacity on the given cell and its descendants. - * - * Parameters: - * - * graph - <mxGraph> that contains the cells. - * cell - <mxCell> to set the opacity for. - * opacity - New value for the opacity in %. - */ - cascadeOpacity: function(graph, cell, opacity) - { - // Fades all children - var childCount = graph.model.getChildCount(cell); - - for (var i=0; i<childCount; i++) - { - var child = graph.model.getChildAt(cell, i); - var childState = graph.getView().getState(child); - - if (childState != null) - { - mxUtils.setOpacity(childState.shape.node, opacity); - mxEffects.cascadeOpacity(graph, child, opacity); - } - } - - // Fades all connected edges - var edges = graph.model.getEdges(cell); - - if (edges != null) - { - for (var i=0; i<edges.length; i++) - { - var edgeState = graph.getView().getState(edges[i]); - - if (edgeState != null) - { - mxUtils.setOpacity(edgeState.shape.node, opacity); - } - } - } - }, - - /** - * Function: fadeOut - * - * Asynchronous fade-out operation. - */ - fadeOut: function(node, from, remove, step, delay, isEnabled) - { - step = step || 40; - delay = delay || 30; - - var opacity = from || 100; - - mxUtils.setOpacity(node, opacity); - - if (isEnabled || isEnabled == null) - { - var f = function() - { - opacity = Math.max(opacity-step, 0); - mxUtils.setOpacity(node, opacity); - - if (opacity > 0) - { - window.setTimeout(f, delay); - } - else - { - node.style.visibility = 'hidden'; - - if (remove && node.parentNode) - { - node.parentNode.removeChild(node); - } - } - }; - window.setTimeout(f, delay); - } - else - { - node.style.visibility = 'hidden'; - - if (remove && node.parentNode) - { - node.parentNode.removeChild(node); - } - } - } - -}; diff --git a/src/js/util/mxEvent.js b/src/js/util/mxEvent.js deleted file mode 100644 index f831631..0000000 --- a/src/js/util/mxEvent.js +++ /dev/null @@ -1,1175 +0,0 @@ -/** - * $Id: mxEvent.js,v 1.76 2012-12-07 07:39:03 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -var mxEvent = -{ - - /** - * Class: mxEvent - * - * Cross-browser DOM event support. For internal event handling, - * <mxEventSource> and the graph event dispatch loop in <mxGraph> are used. - * - * Memory Leaks: - * - * Use this class for adding and removing listeners to/from DOM nodes. The - * <removeAllListeners> function is provided to remove all listeners that - * have been added using <addListener>. The function should be invoked when - * the last reference is removed in the JavaScript code, typically when the - * referenced DOM node is removed from the DOM, and helps to reduce memory - * leaks in IE6. - * - * Variable: objects - * - * Contains all objects where any listener was added using <addListener>. - * This is used to reduce memory leaks in IE, see <mxClient.dispose>. - */ - objects: [], - - /** - * Function: addListener - * - * Binds the function to the specified event on the given element. Use - * <mxUtils.bind> in order to bind the "this" keyword inside the function - * to a given execution scope. - */ - addListener: function() - { - var updateListenerList = function(element, eventName, funct) - { - if (element.mxListenerList == null) - { - element.mxListenerList = []; - mxEvent.objects.push(element); - } - - var entry = {name: eventName, f: funct}; - element.mxListenerList.push(entry); - }; - - if (window.addEventListener) - { - return function(element, eventName, funct) - { - element.addEventListener(eventName, funct, false); - updateListenerList(element, eventName, funct); - }; - } - else - { - return function(element, eventName, funct) - { - element.attachEvent('on' + eventName, funct); - updateListenerList(element, eventName, funct); - }; - } - }(), - - /** - * Function: removeListener - * - * Removes the specified listener from the given element. - */ - removeListener: function() - { - var updateListener = function(element, eventName, funct) - { - if (element.mxListenerList != null) - { - var listenerCount = element.mxListenerList.length; - - for (var i=0; i<listenerCount; i++) - { - var entry = element.mxListenerList[i]; - - if (entry.f == funct) - { - element.mxListenerList.splice(i, 1); - break; - } - } - - if (element.mxListenerList.length == 0) - { - element.mxListenerList = null; - } - } - }; - - if (window.removeEventListener) - { - return function(element, eventName, funct) - { - element.removeEventListener(eventName, funct, false); - updateListener(element, eventName, funct); - }; - } - else - { - return function(element, eventName, funct) - { - element.detachEvent('on' + eventName, funct); - updateListener(element, eventName, funct); - }; - } - }(), - - /** - * Function: removeAllListeners - * - * Removes all listeners from the given element. - */ - removeAllListeners: function(element) - { - var list = element.mxListenerList; - - if (list != null) - { - while (list.length > 0) - { - var entry = list[0]; - mxEvent.removeListener(element, entry.name, entry.f); - } - } - }, - - /** - * Function: redirectMouseEvents - * - * Redirects the mouse events from the given DOM node to the graph dispatch - * loop using the event and given state as event arguments. State can - * either be an instance of <mxCellState> or a function that returns an - * <mxCellState>. The down, move, up and dblClick arguments are optional - * functions that take the trigger event as arguments and replace the - * default behaviour. - */ - redirectMouseEvents: function(node, graph, state, down, move, up, dblClick) - { - var getState = function(evt) - { - return (typeof(state) == 'function') ? state(evt) : state; - }; - - var md = (mxClient.IS_TOUCH) ? 'touchstart' : 'mousedown'; - var mm = (mxClient.IS_TOUCH) ? 'touchmove' : 'mousemove'; - var mu = (mxClient.IS_TOUCH) ? 'touchend' : 'mouseup'; - - mxEvent.addListener(node, md, function (evt) - { - if (down != null) - { - down(evt); - } - else if (!mxEvent.isConsumed(evt)) - { - graph.fireMouseEvent(mxEvent.MOUSE_DOWN, - new mxMouseEvent(evt, getState(evt))); - } - }); - - mxEvent.addListener(node, mm, function (evt) - { - if (move != null) - { - move(evt); - } - else if (!mxEvent.isConsumed(evt)) - { - graph.fireMouseEvent(mxEvent.MOUSE_MOVE, - new mxMouseEvent(evt, getState(evt))); - } - }); - - mxEvent.addListener(node, mu, function (evt) - { - if (up != null) - { - up(evt); - } - else if (!mxEvent.isConsumed(evt)) - { - graph.fireMouseEvent(mxEvent.MOUSE_UP, - new mxMouseEvent(evt, getState(evt))); - } - }); - - mxEvent.addListener(node, 'dblclick', function (evt) - { - if (dblClick != null) - { - dblClick(evt); - } - else if (!mxEvent.isConsumed(evt)) - { - var tmp = getState(evt); - graph.dblClick(evt, (tmp != null) ? tmp.cell : null); - } - }); - }, - - /** - * Function: release - * - * Removes the known listeners from the given DOM node and its descendants. - * - * Parameters: - * - * element - DOM node to remove the listeners from. - */ - release: function(element) - { - if (element != null) - { - mxEvent.removeAllListeners(element); - - var children = element.childNodes; - - if (children != null) - { - var childCount = children.length; - - for (var i = 0; i < childCount; i += 1) - { - mxEvent.release(children[i]); - } - } - } - }, - - /** - * Function: addMouseWheelListener - * - * Installs the given function as a handler for mouse wheel events. The - * function has two arguments: the mouse event and a boolean that specifies - * if the wheel was moved up or down. - * - * This has been tested with IE 6 and 7, Firefox (all versions), Opera and - * Safari. It does currently not work on Safari for Mac. - * - * Example: - * - * (code) - * mxEvent.addMouseWheelListener(function (evt, up) - * { - * mxLog.show(); - * mxLog.debug('mouseWheel: up='+up); - * }); - *(end) - * - * Parameters: - * - * funct - Handler function that takes the event argument and a boolean up - * argument for the mousewheel direction. - */ - addMouseWheelListener: function(funct) - { - if (funct != null) - { - var wheelHandler = function(evt) - { - // IE does not give an event object but the - // global event object is the mousewheel event - // at this point in time. - if (evt == null) - { - evt = window.event; - } - - var delta = 0; - - if (mxClient.IS_NS && !mxClient.IS_SF && !mxClient.IS_GC) - { - delta = -evt.detail/2; - } - else - { - delta = evt.wheelDelta/120; - } - - // Handles the event using the given function - if (delta != 0) - { - funct(evt, delta > 0); - } - }; - - // Webkit has NS event API, but IE event name and details - if (mxClient.IS_NS) - { - var eventName = (mxClient.IS_SF || mxClient.IS_GC) ? - 'mousewheel' : 'DOMMouseScroll'; - mxEvent.addListener(window, eventName, wheelHandler); - } - else - { - // TODO: Does not work with Safari and Chrome but it should be - // working as tested in etc/markup/wheel.html - mxEvent.addListener(document, 'mousewheel', wheelHandler); - } - } - }, - - /** - * Function: disableContextMenu - * - * Disables the context menu for the given element. - */ - disableContextMenu: function() - { - if (mxClient.IS_IE && (typeof(document.documentMode) === 'undefined' || document.documentMode < 9)) - { - return function(element) - { - mxEvent.addListener(element, 'contextmenu', function() - { - return false; - }); - }; - } - else - { - return function(element) - { - element.setAttribute('oncontextmenu', 'return false;'); - }; - } - }(), - - /** - * Function: getSource - * - * Returns the event's target or srcElement depending on the browser. - */ - getSource: function(evt) - { - return (evt.srcElement != null) ? evt.srcElement : evt.target; - }, - - /** - * Function: isConsumed - * - * Returns true if the event has been consumed using <consume>. - */ - isConsumed: function(evt) - { - return evt.isConsumed != null && evt.isConsumed; - }, - - /** - * Function: isLeftMouseButton - * - * Returns true if the left mouse button is pressed for the given event. - * To check if a button is pressed during a mouseMove you should use the - * <mxGraph.isMouseDown> property. - */ - isLeftMouseButton: function(evt) - { - return evt.button == ((mxClient.IS_IE && (typeof(document.documentMode) === 'undefined' || document.documentMode < 9)) ? 1 : 0); - }, - - /** - * Function: isRightMouseButton - * - * Returns true if the right mouse button was pressed. Note that this - * button might not be available on some systems. For handling a popup - * trigger <isPopupTrigger> should be used. - */ - isRightMouseButton: function(evt) - { - return evt.button == 2; - }, - - /** - * Function: isPopupTrigger - * - * Returns true if the event is a popup trigger. This implementation - * returns true if the right mouse button or shift was pressed. - */ - isPopupTrigger: function(evt) - { - return mxEvent.isRightMouseButton(evt) || - (mxEvent.isShiftDown(evt) && - !mxEvent.isControlDown(evt)); - }, - - /** - * Function: isShiftDown - * - * Returns true if the shift key is pressed for the given event. - */ - isShiftDown: function(evt) - { - return (evt != null) ? evt.shiftKey : false; - }, - - /** - * Function: isAltDown - * - * Returns true if the alt key is pressed for the given event. - */ - isAltDown: function(evt) - { - return (evt != null) ? evt.altKey : false; - }, - - /** - * Function: isControlDown - * - * Returns true if the control key is pressed for the given event. - */ - isControlDown: function(evt) - { - return (evt != null) ? evt.ctrlKey : false; - }, - - /** - * Function: isMetaDown - * - * Returns true if the meta key is pressed for the given event. - */ - isMetaDown: function(evt) - { - return (evt != null) ? evt.metaKey : false; - }, - - /** - * Function: getMainEvent - * - * Returns the touch or mouse event that contains the mouse coordinates. - */ - getMainEvent: function(e) - { - if ((e.type == 'touchstart' || e.type == 'touchmove') && - e.touches != null && e.touches[0] != null) - { - e = e.touches[0]; - } - else if (e.type == 'touchend' && e.changedTouches != null && - e.changedTouches[0] != null) - { - e = e.changedTouches[0]; - } - - return e; - }, - - /** - * Function: getClientX - * - * Returns true if the meta key is pressed for the given event. - */ - getClientX: function(e) - { - return mxEvent.getMainEvent(e).clientX; - }, - - /** - * Function: getClientY - * - * Returns true if the meta key is pressed for the given event. - */ - getClientY: function(e) - { - return mxEvent.getMainEvent(e).clientY; - }, - - /** - * Function: consume - * - * Consumes the given event. - * - * Parameters: - * - * evt - Native event to be consumed. - * preventDefault - Optional boolean to prevent the default for the event. - * Default is true. - * stopPropagation - Option boolean to stop event propagation. Default is - * true. - */ - consume: function(evt, preventDefault, stopPropagation) - { - preventDefault = (preventDefault != null) ? preventDefault : true; - stopPropagation = (stopPropagation != null) ? stopPropagation : true; - - if (preventDefault) - { - if (evt.preventDefault) - { - if (stopPropagation) - { - evt.stopPropagation(); - } - - evt.preventDefault(); - } - else if (stopPropagation) - { - evt.cancelBubble = true; - } - } - - // Opera - evt.isConsumed = true; - - // Other browsers - evt.returnValue = false; - }, - - // - // Special handles in mouse events - // - - /** - * Variable: LABEL_HANDLE - * - * Index for the label handle in an mxMouseEvent. This should be a negative - * value that does not interfere with any possible handle indices. Default - * is -1. - */ - LABEL_HANDLE: -1, - - /** - * Variable: ROTATION_HANDLE - * - * Index for the rotation handle in an mxMouseEvent. This should be a - * negative value that does not interfere with any possible handle indices. - * Default is -2. - */ - ROTATION_HANDLE: -2, - - // - // Event names - // - - /** - * Variable: MOUSE_DOWN - * - * Specifies the event name for mouseDown. - */ - MOUSE_DOWN: 'mouseDown', - - /** - * Variable: MOUSE_MOVE - * - * Specifies the event name for mouseMove. - */ - MOUSE_MOVE: 'mouseMove', - - /** - * Variable: MOUSE_UP - * - * Specifies the event name for mouseUp. - */ - MOUSE_UP: 'mouseUp', - - /** - * Variable: ACTIVATE - * - * Specifies the event name for activate. - */ - ACTIVATE: 'activate', - - /** - * Variable: RESIZE_START - * - * Specifies the event name for resizeStart. - */ - RESIZE_START: 'resizeStart', - - /** - * Variable: RESIZE - * - * Specifies the event name for resize. - */ - RESIZE: 'resize', - - /** - * Variable: RESIZE_END - * - * Specifies the event name for resizeEnd. - */ - RESIZE_END: 'resizeEnd', - - /** - * Variable: MOVE_START - * - * Specifies the event name for moveStart. - */ - MOVE_START: 'moveStart', - - /** - * Variable: MOVE - * - * Specifies the event name for move. - */ - MOVE: 'move', - - /** - * Variable: MOVE_END - * - * Specifies the event name for moveEnd. - */ - MOVE_END: 'moveEnd', - - /** - * Variable: PAN_START - * - * Specifies the event name for panStart. - */ - PAN_START: 'panStart', - - /** - * Variable: PAN - * - * Specifies the event name for pan. - */ - PAN: 'pan', - - /** - * Variable: PAN_END - * - * Specifies the event name for panEnd. - */ - PAN_END: 'panEnd', - - /** - * Variable: MINIMIZE - * - * Specifies the event name for minimize. - */ - MINIMIZE: 'minimize', - - /** - * Variable: NORMALIZE - * - * Specifies the event name for normalize. - */ - NORMALIZE: 'normalize', - - /** - * Variable: MAXIMIZE - * - * Specifies the event name for maximize. - */ - MAXIMIZE: 'maximize', - - /** - * Variable: HIDE - * - * Specifies the event name for hide. - */ - HIDE: 'hide', - - /** - * Variable: SHOW - * - * Specifies the event name for show. - */ - SHOW: 'show', - - /** - * Variable: CLOSE - * - * Specifies the event name for close. - */ - CLOSE: 'close', - - /** - * Variable: DESTROY - * - * Specifies the event name for destroy. - */ - DESTROY: 'destroy', - - /** - * Variable: REFRESH - * - * Specifies the event name for refresh. - */ - REFRESH: 'refresh', - - /** - * Variable: SIZE - * - * Specifies the event name for size. - */ - SIZE: 'size', - - /** - * Variable: SELECT - * - * Specifies the event name for select. - */ - SELECT: 'select', - - /** - * Variable: FIRED - * - * Specifies the event name for fired. - */ - FIRED: 'fired', - - /** - * Variable: GET - * - * Specifies the event name for get. - */ - GET: 'get', - - /** - * Variable: RECEIVE - * - * Specifies the event name for receive. - */ - RECEIVE: 'receive', - - /** - * Variable: CONNECT - * - * Specifies the event name for connect. - */ - CONNECT: 'connect', - - /** - * Variable: DISCONNECT - * - * Specifies the event name for disconnect. - */ - DISCONNECT: 'disconnect', - - /** - * Variable: SUSPEND - * - * Specifies the event name for suspend. - */ - SUSPEND: 'suspend', - - /** - * Variable: RESUME - * - * Specifies the event name for suspend. - */ - RESUME: 'resume', - - /** - * Variable: MARK - * - * Specifies the event name for mark. - */ - MARK: 'mark', - - /** - * Variable: SESSION - * - * Specifies the event name for session. - */ - SESSION: 'session', - - /** - * Variable: ROOT - * - * Specifies the event name for root. - */ - ROOT: 'root', - - /** - * Variable: POST - * - * Specifies the event name for post. - */ - POST: 'post', - - /** - * Variable: OPEN - * - * Specifies the event name for open. - */ - OPEN: 'open', - - /** - * Variable: SAVE - * - * Specifies the event name for open. - */ - SAVE: 'save', - - /** - * Variable: BEFORE_ADD_VERTEX - * - * Specifies the event name for beforeAddVertex. - */ - BEFORE_ADD_VERTEX: 'beforeAddVertex', - - /** - * Variable: ADD_VERTEX - * - * Specifies the event name for addVertex. - */ - ADD_VERTEX: 'addVertex', - - /** - * Variable: AFTER_ADD_VERTEX - * - * Specifies the event name for afterAddVertex. - */ - AFTER_ADD_VERTEX: 'afterAddVertex', - - /** - * Variable: DONE - * - * Specifies the event name for done. - */ - DONE: 'done', - - /** - * Variable: EXECUTE - * - * Specifies the event name for execute. - */ - EXECUTE: 'execute', - - /** - * Variable: BEGIN_UPDATE - * - * Specifies the event name for beginUpdate. - */ - BEGIN_UPDATE: 'beginUpdate', - - /** - * Variable: END_UPDATE - * - * Specifies the event name for endUpdate. - */ - END_UPDATE: 'endUpdate', - - /** - * Variable: BEFORE_UNDO - * - * Specifies the event name for beforeUndo. - */ - BEFORE_UNDO: 'beforeUndo', - - /** - * Variable: UNDO - * - * Specifies the event name for undo. - */ - UNDO: 'undo', - - /** - * Variable: REDO - * - * Specifies the event name for redo. - */ - REDO: 'redo', - - /** - * Variable: CHANGE - * - * Specifies the event name for change. - */ - CHANGE: 'change', - - /** - * Variable: NOTIFY - * - * Specifies the event name for notify. - */ - NOTIFY: 'notify', - - /** - * Variable: LAYOUT_CELLS - * - * Specifies the event name for layoutCells. - */ - LAYOUT_CELLS: 'layoutCells', - - /** - * Variable: CLICK - * - * Specifies the event name for click. - */ - CLICK: 'click', - - /** - * Variable: SCALE - * - * Specifies the event name for scale. - */ - SCALE: 'scale', - - /** - * Variable: TRANSLATE - * - * Specifies the event name for translate. - */ - TRANSLATE: 'translate', - - /** - * Variable: SCALE_AND_TRANSLATE - * - * Specifies the event name for scaleAndTranslate. - */ - SCALE_AND_TRANSLATE: 'scaleAndTranslate', - - /** - * Variable: UP - * - * Specifies the event name for up. - */ - UP: 'up', - - /** - * Variable: DOWN - * - * Specifies the event name for down. - */ - DOWN: 'down', - - /** - * Variable: ADD - * - * Specifies the event name for add. - */ - ADD: 'add', - - /** - * Variable: REMOVE - * - * Specifies the event name for remove. - */ - REMOVE: 'remove', - - /** - * Variable: CLEAR - * - * Specifies the event name for clear. - */ - CLEAR: 'clear', - - /** - * Variable: ADD_CELLS - * - * Specifies the event name for addCells. - */ - ADD_CELLS: 'addCells', - - /** - * Variable: CELLS_ADDED - * - * Specifies the event name for cellsAdded. - */ - CELLS_ADDED: 'cellsAdded', - - /** - * Variable: MOVE_CELLS - * - * Specifies the event name for moveCells. - */ - MOVE_CELLS: 'moveCells', - - /** - * Variable: CELLS_MOVED - * - * Specifies the event name for cellsMoved. - */ - CELLS_MOVED: 'cellsMoved', - - /** - * Variable: RESIZE_CELLS - * - * Specifies the event name for resizeCells. - */ - RESIZE_CELLS: 'resizeCells', - - /** - * Variable: CELLS_RESIZED - * - * Specifies the event name for cellsResized. - */ - CELLS_RESIZED: 'cellsResized', - - /** - * Variable: TOGGLE_CELLS - * - * Specifies the event name for toggleCells. - */ - TOGGLE_CELLS: 'toggleCells', - - /** - * Variable: CELLS_TOGGLED - * - * Specifies the event name for cellsToggled. - */ - CELLS_TOGGLED: 'cellsToggled', - - /** - * Variable: ORDER_CELLS - * - * Specifies the event name for orderCells. - */ - ORDER_CELLS: 'orderCells', - - /** - * Variable: CELLS_ORDERED - * - * Specifies the event name for cellsOrdered. - */ - CELLS_ORDERED: 'cellsOrdered', - - /** - * Variable: REMOVE_CELLS - * - * Specifies the event name for removeCells. - */ - REMOVE_CELLS: 'removeCells', - - /** - * Variable: CELLS_REMOVED - * - * Specifies the event name for cellsRemoved. - */ - CELLS_REMOVED: 'cellsRemoved', - - /** - * Variable: GROUP_CELLS - * - * Specifies the event name for groupCells. - */ - GROUP_CELLS: 'groupCells', - - /** - * Variable: UNGROUP_CELLS - * - * Specifies the event name for ungroupCells. - */ - UNGROUP_CELLS: 'ungroupCells', - - /** - * Variable: REMOVE_CELLS_FROM_PARENT - * - * Specifies the event name for removeCellsFromParent. - */ - REMOVE_CELLS_FROM_PARENT: 'removeCellsFromParent', - - /** - * Variable: FOLD_CELLS - * - * Specifies the event name for foldCells. - */ - FOLD_CELLS: 'foldCells', - - /** - * Variable: CELLS_FOLDED - * - * Specifies the event name for cellsFolded. - */ - CELLS_FOLDED: 'cellsFolded', - - /** - * Variable: ALIGN_CELLS - * - * Specifies the event name for alignCells. - */ - ALIGN_CELLS: 'alignCells', - - /** - * Variable: LABEL_CHANGED - * - * Specifies the event name for labelChanged. - */ - LABEL_CHANGED: 'labelChanged', - - /** - * Variable: CONNECT_CELL - * - * Specifies the event name for connectCell. - */ - CONNECT_CELL: 'connectCell', - - /** - * Variable: CELL_CONNECTED - * - * Specifies the event name for cellConnected. - */ - CELL_CONNECTED: 'cellConnected', - - /** - * Variable: SPLIT_EDGE - * - * Specifies the event name for splitEdge. - */ - SPLIT_EDGE: 'splitEdge', - - /** - * Variable: FLIP_EDGE - * - * Specifies the event name for flipEdge. - */ - FLIP_EDGE: 'flipEdge', - - /** - * Variable: START_EDITING - * - * Specifies the event name for startEditing. - */ - START_EDITING: 'startEditing', - - /** - * Variable: ADD_OVERLAY - * - * Specifies the event name for addOverlay. - */ - ADD_OVERLAY: 'addOverlay', - - /** - * Variable: REMOVE_OVERLAY - * - * Specifies the event name for removeOverlay. - */ - REMOVE_OVERLAY: 'removeOverlay', - - /** - * Variable: UPDATE_CELL_SIZE - * - * Specifies the event name for updateCellSize. - */ - UPDATE_CELL_SIZE: 'updateCellSize', - - /** - * Variable: ESCAPE - * - * Specifies the event name for escape. - */ - ESCAPE: 'escape', - - /** - * Variable: CLICK - * - * Specifies the event name for click. - */ - CLICK: 'click', - - /** - * Variable: DOUBLE_CLICK - * - * Specifies the event name for doubleClick. - */ - DOUBLE_CLICK: 'doubleClick', - - /** - * Variable: START - * - * Specifies the event name for start. - */ - START: 'start', - - /** - * Variable: RESET - * - * Specifies the event name for reset. - */ - RESET: 'reset' - -}; diff --git a/src/js/util/mxEventObject.js b/src/js/util/mxEventObject.js deleted file mode 100644 index cb08a55..0000000 --- a/src/js/util/mxEventObject.js +++ /dev/null @@ -1,111 +0,0 @@ -/** - * $Id: mxEventObject.js,v 1.11 2011-09-09 10:29:05 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -/** - * Class: mxEventObject - * - * The mxEventObject is a wrapper for all properties of a single event. - * Additionally, it also offers functions to consume the event and check if it - * was consumed as follows: - * - * (code) - * evt.consume(); - * INV: evt.isConsumed() == true - * (end) - * - * Constructor: mxEventObject - * - * Constructs a new event object with the specified name. An optional - * sequence of key, value pairs can be appended to define properties. - * - * Example: - * - * (code) - * new mxEventObject("eventName", key1, val1, .., keyN, valN) - * (end) - */ -function mxEventObject(name) -{ - this.name = name; - this.properties = []; - - for (var i = 1; i < arguments.length; i += 2) - { - if (arguments[i + 1] != null) - { - this.properties[arguments[i]] = arguments[i + 1]; - } - } -}; - -/** - * Variable: name - * - * Holds the name. - */ -mxEventObject.prototype.name = null; - -/** - * Variable: properties - * - * Holds the properties as an associative array. - */ -mxEventObject.prototype.properties = null; - -/** - * Variable: consumed - * - * Holds the consumed state. Default is false. - */ -mxEventObject.prototype.consumed = false; - -/** - * Function: getName - * - * Returns <name>. - */ -mxEventObject.prototype.getName = function() -{ - return this.name; -}; - -/** - * Function: getProperties - * - * Returns <properties>. - */ -mxEventObject.prototype.getProperties = function() -{ - return this.properties; -}; - -/** - * Function: getProperty - * - * Returns the property for the given key. - */ -mxEventObject.prototype.getProperty = function(key) -{ - return this.properties[key]; -}; - -/** - * Function: isConsumed - * - * Returns true if the event has been consumed. - */ -mxEventObject.prototype.isConsumed = function() -{ - return this.consumed; -}; - -/** - * Function: consume - * - * Consumes the event. - */ -mxEventObject.prototype.consume = function() -{ - this.consumed = true; -}; diff --git a/src/js/util/mxEventSource.js b/src/js/util/mxEventSource.js deleted file mode 100644 index 595f560..0000000 --- a/src/js/util/mxEventSource.js +++ /dev/null @@ -1,191 +0,0 @@ -/** - * $Id: mxEventSource.js,v 1.25 2012-04-16 10:54:20 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -/** - * Class: mxEventSource - * - * Base class for objects that dispatch named events. To create a subclass that - * inherits from mxEventSource, the following code is used. - * - * (code) - * function MyClass() { }; - * - * MyClass.prototype = new mxEventSource(); - * MyClass.prototype.constructor = MyClass; - * (end) - * - * Known Subclasses: - * - * <mxGraphModel>, <mxGraph>, <mxGraphView>, <mxEditor>, <mxCellOverlay>, - * <mxToolbar>, <mxWindow> - * - * Constructor: mxEventSource - * - * Constructs a new event source. - */ -function mxEventSource(eventSource) -{ - this.setEventSource(eventSource); -}; - -/** - * Variable: eventListeners - * - * Holds the event names and associated listeners in an array. The array - * contains the event name followed by the respective listener for each - * registered listener. - */ -mxEventSource.prototype.eventListeners = null; - -/** - * Variable: eventsEnabled - * - * Specifies if events can be fired. Default is true. - */ -mxEventSource.prototype.eventsEnabled = true; - -/** - * Variable: eventSource - * - * Optional source for events. Default is null. - */ -mxEventSource.prototype.eventSource = null; - -/** - * Function: isEventsEnabled - * - * Returns <eventsEnabled>. - */ -mxEventSource.prototype.isEventsEnabled = function() -{ - return this.eventsEnabled; -}; - -/** - * Function: setEventsEnabled - * - * Sets <eventsEnabled>. - */ -mxEventSource.prototype.setEventsEnabled = function(value) -{ - this.eventsEnabled = value; -}; - -/** - * Function: getEventSource - * - * Returns <eventSource>. - */ -mxEventSource.prototype.getEventSource = function() -{ - return this.eventSource; -}; - -/** - * Function: setEventSource - * - * Sets <eventSource>. - */ -mxEventSource.prototype.setEventSource = function(value) -{ - this.eventSource = value; -}; - -/** - * Function: addListener - * - * Binds the specified function to the given event name. If no event name - * is given, then the listener is registered for all events. - * - * The parameters of the listener are the sender and an <mxEventObject>. - */ -mxEventSource.prototype.addListener = function(name, funct) -{ - if (this.eventListeners == null) - { - this.eventListeners = []; - } - - this.eventListeners.push(name); - this.eventListeners.push(funct); -}; - -/** - * Function: removeListener - * - * Removes all occurrences of the given listener from <eventListeners>. - */ -mxEventSource.prototype.removeListener = function(funct) -{ - if (this.eventListeners != null) - { - var i = 0; - - while (i < this.eventListeners.length) - { - if (this.eventListeners[i+1] == funct) - { - this.eventListeners.splice(i, 2); - } - else - { - i += 2; - } - } - } -}; - -/** - * Function: fireEvent - * - * Dispatches the given event to the listeners which are registered for - * the event. The sender argument is optional. The current execution scope - * ("this") is used for the listener invocation (see <mxUtils.bind>). - * - * Example: - * - * (code) - * fireEvent(new mxEventObject("eventName", key1, val1, .., keyN, valN)) - * (end) - * - * Parameters: - * - * evt - <mxEventObject> that represents the event. - * sender - Optional sender to be passed to the listener. Default value is - * the return value of <getEventSource>. - */ -mxEventSource.prototype.fireEvent = function(evt, sender) -{ - if (this.eventListeners != null && - this.isEventsEnabled()) - { - if (evt == null) - { - evt = new mxEventObject(); - } - - if (sender == null) - { - sender = this.getEventSource(); - } - - if (sender == null) - { - sender = this; - } - - var args = [sender, evt]; - - for (var i = 0; i < this.eventListeners.length; i += 2) - { - var listen = this.eventListeners[i]; - - if (listen == null || - listen == evt.getName()) - { - this.eventListeners[i+1].apply(this, args); - } - } - } -}; diff --git a/src/js/util/mxForm.js b/src/js/util/mxForm.js deleted file mode 100644 index bcee299..0000000 --- a/src/js/util/mxForm.js +++ /dev/null @@ -1,202 +0,0 @@ -/** - * $Id: mxForm.js,v 1.16 2010-10-08 04:21:45 david Exp $ - * Copyright (c) 2006-2010, Gaudenz Alder, David Benson - */ -/** - * Class: mxForm - * - * A simple class for creating HTML forms. - * - * Constructor: mxForm - * - * Creates a HTML table using the specified classname. - */ -function mxForm(className) -{ - this.table = document.createElement('table'); - this.table.className = className; - this.body = document.createElement('tbody'); - - this.table.appendChild(this.body); -}; - -/** - * Variable: table - * - * Holds the DOM node that represents the table. - */ -mxForm.prototype.table = null; - -/** - * Variable: body - * - * Holds the DOM node that represents the tbody (table body). New rows - * can be added to this object using DOM API. - */ -mxForm.prototype.body = false; - -/** - * Function: getTable - * - * Returns the table that contains this form. - */ -mxForm.prototype.getTable = function() -{ - return this.table; -}; - -/** - * Function: addButtons - * - * Helper method to add an OK and Cancel button using the respective - * functions. - */ -mxForm.prototype.addButtons = function(okFunct, cancelFunct) -{ - var tr = document.createElement('tr'); - var td = document.createElement('td'); - tr.appendChild(td); - td = document.createElement('td'); - - // Adds the ok button - var button = document.createElement('button'); - mxUtils.write(button, mxResources.get('ok') || 'OK'); - td.appendChild(button); - - mxEvent.addListener(button, 'click', function() - { - okFunct(); - }); - - // Adds the cancel button - button = document.createElement('button'); - mxUtils.write(button, mxResources.get('cancel') || 'Cancel'); - td.appendChild(button); - - mxEvent.addListener(button, 'click', function() - { - cancelFunct(); - }); - - tr.appendChild(td); - this.body.appendChild(tr); -}; - -/** - * Function: addText - * - * Adds a textfield for the given name and value and returns the textfield. - */ -mxForm.prototype.addText = function(name, value) -{ - var input = document.createElement('input'); - - input.setAttribute('type', 'text'); - input.value = value; - - return this.addField(name, input); -}; - -/** - * Function: addCheckbox - * - * Adds a checkbox for the given name and value and returns the textfield. - */ -mxForm.prototype.addCheckbox = function(name, value) -{ - var input = document.createElement('input'); - - input.setAttribute('type', 'checkbox'); - this.addField(name, input); - - // IE can only change the checked value if the input is inside the DOM - if (value) - { - input.checked = true; - } - - return input; -}; - -/** - * Function: addTextarea - * - * Adds a textarea for the given name and value and returns the textarea. - */ -mxForm.prototype.addTextarea = function(name, value, rows) -{ - var input = document.createElement('textarea'); - - if (mxClient.IS_NS) - { - rows--; - } - - input.setAttribute('rows', rows || 2); - input.value = value; - - return this.addField(name, input); -}; - -/** - * Function: addCombo - * - * Adds a combo for the given name and returns the combo. - */ -mxForm.prototype.addCombo = function(name, isMultiSelect, size) -{ - var select = document.createElement('select'); - - if (size != null) - { - select.setAttribute('size', size); - } - - if (isMultiSelect) - { - select.setAttribute('multiple', 'true'); - } - - return this.addField(name, select); -}; - -/** - * Function: addOption - * - * Adds an option for the given label to the specified combo. - */ -mxForm.prototype.addOption = function(combo, label, value, isSelected) -{ - var option = document.createElement('option'); - - mxUtils.writeln(option, label); - option.setAttribute('value', value); - - if (isSelected) - { - option.setAttribute('selected', isSelected); - } - - combo.appendChild(option); -}; - -/** - * Function: addField - * - * Adds a new row with the name and the input field in two columns and - * returns the given input. - */ -mxForm.prototype.addField = function(name, input) -{ - var tr = document.createElement('tr'); - var td = document.createElement('td'); - mxUtils.write(td, name); - tr.appendChild(td); - - td = document.createElement('td'); - td.appendChild(input); - tr.appendChild(td); - this.body.appendChild(tr); - - return input; -}; diff --git a/src/js/util/mxGuide.js b/src/js/util/mxGuide.js deleted file mode 100644 index ab5c26d..0000000 --- a/src/js/util/mxGuide.js +++ /dev/null @@ -1,364 +0,0 @@ -/** - * $Id: mxGuide.js,v 1.7 2012-04-13 12:53:30 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -/** - * Class: mxGuide - * - * Implements the alignment of selection cells to other cells in the graph. - * - * Constructor: mxGuide - * - * Constructs a new guide object. - */ -function mxGuide(graph, states) -{ - this.graph = graph; - this.setStates(states); -}; - -/** - * Variable: graph - * - * Reference to the enclosing <mxGraph> instance. - */ -mxGuide.prototype.graph = null; - -/** - * Variable: states - * - * Contains the <mxCellStates> that are used for alignment. - */ -mxGuide.prototype.states = null; - -/** - * Variable: horizontal - * - * Specifies if horizontal guides are enabled. Default is true. - */ -mxGuide.prototype.horizontal = true; - -/** - * Variable: vertical - * - * Specifies if vertical guides are enabled. Default is true. - */ -mxGuide.prototype.vertical = true; - -/** - * Variable: vertical - * - * Holds the <mxShape> for the horizontal guide. - */ -mxGuide.prototype.guideX = null; - -/** - * Variable: vertical - * - * Holds the <mxShape> for the vertical guide. - */ -mxGuide.prototype.guideY = null; - -/** - * Variable: crisp - * - * Specifies if theguide should be rendered in crisp mode if applicable. - * Default is true. - */ -mxGuide.prototype.crisp = true; - -/** - * Function: setStates - * - * Sets the <mxCellStates> that should be used for alignment. - */ -mxGuide.prototype.setStates = function(states) -{ - this.states = states; -}; - -/** - * Function: isEnabledForEvent - * - * Returns true if the guide should be enabled for the given native event. This - * implementation always returns true. - */ -mxGuide.prototype.isEnabledForEvent = function(evt) -{ - return true; -}; - -/** - * Function: getGuideTolerance - * - * Returns the tolerance for the guides. Default value is - * gridSize * scale / 2. - */ -mxGuide.prototype.getGuideTolerance = function() -{ - return this.graph.gridSize * this.graph.view.scale / 2; -}; - -/** - * Function: createGuideShape - * - * Returns the mxShape to be used for painting the respective guide. This - * implementation returns a new, dashed and crisp <mxPolyline> using - * <mxConstants.GUIDE_COLOR> and <mxConstants.GUIDE_STROKEWIDTH> as the format. - * - * Parameters: - * - * horizontal - Boolean that specifies which guide should be created. - */ -mxGuide.prototype.createGuideShape = function(horizontal) -{ - var guide = new mxPolyline([], mxConstants.GUIDE_COLOR, mxConstants.GUIDE_STROKEWIDTH); - guide.crisp = this.crisp; - guide.isDashed = true; - - return guide; -}; - -/** - * Function: move - * - * Moves the <bounds> by the given <mxPoint> and returnt the snapped point. - */ -mxGuide.prototype.move = function(bounds, delta, gridEnabled) -{ - if (this.states != null && (this.horizontal || this.vertical) && bounds != null && delta != null) - { - var trx = this.graph.getView().translate; - var scale = this.graph.getView().scale; - var dx = delta.x; - var dy = delta.y; - - var overrideX = false; - var overrideY = false; - - var tt = this.getGuideTolerance(); - var ttX = tt; - var ttY = tt; - - var b = bounds.clone(); - b.x += delta.x; - b.y += delta.y; - - var left = b.x; - var right = b.x + b.width; - var center = b.getCenterX(); - var top = b.y; - var bottom = b.y + b.height; - var middle = b.getCenterY(); - - // Snaps the left, center and right to the given x-coordinate - function snapX(x) - { - x += this.graph.panDx; - var override = false; - - if (Math.abs(x - center) < ttX) - { - dx = x - bounds.getCenterX(); - ttX = Math.abs(x - center); - override = true; - } - else if (Math.abs(x - left) < ttX) - { - dx = x - bounds.x; - ttX = Math.abs(x - left); - override = true; - } - else if (Math.abs(x - right) < ttX) - { - dx = x - bounds.x - bounds.width; - ttX = Math.abs(x - right); - override = true; - } - - if (override) - { - if (this.guideX == null) - { - this.guideX = this.createGuideShape(true); - - // Makes sure to use either VML or SVG shapes in order to implement - // event-transparency on the background area of the rectangle since - // HTML shapes do not let mouseevents through even when transparent - this.guideX.dialect = (this.graph.dialect != mxConstants.DIALECT_SVG) ? - mxConstants.DIALECT_VML : mxConstants.DIALECT_SVG; - this.guideX.init(this.graph.getView().getOverlayPane()); - - if (this.graph.dialect == mxConstants.DIALECT_SVG) - { - this.guideX.node.setAttribute('pointer-events', 'none'); - this.guideX.pipe.setAttribute('pointer-events', 'none'); - } - } - - var c = this.graph.container; - x -= this.graph.panDx; - this.guideX.points = [new mxPoint(x, -this.graph.panDy), new mxPoint(x, c.scrollHeight - 3 - this.graph.panDy)]; - } - - overrideX = overrideX || override; - }; - - // Snaps the top, middle or bottom to the given y-coordinate - function snapY(y) - { - y += this.graph.panDy; - var override = false; - - if (Math.abs(y - middle) < ttY) - { - dy = y - bounds.getCenterY(); - ttY = Math.abs(y - middle); - override = true; - } - else if (Math.abs(y - top) < ttY) - { - dy = y - bounds.y; - ttY = Math.abs(y - top); - override = true; - } - else if (Math.abs(y - bottom) < ttY) - { - dy = y - bounds.y - bounds.height; - ttY = Math.abs(y - bottom); - override = true; - } - - if (override) - { - if (this.guideY == null) - { - this.guideY = this.createGuideShape(false); - - // Makes sure to use either VML or SVG shapes in order to implement - // event-transparency on the background area of the rectangle since - // HTML shapes do not let mouseevents through even when transparent - this.guideY.dialect = (this.graph.dialect != mxConstants.DIALECT_SVG) ? - mxConstants.DIALECT_VML : mxConstants.DIALECT_SVG; - this.guideY.init(this.graph.getView().getOverlayPane()); - - if (this.graph.dialect == mxConstants.DIALECT_SVG) - { - this.guideY.node.setAttribute('pointer-events', 'none'); - this.guideY.pipe.setAttribute('pointer-events', 'none'); - } - } - - var c = this.graph.container; - y -= this.graph.panDy; - this.guideY.points = [new mxPoint(-this.graph.panDx, y), new mxPoint(c.scrollWidth - 3 - this.graph.panDx, y)]; - } - - overrideY = overrideY || override; - }; - - for (var i = 0; i < this.states.length; i++) - { - var state = this.states[i]; - - if (state != null) - { - // Align x - if (this.horizontal) - { - snapX.call(this, state.getCenterX()); - snapX.call(this, state.x); - snapX.call(this, state.x + state.width); - } - - // Align y - if (this.vertical) - { - snapY.call(this, state.getCenterY()); - snapY.call(this, state.y); - snapY.call(this, state.y + state.height); - } - } - } - - if (!overrideX && this.guideX != null) - { - this.guideX.node.style.visibility = 'hidden'; - } - else if (this.guideX != null) - { - this.guideX.node.style.visibility = 'visible'; - this.guideX.redraw(); - } - - if (!overrideY && this.guideY != null) - { - this.guideY.node.style.visibility = 'hidden'; - } - else if (this.guideY != null) - { - this.guideY.node.style.visibility = 'visible'; - this.guideY.redraw(); - } - - // Moves cells that are off-grid back to the grid on move - if (gridEnabled) - { - if (!overrideX) - { - var tx = bounds.x - (this.graph.snap(bounds.x / - scale - trx.x) + trx.x) * scale; - dx = this.graph.snap(dx / scale) * scale - tx; - } - - if (!overrideY) - { - var ty = bounds.y - (this.graph.snap(bounds.y / - scale - trx.y) + trx.y) * scale; - dy = this.graph.snap(dy / scale) * scale - ty; - } - } - - delta = new mxPoint(dx, dy); - } - - return delta; -}; - -/** - * Function: hide - * - * Hides all current guides. - */ -mxGuide.prototype.hide = function() -{ - if (this.guideX != null) - { - this.guideX.node.style.visibility = 'hidden'; - } - - if (this.guideY != null) - { - this.guideY.node.style.visibility = 'hidden'; - } -}; - -/** - * Function: destroy - * - * Destroys all resources that this object uses. - */ -mxGuide.prototype.destroy = function() -{ - if (this.guideX != null) - { - this.guideX.destroy(); - this.guideX = null; - } - - if (this.guideY != null) - { - this.guideY.destroy(); - this.guideY = null; - } -}; diff --git a/src/js/util/mxImage.js b/src/js/util/mxImage.js deleted file mode 100644 index 39d1a09..0000000 --- a/src/js/util/mxImage.js +++ /dev/null @@ -1,40 +0,0 @@ -/** - * $Id: mxImage.js,v 1.7 2010-01-02 09:45:14 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -/** - * Class: mxImage - * - * Encapsulates the URL, width and height of an image. - * - * Constructor: mxImage - * - * Constructs a new image. - */ -function mxImage(src, width, height) -{ - this.src = src; - this.width = width; - this.height = height; -}; - -/** - * Variable: src - * - * String that specifies the URL of the image. - */ -mxImage.prototype.src = null; - -/** - * Variable: width - * - * Integer that specifies the width of the image. - */ -mxImage.prototype.width = null; - -/** - * Variable: height - * - * Integer that specifies the height of the image. - */ -mxImage.prototype.height = null; diff --git a/src/js/util/mxImageBundle.js b/src/js/util/mxImageBundle.js deleted file mode 100644 index dc4c2cf..0000000 --- a/src/js/util/mxImageBundle.js +++ /dev/null @@ -1,98 +0,0 @@ -/** - * $Id: mxImageBundle.js,v 1.3 2011-01-20 19:08:11 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -/** - * Class: mxImageBundle - * - * Maps from keys to base64 encoded images or file locations. All values must - * be URLs or use the format data:image/format followed by a comma and the base64 - * encoded image data, eg. "data:image/gif,XYZ", where XYZ is the base64 encoded - * image data. - * - * To add a new image bundle to an existing graph, the following code is used: - * - * (code) - * var bundle = new mxImageBundle(alt); - * bundle.putImage('myImage', 'data:image/gif,R0lGODlhEAAQAMIGAAAAAICAAICAgP' + - * '//AOzp2O3r2////////yH+FUNyZWF0ZWQgd2l0aCBUaGUgR0lNUAAh+QQBCgAHACwAAAAA' + - * 'EAAQAAADTXi63AowynnAMDfjPUDlnAAJhmeBFxAEloliKltWmiYCQvfVr6lBPB1ggxN1hi' + - * 'laSSASFQpIV5HJBDyHpqK2ejVRm2AAgZCdmCGO9CIBADs=', fallback); - * graph.addImageBundle(bundle); - * (end); - * - * Alt is an optional boolean (default is false) that specifies if the value - * or the fallback should be returned in <getImage>. - * - * The image can then be referenced in any cell style using image=myImage. - * If you are using mxOutline, you should use the same image bundles in the - * graph that renders the outline. - * - * The keys for images are resolved in <mxGraph.postProcessCellStyle> and - * turned into a data URI if the returned value has a short data URI format - * as specified above. - * - * A typical value for the fallback is a MTHML link as defined in RFC 2557. - * Note that this format requires a file to be dynamically created on the - * server-side, or the page that contains the graph to be modified to contain - * the resources, this can be done by adding a comment that contains the - * resource in the HEAD section of the page after the title tag. - * - * This type of fallback mechanism should be used in IE6 and IE7. IE8 does - * support data URIs, but the maximum size is limited to 32 KB, which means - * all data URIs should be limited to 32 KB. - */ -function mxImageBundle(alt) -{ - this.images = []; - this.alt = (alt != null) ? alt : false; -}; - -/** - * Variable: images - * - * Maps from keys to images. - */ -mxImageBundle.prototype.images = null; - -/** - * Variable: alt - * - * Specifies if the fallback representation should be returned. - */ -mxImageBundle.prototype.images = null; - -/** - * Function: putImage - * - * Adds the specified entry to the map. The entry is an object with a value and - * fallback property as specified in the arguments. - */ -mxImageBundle.prototype.putImage = function(key, value, fallback) -{ - this.images[key] = {value: value, fallback: fallback}; -}; - -/** - * Function: getImage - * - * Returns the value for the given key. This returns the value - * or fallback, depending on <alt>. The fallback is returned if - * <alt> is true, the value is returned otherwise. - */ -mxImageBundle.prototype.getImage = function(key) -{ - var result = null; - - if (key != null) - { - var img = this.images[key]; - - if (img != null) - { - result = (this.alt) ? img.fallback : img.value; - } - } - - return result; -}; diff --git a/src/js/util/mxImageExport.js b/src/js/util/mxImageExport.js deleted file mode 100644 index dcbcf9a..0000000 --- a/src/js/util/mxImageExport.js +++ /dev/null @@ -1,1412 +0,0 @@ -/** - * $Id: mxImageExport.js,v 1.47 2012-09-24 14:54:32 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -/** - * Class: mxImageExport - * - * Creates a new image export instance to be used with an export canvas. Here - * is an example that uses this class to create an image via a backend using - * <mxXmlExportCanvas>. - * - * (code) - * var xmlDoc = mxUtils.createXmlDocument(); - * var root = xmlDoc.createElement('output'); - * xmlDoc.appendChild(root); - * - * var xmlCanvas = new mxXmlCanvas2D(root); - * var imgExport = new mxImageExport(); - * imgExport.drawState(graph.getView().getState(graph.model.root), xmlCanvas); - * - * var bounds = graph.getGraphBounds(); - * var w = Math.ceil(bounds.x + bounds.width); - * var h = Math.ceil(bounds.y + bounds.height); - * - * var xml = mxUtils.getXml(root); - * new mxXmlRequest('export', 'format=png&w=' + w + - * '&h=' + h + '&bg=#F9F7ED&xml=' + encodeURIComponent(xml)) - * .simulate(document, '_blank'); - * (end) - * - * In order to export images for a graph whose container is not visible or not - * part of the DOM, the following workaround can be used to compute the size of - * the labels. - * - * (code) - * mxText.prototype.getTableSize = function(table) - * { - * var oldParent = table.parentNode; - * - * document.body.appendChild(table); - * var size = new mxRectangle(0, 0, table.offsetWidth, table.offsetHeight); - * oldParent.appendChild(table); - * - * return size; - * }; - * (end) - * - * Constructor: mxImageExport - * - * Constructs a new image export. - */ -function mxImageExport() -{ - this.initShapes(); - this.initMarkers(); -}; - -/** - * Variable: includeOverlays - * - * Specifies if overlays should be included in the export. Default is false. - */ -mxImageExport.prototype.includeOverlays = false; - -/** - * Variable: glassSize - * - * Reference to the thread while the animation is running. - */ -mxImageExport.prototype.glassSize = 0.4; - -/** - * Variable: shapes - * - * Holds implementations for the built-in shapes. - */ -mxImageExport.prototype.shapes = null; - -/** - * Variable: markers - * - * Holds implementations for the built-in markers. - */ -mxImageExport.prototype.markers = null; - -/** - * Function: drawState - * - * Draws the given state and all its descendants to the given canvas. - */ -mxImageExport.prototype.drawState = function(state, canvas) -{ - if (state != null) - { - if (state.shape != null) - { - var shape = (state.shape.stencil != null) ? - state.shape.stencil : - this.shapes[state.style[mxConstants.STYLE_SHAPE]]; - - if (shape == null) - { - // Checks if there is a custom shape - if (typeof(state.shape.redrawPath) == 'function') - { - shape = this.createShape(state, canvas); - } - // Uses a rectangle for all vertices where no shape can be found - else if (state.view.graph.getModel().isVertex(state.cell)) - { - shape = this.shapes['rectangle']; - } - } - - if (shape != null) - { - this.drawShape(state, canvas, shape); - - if (this.includeOverlays) - { - this.drawOverlays(state, canvas); - } - } - } - - var graph = state.view.graph; - var childCount = graph.model.getChildCount(state.cell); - - for (var i = 0; i < childCount; i++) - { - var childState = graph.view.getState(graph.model.getChildAt(state.cell, i)); - this.drawState(childState, canvas); - } - } -}; - -/** - * Function: createShape - * - * Creates a shape wrapper for the custom shape in the given cell state and - * links its output to the given canvas. - */ -mxImageExport.prototype.createShape = function(state, canvas) -{ - return { - drawShape: function(canvas, state, bounds, background) - { - var path = - { - translate: new mxPoint(bounds.x, bounds.y), - moveTo: function(x, y) - { - canvas.moveTo(this.translate.x + x, this.translate.y + y); - }, - lineTo: function(x, y) - { - canvas.lineTo(this.translate.x + x, this.translate.y + y); - }, - quadTo: function(x1, y1, x, y) - { - canvas.quadTo(this.translate.x + x1, this.translate.y + y1, this.translate.x + x, this.translate.y + y); - }, - curveTo: function(x1, y1, x2, y2, x, y) - { - canvas.curveTo(this.translate.x + x1, this.translate.y + y1, this.translate.x + x2, this.translate.y + y2, this.translate.x + x, this.translate.y + y); - }, - end: function() - { - // do nothing - }, - close: function() - { - canvas.close(); - } - }; - - if (!background) - { - canvas.fillAndStroke(); - } - - // LATER: Remove empty path if shape does not implement foreground, add shadow/clipping - canvas.begin(); - state.shape.redrawPath.call(state.shape, path, bounds.x, bounds.y, bounds.width, bounds.height, !background); - - if (!background) - { - canvas.fillAndStroke(); - } - - return true; - } - }; -}; - -/** - * Function: drawOverlays - * - * Draws the overlays for the given state. This is called if <includeOverlays> - * is true. - */ -mxImageExport.prototype.drawOverlays = function(state, canvas) -{ - if (state.overlays != null) - { - state.overlays.visit(function(id, shape) - { - var bounds = shape.bounds; - - if (bounds != null) - { - canvas.image(bounds.x, bounds.y, bounds.width, bounds.height, shape.image); - } - }); - } -}; - -/** - * Function: drawShape - * - * Draws the given state to the given canvas. - */ -mxImageExport.prototype.drawShape = function(state, canvas, shape) -{ - var rotation = mxUtils.getNumber(state.style, mxConstants.STYLE_ROTATION, 0); - var direction = mxUtils.getValue(state.style, mxConstants.STYLE_DIRECTION, null); - - // New styles for shape flipping the stencil - var flipH = state.style[mxConstants.STYLE_STENCIL_FLIPH]; - var flipV = state.style[mxConstants.STYLE_STENCIL_FLIPV]; - - if (flipH ? !flipV : flipV) - { - rotation *= -1; - } - - // Default direction is east (ignored if rotation exists) - if (direction != null) - { - if (direction == 'north') - { - rotation += 270; - } - else if (direction == 'west') - { - rotation += 180; - } - else if (direction == 'south') - { - rotation += 90; - } - } - - if (flipH && flipV) - { - rotation += 180; - flipH = false; - flipV = false; - } - - // Saves the global state for each cell - canvas.save(); - - // Adds rotation and horizontal/vertical flipping - // FIXME: Rotation and stencil flip only supported for stencil shapes - rotation = rotation % 360; - - if (rotation != 0 || flipH || flipV) - { - canvas.rotate(rotation, flipH, flipV, state.getCenterX(), state.getCenterY()); - } - - // Note: Overwritten in mxStencil.paintShape (can depend on aspect) - var scale = state.view.scale; - var sw = mxUtils.getNumber(state.style, mxConstants.STYLE_STROKEWIDTH, 1) * scale; - canvas.setStrokeWidth(sw); - - var sw2 = sw / 2; - var bg = this.getBackgroundBounds(state); - - // Stencils will rotate the bounds as required - if (state.shape.stencil == null && (direction == 'south' || direction == 'north')) - { - var dx = (bg.width - bg.height) / 2; - bg.x += dx; - bg.y += -dx; - var tmp = bg.width; - bg.width = bg.height; - bg.height = tmp; - } - - var bb = new mxRectangle(bg.x - sw2, bg.y - sw2, bg.width + sw, bg.height + sw); - var alpha = mxUtils.getValue(state.style, mxConstants.STYLE_OPACITY, 100) / 100; - - var shp = state.style[mxConstants.STYLE_SHAPE]; - var imageShape = shp == mxConstants.SHAPE_IMAGE; - var gradientColor = (imageShape) ? null : mxUtils.getValue(state.style, mxConstants.STYLE_GRADIENTCOLOR); - - // Converts colors with special keyword none to null - if (gradientColor == mxConstants.NONE) - { - gradientColor = null; - } - - var fcKey = (imageShape) ? mxConstants.STYLE_IMAGE_BACKGROUND : mxConstants.STYLE_FILLCOLOR; - var fillColor = mxUtils.getValue(state.style, fcKey, null); - - if (fillColor == mxConstants.NONE) - { - fillColor = null; - } - - var scKey = (imageShape) ? mxConstants.STYLE_IMAGE_BORDER : mxConstants.STYLE_STROKECOLOR; - var strokeColor = mxUtils.getValue(state.style, scKey, null); - - if (strokeColor == mxConstants.NONE) - { - strokeColor = null; - } - - var glass = (fillColor != null && (shp == mxConstants.SHAPE_LABEL || shp == mxConstants.SHAPE_RECTANGLE)); - - // Draws the shadow if the fillColor is not transparent - if (mxUtils.getValue(state.style, mxConstants.STYLE_SHADOW, false)) - { - this.drawShadow(canvas, state, shape, rotation, flipH, flipV, bg, alpha, fillColor != null); - } - - canvas.setAlpha(alpha); - - // Sets the dashed state - if (mxUtils.getValue(state.style, mxConstants.STYLE_DASHED, '0') == '1') - { - canvas.setDashed(true); - - // Supports custom dash patterns - var dash = state.style['dashPattern']; - - if (dash != null) - { - canvas.setDashPattern(dash); - } - } - - // Draws background and foreground - if (strokeColor != null || fillColor != null) - { - if (strokeColor != null) - { - canvas.setStrokeColor(strokeColor); - } - - if (fillColor != null) - { - if (gradientColor != null && gradientColor != 'transparent') - { - canvas.setGradient(fillColor, gradientColor, bg.x, bg.y, bg.width, bg.height, direction); - } - else - { - canvas.setFillColor(fillColor); - } - } - - // Draws background and foreground of shape - glass = shape.drawShape(canvas, state, bg, true, false) && glass; - shape.drawShape(canvas, state, bg, false, false); - } - - // Draws the glass effect - // Requires background in generic shape for clipping - if (glass && mxUtils.getValue(state.style, mxConstants.STYLE_GLASS, 0) == 1) - { - this.drawGlass(state, canvas, bb, shape, this.glassSize); - } - - // Draws the image (currently disabled for everything but image and label shapes) - if (imageShape || shp == mxConstants.SHAPE_LABEL) - { - var src = state.view.graph.getImage(state); - - if (src != null) - { - var imgBounds = this.getImageBounds(state); - - if (imgBounds != null) - { - this.drawImage(state, canvas, imgBounds, src); - } - } - } - - // Restores canvas state - canvas.restore(); - - // Draws the label (label has separate rotation) - var txt = state.text; - - // Does not use mxCellRenderer.getLabelValue to avoid conversion of HTML entities for VML - var label = state.view.graph.getLabel(state.cell); - - if (txt != null && label != null && label.length > 0) - { - canvas.save(); - canvas.setAlpha(mxUtils.getValue(state.style, mxConstants.STYLE_TEXT_OPACITY, 100) / 100); - var bounds = new mxRectangle(txt.boundingBox.x, txt.boundingBox.y, txt.boundingBox.width, txt.boundingBox.height); - var vert = mxUtils.getValue(state.style, mxConstants.STYLE_HORIZONTAL, 1) == 0; - - // Vertical error offset - bounds.y += 2; - - if (vert) - { - if (txt.dialect != mxConstants.DIALECT_SVG) - { - var cx = bounds.x + bounds.width / 2; - var cy = bounds.y + bounds.height / 2; - var tmp = bounds.width; - bounds.width = bounds.height; - bounds.height = tmp; - bounds.x = cx - bounds.width / 2; - bounds.y = cy - bounds.height / 2; - } - else if (txt.dialect == mxConstants.DIALECT_SVG) - { - // Workarounds for different label bounding boxes (mostly ignoring rotation). - // LATER: Fix in mxText so that the bounding box is consistent and rotated. - // TODO: Check non-center/middle-aligned vertical labels in VML for IE8. - var b = state.y + state.height; - var cx = bounds.getCenterX() - state.x; - var cy = bounds.getCenterY() - state.y; - - var y = b - cx - bounds.height / 2; - bounds.x = state.x + cy - bounds.width / 2; - bounds.y = y; - //bounds.x -= state.height / 2 - state.width / 2; - //bounds.y -= state.width / 2 - state.height / 2; - } - } - - this.drawLabelBackground(state, canvas, bounds, vert); - this.drawLabel(state, canvas, bounds, vert, label); - canvas.restore(); - } -}; - -/** - * Function: drawGlass - * - * Draws the given state to the given canvas. - */ -mxImageExport.prototype.drawShadow = function(canvas, state, shape, rotation, flipH, flipV, bounds, alpha, filled) -{ - // Requires background in generic shape for shadow, looks like only one - // fillAndStroke is allowed per current path, try working around that - // Computes rotated shadow offset - var rad = rotation * Math.PI / 180; - var cos = Math.cos(-rad); - var sin = Math.sin(-rad); - var offset = mxUtils.getRotatedPoint(new mxPoint(mxConstants.SHADOW_OFFSET_X, mxConstants.SHADOW_OFFSET_Y), cos, sin); - - if (flipH) - { - offset.x *= -1; - } - - if (flipV) - { - offset.y *= -1; - } - - // TODO: Use save/restore instead of negative offset to restore (requires fix for HTML canvas) - canvas.translate(offset.x, offset.y); - - // Returns true if a shadow has been painted (path has been created) - if (shape.drawShape(canvas, state, bounds, true, true)) - { - canvas.setAlpha(mxConstants.SHADOW_OPACITY * alpha); - canvas.shadow(mxConstants.SHADOWCOLOR, filled); - } - - canvas.translate(-offset.x, -offset.y); -}; - -/** - * Function: drawGlass - * - * Draws the given state to the given canvas. - */ -mxImageExport.prototype.drawGlass = function(state, canvas, bounds, shape, size) -{ - // LATER: Clipping region should include stroke - if (shape.drawShape(canvas, state, bounds, true, false)) - { - canvas.save(); - canvas.clip(); - canvas.setGlassGradient(bounds.x, bounds.y, bounds.width, bounds.height); - - canvas.begin(); - canvas.moveTo(bounds.x, bounds.y); - canvas.lineTo(bounds.x, (bounds.y + bounds.height * size)); - canvas.quadTo((bounds.x + bounds.width * 0.5), - (bounds.y + bounds.height * 0.7), bounds.x + bounds.width, - (bounds.y + bounds.height * size)); - canvas.lineTo(bounds.x + bounds.width, bounds.y); - canvas.close(); - - canvas.fill(); - canvas.restore(); - } -}; - -/** - * Function: drawImage - * - * Draws the given state to the given canvas. - */ -mxImageExport.prototype.drawImage = function(state, canvas, bounds, image) -{ - var aspect = mxUtils.getValue(state.style, mxConstants.STYLE_IMAGE_ASPECT, 1) == 1; - var flipH = mxUtils.getValue(state.style, mxConstants.STYLE_IMAGE_FLIPH, 0) == 1; - var flipV = mxUtils.getValue(state.style, mxConstants.STYLE_IMAGE_FLIPV, 0) == 1; - - canvas.image(bounds.x, bounds.y, bounds.width, bounds.height, image, aspect, flipH, flipV); -}; - -/** - * Function: drawLabelBackground - * - * Draws background for the label of the given state to the given canvas. - */ -mxImageExport.prototype.drawLabelBackground = function(state, canvas, bounds, vert) -{ - var stroke = mxUtils.getValue(state.style, mxConstants.STYLE_LABEL_BORDERCOLOR); - var fill = mxUtils.getValue(state.style, mxConstants.STYLE_LABEL_BACKGROUNDCOLOR); - - if (stroke == mxConstants.NONE) - { - stroke = null; - } - - if (fill == mxConstants.NONE) - { - fill = null; - } - - if (stroke != null || fill != null) - { - var x = bounds.x; - var y = bounds.y - mxUtils.getValue(state.style, mxConstants.STYLE_LABEL_PADDING, 0); - var w = bounds.width; - var h = bounds.height; - - if (vert) - { - x += (w - h) / 2; - y += (h - w) / 2; - var tmp = w; - w = h; - h = tmp; - } - - if (fill != null) - { - canvas.setFillColor(fill); - } - - if (stroke != null) - { - canvas.setStrokeColor(stroke); - canvas.setStrokeWidth(1); - canvas.setDashed(false); - } - - canvas.rect(x, y, w, h); - - if (fill != null && stroke != null) - { - canvas.fillAndStroke(); - } - else if (fill != null) - { - canvas.fill(); - } - else if (stroke != null) - { - canvas.stroke(); - } - } -}; - -/** - * Function: drawLabel - * - * Draws the given state to the given canvas. - */ -mxImageExport.prototype.drawLabel = function(state, canvas, bounds, vert, str) -{ - var scale = state.view.scale; - - // Applies color - canvas.setFontColor(mxUtils.getValue(state.style, mxConstants.STYLE_FONTCOLOR, '#000000')); - - // Applies font settings - canvas.setFontFamily(mxUtils.getValue(state.style, mxConstants.STYLE_FONTFAMILY, - mxConstants.DEFAULT_FONTFAMILY)); - canvas.setFontStyle(mxUtils.getValue(state.style, mxConstants.STYLE_FONTSTYLE, 0)); - canvas.setFontSize(mxUtils.getValue(state.style, mxConstants.STYLE_FONTSIZE, - mxConstants.DEFAULT_FONTSIZE) * scale); - - var align = mxUtils.getValue(state.style, mxConstants.STYLE_ALIGN, mxConstants.ALIGN_LEFT); - - // Uses null alignment for default values (valign default is 'top' which is fine) - if (align == 'left') - { - align = null; - } - - var y = bounds.y - mxUtils.getValue(state.style, mxConstants.STYLE_LABEL_PADDING, 0); - var wrap = state.view.graph.isWrapping(state.cell); - var html = state.view.graph.isHtmlLabel(state.cell); - - // Replaces linefeeds in HTML markup to match the display output - if (html && mxText.prototype.replaceLinefeeds) - { - str = str.replace(/\n/g, '<br/>'); - } - - canvas.text(bounds.x, y, bounds.width, bounds.height, str, align, null, vert, wrap, (html) ? 'html' : ''); -}; - -/** - * Function: getBackgroundBounds - * - * Draws the given state to the given canvas. - */ -mxImageExport.prototype.getBackgroundBounds = function(state) -{ - if (state.style[mxConstants.STYLE_SHAPE] == mxConstants.SHAPE_SWIMLANE) - { - var scale = state.view.scale; - var start = mxUtils.getValue(state.style, mxConstants.STYLE_STARTSIZE, mxConstants.DEFAULT_STARTSIZE) * scale; - var w = state.width; - var h = state.height; - - if (mxUtils.getValue(state.style, mxConstants.STYLE_HORIZONTAL, true)) - { - h = start; - } - else - { - w = start; - } - - return new mxRectangle(state.x, state.y, Math.min(state.width, w), Math.min(state.height, h)); - } - else - { - return new mxRectangle(state.x, state.y, state.width, state.height); - } -}; - -/** - * Function: getImageBounds - * - * Draws the given state to the given canvas. - */ -mxImageExport.prototype.getImageBounds = function(state) -{ - var bounds = new mxRectangle(state.x, state.y, state.width, state.height); - var style = state.style; - - if (mxUtils.getValue(style, mxConstants.STYLE_SHAPE) != mxConstants.SHAPE_IMAGE) - { - var imgAlign = mxUtils.getValue(style, mxConstants.STYLE_IMAGE_ALIGN, mxConstants.ALIGN_LEFT); - var imgValign = mxUtils.getValue(style, mxConstants.STYLE_IMAGE_VERTICAL_ALIGN, mxConstants.ALIGN_MIDDLE); - var imgWidth = mxUtils.getValue(style, mxConstants.STYLE_IMAGE_WIDTH, mxConstants.DEFAULT_IMAGESIZE); - var imgHeight = mxUtils.getValue(style, mxConstants.STYLE_IMAGE_HEIGHT, mxConstants.DEFAULT_IMAGESIZE); - var spacing = mxUtils.getValue(style, mxConstants.STYLE_SPACING, 2); - - if (imgAlign == mxConstants.ALIGN_CENTER) - { - bounds.x += (bounds.width - imgWidth) / 2; - } - else if (imgAlign == mxConstants.ALIGN_RIGHT) - { - bounds.x += bounds.width - imgWidth - spacing - 2; - } - else - // LEFT - { - bounds.x += spacing + 4; - } - - if (imgValign == mxConstants.ALIGN_TOP) - { - bounds.y += spacing; - } - else if (imgValign == mxConstants.ALIGN_BOTTOM) - { - bounds.y += bounds.height - imgHeight - spacing; - } - else - // MIDDLE - { - bounds.y += (bounds.height - imgHeight) / 2; - } - - bounds.width = imgWidth; - bounds.height = imgHeight; - } - - return bounds; -}; - -/** - * Function: drawMarker - * - * Initializes the built-in shapes. - */ -mxImageExport.prototype.drawMarker = function(canvas, state, source) -{ - var offset = null; - - // Computes the norm and the inverse norm - var pts = state.absolutePoints; - var n = pts.length; - - var p0 = (source) ? pts[1] : pts[n - 2]; - var pe = (source) ? pts[0] : pts[n - 1]; - - var dx = pe.x - p0.x; - var dy = pe.y - p0.y; - - var dist = Math.max(1, Math.sqrt(dx * dx + dy * dy)); - - var unitX = dx / dist; - var unitY = dy / dist; - - var size = mxUtils.getValue(state.style, (source) ? - mxConstants.STYLE_STARTSIZE : - mxConstants.STYLE_ENDSIZE, - mxConstants.DEFAULT_MARKERSIZE); - - // Allow for stroke width in the end point used and the - // orthogonal vectors describing the direction of the marker - // TODO: Should get strokewidth from canvas (same for strokecolor) - var sw = mxUtils.getValue(state.style, mxConstants.STYLE_STROKEWIDTH, 1); - - pe = pe.clone(); - - var type = mxUtils.getValue(state.style, (source) ? - mxConstants.STYLE_STARTARROW : - mxConstants.STYLE_ENDARROW); - var f = this.markers[type]; - - if (f != null) - { - offset = f(canvas, state, type, pe, unitX, unitY, size, source, sw); - } - - return offset; -}; - -/** - * Function: initShapes - * - * Initializes the built-in shapes. - */ -mxImageExport.prototype.initShapes = function() -{ - this.shapes = []; - - // Implements the rectangle and rounded rectangle shape - this.shapes['rectangle'] = - { - drawShape: function(canvas, state, bounds, background) - { - if (background) - { - // Paints the shape - if (mxUtils.getValue(state.style, mxConstants.STYLE_ROUNDED, false)) - { - var f = mxUtils.getValue(state.style, mxConstants.STYLE_ARCSIZE, mxConstants.RECTANGLE_ROUNDING_FACTOR * 100) / 100; - var r = Math.min(bounds.width * f, bounds.height * f); - canvas.roundrect(bounds.x, bounds.y, bounds.width, bounds.height, r, r); - } - else - { - canvas.rect(bounds.x, bounds.y, bounds.width, bounds.height); - } - - return true; - } - else - { - canvas.fillAndStroke(); - } - } - }; - - // Implements the swimlane shape - this.shapes['swimlane'] = - { - drawShape: function(canvas, state, bounds, background) - { - if (background) - { - if (mxUtils.getValue(state.style, mxConstants.STYLE_ROUNDED, false)) - { - var r = Math.min(bounds.width * mxConstants.RECTANGLE_ROUNDING_FACTOR, - bounds.height * mxConstants.RECTANGLE_ROUNDING_FACTOR); - canvas.roundrect(bounds.x, bounds.y, bounds.width, bounds.height, r, r); - } - else - { - canvas.rect(bounds.x, bounds.y, bounds.width, bounds.height); - } - - return true; - } - else - { - canvas.fillAndStroke(); - canvas.begin(); - - var x = state.x; - var y = state.y; - var w = state.width; - var h = state.height; - - if (mxUtils.getValue(state.style, mxConstants.STYLE_HORIZONTAL, 1) == 0) - { - x += bounds.width; - w -= bounds.width; - - canvas.moveTo(x, y); - canvas.lineTo(x + w, y); - canvas.lineTo(x + w, y + h); - canvas.lineTo(x, y + h); - } - else - { - y += bounds.height; - h -= bounds.height; - - canvas.moveTo(x, y); - canvas.lineTo(x, y + h); - canvas.lineTo(x + w, y + h); - canvas.lineTo(x + w, y); - } - - canvas.stroke(); - } - } - }; - - this.shapes['image'] = this.shapes['rectangle']; - this.shapes['label'] = this.shapes['rectangle']; - - var imageExport = this; - - this.shapes['connector'] = - { - translatePoint: function(points, index, offset) - { - if (offset != null) - { - var pt = points[index].clone(); - pt.x += offset.x; - pt.y += offset.y; - points[index] = pt; - } - }, - - drawShape: function(canvas, state, bounds, background, shadow) - { - if (background) - { - var rounded = mxUtils.getValue(state.style, mxConstants.STYLE_ROUNDED, false); - var arcSize = mxConstants.LINE_ARCSIZE / 2; - - // Does not draw the markers in the shadow to match the display - canvas.setFillColor((shadow) ? mxConstants.NONE : mxUtils.getValue(state.style, mxConstants.STYLE_STROKECOLOR, "#000000")); - canvas.setDashed(false); - var pts = state.absolutePoints.slice(); - this.translatePoint(pts, 0, imageExport.drawMarker(canvas, state, true)); - this.translatePoint(pts, pts.length - 1, imageExport.drawMarker(canvas, state, false)); - canvas.setDashed(mxUtils.getValue(state.style, mxConstants.STYLE_DASHED, '0') == '1'); - - var pt = pts[0]; - var pe = pts[pts.length - 1]; - canvas.begin(); - canvas.moveTo(pt.x, pt.y); - - // Draws the line segments - for (var i = 1; i < pts.length - 1; i++) - { - var tmp = pts[i]; - var dx = pt.x - tmp.x; - var dy = pt.y - tmp.y; - - if ((rounded && i < pts.length - 1) && (dx != 0 || dy != 0)) - { - // Draws a line from the last point to the current - // point with a spacing of size off the current point - // into direction of the last point - var dist = Math.sqrt(dx * dx + dy * dy); - var nx1 = dx * Math.min(arcSize, dist / 2) / dist; - var ny1 = dy * Math.min(arcSize, dist / 2) / dist; - - var x1 = tmp.x + nx1; - var y1 = tmp.y + ny1; - canvas.lineTo(x1, y1); - - // Draws a curve from the last point to the current - // point with a spacing of size off the current point - // into direction of the next point - var next = pts[i + 1]; - dx = next.x - tmp.x; - dy = next.y - tmp.y; - - dist = Math.max(1, Math.sqrt(dx * dx + dy * dy)); - var nx2 = dx * Math.min(arcSize, dist / 2) / dist; - var ny2 = dy * Math.min(arcSize, dist / 2) / dist; - - var x2 = tmp.x + nx2; - var y2 = tmp.y + ny2; - - canvas.curveTo(tmp.x, tmp.y, tmp.x, tmp.y, x2, y2); - tmp = new mxPoint(x2, y2); - } - else - { - canvas.lineTo(tmp.x, tmp.y); - } - - pt = tmp; - } - - canvas.lineTo(pe.x, pe.y); - canvas.stroke(); - - return true; - } - else - { - // no foreground - } - } - }; - - this.shapes['arrow'] = - { - drawShape: function(canvas, state, bounds, background) - { - if (background) - { - // Geometry of arrow - var spacing = mxConstants.ARROW_SPACING; - var width = mxConstants.ARROW_WIDTH; - var arrow = mxConstants.ARROW_SIZE; - - // Base vector (between end points) - var pts = state.absolutePoints; - var p0 = pts[0]; - var pe = pts[pts.length - 1]; - var dx = pe.x - p0.x; - var dy = pe.y - p0.y; - var dist = Math.sqrt(dx * dx + dy * dy); - var length = dist - 2 * spacing - arrow; - - // Computes the norm and the inverse norm - var nx = dx / dist; - var ny = dy / dist; - var basex = length * nx; - var basey = length * ny; - var floorx = width * ny/3; - var floory = -width * nx/3; - - // Computes points - var p0x = p0.x - floorx / 2 + spacing * nx; - var p0y = p0.y - floory / 2 + spacing * ny; - var p1x = p0x + floorx; - var p1y = p0y + floory; - var p2x = p1x + basex; - var p2y = p1y + basey; - var p3x = p2x + floorx; - var p3y = p2y + floory; - // p4 not necessary - var p5x = p3x - 3 * floorx; - var p5y = p3y - 3 * floory; - - canvas.begin(); - canvas.moveTo(p0x, p0y); - canvas.lineTo(p1x, p1y); - canvas.lineTo(p2x, p2y); - canvas.lineTo(p3x, p3y); - canvas.lineTo(pe.x - spacing * nx, pe.y - spacing * ny); - canvas.lineTo(p5x, p5y); - canvas.lineTo(p5x + floorx, p5y + floory); - canvas.close(); - - return true; - } - else - { - canvas.fillAndStroke(); - } - } - }; - - this.shapes['cylinder'] = - { - drawShape: function(canvas, state, bounds, background) - { - if (background) - { - return false; - } - else - { - var x = bounds.x; - var y = bounds.y; - var w = bounds.width; - var h = bounds.height; - var dy = Math.min(mxCylinder.prototype.maxHeight, Math.floor(h / 5)); - - canvas.begin(); - canvas.moveTo(x, y + dy); - canvas.curveTo(x, y - dy / 3, x + w, y - dy / 3, x + w, y + dy); - canvas.lineTo(x + w, y + h - dy); - canvas.curveTo(x + w, y + h + dy / 3, x, y + h + dy / 3, x, y + h - dy); - canvas.close(); - canvas.fillAndStroke(); - - canvas.begin(); - canvas.moveTo(x, y + dy); - canvas.curveTo(x, y + 2 * dy, x + w, y + 2 * dy, x + w, y + dy); - canvas.stroke(); - } - } - }; - - this.shapes['line'] = - { - drawShape: function(canvas, state, bounds, background) - { - if (background) - { - return false; - } - else - { - canvas.begin(); - - var mid = state.getCenterY(); - canvas.moveTo(bounds.x, mid); - canvas.lineTo(bounds.x + bounds.width, mid); - - canvas.stroke(); - } - } - }; - - this.shapes['ellipse'] = - { - drawShape: function(canvas, state, bounds, background) - { - if (background) - { - canvas.ellipse(bounds.x, bounds.y, bounds.width, bounds.height); - - return true; - } - else - { - canvas.fillAndStroke(); - } - } - }; - - this.shapes['doubleEllipse'] = - { - drawShape: function(canvas, state, bounds, background) - { - var x = bounds.x; - var y = bounds.y; - var w = bounds.width; - var h = bounds.height; - - if (background) - { - canvas.ellipse(x, y, w, h); - - return true; - } - else - { - canvas.fillAndStroke(); - - var inset = Math.min(4, Math.min(w / 5, h / 5)); - x += inset; - y += inset; - w -= 2 * inset; - h -= 2 * inset; - - if (w > 0 && h > 0) - { - canvas.ellipse(x, y, w, h); - } - - canvas.stroke(); - } - } - }; - - this.shapes['triangle'] = - { - drawShape: function(canvas, state, bounds, background) - { - if (background) - { - var x = bounds.x; - var y = bounds.y; - var w = bounds.width; - var h = bounds.height; - canvas.begin(); - canvas.moveTo(x, y); - canvas.lineTo(x + w, y + h / 2); - canvas.lineTo(x, y + h); - canvas.close(); - - return true; - } - else - { - canvas.fillAndStroke(); - } - } - }; - - this.shapes['rhombus'] = - { - drawShape: function(canvas, state, bounds, background) - { - if (background) - { - var x = bounds.x; - var y = bounds.y; - var w = bounds.width; - var h = bounds.height; - var hw = w / 2; - var hh = h / 2; - - canvas.begin(); - canvas.moveTo(x + hw, y); - canvas.lineTo(x + w, y + hh); - canvas.lineTo(x + hw, y + h); - canvas.lineTo(x, y + hh); - canvas.close(); - - return true; - } - else - { - canvas.fillAndStroke(); - } - } - - }; - - this.shapes['hexagon'] = - { - drawShape: function(canvas, state, bounds, background) - { - if (background) - { - var x = bounds.x; - var y = bounds.y; - var w = bounds.width; - var h = bounds.height; - - canvas.begin(); - canvas.moveTo(x + 0.25 * w, y); - canvas.lineTo(x + 0.75 * w, y); - canvas.lineTo(x + w, y + 0.5 * h); - canvas.lineTo(x + 0.75 * w, y + h); - canvas.lineTo(x + 0.25 * w, y + h); - canvas.lineTo(x, y + 0.5 * h); - canvas.close(); - - return true; - } - else - { - canvas.fillAndStroke(); - } - } - }; - - this.shapes['actor'] = - { - drawShape: function(canvas, state, bounds, background) - { - if (background) - { - var x = bounds.x; - var y = bounds.y; - var w = bounds.width; - var h = bounds.height; - var width = w * 2 / 6; - - canvas.begin(); - canvas.moveTo(x, y + h); - canvas.curveTo(x, y + 3 * h / 5, x, y + 2 * h / 5, x + w / 2, y + 2 * h - / 5); - canvas.curveTo(x + w / 2 - width, y + 2 * h / 5, x + w / 2 - width, y, x - + w / 2, y); - canvas.curveTo(x + w / 2 + width, y, x + w / 2 + width, y + 2 * h / 5, x - + w / 2, y + 2 * h / 5); - canvas.curveTo(x + w, y + 2 * h / 5, x + w, y + 3 * h / 5, x + w, y + h); - canvas.close(); - - return true; - } - else - { - canvas.fillAndStroke(); - } - } - }; - - this.shapes['cloud'] = - { - drawShape: function(canvas, state, bounds, background) - { - if (background) - { - var x = bounds.x; - var y = bounds.y; - var w = bounds.width; - var h = bounds.height; - - canvas.begin(); - canvas.moveTo(x + 0.25 * w, y + 0.25 * h); - canvas.curveTo(x + 0.05 * w, y + 0.25 * h, x, - y + 0.5 * h, x + 0.16 * w, y + 0.55 * h); - canvas.curveTo(x, y + 0.66 * h, x + 0.18 * w, - y + 0.9 * h, x + 0.31 * w, y + 0.8 * h); - canvas.curveTo(x + 0.4 * w, y + h, x + 0.7 * w, - y + h, x + 0.8 * w, y + 0.8 * h); - canvas.curveTo(x + w, y + 0.8 * h, x + w, - y + 0.6 * h, x + 0.875 * w, y + 0.5 * h); - canvas.curveTo(x + w, y + 0.3 * h, x + 0.8 * w, - y + 0.1 * h, x + 0.625 * w, y + 0.2 * h); - canvas.curveTo(x + 0.5 * w, y + 0.05 * h, - x + 0.3 * w, y + 0.05 * h, - x + 0.25 * w, y + 0.25 * h); - canvas.close(); - - return true; - } - else - { - canvas.fillAndStroke(); - } - } - }; - -}; - -/** - * Function: initMarkers - * - * Initializes the built-in markers. - */ -mxImageExport.prototype.initMarkers = function() -{ - this.markers = []; - - var tmp = function(canvas, state, type, pe, unitX, unitY, size, source, sw) - { - // The angle of the forward facing arrow sides against the x axis is - // 26.565 degrees, 1/sin(26.565) = 2.236 / 2 = 1.118 ( / 2 allows for - // only half the strokewidth is processed ). - var endOffsetX = unitX * sw * 1.118; - var endOffsetY = unitY * sw * 1.118; - - pe.x -= endOffsetX; - pe.y -= endOffsetY; - - unitX = unitX * (size + sw); - unitY = unitY * (size + sw); - - canvas.begin(); - canvas.moveTo(pe.x, pe.y); - canvas.lineTo(pe.x - unitX - unitY / 2, pe.y - unitY + unitX / 2); - - if (type == mxConstants.ARROW_CLASSIC) - { - canvas.lineTo(pe.x - unitX * 3 / 4, pe.y - unitY * 3 / 4); - } - - canvas.lineTo(pe.x + unitY / 2 - unitX, pe.y - unitY - unitX / 2); - canvas.close(); - - var key = (source) ? mxConstants.STYLE_STARTFILL : mxConstants.STYLE_ENDFILL; - - if (state.style[key] == 0) - { - canvas.stroke(); - } - else - { - canvas.fillAndStroke(); - } - - var f = (type != mxConstants.ARROW_CLASSIC) ? 1 : 3 / 4; - return new mxPoint(-unitX * f - endOffsetX, -unitY * f - endOffsetY); - }; - - this.markers['classic'] = tmp; - this.markers['block'] = tmp; - - this.markers['open'] = function(canvas, state, type, pe, unitX, unitY, size, source, sw) - { - // The angle of the forward facing arrow sides against the x axis is - // 26.565 degrees, 1/sin(26.565) = 2.236 / 2 = 1.118 ( / 2 allows for - // only half the strokewidth is processed ). - var endOffsetX = unitX * sw * 1.118; - var endOffsetY = unitY * sw * 1.118; - - pe.x -= endOffsetX; - pe.y -= endOffsetY; - - unitX = unitX * (size + sw); - unitY = unitY * (size + sw); - - canvas.begin(); - canvas.moveTo(pe.x - unitX - unitY / 2, pe.y - unitY + unitX / 2); - canvas.lineTo(pe.x, pe.y); - canvas.lineTo(pe.x + unitY / 2 - unitX, pe.y - unitY - unitX / 2); - canvas.stroke(); - - return new mxPoint(-endOffsetX * 2, -endOffsetY * 2); - }; - - this.markers['oval'] = function(canvas, state, type, pe, unitX, unitY, size, source, sw) - { - var a = size / 2; - - canvas.ellipse(pe.x - a, pe.y - a, size, size); - - var key = (source) ? mxConstants.STYLE_STARTFILL : mxConstants.STYLE_ENDFILL; - - if (state.style[key] == 0) - { - canvas.stroke(); - } - else - { - canvas.fillAndStroke(); - } - - return new mxPoint(-unitX / 2, -unitY / 2); - }; - - var tmp_diamond = function(canvas, state, type, pe, unitX, unitY, size, source, sw) - { - // The angle of the forward facing arrow sides against the x axis is - // 45 degrees, 1/sin(45) = 1.4142 / 2 = 0.7071 ( / 2 allows for - // only half the strokewidth is processed ). Or 0.9862 for thin diamond. - // Note these values and the tk variable below are dependent, update - // both together (saves trig hard coding it). - var swFactor = (type == mxConstants.ARROW_DIAMOND) ? 0.7071 : 0.9862; - var endOffsetX = unitX * sw * swFactor; - var endOffsetY = unitY * sw * swFactor; - - unitX = unitX * (size + sw); - unitY = unitY * (size + sw); - - pe.x -= endOffsetX; - pe.y -= endOffsetY; - - // thickness factor for diamond - var tk = ((type == mxConstants.ARROW_DIAMOND) ? 2 : 3.4); - - canvas.begin(); - canvas.moveTo(pe.x, pe.y); - canvas.lineTo(pe.x - unitX / 2 - unitY / tk, pe.y + unitX / tk - unitY / 2); - canvas.lineTo(pe.x - unitX, pe.y - unitY); - canvas.lineTo(pe.x - unitX / 2 + unitY / tk, pe.y - unitY / 2 - unitX / tk); - canvas.close(); - - var key = (source) ? mxConstants.STYLE_STARTFILL : mxConstants.STYLE_ENDFILL; - - if (state.style[key] == 0) - { - canvas.stroke(); - } - else - { - canvas.fillAndStroke(); - } - - return new mxPoint(-endOffsetX - unitX, -endOffsetY - unitY); - }; - - this.markers['diamond'] = tmp_diamond; - this.markers['diamondThin'] = tmp_diamond; -}; diff --git a/src/js/util/mxLog.js b/src/js/util/mxLog.js deleted file mode 100644 index c556e22..0000000 --- a/src/js/util/mxLog.js +++ /dev/null @@ -1,410 +0,0 @@ -/** - * $Id: mxLog.js,v 1.32 2012-11-12 09:40:59 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -var mxLog = -{ - /** - * Class: mxLog - * - * A singleton class that implements a simple console. - * - * Variable: consoleName - * - * Specifies the name of the console window. Default is 'Console'. - */ - consoleName: 'Console', - - /** - * Variable: TRACE - * - * Specified if the output for <enter> and <leave> should be visible in the - * console. Default is false. - */ - TRACE: false, - - /** - * Variable: DEBUG - * - * Specifies if the output for <debug> should be visible in the console. - * Default is true. - */ - DEBUG: true, - - /** - * Variable: WARN - * - * Specifies if the output for <warn> should be visible in the console. - * Default is true. - */ - WARN: true, - - /** - * Variable: buffer - * - * Buffer for pre-initialized content. - */ - buffer: '', - - /** - * Function: init - * - * Initializes the DOM node for the console. This requires document.body to - * point to a non-null value. This is called from within <setVisible> if the - * log has not yet been initialized. - */ - init: function() - { - if (mxLog.window == null && document.body != null) - { - var title = mxLog.consoleName + ' - mxGraph ' + mxClient.VERSION; - - // Creates a table that maintains the layout - var table = document.createElement('table'); - table.setAttribute('width', '100%'); - table.setAttribute('height', '100%'); - - var tbody = document.createElement('tbody'); - var tr = document.createElement('tr'); - var td = document.createElement('td'); - td.style.verticalAlign = 'top'; - - // Adds the actual console as a textarea - mxLog.textarea = document.createElement('textarea'); - mxLog.textarea.setAttribute('readOnly', 'true'); - mxLog.textarea.style.height = '100%'; - mxLog.textarea.style.resize = 'none'; - mxLog.textarea.value = mxLog.buffer; - - // Workaround for wrong width in standards mode - if (mxClient.IS_NS && document.compatMode != 'BackCompat') - { - mxLog.textarea.style.width = '99%'; - } - else - { - mxLog.textarea.style.width = '100%'; - } - - td.appendChild(mxLog.textarea); - tr.appendChild(td); - tbody.appendChild(tr); - - // Creates the container div - tr = document.createElement('tr'); - mxLog.td = document.createElement('td'); - mxLog.td.style.verticalAlign = 'top'; - mxLog.td.setAttribute('height', '30px'); - - tr.appendChild(mxLog.td); - tbody.appendChild(tr); - table.appendChild(tbody); - - // Adds various debugging buttons - mxLog.addButton('Info', function (evt) - { - mxLog.info(); - }); - - mxLog.addButton('DOM', function (evt) - { - var content = mxUtils.getInnerHtml(document.body); - mxLog.debug(content); - }); - - mxLog.addButton('Trace', function (evt) - { - mxLog.TRACE = !mxLog.TRACE; - - if (mxLog.TRACE) - { - mxLog.debug('Tracing enabled'); - } - else - { - mxLog.debug('Tracing disabled'); - } - }); - - mxLog.addButton('Copy', function (evt) - { - try - { - mxUtils.copy(mxLog.textarea.value); - } - catch (err) - { - mxUtils.alert(err); - } - }); - - mxLog.addButton('Show', function (evt) - { - try - { - mxUtils.popup(mxLog.textarea.value); - } - catch (err) - { - mxUtils.alert(err); - } - }); - - mxLog.addButton('Clear', function (evt) - { - mxLog.textarea.value = ''; - }); - - // Cross-browser code to get window size - var h = 0; - var w = 0; - - if (typeof(window.innerWidth) === 'number') - { - h = window.innerHeight; - w = window.innerWidth; - } - else - { - h = (document.documentElement.clientHeight || document.body.clientHeight); - w = document.body.clientWidth; - } - - mxLog.window = new mxWindow(title, table, Math.max(0, w-320), Math.max(0, h-210), 300, 160); - mxLog.window.setMaximizable(true); - mxLog.window.setScrollable(false); - mxLog.window.setResizable(true); - mxLog.window.setClosable(true); - mxLog.window.destroyOnClose = false; - - // Workaround for ignored textarea height in various setups - if ((mxClient.IS_NS || mxClient.IS_IE) && !mxClient.IS_GC && - !mxClient.IS_SF && document.compatMode != 'BackCompat') - { - var elt = mxLog.window.getElement(); - - var resizeHandler = function(sender, evt) - { - mxLog.textarea.style.height = Math.max(0, elt.offsetHeight - 70)+'px'; - }; - - mxLog.window.addListener(mxEvent.RESIZE_END, resizeHandler); - mxLog.window.addListener(mxEvent.MAXIMIZE, resizeHandler); - mxLog.window.addListener(mxEvent.NORMALIZE, resizeHandler); - - mxLog.textarea.style.height = '92px'; - } - } - }, - - /** - * Function: info - * - * Writes the current navigator information to the console. - */ - info: function() - { - mxLog.writeln(mxUtils.toString(navigator)); - }, - - /** - * Function: addButton - * - * Adds a button to the console using the given label and function. - */ - addButton: function(lab, funct) - { - var button = document.createElement('button'); - mxUtils.write(button, lab); - mxEvent.addListener(button, 'click', funct); - mxLog.td.appendChild(button); - }, - - /** - * Function: isVisible - * - * Returns true if the console is visible. - */ - isVisible: function() - { - if (mxLog.window != null) - { - return mxLog.window.isVisible(); - } - return false; - }, - - - /** - * Function: show - * - * Shows the console. - */ - show: function() - { - mxLog.setVisible(true); - }, - - /** - * Function: setVisible - * - * Shows or hides the console. - */ - setVisible: function(visible) - { - if (mxLog.window == null) - { - mxLog.init(); - } - - if (mxLog.window != null) - { - mxLog.window.setVisible(visible); - } - }, - - /** - * Function: enter - * - * Writes the specified string to the console - * if <TRACE> is true and returns the current - * time in milliseconds. - * - * Example: - * - * (code) - * mxLog.show(); - * var t0 = mxLog.enter('Hello'); - * // Do something - * mxLog.leave('World!', t0); - * (end) - */ - enter: function(string) - { - if (mxLog.TRACE) - { - mxLog.writeln('Entering '+string); - - return new Date().getTime(); - } - }, - - /** - * Function: leave - * - * Writes the specified string to the console - * if <TRACE> is true and computes the difference - * between the current time and t0 in milliseconds. - * See <enter> for an example. - */ - leave: function(string, t0) - { - if (mxLog.TRACE) - { - var dt = (t0 != 0) ? ' ('+(new Date().getTime() - t0)+' ms)' : ''; - mxLog.writeln('Leaving '+string+dt); - } - }, - - /** - * Function: debug - * - * Adds all arguments to the console if <DEBUG> is enabled. - * - * Example: - * - * (code) - * mxLog.show(); - * mxLog.debug('Hello, World!'); - * (end) - */ - debug: function() - { - if (mxLog.DEBUG) - { - mxLog.writeln.apply(this, arguments); - } - }, - - /** - * Function: warn - * - * Adds all arguments to the console if <WARN> is enabled. - * - * Example: - * - * (code) - * mxLog.show(); - * mxLog.warn('Hello, World!'); - * (end) - */ - warn: function() - { - if (mxLog.WARN) - { - mxLog.writeln.apply(this, arguments); - } - }, - - /** - * Function: write - * - * Adds the specified strings to the console. - */ - write: function() - { - var string = ''; - - for (var i = 0; i < arguments.length; i++) - { - string += arguments[i]; - - if (i < arguments.length - 1) - { - string += ' '; - } - } - - if (mxLog.textarea != null) - { - mxLog.textarea.value = mxLog.textarea.value + string; - - // Workaround for no update in Presto 2.5.22 (Opera 10.5) - if (navigator.userAgent.indexOf('Presto/2.5') >= 0) - { - mxLog.textarea.style.visibility = 'hidden'; - mxLog.textarea.style.visibility = 'visible'; - } - - mxLog.textarea.scrollTop = mxLog.textarea.scrollHeight; - } - else - { - mxLog.buffer += string; - } - }, - - /** - * Function: writeln - * - * Adds the specified strings to the console, appending a linefeed at the - * end of each string. - */ - writeln: function() - { - var string = ''; - - for (var i = 0; i < arguments.length; i++) - { - string += arguments[i]; - - if (i < arguments.length - 1) - { - string += ' '; - } - } - - mxLog.write(string + '\n'); - } - -}; diff --git a/src/js/util/mxMorphing.js b/src/js/util/mxMorphing.js deleted file mode 100644 index 442143d..0000000 --- a/src/js/util/mxMorphing.js +++ /dev/null @@ -1,239 +0,0 @@ -/** - * $Id: mxMorphing.js,v 1.4 2010-06-03 13:37:07 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -/** - * - * Class: mxMorphing - * - * Implements animation for morphing cells. Here is an example of - * using this class for animating the result of a layout algorithm: - * - * (code) - * graph.getModel().beginUpdate(); - * try - * { - * var circleLayout = new mxCircleLayout(graph); - * circleLayout.execute(graph.getDefaultParent()); - * } - * finally - * { - * var morph = new mxMorphing(graph); - * morph.addListener(mxEvent.DONE, function() - * { - * graph.getModel().endUpdate(); - * }); - * - * morph.startAnimation(); - * } - * (end) - * - * Constructor: mxMorphing - * - * Constructs an animation. - * - * Parameters: - * - * graph - Reference to the enclosing <mxGraph>. - * steps - Optional number of steps in the morphing animation. Default is 6. - * ease - Optional easing constant for the animation. Default is 1.5. - * delay - Optional delay between the animation steps. Passed to <mxAnimation>. - */ -function mxMorphing(graph, steps, ease, delay) -{ - mxAnimation.call(this, delay); - this.graph = graph; - this.steps = (steps != null) ? steps : 6; - this.ease = (ease != null) ? ease : 1.5; -}; - -/** - * Extends mxEventSource. - */ -mxMorphing.prototype = new mxAnimation(); -mxMorphing.prototype.constructor = mxMorphing; - -/** - * Variable: graph - * - * Specifies the delay between the animation steps. Defaul is 30ms. - */ -mxMorphing.prototype.graph = null; - -/** - * Variable: steps - * - * Specifies the maximum number of steps for the morphing. - */ -mxMorphing.prototype.steps = null; - -/** - * Variable: step - * - * Contains the current step. - */ -mxMorphing.prototype.step = 0; - -/** - * Variable: ease - * - * Ease-off for movement towards the given vector. Larger values are - * slower and smoother. Default is 4. - */ -mxMorphing.prototype.ease = null; - -/** - * Variable: cells - * - * Optional array of cells to be animated. If this is not specified - * then all cells are checked and animated if they have been moved - * in the current transaction. - */ -mxMorphing.prototype.cells = null; - -/** - * Function: updateAnimation - * - * Animation step. - */ -mxMorphing.prototype.updateAnimation = function() -{ - var move = new mxCellStatePreview(this.graph); - - if (this.cells != null) - { - // Animates the given cells individually without recursion - for (var i = 0; i < this.cells.length; i++) - { - this.animateCell(cells[i], move, false); - } - } - else - { - // Animates all changed cells by using recursion to find - // the changed cells but not for the animation itself - this.animateCell(this.graph.getModel().getRoot(), move, true); - } - - this.show(move); - - if (move.isEmpty() || - this.step++ >= this.steps) - { - this.stopAnimation(); - } -}; - -/** - * Function: show - * - * Shows the changes in the given <mxCellStatePreview>. - */ -mxMorphing.prototype.show = function(move) -{ - move.show(); -}; - -/** - * Function: animateCell - * - * Animates the given cell state using <mxCellStatePreview.moveState>. - */ -mxMorphing.prototype.animateCell = function(cell, move, recurse) -{ - var state = this.graph.getView().getState(cell); - var delta = null; - - if (state != null) - { - // Moves the animated state from where it will be after the model - // change by subtracting the given delta vector from that location - delta = this.getDelta(state); - - if (this.graph.getModel().isVertex(cell) && - (delta.x != 0 || delta.y != 0)) - { - var translate = this.graph.view.getTranslate(); - var scale = this.graph.view.getScale(); - - delta.x += translate.x * scale; - delta.y += translate.y * scale; - - move.moveState(state, -delta.x / this.ease, -delta.y / this.ease); - } - } - - if (recurse && !this.stopRecursion(state, delta)) - { - var childCount = this.graph.getModel().getChildCount(cell); - - for (var i = 0; i < childCount; i++) - { - this.animateCell(this.graph.getModel().getChildAt(cell, i), move, recurse); - } - } -}; - -/** - * Function: stopRecursion - * - * Returns true if the animation should not recursively find more - * deltas for children if the given parent state has been animated. - */ -mxMorphing.prototype.stopRecursion = function(state, delta) -{ - return delta != null && (delta.x != 0 || delta.y != 0); -}; - -/** - * Function: getDelta - * - * Returns the vector between the current rendered state and the future - * location of the state after the display will be updated. - */ -mxMorphing.prototype.getDelta = function(state) -{ - var origin = this.getOriginForCell(state.cell); - var translate = this.graph.getView().getTranslate(); - var scale = this.graph.getView().getScale(); - var current = new mxPoint( - state.x / scale - translate.x, - state.y / scale - translate.y); - - return new mxPoint( - (origin.x - current.x) * scale, - (origin.y - current.y) * scale); -}; - -/** - * Function: getOriginForCell - * - * Returns the top, left corner of the given cell. TODO: Improve performance - * by using caching inside this method as the result per cell never changes - * during the lifecycle of this object. - */ -mxMorphing.prototype.getOriginForCell = function(cell) -{ - var result = null; - - if (cell != null) - { - result = this.getOriginForCell(this.graph.getModel().getParent(cell)); - var geo = this.graph.getCellGeometry(cell); - - // TODO: Handle offset, relative geometries etc - if (geo != null) - { - result.x += geo.x; - result.y += geo.y; - } - } - - if (result == null) - { - var t = this.graph.view.getTranslate(); - result = new mxPoint(-t.x, -t.y); - } - - return result; -}; diff --git a/src/js/util/mxMouseEvent.js b/src/js/util/mxMouseEvent.js deleted file mode 100644 index e161d3a..0000000 --- a/src/js/util/mxMouseEvent.js +++ /dev/null @@ -1,241 +0,0 @@ -/** - * $Id: mxMouseEvent.js,v 1.20 2011-03-02 17:24:39 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -/** - * Class: mxMouseEvent - * - * Base class for all mouse events in mxGraph. A listener for this event should - * implement the following methods: - * - * (code) - * graph.addMouseListener( - * { - * mouseDown: function(sender, evt) - * { - * mxLog.debug('mouseDown'); - * }, - * mouseMove: function(sender, evt) - * { - * mxLog.debug('mouseMove'); - * }, - * mouseUp: function(sender, evt) - * { - * mxLog.debug('mouseUp'); - * } - * }); - * (end) - * - * Constructor: mxMouseEvent - * - * Constructs a new event object for the given arguments. - * - * Parameters: - * - * evt - Native mouse event. - * state - Optional <mxCellState> under the mouse. - * - */ -function mxMouseEvent(evt, state) -{ - this.evt = evt; - this.state = state; -}; - -/** - * Variable: consumed - * - * Holds the consumed state of this event. - */ -mxMouseEvent.prototype.consumed = false; - -/** - * Variable: evt - * - * Holds the inner event object. - */ -mxMouseEvent.prototype.evt = null; - -/** - * Variable: graphX - * - * Holds the x-coordinate of the event in the graph. This value is set in - * <mxGraph.fireMouseEvent>. - */ -mxMouseEvent.prototype.graphX = null; - -/** - * Variable: graphY - * - * Holds the y-coordinate of the event in the graph. This value is set in - * <mxGraph.fireMouseEvent>. - */ -mxMouseEvent.prototype.graphY = null; - -/** - * Variable: state - * - * Holds the optional <mxCellState> associated with this event. - */ -mxMouseEvent.prototype.state = null; - -/** - * Function: getEvent - * - * Returns <evt>. - */ -mxMouseEvent.prototype.getEvent = function() -{ - return this.evt; -}; - -/** - * Function: getSource - * - * Returns the target DOM element using <mxEvent.getSource> for <evt>. - */ -mxMouseEvent.prototype.getSource = function() -{ - return mxEvent.getSource(this.evt); -}; - -/** - * Function: isSource - * - * Returns true if the given <mxShape> is the source of <evt>. - */ -mxMouseEvent.prototype.isSource = function(shape) -{ - if (shape != null) - { - var source = this.getSource(); - - while (source != null) - { - if (source == shape.node) - { - return true; - } - - source = source.parentNode; - } - } - - return false; -}; - -/** - * Function: getX - * - * Returns <evt.clientX>. - */ -mxMouseEvent.prototype.getX = function() -{ - return mxEvent.getClientX(this.getEvent()); -}; - -/** - * Function: getY - * - * Returns <evt.clientY>. - */ -mxMouseEvent.prototype.getY = function() -{ - return mxEvent.getClientY(this.getEvent()); -}; - -/** - * Function: getGraphX - * - * Returns <graphX>. - */ -mxMouseEvent.prototype.getGraphX = function() -{ - return this.graphX; -}; - -/** - * Function: getGraphY - * - * Returns <graphY>. - */ -mxMouseEvent.prototype.getGraphY = function() -{ - return this.graphY; -}; - -/** - * Function: getState - * - * Returns <state>. - */ -mxMouseEvent.prototype.getState = function() -{ - return this.state; -}; - -/** - * Function: getCell - * - * Returns the <mxCell> in <state> is not null. - */ -mxMouseEvent.prototype.getCell = function() -{ - var state = this.getState(); - - if (state != null) - { - return state.cell; - } - - return null; -}; - -/** - * Function: isPopupTrigger - * - * Returns true if the event is a popup trigger. - */ -mxMouseEvent.prototype.isPopupTrigger = function() -{ - return mxEvent.isPopupTrigger(this.getEvent()); -}; - -/** - * Function: isConsumed - * - * Returns <consumed>. - */ -mxMouseEvent.prototype.isConsumed = function() -{ - return this.consumed; -}; - -/** - * Function: consume - * - * Sets <consumed> to true and invokes preventDefault on the native event - * if such a method is defined. This is used mainly to avoid the cursor from - * being changed to a text cursor in Webkit. You can use the preventDefault - * flag to disable this functionality. - * - * Parameters: - * - * preventDefault - Specifies if the native event should be canceled. Default - * is true. - */ -mxMouseEvent.prototype.consume = function(preventDefault) -{ - preventDefault = (preventDefault != null) ? preventDefault : true; - - if (preventDefault && this.evt.preventDefault) - { - this.evt.preventDefault(); - } - - // Workaround for images being dragged in IE - this.evt.returnValue = false; - - // Sets local consumed state - this.consumed = true; -}; diff --git a/src/js/util/mxObjectIdentity.js b/src/js/util/mxObjectIdentity.js deleted file mode 100644 index 778a4ea..0000000 --- a/src/js/util/mxObjectIdentity.js +++ /dev/null @@ -1,59 +0,0 @@ -/** - * $Id: mxObjectIdentity.js,v 1.8 2010-01-02 09:45:14 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -var mxObjectIdentity = -{ - /** - * Class: mxObjectIdentity - * - * Identity for JavaScript objects. This is implemented using a simple - * incremeting counter which is stored in each object under <ID_NAME>. - * - * The identity for an object does not change during its lifecycle. - * - * Variable: FIELD_NAME - * - * Name of the field to be used to store the object ID. Default is - * '_mxObjectId'. - */ - FIELD_NAME: 'mxObjectId', - - /** - * Variable: counter - * - * Current counter for objects. - */ - counter: 0, - - /** - * Function: get - * - * Returns the object id for the given object. - */ - get: function(obj) - { - if (typeof(obj) == 'object' && - obj[mxObjectIdentity.FIELD_NAME] == null) - { - var ctor = mxUtils.getFunctionName(obj.constructor); - obj[mxObjectIdentity.FIELD_NAME] = ctor+'#'+mxObjectIdentity.counter++; - } - - return obj[mxObjectIdentity.FIELD_NAME]; - }, - - /** - * Function: clear - * - * Removes the object id from the given object. - */ - clear: function(obj) - { - if (typeof(obj) == 'object') - { - delete obj[mxObjectIdentity.FIELD_NAME]; - } - } - -}; diff --git a/src/js/util/mxPanningManager.js b/src/js/util/mxPanningManager.js deleted file mode 100644 index 9f9f349..0000000 --- a/src/js/util/mxPanningManager.js +++ /dev/null @@ -1,262 +0,0 @@ -/** - * $Id: mxPanningManager.js,v 1.7 2012-06-13 06:46:37 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -/** - * Class: mxPanningManager - * - * Implements a handler for panning. - */ -function mxPanningManager(graph) -{ - this.thread = null; - this.active = false; - this.tdx = 0; - this.tdy = 0; - this.t0x = 0; - this.t0y = 0; - this.dx = 0; - this.dy = 0; - this.scrollbars = false; - this.scrollLeft = 0; - this.scrollTop = 0; - - this.mouseListener = - { - mouseDown: function(sender, me) { }, - mouseMove: function(sender, me) { }, - mouseUp: mxUtils.bind(this, function(sender, me) - { - if (this.active) - { - this.stop(); - } - }) - }; - - graph.addMouseListener(this.mouseListener); - - // Stops scrolling on every mouseup anywhere in the document - mxEvent.addListener(document, 'mouseup', mxUtils.bind(this, function() - { - if (this.active) - { - this.stop(); - } - })); - - var createThread = mxUtils.bind(this, function() - { - this.scrollbars = mxUtils.hasScrollbars(graph.container); - this.scrollLeft = graph.container.scrollLeft; - this.scrollTop = graph.container.scrollTop; - - return window.setInterval(mxUtils.bind(this, function() - { - this.tdx -= this.dx; - this.tdy -= this.dy; - - if (this.scrollbars) - { - var left = -graph.container.scrollLeft - Math.ceil(this.dx); - var top = -graph.container.scrollTop - Math.ceil(this.dy); - graph.panGraph(left, top); - graph.panDx = this.scrollLeft - graph.container.scrollLeft; - graph.panDy = this.scrollTop - graph.container.scrollTop; - graph.fireEvent(new mxEventObject(mxEvent.PAN)); - // TODO: Implement graph.autoExtend - } - else - { - graph.panGraph(this.getDx(), this.getDy()); - } - }), this.delay); - }); - - this.isActive = function() - { - return active; - }; - - this.getDx = function() - { - return Math.round(this.tdx); - }; - - this.getDy = function() - { - return Math.round(this.tdy); - }; - - this.start = function() - { - this.t0x = graph.view.translate.x; - this.t0y = graph.view.translate.y; - this.active = true; - }; - - this.panTo = function(x, y, w, h) - { - if (!this.active) - { - this.start(); - } - - this.scrollLeft = graph.container.scrollLeft; - this.scrollTop = graph.container.scrollTop; - - w = (w != null) ? w : 0; - h = (h != null) ? h : 0; - - var c = graph.container; - this.dx = x + w - c.scrollLeft - c.clientWidth; - - if (this.dx < 0 && Math.abs(this.dx) < this.border) - { - this.dx = this.border + this.dx; - } - else if (this.handleMouseOut) - { - this.dx = Math.max(this.dx, 0); - } - else - { - this.dx = 0; - } - - if (this.dx == 0) - { - this.dx = x - c.scrollLeft; - - if (this.dx > 0 && this.dx < this.border) - { - this.dx = this.dx - this.border; - } - else if (this.handleMouseOut) - { - this.dx = Math.min(0, this.dx); - } - else - { - this.dx = 0; - } - } - - this.dy = y + h - c.scrollTop - c.clientHeight; - - if (this.dy < 0 && Math.abs(this.dy) < this.border) - { - this.dy = this.border + this.dy; - } - else if (this.handleMouseOut) - { - this.dy = Math.max(this.dy, 0); - } - else - { - this.dy = 0; - } - - if (this.dy == 0) - { - this.dy = y - c.scrollTop; - - if (this.dy > 0 && this.dy < this.border) - { - this.dy = this.dy - this.border; - } - else if (this.handleMouseOut) - { - this.dy = Math.min(0, this.dy); - } - else - { - this.dy = 0; - } - } - - if (this.dx != 0 || this.dy != 0) - { - this.dx *= this.damper; - this.dy *= this.damper; - - if (this.thread == null) - { - this.thread = createThread(); - } - } - else if (this.thread != null) - { - window.clearInterval(this.thread); - this.thread = null; - } - }; - - this.stop = function() - { - if (this.active) - { - this.active = false; - - if (this.thread != null) - { - window.clearInterval(this.thread); - this.thread = null; - } - - this.tdx = 0; - this.tdy = 0; - - if (!this.scrollbars) - { - var px = graph.panDx; - var py = graph.panDy; - - if (px != 0 || py != 0) - { - graph.panGraph(0, 0); - graph.view.setTranslate(this.t0x + px / graph.view.scale, this.t0y + py / graph.view.scale); - } - } - else - { - graph.panDx = 0; - graph.panDy = 0; - graph.fireEvent(new mxEventObject(mxEvent.PAN)); - } - } - }; - - this.destroy = function() - { - graph.removeMouseListener(this.mouseListener); - }; -}; - -/** - * Variable: damper - * - * Damper value for the panning. Default is 1/6. - */ -mxPanningManager.prototype.damper = 1/6; - -/** - * Variable: delay - * - * Delay in milliseconds for the panning. Default is 10. - */ -mxPanningManager.prototype.delay = 10; - -/** - * Variable: handleMouseOut - * - * Specifies if mouse events outside of the component should be handled. Default is true. - */ -mxPanningManager.prototype.handleMouseOut = true; - -/** - * Variable: border - * - * Border to handle automatic panning inside the component. Default is 0 (disabled). - */ -mxPanningManager.prototype.border = 0; diff --git a/src/js/util/mxPath.js b/src/js/util/mxPath.js deleted file mode 100644 index 57efe74..0000000 --- a/src/js/util/mxPath.js +++ /dev/null @@ -1,314 +0,0 @@ -/** - * $Id: mxPath.js,v 1.24 2012-06-13 17:31:32 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -/** - * Class: mxPath - * - * An abstraction for creating VML and SVG paths. See <mxActor> for using this - * object inside an <mxShape> for painting cells. - * - * Constructor: mxPath - * - * Constructs a path for the given format, which is one of svg or vml. - * - * Parameters: - * - * format - String specifying the <format>. May be one of vml or svg - * (default). - */ -function mxPath(format) -{ - this.format = format; - this.path = []; - this.translate = new mxPoint(0, 0); -}; - -/** - * Variable: format - * - * Defines the format for the output of this path. Possible values are - * svg and vml. - */ -mxPath.prototype.format = null; - -/** - * Variable: translate - * - * <mxPoint> that specifies the translation of the complete path. - */ -mxPath.prototype.translate = null; - -/** - * Variable: scale - * - * Number that specifies the translation of the path. - */ -mxPath.prototype.scale = 1; - -/** - * Variable: path - * - * Contains the textual representation of the path as an array. - */ -mxPath.prototype.path = null; - -/** - * Function: isVml - * - * Returns true if <format> is vml. - */ -mxPath.prototype.isVml = function() -{ - return this.format == 'vml'; -}; - -/** - * Function: getPath - * - * Returns string that represents the path in <format>. - */ -mxPath.prototype.getPath = function() -{ - return this.path.join(''); -}; - -/** - * Function: setTranslate - * - * Set the global translation of this path, that is, the origin of the - * coordinate system. - * - * Parameters: - * - * x - X-coordinate of the new origin. - * y - Y-coordinate of the new origin. - */ -mxPath.prototype.setTranslate = function(x, y) -{ - this.translate = new mxPoint(x, y); -}; - -/** - * Function: moveTo - * - * Moves the cursor to (x, y). - * - * Parameters: - * - * x - X-coordinate of the new cursor location. - * y - Y-coordinate of the new cursor location. - */ -mxPath.prototype.moveTo = function(x, y) -{ - x += this.translate.x; - y += this.translate.y; - - x *= this.scale; - y *= this.scale; - - if (this.isVml()) - { - this.path.push('m ', Math.round(x), ' ', Math.round(y), ' '); - } - else - { - this.path.push('M ', x, ' ', y, ' '); - } -}; - -/** - * Function: lineTo - * - * Draws a straight line from the current poin to (x, y). - * - * Parameters: - * - * x - X-coordinate of the endpoint. - * y - Y-coordinate of the endpoint. - */ -mxPath.prototype.lineTo = function(x, y) -{ - x += this.translate.x; - y += this.translate.y; - - x *= this.scale; - y *= this.scale; - - if (this.isVml()) - { - this.path.push('l ', Math.round(x), ' ', Math.round(y), ' '); - } - else - { - this.path.push('L ', x, ' ', y, ' '); - } -}; - -/** - * Function: quadTo - * - * Draws a quadratic Bézier curve from the current point to (x, y) using - * (x1, y1) as the control point. - * - * Parameters: - * - * x1 - X-coordinate of the control point. - * y1 - Y-coordinate of the control point. - * x - X-coordinate of the endpoint. - * y - Y-coordinate of the endpoint. - */ -mxPath.prototype.quadTo = function(x1, y1, x, y) -{ - x1 += this.translate.x; - y1 += this.translate.y; - - x1 *= this.scale; - y1 *= this.scale; - - x += this.translate.x; - y += this.translate.y; - - x *= this.scale; - y *= this.scale; - - if (this.isVml()) - { - this.path.push('c ', Math.round(x1), ' ', Math.round(y1), ' ', Math.round(x), ' ', - Math.round(y), ' ', Math.round(x), ' ', Math.round(y), ' '); - } - else - { - this.path.push('Q ', x1, ' ', y1, ' ', x, ' ', y, ' '); - } -}; - -/** - * Function: curveTo - * - * Draws a cubic Bézier curve from the current point to (x, y) using - * (x1, y1) as the control point at the beginning of the curve and (x2, y2) - * as the control point at the end of the curve. - * - * Parameters: - * - * x1 - X-coordinate of the first control point. - * y1 - Y-coordinate of the first control point. - * x2 - X-coordinate of the second control point. - * y2 - Y-coordinate of the second control point. - * x - X-coordinate of the endpoint. - * y - Y-coordinate of the endpoint. - */ -mxPath.prototype.curveTo = function(x1, y1, x2, y2, x, y) -{ - x1 += this.translate.x; - y1 += this.translate.y; - - x1 *= this.scale; - y1 *= this.scale; - - x2 += this.translate.x; - y2 += this.translate.y; - - x2 *= this.scale; - y2 *= this.scale; - - x += this.translate.x; - y += this.translate.y; - - x *= this.scale; - y *= this.scale; - - if (this.isVml()) - { - this.path.push('c ', Math.round(x1), ' ', Math.round(y1), ' ', Math.round(x2), - ' ', Math.round(y2), ' ', Math.round(x), ' ', Math.round(y), ' '); - } - else - { - this.path.push('C ', x1, ' ', y1, ' ', x2, - ' ', y2, ' ', x, ' ', y, ' '); - } -}; - -/** - * Function: ellipse - * - * Adds the given ellipse. Some implementations may require the path to be - * closed after this operation. - */ -mxPath.prototype.ellipse = function(x, y, w, h) -{ - x += this.translate.x; - y += this.translate.y; - x *= this.scale; - y *= this.scale; - - if (this.isVml()) - { - this.path.push('at ', Math.round(x), ' ', Math.round(y), ' ', Math.round(x + w), ' ', Math.round(y + h), ' ', - Math.round(x), ' ', Math.round(y + h / 2), ' ', Math.round(x), ' ', Math.round(y + h / 2)); - } - else - { - var startX = x; - var startY = y + h/2; - var endX = x + w; - var endY = y + h/2; - var r1 = w/2; - var r2 = h/2; - this.path.push('M ', startX, ' ', startY, ' '); - this.path.push('A ', r1, ' ', r2, ' 0 1 0 ', endX, ' ', endY, ' '); - this.path.push('A ', r1, ' ', r2, ' 0 1 0 ', startX, ' ', startY); - } -}; - -/** - * Function: addPath - * - * Adds the given path. - */ -mxPath.prototype.addPath = function(path) -{ - this.path = this.path.concat(path.path); -}; - -/** - * Function: write - * - * Writes directly into the path. This bypasses all conversions. - */ -mxPath.prototype.write = function(string) -{ - this.path.push(string, ' '); -}; - -/** - * Function: end - * - * Ends the path. - */ -mxPath.prototype.end = function() -{ - if (this.format == 'vml') - { - this.path.push('e'); - } -}; - -/** - * Function: close - * - * Closes the path. - */ -mxPath.prototype.close = function() -{ - if (this.format == 'vml') - { - this.path.push('x e'); - } - else - { - this.path.push('Z'); - } -}; diff --git a/src/js/util/mxPoint.js b/src/js/util/mxPoint.js deleted file mode 100644 index e029a29..0000000 --- a/src/js/util/mxPoint.js +++ /dev/null @@ -1,55 +0,0 @@ -/** - * $Id: mxPoint.js,v 1.12 2010-01-02 09:45:14 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -/** - * Class: mxPoint - * - * Implements a 2-dimensional vector with double precision coordinates. - * - * Constructor: mxPoint - * - * Constructs a new point for the optional x and y coordinates. If no - * coordinates are given, then the default values for <x> and <y> are used. - */ -function mxPoint(x, y) -{ - this.x = (x != null) ? x : 0; - this.y = (y != null) ? y : 0; -}; - -/** - * Variable: x - * - * Holds the x-coordinate of the point. Default is 0. - */ -mxPoint.prototype.x = null; - -/** - * Variable: y - * - * Holds the y-coordinate of the point. Default is 0. - */ -mxPoint.prototype.y = null; - -/** - * Function: equals - * - * Returns true if the given object equals this rectangle. - */ -mxPoint.prototype.equals = function(obj) -{ - return obj.x == this.x && - obj.y == this.y; -}; - -/** - * Function: clone - * - * Returns a clone of this <mxPoint>. - */ -mxPoint.prototype.clone = function() -{ - // Handles subclasses as well - return mxUtils.clone(this); -}; diff --git a/src/js/util/mxPopupMenu.js b/src/js/util/mxPopupMenu.js deleted file mode 100644 index b188cb6..0000000 --- a/src/js/util/mxPopupMenu.js +++ /dev/null @@ -1,574 +0,0 @@ -/** - * $Id: mxPopupMenu.js,v 1.37 2012-04-22 10:16:23 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -/** - * Class: mxPopupMenu - * - * Event handler that pans and creates popupmenus. To use the left - * mousebutton for panning without interfering with cell moving and - * resizing, use <isUseLeftButton> and <isIgnoreCell>. For grid size - * steps while panning, use <useGrid>. This handler is built-into - * <mxGraph.panningHandler> and enabled using <mxGraph.setPanning>. - * - * Constructor: mxPopupMenu - * - * Constructs an event handler that creates a popupmenu. The - * event handler is not installed anywhere in this ctor. - * - * Event: mxEvent.SHOW - * - * Fires after the menu has been shown in <popup>. - */ -function mxPopupMenu(factoryMethod) -{ - this.factoryMethod = factoryMethod; - - if (factoryMethod != null) - { - this.init(); - } -}; - -/** - * Extends mxEventSource. - */ -mxPopupMenu.prototype = new mxEventSource(); -mxPopupMenu.prototype.constructor = mxPopupMenu; - -/** - * Variable: submenuImage - * - * URL of the image to be used for the submenu icon. - */ -mxPopupMenu.prototype.submenuImage = mxClient.imageBasePath + '/submenu.gif'; - -/** - * Variable: zIndex - * - * Specifies the zIndex for the popupmenu and its shadow. Default is 1006. - */ -mxPopupMenu.prototype.zIndex = 10006; - -/** - * Variable: factoryMethod - * - * Function that is used to create the popup menu. The function takes the - * current panning handler, the <mxCell> under the mouse and the mouse - * event that triggered the call as arguments. - */ -mxPopupMenu.prototype.factoryMethod = null; - -/** - * Variable: useLeftButtonForPopup - * - * Specifies if popupmenus should be activated by clicking the left mouse - * button. Default is false. - */ -mxPopupMenu.prototype.useLeftButtonForPopup = false; - -/** - * Variable: enabled - * - * Specifies if events are handled. Default is true. - */ -mxPopupMenu.prototype.enabled = true; - -/** - * Variable: itemCount - * - * Contains the number of times <addItem> has been called for a new menu. - */ -mxPopupMenu.prototype.itemCount = 0; - -/** - * Variable: autoExpand - * - * Specifies if submenus should be expanded on mouseover. Default is false. - */ -mxPopupMenu.prototype.autoExpand = false; - -/** - * Variable: smartSeparators - * - * Specifies if separators should only be added if a menu item follows them. - * Default is false. - */ -mxPopupMenu.prototype.smartSeparators = false; - -/** - * Variable: labels - * - * Specifies if any labels should be visible. Default is true. - */ -mxPopupMenu.prototype.labels = true; - -/** - * Function: init - * - * Initializes the shapes required for this vertex handler. - */ -mxPopupMenu.prototype.init = function() -{ - // Adds the inner table - this.table = document.createElement('table'); - this.table.className = 'mxPopupMenu'; - - this.tbody = document.createElement('tbody'); - this.table.appendChild(this.tbody); - - // Adds the outer div - this.div = document.createElement('div'); - this.div.className = 'mxPopupMenu'; - this.div.style.display = 'inline'; - this.div.style.zIndex = this.zIndex; - this.div.appendChild(this.table); - - // Disables the context menu on the outer div - mxEvent.disableContextMenu(this.div); -}; - -/** - * Function: isEnabled - * - * Returns true if events are handled. This implementation - * returns <enabled>. - */ -mxPopupMenu.prototype.isEnabled = function() -{ - return this.enabled; -}; - -/** - * Function: setEnabled - * - * Enables or disables event handling. This implementation - * updates <enabled>. - */ -mxPopupMenu.prototype.setEnabled = function(enabled) -{ - this.enabled = enabled; -}; - -/** - * Function: isPopupTrigger - * - * Returns true if the given event is a popupmenu trigger for the optional - * given cell. - * - * Parameters: - * - * me - <mxMouseEvent> that represents the mouse event. - */ -mxPopupMenu.prototype.isPopupTrigger = function(me) -{ - return me.isPopupTrigger() || (this.useLeftButtonForPopup && - mxEvent.isLeftMouseButton(me.getEvent())); -}; - -/** - * Function: addItem - * - * Adds the given item to the given parent item. If no parent item is specified - * then the item is added to the top-level menu. The return value may be used - * as the parent argument, ie. as a submenu item. The return value is the table - * row that represents the item. - * - * Paramters: - * - * title - String that represents the title of the menu item. - * image - Optional URL for the image icon. - * funct - Function associated that takes a mouseup or touchend event. - * parent - Optional item returned by <addItem>. - * iconCls - Optional string that represents the CSS class for the image icon. - * IconsCls is ignored if image is given. - * enabled - Optional boolean indicating if the item is enabled. Default is true. - */ -mxPopupMenu.prototype.addItem = function(title, image, funct, parent, iconCls, enabled) -{ - parent = parent || this; - this.itemCount++; - - // Smart separators only added if element contains items - if (parent.willAddSeparator) - { - if (parent.containsItems) - { - this.addSeparator(parent, true); - } - - parent.willAddSeparator = false; - } - - parent.containsItems = true; - var tr = document.createElement('tr'); - tr.className = 'mxPopupMenuItem'; - var col1 = document.createElement('td'); - col1.className = 'mxPopupMenuIcon'; - - // Adds the given image into the first column - if (image != null) - { - var img = document.createElement('img'); - img.src = image; - col1.appendChild(img); - } - else if (iconCls != null) - { - var div = document.createElement('div'); - div.className = iconCls; - col1.appendChild(div); - } - - tr.appendChild(col1); - - if (this.labels) - { - var col2 = document.createElement('td'); - col2.className = 'mxPopupMenuItem' + - ((enabled != null && !enabled) ? ' disabled' : ''); - mxUtils.write(col2, title); - col2.align = 'left'; - tr.appendChild(col2); - - var col3 = document.createElement('td'); - col3.className = 'mxPopupMenuItem' + - ((enabled != null && !enabled) ? ' disabled' : ''); - col3.style.paddingRight = '6px'; - col3.style.textAlign = 'right'; - - tr.appendChild(col3); - - if (parent.div == null) - { - this.createSubmenu(parent); - } - } - - parent.tbody.appendChild(tr); - - if (enabled == null || enabled) - { - var md = (mxClient.IS_TOUCH) ? 'touchstart' : 'mousedown'; - var mm = (mxClient.IS_TOUCH) ? 'touchmove' : 'mousemove'; - var mu = (mxClient.IS_TOUCH) ? 'touchend' : 'mouseup'; - - // Consumes the event on mouse down - mxEvent.addListener(tr, md, mxUtils.bind(this, function(evt) - { - this.eventReceiver = tr; - - if (parent.activeRow != tr && parent.activeRow != parent) - { - if (parent.activeRow != null && - parent.activeRow.div.parentNode != null) - { - this.hideSubmenu(parent); - } - - if (tr.div != null) - { - this.showSubmenu(parent, tr); - parent.activeRow = tr; - } - } - - mxEvent.consume(evt); - })); - - mxEvent.addListener(tr, mm, mxUtils.bind(this, function(evt) - { - if (parent.activeRow != tr && parent.activeRow != parent) - { - if (parent.activeRow != null && - parent.activeRow.div.parentNode != null) - { - this.hideSubmenu(parent); - } - - if (this.autoExpand && tr.div != null) - { - this.showSubmenu(parent, tr); - parent.activeRow = tr; - } - } - - // Sets hover style because TR in IE doesn't have hover - tr.className = 'mxPopupMenuItemHover'; - })); - - mxEvent.addListener(tr, mu, mxUtils.bind(this, function(evt) - { - // EventReceiver avoids clicks on a submenu item - // which has just been shown in the mousedown - if (this.eventReceiver == tr) - { - if (parent.activeRow != tr) - { - this.hideMenu(); - } - - if (funct != null) - { - funct(evt); - } - } - - this.eventReceiver = null; - mxEvent.consume(evt); - })); - - // Resets hover style because TR in IE doesn't have hover - mxEvent.addListener(tr, 'mouseout', - mxUtils.bind(this, function(evt) - { - tr.className = 'mxPopupMenuItem'; - }) - ); - } - - return tr; -}; - -/** - * Function: createSubmenu - * - * Creates the nodes required to add submenu items inside the given parent - * item. This is called in <addItem> if a parent item is used for the first - * time. This adds various DOM nodes and a <submenuImage> to the parent. - * - * Parameters: - * - * parent - An item returned by <addItem>. - */ -mxPopupMenu.prototype.createSubmenu = function(parent) -{ - parent.table = document.createElement('table'); - parent.table.className = 'mxPopupMenu'; - - parent.tbody = document.createElement('tbody'); - parent.table.appendChild(parent.tbody); - - parent.div = document.createElement('div'); - parent.div.className = 'mxPopupMenu'; - - parent.div.style.position = 'absolute'; - parent.div.style.display = 'inline'; - parent.div.style.zIndex = this.zIndex; - - parent.div.appendChild(parent.table); - - var img = document.createElement('img'); - img.setAttribute('src', this.submenuImage); - - // Last column of the submenu item in the parent menu - td = parent.firstChild.nextSibling.nextSibling; - td.appendChild(img); -}; - -/** - * Function: showSubmenu - * - * Shows the submenu inside the given parent row. - */ -mxPopupMenu.prototype.showSubmenu = function(parent, row) -{ - if (row.div != null) - { - row.div.style.left = (parent.div.offsetLeft + - row.offsetLeft+row.offsetWidth - 1) + 'px'; - row.div.style.top = (parent.div.offsetTop+row.offsetTop) + 'px'; - document.body.appendChild(row.div); - - // Moves the submenu to the left side if there is no space - var left = parseInt(row.div.offsetLeft); - var width = parseInt(row.div.offsetWidth); - - var b = document.body; - var d = document.documentElement; - - var right = (b.scrollLeft || d.scrollLeft) + (b.clientWidth || d.clientWidth); - - if (left + width > right) - { - row.div.style.left = (parent.div.offsetLeft - width + - ((mxClient.IS_IE) ? 6 : -6)) + 'px'; - } - - mxUtils.fit(row.div); - } -}; - -/** - * Function: addSeparator - * - * Adds a horizontal separator in the given parent item or the top-level menu - * if no parent is specified. - * - * Parameters: - * - * parent - Optional item returned by <addItem>. - * force - Optional boolean to ignore <smartSeparators>. Default is false. - */ -mxPopupMenu.prototype.addSeparator = function(parent, force) -{ - parent = parent || this; - - if (this.smartSeparators && !force) - { - parent.willAddSeparator = true; - } - else if (parent.tbody != null) - { - parent.willAddSeparator = false; - var tr = document.createElement('tr'); - - var col1 = document.createElement('td'); - col1.className = 'mxPopupMenuIcon'; - col1.style.padding = '0 0 0 0px'; - - tr.appendChild(col1); - - var col2 = document.createElement('td'); - col2.style.padding = '0 0 0 0px'; - col2.setAttribute('colSpan', '2'); - - var hr = document.createElement('hr'); - hr.setAttribute('size', '1'); - col2.appendChild(hr); - - tr.appendChild(col2); - - parent.tbody.appendChild(tr); - } -}; - -/** - * Function: popup - * - * Shows the popup menu for the given event and cell. - * - * Example: - * - * (code) - * graph.panningHandler.popup = function(x, y, cell, evt) - * { - * mxUtils.alert('Hello, World!'); - * } - * (end) - */ -mxPopupMenu.prototype.popup = function(x, y, cell, evt) -{ - if (this.div != null && this.tbody != null && this.factoryMethod != null) - { - this.div.style.left = x + 'px'; - this.div.style.top = y + 'px'; - - // Removes all child nodes from the existing menu - while (this.tbody.firstChild != null) - { - mxEvent.release(this.tbody.firstChild); - this.tbody.removeChild(this.tbody.firstChild); - } - - this.itemCount = 0; - this.factoryMethod(this, cell, evt); - - if (this.itemCount > 0) - { - this.showMenu(); - this.fireEvent(new mxEventObject(mxEvent.SHOW)); - } - } -}; - -/** - * Function: isMenuShowing - * - * Returns true if the menu is showing. - */ -mxPopupMenu.prototype.isMenuShowing = function() -{ - return this.div != null && this.div.parentNode == document.body; -}; - -/** - * Function: showMenu - * - * Shows the menu. - */ -mxPopupMenu.prototype.showMenu = function() -{ - // Disables filter-based shadow in IE9 standards mode - if (document.documentMode >= 9) - { - this.div.style.filter = 'none'; - } - - // Fits the div inside the viewport - document.body.appendChild(this.div); - mxUtils.fit(this.div); -}; - -/** - * Function: hideMenu - * - * Removes the menu and all submenus. - */ -mxPopupMenu.prototype.hideMenu = function() -{ - if (this.div != null) - { - if (this.div.parentNode != null) - { - this.div.parentNode.removeChild(this.div); - } - - this.hideSubmenu(this); - this.containsItems = false; - } -}; - -/** - * Function: hideSubmenu - * - * Removes all submenus inside the given parent. - * - * Parameters: - * - * parent - An item returned by <addItem>. - */ -mxPopupMenu.prototype.hideSubmenu = function(parent) -{ - if (parent.activeRow != null) - { - this.hideSubmenu(parent.activeRow); - - if (parent.activeRow.div.parentNode != null) - { - parent.activeRow.div.parentNode.removeChild(parent.activeRow.div); - } - - parent.activeRow = null; - } -}; - -/** - * Function: destroy - * - * Destroys the handler and all its resources and DOM nodes. - */ -mxPopupMenu.prototype.destroy = function() -{ - if (this.div != null) - { - mxEvent.release(this.div); - - if (this.div.parentNode != null) - { - this.div.parentNode.removeChild(this.div); - } - - this.div = null; - } -}; diff --git a/src/js/util/mxRectangle.js b/src/js/util/mxRectangle.js deleted file mode 100644 index 035abf5..0000000 --- a/src/js/util/mxRectangle.js +++ /dev/null @@ -1,134 +0,0 @@ -/** - * $Id: mxRectangle.js,v 1.17 2010-12-08 12:46:03 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -/** - * Class: mxRectangle - * - * Extends <mxPoint> to implement a 2-dimensional rectangle with double - * precision coordinates. - * - * Constructor: mxRectangle - * - * Constructs a new rectangle for the optional parameters. If no parameters - * are given then the respective default values are used. - */ -function mxRectangle(x, y, width, height) -{ - mxPoint.call(this, x, y); - - this.width = (width != null) ? width : 0; - this.height = (height != null) ? height : 0; -}; - -/** - * Extends mxPoint. - */ -mxRectangle.prototype = new mxPoint(); -mxRectangle.prototype.constructor = mxRectangle; - -/** - * Variable: width - * - * Holds the width of the rectangle. Default is 0. - */ -mxRectangle.prototype.width = null; - -/** - * Variable: height - * - * Holds the height of the rectangle. Default is 0. - */ -mxRectangle.prototype.height = null; - -/** - * Function: setRect - * - * Sets this rectangle to the specified values - */ -mxRectangle.prototype.setRect = function(x, y, w, h) -{ - this.x = x; - this.y = y; - this.width = w; - this.height = h; -}; - -/** - * Function: getCenterX - * - * Returns the x-coordinate of the center point. - */ -mxRectangle.prototype.getCenterX = function () -{ - return this.x + this.width/2; -}; - -/** - * Function: getCenterY - * - * Returns the y-coordinate of the center point. - */ -mxRectangle.prototype.getCenterY = function () -{ - return this.y + this.height/2; -}; - -/** - * Function: add - * - * Adds the given rectangle to this rectangle. - */ -mxRectangle.prototype.add = function(rect) -{ - if (rect != null) - { - var minX = Math.min(this.x, rect.x); - var minY = Math.min(this.y, rect.y); - var maxX = Math.max(this.x + this.width, rect.x + rect.width); - var maxY = Math.max(this.y + this.height, rect.y + rect.height); - - this.x = minX; - this.y = minY; - this.width = maxX - minX; - this.height = maxY - minY; - } -}; - -/** - * Function: grow - * - * Grows the rectangle by the given amount, that is, this method subtracts - * the given amount from the x- and y-coordinates and adds twice the amount - * to the width and height. - */ -mxRectangle.prototype.grow = function(amount) -{ - this.x -= amount; - this.y -= amount; - this.width += 2 * amount; - this.height += 2 * amount; -}; - -/** - * Function: getPoint - * - * Returns the top, left corner as a new <mxPoint>. - */ -mxRectangle.prototype.getPoint = function() -{ - return new mxPoint(this.x, this.y); -}; - -/** - * Function: equals - * - * Returns true if the given object equals this rectangle. - */ -mxRectangle.prototype.equals = function(obj) -{ - return obj.x == this.x && - obj.y == this.y && - obj.width == this.width && - obj.height == this.height; -}; diff --git a/src/js/util/mxResources.js b/src/js/util/mxResources.js deleted file mode 100644 index 0969ebe..0000000 --- a/src/js/util/mxResources.js +++ /dev/null @@ -1,366 +0,0 @@ -/** - * $Id: mxResources.js,v 1.32 2012-10-26 13:36:50 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -var mxResources = -{ - /** - * Class: mxResources - * - * Implements internationalization. You can provide any number of - * resource files on the server using the following format for the - * filename: name[-en].properties. The en stands for any lowercase - * 2-character language shortcut (eg. de for german, fr for french). - * - * If the optional language extension is omitted, then the file is used as a - * default resource which is loaded in all cases. If a properties file for a - * specific language exists, then it is used to override the settings in the - * default resource. All entries in the file are of the form key=value. The - * values may then be accessed in code via <get>. Lines without - * equal signs in the properties files are ignored. - * - * Resource files may either be added programmatically using - * <add> or via a resource tag in the UI section of the - * editor configuration file, eg: - * - * (code) - * <mxEditor> - * <ui> - * <resource basename="examples/resources/mxWorkflow"/> - * (end) - * - * The above element will load examples/resources/mxWorkflow.properties as well - * as the language specific file for the current language, if it exists. - * - * Values may contain placeholders of the form {1}...{n} where each placeholder - * is replaced with the value of the corresponding array element in the params - * argument passed to <mxResources.get>. The placeholder {1} maps to the first - * element in the array (at index 0). - * - * See <mxClient.language> for more information on specifying the default - * language or disabling all loading of resources. - * - * Lines that start with a # sign will be ignored. - * - * Special characters - * - * To use unicode characters, use the standard notation (eg. \u8fd1) or %u as a - * prefix (eg. %u20AC will display a Euro sign). For normal hex encoded strings, - * use % as a prefix, eg. %F6 will display a � (ö). - * - * See <resourcesEncoded> to disable this. If you disable this, make sure that - * your files are UTF-8 encoded. - * - * Variable: resources - * - * Associative array that maps from keys to values. - */ - resources: [], - - /** - * Variable: extension - * - * Specifies the extension used for language files. Default is '.properties'. - */ - extension: '.properties', - - /** - * Variable: resourcesEncoded - * - * Specifies whether or not values in resource files are encoded with \u or - * percentage. Default is true. - */ - resourcesEncoded: true, - - /** - * Variable: loadDefaultBundle - * - * Specifies if the default file for a given basename should be loaded. - * Default is true. - */ - loadDefaultBundle: true, - - /** - * Variable: loadDefaultBundle - * - * Specifies if the specific language file file for a given basename should - * be loaded. Default is true. - */ - loadSpecialBundle: true, - - /** - * Function: isBundleSupported - * - * Hook for subclassers to disable support for a given language. This - * implementation always returns true. - * - * Parameters: - * - * basename - The basename for which the file should be loaded. - * lan - The current language. - */ - isLanguageSupported: function(lan) - { - if (mxClient.languages != null) - { - return mxUtils.indexOf(mxClient.languages, lan) >= 0; - } - - return true; - }, - - /** - * Function: getDefaultBundle - * - * Hook for subclassers to return the URL for the special bundle. This - * implementation returns basename + <extension> or null if - * <loadDefaultBundle> is false. - * - * Parameters: - * - * basename - The basename for which the file should be loaded. - * lan - The current language. - */ - getDefaultBundle: function(basename, lan) - { - if (mxResources.loadDefaultBundle || !mxResources.isLanguageSupported(lan)) - { - return basename + mxResources.extension; - } - else - { - return null; - } - }, - - /** - * Function: getSpecialBundle - * - * Hook for subclassers to return the URL for the special bundle. This - * implementation returns basename + '_' + lan + <extension> or null if - * <loadSpecialBundle> is false or lan equals <mxClient.defaultLanguage>. - * - * If <mxResources.languages> is not null and <mxClient.language> contains - * a dash, then this method checks if <isLanguageSupported> returns true - * for the full language (including the dash). If that returns false the - * first part of the language (up to the dash) will be tried as an extension. - * - * If <mxResources.language> is null then the first part of the language is - * used to maintain backwards compatibility. - * - * Parameters: - * - * basename - The basename for which the file should be loaded. - * lan - The language for which the file should be loaded. - */ - getSpecialBundle: function(basename, lan) - { - if (mxClient.languages == null || !this.isLanguageSupported(lan)) - { - var dash = lan.indexOf('-'); - - if (dash > 0) - { - lan = lan.substring(0, dash); - } - } - - if (mxResources.loadSpecialBundle && mxResources.isLanguageSupported(lan) && lan != mxClient.defaultLanguage) - { - return basename + '_' + lan + mxResources.extension; - } - else - { - return null; - } - }, - - /** - * Function: add - * - * Adds the default and current language properties - * file for the specified basename. Existing keys - * are overridden as new files are added. - * - * Example: - * - * At application startup, additional resources may be - * added using the following code: - * - * (code) - * mxResources.add('resources/editor'); - * (end) - */ - add: function(basename, lan) - { - lan = (lan != null) ? lan : mxClient.language.toLowerCase(); - - if (lan != mxConstants.NONE) - { - // Loads the common language file (no extension) - var defaultBundle = mxResources.getDefaultBundle(basename, lan); - - if (defaultBundle != null) - { - try - { - var req = mxUtils.load(defaultBundle); - - if (req.isReady()) - { - mxResources.parse(req.getText()); - } - } - catch (e) - { - // ignore - } - } - - // Overlays the language specific file (_lan-extension) - var specialBundle = mxResources.getSpecialBundle(basename, lan); - - if (specialBundle != null) - { - try - { - var req = mxUtils.load(specialBundle); - - if (req.isReady()) - { - mxResources.parse(req.getText()); - } - } - catch (e) - { - // ignore - } - } - } - }, - - /** - * Function: parse - * - * Parses the key, value pairs in the specified - * text and stores them as local resources. - */ - parse: function(text) - { - if (text != null) - { - var lines = text.split('\n'); - - for (var i = 0; i < lines.length; i++) - { - if (lines[i].charAt(0) != '#') - { - var index = lines[i].indexOf('='); - - if (index > 0) - { - var key = lines[i].substring(0, index); - var idx = lines[i].length; - - if (lines[i].charCodeAt(idx - 1) == 13) - { - idx--; - } - - var value = lines[i].substring(index + 1, idx); - - if (this.resourcesEncoded) - { - value = value.replace(/\\(?=u[a-fA-F\d]{4})/g,"%"); - mxResources.resources[key] = unescape(value); - } - else - { - mxResources.resources[key] = value; - } - } - } - } - } - }, - - /** - * Function: get - * - * Returns the value for the specified resource key. - * - * Example: - * To read the value for 'welomeMessage', use the following: - * (code) - * var result = mxResources.get('welcomeMessage') || ''; - * (end) - * - * This would require an entry of the following form in - * one of the English language resource files: - * (code) - * welcomeMessage=Welcome to mxGraph! - * (end) - * - * The part behind the || is the string value to be used if the given - * resource is not available. - * - * Parameters: - * - * key - String that represents the key of the resource to be returned. - * params - Array of the values for the placeholders of the form {1}...{n} - * to be replaced with in the resulting string. - * defaultValue - Optional string that specifies the default return value. - */ - get: function(key, params, defaultValue) - { - var value = mxResources.resources[key]; - - // Applies the default value if no resource was found - if (value == null) - { - value = defaultValue; - } - - // Replaces the placeholders with the values in the array - if (value != null && - params != null) - { - var result = []; - var index = null; - - for (var i = 0; i < value.length; i++) - { - var c = value.charAt(i); - - if (c == '{') - { - index = ''; - } - else if (index != null && c == '}') - { - index = parseInt(index)-1; - - if (index >= 0 && index < params.length) - { - result.push(params[index]); - } - - index = null; - } - else if (index != null) - { - index += c; - } - else - { - result.push(c); - } - } - - value = result.join(''); - } - - return value; - } - -}; diff --git a/src/js/util/mxSession.js b/src/js/util/mxSession.js deleted file mode 100644 index 4c2a70c..0000000 --- a/src/js/util/mxSession.js +++ /dev/null @@ -1,674 +0,0 @@ -/** - * $Id: mxSession.js,v 1.46 2012-08-22 15:30:49 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -/** - * Class: mxSession - * - * Session for sharing an <mxGraphModel> with other parties - * via a backend that acts as a multicaster for all changes. - * - * Diagram Sharing: - * - * The diagram sharing is a mechanism where each atomic change of the model is - * encoded into XML using <mxCodec> and then transmitted to the server by the - * <mxSession> object. On the server, the XML data is dispatched to each - * listener on the same diagram (except the sender), and the XML is decoded - * back into atomic changes on the client side, which are then executed on the - * model and stored in the command history. - * - * The <mxSession.significantRemoteChanges> specifies how these changes are - * treated with respect to undo: The default value (true) will undo the last - * change regardless of whether it was a remote or a local change. If the - * switch is false, then an undo will go back until the last local change, - * silently undoing all remote changes up to that point. Note that these - * changes will be added as new remote changes to the history of the other - * clients. - * - * Event: mxEvent.CONNECT - * - * Fires after the session has been started, that is, after the response to the - * initial request was received and the session goes into polling mode. This - * event has no properties. - * - * Event: mxEvent.SUSPEND - * - * Fires after <suspend> was called an the session was not already in suspended - * state. This event has no properties. - * - * Event: mxEvent.RESUME - * - * Fires after the session was resumed in <resume>. This event has no - * properties. - * - * Event: mxEvent.DISCONNECT - * - * Fires after the session was stopped in <stop>. The <code>reason</code> - * property contains the optional exception that was passed to the stop method. - * - * Event: mxEvent.NOTIFY - * - * Fires after a notification was sent in <notify>. The <code>url</code> - * property contains the URL and the <code>xml</code> property contains the XML - * data of the request. - * - * Event: mxEvent.GET - * - * Fires after a response was received in <get>. The <code>url</code> property - * contains the URL and the <code>request</code> is the <mxXmlRequest> that - * contains the response. - * - * Event: mxEvent.FIRED - * - * Fires after an array of edits has been executed on the model. The - * <code>changes</code> property contains the array of changes. - * - * Event: mxEvent.RECEIVE - * - * Fires after an XML node was received in <receive>. The <code>node</code> - * property contains the node that was received. - * - * Constructor: mxSession - * - * Constructs a new session using the given <mxGraphModel> and URLs to - * communicate with the backend. - * - * Parameters: - * - * model - <mxGraphModel> that contains the data. - * urlInit - URL to be used for initializing the session. - * urlPoll - URL to be used for polling the backend. - * urlNotify - URL to be used for sending changes to the backend. - */ -function mxSession(model, urlInit, urlPoll, urlNotify) -{ - this.model = model; - this.urlInit = urlInit; - this.urlPoll = urlPoll; - this.urlNotify = urlNotify; - - // Resolves cells by id using the model - if (model != null) - { - this.codec = new mxCodec(); - - this.codec.lookup = function(id) - { - return model.getCell(id); - }; - } - - // Adds the listener for notifying the backend of any - // changes in the model - model.addListener(mxEvent.NOTIFY, mxUtils.bind(this, function(sender, evt) - { - var edit = evt.getProperty('edit'); - - if (edit != null && this.debug || (this.connected && !this.suspended)) - { - this.notify('<edit>'+this.encodeChanges(edit.changes, edit.undone)+'</edit>'); - } - })); -}; - -/** - * Extends mxEventSource. - */ -mxSession.prototype = new mxEventSource(); -mxSession.prototype.constructor = mxSession; - -/** - * Variable: model - * - * Reference to the enclosing <mxGraphModel>. - */ -mxSession.prototype.model = null; - -/** - * Variable: urlInit - * - * URL to initialize the session. - */ -mxSession.prototype.urlInit = null; - -/** - * Variable: urlPoll - * - * URL for polling the backend. - */ -mxSession.prototype.urlPoll = null; - -/** - * Variable: urlNotify - * - * URL to send changes to the backend. - */ -mxSession.prototype.urlNotify = null; - -/** - * Variable: codec - * - * Reference to the <mxCodec> used to encoding and decoding changes. - */ -mxSession.prototype.codec = null; - -/** - * Variable: linefeed - * - * Used for encoding linefeeds. Default is '
'. - */ -mxSession.prototype.linefeed = '
'; - -/** - * Variable: escapePostData - * - * Specifies if the data in the post request sent in <notify> - * should be converted using encodeURIComponent. Default is true. - */ -mxSession.prototype.escapePostData = true; - -/** - * Variable: significantRemoteChanges - * - * Whether remote changes should be significant in the - * local command history. Default is true. - */ -mxSession.prototype.significantRemoteChanges = true; - -/** - * Variable: sent - * - * Total number of sent bytes. - */ -mxSession.prototype.sent = 0; - -/** - * Variable: received - * - * Total number of received bytes. - */ -mxSession.prototype.received = 0; - -/** - * Variable: debug - * - * Specifies if the session should run in debug mode. In this mode, no - * connection is established. The data is written to the console instead. - * Default is false. - */ -mxSession.prototype.debug = false; - -/** - * Variable: connected - */ -mxSession.prototype.connected = false; - -/** - * Variable: send - */ -mxSession.prototype.suspended = false; - -/** - * Variable: polling - */ -mxSession.prototype.polling = false; - -/** - * Function: start - */ -mxSession.prototype.start = function() -{ - if (this.debug) - { - this.connected = true; - this.fireEvent(new mxEventObject(mxEvent.CONNECT)); - } - else if (!this.connected) - { - this.get(this.urlInit, mxUtils.bind(this, function(req) - { - this.connected = true; - this.fireEvent(new mxEventObject(mxEvent.CONNECT)); - this.poll(); - })); - } -}; - -/** - * Function: suspend - * - * Suspends the polling. Use <resume> to reactive the session. Fires a - * suspend event. - */ -mxSession.prototype.suspend = function() -{ - if (this.connected && !this.suspended) - { - this.suspended = true; - this.fireEvent(new mxEventObject(mxEvent.SUSPEND)); - } -}; - -/** - * Function: resume - * - * Resumes the session if it has been suspended. Fires a resume-event - * before starting the polling. - */ -mxSession.prototype.resume = function(type, attr, value) -{ - if (this.connected && - this.suspended) - { - this.suspended = false; - this.fireEvent(new mxEventObject(mxEvent.RESUME)); - - if (!this.polling) - { - this.poll(); - } - } -}; - -/** - * Function: stop - * - * Stops the session and fires a disconnect event. The given reason is - * passed to the disconnect event listener as the second argument. - */ -mxSession.prototype.stop = function(reason) -{ - if (this.connected) - { - this.connected = false; - } - - this.fireEvent(new mxEventObject(mxEvent.DISCONNECT, - 'reason', reason)); -}; - -/** - * Function: poll - * - * Sends an asynchronous GET request to <urlPoll>. - */ -mxSession.prototype.poll = function() -{ - if (this.connected && - !this.suspended && - this.urlPoll != null) - { - this.polling = true; - - this.get(this.urlPoll, mxUtils.bind(this, function() - { - this.poll(); - })); - } - else - { - this.polling = false; - } -}; - -/** - * Function: notify - * - * Sends out the specified XML to <urlNotify> and fires a <notify> event. - */ -mxSession.prototype.notify = function(xml, onLoad, onError) -{ - if (xml != null && - xml.length > 0) - { - if (this.urlNotify != null) - { - if (this.debug) - { - mxLog.show(); - mxLog.debug('mxSession.notify: '+this.urlNotify+' xml='+xml); - } - else - { - xml = '<message><delta>'+xml+'</delta></message>'; - - if (this.escapePostData) - { - xml = encodeURIComponent(xml); - } - - mxUtils.post(this.urlNotify, 'xml='+xml, onLoad, onError); - } - } - - this.sent += xml.length; - this.fireEvent(new mxEventObject(mxEvent.NOTIFY, - 'url', this.urlNotify, 'xml', xml)); - } -}; - -/** - * Function: get - * - * Sends an asynchronous get request to the given URL, fires a <get> event - * and invokes the given onLoad function when a response is received. - */ -mxSession.prototype.get = function(url, onLoad, onError) -{ - // Response after browser refresh has no global scope - // defined. This response is ignored and the session - // stops implicitely. - if (typeof(mxUtils) != 'undefined') - { - var onErrorWrapper = mxUtils.bind(this, function(ex) - { - if (onError != null) - { - onError(ex); - } - else - { - this.stop(ex); - } - }); - - // Handles a successful response for - // the above request. - mxUtils.get(url, mxUtils.bind(this, function(req) - { - if (typeof(mxUtils) != 'undefined') - { - if (req.isReady() && req.getStatus() != 404) - { - this.received += req.getText().length; - this.fireEvent(new mxEventObject(mxEvent.GET, 'url', url, 'request', req)); - - if (this.isValidResponse(req)) - { - if (req.getText().length > 0) - { - var node = req.getDocumentElement(); - - if (node == null) - { - onErrorWrapper('Invalid response: '+req.getText()); - } - else - { - this.receive(node); - } - } - - if (onLoad != null) - { - onLoad(req); - } - } - } - else - { - onErrorWrapper('Response not ready'); - } - } - }), - // Handles a transmission error for the - // above request - function(req) - { - onErrorWrapper('Transmission error'); - }); - } -}; - -/** - * Function: isValidResponse - * - * Returns true if the response data in the given <mxXmlRequest> is valid. - */ -mxSession.prototype.isValidResponse = function(req) -{ - // TODO: Find condition to check if response - // contains valid XML (not eg. the PHP code). - return req.getText().indexOf('<?php') < 0; -}; - -/** - * Function: encodeChanges - * - * Returns the XML representation for the given array of changes. - */ -mxSession.prototype.encodeChanges = function(changes, invert) -{ - // TODO: Use array for string concatenation - var xml = ''; - var step = (invert) ? -1 : 1; - var i0 = (invert) ? changes.length - 1 : 0; - - for (var i = i0; i >= 0 && i < changes.length; i += step) - { - // Newlines must be kept, they will be converted - // to 
 when the server sends data to the - // client - var node = this.codec.encode(changes[i]); - xml += mxUtils.getXml(node, this.linefeed); - } - - return xml; -}; - -/** - * Function: receive - * - * Processes the given node by applying the changes to the model. If the nodename - * is state, then the namespace is used as a prefix for creating Ids in the model, - * and the child nodes are visited recursively. If the nodename is delta, then the - * changes encoded in the child nodes are applied to the model. Each call to the - * receive function fires a <receive> event with the given node as the second argument - * after processing. If changes are processed, then the function additionally fires - * a <mxEvent.FIRED> event before the <mxEvent.RECEIVE> event. - */ -mxSession.prototype.receive = function(node) -{ - if (node != null && node.nodeType == mxConstants.NODETYPE_ELEMENT) - { - // Uses the namespace in the model - var ns = node.getAttribute('namespace'); - - if (ns != null) - { - this.model.prefix = ns + '-'; - } - - var child = node.firstChild; - - while (child != null) - { - var name = child.nodeName.toLowerCase(); - - if (name == 'state') - { - this.processState(child); - } - else if (name == 'delta') - { - this.processDelta(child); - } - - child = child.nextSibling; - } - - // Fires receive event - this.fireEvent(new mxEventObject(mxEvent.RECEIVE, 'node', node)); - } -}; - -/** - * Function: processState - * - * Processes the given state node which contains the current state of the - * remote model. - */ -mxSession.prototype.processState = function(node) -{ - var dec = new mxCodec(node.ownerDocument); - dec.decode(node.firstChild, this.model); -}; - -/** - * Function: processDelta - * - * Processes the given delta node which contains a sequence of edits which in - * turn map to one transaction on the remote model each. - */ -mxSession.prototype.processDelta = function(node) -{ - var edit = node.firstChild; - - while (edit != null) - { - if (edit.nodeName == 'edit') - { - this.processEdit(edit); - } - - edit = edit.nextSibling; - } -}; - -/** - * Function: processEdit - * - * Processes the given edit by executing its changes and firing the required - * events via the model. - */ -mxSession.prototype.processEdit = function(node) -{ - var changes = this.decodeChanges(node); - - if (changes.length > 0) - { - var edit = this.createUndoableEdit(changes); - - // No notify event here to avoid the edit from being encoded and transmitted - // LATER: Remove changes property (deprecated) - this.model.fireEvent(new mxEventObject(mxEvent.CHANGE, - 'edit', edit, 'changes', changes)); - this.model.fireEvent(new mxEventObject(mxEvent.UNDO, 'edit', edit)); - this.fireEvent(new mxEventObject(mxEvent.FIRED, 'edit', edit)); - } -}; - -/** - * Function: createUndoableEdit - * - * Creates a new <mxUndoableEdit> that implements the notify function to fire a - * <change> and <notify> event via the model. - */ -mxSession.prototype.createUndoableEdit = function(changes) -{ - var edit = new mxUndoableEdit(this.model, this.significantRemoteChanges); - edit.changes = changes; - - edit.notify = function() - { - // LATER: Remove changes property (deprecated) - edit.source.fireEvent(new mxEventObject(mxEvent.CHANGE, - 'edit', edit, 'changes', edit.changes)); - edit.source.fireEvent(new mxEventObject(mxEvent.NOTIFY, - 'edit', edit, 'changes', edit.changes)); - }; - - return edit; -}; - -/** - * Function: decodeChanges - * - * Decodes and executes the changes represented by the children in the - * given node. Returns an array that contains all changes. - */ -mxSession.prototype.decodeChanges = function(node) -{ - // Updates the document in the existing codec - this.codec.document = node.ownerDocument; - - // Parses and executes the changes on the model - var changes = []; - node = node.firstChild; - - while (node != null) - { - var change = this.decodeChange(node); - - if (change != null) - { - changes.push(change); - } - - node = node.nextSibling; - } - - return changes; -}; - -/** - * Function: decodeChange - * - * Decodes, executes and returns the change object represented by the given - * XML node. - */ -mxSession.prototype.decodeChange = function(node) -{ - var change = null; - - if (node.nodeType == mxConstants.NODETYPE_ELEMENT) - { - if (node.nodeName == 'mxRootChange') - { - // Handles the special case were no ids should be - // resolved in the existing model. This change will - // replace all registered ids and cells from the - // model and insert a new cell hierarchy instead. - var tmp = new mxCodec(node.ownerDocument); - change = tmp.decode(node); - } - else - { - change = this.codec.decode(node); - } - - if (change != null) - { - change.model = this.model; - change.execute(); - - // Workaround for references not being resolved if cells have - // been removed from the model prior to being referenced. This - // adds removed cells in the codec object lookup table. - if (node.nodeName == 'mxChildChange' && change.parent == null) - { - this.cellRemoved(change.child); - } - } - } - - return change; -}; - -/** - * Function: cellRemoved - * - * Adds removed cells to the codec object lookup for references to the removed - * cells after this point in time. - */ -mxSession.prototype.cellRemoved = function(cell, codec) -{ - this.codec.putObject(cell.getId(), cell); - - var childCount = this.model.getChildCount(cell); - - for (var i = 0; i < childCount; i++) - { - this.cellRemoved(this.model.getChildAt(cell, i)); - } -}; diff --git a/src/js/util/mxSvgCanvas2D.js b/src/js/util/mxSvgCanvas2D.js deleted file mode 100644 index 4af0642..0000000 --- a/src/js/util/mxSvgCanvas2D.js +++ /dev/null @@ -1,1234 +0,0 @@ -/** - * $Id: mxSvgCanvas2D.js,v 1.18 2012-11-23 15:13:19 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -/** - * - * Class: mxSvgCanvas2D - * - * Implements a canvas to be used with <mxImageExport>. This canvas writes all - * calls as SVG output to the given SVG root node. - * - * (code) - * var svgDoc = mxUtils.createXmlDocument(); - * var root = (svgDoc.createElementNS != null) ? - * svgDoc.createElementNS(mxConstants.NS_SVG, 'svg') : svgDoc.createElement('svg'); - * - * if (svgDoc.createElementNS == null) - * { - * root.setAttribute('xmlns', mxConstants.NS_SVG); - * } - * - * var bounds = graph.getGraphBounds(); - * root.setAttribute('width', (bounds.x + bounds.width + 4) + 'px'); - * root.setAttribute('height', (bounds.y + bounds.height + 4) + 'px'); - * root.setAttribute('version', '1.1'); - * - * svgDoc.appendChild(root); - * - * var svgCanvas = new mxSvgCanvas2D(root); - * (end) - * - * Constructor: mxSvgCanvas2D - * - * Constructs an SVG canvas. - * - * Parameters: - * - * root - SVG container for the output. - * styleEnabled - Optional boolean that specifies if a style section should be - * added. The style section sets the default font-size, font-family and - * stroke-miterlimit globally. Default is false. - */ -var mxSvgCanvas2D = function(root, styleEnabled) -{ - styleEnabled = (styleEnabled != null) ? styleEnabled : false; - - /** - * Variable: converter - * - * Holds the <mxUrlConverter> to convert image URLs. - */ - var converter = new mxUrlConverter(); - - /** - * Variable: autoAntiAlias - * - * Specifies if anti aliasing should be disabled for rectangles - * and orthogonal paths. Default is true. - */ - var autoAntiAlias = true; - - /** - * Variable: textEnabled - * - * Specifies if text output should be enabled. Default is true. - */ - var textEnabled = true; - - /** - * Variable: foEnabled - * - * Specifies if use of foreignObject for HTML markup is allowed. Default is true. - */ - var foEnabled = true; - - // Private helper function to create SVG elements - var create = function(tagName, namespace) - { - var doc = root.ownerDocument || document; - - if (doc.createElementNS != null) - { - return doc.createElementNS(namespace || mxConstants.NS_SVG, tagName); - } - else - { - var elt = doc.createElement(tagName); - - if (namespace != null) - { - elt.setAttribute('xmlns', namespace); - } - - return elt; - } - }; - - // Defs section contains optional style and gradients - var defs = create('defs'); - - // Creates defs section with optional global style - if (styleEnabled) - { - var style = create('style'); - style.setAttribute('type', 'text/css'); - mxUtils.write(style, 'svg{font-family:' + mxConstants.DEFAULT_FONTFAMILY + - ';font-size:' + mxConstants.DEFAULT_FONTSIZE + - ';fill:none;stroke-miterlimit:10}'); - - if (autoAntiAlias) - { - mxUtils.write(style, 'rect{shape-rendering:crispEdges}'); - } - - // Appends style to defs and defs to SVG container - defs.appendChild(style); - } - - root.appendChild(defs); - - // Defines the current state - var currentState = - { - dx: 0, - dy: 0, - scale: 1, - transform: '', - fill: null, - gradient: null, - stroke: null, - strokeWidth: 1, - dashed: false, - dashpattern: '3 3', - alpha: 1, - linecap: 'flat', - linejoin: 'miter', - miterlimit: 10, - fontColor: '#000000', - fontSize: mxConstants.DEFAULT_FONTSIZE, - fontFamily: mxConstants.DEFAULT_FONTFAMILY, - fontStyle: 0 - }; - - // Local variables - var currentPathIsOrthogonal = true; - var glassGradient = null; - var currentNode = null; - var currentPath = null; - var lastPoint = null; - var gradients = []; - var refCount = 0; - var stack = []; - - // Other private helper methods - var createGradientId = function(start, end, direction) - { - // Removes illegal characters from gradient ID - if (start.charAt(0) == '#') - { - start = start.substring(1); - } - - if (end.charAt(0) == '#') - { - end = end.substring(1); - } - - // Workaround for gradient IDs not working in Safari 5 / Chrome 6 - // if they contain uppercase characters - start = start.toLowerCase(); - end = end.toLowerCase(); - - // Wrong gradient directions possible? - var dir = null; - - if (direction == null || direction == mxConstants.DIRECTION_SOUTH) - { - dir = 's'; - } - else if (direction == mxConstants.DIRECTION_EAST) - { - dir = 'e'; - } - else - { - var tmp = start; - start = end; - end = tmp; - - if (direction == mxConstants.DIRECTION_NORTH) - { - dir = 's'; - } - else if (direction == mxConstants.DIRECTION_WEST) - { - dir = 'e'; - } - } - - return start+'-'+end+'-'+dir; - }; - - var createHtmlBody = function(str, align, valign) - { - var style = 'margin:0px;font-size:' + Math.floor(currentState.fontSize) + 'px;' + - 'font-family:' + currentState.fontFamily + ';color:' + currentState.fontColor+ ';'; - - if ((currentState.fontStyle & mxConstants.FONT_BOLD) == mxConstants.FONT_BOLD) - { - style += 'font-weight:bold;'; - } - - if ((currentState.fontStyle & mxConstants.FONT_ITALIC) == mxConstants.FONT_ITALIC) - { - style += 'font-style:italic;'; - } - - if ((currentState.fontStyle & mxConstants.FONT_UNDERLINE) == mxConstants.FONT_UNDERLINE) - { - style += 'font-decoration:underline;'; - } - - if (align == mxConstants.ALIGN_CENTER) - { - style += 'text-align:center;'; - } - else if (align == mxConstants.ALIGN_RIGHT) - { - style += 'text-align:right;'; - } - - // Converts HTML entities to unicode - var t = document.createElement('div'); - t.innerHTML = str; - str = t.innerHTML.replace(/ /g, ' '); - - // LATER: Add vertical align support via table, adds xmlns to workaround empty NS in IE9 standards - var node = mxUtils.parseXml('<div xmlns="http://www.w3.org/1999/xhtml" style="' + - style + '">' + str + '</div>').documentElement; - - return node; - }; - - var getSvgGradient = function(start, end, direction) - { - var id = createGradientId(start, end, direction); - var gradient = gradients[id]; - - if (gradient == null) - { - gradient = create('linearGradient'); - gradient.setAttribute('id', ++refCount); - gradient.setAttribute('x1', '0%'); - gradient.setAttribute('y1', '0%'); - gradient.setAttribute('x2', '0%'); - gradient.setAttribute('y2', '0%'); - - if (direction == null || direction == mxConstants.DIRECTION_SOUTH) - { - gradient.setAttribute('y2', '100%'); - } - else if (direction == mxConstants.DIRECTION_EAST) - { - gradient.setAttribute('x2', '100%'); - } - else if (direction == mxConstants.DIRECTION_NORTH) - { - gradient.setAttribute('y1', '100%'); - } - else if (direction == mxConstants.DIRECTION_WEST) - { - gradient.setAttribute('x1', '100%'); - } - - var stop = create('stop'); - stop.setAttribute('offset', '0%'); - stop.setAttribute('style', 'stop-color:'+start); - gradient.appendChild(stop); - - stop = create('stop'); - stop.setAttribute('offset', '100%'); - stop.setAttribute('style', 'stop-color:'+end); - gradient.appendChild(stop); - - defs.appendChild(gradient); - gradients[id] = gradient; - } - - return gradient.getAttribute('id'); - }; - - var appendNode = function(node, state, filled, stroked) - { - if (node != null) - { - if (state.clip != null) - { - node.setAttribute('clip-path', 'url(#' + state.clip + ')'); - state.clip = null; - } - - if (currentPath != null) - { - node.setAttribute('d', currentPath.join(' ')); - currentPath = null; - - if (autoAntiAlias && currentPathIsOrthogonal) - { - node.setAttribute('shape-rendering', 'crispEdges'); - state.strokeWidth = Math.max(1, state.strokeWidth); - } - } - - if (state.alpha < 1) - { - // LATER: Check if using fill/stroke-opacity here is faster - node.setAttribute('opacity', state.alpha); - //node.setAttribute('fill-opacity', state.alpha); - //node.setAttribute('stroke-opacity', state.alpha); - } - - if (filled && (state.fill != null || state.gradient != null)) - { - if (state.gradient != null) - { - node.setAttribute('fill', 'url(#' + state.gradient + ')'); - } - else - { - node.setAttribute('fill', state.fill.toLowerCase()); - } - } - else if (!styleEnabled) - { - node.setAttribute('fill', 'none'); - } - - if (stroked && state.stroke != null) - { - node.setAttribute('stroke', state.stroke.toLowerCase()); - - // Sets the stroke properties (1 is default is SVG) - if (state.strokeWidth != 1) - { - if (node.nodeName == 'rect' && autoAntiAlias) - { - state.strokeWidth = Math.max(1, state.strokeWidth); - } - - node.setAttribute('stroke-width', state.strokeWidth); - } - - if (node.nodeName == 'path') - { - // Linejoin miter is default in SVG - if (state.linejoin != null && state.linejoin != 'miter') - { - node.setAttribute('stroke-linejoin', state.linejoin); - } - - if (state.linecap != null) - { - // flat is called butt in SVG - var value = state.linecap; - - if (value == 'flat') - { - value = 'butt'; - } - - // Linecap butt is default in SVG - if (value != 'butt') - { - node.setAttribute('stroke-linecap', value); - } - } - - // Miterlimit 10 is default in our document - if (state.miterlimit != null && (!styleEnabled || state.miterlimit != 10)) - { - node.setAttribute('stroke-miterlimit', state.miterlimit); - } - } - - if (state.dashed) - { - var dash = state.dashpattern.split(' '); - - if (dash.length > 0) - { - var pat = []; - - for (var i = 0; i < dash.length; i++) - { - pat[i] = Number(dash[i]) * currentState.strokeWidth; - } - - - node.setAttribute('stroke-dasharray', pat.join(' ')); - } - } - } - - if (state.transform.length > 0) - { - node.setAttribute('transform', state.transform); - } - - root.appendChild(node); - } - }; - - // Private helper function to format a number - var f2 = function(x) - { - return Math.round(parseFloat(x) * 100) / 100; - }; - - // Returns public interface - return { - - /** - * Function: getConverter - * - * Returns <converter>. - */ - getConverter: function() - { - return converter; - }, - - /** - * Function: isAutoAntiAlias - * - * Returns <autoAntiAlias>. - */ - isAutoAntiAlias: function() - { - return autoAntiAlias; - }, - - /** - * Function: setAutoAntiAlias - * - * Sets <autoAntiAlias>. - */ - setAutoAntiAlias: function(value) - { - autoAntiAlias = value; - }, - - /** - * Function: isTextEnabled - * - * Returns <textEnabled>. - */ - isTextEnabled: function() - { - return textEnabled; - }, - - /** - * Function: setTextEnabled - * - * Sets <textEnabled>. - */ - setTextEnabled: function(value) - { - textEnabled = value; - }, - - /** - * Function: isFoEnabled - * - * Returns <foEnabled>. - */ - isFoEnabled: function() - { - return foEnabled; - }, - - /** - * Function: setFoEnabled - * - * Sets <foEnabled>. - */ - setFoEnabled: function(value) - { - foEnabled = value; - }, - - /** - * Function: save - * - * Saves the state of the graphics object. - */ - save: function() - { - stack.push(currentState); - currentState = mxUtils.clone(currentState); - }, - - /** - * Function: restore - * - * Restores the state of the graphics object. - */ - restore: function() - { - currentState = stack.pop(); - }, - - /** - * Function: scale - * - * Scales the current graphics object. - */ - scale: function(value) - { - currentState.scale *= value; - currentState.strokeWidth *= value; - }, - - /** - * Function: translate - * - * Translates the current graphics object. - */ - translate: function(dx, dy) - { - currentState.dx += dx; - currentState.dy += dy; - }, - - /** - * Function: rotate - * - * Rotates and/or flips the current graphics object. - */ - rotate: function(theta, flipH, flipV, cx, cy) - { - cx += currentState.dx; - cy += currentState.dy; - - cx *= currentState.scale; - cy *= currentState.scale; - - // This implementation uses custom scale/translate and built-in rotation - // Rotation state is part of the AffineTransform in state.transform - if (flipH ^ flipV) - { - var tx = (flipH) ? cx : 0; - var sx = (flipH) ? -1 : 1; - - var ty = (flipV) ? cy : 0; - var sy = (flipV) ? -1 : 1; - - currentState.transform += 'translate(' + f2(tx) + ',' + f2(ty) + ')'; - currentState.transform += 'scale(' + f2(sx) + ',' + f2(sy) + ')'; - currentState.transform += 'translate(' + f2(-tx) + ' ' + f2(-ty) + ')'; - } - - currentState.transform += 'rotate(' + f2(theta) + ',' + f2(cx) + ',' + f2(cy) + ')'; - }, - - /** - * Function: setStrokeWidth - * - * Sets the stroke width. - */ - setStrokeWidth: function(value) - { - currentState.strokeWidth = value * currentState.scale; - }, - - /** - * Function: setStrokeColor - * - * Sets the stroke color. - */ - setStrokeColor: function(value) - { - currentState.stroke = value; - }, - - /** - * Function: setDashed - * - * Sets the dashed state to true or false. - */ - setDashed: function(value) - { - currentState.dashed = value; - }, - - /** - * Function: setDashPattern - * - * Sets the dashed pattern to the given space separated list of numbers. - */ - setDashPattern: function(value) - { - currentState.dashpattern = value; - }, - - /** - * Function: setLineCap - * - * Sets the linecap. - */ - setLineCap: function(value) - { - currentState.linecap = value; - }, - - /** - * Function: setLineJoin - * - * Sets the linejoin. - */ - setLineJoin: function(value) - { - currentState.linejoin = value; - }, - - /** - * Function: setMiterLimit - * - * Sets the miterlimit. - */ - setMiterLimit: function(value) - { - currentState.miterlimit = value; - }, - - /** - * Function: setFontSize - * - * Sets the fontsize. - */ - setFontSize: function(value) - { - currentState.fontSize = value; - }, - - /** - * Function: setFontColor - * - * Sets the fontcolor. - */ - setFontColor: function(value) - { - currentState.fontColor = value; - }, - - /** - * Function: setFontFamily - * - * Sets the fontfamily. - */ - setFontFamily: function(value) - { - currentState.fontFamily = value; - }, - - /** - * Function: setFontStyle - * - * Sets the fontstyle. - */ - setFontStyle: function(value) - { - currentState.fontStyle = value; - }, - - /** - * Function: setAlpha - * - * Sets the current alpha. - */ - setAlpha: function(alpha) - { - currentState.alpha = alpha; - }, - - /** - * Function: setFillColor - * - * Sets the fillcolor. - */ - setFillColor: function(value) - { - currentState.fill = value; - currentState.gradient = null; - }, - - /** - * Function: setGradient - * - * Sets the gradient color. - */ - setGradient: function(color1, color2, x, y, w, h, direction) - { - if (color1 != null && color2 != null) - { - currentState.gradient = getSvgGradient(color1, color2, direction); - currentState.fill = color1; - } - }, - - /** - * Function: setGlassGradient - * - * Sets the glass gradient. - */ - setGlassGradient: function(x, y, w, h) - { - // Creates glass overlay gradient - if (glassGradient == null) - { - glassGradient = create('linearGradient'); - glassGradient.setAttribute('id', '0'); - glassGradient.setAttribute('x1', '0%'); - glassGradient.setAttribute('y1', '0%'); - glassGradient.setAttribute('x2', '0%'); - glassGradient.setAttribute('y2', '100%'); - - var stop1 = create('stop'); - stop1.setAttribute('offset', '0%'); - stop1.setAttribute('style', 'stop-color:#ffffff;stop-opacity:0.9'); - glassGradient.appendChild(stop1); - - var stop2 = create('stop'); - stop2.setAttribute('offset', '100%'); - stop2.setAttribute('style', 'stop-color:#ffffff;stop-opacity:0.1'); - glassGradient.appendChild(stop2); - - // Makes it the first entry of all gradients in defs - if (defs.firstChild.nextSibling != null) - { - defs.insertBefore(glassGradient, defs.firstChild.nextSibling); - } - else - { - defs.appendChild(glassGradient); - } - } - - // Glass gradient has hardcoded ID (see above) - currentState.gradient = '0'; - }, - - /** - * Function: rect - * - * Sets the current path to a rectangle. - */ - rect: function(x, y, w, h) - { - x += currentState.dx; - y += currentState.dy; - - currentNode = create('rect'); - currentNode.setAttribute('x', f2(x * currentState.scale)); - currentNode.setAttribute('y', f2(y * currentState.scale)); - currentNode.setAttribute('width', f2(w * currentState.scale)); - currentNode.setAttribute('height', f2(h * currentState.scale)); - - if (!styleEnabled && autoAntiAlias) - { - currentNode.setAttribute('shape-rendering', 'crispEdges'); - } - }, - - /** - * Function: roundrect - * - * Sets the current path to a rounded rectangle. - */ - roundrect: function(x, y, w, h, dx, dy) - { - x += currentState.dx; - y += currentState.dy; - - currentNode = create('rect'); - currentNode.setAttribute('x', f2(x * currentState.scale)); - currentNode.setAttribute('y', f2(y * currentState.scale)); - currentNode.setAttribute('width', f2(w * currentState.scale)); - currentNode.setAttribute('height', f2(h * currentState.scale)); - - if (dx > 0) - { - currentNode.setAttribute('rx', f2(dx * currentState.scale)); - } - - if (dy > 0) - { - currentNode.setAttribute('ry', f2(dy * currentState.scale)); - } - - if (!styleEnabled && autoAntiAlias) - { - currentNode.setAttribute('shape-rendering', 'crispEdges'); - } - }, - - /** - * Function: ellipse - * - * Sets the current path to an ellipse. - */ - ellipse: function(x, y, w, h) - { - x += currentState.dx; - y += currentState.dy; - - currentNode = create('ellipse'); - currentNode.setAttribute('cx', f2((x + w / 2) * currentState.scale)); - currentNode.setAttribute('cy', f2((y + h / 2) * currentState.scale)); - currentNode.setAttribute('rx', f2(w / 2 * currentState.scale)); - currentNode.setAttribute('ry', f2(h / 2 * currentState.scale)); - }, - - /** - * Function: image - * - * Paints an image. - */ - image: function(x, y, w, h, src, aspect, flipH, flipV) - { - src = converter.convert(src); - - // TODO: Add option for embedded images as base64. Current - // known issues are binary loading of cross-domain images. - aspect = (aspect != null) ? aspect : true; - flipH = (flipH != null) ? flipH : false; - flipV = (flipV != null) ? flipV : false; - x += currentState.dx; - y += currentState.dy; - - var node = create('image'); - node.setAttribute('x', f2(x * currentState.scale)); - node.setAttribute('y', f2(y * currentState.scale)); - node.setAttribute('width', f2(w * currentState.scale)); - node.setAttribute('height', f2(h * currentState.scale)); - - if (mxClient.IS_VML) - { - node.setAttribute('xlink:href', src); - } - else - { - node.setAttributeNS(mxConstants.NS_XLINK, 'xlink:href', src); - } - - if (!aspect) - { - node.setAttribute('preserveAspectRatio', 'none'); - } - - if (currentState.alpha < 1) - { - node.setAttribute('opacity', currentState.alpha); - } - - - var tr = currentState.transform; - - if (flipH || flipV) - { - var sx = 1; - var sy = 1; - var dx = 0; - var dy = 0; - - if (flipH) - { - sx = -1; - dx = -w - 2 * x; - } - - if (flipV) - { - sy = -1; - dy = -h - 2 * y; - } - - // Adds image tansformation to existing transforms - tr += 'scale(' + sx + ',' + sy + ')translate(' + dx + ',' + dy + ')'; - } - - if (tr.length > 0) - { - node.setAttribute('transform', tr); - } - - root.appendChild(node); - }, - - /** - * Function: text - * - * Paints the given text. Possible values for format are empty string for - * plain text and html for HTML markup. - */ - text: function(x, y, w, h, str, align, valign, vertical, wrap, format) - { - if (textEnabled) - { - x += currentState.dx; - y += currentState.dy; - - if (foEnabled && format == 'html') - { - var node = create('g'); - node.setAttribute('transform', currentState.transform + 'scale(' + currentState.scale + ',' + currentState.scale + ')'); - - if (currentState.alpha < 1) - { - node.setAttribute('opacity', currentState.alpha); - } - - var fo = create('foreignObject'); - fo.setAttribute('x', Math.round(x)); - fo.setAttribute('y', Math.round(y)); - fo.setAttribute('width', Math.round(w)); - fo.setAttribute('height', Math.round(h)); - fo.appendChild(createHtmlBody(str, align, valign)); - node.appendChild(fo); - root.appendChild(node); - } - else - { - var size = Math.floor(currentState.fontSize); - var node = create('g'); - var tr = currentState.transform; - - if (vertical) - { - var cx = x + w / 2; - var cy = y + h / 2; - tr += 'rotate(-90,' + f2(cx * currentState.scale) + ',' + f2(cy * currentState.scale) + ')'; - } - - if (tr.length > 0) - { - node.setAttribute('transform', tr); - } - - if (currentState.alpha < 1) - { - node.setAttribute('opacity', currentState.alpha); - } - - // Default is left - var anchor = (align == mxConstants.ALIGN_RIGHT) ? 'end' : - (align == mxConstants.ALIGN_CENTER) ? 'middle' : - 'start'; - - if (anchor == 'end') - { - x += Math.max(0, w - 2); - } - else if (anchor == 'middle') - { - x += w / 2; - } - else - { - x += (w > 0) ? 2 : 0; - } - - if ((currentState.fontStyle & mxConstants.FONT_BOLD) == mxConstants.FONT_BOLD) - { - node.setAttribute('font-weight', 'bold'); - } - - if ((currentState.fontStyle & mxConstants.FONT_ITALIC) == mxConstants.FONT_ITALIC) - { - node.setAttribute('font-style', 'italic'); - } - - if ((currentState.fontStyle & mxConstants.FONT_UNDERLINE) == mxConstants.FONT_UNDERLINE) - { - node.setAttribute('text-decoration', 'underline'); - } - - // Text-anchor start is default in SVG - if (anchor != 'start') - { - node.setAttribute('text-anchor', anchor); - } - - if (!styleEnabled || size != mxConstants.DEFAULT_FONTSIZE) - { - node.setAttribute('font-size', Math.floor(size * currentState.scale) + 'px'); - } - - if (!styleEnabled || currentState.fontFamily != mxConstants.DEFAULT_FONTFAMILY) - { - node.setAttribute('font-family', currentState.fontFamily); - } - - node.setAttribute('fill', currentState.fontColor); - - var lines = str.split('\n'); - - var lineHeight = size * 1.25; - var textHeight = (h > 0) ? size + (lines.length - 1) * lineHeight : lines.length * lineHeight - 1; - var dy = h - textHeight; - - // Top is default - if (valign == null || valign == mxConstants.ALIGN_TOP) - { - y = Math.max(y - 3 * currentState.scale, y + dy / 2 + ((h > 0) ? lineHeight / 2 - 8 : 0)); - } - else if (valign == mxConstants.ALIGN_MIDDLE) - { - y = y + dy / 2; - } - else if (valign == mxConstants.ALIGN_BOTTOM) - { - y = Math.min(y, y + dy + 2 * currentState.scale); - } - - y += size; - - for (var i = 0; i < lines.length; i++) - { - var text = create('text'); - text.setAttribute('x', f2(x * currentState.scale)); - text.setAttribute('y', f2(y * currentState.scale)); - - mxUtils.write(text, lines[i]); - node.appendChild(text); - y += size * 1.3; - } - - root.appendChild(node); - } - } - }, - - /** - * Function: begin - * - * Starts a new path. - */ - begin: function() - { - currentNode = create('path'); - currentPath = []; - lastPoint = null; - currentPathIsOrthogonal = true; - }, - - /** - * Function: moveTo - * - * Moves the current path the given coordinates. - */ - moveTo: function(x, y) - { - if (currentPath != null) - { - x += currentState.dx; - y += currentState.dy; - currentPath.push('M ' + f2(x * currentState.scale) + ' ' + f2(y * currentState.scale)); - - if (autoAntiAlias) - { - lastPoint = new mxPoint(x, y); - } - } - }, - - /** - * Function: lineTo - * - * Adds a line to the current path. - */ - lineTo: function(x, y) - { - if (currentPath != null) - { - x += currentState.dx; - y += currentState.dy; - currentPath.push('L ' + f2(x * currentState.scale) + ' ' + f2(y * currentState.scale)); - - if (autoAntiAlias) - { - if (lastPoint != null && currentPathIsOrthogonal && x != lastPoint.x && y != lastPoint.y) - { - currentPathIsOrthogonal = false; - } - - lastPoint = new mxPoint(x, y); - } - } - }, - - /** - * Function: quadTo - * - * Adds a quadratic curve to the current path. - */ - quadTo: function(x1, y1, x2, y2) - { - if (currentPath != null) - { - x1 += currentState.dx; - y1 += currentState.dy; - x2 += currentState.dx; - y2 += currentState.dy; - currentPath.push('Q ' + f2(x1 * currentState.scale) + ' ' + f2(y1 * currentState.scale) + - ' ' + f2(x2 * currentState.scale) + ' ' + f2(y2 * currentState.scale)); - currentPathIsOrthogonal = false; - } - }, - - /** - * Function: curveTo - * - * Adds a bezier curve to the current path. - */ - curveTo: function(x1, y1, x2, y2, x3, y3) - { - if (currentPath != null) - { - x1 += currentState.dx; - y1 += currentState.dy; - x2 += currentState.dx; - y2 += currentState.dy; - x3 += currentState.dx; - y3 += currentState.dy; - currentPath.push('C ' + f2(x1 * currentState.scale) + ' ' + f2(y1 * currentState.scale) + - ' ' + f2(x2 * currentState.scale) + ' ' + f2(y2 * currentState.scale) +' ' + - f2(x3 * currentState.scale) + ' ' + f2(y3 * currentState.scale)); - currentPathIsOrthogonal = false; - } - }, - - /** - * Function: close - * - * Closes the current path. - */ - close: function() - { - if (currentPath != null) - { - currentPath.push('Z'); - } - }, - - /** - * Function: stroke - * - * Paints the outline of the current path. - */ - stroke: function() - { - appendNode(currentNode, currentState, false, true); - }, - - /** - * Function: fill - * - * Fills the current path. - */ - fill: function() - { - appendNode(currentNode, currentState, true, false); - }, - - /** - * Function: fillstroke - * - * Fills and paints the outline of the current path. - */ - fillAndStroke: function() - { - appendNode(currentNode, currentState, true, true); - }, - - /** - * Function: shadow - * - * Paints the current path as a shadow of the given color. - */ - shadow: function(value, filled) - { - this.save(); - this.setStrokeColor(value); - - if (filled) - { - this.setFillColor(value); - this.fillAndStroke(); - } - else - { - this.stroke(); - } - - this.restore(); - }, - - /** - * Function: clip - * - * Uses the current path for clipping. - */ - clip: function() - { - if (currentNode != null) - { - if (currentPath != null) - { - currentNode.setAttribute('d', currentPath.join(' ')); - currentPath = null; - } - - var id = ++refCount; - var clip = create('clipPath'); - clip.setAttribute('id', id); - clip.appendChild(currentNode); - defs.appendChild(clip); - currentState.clip = id; - } - } - }; - -};
\ No newline at end of file diff --git a/src/js/util/mxToolbar.js b/src/js/util/mxToolbar.js deleted file mode 100644 index 754e6b3..0000000 --- a/src/js/util/mxToolbar.js +++ /dev/null @@ -1,528 +0,0 @@ -/** - * $Id: mxToolbar.js,v 1.36 2012-06-22 11:17:13 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -/** - * Class: mxToolbar - * - * Creates a toolbar inside a given DOM node. The toolbar may contain icons, - * buttons and combo boxes. - * - * Event: mxEvent.SELECT - * - * Fires when an item was selected in the toolbar. The <code>function</code> - * property contains the function that was selected in <selectMode>. - * - * Constructor: mxToolbar - * - * Constructs a toolbar in the specified container. - * - * Parameters: - * - * container - DOM node that contains the toolbar. - */ -function mxToolbar(container) -{ - this.container = container; -}; - -/** - * Extends mxEventSource. - */ -mxToolbar.prototype = new mxEventSource(); -mxToolbar.prototype.constructor = mxToolbar; - -/** - * Variable: container - * - * Reference to the DOM nodes that contains the toolbar. - */ -mxToolbar.prototype.container = null; - -/** - * Variable: enabled - * - * Specifies if events are handled. Default is true. - */ -mxToolbar.prototype.enabled = true; - -/** - * Variable: noReset - * - * Specifies if <resetMode> requires a forced flag of true for resetting - * the current mode in the toolbar. Default is false. This is set to true - * if the toolbar item is double clicked to avoid a reset after a single - * use of the item. - */ -mxToolbar.prototype.noReset = false; - -/** - * Variable: updateDefaultMode - * - * Boolean indicating if the default mode should be the last selected - * switch mode or the first inserted switch mode. Default is true, that - * is the last selected switch mode is the default mode. The default mode - * is the mode to be selected after a reset of the toolbar. If this is - * false, then the default mode is the first inserted mode item regardless - * of what was last selected. Otherwise, the selected item after a reset is - * the previously selected item. - */ -mxToolbar.prototype.updateDefaultMode = true; - -/** - * Function: addItem - * - * Adds the given function as an image with the specified title and icon - * and returns the new image node. - * - * Parameters: - * - * title - Optional string that is used as the tooltip. - * icon - Optional URL of the image to be used. If no URL is given, then a - * button is created. - * funct - Function to execute on a mouse click. - * pressedIcon - Optional URL of the pressed image. Default is a gray - * background. - * style - Optional style classname. Default is mxToolbarItem. - * factoryMethod - Optional factory method for popup menu, eg. - * function(menu, evt, cell) { menu.addItem('Hello, World!'); } - */ -mxToolbar.prototype.addItem = function(title, icon, funct, pressedIcon, style, factoryMethod) -{ - var img = document.createElement((icon != null) ? 'img' : 'button'); - var initialClassName = style || ((factoryMethod != null) ? - 'mxToolbarMode' : 'mxToolbarItem'); - img.className = initialClassName; - img.setAttribute('src', icon); - - if (title != null) - { - if (icon != null) - { - img.setAttribute('title', title); - } - else - { - mxUtils.write(img, title); - } - } - - this.container.appendChild(img); - - // Invokes the function on a click on the toolbar item - if (funct != null) - { - mxEvent.addListener(img, (mxClient.IS_TOUCH) ? 'touchend' : 'click', funct); - } - - var md = (mxClient.IS_TOUCH) ? 'touchstart' : 'mousedown'; - var mu = (mxClient.IS_TOUCH) ? 'touchend' : 'mouseup'; - - // Highlights the toolbar item with a gray background - // while it is being clicked with the mouse - mxEvent.addListener(img, md, mxUtils.bind(this, function(evt) - { - if (pressedIcon != null) - { - img.setAttribute('src', pressedIcon); - } - else - { - img.style.backgroundColor = 'gray'; - } - - // Popup Menu - if (factoryMethod != null) - { - if (this.menu == null) - { - this.menu = new mxPopupMenu(); - this.menu.init(); - } - - var last = this.currentImg; - - if (this.menu.isMenuShowing()) - { - this.menu.hideMenu(); - } - - if (last != img) - { - // Redirects factory method to local factory method - this.currentImg = img; - this.menu.factoryMethod = factoryMethod; - - var point = new mxPoint( - img.offsetLeft, - img.offsetTop + img.offsetHeight); - this.menu.popup(point.x, point.y, null, evt); - - // Sets and overrides to restore classname - if (this.menu.isMenuShowing()) - { - img.className = initialClassName + 'Selected'; - - this.menu.hideMenu = function() - { - mxPopupMenu.prototype.hideMenu.apply(this); - img.className = initialClassName; - this.currentImg = null; - }; - } - } - } - })); - - var mouseHandler = mxUtils.bind(this, function(evt) - { - if (pressedIcon != null) - { - img.setAttribute('src', icon); - } - else - { - img.style.backgroundColor = ''; - } - }); - - mxEvent.addListener(img, mu, mouseHandler); - mxEvent.addListener(img, 'mouseout', mouseHandler); - - return img; -}; - -/** - * Function: addCombo - * - * Adds and returns a new SELECT element using the given style. The element - * is placed inside a DIV with the mxToolbarComboContainer style classname. - * - * Parameters: - * - * style - Optional style classname. Default is mxToolbarCombo. - */ -mxToolbar.prototype.addCombo = function(style) -{ - var div = document.createElement('div'); - div.style.display = 'inline'; - div.className = 'mxToolbarComboContainer'; - - var select = document.createElement('select'); - select.className = style || 'mxToolbarCombo'; - div.appendChild(select); - - this.container.appendChild(div); - - return select; -}; - -/** - * Function: addCombo - * - * Adds and returns a new SELECT element using the given title as the - * default element. The selection is reset to this element after each - * change. - * - * Parameters: - * - * title - String that specifies the title of the default element. - * style - Optional style classname. Default is mxToolbarCombo. - */ -mxToolbar.prototype.addActionCombo = function(title, style) -{ - var select = document.createElement('select'); - select.className = style || 'mxToolbarCombo'; - - this.addOption(select, title, null); - - mxEvent.addListener(select, 'change', function(evt) - { - var value = select.options[select.selectedIndex]; - select.selectedIndex = 0; - if (value.funct != null) - { - value.funct(evt); - } - }); - - this.container.appendChild(select); - - return select; -}; - -/** - * Function: addOption - * - * Adds and returns a new OPTION element inside the given SELECT element. - * If the given value is a function then it is stored in the option's funct - * field. - * - * Parameters: - * - * combo - SELECT element that will contain the new entry. - * title - String that specifies the title of the option. - * value - Specifies the value associated with this option. - */ -mxToolbar.prototype.addOption = function(combo, title, value) -{ - var option = document.createElement('option'); - mxUtils.writeln(option, title); - - if (typeof(value) == 'function') - { - option.funct = value; - } - else - { - option.setAttribute('value', value); - } - - combo.appendChild(option); - - return option; -}; - -/** - * Function: addSwitchMode - * - * Adds a new selectable item to the toolbar. Only one switch mode item may - * be selected at a time. The currently selected item is the default item - * after a reset of the toolbar. - */ -mxToolbar.prototype.addSwitchMode = function(title, icon, funct, pressedIcon, style) -{ - var img = document.createElement('img'); - img.initialClassName = style || 'mxToolbarMode'; - img.className = img.initialClassName; - img.setAttribute('src', icon); - img.altIcon = pressedIcon; - - if (title != null) - { - img.setAttribute('title', title); - } - - mxEvent.addListener(img, 'click', mxUtils.bind(this, function(evt) - { - var tmp = this.selectedMode.altIcon; - - if (tmp != null) - { - this.selectedMode.altIcon = this.selectedMode.getAttribute('src'); - this.selectedMode.setAttribute('src', tmp); - } - else - { - this.selectedMode.className = this.selectedMode.initialClassName; - } - - if (this.updateDefaultMode) - { - this.defaultMode = img; - } - - this.selectedMode = img; - - var tmp = img.altIcon; - - if (tmp != null) - { - img.altIcon = img.getAttribute('src'); - img.setAttribute('src', tmp); - } - else - { - img.className = img.initialClassName+'Selected'; - } - - this.fireEvent(new mxEventObject(mxEvent.SELECT)); - funct(); - })); - - this.container.appendChild(img); - - if (this.defaultMode == null) - { - this.defaultMode = img; - - // Function should fire only once so - // do not pass it with the select event - this.selectMode(img); - funct(); - } - - return img; -}; - -/** - * Function: addMode - * - * Adds a new item to the toolbar. The selection is typically reset after - * the item has been consumed, for example by adding a new vertex to the - * graph. The reset is not carried out if the item is double clicked. - * - * The function argument uses the following signature: funct(evt, cell) where - * evt is the native mouse event and cell is the cell under the mouse. - */ -mxToolbar.prototype.addMode = function(title, icon, funct, pressedIcon, style, toggle) -{ - toggle = (toggle != null) ? toggle : true; - var img = document.createElement((icon != null) ? 'img' : 'button'); - - img.initialClassName = style || 'mxToolbarMode'; - img.className = img.initialClassName; - img.setAttribute('src', icon); - img.altIcon = pressedIcon; - - if (title != null) - { - img.setAttribute('title', title); - } - - if (this.enabled && toggle) - { - mxEvent.addListener(img, 'click', mxUtils.bind(this, function(evt) - { - this.selectMode(img, funct); - this.noReset = false; - })); - mxEvent.addListener(img, 'dblclick', - mxUtils.bind(this, function(evt) - { - this.selectMode(img, funct); - this.noReset = true; - }) - ); - - if (this.defaultMode == null) - { - this.defaultMode = img; - this.defaultFunction = funct; - this.selectMode(img, funct); - } - } - - this.container.appendChild(img); - - return img; -}; - -/** - * Function: selectMode - * - * Resets the state of the previously selected mode and displays the given - * DOM node as selected. This function fires a select event with the given - * function as a parameter. - */ -mxToolbar.prototype.selectMode = function(domNode, funct) -{ - if (this.selectedMode != domNode) - { - if (this.selectedMode != null) - { - var tmp = this.selectedMode.altIcon; - - if (tmp != null) - { - this.selectedMode.altIcon = this.selectedMode.getAttribute('src'); - this.selectedMode.setAttribute('src', tmp); - } - else - { - this.selectedMode.className = this.selectedMode.initialClassName; - } - } - - this.selectedMode = domNode; - var tmp = this.selectedMode.altIcon; - - if (tmp != null) - { - this.selectedMode.altIcon = this.selectedMode.getAttribute('src'); - this.selectedMode.setAttribute('src', tmp); - } - else - { - this.selectedMode.className = this.selectedMode.initialClassName+'Selected'; - } - - this.fireEvent(new mxEventObject(mxEvent.SELECT, "function", funct)); - } -}; - -/** - * Function: resetMode - * - * Selects the default mode and resets the state of the previously selected - * mode. - */ -mxToolbar.prototype.resetMode = function(forced) -{ - if ((forced || !this.noReset) && - this.selectedMode != this.defaultMode) - { - // The last selected switch mode will be activated - // so the function was already executed and is - // no longer required here - this.selectMode(this.defaultMode, this.defaultFunction); - } -}; - -/** - * Function: addSeparator - * - * Adds the specifies image as a separator. - * - * Parameters: - * - * icon - URL of the separator icon. - */ -mxToolbar.prototype.addSeparator = function(icon) -{ - return this.addItem(null, icon, null); -}; - -/** - * Function: addBreak - * - * Adds a break to the container. - */ -mxToolbar.prototype.addBreak = function() -{ - mxUtils.br(this.container); -}; - -/** - * Function: addLine - * - * Adds a horizontal line to the container. - */ -mxToolbar.prototype.addLine = function() -{ - var hr = document.createElement('hr'); - - hr.style.marginRight = '6px'; - hr.setAttribute('size', '1'); - - this.container.appendChild(hr); -}; - -/** - * Function: destroy - * - * Removes the toolbar and all its associated resources. - */ -mxToolbar.prototype.destroy = function () -{ - mxEvent.release(this.container); - this.container = null; - this.defaultMode = null; - this.defaultFunction = null; - this.selectedMode = null; - - if (this.menu != null) - { - this.menu.destroy(); - } -}; diff --git a/src/js/util/mxUndoManager.js b/src/js/util/mxUndoManager.js deleted file mode 100644 index 2cb93cb..0000000 --- a/src/js/util/mxUndoManager.js +++ /dev/null @@ -1,229 +0,0 @@ -/** - * $Id: mxUndoManager.js,v 1.30 2011-10-05 06:39:19 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -/** - * Class: mxUndoManager - * - * Implements a command history. When changing the graph model, an - * <mxUndoableChange> object is created at the start of the transaction (when - * model.beginUpdate is called). All atomic changes are then added to this - * object until the last model.endUpdate call, at which point the - * <mxUndoableEdit> is dispatched in an event, and added to the history inside - * <mxUndoManager>. This is done by an event listener in - * <mxEditor.installUndoHandler>. - * - * Each atomic change of the model is represented by an object (eg. - * <mxRootChange>, <mxChildChange>, <mxTerminalChange> etc) which contains the - * complete undo information. The <mxUndoManager> also listens to the - * <mxGraphView> and stores it's changes to the current root as insignificant - * undoable changes, so that drilling (step into, step up) is undone. - * - * This means when you execute an atomic change on the model, then change the - * current root on the view and click undo, the change of the root will be - * undone together with the change of the model so that the display represents - * the state at which the model was changed. However, these changes are not - * transmitted for sharing as they do not represent a state change. - * - * Example: - * - * When adding an undo manager to a graph, make sure to add it - * to the model and the view as well to maintain a consistent - * display across multiple undo/redo steps. - * - * (code) - * var undoManager = new mxUndoManager(); - * var listener = function(sender, evt) - * { - * undoManager.undoableEditHappened(evt.getProperty('edit')); - * }; - * graph.getModel().addListener(mxEvent.UNDO, listener); - * graph.getView().addListener(mxEvent.UNDO, listener); - * (end) - * - * The code creates a function that informs the undoManager - * of an undoable edit and binds it to the undo event of - * <mxGraphModel> and <mxGraphView> using - * <mxEventSource.addListener>. - * - * Event: mxEvent.CLEAR - * - * Fires after <clear> was invoked. This event has no properties. - * - * Event: mxEvent.UNDO - * - * Fires afer a significant edit was undone in <undo>. The <code>edit</code> - * property contains the <mxUndoableEdit> that was undone. - * - * Event: mxEvent.REDO - * - * Fires afer a significant edit was redone in <redo>. The <code>edit</code> - * property contains the <mxUndoableEdit> that was redone. - * - * Event: mxEvent.ADD - * - * Fires after an undoable edit was added to the history. The <code>edit</code> - * property contains the <mxUndoableEdit> that was added. - * - * Constructor: mxUndoManager - * - * Constructs a new undo manager with the given history size. If no history - * size is given, then a default size of 100 steps is used. - */ -function mxUndoManager(size) -{ - this.size = (size != null) ? size : 100; - this.clear(); -}; - -/** - * Extends mxEventSource. - */ -mxUndoManager.prototype = new mxEventSource(); -mxUndoManager.prototype.constructor = mxUndoManager; - -/** - * Variable: size - * - * Maximum command history size. 0 means unlimited history. Default is - * 100. - */ -mxUndoManager.prototype.size = null; - -/** - * Variable: history - * - * Array that contains the steps of the command history. - */ -mxUndoManager.prototype.history = null; - -/** - * Variable: indexOfNextAdd - * - * Index of the element to be added next. - */ -mxUndoManager.prototype.indexOfNextAdd = 0; - -/** - * Function: isEmpty - * - * Returns true if the history is empty. - */ -mxUndoManager.prototype.isEmpty = function() -{ - return this.history.length == 0; -}; - -/** - * Function: clear - * - * Clears the command history. - */ -mxUndoManager.prototype.clear = function() -{ - this.history = []; - this.indexOfNextAdd = 0; - this.fireEvent(new mxEventObject(mxEvent.CLEAR)); -}; - -/** - * Function: canUndo - * - * Returns true if an undo is possible. - */ -mxUndoManager.prototype.canUndo = function() -{ - return this.indexOfNextAdd > 0; -}; - -/** - * Function: undo - * - * Undoes the last change. - */ -mxUndoManager.prototype.undo = function() -{ - while (this.indexOfNextAdd > 0) - { - var edit = this.history[--this.indexOfNextAdd]; - edit.undo(); - - if (edit.isSignificant()) - { - this.fireEvent(new mxEventObject(mxEvent.UNDO, 'edit', edit)); - break; - } - } -}; - -/** - * Function: canRedo - * - * Returns true if a redo is possible. - */ -mxUndoManager.prototype.canRedo = function() -{ - return this.indexOfNextAdd < this.history.length; -}; - -/** - * Function: redo - * - * Redoes the last change. - */ -mxUndoManager.prototype.redo = function() -{ - var n = this.history.length; - - while (this.indexOfNextAdd < n) - { - var edit = this.history[this.indexOfNextAdd++]; - edit.redo(); - - if (edit.isSignificant()) - { - this.fireEvent(new mxEventObject(mxEvent.REDO, 'edit', edit)); - break; - } - } -}; - -/** - * Function: undoableEditHappened - * - * Method to be called to add new undoable edits to the <history>. - */ -mxUndoManager.prototype.undoableEditHappened = function(undoableEdit) -{ - this.trim(); - - if (this.size > 0 && - this.size == this.history.length) - { - this.history.shift(); - } - - this.history.push(undoableEdit); - this.indexOfNextAdd = this.history.length; - this.fireEvent(new mxEventObject(mxEvent.ADD, 'edit', undoableEdit)); -}; - -/** - * Function: trim - * - * Removes all pending steps after <indexOfNextAdd> from the history, - * invoking die on each edit. This is called from <undoableEditHappened>. - */ -mxUndoManager.prototype.trim = function() -{ - if (this.history.length > this.indexOfNextAdd) - { - var edits = this.history.splice(this.indexOfNextAdd, - this.history.length - this.indexOfNextAdd); - - for (var i = 0; i < edits.length; i++) - { - edits[i].die(); - } - } -}; diff --git a/src/js/util/mxUndoableEdit.js b/src/js/util/mxUndoableEdit.js deleted file mode 100644 index 886c262..0000000 --- a/src/js/util/mxUndoableEdit.js +++ /dev/null @@ -1,168 +0,0 @@ -/** - * $Id: mxUndoableEdit.js,v 1.14 2010-09-15 16:58:51 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -/** - * Class: mxUndoableEdit - * - * Implements a composite undoable edit. - * - * Constructor: mxUndoableEdit - * - * Constructs a new undoable edit for the given source. - */ -function mxUndoableEdit(source, significant) -{ - this.source = source; - this.changes = []; - this.significant = (significant != null) ? significant : true; -}; - -/** - * Variable: source - * - * Specifies the source of the edit. - */ -mxUndoableEdit.prototype.source = null; - -/** - * Variable: changes - * - * Array that contains the changes that make up this edit. The changes are - * expected to either have an undo and redo function, or an execute - * function. Default is an empty array. - */ -mxUndoableEdit.prototype.changes = null; - -/** - * Variable: significant - * - * Specifies if the undoable change is significant. - * Default is true. - */ -mxUndoableEdit.prototype.significant = null; - -/** - * Variable: undone - * - * Specifies if this edit has been undone. Default is false. - */ -mxUndoableEdit.prototype.undone = false; - -/** - * Variable: redone - * - * Specifies if this edit has been redone. Default is false. - */ -mxUndoableEdit.prototype.redone = false; - -/** - * Function: isEmpty - * - * Returns true if the this edit contains no changes. - */ -mxUndoableEdit.prototype.isEmpty = function() -{ - return this.changes.length == 0; -}; - -/** - * Function: isSignificant - * - * Returns <significant>. - */ -mxUndoableEdit.prototype.isSignificant = function() -{ - return this.significant; -}; - -/** - * Function: add - * - * Adds the specified change to this edit. The change is an object that is - * expected to either have an undo and redo, or an execute function. - */ -mxUndoableEdit.prototype.add = function(change) -{ - this.changes.push(change); -}; - -/** - * Function: notify - * - * Hook to notify any listeners of the changes after an <undo> or <redo> - * has been carried out. This implementation is empty. - */ -mxUndoableEdit.prototype.notify = function() { }; - -/** - * Function: die - * - * Hook to free resources after the edit has been removed from the command - * history. This implementation is empty. - */ -mxUndoableEdit.prototype.die = function() { }; - -/** - * Function: undo - * - * Undoes all changes in this edit. - */ -mxUndoableEdit.prototype.undo = function() -{ - if (!this.undone) - { - var count = this.changes.length; - - for (var i = count - 1; i >= 0; i--) - { - var change = this.changes[i]; - - if (change.execute != null) - { - change.execute(); - } - else if (change.undo != null) - { - change.undo(); - } - } - - this.undone = true; - this.redone = false; - } - - this.notify(); -}; - -/** - * Function: redo - * - * Redoes all changes in this edit. - */ -mxUndoableEdit.prototype.redo = function() -{ - if (!this.redone) - { - var count = this.changes.length; - - for (var i = 0; i < count; i++) - { - var change = this.changes[i]; - - if (change.execute != null) - { - change.execute(); - } - else if (change.redo != null) - { - change.redo(); - } - } - - this.undone = false; - this.redone = true; - } - - this.notify(); -}; diff --git a/src/js/util/mxUrlConverter.js b/src/js/util/mxUrlConverter.js deleted file mode 100644 index 764767f..0000000 --- a/src/js/util/mxUrlConverter.js +++ /dev/null @@ -1,141 +0,0 @@ -/** - * $Id: mxUrlConverter.js,v 1.3 2012-08-24 17:10:41 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -/** - * - * Class: mxUrlConverter - * - * Converts relative and absolute URLs to absolute URLs with protocol and domain. - */ -var mxUrlConverter = function(root) -{ - /** - * Variable: enabled - * - * Specifies if the converter is enabled. Default is true. - */ - var enabled = true; - - /** - * Variable: baseUrl - * - * Specifies the base URL to be used as a prefix for relative URLs. - */ - var baseUrl = null; - - /** - * Variable: baseDomain - * - * Specifies the base domain to be used as a prefix for absolute URLs. - */ - var baseDomain = null; - - // Private helper function to update the base URL - var updateBaseUrl = function() - { - baseDomain = location.protocol + '//' + location.host; - baseUrl = baseDomain + location.pathname; - var tmp = baseUrl.lastIndexOf('/'); - - // Strips filename etc - if (tmp > 0) - { - baseUrl = baseUrl.substring(0, tmp + 1); - } - }; - - // Returns public interface - return { - - /** - * Function: isEnabled - * - * Returns <enabled>. - */ - isEnabled: function() - { - return enabled; - }, - - /** - * Function: setEnabled - * - * Sets <enabled>. - */ - setEnabled: function(value) - { - enabled = value; - }, - - /** - * Function: getBaseUrl - * - * Returns <baseUrl>. - */ - getBaseUrl: function() - { - return baseUrl; - }, - - /** - * Function: setBaseUrl - * - * Sets <baseUrl>. - */ - setBaseUrl: function(value) - { - baseUrl = value; - }, - - /** - * Function: getBaseDomain - * - * Returns <baseDomain>. - */ - getBaseDomain: function() - { - return baseUrl; - }, - - /** - * Function: setBaseDomain - * - * Sets <baseDomain>. - */ - setBaseDomain: function(value) - { - baseUrl = value; - }, - - /** - * Function: convert - * - * Converts the given URL to an absolute URL with protol and domain. - * Relative URLs are first converted to absolute URLs. - */ - convert: function(url) - { - if (enabled && url.indexOf('http://') != 0 && url.indexOf('https://') != 0 && url.indexOf('data:image') != 0) - { - if (baseUrl == null) - { - updateBaseUrl(); - } - - if (url.charAt(0) == '/') - { - url = baseDomain + url; - } - else - { - url = baseUrl + url; - } - } - - return url; - } - - }; - -};
\ No newline at end of file diff --git a/src/js/util/mxUtils.js b/src/js/util/mxUtils.js deleted file mode 100644 index 34c0318..0000000 --- a/src/js/util/mxUtils.js +++ /dev/null @@ -1,3920 +0,0 @@ -/** - * $Id: mxUtils.js,v 1.297 2012-12-07 19:47:29 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -var mxUtils = -{ - /** - * Class: mxUtils - * - * A singleton class that provides cross-browser helper methods. - * This is a global functionality. To access the functions in this - * class, use the global classname appended by the functionname. - * You may have to load chrome://global/content/contentAreaUtils.js - * to disable certain security restrictions in Mozilla for the <open>, - * <save>, <saveAs> and <copy> function. - * - * For example, the following code displays an error message: - * - * (code) - * mxUtils.error('Browser is not supported!', 200, false); - * (end) - * - * Variable: errorResource - * - * Specifies the resource key for the title of the error window. If the - * resource for this key does not exist then the value is used as - * the title. Default is 'error'. - */ - errorResource: (mxClient.language != 'none') ? 'error' : '', - - /** - * Variable: closeResource - * - * Specifies the resource key for the label of the close button. If the - * resource for this key does not exist then the value is used as - * the label. Default is 'close'. - */ - closeResource: (mxClient.language != 'none') ? 'close' : '', - - /** - * Variable: errorImage - * - * Defines the image used for error dialogs. - */ - errorImage: mxClient.imageBasePath + '/error.gif', - - /** - * Function: removeCursors - * - * Removes the cursors from the style of the given DOM node and its - * descendants. - * - * Parameters: - * - * element - DOM node to remove the cursor style from. - */ - removeCursors: function(element) - { - if (element.style != null) - { - element.style.cursor = ''; - } - - var children = element.childNodes; - - if (children != null) - { - var childCount = children.length; - - for (var i = 0; i < childCount; i += 1) - { - mxUtils.removeCursors(children[i]); - } - } - }, - - /** - * Function: repaintGraph - * - * Normally not required, this contains the code to workaround a repaint - * issue and force a repaint of the graph container in AppleWebKit. - * - * Parameters: - * - * graph - <mxGraph> to be repainted. - * pt - <mxPoint> where the dummy element should be placed. - */ - repaintGraph: function(graph, pt) - { - if (mxClient.IS_GC || mxClient.IS_SF || mxClient.IS_OP) - { - var c = graph.container; - - if (c != null && pt != null && (c.scrollLeft > 0 || c.scrollTop > 0)) - { - var dummy = document.createElement('div'); - dummy.style.position = 'absolute'; - dummy.style.left = pt.x + 'px'; - dummy.style.top = pt.y + 'px'; - dummy.style.width = '1px'; - dummy.style.height = '1px'; - - c.appendChild(dummy); - c.removeChild(dummy); - } - } - }, - - /** - * Function: getCurrentStyle - * - * Returns the current style of the specified element. - * - * Parameters: - * - * element - DOM node whose current style should be returned. - */ - getCurrentStyle: function() - { - if (mxClient.IS_IE) - { - return function(element) - { - return (element != null) ? element.currentStyle : null; - }; - } - else - { - return function(element) - { - return (element != null) ? - window.getComputedStyle(element, '') : - null; - }; - } - }(), - - /** - * Function: hasScrollbars - * - * Returns true if the overflow CSS property of the given node is either - * scroll or auto. - * - * Parameters: - * - * node - DOM node whose style should be checked for scrollbars. - */ - hasScrollbars: function(node) - { - var style = mxUtils.getCurrentStyle(node); - - return style != null && (style.overflow == 'scroll' || style.overflow == 'auto'); - }, - - /** - * Function: bind - * - * Returns a wrapper function that locks the execution scope of the given - * function to the specified scope. Inside funct, the "this" keyword - * becomes a reference to that scope. - */ - bind: function(scope, funct) - { - return function() - { - return funct.apply(scope, arguments); - }; - }, - - /** - * Function: eval - * - * Evaluates the given expression using eval and returns the JavaScript - * object that represents the expression result. Supports evaluation of - * expressions that define functions and returns the function object for - * these expressions. - * - * Parameters: - * - * expr - A string that represents a JavaScript expression. - */ - eval: function(expr) - { - var result = null; - - if (expr.indexOf('function') >= 0) - { - try - { - eval('var _mxJavaScriptExpression='+expr); - result = _mxJavaScriptExpression; - // TODO: Use delete here? - _mxJavaScriptExpression = null; - } - catch (e) - { - mxLog.warn(e.message + ' while evaluating ' + expr); - } - } - else - { - try - { - result = eval(expr); - } - catch (e) - { - mxLog.warn(e.message + ' while evaluating ' + expr); - } - } - - return result; - }, - - /** - * Function: findNode - * - * Returns the first node where attr equals value. - * This implementation does not use XPath. - */ - findNode: function(node, attr, value) - { - var tmp = node.getAttribute(attr); - - if (tmp != null && tmp == value) - { - return node; - } - - node = node.firstChild; - - while (node != null) - { - var result = mxUtils.findNode(node, attr, value); - - if (result != null) - { - return result; - } - - node = node.nextSibling; - } - - return null; - }, - - /** - * Function: findNodeByAttribute - * - * Returns the first node where the given attribute matches the given value. - * - * Parameters: - * - * node - Root node where the search should start. - * attr - Name of the attribute to be checked. - * value - Value of the attribute to match. - */ - findNodeByAttribute: function() - { - // Workaround for missing XPath support in IE9 - if (document.documentMode >= 9) - { - return function(node, attr, value) - { - var result = null; - - if (node != null) - { - if (node.nodeType == mxConstants.NODETYPE_ELEMENT && node.getAttribute(attr) == value) - { - result = node; - } - else - { - var child = node.firstChild; - - while (child != null && result == null) - { - result = mxUtils.findNodeByAttribute(child, attr, value); - child = child.nextSibling; - } - } - } - - return result; - }; - } - else if (mxClient.IS_IE) - { - return function(node, attr, value) - { - if (node == null) - { - return null; - } - else - { - var expr = '//*[@' + attr + '=\'' + value + '\']'; - - return node.ownerDocument.selectSingleNode(expr); - } - }; - } - else - { - return function(node, attr, value) - { - if (node == null) - { - return null; - } - else - { - var result = node.ownerDocument.evaluate( - '//*[@' + attr + '=\'' + value + '\']', - node.ownerDocument, null, - XPathResult.ANY_TYPE, null); - - return result.iterateNext(); - } - }; - } - }(), - - /** - * Function: getFunctionName - * - * Returns the name for the given function. - * - * Parameters: - * - * f - JavaScript object that represents a function. - */ - getFunctionName: function(f) - { - var str = null; - - if (f != null) - { - if (f.name != null) - { - str = f.name; - } - else - { - var tmp = f.toString(); - var idx1 = 9; - - while (tmp.charAt(idx1) == ' ') - { - idx1++; - } - - var idx2 = tmp.indexOf('(', idx1); - str = tmp.substring(idx1, idx2); - } - } - - return str; - }, - - /** - * Function: indexOf - * - * Returns the index of obj in array or -1 if the array does not contains - * the given object. - * - * Parameters: - * - * array - Array to check for the given obj. - * obj - Object to find in the given array. - */ - indexOf: function(array, obj) - { - if (array != null && obj != null) - { - for (var i = 0; i < array.length; i++) - { - if (array[i] == obj) - { - return i; - } - } - } - - return -1; - }, - - /** - * Function: remove - * - * Removes all occurrences of the given object in the given array or - * object. If there are multiple occurrences of the object, be they - * associative or as an array entry, all occurrences are removed from - * the array or deleted from the object. By removing the object from - * the array, all elements following the removed element are shifted - * by one step towards the beginning of the array. - * - * The length of arrays is not modified inside this function. - * - * Parameters: - * - * obj - Object to find in the given array. - * array - Array to check for the given obj. - */ - remove: function(obj, array) - { - var result = null; - - if (typeof(array) == 'object') - { - var index = mxUtils.indexOf(array, obj); - - while (index >= 0) - { - array.splice(index, 1); - result = obj; - index = mxUtils.indexOf(array, obj); - } - } - - for (var key in array) - { - if (array[key] == obj) - { - delete array[key]; - result = obj; - } - } - - return result; - }, - - /** - * Function: isNode - * - * Returns true if the given value is an XML node with the node name - * and if the optional attribute has the specified value. - * - * This implementation assumes that the given value is a DOM node if the - * nodeType property is numeric, that is, if isNaN returns false for - * value.nodeType. - * - * Parameters: - * - * value - Object that should be examined as a node. - * nodeName - String that specifies the node name. - * attributeName - Optional attribute name to check. - * attributeValue - Optional attribute value to check. - */ - isNode: function(value, nodeName, attributeName, attributeValue) - { - if (value != null && !isNaN(value.nodeType) && (nodeName == null || - value.nodeName.toLowerCase() == nodeName.toLowerCase())) - { - return attributeName == null || - value.getAttribute(attributeName) == attributeValue; - } - - return false; - }, - - /** - * Function: getChildNodes - * - * Returns an array of child nodes that are of the given node type. - * - * Parameters: - * - * node - Parent DOM node to return the children from. - * nodeType - Optional node type to return. Default is - * <mxConstants.NODETYPE_ELEMENT>. - */ - getChildNodes: function(node, nodeType) - { - nodeType = nodeType || mxConstants.NODETYPE_ELEMENT; - - var children = []; - var tmp = node.firstChild; - - while (tmp != null) - { - if (tmp.nodeType == nodeType) - { - children.push(tmp); - } - - tmp = tmp.nextSibling; - } - - return children; - }, - - /** - * Function: createXmlDocument - * - * Returns a new, empty XML document. - */ - createXmlDocument: function() - { - var doc = null; - - if (document.implementation && document.implementation.createDocument) - { - doc = document.implementation.createDocument('', '', null); - } - else if (window.ActiveXObject) - { - doc = new ActiveXObject('Microsoft.XMLDOM'); - } - - return doc; - }, - - /** - * Function: parseXml - * - * Parses the specified XML string into a new XML document and returns the - * new document. - * - * Example: - * - * (code) - * var doc = mxUtils.parseXml( - * '<mxGraphModel><root><MyDiagram id="0"><mxCell/></MyDiagram>'+ - * '<MyLayer id="1"><mxCell parent="0" /></MyLayer><MyObject id="2">'+ - * '<mxCell style="strokeColor=blue;fillColor=red" parent="1" vertex="1">'+ - * '<mxGeometry x="10" y="10" width="80" height="30" as="geometry"/>'+ - * '</mxCell></MyObject></root></mxGraphModel>'); - * (end) - * - * Parameters: - * - * xml - String that contains the XML data. - */ - parseXml: function() - { - if (mxClient.IS_IE && (typeof(document.documentMode) === 'undefined' || document.documentMode < 9)) - { - return function(xml) - { - var result = mxUtils.createXmlDocument(); - - result.async = 'false'; - result.loadXML(xml); - - return result; - }; - } - else - { - return function(xml) - { - var parser = new DOMParser(); - - return parser.parseFromString(xml, 'text/xml'); - }; - } - }(), - - /** - * Function: clearSelection - * - * Clears the current selection in the page. - */ - clearSelection: function() - { - if (document.selection) - { - return function() - { - document.selection.empty(); - }; - } - else if (window.getSelection) - { - return function() - { - window.getSelection().removeAllRanges(); - }; - } - }(), - - /** - * Function: getPrettyXML - * - * Returns a pretty printed string that represents the XML tree for the - * given node. This method should only be used to print XML for reading, - * use <getXml> instead to obtain a string for processing. - * - * Parameters: - * - * node - DOM node to return the XML for. - * tab - Optional string that specifies the indentation for one level. - * Default is two spaces. - * indent - Optional string that represents the current indentation. - * Default is an empty string. - */ - getPrettyXml: function(node, tab, indent) - { - var result = []; - - if (node != null) - { - tab = tab || ' '; - indent = indent || ''; - - if (node.nodeType == mxConstants.NODETYPE_TEXT) - { - result.push(node.nodeValue); - } - else - { - result.push(indent + '<'+node.nodeName); - - // Creates the string with the node attributes - // and converts all HTML entities in the values - var attrs = node.attributes; - - if (attrs != null) - { - for (var i = 0; i < attrs.length; i++) - { - var val = mxUtils.htmlEntities(attrs[i].nodeValue); - result.push(' ' + attrs[i].nodeName + - '="' + val + '"'); - } - } - - // Recursively creates the XML string for each - // child nodes and appends it here with an - // indentation - var tmp = node.firstChild; - - if (tmp != null) - { - result.push('>\n'); - - while (tmp != null) - { - result.push(mxUtils.getPrettyXml( - tmp, tab, indent + tab)); - tmp = tmp.nextSibling; - } - - result.push(indent + '</'+node.nodeName+'>\n'); - } - else - { - result.push('/>\n'); - } - } - } - - return result.join(''); - }, - - /** - * Function: removeWhitespace - * - * Removes the sibling text nodes for the given node that only consists - * of tabs, newlines and spaces. - * - * Parameters: - * - * node - DOM node whose siblings should be removed. - * before - Optional boolean that specifies the direction of the traversal. - */ - removeWhitespace: function(node, before) - { - var tmp = (before) ? node.previousSibling : node.nextSibling; - - while (tmp != null && tmp.nodeType == mxConstants.NODETYPE_TEXT) - { - var next = (before) ? tmp.previousSibling : tmp.nextSibling; - var text = mxUtils.getTextContent(tmp); - - if (mxUtils.trim(text).length == 0) - { - tmp.parentNode.removeChild(tmp); - } - - tmp = next; - } - }, - - /** - * Function: htmlEntities - * - * Replaces characters (less than, greater than, newlines and quotes) with - * their HTML entities in the given string and returns the result. - * - * Parameters: - * - * s - String that contains the characters to be converted. - * newline - If newlines should be replaced. Default is true. - */ - htmlEntities: function(s, newline) - { - s = s || ''; - - s = s.replace(/&/g,'&'); // 38 26 - s = s.replace(/"/g,'"'); // 34 22 - s = s.replace(/\'/g,'''); // 39 27 - s = s.replace(/</g,'<'); // 60 3C - s = s.replace(/>/g,'>'); // 62 3E - - if (newline == null || newline) - { - s = s.replace(/\n/g, '
'); - } - - return s; - }, - - /** - * Function: isVml - * - * Returns true if the given node is in the VML namespace. - * - * Parameters: - * - * node - DOM node whose tag urn should be checked. - */ - isVml: function(node) - { - return node != null && node.tagUrn == 'urn:schemas-microsoft-com:vml'; - }, - - /** - * Function: getXml - * - * Returns the XML content of the specified node. For Internet Explorer, - * all \r\n\t[\t]* are removed from the XML string and the remaining \r\n - * are replaced by \n. All \n are then replaced with linefeed, or 
 if - * no linefeed is defined. - * - * Parameters: - * - * node - DOM node to return the XML for. - * linefeed - Optional string that linefeeds are converted into. Default is - * 
 - */ - getXml: function(node, linefeed) - { - var xml = ''; - - if (node != null) - { - xml = node.xml; - - if (xml == null) - { - if (node.innerHTML) - { - xml = node.innerHTML; - } - else - { - var xmlSerializer = new XMLSerializer(); - xml = xmlSerializer.serializeToString(node); - } - } - else - { - xml = xml.replace(/\r\n\t[\t]*/g, ''). - replace(/>\r\n/g, '>'). - replace(/\r\n/g, '\n'); - } - } - - // Replaces linefeeds with HTML Entities. - linefeed = linefeed || '
'; - xml = xml.replace(/\n/g, linefeed); - - return xml; - }, - - /** - * Function: getTextContent - * - * Returns the text content of the specified node. - * - * Parameters: - * - * node - DOM node to return the text content for. - */ - getTextContent: function(node) - { - var result = ''; - - if (node != null) - { - if (node.firstChild != null) - { - node = node.firstChild; - } - - result = node.nodeValue || ''; - } - - return result; - }, - - /** - * Function: getInnerHtml - * - * Returns the inner HTML for the given node as a string or an empty string - * if no node was specified. The inner HTML is the text representing all - * children of the node, but not the node itself. - * - * Parameters: - * - * node - DOM node to return the inner HTML for. - */ - getInnerHtml: function() - { - if (mxClient.IS_IE) - { - return function(node) - { - if (node != null) - { - return node.innerHTML; - } - - return ''; - }; - } - else - { - return function(node) - { - if (node != null) - { - var serializer = new XMLSerializer(); - return serializer.serializeToString(node); - } - - return ''; - }; - } - }(), - - /** - * Function: getOuterHtml - * - * Returns the outer HTML for the given node as a string or an empty - * string if no node was specified. The outer HTML is the text representing - * all children of the node including the node itself. - * - * Parameters: - * - * node - DOM node to return the outer HTML for. - */ - getOuterHtml: function() - { - if (mxClient.IS_IE) - { - return function(node) - { - if (node != null) - { - if (node.outerHTML != null) - { - return node.outerHTML; - } - else - { - var tmp = []; - tmp.push('<'+node.nodeName); - - var attrs = node.attributes; - - if (attrs != null) - { - for (var i = 0; i < attrs.length; i++) - { - var value = attrs[i].nodeValue; - - if (value != null && value.length > 0) - { - tmp.push(' '); - tmp.push(attrs[i].nodeName); - tmp.push('="'); - tmp.push(value); - tmp.push('"'); - } - } - } - - if (node.innerHTML.length == 0) - { - tmp.push('/>'); - } - else - { - tmp.push('>'); - tmp.push(node.innerHTML); - tmp.push('</'+node.nodeName+'>'); - } - - return tmp.join(''); - } - } - - return ''; - }; - } - else - { - return function(node) - { - if (node != null) - { - var serializer = new XMLSerializer(); - return serializer.serializeToString(node); - } - - return ''; - }; - } - }(), - - /** - * Function: write - * - * Creates a text node for the given string and appends it to the given - * parent. Returns the text node. - * - * Parameters: - * - * parent - DOM node to append the text node to. - * text - String representing the text to be added. - */ - write: function(parent, text) - { - var doc = parent.ownerDocument; - var node = doc.createTextNode(text); - - if (parent != null) - { - parent.appendChild(node); - } - - return node; - }, - - /** - * Function: writeln - * - * Creates a text node for the given string and appends it to the given - * parent with an additional linefeed. Returns the text node. - * - * Parameters: - * - * parent - DOM node to append the text node to. - * text - String representing the text to be added. - */ - writeln: function(parent, text) - { - var doc = parent.ownerDocument; - var node = doc.createTextNode(text); - - if (parent != null) - { - parent.appendChild(node); - parent.appendChild(document.createElement('br')); - } - - return node; - }, - - /** - * Function: br - * - * Appends a linebreak to the given parent and returns the linebreak. - * - * Parameters: - * - * parent - DOM node to append the linebreak to. - */ - br: function(parent, count) - { - count = count || 1; - var br = null; - - for (var i = 0; i < count; i++) - { - if (parent != null) - { - br = parent.ownerDocument.createElement('br'); - parent.appendChild(br); - } - } - - return br; - }, - - /** - * Function: button - * - * Returns a new button with the given level and function as an onclick - * event handler. - * - * (code) - * document.body.appendChild(mxUtils.button('Test', function(evt) - * { - * alert('Hello, World!'); - * })); - * (end) - * - * Parameters: - * - * label - String that represents the label of the button. - * funct - Function to be called if the button is pressed. - * doc - Optional document to be used for creating the button. Default is the - * current document. - */ - button: function(label, funct, doc) - { - doc = (doc != null) ? doc : document; - - var button = doc.createElement('button'); - mxUtils.write(button, label); - - mxEvent.addListener(button, 'click', function(evt) - { - funct(evt); - }); - - return button; - }, - - /** - * Function: para - * - * Appends a new paragraph with the given text to the specified parent and - * returns the paragraph. - * - * Parameters: - * - * parent - DOM node to append the text node to. - * text - String representing the text for the new paragraph. - */ - para: function(parent, text) - { - var p = document.createElement('p'); - mxUtils.write(p, text); - - if (parent != null) - { - parent.appendChild(p); - } - - return p; - }, - - /** - * Function: linkAction - * - * Adds a hyperlink to the specified parent that invokes action on the - * specified editor. - * - * Parameters: - * - * parent - DOM node to contain the new link. - * text - String that is used as the link label. - * editor - <mxEditor> that will execute the action. - * action - String that defines the name of the action to be executed. - * pad - Optional left-padding for the link. Default is 0. - */ - linkAction: function(parent, text, editor, action, pad) - { - return mxUtils.link(parent, text, function() - { - editor.execute(action); - }, pad); - }, - - /** - * Function: linkInvoke - * - * Adds a hyperlink to the specified parent that invokes the specified - * function on the editor passing along the specified argument. The - * function name is the name of a function of the editor instance, - * not an action name. - * - * Parameters: - * - * parent - DOM node to contain the new link. - * text - String that is used as the link label. - * editor - <mxEditor> instance to execute the function on. - * functName - String that represents the name of the function. - * arg - Object that represents the argument to the function. - * pad - Optional left-padding for the link. Default is 0. - */ - linkInvoke: function(parent, text, editor, functName, arg, pad) - { - return mxUtils.link(parent, text, function() - { - editor[functName](arg); - }, pad); - }, - - /** - * Function: link - * - * Adds a hyperlink to the specified parent and invokes the given function - * when the link is clicked. - * - * Parameters: - * - * parent - DOM node to contain the new link. - * text - String that is used as the link label. - * funct - Function to execute when the link is clicked. - * pad - Optional left-padding for the link. Default is 0. - */ - link: function(parent, text, funct, pad) - { - var a = document.createElement('span'); - - a.style.color = 'blue'; - a.style.textDecoration = 'underline'; - a.style.cursor = 'pointer'; - - if (pad != null) - { - a.style.paddingLeft = pad+'px'; - } - - mxEvent.addListener(a, 'click', funct); - mxUtils.write(a, text); - - if (parent != null) - { - parent.appendChild(a); - } - - return a; - }, - - /** - * Function: fit - * - * Makes sure the given node is inside the visible area of the window. This - * is done by setting the left and top in the style. - */ - fit: function(node) - { - var left = parseInt(node.offsetLeft); - var width = parseInt(node.offsetWidth); - - var b = document.body; - var d = document.documentElement; - - var right = (b.scrollLeft || d.scrollLeft) + - (b.clientWidth || d.clientWidth); - - if (left + width > right) - { - node.style.left = Math.max((b.scrollLeft || d.scrollLeft), - right - width)+'px'; - } - - var top = parseInt(node.offsetTop); - var height = parseInt(node.offsetHeight); - - var bottom = (b.scrollTop || d.scrollTop) + - Math.max(b.clientHeight || 0, d.clientHeight); - - if (top + height > bottom) - { - node.style.top = Math.max((b.scrollTop || d.scrollTop), - bottom - height)+'px'; - } - }, - - /** - * Function: open - * - * Opens the specified file from the local filesystem and returns the - * contents of the file as a string. This implementation requires an - * ActiveX object in IE and special privileges in Firefox. Relative - * filenames are only supported in IE and will go onto the users' - * Desktop. You may have to load - * chrome://global/content/contentAreaUtils.js to disable certain - * security restrictions in Mozilla for this to work. - * - * See known-issues before using this function. - * - * Example: - * (code) - * var data = mxUtils.open('C:\\temp\\test.txt'); - * mxUtils.alert('Data: '+data); - * (end) - * - * Parameters: - * - * filename - String representing the local file name. - */ - open: function(filename) - { - // Requests required privileges in Firefox - if (mxClient.IS_NS) - { - try - { - netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect'); - } - catch (e) - { - mxUtils.alert('Permission to read file denied.'); - - return ''; - } - - var file = Components.classes['@mozilla.org/file/local;1'].createInstance(Components.interfaces.nsILocalFile); - file.initWithPath(filename); - - if (!file.exists()) - { - mxUtils.alert('File not found.'); - return ''; - } - - var is = Components.classes['@mozilla.org/network/file-input-stream;1'].createInstance(Components.interfaces.nsIFileInputStream); - is.init(file,0x01, 00004, null); - - var sis = Components.classes['@mozilla.org/scriptableinputstream;1'].createInstance(Components.interfaces.nsIScriptableInputStream); - sis.init(is); - - var output = sis.read(sis.available()); - - return output; - } - else - { - var activeXObject = new ActiveXObject('Scripting.FileSystemObject'); - - var newStream = activeXObject.OpenTextFile(filename, 1); - var text = newStream.readAll(); - newStream.close(); - - return text; - } - }, - - /** - * Function: save - * - * Saves the specified content in the given file on the local file system. - * This implementation requires an ActiveX object in IE and special - * privileges in Firefox. Relative filenames are only supported in IE and - * will be loaded from the users' Desktop. You may have to load - * chrome://global/content/contentAreaUtils.js to disable certain - * security restrictions in Mozilla for this to work. - * - * See known-issues before using this function. - * - * Example: - * - * (code) - * var data = 'Hello, World!'; - * mxUtils.save('C:\\test.txt', data); - * (end) - * - * Parameters: - * - * filename - String representing the local file name. - */ - save: function(filename, content) - { - if (mxClient.IS_NS) - { - try - { - netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect'); - } - catch (e) - { - mxUtils.alert('Permission to write file denied.'); - return; - } - - var file = Components.classes['@mozilla.org/file/local;1'].createInstance(Components.interfaces.nsILocalFile); - file.initWithPath(filename); - - if (!file.exists()) - { - file.create(0x00, 0644); - } - - var outputStream = Components.classes['@mozilla.org/network/file-output-stream;1'].createInstance(Components.interfaces.nsIFileOutputStream); - - outputStream.init(file, 0x20 | 0x02,00004, null); - outputStream.write(content, content.length); - outputStream.flush(); - outputStream.close(); - } - else - { - var fso = new ActiveXObject('Scripting.FileSystemObject'); - - var file = fso.CreateTextFile(filename, true); - file.Write(content); - file.Close(); - } - }, - - /** - * Function: saveAs - * - * Saves the specified content by displaying a dialog to save the content - * as a file on the local filesystem. This implementation does not use an - * ActiveX object in IE, however, it does require special privileges in - * Firefox. You may have to load - * chrome://global/content/contentAreaUtils.js to disable certain - * security restrictions in Mozilla for this to work. - * - * See known-issues before using this function. It is not recommended using - * this function in production environment as access to the filesystem - * cannot be guaranteed in Firefox. The following code is used in - * Firefox to try and enable saving to the filesystem. - * - * (code) - * netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect'); - * (end) - * - * Example: - * - * (code) - * mxUtils.saveAs('Hello, World!'); - * (end) - * - * Parameters: - * - * content - String representing the file's content. - */ - saveAs: function(content) - { - var iframe = document.createElement('iframe'); - iframe.setAttribute('src', ''); - iframe.style.visibility = 'hidden'; - document.body.appendChild(iframe); - - try - { - if (mxClient.IS_NS) - { - var doc = iframe.contentDocument; - - doc.open(); - doc.write(content); - doc.close(); - - try - { - netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect'); - // LATER: Remove existing HTML markup in file - iframe.focus(); - saveDocument(doc); - } - catch (e) - { - mxUtils.alert('Permission to save document denied.'); - } - } - else - { - var doc = iframe.contentWindow.document; - doc.write(content); - doc.execCommand('SaveAs', false, document.location); - } - } - finally - { - document.body.removeChild(iframe); - } - }, - - /** - * Function: copy - * - * Copies the specified content to the local clipboard. This implementation - * requires special privileges in Firefox. You may have to load - * chrome://global/content/contentAreaUtils.js to disable certain - * security restrictions in Mozilla for this to work. - * - * Parameters: - * - * content - String to be copied to the clipboard. - */ - copy: function(content) - { - if (window.clipboardData) - { - window.clipboardData.setData('Text', content); - } - else - { - netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect'); - - var clip = Components.classes['@mozilla.org/widget/clipboard;1'] - .createInstance(Components.interfaces.nsIClipboard); - - if (!clip) - { - return; - } - - var trans = Components.classes['@mozilla.org/widget/transferable;1'] - .createInstance(Components.interfaces.nsITransferable); - - if (!trans) - { - return; - } - - trans.addDataFlavor('text/unicode'); - var str = Components.classes['@mozilla.org/supports-string;1'] - .createInstance(Components.interfaces.nsISupportsString); - - var copytext=content; - str.data=copytext; - trans.setTransferData('text/unicode', str, copytext.length*2); - var clipid=Components.interfaces.nsIClipboard; - - clip.setData(trans,null,clipid.kGlobalClipboard); - } - }, - - /** - * Function: load - * - * Loads the specified URL *synchronously* and returns the <mxXmlRequest>. - * Throws an exception if the file cannot be loaded. See <mxUtils.get> for - * an asynchronous implementation. - * - * Example: - * - * (code) - * try - * { - * var req = mxUtils.load(filename); - * var root = req.getDocumentElement(); - * // Process XML DOM... - * } - * catch (ex) - * { - * mxUtils.alert('Cannot load '+filename+': '+ex); - * } - * (end) - * - * Parameters: - * - * url - URL to get the data from. - */ - load: function(url) - { - var req = new mxXmlRequest(url, null, 'GET', false); - req.send(); - - return req; - }, - - /** - * Function: get - * - * Loads the specified URL *asynchronously* and invokes the given functions - * depending on the request status. Returns the <mxXmlRequest> in use. Both - * functions take the <mxXmlRequest> as the only parameter. See - * <mxUtils.load> for a synchronous implementation. - * - * Example: - * - * (code) - * mxUtils.get(url, function(req) - * { - * var node = req.getDocumentElement(); - * // Process XML DOM... - * }); - * (end) - * - * So for example, to load a diagram into an existing graph model, the - * following code is used. - * - * (code) - * mxUtils.get(url, function(req) - * { - * var node = req.getDocumentElement(); - * var dec = new mxCodec(node.ownerDocument); - * dec.decode(node, graph.getModel()); - * }); - * (end) - * - * Parameters: - * - * url - URL to get the data from. - * onload - Optional function to execute for a successful response. - * onerror - Optional function to execute on error. - */ - get: function(url, onload, onerror) - { - return new mxXmlRequest(url, null, 'GET').send(onload, onerror); - }, - - /** - * Function: post - * - * Posts the specified params to the given URL *asynchronously* and invokes - * the given functions depending on the request status. Returns the - * <mxXmlRequest> in use. Both functions take the <mxXmlRequest> as the - * only parameter. Make sure to use encodeURIComponent for the parameter - * values. - * - * Example: - * - * (code) - * mxUtils.post(url, 'key=value', function(req) - * { - * mxUtils.alert('Ready: '+req.isReady()+' Status: '+req.getStatus()); - * // Process req.getDocumentElement() using DOM API if OK... - * }); - * (end) - * - * Parameters: - * - * url - URL to get the data from. - * params - Parameters for the post request. - * onload - Optional function to execute for a successful response. - * onerror - Optional function to execute on error. - */ - post: function(url, params, onload, onerror) - { - return new mxXmlRequest(url, params).send(onload, onerror); - }, - - /** - * Function: submit - * - * Submits the given parameters to the specified URL using - * <mxXmlRequest.simulate> and returns the <mxXmlRequest>. - * Make sure to use encodeURIComponent for the parameter - * values. - * - * Parameters: - * - * url - URL to get the data from. - * params - Parameters for the form. - * doc - Document to create the form in. - * target - Target to send the form result to. - */ - submit: function(url, params, doc, target) - { - return new mxXmlRequest(url, params).simulate(doc, target); - }, - - /** - * Function: loadInto - * - * Loads the specified URL *asynchronously* into the specified document, - * invoking onload after the document has been loaded. This implementation - * does not use <mxXmlRequest>, but the document.load method. - * - * Parameters: - * - * url - URL to get the data from. - * doc - The document to load the URL into. - * onload - Function to execute when the URL has been loaded. - */ - loadInto: function(url, doc, onload) - { - if (mxClient.IS_IE) - { - doc.onreadystatechange = function () - { - if (doc.readyState == 4) - { - onload(); - } - }; - } - else - { - doc.addEventListener('load', onload, false); - } - - doc.load(url); - }, - - /** - * Function: getValue - * - * Returns the value for the given key in the given associative array or - * the given default value if the value is null. - * - * Parameters: - * - * array - Associative array that contains the value for the key. - * key - Key whose value should be returned. - * defaultValue - Value to be returned if the value for the given - * key is null. - */ - getValue: function(array, key, defaultValue) - { - var value = (array != null) ? array[key] : null; - - if (value == null) - { - value = defaultValue; - } - - return value; - }, - - /** - * Function: getNumber - * - * Returns the numeric value for the given key in the given associative - * array or the given default value (or 0) if the value is null. The value - * is converted to a numeric value using the Number function. - * - * Parameters: - * - * array - Associative array that contains the value for the key. - * key - Key whose value should be returned. - * defaultValue - Value to be returned if the value for the given - * key is null. Default is 0. - */ - getNumber: function(array, key, defaultValue) - { - var value = (array != null) ? array[key] : null; - - if (value == null) - { - value = defaultValue || 0; - } - - return Number(value); - }, - - /** - * Function: getColor - * - * Returns the color value for the given key in the given associative - * array or the given default value if the value is null. If the value - * is <mxConstants.NONE> then null is returned. - * - * Parameters: - * - * array - Associative array that contains the value for the key. - * key - Key whose value should be returned. - * defaultValue - Value to be returned if the value for the given - * key is null. Default is null. - */ - getColor: function(array, key, defaultValue) - { - var value = (array != null) ? array[key] : null; - - if (value == null) - { - value = defaultValue; - } - else if (value == mxConstants.NONE) - { - value = null; - } - - return value; - }, - - /** - * Function: clone - * - * Recursively clones the specified object ignoring all fieldnames in the - * given array of transient fields. <mxObjectIdentity.FIELD_NAME> is always - * ignored by this function. - * - * Parameters: - * - * obj - Object to be cloned. - * transients - Optional array of strings representing the fieldname to be - * ignored. - * shallow - Optional boolean argument to specify if a shallow clone should - * be created, that is, one where all object references are not cloned or, - * in other words, one where only atomic (strings, numbers) values are - * cloned. Default is false. - */ - clone: function(obj, transients, shallow) - { - shallow = (shallow != null) ? shallow : false; - var clone = null; - - if (obj != null && typeof(obj.constructor) == 'function') - { - clone = new obj.constructor(); - - for (var i in obj) - { - if (i != mxObjectIdentity.FIELD_NAME && (transients == null || - mxUtils.indexOf(transients, i) < 0)) - { - if (!shallow && typeof(obj[i]) == 'object') - { - clone[i] = mxUtils.clone(obj[i]); - } - else - { - clone[i] = obj[i]; - } - } - } - } - - return clone; - }, - - /** - * Function: equalPoints - * - * Compares all mxPoints in the given lists. - * - * Parameters: - * - * a - Array of <mxPoints> to be compared. - * b - Array of <mxPoints> to be compared. - */ - equalPoints: function(a, b) - { - if ((a == null && b != null) || (a != null && b == null) || - (a != null && b != null && a.length != b.length)) - { - return false; - } - else if (a != null && b != null) - { - for (var i = 0; i < a.length; i++) - { - if (a[i] == b[i] || (a[i] != null && !a[i].equals(b[i]))) - { - return false; - } - } - } - - return true; - }, - - /** - * Function: equalEntries - * - * Compares all entries in the given dictionaries. - * - * Parameters: - * - * a - <mxRectangle> to be compared. - * b - <mxRectangle> to be compared. - */ - equalEntries: function(a, b) - { - if ((a == null && b != null) || (a != null && b == null) || - (a != null && b != null && a.length != b.length)) - { - return false; - } - else if (a != null && b != null) - { - for (var key in a) - { - if (a[key] != b[key]) - { - return false; - } - } - } - - return true; - }, - - /** - * Function: extend - * - * Assigns a copy of the superclass prototype to the subclass prototype. - * Note that this does not call the constructor of the superclass at this - * point, the superclass constructor should be called explicitely in the - * subclass constructor. Below is an example. - * - * (code) - * MyGraph = function(container, model, renderHint, stylesheet) - * { - * mxGraph.call(this, container, model, renderHint, stylesheet); - * } - * - * mxUtils.extend(MyGraph, mxGraph); - * (end) - * - * Parameters: - * - * ctor - Constructor of the subclass. - * superCtor - Constructor of the superclass. - */ - extend: function(ctor, superCtor) - { - var f = function() {}; - f.prototype = superCtor.prototype; - - ctor.prototype = new f(); - ctor.prototype.constructor = ctor; - }, - - /** - * Function: toString - * - * Returns a textual representation of the specified object. - * - * Parameters: - * - * obj - Object to return the string representation for. - */ - toString: function(obj) - { - var output = ''; - - for (var i in obj) - { - try - { - if (obj[i] == null) - { - output += i + ' = [null]\n'; - } - else if (typeof(obj[i]) == 'function') - { - output += i + ' => [Function]\n'; - } - else if (typeof(obj[i]) == 'object') - { - var ctor = mxUtils.getFunctionName(obj[i].constructor); - output += i + ' => [' + ctor + ']\n'; - } - else - { - output += i + ' = ' + obj[i] + '\n'; - } - } - catch (e) - { - output += i + '=' + e.message; - } - } - - return output; - }, - - /** - * Function: toRadians - * - * Converts the given degree to radians. - */ - toRadians: function(deg) - { - return Math.PI * deg / 180; - }, - - /** - * Function: arcToCurves - * - * Converts the given arc to a series of curves. - */ - arcToCurves: function(x0, y0, r1, r2, angle, largeArcFlag, sweepFlag, x, y) - { - x -= x0; - y -= y0; - - if (r1 === 0 || r2 === 0) - { - return result; - } - - var fS = sweepFlag; - var psai = angle; - r1 = Math.abs(r1); - r2 = Math.abs(r2); - var ctx = -x / 2; - var cty = -y / 2; - var cpsi = Math.cos(psai * Math.PI / 180); - var spsi = Math.sin(psai * Math.PI / 180); - var rxd = cpsi * ctx + spsi * cty; - var ryd = -1 * spsi * ctx + cpsi * cty; - var rxdd = rxd * rxd; - var rydd = ryd * ryd; - var r1x = r1 * r1; - var r2y = r2 * r2; - var lamda = rxdd / r1x + rydd / r2y; - var sds; - - if (lamda > 1) - { - r1 = Math.sqrt(lamda) * r1; - r2 = Math.sqrt(lamda) * r2; - sds = 0; - } - else - { - var seif = 1; - - if (largeArcFlag === fS) - { - seif = -1; - } - - sds = seif * Math.sqrt((r1x * r2y - r1x * rydd - r2y * rxdd) / (r1x * rydd + r2y * rxdd)); - } - - var txd = sds * r1 * ryd / r2; - var tyd = -1 * sds * r2 * rxd / r1; - var tx = cpsi * txd - spsi * tyd + x / 2; - var ty = spsi * txd + cpsi * tyd + y / 2; - var rad = Math.atan2((ryd - tyd) / r2, (rxd - txd) / r1) - Math.atan2(0, 1); - var s1 = (rad >= 0) ? rad : 2 * Math.PI + rad; - rad = Math.atan2((-ryd - tyd) / r2, (-rxd - txd) / r1) - Math.atan2((ryd - tyd) / r2, (rxd - txd) / r1); - var dr = (rad >= 0) ? rad : 2 * Math.PI + rad; - - if (fS == 0 && dr > 0) - { - dr -= 2 * Math.PI; - } - else if (fS != 0 && dr < 0) - { - dr += 2 * Math.PI; - } - - var sse = dr * 2 / Math.PI; - var seg = Math.ceil(sse < 0 ? -1 * sse : sse); - var segr = dr / seg; - var t = 8/3 * Math.sin(segr / 4) * Math.sin(segr / 4) / Math.sin(segr / 2); - var cpsir1 = cpsi * r1; - var cpsir2 = cpsi * r2; - var spsir1 = spsi * r1; - var spsir2 = spsi * r2; - var mc = Math.cos(s1); - var ms = Math.sin(s1); - var x2 = -t * (cpsir1 * ms + spsir2 * mc); - var y2 = -t * (spsir1 * ms - cpsir2 * mc); - var x3 = 0; - var y3 = 0; - - var result = []; - - for (var n = 0; n < seg; ++n) - { - s1 += segr; - mc = Math.cos(s1); - ms = Math.sin(s1); - - x3 = cpsir1 * mc - spsir2 * ms + tx; - y3 = spsir1 * mc + cpsir2 * ms + ty; - var dx = -t * (cpsir1 * ms + spsir2 * mc); - var dy = -t * (spsir1 * ms - cpsir2 * mc); - - // CurveTo updates x0, y0 so need to restore it - var index = n * 6; - result[index] = Number(x2 + x0); - result[index + 1] = Number(y2 + y0); - result[index + 2] = Number(x3 - dx + x0); - result[index + 3] = Number(y3 - dy + y0); - result[index + 4] = Number(x3 + x0); - result[index + 5] = Number(y3 + y0); - - x2 = x3 + dx; - y2 = y3 + dy; - } - - return result; - }, - - /** - * Function: getBoundingBox - * - * Returns the bounding box for the rotated rectangle. - */ - getBoundingBox: function(rect, rotation) - { - var result = null; - - if (rect != null && rotation != null && rotation != 0) - { - var rad = mxUtils.toRadians(rotation); - var cos = Math.cos(rad); - var sin = Math.sin(rad); - - var cx = new mxPoint( - rect.x + rect.width / 2, - rect.y + rect.height / 2); - - var p1 = new mxPoint(rect.x, rect.y); - var p2 = new mxPoint(rect.x + rect.width, rect.y); - var p3 = new mxPoint(p2.x, rect.y + rect.height); - var p4 = new mxPoint(rect.x, p3.y); - - p1 = mxUtils.getRotatedPoint(p1, cos, sin, cx); - p2 = mxUtils.getRotatedPoint(p2, cos, sin, cx); - p3 = mxUtils.getRotatedPoint(p3, cos, sin, cx); - p4 = mxUtils.getRotatedPoint(p4, cos, sin, cx); - - result = new mxRectangle(p1.x, p1.y, 0, 0); - result.add(new mxRectangle(p2.x, p2.y, 0, 0)); - result.add(new mxRectangle(p3.x, p3.y, 0, 0)); - result.add(new mxRectangle(p4.x, p4.y, 0, 0)); - } - - return result; - }, - - /** - * Function: getRotatedPoint - * - * Rotates the given point by the given cos and sin. - */ - getRotatedPoint: function(pt, cos, sin, c) - { - c = (c != null) ? c : new mxPoint(); - var x = pt.x - c.x; - var y = pt.y - c.y; - - var x1 = x * cos - y * sin; - var y1 = y * cos + x * sin; - - return new mxPoint(x1 + c.x, y1 + c.y); - }, - - /** - * Returns an integer mask of the port constraints of the given map - * @param dict the style map to determine the port constraints for - * @param defaultValue Default value to return if the key is undefined. - * @return the mask of port constraint directions - * - * Parameters: - * - * terminal - <mxCelState> that represents the terminal. - * edge - <mxCellState> that represents the edge. - * source - Boolean that specifies if the terminal is the source terminal. - * defaultValue - Default value to be returned. - */ - getPortConstraints: function(terminal, edge, source, defaultValue) - { - var value = mxUtils.getValue(terminal.style, mxConstants.STYLE_PORT_CONSTRAINT, null); - - if (value == null) - { - return defaultValue; - } - else - { - var directions = value.toString(); - var returnValue = mxConstants.DIRECTION_MASK_NONE; - - if (directions.indexOf(mxConstants.DIRECTION_NORTH) >= 0) - { - returnValue |= mxConstants.DIRECTION_MASK_NORTH; - } - if (directions.indexOf(mxConstants.DIRECTION_WEST) >= 0) - { - returnValue |= mxConstants.DIRECTION_MASK_WEST; - } - if (directions.indexOf(mxConstants.DIRECTION_SOUTH) >= 0) - { - returnValue |= mxConstants.DIRECTION_MASK_SOUTH; - } - if (directions.indexOf(mxConstants.DIRECTION_EAST) >= 0) - { - returnValue |= mxConstants.DIRECTION_MASK_EAST; - } - - return returnValue; - } - }, - - /** - * Function: reversePortConstraints - * - * Reverse the port constraint bitmask. For example, north | east - * becomes south | west - */ - reversePortConstraints: function(constraint) - { - var result = 0; - - result = (constraint & mxConstants.DIRECTION_MASK_WEST) << 3; - result |= (constraint & mxConstants.DIRECTION_MASK_NORTH) << 1; - result |= (constraint & mxConstants.DIRECTION_MASK_SOUTH) >> 1; - result |= (constraint & mxConstants.DIRECTION_MASK_EAST) >> 3; - - return result; - }, - - /** - * Function: findNearestSegment - * - * Finds the index of the nearest segment on the given cell state for - * the specified coordinate pair. - */ - findNearestSegment: function(state, x, y) - { - var index = -1; - - if (state.absolutePoints.length > 0) - { - var last = state.absolutePoints[0]; - var min = null; - - for (var i = 1; i < state.absolutePoints.length; i++) - { - var current = state.absolutePoints[i]; - var dist = mxUtils.ptSegDistSq(last.x, last.y, - current.x, current.y, x, y); - - if (min == null || dist < min) - { - min = dist; - index = i - 1; - } - - last = current; - } - } - - return index; - }, - - /** - * Function: rectangleIntersectsSegment - * - * Returns true if the given rectangle intersects the given segment. - * - * Parameters: - * - * bounds - <mxRectangle> that represents the rectangle. - * p1 - <mxPoint> that represents the first point of the segment. - * p2 - <mxPoint> that represents the second point of the segment. - */ - rectangleIntersectsSegment: function(bounds, p1, p2) - { - var top = bounds.y; - var left = bounds.x; - var bottom = top + bounds.height; - var right = left + bounds.width; - - // Find min and max X for the segment - var minX = p1.x; - var maxX = p2.x; - - if (p1.x > p2.x) - { - minX = p2.x; - maxX = p1.x; - } - - // Find the intersection of the segment's and rectangle's x-projections - if (maxX > right) - { - maxX = right; - } - - if (minX < left) - { - minX = left; - } - - if (minX > maxX) // If their projections do not intersect return false - { - return false; - } - - // Find corresponding min and max Y for min and max X we found before - var minY = p1.y; - var maxY = p2.y; - var dx = p2.x - p1.x; - - if (Math.abs(dx) > 0.0000001) - { - var a = (p2.y - p1.y) / dx; - var b = p1.y - a * p1.x; - minY = a * minX + b; - maxY = a * maxX + b; - } - - if (minY > maxY) - { - var tmp = maxY; - maxY = minY; - minY = tmp; - } - - // Find the intersection of the segment's and rectangle's y-projections - if (maxY > bottom) - { - maxY = bottom; - } - - if (minY < top) - { - minY = top; - } - - if (minY > maxY) // If Y-projections do not intersect return false - { - return false; - } - - return true; - }, - - /** - * Function: contains - * - * Returns true if the specified point (x, y) is contained in the given rectangle. - * - * Parameters: - * - * bounds - <mxRectangle> that represents the area. - * x - X-coordinate of the point. - * y - Y-coordinate of the point. - */ - contains: function(bounds, x, y) - { - return (bounds.x <= x && bounds.x + bounds.width >= x && - bounds.y <= y && bounds.y + bounds.height >= y); - }, - - /** - * Function: intersects - * - * Returns true if the two rectangles intersect. - * - * Parameters: - * - * a - <mxRectangle> to be checked for intersection. - * b - <mxRectangle> to be checked for intersection. - */ - intersects: function(a, b) - { - var tw = a.width; - var th = a.height; - var rw = b.width; - var rh = b.height; - - if (rw <= 0 || rh <= 0 || tw <= 0 || th <= 0) - { - return false; - } - - var tx = a.x; - var ty = a.y; - var rx = b.x; - var ry = b.y; - - rw += rx; - rh += ry; - tw += tx; - th += ty; - - return ((rw < rx || rw > tx) && - (rh < ry || rh > ty) && - (tw < tx || tw > rx) && - (th < ty || th > ry)); - }, - - /** - * Function: intersects - * - * Returns true if the two rectangles intersect. - * - * Parameters: - * - * a - <mxRectangle> to be checked for intersection. - * b - <mxRectangle> to be checked for intersection. - */ - intersectsHotspot: function(state, x, y, hotspot, min, max) - { - hotspot = (hotspot != null) ? hotspot : 1; - min = (min != null) ? min : 0; - max = (max != null) ? max : 0; - - if (hotspot > 0) - { - var cx = state.getCenterX(); - var cy = state.getCenterY(); - var w = state.width; - var h = state.height; - - var start = mxUtils.getValue(state.style, mxConstants.STYLE_STARTSIZE) * state.view.scale; - - if (start > 0) - { - if (mxUtils.getValue(state.style, - mxConstants.STYLE_HORIZONTAL, true)) - { - cy = state.y + start / 2; - h = start; - } - else - { - cx = state.x + start / 2; - w = start; - } - } - - w = Math.max(min, w * hotspot); - h = Math.max(min, h * hotspot); - - if (max > 0) - { - w = Math.min(w, max); - h = Math.min(h, max); - } - - var rect = new mxRectangle(cx - w / 2, cy - h / 2, w, h); - - return mxUtils.contains(rect, x, y); - } - - return true; - }, - - /** - * Function: getOffset - * - * Returns the offset for the specified container as an <mxPoint>. The - * offset is the distance from the top left corner of the container to the - * top left corner of the document. - * - * Parameters: - * - * container - DOM node to return the offset for. - * scollOffset - Optional boolean to add the scroll offset of the document. - * Default is false. - */ - getOffset: function(container, scrollOffset) - { - var offsetLeft = 0; - var offsetTop = 0; - - if (scrollOffset != null && scrollOffset) - { - var b = document.body; - var d = document.documentElement; - offsetLeft += (b.scrollLeft || d.scrollLeft); - offsetTop += (b.scrollTop || d.scrollTop); - } - - while (container.offsetParent) - { - offsetLeft += container.offsetLeft; - offsetTop += container.offsetTop; - - container = container.offsetParent; - } - - return new mxPoint(offsetLeft, offsetTop); - }, - - /** - * Function: getScrollOrigin - * - * Returns the top, left corner of the viewrect as an <mxPoint>. - */ - getScrollOrigin: function(node) - { - var b = document.body; - var d = document.documentElement; - var sl = (b.scrollLeft || d.scrollLeft); - var st = (b.scrollTop || d.scrollTop); - - var result = new mxPoint(sl, st); - - while (node != null && node != b && node != d) - { - if (!isNaN(node.scrollLeft) && !isNaN(node.scrollTop)) - { - result.x += node.scrollLeft; - result.y += node.scrollTop; - } - - node = node.parentNode; - } - - return result; - }, - - /** - * Function: convertPoint - * - * Converts the specified point (x, y) using the offset of the specified - * container and returns a new <mxPoint> with the result. - * - * Parameters: - * - * container - DOM node to use for the offset. - * x - X-coordinate of the point to be converted. - * y - Y-coordinate of the point to be converted. - */ - convertPoint: function(container, x, y) - { - var origin = mxUtils.getScrollOrigin(container); - var offset = mxUtils.getOffset(container); - - offset.x -= origin.x; - offset.y -= origin.y; - - return new mxPoint(x - offset.x, y - offset.y); - }, - - /** - * Function: ltrim - * - * Strips all whitespaces from the beginning of the string. - * Without the second parameter, Javascript function will trim these - * characters: - * - * - " " (ASCII 32 (0x20)), an ordinary space - * - "\t" (ASCII 9 (0x09)), a tab - * - "\n" (ASCII 10 (0x0A)), a new line (line feed) - * - "\r" (ASCII 13 (0x0D)), a carriage return - * - "\0" (ASCII 0 (0x00)), the NUL-byte - * - "\x0B" (ASCII 11 (0x0B)), a vertical tab - */ - ltrim: function(str, chars) - { - chars = chars || "\\s"; - - return str.replace(new RegExp("^[" + chars + "]+", "g"), ""); - }, - - /** - * Function: rtrim - * - * Strips all whitespaces from the end of the string. - * Without the second parameter, Javascript function will trim these - * characters: - * - * - " " (ASCII 32 (0x20)), an ordinary space - * - "\t" (ASCII 9 (0x09)), a tab - * - "\n" (ASCII 10 (0x0A)), a new line (line feed) - * - "\r" (ASCII 13 (0x0D)), a carriage return - * - "\0" (ASCII 0 (0x00)), the NUL-byte - * - "\x0B" (ASCII 11 (0x0B)), a vertical tab - */ - rtrim: function(str, chars) - { - chars = chars || "\\s"; - - return str.replace(new RegExp("[" + chars + "]+$", "g"), ""); - }, - - /** - * Function: trim - * - * Strips all whitespaces from both end of the string. - * Without the second parameter, Javascript function will trim these - * characters: - * - * - " " (ASCII 32 (0x20)), an ordinary space - * - "\t" (ASCII 9 (0x09)), a tab - * - "\n" (ASCII 10 (0x0A)), a new line (line feed) - * - "\r" (ASCII 13 (0x0D)), a carriage return - * - "\0" (ASCII 0 (0x00)), the NUL-byte - * - "\x0B" (ASCII 11 (0x0B)), a vertical tab - */ - trim: function(str, chars) - { - return mxUtils.ltrim(mxUtils.rtrim(str, chars), chars); - }, - - /** - * Function: isNumeric - * - * Returns true if the specified value is numeric, that is, if it is not - * null, not an empty string, not a HEX number and isNaN returns false. - * - * Parameters: - * - * str - String representing the possibly numeric value. - */ - isNumeric: function(str) - { - return str != null && (str.length == null || (str.length > 0 && - str.indexOf('0x') < 0) && str.indexOf('0X') < 0) && !isNaN(str); - }, - - /** - * Function: mod - * - * Returns the remainder of division of n by m. You should use this instead - * of the built-in operation as the built-in operation does not properly - * handle negative numbers. - */ - mod: function(n, m) - { - return ((n % m) + m) % m; - }, - - /** - * Function: intersection - * - * Returns the intersection of two lines as an <mxPoint>. - * - * Parameters: - * - * x0 - X-coordinate of the first line's startpoint. - * y0 - X-coordinate of the first line's startpoint. - * x1 - X-coordinate of the first line's endpoint. - * y1 - Y-coordinate of the first line's endpoint. - * x2 - X-coordinate of the second line's startpoint. - * y2 - Y-coordinate of the second line's startpoint. - * x3 - X-coordinate of the second line's endpoint. - * y3 - Y-coordinate of the second line's endpoint. - */ - intersection: function (x0, y0, x1, y1, x2, y2, x3, y3) - { - var denom = ((y3 - y2)*(x1 - x0)) - ((x3 - x2)*(y1 - y0)); - var nume_a = ((x3 - x2)*(y0 - y2)) - ((y3 - y2)*(x0 - x2)); - var nume_b = ((x1 - x0)*(y0 - y2)) - ((y1 - y0)*(x0 - x2)); - - var ua = nume_a / denom; - var ub = nume_b / denom; - - if(ua >= 0.0 && ua <= 1.0 && ub >= 0.0 && ub <= 1.0) - { - // Get the intersection point - var intersectionX = x0 + ua*(x1 - x0); - var intersectionY = y0 + ua*(y1 - y0); - - return new mxPoint(intersectionX, intersectionY); - } - - // No intersection - return null; - }, - - /** - * Function: ptSeqDistSq - * - * Returns the square distance between a segment and a point. - * - * Parameters: - * - * x1 - X-coordinate of the startpoint of the segment. - * y1 - Y-coordinate of the startpoint of the segment. - * x2 - X-coordinate of the endpoint of the segment. - * y2 - Y-coordinate of the endpoint of the segment. - * px - X-coordinate of the point. - * py - Y-coordinate of the point. - */ - ptSegDistSq: function(x1, y1, x2, y2, px, py) - { - x2 -= x1; - y2 -= y1; - - px -= x1; - py -= y1; - - var dotprod = px * x2 + py * y2; - var projlenSq; - - if (dotprod <= 0.0) - { - projlenSq = 0.0; - } - else - { - px = x2 - px; - py = y2 - py; - dotprod = px * x2 + py * y2; - - if (dotprod <= 0.0) - { - projlenSq = 0.0; - } - else - { - projlenSq = dotprod * dotprod / (x2 * x2 + y2 * y2); - } - } - - var lenSq = px * px + py * py - projlenSq; - - if (lenSq < 0) - { - lenSq = 0; - } - - return lenSq; - }, - - /** - * Function: relativeCcw - * - * Returns 1 if the given point on the right side of the segment, 0 if its - * on the segment, and -1 if the point is on the left side of the segment. - * - * Parameters: - * - * x1 - X-coordinate of the startpoint of the segment. - * y1 - Y-coordinate of the startpoint of the segment. - * x2 - X-coordinate of the endpoint of the segment. - * y2 - Y-coordinate of the endpoint of the segment. - * px - X-coordinate of the point. - * py - Y-coordinate of the point. - */ - relativeCcw: function(x1, y1, x2, y2, px, py) - { - x2 -= x1; - y2 -= y1; - px -= x1; - py -= y1; - var ccw = px * y2 - py * x2; - - if (ccw == 0.0) - { - ccw = px * x2 + py * y2; - - if (ccw > 0.0) - { - px -= x2; - py -= y2; - ccw = px * x2 + py * y2; - - if (ccw < 0.0) - { - ccw = 0.0; - } - } - } - - return (ccw < 0.0) ? -1 : ((ccw > 0.0) ? 1 : 0); - }, - - /** - * Function: animateChanges - * - * See <mxEffects.animateChanges>. This is for backwards compatibility and - * will be removed later. - */ - animateChanges: function(graph, changes) - { - // LATER: Deprecated, remove this function - mxEffects.animateChanges.apply(this, arguments); - }, - - /** - * Function: cascadeOpacity - * - * See <mxEffects.cascadeOpacity>. This is for backwards compatibility and - * will be removed later. - */ - cascadeOpacity: function(graph, cell, opacity) - { - mxEffects.cascadeOpacity.apply(this, arguments); - }, - - /** - * Function: fadeOut - * - * See <mxEffects.fadeOut>. This is for backwards compatibility and - * will be removed later. - */ - fadeOut: function(node, from, remove, step, delay, isEnabled) - { - mxEffects.fadeOut.apply(this, arguments); - }, - - /** - * Function: setOpacity - * - * Sets the opacity of the specified DOM node to the given value in %. - * - * Parameters: - * - * node - DOM node to set the opacity for. - * value - Opacity in %. Possible values are between 0 and 100. - */ - setOpacity: function(node, value) - { - if (mxUtils.isVml(node)) - { - if (value >= 100) - { - node.style.filter = null; - } - else - { - // TODO: Why is the division by 5 needed in VML? - node.style.filter = 'alpha(opacity=' + (value/5) + ')'; - } - } - else if (mxClient.IS_IE && (typeof(document.documentMode) === 'undefined' || document.documentMode < 9)) - { - if (value >= 100) - { - node.style.filter = null; - } - else - { - node.style.filter = 'alpha(opacity=' + value + ')'; - } - } - else - { - node.style.opacity = (value / 100); - } - }, - - /** - * Function: createImage - * - * Creates and returns an image (IMG node) or VML image (v:image) in IE6 in - * quirs mode. - * - * Parameters: - * - * src - URL that points to the image to be displayed. - */ - createImage: function(src) - { - var imageNode = null; - - if (mxClient.IS_IE6 && document.compatMode != 'CSS1Compat') - { - imageNode = document.createElement('v:image'); - imageNode.setAttribute('src', src); - imageNode.style.borderStyle = 'none'; - } - else - { - imageNode = document.createElement('img'); - imageNode.setAttribute('src', src); - imageNode.setAttribute('border', '0'); - } - - return imageNode; - }, - - /** - * Function: sortCells - * - * Sorts the given cells according to the order in the cell hierarchy. - * Ascending is optional and defaults to true. - */ - sortCells: function(cells, ascending) - { - ascending = (ascending != null) ? ascending : true; - var lookup = new mxDictionary(); - cells.sort(function(o1, o2) - { - var p1 = lookup.get(o1); - - if (p1 == null) - { - p1 = mxCellPath.create(o1).split(mxCellPath.PATH_SEPARATOR); - lookup.put(o1, p1); - } - - var p2 = lookup.get(o2); - - if (p2 == null) - { - p2 = mxCellPath.create(o2).split(mxCellPath.PATH_SEPARATOR); - lookup.put(o2, p2); - } - - var comp = mxCellPath.compare(p1, p2); - - return (comp == 0) ? 0 : (((comp > 0) == ascending) ? 1 : -1); - }); - - return cells; - }, - - /** - * Function: getStylename - * - * Returns the stylename in a style of the form [(stylename|key=value);] or - * an empty string if the given style does not contain a stylename. - * - * Parameters: - * - * style - String of the form [(stylename|key=value);]. - */ - getStylename: function(style) - { - if (style != null) - { - var pairs = style.split(';'); - var stylename = pairs[0]; - - if (stylename.indexOf('=') < 0) - { - return stylename; - } - } - - return ''; - }, - - /** - * Function: getStylenames - * - * Returns the stylenames in a style of the form [(stylename|key=value);] - * or an empty array if the given style does not contain any stylenames. - * - * Parameters: - * - * style - String of the form [(stylename|key=value);]. - */ - getStylenames: function(style) - { - var result = []; - - if (style != null) - { - var pairs = style.split(';'); - - for (var i = 0; i < pairs.length; i++) - { - if (pairs[i].indexOf('=') < 0) - { - result.push(pairs[i]); - } - } - } - - return result; - }, - - /** - * Function: indexOfStylename - * - * Returns the index of the given stylename in the given style. This - * returns -1 if the given stylename does not occur (as a stylename) in the - * given style, otherwise it returns the index of the first character. - */ - indexOfStylename: function(style, stylename) - { - if (style != null && stylename != null) - { - var tokens = style.split(';'); - var pos = 0; - - for (var i = 0; i < tokens.length; i++) - { - if (tokens[i] == stylename) - { - return pos; - } - - pos += tokens[i].length + 1; - } - } - - return -1; - }, - - /** - * Function: addStylename - * - * Adds the specified stylename to the given style if it does not already - * contain the stylename. - */ - addStylename: function(style, stylename) - { - if (mxUtils.indexOfStylename(style, stylename) < 0) - { - if (style == null) - { - style = ''; - } - else if (style.length > 0 && style.charAt(style.length - 1) != ';') - { - style += ';'; - } - - style += stylename; - } - - return style; - }, - - /** - * Function: removeStylename - * - * Removes all occurrences of the specified stylename in the given style - * and returns the updated style. Trailing semicolons are not preserved. - */ - removeStylename: function(style, stylename) - { - var result = []; - - if (style != null) - { - var tokens = style.split(';'); - - for (var i = 0; i < tokens.length; i++) - { - if (tokens[i] != stylename) - { - result.push(tokens[i]); - } - } - } - - return result.join(';'); - }, - - /** - * Function: removeAllStylenames - * - * Removes all stylenames from the given style and returns the updated - * style. - */ - removeAllStylenames: function(style) - { - var result = []; - - if (style != null) - { - var tokens = style.split(';'); - - for (var i = 0; i < tokens.length; i++) - { - // Keeps the key, value assignments - if (tokens[i].indexOf('=') >= 0) - { - result.push(tokens[i]); - } - } - } - - return result.join(';'); - }, - - /** - * Function: setCellStyles - * - * Assigns the value for the given key in the styles of the given cells, or - * removes the key from the styles if the value is null. - * - * Parameters: - * - * model - <mxGraphModel> to execute the transaction in. - * cells - Array of <mxCells> to be updated. - * key - Key of the style to be changed. - * value - New value for the given key. - */ - setCellStyles: function(model, cells, key, value) - { - if (cells != null && cells.length > 0) - { - model.beginUpdate(); - try - { - for (var i = 0; i < cells.length; i++) - { - if (cells[i] != null) - { - var style = mxUtils.setStyle( - model.getStyle(cells[i]), - key, value); - model.setStyle(cells[i], style); - } - } - } - finally - { - model.endUpdate(); - } - } - }, - - /** - * Function: setStyle - * - * Adds or removes the given key, value pair to the style and returns the - * new style. If value is null or zero length then the key is removed from - * the style. This is for cell styles, not for CSS styles. - * - * Parameters: - * - * style - String of the form [(stylename|key=value);]. - * key - Key of the style to be changed. - * value - New value for the given key. - */ - setStyle: function(style, key, value) - { - var isValue = value != null && (typeof(value.length) == 'undefined' || value.length > 0); - - if (style == null || style.length == 0) - { - if (isValue) - { - style = key+'='+value; - } - } - else - { - var index = style.indexOf(key+'='); - - if (index < 0) - { - if (isValue) - { - var sep = (style.charAt(style.length-1) == ';') ? '' : ';'; - style = style + sep + key+'='+value; - } - } - else - { - var tmp = (isValue) ? (key + '=' + value) : ''; - var cont = style.indexOf(';', index); - - if (!isValue) - { - cont++; - } - - style = style.substring(0, index) + tmp + - ((cont > index) ? style.substring(cont) : ''); - } - } - - return style; - }, - - /** - * Function: setCellStyleFlags - * - * Sets or toggles the flag bit for the given key in the cell's styles. - * If value is null then the flag is toggled. - * - * Example: - * - * (code) - * var cells = graph.getSelectionCells(); - * mxUtils.setCellStyleFlags(graph.model, - * cells, - * mxConstants.STYLE_FONTSTYLE, - * mxConstants.FONT_BOLD); - * (end) - * - * Toggles the bold font style. - * - * Parameters: - * - * model - <mxGraphModel> that contains the cells. - * cells - Array of <mxCells> to change the style for. - * key - Key of the style to be changed. - * flag - Integer for the bit to be changed. - * value - Optional boolean value for the flag. - */ - setCellStyleFlags: function(model, cells, key, flag, value) - { - if (cells != null && cells.length > 0) - { - model.beginUpdate(); - try - { - for (var i = 0; i < cells.length; i++) - { - if (cells[i] != null) - { - var style = mxUtils.setStyleFlag( - model.getStyle(cells[i]), - key, flag, value); - model.setStyle(cells[i], style); - } - } - } - finally - { - model.endUpdate(); - } - } - }, - - /** - * Function: setStyleFlag - * - * Sets or removes the given key from the specified style and returns the - * new style. If value is null then the flag is toggled. - * - * Parameters: - * - * style - String of the form [(stylename|key=value);]. - * key - Key of the style to be changed. - * flag - Integer for the bit to be changed. - * value - Optional boolean value for the given flag. - */ - setStyleFlag: function(style, key, flag, value) - { - if (style == null || style.length == 0) - { - if (value || value == null) - { - style = key+'='+flag; - } - else - { - style = key+'=0'; - } - } - else - { - var index = style.indexOf(key+'='); - - if (index < 0) - { - var sep = (style.charAt(style.length-1) == ';') ? '' : ';'; - - if (value || value == null) - { - style = style + sep + key + '=' + flag; - } - else - { - style = style + sep + key + '=0'; - } - } - else - { - var cont = style.indexOf(';', index); - var tmp = ''; - - if (cont < 0) - { - tmp = style.substring(index+key.length+1); - } - else - { - tmp = style.substring(index+key.length+1, cont); - } - - if (value == null) - { - tmp = parseInt(tmp) ^ flag; - } - else if (value) - { - tmp = parseInt(tmp) | flag; - } - else - { - tmp = parseInt(tmp) & ~flag; - } - - style = style.substring(0, index) + key + '=' + tmp + - ((cont >= 0) ? style.substring(cont) : ''); - } - } - - return style; - }, - - /** - * Function: getSizeForString - * - * Returns an <mxRectangle> with the size (width and height in pixels) of - * the given string. The string may contain HTML markup. Newlines should be - * converted to <br> before calling this method. - * - * Example: - * - * (code) - * var label = graph.getLabel(cell).replace(/\n/g, "<br>"); - * var size = graph.getSizeForString(label); - * (end) - * - * Parameters: - * - * text - String whose size should be returned. - * fontSize - Integer that specifies the font size in pixels. Default is - * <mxConstants.DEFAULT_FONTSIZE>. - * fontFamily - String that specifies the name of the font family. Default - * is <mxConstants.DEFAULT_FONTFAMILY>. - */ - getSizeForString: function(text, fontSize, fontFamily) - { - var div = document.createElement('div'); - - // Sets the font size and family if non-default - div.style.fontSize = (fontSize || mxConstants.DEFAULT_FONTSIZE) + 'px'; - div.style.fontFamily = fontFamily || mxConstants.DEFAULT_FONTFAMILY; - - // Disables block layout and outside wrapping and hides the div - div.style.position = 'absolute'; - div.style.display = 'inline'; - div.style.visibility = 'hidden'; - - // Adds the text and inserts into DOM for updating of size - div.innerHTML = text; - document.body.appendChild(div); - - // Gets the size and removes from DOM - var size = new mxRectangle(0, 0, div.offsetWidth, div.offsetHeight); - document.body.removeChild(div); - - return size; - }, - - /** - * Function: getViewXml - */ - getViewXml: function(graph, scale, cells, x0, y0) - { - x0 = (x0 != null) ? x0 : 0; - y0 = (y0 != null) ? y0 : 0; - scale = (scale != null) ? scale : 1; - - if (cells == null) - { - var model = graph.getModel(); - cells = [model.getRoot()]; - } - - var view = graph.getView(); - var result = null; - - // Disables events on the view - var eventsEnabled = view.isEventsEnabled(); - view.setEventsEnabled(false); - - // Workaround for label bounds not taken into account for image export. - // Creates a temporary draw pane which is used for rendering the text. - // Text rendering is required for finding the bounds of the labels. - var drawPane = view.drawPane; - var overlayPane = view.overlayPane; - - if (graph.dialect == mxConstants.DIALECT_SVG) - { - view.drawPane = document.createElementNS(mxConstants.NS_SVG, 'g'); - view.canvas.appendChild(view.drawPane); - - // Redirects cell overlays into temporary container - view.overlayPane = document.createElementNS(mxConstants.NS_SVG, 'g'); - view.canvas.appendChild(view.overlayPane); - } - else - { - view.drawPane = view.drawPane.cloneNode(false); - view.canvas.appendChild(view.drawPane); - - // Redirects cell overlays into temporary container - view.overlayPane = view.overlayPane.cloneNode(false); - view.canvas.appendChild(view.overlayPane); - } - - // Resets the translation - var translate = view.getTranslate(); - view.translate = new mxPoint(x0, y0); - - // Creates the temporary cell states in the view - var temp = new mxTemporaryCellStates(graph.getView(), scale, cells); - - try - { - var enc = new mxCodec(); - result = enc.encode(graph.getView()); - } - finally - { - temp.destroy(); - view.translate = translate; - view.canvas.removeChild(view.drawPane); - view.canvas.removeChild(view.overlayPane); - view.drawPane = drawPane; - view.overlayPane = overlayPane; - view.setEventsEnabled(eventsEnabled); - } - - return result; - }, - - /** - * Function: getScaleForPageCount - * - * Returns the scale to be used for printing the graph with the given - * bounds across the specifies number of pages with the given format. The - * scale is always computed such that it given the given amount or fewer - * pages in the print output. See <mxPrintPreview> for an example. - * - * Parameters: - * - * pageCount - Specifies the number of pages in the print output. - * graph - <mxGraph> that should be printed. - * pageFormat - Optional <mxRectangle> that specifies the page format. - * Default is <mxConstants.PAGE_FORMAT_A4_PORTRAIT>. - * border - The border along each side of every page. - */ - getScaleForPageCount: function(pageCount, graph, pageFormat, border) - { - if (pageCount < 1) - { - // We can't work with less than 1 page, return no scale - // change - return 1; - } - - pageFormat = (pageFormat != null) ? pageFormat : mxConstants.PAGE_FORMAT_A4_PORTRAIT; - border = (border != null) ? border : 0; - - var availablePageWidth = pageFormat.width - (border * 2); - var availablePageHeight = pageFormat.height - (border * 2); - - // Work out the number of pages required if the - // graph is not scaled. - var graphBounds = graph.getGraphBounds().clone(); - var sc = graph.getView().getScale(); - graphBounds.width /= sc; - graphBounds.height /= sc; - var graphWidth = graphBounds.width; - var graphHeight = graphBounds.height; - - var scale = 1; - - // The ratio of the width/height for each printer page - var pageFormatAspectRatio = availablePageWidth / availablePageHeight; - // The ratio of the width/height for the graph to be printer - var graphAspectRatio = graphWidth / graphHeight; - - // The ratio of horizontal pages / vertical pages for this - // graph to maintain its aspect ratio on this page format - var pagesAspectRatio = graphAspectRatio / pageFormatAspectRatio; - - // Factor the square root of the page count up and down - // by the pages aspect ratio to obtain a horizontal and - // vertical page count that adds up to the page count - // and has the correct aspect ratio - var pageRoot = Math.sqrt(pageCount); - var pagesAspectRatioSqrt = Math.sqrt(pagesAspectRatio); - var numRowPages = pageRoot * pagesAspectRatioSqrt; - var numColumnPages = pageRoot / pagesAspectRatioSqrt; - - // These value are rarely more than 2 rounding downs away from - // a total that meets the page count. In cases of one being less - // than 1 page, the other value can be too high and take more iterations - // In this case, just change that value to be the page count, since - // we know the other value is 1 - if (numRowPages < 1 && numColumnPages > pageCount) - { - var scaleChange = numColumnPages / pageCount; - numColumnPages = pageCount; - numRowPages /= scaleChange; - } - - if (numColumnPages < 1 && numRowPages > pageCount) - { - var scaleChange = numRowPages / pageCount; - numRowPages = pageCount; - numColumnPages /= scaleChange; - } - - var currentTotalPages = Math.ceil(numRowPages) * Math.ceil(numColumnPages); - - var numLoops = 0; - - // Iterate through while the rounded up number of pages comes to - // a total greater than the required number - while (currentTotalPages > pageCount) - { - // Round down the page count (rows or columns) that is - // closest to its next integer down in percentage terms. - // i.e. Reduce the page total by reducing the total - // page area by the least possible amount - - var roundRowDownProportion = Math.floor(numRowPages) / numRowPages; - var roundColumnDownProportion = Math.floor(numColumnPages) / numColumnPages; - - // If the round down proportion is, work out the proportion to - // round down to 1 page less - if (roundRowDownProportion == 1) - { - roundRowDownProportion = Math.floor(numRowPages-1) / numRowPages; - } - if (roundColumnDownProportion == 1) - { - roundColumnDownProportion = Math.floor(numColumnPages-1) / numColumnPages; - } - - // Check which rounding down is smaller, but in the case of very small roundings - // try the other dimension instead - var scaleChange = 1; - - // Use the higher of the two values - if (roundRowDownProportion > roundColumnDownProportion) - { - scaleChange = roundRowDownProportion; - } - else - { - scaleChange = roundColumnDownProportion; - } - - numRowPages = numRowPages * scaleChange; - numColumnPages = numColumnPages * scaleChange; - currentTotalPages = Math.ceil(numRowPages) * Math.ceil(numColumnPages); - - numLoops++; - - if (numLoops > 10) - { - break; - } - } - - // Work out the scale from the number of row pages required - // The column pages will give the same value - var posterWidth = availablePageWidth * numRowPages; - scale = posterWidth / graphWidth; - - // Allow for rounding errors - return scale * 0.99999; - }, - - /** - * Function: show - * - * Copies the styles and the markup from the graph's container into the - * given document and removes all cursor styles. The document is returned. - * - * This function should be called from within the document with the graph. - * If you experience problems with missing stylesheets in IE then try adding - * the domain to the trusted sites. - * - * Parameters: - * - * graph - <mxGraph> to be copied. - * doc - Document where the new graph is created. - * x0 - X-coordinate of the graph view origin. Default is 0. - * y0 - Y-coordinate of the graph view origin. Default is 0. - */ - show: function(graph, doc, x0, y0) - { - x0 = (x0 != null) ? x0 : 0; - y0 = (y0 != null) ? y0 : 0; - - if (doc == null) - { - var wnd = window.open(); - doc = wnd.document; - } - else - { - doc.open(); - } - - var bounds = graph.getGraphBounds(); - var dx = -bounds.x + x0; - var dy = -bounds.y + y0; - - // Needs a special way of creating the page so that no click is required - // to refresh the contents after the external CSS styles have been loaded. - // To avoid a click or programmatic refresh, the styleSheets[].cssText - // property is copied over from the original document. - if (mxClient.IS_IE) - { - var html = '<html>'; - html += '<head>'; - - var base = document.getElementsByTagName('base'); - - for (var i = 0; i < base.length; i++) - { - html += base[i].outerHTML; - } - - html += '<style>'; - - // Copies the stylesheets without having to load them again - for (var i = 0; i < document.styleSheets.length; i++) - { - try - { - html += document.styleSheets(i).cssText; - } - catch (e) - { - // ignore security exception - } - } - - html += '</style>'; - - html += '</head>'; - html += '<body>'; - - // Copies the contents of the graph container - html += graph.container.innerHTML; - - html += '</body>'; - html += '<html>'; - - doc.writeln(html); - doc.close(); - - // Makes sure the inner container is on the top, left - var node = doc.body.getElementsByTagName('DIV')[0]; - - if (node != null) - { - node.style.position = 'absolute'; - node.style.left = dx + 'px'; - node.style.top = dy + 'px'; - } - } - else - { - doc.writeln('<html'); - doc.writeln('<head>'); - - var base = document.getElementsByTagName('base'); - - for (var i=0; i<base.length; i++) - { - doc.writeln(mxUtils.getOuterHtml(base[i])); - } - - var links = document.getElementsByTagName('link'); - - for (var i=0; i<links.length; i++) - { - doc.writeln(mxUtils.getOuterHtml(links[i])); - } - - var styles = document.getElementsByTagName('style'); - - for (var i=0; i<styles.length; i++) - { - doc.writeln(mxUtils.getOuterHtml(styles[i])); - } - - doc.writeln('</head>'); - doc.writeln('</html>'); - doc.close(); - - // Workaround for FF2 which has no body element in a document where - // the body has been added using document.write. - if (doc.body == null) - { - doc.documentElement.appendChild(doc.createElement('body')); - } - - // Workaround for missing scrollbars in FF - doc.body.style.overflow = 'auto'; - - var node = graph.container.firstChild; - - while (node != null) - { - var clone = node.cloneNode(true); - doc.body.appendChild(clone); - node = node.nextSibling; - } - - // Shifts negative coordinates into visible space - var node = doc.getElementsByTagName('g')[0]; - - if (node != null) - { - node.setAttribute('transform', 'translate(' + dx + ',' + dy + ')'); - - // Updates the size of the SVG container - var root = node.ownerSVGElement; - root.setAttribute('width', bounds.width + Math.max(bounds.x, 0) + 3); - root.setAttribute('height', bounds.height + Math.max(bounds.y, 0) + 3); - } - } - - mxUtils.removeCursors(doc.body); - - return doc; - }, - - /** - * Function: printScreen - * - * Prints the specified graph using a new window and the built-in print - * dialog. - * - * This function should be called from within the document with the graph. - * - * Parameters: - * - * graph - <mxGraph> to be printed. - */ - printScreen: function(graph) - { - var wnd = window.open(); - mxUtils.show(graph, wnd.document); - - var print = function() - { - wnd.focus(); - wnd.print(); - wnd.close(); - }; - - // Workaround for Google Chrome which needs a bit of a - // delay in order to render the SVG contents - if (mxClient.IS_GC) - { - wnd.setTimeout(print, 500); - } - else - { - print(); - } - }, - - /** - * Function: popup - * - * Shows the specified text content in a new <mxWindow> or a new browser - * window if isInternalWindow is false. - * - * Parameters: - * - * content - String that specifies the text to be displayed. - * isInternalWindow - Optional boolean indicating if an mxWindow should be - * used instead of a new browser window. Default is false. - */ - popup: function(content, isInternalWindow) - { - if (isInternalWindow) - { - var div = document.createElement('div'); - - div.style.overflow = 'scroll'; - div.style.width = '636px'; - div.style.height = '460px'; - - var pre = document.createElement('pre'); - pre.innerHTML = mxUtils.htmlEntities(content, false). - replace(/\n/g,'<br>').replace(/ /g, ' '); - - div.appendChild(pre); - - var w = document.body.clientWidth; - var h = (document.body.clientHeight || document.documentElement.clientHeight); - var wnd = new mxWindow('Popup Window', div, - w/2-320, h/2-240, 640, 480, false, true); - - wnd.setClosable(true); - wnd.setVisible(true); - } - else - { - // Wraps up the XML content in a textarea - if (mxClient.IS_NS) - { - var wnd = window.open(); - wnd.document.writeln('<pre>'+mxUtils.htmlEntities(content)+'</pre'); - wnd.document.close(); - } - else - { - var wnd = window.open(); - var pre = wnd.document.createElement('pre'); - pre.innerHTML = mxUtils.htmlEntities(content, false). - replace(/\n/g,'<br>').replace(/ /g, ' '); - wnd.document.body.appendChild(pre); - } - } - }, - - /** - * Function: alert - * - * Displayss the given alert in a new dialog. This implementation uses the - * built-in alert function. This is used to display validation errors when - * connections cannot be changed or created. - * - * Parameters: - * - * message - String specifying the message to be displayed. - */ - alert: function(message) - { - alert(message); - }, - - /** - * Function: prompt - * - * Displays the given message in a prompt dialog. This implementation uses - * the built-in prompt function. - * - * Parameters: - * - * message - String specifying the message to be displayed. - * defaultValue - Optional string specifying the default value. - */ - prompt: function(message, defaultValue) - { - return prompt(message, defaultValue); - }, - - /** - * Function: confirm - * - * Displays the given message in a confirm dialog. This implementation uses - * the built-in confirm function. - * - * Parameters: - * - * message - String specifying the message to be displayed. - */ - confirm: function(message) - { - return confirm(message); - }, - - /** - * Function: error - * - * Displays the given error message in a new <mxWindow> of the given width. - * If close is true then an additional close button is added to the window. - * The optional icon specifies the icon to be used for the window. Default - * is <mxUtils.errorImage>. - * - * Parameters: - * - * message - String specifying the message to be displayed. - * width - Integer specifying the width of the window. - * close - Optional boolean indicating whether to add a close button. - * icon - Optional icon for the window decoration. - */ - error: function(message, width, close, icon) - { - var div = document.createElement('div'); - div.style.padding = '20px'; - - var img = document.createElement('img'); - img.setAttribute('src', icon || mxUtils.errorImage); - img.setAttribute('valign', 'bottom'); - img.style.verticalAlign = 'middle'; - div.appendChild(img); - - div.appendChild(document.createTextNode('\u00a0')); // - div.appendChild(document.createTextNode('\u00a0')); // - div.appendChild(document.createTextNode('\u00a0')); // - mxUtils.write(div, message); - - var w = document.body.clientWidth; - var h = (document.body.clientHeight || document.documentElement.clientHeight); - var warn = new mxWindow(mxResources.get(mxUtils.errorResource) || - mxUtils.errorResource, div, (w-width)/2, h/4, width, null, - false, true); - - if (close) - { - mxUtils.br(div); - - var tmp = document.createElement('p'); - var button = document.createElement('button'); - - if (mxClient.IS_IE) - { - button.style.cssText = 'float:right'; - } - else - { - button.setAttribute('style', 'float:right'); - } - - mxEvent.addListener(button, 'click', function(evt) - { - warn.destroy(); - }); - - mxUtils.write(button, mxResources.get(mxUtils.closeResource) || - mxUtils.closeResource); - - tmp.appendChild(button); - div.appendChild(tmp); - - mxUtils.br(div); - - warn.setClosable(true); - } - - warn.setVisible(true); - - return warn; - }, - - /** - * Function: makeDraggable - * - * Configures the given DOM element to act as a drag source for the - * specified graph. Returns a a new <mxDragSource>. If - * <mxDragSource.guideEnabled> is enabled then the x and y arguments must - * be used in funct to match the preview location. - * - * Example: - * - * (code) - * var funct = function(graph, evt, cell, x, y) - * { - * if (graph.canImportCell(cell)) - * { - * var parent = graph.getDefaultParent(); - * var vertex = null; - * - * graph.getModel().beginUpdate(); - * try - * { - * vertex = graph.insertVertex(parent, null, 'Hello', x, y, 80, 30); - * } - * finally - * { - * graph.getModel().endUpdate(); - * } - * - * graph.setSelectionCell(vertex); - * } - * } - * - * var img = document.createElement('img'); - * img.setAttribute('src', 'editors/images/rectangle.gif'); - * img.style.position = 'absolute'; - * img.style.left = '0px'; - * img.style.top = '0px'; - * img.style.width = '16px'; - * img.style.height = '16px'; - * - * var dragImage = img.cloneNode(true); - * dragImage.style.width = '32px'; - * dragImage.style.height = '32px'; - * mxUtils.makeDraggable(img, graph, funct, dragImage); - * document.body.appendChild(img); - * (end) - * - * Parameters: - * - * element - DOM element to make draggable. - * graphF - <mxGraph> that acts as the drop target or a function that takes a - * mouse event and returns the current <mxGraph>. - * funct - Function to execute on a successful drop. - * dragElement - Optional DOM node to be used for the drag preview. - * dx - Optional horizontal offset between the cursor and the drag - * preview. - * dy - Optional vertical offset between the cursor and the drag - * preview. - * autoscroll - Optional boolean that specifies if autoscroll should be - * used. Default is mxGraph.autoscroll. - * scalePreview - Optional boolean that specifies if the preview element - * should be scaled according to the graph scale. If this is true, then - * the offsets will also be scaled. Default is false. - * highlightDropTargets - Optional boolean that specifies if dropTargets - * should be highlighted. Default is true. - * getDropTarget - Optional function to return the drop target for a given - * location (x, y). Default is mxGraph.getCellAt. - */ - makeDraggable: function(element, graphF, funct, dragElement, dx, dy, autoscroll, - scalePreview, highlightDropTargets, getDropTarget) - { - var dragSource = new mxDragSource(element, funct); - dragSource.dragOffset = new mxPoint((dx != null) ? dx : 0, - (dy != null) ? dy : mxConstants.TOOLTIP_VERTICAL_OFFSET); - dragSource.autoscroll = autoscroll; - - // Cannot enable this by default. This needs to be enabled in the caller - // if the funct argument uses the new x- and y-arguments. - dragSource.setGuidesEnabled(false); - - if (highlightDropTargets != null) - { - dragSource.highlightDropTargets = highlightDropTargets; - } - - // Overrides function to find drop target cell - if (getDropTarget != null) - { - dragSource.getDropTarget = getDropTarget; - } - - // Overrides function to get current graph - dragSource.getGraphForEvent = function(evt) - { - return (typeof(graphF) == 'function') ? graphF(evt) : graphF; - }; - - // Translates switches into dragSource customizations - if (dragElement != null) - { - dragSource.createDragElement = function() - { - return dragElement.cloneNode(true); - }; - - if (scalePreview) - { - dragSource.createPreviewElement = function(graph) - { - var elt = dragElement.cloneNode(true); - - var w = parseInt(elt.style.width); - var h = parseInt(elt.style.height); - elt.style.width = Math.round(w * graph.view.scale) + 'px'; - elt.style.height = Math.round(h * graph.view.scale) + 'px'; - - return elt; - }; - } - } - - return dragSource; - } - -}; diff --git a/src/js/util/mxWindow.js b/src/js/util/mxWindow.js deleted file mode 100644 index e4cbcfc..0000000 --- a/src/js/util/mxWindow.js +++ /dev/null @@ -1,1065 +0,0 @@ -/** - * $Id: mxWindow.js,v 1.67 2012-10-11 17:18:51 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -/** - * Class: mxWindow - * - * Basic window inside a document. - * - * Examples: - * - * Creating a simple window. - * - * (code) - * var tb = document.createElement('div'); - * var wnd = new mxWindow('Title', tb, 100, 100, 200, 200, true, true); - * wnd.setVisible(true); - * (end) - * - * Creating a window that contains an iframe. - * - * (code) - * var frame = document.createElement('iframe'); - * frame.setAttribute('width', '192px'); - * frame.setAttribute('height', '172px'); - * frame.setAttribute('src', 'http://www.example.com/'); - * frame.style.backgroundColor = 'white'; - * - * var w = document.body.clientWidth; - * var h = (document.body.clientHeight || document.documentElement.clientHeight); - * var wnd = new mxWindow('Title', frame, (w-200)/2, (h-200)/3, 200, 200); - * wnd.setVisible(true); - * (end) - * - * To limit the movement of a window, eg. to keep it from being moved beyond - * the top, left corner the following method can be overridden (recommended): - * - * (code) - * wnd.setLocation = function(x, y) - * { - * x = Math.max(0, x); - * y = Math.max(0, y); - * mxWindow.prototype.setLocation.apply(this, arguments); - * }; - * (end) - * - * Or the following event handler can be used: - * - * (code) - * wnd.addListener(mxEvent.MOVE, function(e) - * { - * wnd.setLocation(Math.max(0, wnd.getX()), Math.max(0, wnd.getY())); - * }); - * (end) - * - * Event: mxEvent.MOVE_START - * - * Fires before the window is moved. The <code>event</code> property contains - * the corresponding mouse event. - * - * Event: mxEvent.MOVE - * - * Fires while the window is being moved. The <code>event</code> property - * contains the corresponding mouse event. - * - * Event: mxEvent.MOVE_END - * - * Fires after the window is moved. The <code>event</code> property contains - * the corresponding mouse event. - * - * Event: mxEvent.RESIZE_START - * - * Fires before the window is resized. The <code>event</code> property contains - * the corresponding mouse event. - * - * Event: mxEvent.RESIZE - * - * Fires while the window is being resized. The <code>event</code> property - * contains the corresponding mouse event. - * - * Event: mxEvent.RESIZE_END - * - * Fires after the window is resized. The <code>event</code> property contains - * the corresponding mouse event. - * - * Event: mxEvent.MAXIMIZE - * - * Fires after the window is maximized. The <code>event</code> property - * contains the corresponding mouse event. - * - * Event: mxEvent.MINIMIZE - * - * Fires after the window is minimized. The <code>event</code> property - * contains the corresponding mouse event. - * - * Event: mxEvent.NORMALIZE - * - * Fires after the window is normalized, that is, it returned from - * maximized or minimized state. The <code>event</code> property contains the - * corresponding mouse event. - * - * Event: mxEvent.ACTIVATE - * - * Fires after a window is activated. The <code>previousWindow</code> property - * contains the previous window. The event sender is the active window. - * - * Event: mxEvent.SHOW - * - * Fires after the window is shown. This event has no properties. - * - * Event: mxEvent.HIDE - * - * Fires after the window is hidden. This event has no properties. - * - * Event: mxEvent.CLOSE - * - * Fires before the window is closed. The <code>event</code> property contains - * the corresponding mouse event. - * - * Event: mxEvent.DESTROY - * - * Fires before the window is destroyed. This event has no properties. - * - * Constructor: mxWindow - * - * Constructs a new window with the given dimension and title to display - * the specified content. The window elements use the given style as a - * prefix for the classnames of the respective window elements, namely, - * the window title and window pane. The respective postfixes are appended - * to the given stylename as follows: - * - * style - Base style for the window. - * style+Title - Style for the window title. - * style+Pane - Style for the window pane. - * - * The default value for style is mxWindow, resulting in the following - * classnames for the window elements: mxWindow, mxWindowTitle and - * mxWindowPane. - * - * If replaceNode is given then the window replaces the given DOM node in - * the document. - * - * Parameters: - * - * title - String that represents the title of the new window. - * content - DOM node that is used as the window content. - * x - X-coordinate of the window location. - * y - Y-coordinate of the window location. - * width - Width of the window. - * height - Optional height of the window. Default is to match the height - * of the content at the specified width. - * minimizable - Optional boolean indicating if the window is minimizable. - * Default is true. - * movable - Optional boolean indicating if the window is movable. Default - * is true. - * replaceNode - Optional DOM node that the window should replace. - * style - Optional base classname for the window elements. Default is - * mxWindow. - */ -function mxWindow(title, content, x, y, width, height, minimizable, movable, replaceNode, style) -{ - if (content != null) - { - minimizable = (minimizable != null) ? minimizable : true; - this.content = content; - this.init(x, y, width, height, style); - - this.installMaximizeHandler(); - this.installMinimizeHandler(); - this.installCloseHandler(); - this.setMinimizable(minimizable); - this.setTitle(title); - - if (movable == null || movable) - { - this.installMoveHandler(); - } - - if (replaceNode != null && replaceNode.parentNode != null) - { - replaceNode.parentNode.replaceChild(this.div, replaceNode); - } - else - { - document.body.appendChild(this.div); - } - } -}; - -/** - * Extends mxEventSource. - */ -mxWindow.prototype = new mxEventSource(); -mxWindow.prototype.constructor = mxWindow; - -/** - * Variable: closeImage - * - * URL of the image to be used for the close icon in the titlebar. - */ -mxWindow.prototype.closeImage = mxClient.imageBasePath + '/close.gif'; - -/** - * Variable: minimizeImage - * - * URL of the image to be used for the minimize icon in the titlebar. - */ -mxWindow.prototype.minimizeImage = mxClient.imageBasePath + '/minimize.gif'; - -/** - * Variable: normalizeImage - * - * URL of the image to be used for the normalize icon in the titlebar. - */ -mxWindow.prototype.normalizeImage = mxClient.imageBasePath + '/normalize.gif'; - -/** - * Variable: maximizeImage - * - * URL of the image to be used for the maximize icon in the titlebar. - */ -mxWindow.prototype.maximizeImage = mxClient.imageBasePath + '/maximize.gif'; - -/** - * Variable: normalizeImage - * - * URL of the image to be used for the resize icon. - */ -mxWindow.prototype.resizeImage = mxClient.imageBasePath + '/resize.gif'; - -/** - * Variable: visible - * - * Boolean flag that represents the visible state of the window. - */ -mxWindow.prototype.visible = false; - -/** - * Variable: content - * - * Reference to the DOM node that represents the window content. - */ -mxWindow.prototype.content = false; - -/** - * Variable: minimumSize - * - * <mxRectangle> that specifies the minimum width and height of the window. - * Default is (50, 40). - */ -mxWindow.prototype.minimumSize = new mxRectangle(0, 0, 50, 40); - -/** - * Variable: title - * - * Reference to the DOM node (TD) that contains the title. - */ -mxWindow.prototype.title = false; - -/** - * Variable: content - * - * Reference to the DOM node that represents the window content. - */ -mxWindow.prototype.content = false; - -/** - * Variable: destroyOnClose - * - * Specifies if the window should be destroyed when it is closed. If this - * is false then the window is hidden using <setVisible>. Default is true. - */ -mxWindow.prototype.destroyOnClose = true; - -/** - * Function: init - * - * Initializes the DOM tree that represents the window. - */ -mxWindow.prototype.init = function(x, y, width, height, style) -{ - style = (style != null) ? style : 'mxWindow'; - - this.div = document.createElement('div'); - this.div.className = style; - this.div.style.left = x+'px'; - this.div.style.top = y+'px'; - this.table = document.createElement('table'); - this.table.className = style; - - // Workaround for table size problems in FF - if (width != null) - { - if (!mxClient.IS_IE) - { - this.div.style.width = width+'px'; - } - - this.table.style.width = width+'px'; - } - - if (height != null) - { - if (!mxClient.IS_IE) - { - this.div.style.height = height+'px'; - } - - this.table.style.height = height+'px'; - } - - // Creates title row - var tbody = document.createElement('tbody'); - var tr = document.createElement('tr'); - - this.title = document.createElement('td'); - this.title.className = style+'Title'; - tr.appendChild(this.title); - tbody.appendChild(tr); - - // Creates content row and table cell - tr = document.createElement('tr'); - this.td = document.createElement('td'); - this.td.className = style+'Pane'; - - this.contentWrapper = document.createElement('div'); - this.contentWrapper.className = style+'Pane'; - this.contentWrapper.style.width = '100%'; - this.contentWrapper.appendChild(this.content); - - // Workaround for div around div restricts height - // of inner div if outerdiv has hidden overflow - if (mxClient.IS_IE || this.content.nodeName.toUpperCase() != 'DIV') - { - this.contentWrapper.style.height = '100%'; - } - - // Puts all content into the DOM - this.td.appendChild(this.contentWrapper); - tr.appendChild(this.td); - tbody.appendChild(tr); - this.table.appendChild(tbody); - this.div.appendChild(this.table); - - // Puts the window on top of other windows when clicked - var activator = mxUtils.bind(this, function(evt) - { - this.activate(); - }); - - var md = (mxClient.IS_TOUCH) ? 'touchstart' : 'mousedown'; - mxEvent.addListener(this.title, md, activator); - mxEvent.addListener(this.table, md, activator); - - this.hide(); -}; - -/** - * Function: setTitle - * - * Sets the window title to the given string. HTML markup inside the title - * will be escaped. - */ -mxWindow.prototype.setTitle = function(title) -{ - // Removes all text content nodes (normally just one) - var child = this.title.firstChild; - - while (child != null) - { - var next = child.nextSibling; - - if (child.nodeType == mxConstants.NODETYPE_TEXT) - { - child.parentNode.removeChild(child); - } - - child = next; - } - - mxUtils.write(this.title, title || ''); -}; - -/** - * Function: setScrollable - * - * Sets if the window contents should be scrollable. - */ -mxWindow.prototype.setScrollable = function(scrollable) -{ - // Workaround for hang in Presto 2.5.22 (Opera 10.5) - if (navigator.userAgent.indexOf('Presto/2.5') < 0) - { - if (scrollable) - { - this.contentWrapper.style.overflow = 'auto'; - } - else - { - this.contentWrapper.style.overflow = 'hidden'; - } - } -}; - -/** - * Function: activate - * - * Puts the window on top of all other windows. - */ -mxWindow.prototype.activate = function() -{ - if (mxWindow.activeWindow != this) - { - var style = mxUtils.getCurrentStyle(this.getElement()); - var index = (style != null) ? style.zIndex : 3; - - if (mxWindow.activeWindow) - { - var elt = mxWindow.activeWindow.getElement(); - - if (elt != null && elt.style != null) - { - elt.style.zIndex = index; - } - } - - var previousWindow = mxWindow.activeWindow; - this.getElement().style.zIndex = parseInt(index) + 1; - mxWindow.activeWindow = this; - - this.fireEvent(new mxEventObject(mxEvent.ACTIVATE, 'previousWindow', previousWindow)); - } -}; - -/** - * Function: getElement - * - * Returuns the outermost DOM node that makes up the window. - */ -mxWindow.prototype.getElement = function() -{ - return this.div; -}; - -/** - * Function: fit - * - * Makes sure the window is inside the client area of the window. - */ -mxWindow.prototype.fit = function() -{ - mxUtils.fit(this.div); -}; - -/** - * Function: isResizable - * - * Returns true if the window is resizable. - */ -mxWindow.prototype.isResizable = function() -{ - if (this.resize != null) - { - return this.resize.style.display != 'none'; - } - - return false; -}; - -/** - * Function: setResizable - * - * Sets if the window should be resizable. - */ -mxWindow.prototype.setResizable = function(resizable) -{ - if (resizable) - { - if (this.resize == null) - { - this.resize = document.createElement('img'); - this.resize.style.position = 'absolute'; - this.resize.style.bottom = '2px'; - this.resize.style.right = '2px'; - - this.resize.setAttribute('src', mxClient.imageBasePath + '/resize.gif'); - this.resize.style.cursor = 'nw-resize'; - - var md = (mxClient.IS_TOUCH) ? 'touchstart' : 'mousedown'; - var mm = (mxClient.IS_TOUCH) ? 'touchmove' : 'mousemove'; - var mu = (mxClient.IS_TOUCH) ? 'touchend' : 'mouseup'; - - mxEvent.addListener(this.resize, md, mxUtils.bind(this, function(evt) - { - this.activate(); - var startX = mxEvent.getClientX(evt); - var startY = mxEvent.getClientY(evt); - var width = this.div.offsetWidth; - var height = this.div.offsetHeight; - - // Adds a temporary pair of listeners to intercept - // the gesture event in the document - var dragHandler = mxUtils.bind(this, function(evt) - { - var dx = mxEvent.getClientX(evt) - startX; - var dy = mxEvent.getClientY(evt) - startY; - - this.setSize(width + dx, height + dy); - - this.fireEvent(new mxEventObject(mxEvent.RESIZE, 'event', evt)); - mxEvent.consume(evt); - }); - - var dropHandler = mxUtils.bind(this, function(evt) - { - mxEvent.removeListener(document, mm, dragHandler); - mxEvent.removeListener(document, mu, dropHandler); - - this.fireEvent(new mxEventObject(mxEvent.RESIZE_END, 'event', evt)); - mxEvent.consume(evt); - }); - - mxEvent.addListener(document, mm, dragHandler); - mxEvent.addListener(document, mu, dropHandler); - - this.fireEvent(new mxEventObject(mxEvent.RESIZE_START, 'event', evt)); - mxEvent.consume(evt); - })); - - this.div.appendChild(this.resize); - } - else - { - this.resize.style.display = 'inline'; - } - } - else if (this.resize != null) - { - this.resize.style.display = 'none'; - } -}; - -/** - * Function: setSize - * - * Sets the size of the window. - */ -mxWindow.prototype.setSize = function(width, height) -{ - width = Math.max(this.minimumSize.width, width); - height = Math.max(this.minimumSize.height, height); - - // Workaround for table size problems in FF - if (!mxClient.IS_IE) - { - this.div.style.width = width + 'px'; - this.div.style.height = height + 'px'; - } - - this.table.style.width = width + 'px'; - this.table.style.height = height + 'px'; - - if (!mxClient.IS_IE) - { - this.contentWrapper.style.height = - (this.div.offsetHeight - this.title.offsetHeight - 2)+'px'; - } -}; - -/** - * Function: setMinimizable - * - * Sets if the window is minimizable. - */ -mxWindow.prototype.setMinimizable = function(minimizable) -{ - this.minimize.style.display = (minimizable) ? '' : 'none'; -}; - -/** - * Function: getMinimumSize - * - * Returns an <mxRectangle> that specifies the size for the minimized window. - * A width or height of 0 means keep the existing width or height. This - * implementation returns the height of the window title and keeps the width. - */ -mxWindow.prototype.getMinimumSize = function() -{ - return new mxRectangle(0, 0, 0, this.title.offsetHeight); -}; - -/** - * Function: installMinimizeHandler - * - * Installs the event listeners required for minimizing the window. - */ -mxWindow.prototype.installMinimizeHandler = function() -{ - this.minimize = document.createElement('img'); - - this.minimize.setAttribute('src', this.minimizeImage); - this.minimize.setAttribute('align', 'right'); - this.minimize.setAttribute('title', 'Minimize'); - this.minimize.style.cursor = 'pointer'; - this.minimize.style.marginRight = '1px'; - this.minimize.style.display = 'none'; - - this.title.appendChild(this.minimize); - - var minimized = false; - var maxDisplay = null; - var height = null; - - var funct = mxUtils.bind(this, function(evt) - { - this.activate(); - - if (!minimized) - { - minimized = true; - - this.minimize.setAttribute('src', this.normalizeImage); - this.minimize.setAttribute('title', 'Normalize'); - this.contentWrapper.style.display = 'none'; - maxDisplay = this.maximize.style.display; - - this.maximize.style.display = 'none'; - height = this.table.style.height; - - var minSize = this.getMinimumSize(); - - if (minSize.height > 0) - { - if (!mxClient.IS_IE) - { - this.div.style.height = minSize.height + 'px'; - } - - this.table.style.height = minSize.height + 'px'; - } - - if (minSize.width > 0) - { - if (!mxClient.IS_IE) - { - this.div.style.width = minSize.width + 'px'; - } - - this.table.style.width = minSize.width + 'px'; - } - - if (this.resize != null) - { - this.resize.style.visibility = 'hidden'; - } - - this.fireEvent(new mxEventObject(mxEvent.MINIMIZE, 'event', evt)); - } - else - { - minimized = false; - - this.minimize.setAttribute('src', this.minimizeImage); - this.minimize.setAttribute('title', 'Minimize'); - this.contentWrapper.style.display = ''; // default - this.maximize.style.display = maxDisplay; - - if (!mxClient.IS_IE) - { - this.div.style.height = height; - } - - this.table.style.height = height; - - if (this.resize != null) - { - this.resize.style.visibility = ''; - } - - this.fireEvent(new mxEventObject(mxEvent.NORMALIZE, 'event', evt)); - } - - mxEvent.consume(evt); - }); - - var md = (mxClient.IS_TOUCH) ? 'touchstart' : 'mousedown'; - mxEvent.addListener(this.minimize, md, funct); -}; - -/** - * Function: setMaximizable - * - * Sets if the window is maximizable. - */ -mxWindow.prototype.setMaximizable = function(maximizable) -{ - this.maximize.style.display = (maximizable) ? '' : 'none'; -}; - -/** - * Function: installMaximizeHandler - * - * Installs the event listeners required for maximizing the window. - */ -mxWindow.prototype.installMaximizeHandler = function() -{ - this.maximize = document.createElement('img'); - - this.maximize.setAttribute('src', this.maximizeImage); - this.maximize.setAttribute('align', 'right'); - this.maximize.setAttribute('title', 'Maximize'); - this.maximize.style.cursor = 'default'; - this.maximize.style.marginLeft = '1px'; - this.maximize.style.cursor = 'pointer'; - this.maximize.style.display = 'none'; - - this.title.appendChild(this.maximize); - - var maximized = false; - var x = null; - var y = null; - var height = null; - var width = null; - - var funct = mxUtils.bind(this, function(evt) - { - this.activate(); - - if (this.maximize.style.display != 'none') - { - if (!maximized) - { - maximized = true; - - this.maximize.setAttribute('src', this.normalizeImage); - this.maximize.setAttribute('title', 'Normalize'); - this.contentWrapper.style.display = ''; - this.minimize.style.visibility = 'hidden'; - - // Saves window state - x = parseInt(this.div.style.left); - y = parseInt(this.div.style.top); - height = this.table.style.height; - width = this.table.style.width; - - this.div.style.left = '0px'; - this.div.style.top = '0px'; - - if (!mxClient.IS_IE) - { - this.div.style.height = (document.body.clientHeight-2)+'px'; - this.div.style.width = (document.body.clientWidth-2)+'px'; - } - - this.table.style.width = (document.body.clientWidth-2)+'px'; - this.table.style.height = (document.body.clientHeight-2)+'px'; - - if (this.resize != null) - { - this.resize.style.visibility = 'hidden'; - } - - if (!mxClient.IS_IE) - { - var style = mxUtils.getCurrentStyle(this.contentWrapper); - - if (style.overflow == 'auto' || this.resize != null) - { - this.contentWrapper.style.height = - (this.div.offsetHeight - this.title.offsetHeight - 2)+'px'; - } - } - - this.fireEvent(new mxEventObject(mxEvent.MAXIMIZE, 'event', evt)); - } - else - { - maximized = false; - - this.maximize.setAttribute('src', this.maximizeImage); - this.maximize.setAttribute('title', 'Maximize'); - this.contentWrapper.style.display = ''; - this.minimize.style.visibility = ''; - - // Restores window state - this.div.style.left = x+'px'; - this.div.style.top = y+'px'; - - if (!mxClient.IS_IE) - { - this.div.style.height = height; - this.div.style.width = width; - - var style = mxUtils.getCurrentStyle(this.contentWrapper); - - if (style.overflow == 'auto' || this.resize != null) - { - this.contentWrapper.style.height = - (this.div.offsetHeight - this.title.offsetHeight - 2)+'px'; - } - } - - this.table.style.height = height; - this.table.style.width = width; - - if (this.resize != null) - { - this.resize.style.visibility = ''; - } - - this.fireEvent(new mxEventObject(mxEvent.NORMALIZE, 'event', evt)); - } - - mxEvent.consume(evt); - } - }); - - var md = (mxClient.IS_TOUCH) ? 'touchstart' : 'mousedown'; - mxEvent.addListener(this.maximize, md, funct); - mxEvent.addListener(this.title, 'dblclick', funct); -}; - -/** - * Function: installMoveHandler - * - * Installs the event listeners required for moving the window. - */ -mxWindow.prototype.installMoveHandler = function() -{ - this.title.style.cursor = 'move'; - - var md = (mxClient.IS_TOUCH) ? 'touchstart' : 'mousedown'; - var mm = (mxClient.IS_TOUCH) ? 'touchmove' : 'mousemove'; - var mu = (mxClient.IS_TOUCH) ? 'touchend' : 'mouseup'; - - mxEvent.addListener(this.title, md, mxUtils.bind(this, function(evt) - { - var startX = mxEvent.getClientX(evt); - var startY = mxEvent.getClientY(evt); - var x = this.getX(); - var y = this.getY(); - - // Adds a temporary pair of listeners to intercept - // the gesture event in the document - var dragHandler = mxUtils.bind(this, function(evt) - { - var dx = mxEvent.getClientX(evt) - startX; - var dy = mxEvent.getClientY(evt) - startY; - this.setLocation(x + dx, y + dy); - this.fireEvent(new mxEventObject(mxEvent.MOVE, 'event', evt)); - mxEvent.consume(evt); - }); - - var dropHandler = mxUtils.bind(this, function(evt) - { - mxEvent.removeListener(document, mm, dragHandler); - mxEvent.removeListener(document, mu, dropHandler); - - this.fireEvent(new mxEventObject(mxEvent.MOVE_END, 'event', evt)); - mxEvent.consume(evt); - }); - - mxEvent.addListener(document, mm, dragHandler); - mxEvent.addListener(document, mu, dropHandler); - - this.fireEvent(new mxEventObject(mxEvent.MOVE_START, 'event', evt)); - mxEvent.consume(evt); - })); -}; - -/** - * Function: setLocation - * - * Sets the upper, left corner of the window. - */ - mxWindow.prototype.setLocation = function(x, y) - { - this.div.style.left = x + 'px'; - this.div.style.top = y + 'px'; - }; - -/** - * Function: getX - * - * Returns the current position on the x-axis. - */ -mxWindow.prototype.getX = function() -{ - return parseInt(this.div.style.left); -}; - -/** - * Function: getY - * - * Returns the current position on the y-axis. - */ -mxWindow.prototype.getY = function() -{ - return parseInt(this.div.style.top); -}; - -/** - * Function: installCloseHandler - * - * Adds the <closeImage> as a new image node in <closeImg> and installs the - * <close> event. - */ -mxWindow.prototype.installCloseHandler = function() -{ - this.closeImg = document.createElement('img'); - - this.closeImg.setAttribute('src', this.closeImage); - this.closeImg.setAttribute('align', 'right'); - this.closeImg.setAttribute('title', 'Close'); - this.closeImg.style.marginLeft = '2px'; - this.closeImg.style.cursor = 'pointer'; - this.closeImg.style.display = 'none'; - - this.title.insertBefore(this.closeImg, this.title.firstChild); - - var md = (mxClient.IS_TOUCH) ? 'touchstart' : 'mousedown'; - mxEvent.addListener(this.closeImg, md, mxUtils.bind(this, function(evt) - { - this.fireEvent(new mxEventObject(mxEvent.CLOSE, 'event', evt)); - - if (this.destroyOnClose) - { - this.destroy(); - } - else - { - this.setVisible(false); - } - - mxEvent.consume(evt); - })); -}; - -/** - * Function: setImage - * - * Sets the image associated with the window. - * - * Parameters: - * - * image - URL of the image to be used. - */ -mxWindow.prototype.setImage = function(image) -{ - this.image = document.createElement('img'); - this.image.setAttribute('src', image); - this.image.setAttribute('align', 'left'); - this.image.style.marginRight = '4px'; - this.image.style.marginLeft = '0px'; - this.image.style.marginTop = '-2px'; - - this.title.insertBefore(this.image, this.title.firstChild); -}; - -/** - * Function: setClosable - * - * Sets the image associated with the window. - * - * Parameters: - * - * closable - Boolean specifying if the window should be closable. - */ -mxWindow.prototype.setClosable = function(closable) -{ - this.closeImg.style.display = (closable) ? '' : 'none'; -}; - -/** - * Function: isVisible - * - * Returns true if the window is visible. - */ -mxWindow.prototype.isVisible = function() -{ - if (this.div != null) - { - return this.div.style.visibility != 'hidden'; - } - - return false; -}; - -/** - * Function: setVisible - * - * Shows or hides the window depending on the given flag. - * - * Parameters: - * - * visible - Boolean indicating if the window should be made visible. - */ -mxWindow.prototype.setVisible = function(visible) -{ - if (this.div != null && this.isVisible() != visible) - { - if (visible) - { - this.show(); - } - else - { - this.hide(); - } - } -}; - -/** - * Function: show - * - * Shows the window. - */ -mxWindow.prototype.show = function() -{ - this.div.style.visibility = ''; - this.activate(); - - var style = mxUtils.getCurrentStyle(this.contentWrapper); - - if (!mxClient.IS_IE && (style.overflow == 'auto' || this.resize != null)) - { - this.contentWrapper.style.height = - (this.div.offsetHeight - this.title.offsetHeight - 2)+'px'; - } - - this.fireEvent(new mxEventObject(mxEvent.SHOW)); -}; - -/** - * Function: hide - * - * Hides the window. - */ -mxWindow.prototype.hide = function() -{ - this.div.style.visibility = 'hidden'; - this.fireEvent(new mxEventObject(mxEvent.HIDE)); -}; - -/** - * Function: destroy - * - * Destroys the window and removes all associated resources. Fires a - * <destroy> event prior to destroying the window. - */ -mxWindow.prototype.destroy = function() -{ - this.fireEvent(new mxEventObject(mxEvent.DESTROY)); - - if (this.div != null) - { - mxEvent.release(this.div); - this.div.parentNode.removeChild(this.div); - this.div = null; - } - - this.title = null; - this.content = null; - this.contentWrapper = null; -}; diff --git a/src/js/util/mxXmlCanvas2D.js b/src/js/util/mxXmlCanvas2D.js deleted file mode 100644 index 499c71a..0000000 --- a/src/js/util/mxXmlCanvas2D.js +++ /dev/null @@ -1,715 +0,0 @@ -/** - * $Id: mxXmlCanvas2D.js,v 1.9 2012-04-24 13:56:56 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -/** - * - * Class: mxXmlCanvas2D - * - * Implements a canvas to be used with <mxImageExport>. This canvas writes all - * calls as child nodes to the given root XML node. - * - * (code) - * var xmlDoc = mxUtils.createXmlDocument(); - * var root = xmlDoc.createElement('output'); - * xmlDoc.appendChild(root); - * var xmlCanvas = new mxXmlCanvas2D(root); - * (end) - * - * Constructor: mxXmlCanvas2D - * - * Constructs a XML canvas. - * - * Parameters: - * - * root - XML node for adding child nodes. - */ -var mxXmlCanvas2D = function(root) -{ - /** - * Variable: converter - * - * Holds the <mxUrlConverter> to convert image URLs. - */ - var converter = new mxUrlConverter(); - - /** - * Variable: compressed - * - * Specifies if the output should be compressed by removing redundant calls. - * Default is true. - */ - var compressed = true; - - /** - * Variable: textEnabled - * - * Specifies if text output should be enabled. Default is true. - */ - var textEnabled = true; - - // Private reference to the owner document - var doc = root.ownerDocument; - - // Implements stack for save/restore - var stack = []; - - // Implements state for redundancy checks - var state = - { - alpha: 1, - dashed: false, - strokewidth: 1, - fontsize: mxConstants.DEFAULT_FONTSIZE, - fontfamily: mxConstants.DEFAULT_FONTFAMILY, - fontcolor: '#000000' - }; - - // Private helper function set set precision to 2 - var f2 = function(x) - { - return Math.round(parseFloat(x) * 100) / 100; - }; - - // Returns public interface - return { - - /** - * Function: getConverter - * - * Returns <converter>. - */ - getConverter: function() - { - return converter; - }, - - /** - * Function: isCompressed - * - * Returns <compressed>. - */ - isCompressed: function() - { - return compressed; - }, - - /** - * Function: setCompressed - * - * Sets <compressed>. - */ - setCompressed: function(value) - { - compressed = value; - }, - - /** - * Function: isTextEnabled - * - * Returns <textEnabled>. - */ - isTextEnabled: function() - { - return textEnabled; - }, - - /** - * Function: setTextEnabled - * - * Sets <textEnabled>. - */ - setTextEnabled: function(value) - { - textEnabled = value; - }, - - /** - * Function: getDocument - * - * Returns the owner document of the root element. - */ - getDocument: function() - { - return doc; - }, - - /** - * Function: save - * - * Saves the state of the graphics object. - */ - save: function() - { - if (compressed) - { - stack.push(state); - state = mxUtils.clone(state); - } - - root.appendChild(doc.createElement('save')); - }, - - /** - * Function: restore - * - * Restores the state of the graphics object. - */ - restore: function() - { - if (compressed) - { - state = stack.pop(); - } - - root.appendChild(doc.createElement('restore')); - }, - - /** - * Function: scale - * - * Scales the current graphics object. - */ - scale: function(value) - { - var elem = doc.createElement('scale'); - elem.setAttribute('scale', value); - root.appendChild(elem); - }, - - /** - * Function: translate - * - * Translates the current graphics object. - */ - translate: function(dx, dy) - { - var elem = doc.createElement('translate'); - elem.setAttribute('dx', f2(dx)); - elem.setAttribute('dy', f2(dy)); - root.appendChild(elem); - }, - - /** - * Function: rotate - * - * Rotates and/or flips the current graphics object. - */ - rotate: function(theta, flipH, flipV, cx, cy) - { - var elem = doc.createElement('rotate'); - elem.setAttribute('theta', f2(theta)); - elem.setAttribute('flipH', (flipH) ? '1' : '0'); - elem.setAttribute('flipV', (flipV) ? '1' : '0'); - elem.setAttribute('cx', f2(cx)); - elem.setAttribute('cy', f2(cy)); - root.appendChild(elem); - }, - - /** - * Function: setStrokeWidth - * - * Sets the stroke width. - */ - setStrokeWidth: function(value) - { - if (compressed) - { - if (state.strokewidth == value) - { - return; - } - - state.strokewidth = value; - } - - var elem = doc.createElement('strokewidth'); - elem.setAttribute('width', f2(value)); - root.appendChild(elem); - }, - - /** - * Function: setStrokeColor - * - * Sets the stroke color. - */ - setStrokeColor: function(value) - { - var elem = doc.createElement('strokecolor'); - elem.setAttribute('color', value); - root.appendChild(elem); - }, - - /** - * Function: setDashed - * - * Sets the dashed state to true or false. - */ - setDashed: function(value) - { - if (compressed) - { - if (state.dashed == value) - { - return; - } - - state.dashed = value; - } - - var elem = doc.createElement('dashed'); - elem.setAttribute('dashed', (value) ? '1' : '0'); - root.appendChild(elem); - }, - - /** - * Function: setDashPattern - * - * Sets the dashed pattern to the given space separated list of numbers. - */ - setDashPattern: function(value) - { - var elem = doc.createElement('dashpattern'); - elem.setAttribute('pattern', value); - root.appendChild(elem); - }, - - /** - * Function: setLineCap - * - * Sets the linecap. - */ - setLineCap: function(value) - { - var elem = doc.createElement('linecap'); - elem.setAttribute('cap', value); - root.appendChild(elem); - }, - - /** - * Function: setLineJoin - * - * Sets the linejoin. - */ - setLineJoin: function(value) - { - var elem = doc.createElement('linejoin'); - elem.setAttribute('join', value); - root.appendChild(elem); - }, - - /** - * Function: setMiterLimit - * - * Sets the miterlimit. - */ - setMiterLimit: function(value) - { - var elem = doc.createElement('miterlimit'); - elem.setAttribute('limit', value); - root.appendChild(elem); - }, - - /** - * Function: setFontSize - * - * Sets the fontsize. - */ - setFontSize: function(value) - { - if (textEnabled) - { - if (compressed) - { - if (state.fontsize == value) - { - return; - } - - state.fontsize = value; - } - - var elem = doc.createElement('fontsize'); - elem.setAttribute('size', value); - root.appendChild(elem); - } - }, - - /** - * Function: setFontColor - * - * Sets the fontcolor. - */ - setFontColor: function(value) - { - if (textEnabled) - { - if (compressed) - { - if (state.fontcolor == value) - { - return; - } - - state.fontcolor = value; - } - - var elem = doc.createElement('fontcolor'); - elem.setAttribute('color', value); - root.appendChild(elem); - } - }, - - /** - * Function: setFontFamily - * - * Sets the fontfamily. - */ - setFontFamily: function(value) - { - if (textEnabled) - { - if (compressed) - { - if (state.fontfamily == value) - { - return; - } - - state.fontfamily = value; - } - - var elem = doc.createElement('fontfamily'); - elem.setAttribute('family', value); - root.appendChild(elem); - } - }, - - /** - * Function: setFontStyle - * - * Sets the fontstyle. - */ - setFontStyle: function(value) - { - if (textEnabled) - { - var elem = doc.createElement('fontstyle'); - elem.setAttribute('style', value); - root.appendChild(elem); - } - }, - - /** - * Function: setAlpha - * - * Sets the current alpha. - */ - setAlpha: function(alpha) - { - if (compressed) - { - if (state.alpha == alpha) - { - return; - } - - state.alpha = alpha; - } - - var elem = doc.createElement('alpha'); - elem.setAttribute('alpha', f2(alpha)); - root.appendChild(elem); - }, - - /** - * Function: setFillColor - * - * Sets the fillcolor. - */ - setFillColor: function(value) - { - var elem = doc.createElement('fillcolor'); - elem.setAttribute('color', value); - root.appendChild(elem); - }, - - /** - * Function: setGradient - * - * Sets the gradient color. - */ - setGradient: function(color1, color2, x, y, w, h, direction) - { - var elem = doc.createElement('gradient'); - elem.setAttribute('c1', color1); - elem.setAttribute('c2', color2); - elem.setAttribute('x', f2(x)); - elem.setAttribute('y', f2(y)); - elem.setAttribute('w', f2(w)); - elem.setAttribute('h', f2(h)); - - // Default direction is south - if (direction != null) - { - elem.setAttribute('direction', direction); - } - - root.appendChild(elem); - }, - - /** - * Function: setGlassGradient - * - * Sets the glass gradient. - */ - setGlassGradient: function(x, y, w, h) - { - var elem = doc.createElement('glass'); - elem.setAttribute('x', f2(x)); - elem.setAttribute('y', f2(y)); - elem.setAttribute('w', f2(w)); - elem.setAttribute('h', f2(h)); - root.appendChild(elem); - }, - - /** - * Function: rect - * - * Sets the current path to a rectangle. - */ - rect: function(x, y, w, h) - { - var elem = doc.createElement('rect'); - elem.setAttribute('x', f2(x)); - elem.setAttribute('y', f2(y)); - elem.setAttribute('w', f2(w)); - elem.setAttribute('h', f2(h)); - root.appendChild(elem); - }, - - /** - * Function: roundrect - * - * Sets the current path to a rounded rectangle. - */ - roundrect: function(x, y, w, h, dx, dy) - { - var elem = doc.createElement('roundrect'); - elem.setAttribute('x', f2(x)); - elem.setAttribute('y', f2(y)); - elem.setAttribute('w', f2(w)); - elem.setAttribute('h', f2(h)); - elem.setAttribute('dx', f2(dx)); - elem.setAttribute('dy', f2(dy)); - root.appendChild(elem); - }, - - /** - * Function: ellipse - * - * Sets the current path to an ellipse. - */ - ellipse: function(x, y, w, h) - { - var elem = doc.createElement('ellipse'); - elem.setAttribute('x', f2(x)); - elem.setAttribute('y', f2(y)); - elem.setAttribute('w', f2(w)); - elem.setAttribute('h', f2(h)); - root.appendChild(elem); - }, - - /** - * Function: image - * - * Paints an image. - */ - image: function(x, y, w, h, src, aspect, flipH, flipV) - { - src = converter.convert(src); - - // TODO: Add option for embedding images as base64 - var elem = doc.createElement('image'); - elem.setAttribute('x', f2(x)); - elem.setAttribute('y', f2(y)); - elem.setAttribute('w', f2(w)); - elem.setAttribute('h', f2(h)); - elem.setAttribute('src', src); - elem.setAttribute('aspect', (aspect) ? '1' : '0'); - elem.setAttribute('flipH', (flipH) ? '1' : '0'); - elem.setAttribute('flipV', (flipV) ? '1' : '0'); - root.appendChild(elem); - }, - - /** - * Function: text - * - * Paints the given text. - */ - text: function(x, y, w, h, str, align, valign, vertical, wrap, format) - { - if (textEnabled) - { - var elem = doc.createElement('text'); - elem.setAttribute('x', f2(x)); - elem.setAttribute('y', f2(y)); - elem.setAttribute('w', f2(w)); - elem.setAttribute('h', f2(h)); - elem.setAttribute('str', str); - - if (align != null) - { - elem.setAttribute('align', align); - } - - if (valign != null) - { - elem.setAttribute('valign', valign); - } - - elem.setAttribute('vertical', (vertical) ? '1' : '0'); - elem.setAttribute('wrap', (wrap) ? '1' : '0'); - elem.setAttribute('format', format); - root.appendChild(elem); - } - }, - - /** - * Function: begin - * - * Starts a new path. - */ - begin: function() - { - root.appendChild(doc.createElement('begin')); - }, - - /** - * Function: moveTo - * - * Moves the current path the given coordinates. - */ - moveTo: function(x, y) - { - var elem = doc.createElement('move'); - elem.setAttribute('x', f2(x)); - elem.setAttribute('y', f2(y)); - root.appendChild(elem); - }, - - /** - * Function: lineTo - * - * Adds a line to the current path. - */ - lineTo: function(x, y) - { - var elem = doc.createElement('line'); - elem.setAttribute('x', f2(x)); - elem.setAttribute('y', f2(y)); - root.appendChild(elem); - }, - - /** - * Function: quadTo - * - * Adds a quadratic curve to the current path. - */ - quadTo: function(x1, y1, x2, y2) - { - var elem = doc.createElement('quad'); - elem.setAttribute('x1', f2(x1)); - elem.setAttribute('y1', f2(y1)); - elem.setAttribute('x2', f2(x2)); - elem.setAttribute('y2', f2(y2)); - root.appendChild(elem); - }, - - /** - * Function: curveTo - * - * Adds a bezier curve to the current path. - */ - curveTo: function(x1, y1, x2, y2, x3, y3) - { - var elem = doc.createElement('curve'); - elem.setAttribute('x1', f2(x1)); - elem.setAttribute('y1', f2(y1)); - elem.setAttribute('x2', f2(x2)); - elem.setAttribute('y2', f2(y2)); - elem.setAttribute('x3', f2(x3)); - elem.setAttribute('y3', f2(y3)); - root.appendChild(elem); - }, - - /** - * Function: close - * - * Closes the current path. - */ - close: function() - { - root.appendChild(doc.createElement('close')); - }, - - /** - * Function: stroke - * - * Paints the outline of the current path. - */ - stroke: function() - { - root.appendChild(doc.createElement('stroke')); - }, - - /** - * Function: fill - * - * Fills the current path. - */ - fill: function() - { - root.appendChild(doc.createElement('fill')); - }, - - /** - * Function: fillstroke - * - * Fills and paints the outline of the current path. - */ - fillAndStroke: function() - { - root.appendChild(doc.createElement('fillstroke')); - }, - - /** - * Function: shadow - * - * Paints the current path as a shadow of the given color. - */ - shadow: function(value, filled) - { - var elem = doc.createElement('shadow'); - elem.setAttribute('value', value); - - if (filled != null) - { - elem.setAttribute('filled', (filled) ? '1' : '0'); - } - - root.appendChild(elem); - }, - - /** - * Function: clip - * - * Uses the current path for clipping. - */ - clip: function() - { - root.appendChild(doc.createElement('clip')); - } - }; - -};
\ No newline at end of file diff --git a/src/js/util/mxXmlRequest.js b/src/js/util/mxXmlRequest.js deleted file mode 100644 index 0ac55ed..0000000 --- a/src/js/util/mxXmlRequest.js +++ /dev/null @@ -1,425 +0,0 @@ -/** - * $Id: mxXmlRequest.js,v 1.38 2012-04-22 10:16:23 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -/** - * Class: mxXmlRequest - * - * XML HTTP request wrapper. See also: <mxUtils.get>, <mxUtils.post> and - * <mxUtils.load>. This class provides a cross-browser abstraction for Ajax - * requests. - * - * Encoding: - * - * For encoding parameter values, the built-in encodeURIComponent JavaScript - * method must be used. For automatic encoding of post data in <mxEditor> the - * <mxEditor.escapePostData> switch can be set to true (default). The encoding - * will be carried out using the conte type of the page. That is, the page - * containting the editor should contain a meta tag in the header, eg. - * <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> - * - * Example: - * - * (code) - * var onload = function(req) - * { - * mxUtils.alert(req.getDocumentElement()); - * } - * - * var onerror = function(req) - * { - * mxUtils.alert(req.getStatus()); - * } - * new mxXmlRequest(url, 'key=value').send(onload, onerror); - * (end) - * - * Sends an asynchronous POST request to the specified URL. - * - * Example: - * - * (code) - * var req = new mxXmlRequest(url, 'key=value', 'POST', false); - * req.send(); - * mxUtils.alert(req.getDocumentElement()); - * (end) - * - * Sends a synchronous POST request to the specified URL. - * - * Example: - * - * (code) - * var encoder = new mxCodec(); - * var result = encoder.encode(graph.getModel()); - * var xml = encodeURIComponent(mxUtils.getXml(result)); - * new mxXmlRequest(url, 'xml='+xml).send(); - * (end) - * - * Sends an encoded graph model to the specified URL using xml as the - * parameter name. The parameter can then be retrieved in C# as follows: - * - * (code) - * string xml = HttpUtility.UrlDecode(context.Request.Params["xml"]); - * (end) - * - * Or in Java as follows: - * - * (code) - * String xml = URLDecoder.decode(request.getParameter("xml"), "UTF-8").replace("\n", "
"); - * (end) - * - * Note that the linefeeds should only be replaced if the XML is - * processed in Java, for example when creating an image. - * - * Constructor: mxXmlRequest - * - * Constructs an XML HTTP request. - * - * Parameters: - * - * url - Target URL of the request. - * params - Form encoded parameters to send with a POST request. - * method - String that specifies the request method. Possible values are - * POST and GET. Default is POST. - * async - Boolean specifying if an asynchronous request should be used. - * Default is true. - * username - String specifying the username to be used for the request. - * password - String specifying the password to be used for the request. - */ -function mxXmlRequest(url, params, method, async, username, password) -{ - this.url = url; - this.params = params; - this.method = method || 'POST'; - this.async = (async != null) ? async : true; - this.username = username; - this.password = password; -}; - -/** - * Variable: url - * - * Holds the target URL of the request. - */ -mxXmlRequest.prototype.url = null; - -/** - * Variable: params - * - * Holds the form encoded data for the POST request. - */ -mxXmlRequest.prototype.params = null; - -/** - * Variable: method - * - * Specifies the request method. Possible values are POST and GET. Default - * is POST. - */ -mxXmlRequest.prototype.method = null; - -/** - * Variable: async - * - * Boolean indicating if the request is asynchronous. - */ -mxXmlRequest.prototype.async = null; - -/** - * Variable: binary - * - * Boolean indicating if the request is binary. This option is ignored in IE. - * In all other browsers the requested mime type is set to - * text/plain; charset=x-user-defined. Default is false. - */ -mxXmlRequest.prototype.binary = false; - -/** - * Variable: username - * - * Specifies the username to be used for authentication. - */ -mxXmlRequest.prototype.username = null; - -/** - * Variable: password - * - * Specifies the password to be used for authentication. - */ -mxXmlRequest.prototype.password = null; - -/** - * Variable: request - * - * Holds the inner, browser-specific request object. - */ -mxXmlRequest.prototype.request = null; - -/** - * Function: isBinary - * - * Returns <binary>. - */ -mxXmlRequest.prototype.isBinary = function() -{ - return this.binary; -}; - -/** - * Function: setBinary - * - * Sets <binary>. - */ -mxXmlRequest.prototype.setBinary = function(value) -{ - this.binary = value; -}; - -/** - * Function: getText - * - * Returns the response as a string. - */ -mxXmlRequest.prototype.getText = function() -{ - return this.request.responseText; -}; - -/** - * Function: isReady - * - * Returns true if the response is ready. - */ -mxXmlRequest.prototype.isReady = function() -{ - return this.request.readyState == 4; -}; - -/** - * Function: getDocumentElement - * - * Returns the document element of the response XML document. - */ -mxXmlRequest.prototype.getDocumentElement = function() -{ - var doc = this.getXml(); - - if (doc != null) - { - return doc.documentElement; - } - - return null; -}; - -/** - * Function: getXml - * - * Returns the response as an XML document. Use <getDocumentElement> to get - * the document element of the XML document. - */ -mxXmlRequest.prototype.getXml = function() -{ - var xml = this.request.responseXML; - - // Handles missing response headers in IE, the first condition handles - // the case where responseXML is there, but using its nodes leads to - // type errors in the mxCellCodec when putting the nodes into a new - // document. This happens in IE9 standards mode and with XML user - // objects only, as they are used directly as values in cells. - if (document.documentMode >= 9 || xml == null || xml.documentElement == null) - { - xml = mxUtils.parseXml(this.request.responseText); - } - - return xml; -}; - -/** - * Function: getText - * - * Returns the response as a string. - */ -mxXmlRequest.prototype.getText = function() -{ - return this.request.responseText; -}; - -/** - * Function: getStatus - * - * Returns the status as a number, eg. 404 for "Not found" or 200 for "OK". - * Note: The NS_ERROR_NOT_AVAILABLE for invalid responses cannot be cought. - */ -mxXmlRequest.prototype.getStatus = function() -{ - return this.request.status; -}; - -/** - * Function: create - * - * Creates and returns the inner <request> object. - */ -mxXmlRequest.prototype.create = function() -{ - if (window.XMLHttpRequest) - { - return function() - { - var req = new XMLHttpRequest(); - - // TODO: Check for overrideMimeType required here? - if (this.isBinary() && req.overrideMimeType) - { - req.overrideMimeType('text/plain; charset=x-user-defined'); - } - - return req; - }; - } - else if (typeof(ActiveXObject) != "undefined") - { - return function() - { - // TODO: Implement binary option - return new ActiveXObject("Microsoft.XMLHTTP"); - }; - } -}(); - -/** - * Function: send - * - * Send the <request> to the target URL using the specified functions to - * process the response asychronously. - * - * Parameters: - * - * onload - Function to be invoked if a successful response was received. - * onerror - Function to be called on any error. - */ -mxXmlRequest.prototype.send = function(onload, onerror) -{ - this.request = this.create(); - - if (this.request != null) - { - if (onload != null) - { - this.request.onreadystatechange = mxUtils.bind(this, function() - { - if (this.isReady()) - { - onload(this); - this.onreadystatechaange = null; - } - }); - } - - this.request.open(this.method, this.url, this.async, - this.username, this.password); - this.setRequestHeaders(this.request, this.params); - this.request.send(this.params); - } -}; - -/** - * Function: setRequestHeaders - * - * Sets the headers for the given request and parameters. This sets the - * content-type to application/x-www-form-urlencoded if any params exist. - * - * Example: - * - * (code) - * request.setRequestHeaders = function(request, params) - * { - * if (params != null) - * { - * request.setRequestHeader('Content-Type', - * 'multipart/form-data'); - * request.setRequestHeader('Content-Length', - * params.length); - * } - * }; - * (end) - * - * Use the code above before calling <send> if you require a - * multipart/form-data request. - */ -mxXmlRequest.prototype.setRequestHeaders = function(request, params) -{ - if (params != null) - { - request.setRequestHeader('Content-Type', - 'application/x-www-form-urlencoded'); - } -}; - -/** - * Function: simulate - * - * Creates and posts a request to the given target URL using a dynamically - * created form inside the given document. - * - * Parameters: - * - * docs - Document that contains the form element. - * target - Target to send the form result to. - */ -mxXmlRequest.prototype.simulate = function(doc, target) -{ - doc = doc || document; - var old = null; - - if (doc == document) - { - old = window.onbeforeunload; - window.onbeforeunload = null; - } - - var form = doc.createElement('form'); - form.setAttribute('method', this.method); - form.setAttribute('action', this.url); - - if (target != null) - { - form.setAttribute('target', target); - } - - form.style.display = 'none'; - form.style.visibility = 'hidden'; - - var pars = (this.params.indexOf('&') > 0) ? - this.params.split('&') : - this.params.split(); - - // Adds the parameters as textareas to the form - for (var i=0; i<pars.length; i++) - { - var pos = pars[i].indexOf('='); - - if (pos > 0) - { - var name = pars[i].substring(0, pos); - var value = pars[i].substring(pos+1); - - var textarea = doc.createElement('textarea'); - textarea.setAttribute('name', name); - value = value.replace(/\n/g, '
'); - - var content = doc.createTextNode(value); - textarea.appendChild(content); - form.appendChild(textarea); - } - } - - doc.body.appendChild(form); - form.submit(); - doc.body.removeChild(form); - - if (old != null) - { - window.onbeforeunload = old; - } -}; diff --git a/src/js/view/mxCellEditor.js b/src/js/view/mxCellEditor.js deleted file mode 100644 index 2086cca..0000000 --- a/src/js/view/mxCellEditor.js +++ /dev/null @@ -1,522 +0,0 @@ -/** - * $Id: mxCellEditor.js,v 1.62 2012-12-11 16:59:31 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -/** - * Class: mxCellEditor - * - * In-place editor for the graph. To control this editor, use - * <mxGraph.invokesStopCellEditing>, <mxGraph.enterStopsCellEditing> and - * <mxGraph.escapeEnabled>. If <mxGraph.enterStopsCellEditing> is true then - * ctrl-enter or shift-enter can be used to create a linefeed. The F2 and - * escape keys can always be used to stop editing. To customize the location - * of the textbox in the graph, override <getEditorBounds> as follows: - * - * (code) - * graph.cellEditor.getEditorBounds = function(state) - * { - * var result = mxCellEditor.prototype.getEditorBounds.apply(this, arguments); - * - * if (this.graph.getModel().isEdge(state.cell)) - * { - * result.x = state.getCenterX() - result.width / 2; - * result.y = state.getCenterY() - result.height / 2; - * } - * - * return result; - * }; - * (end) - * - * The textarea uses the mxCellEditor CSS class. You can modify this class in - * your custom CSS. Note: You should modify the CSS after loading the client - * in the page. - * - * Example: - * - * To only allow numeric input in the in-place editor, use the following code. - * - * (code) - * var text = graph.cellEditor.textarea; - * - * mxEvent.addListener(text, 'keydown', function (evt) - * { - * if (!(evt.keyCode >= 48 && evt.keyCode <= 57) && - * !(evt.keyCode >= 96 && evt.keyCode <= 105)) - * { - * mxEvent.consume(evt); - * } - * }); - * (end) - * - * Initial values: - * - * To implement an initial value for cells without a label, use the - * <emptyLabelText> variable. - * - * Resize in Chrome: - * - * Resize of the textarea is disabled by default. If you want to enable - * this feature extend <init> and set this.textarea.style.resize = ''. - * - * Constructor: mxCellEditor - * - * Constructs a new in-place editor for the specified graph. - * - * Parameters: - * - * graph - Reference to the enclosing <mxGraph>. - */ -function mxCellEditor(graph) -{ - this.graph = graph; -}; - -/** - * Variable: graph - * - * Reference to the enclosing <mxGraph>. - */ -mxCellEditor.prototype.graph = null; - -/** - * Variable: textarea - * - * Holds the input textarea. Note that this may be null before the first - * edit. Instantiated in <init>. - */ -mxCellEditor.prototype.textarea = null; - -/** - * Variable: editingCell - * - * Reference to the <mxCell> that is currently being edited. - */ -mxCellEditor.prototype.editingCell = null; - -/** - * Variable: trigger - * - * Reference to the event that was used to start editing. - */ -mxCellEditor.prototype.trigger = null; - -/** - * Variable: modified - * - * Specifies if the label has been modified. - */ -mxCellEditor.prototype.modified = false; - -/** - * Variable: emptyLabelText - * - * Text to be displayed for empty labels. Default is ''. This can be set - * to eg. "[Type Here]" to easier visualize editing of empty labels. The - * value is only displayed before the first keystroke and is never used - * as the actual editin value. - */ -mxCellEditor.prototype.emptyLabelText = ''; - -/** - * Variable: textNode - * - * Reference to the label DOM node that has been hidden. - */ -mxCellEditor.prototype.textNode = ''; - -/** - * Function: init - * - * Creates the <textarea> and installs the event listeners. The key handler - * updates the <modified> state. - */ -mxCellEditor.prototype.init = function () -{ - this.textarea = document.createElement('textarea'); - - this.textarea.className = 'mxCellEditor'; - this.textarea.style.position = 'absolute'; - this.textarea.style.overflow = 'visible'; - - this.textarea.setAttribute('cols', '20'); - this.textarea.setAttribute('rows', '4'); - - if (mxClient.IS_GC) - { - this.textarea.style.resize = 'none'; - } - - mxEvent.addListener(this.textarea, 'blur', mxUtils.bind(this, function(evt) - { - this.focusLost(); - })); - - mxEvent.addListener(this.textarea, 'keydown', mxUtils.bind(this, function(evt) - { - if (!mxEvent.isConsumed(evt)) - { - if (evt.keyCode == 113 /* F2 */ || (this.graph.isEnterStopsCellEditing() && - evt.keyCode == 13 /* Enter */ && !mxEvent.isControlDown(evt) && - !mxEvent.isShiftDown(evt))) - { - this.graph.stopEditing(false); - mxEvent.consume(evt); - } - else if (evt.keyCode == 27 /* Escape */) - { - this.graph.stopEditing(true); - mxEvent.consume(evt); - } - else - { - // Clears the initial empty label on the first keystroke - if (this.clearOnChange) - { - this.clearOnChange = false; - this.textarea.value = ''; - } - - // Updates the modified flag for storing the value - this.setModified(true); - } - } - })); -}; - -/** - * Function: isModified - * - * Returns <modified>. - */ -mxCellEditor.prototype.isModified = function() -{ - return this.modified; -}; - -/** - * Function: setModified - * - * Sets <modified> to the specified boolean value. - */ -mxCellEditor.prototype.setModified = function(value) -{ - this.modified = value; -}; - -/** - * Function: focusLost - * - * Called if the textarea has lost focus. - */ -mxCellEditor.prototype.focusLost = function() -{ - this.stopEditing(!this.graph.isInvokesStopCellEditing()); -}; - -/** - * Function: startEditing - * - * Starts the editor for the given cell. - * - * Parameters: - * - * cell - <mxCell> to start editing. - * trigger - Optional mouse event that triggered the editor. - */ -mxCellEditor.prototype.startEditing = function(cell, trigger) -{ - // Lazy instantiates textarea to save memory in IE - if (this.textarea == null) - { - this.init(); - } - - this.stopEditing(true); - var state = this.graph.getView().getState(cell); - - if (state != null) - { - this.editingCell = cell; - this.trigger = trigger; - this.textNode = null; - - if (state.text != null && this.isHideLabel(state)) - { - this.textNode = state.text.node; - this.textNode.style.visibility = 'hidden'; - } - - // Configures the style of the in-place editor - var scale = this.graph.getView().scale; - var size = mxUtils.getValue(state.style, mxConstants.STYLE_FONTSIZE, mxConstants.DEFAULT_FONTSIZE) * scale; - var family = mxUtils.getValue(state.style, mxConstants.STYLE_FONTFAMILY, mxConstants.DEFAULT_FONTFAMILY); - var color = mxUtils.getValue(state.style, mxConstants.STYLE_FONTCOLOR, 'black'); - var align = (this.graph.model.isEdge(state.cell)) ? mxConstants.ALIGN_LEFT : - mxUtils.getValue(state.style, mxConstants.STYLE_ALIGN, mxConstants.ALIGN_LEFT); - var bold = (mxUtils.getValue(state.style, mxConstants.STYLE_FONTSTYLE, 0) & - mxConstants.FONT_BOLD) == mxConstants.FONT_BOLD; - var italic = (mxUtils.getValue(state.style, mxConstants.STYLE_FONTSTYLE, 0) & - mxConstants.FONT_ITALIC) == mxConstants.FONT_ITALIC; - var uline = (mxUtils.getValue(state.style, mxConstants.STYLE_FONTSTYLE, 0) & - mxConstants.FONT_UNDERLINE) == mxConstants.FONT_UNDERLINE; - - this.textarea.style.fontSize = size + 'px'; - this.textarea.style.fontFamily = family; - this.textarea.style.textAlign = align; - this.textarea.style.color = color; - this.textarea.style.fontWeight = (bold) ? 'bold' : 'normal'; - this.textarea.style.fontStyle = (italic) ? 'italic' : ''; - this.textarea.style.textDecoration = (uline) ? 'underline' : ''; - - // Specifies the bounds of the editor box - var bounds = this.getEditorBounds(state); - - this.textarea.style.left = bounds.x + 'px'; - this.textarea.style.top = bounds.y + 'px'; - this.textarea.style.width = bounds.width + 'px'; - this.textarea.style.height = bounds.height + 'px'; - this.textarea.style.zIndex = 5; - - var value = this.getInitialValue(state, trigger); - - // Uses an optional text value for empty labels which is cleared - // when the first keystroke appears. This makes it easier to see - // that a label is being edited even if the label is empty. - if (value == null || value.length == 0) - { - value = this.getEmptyLabelText(); - this.clearOnChange = true; - } - else - { - this.clearOnChange = false; - } - - this.setModified(false); - this.textarea.value = value; - this.graph.container.appendChild(this.textarea); - - if (this.textarea.style.display != 'none') - { - // FIXME: Doesn't bring up the virtual keyboard on iPad - this.textarea.focus(); - this.textarea.select(); - } - } -}; - -/** - * Function: stopEditing - * - * Stops the editor and applies the value if cancel is false. - */ -mxCellEditor.prototype.stopEditing = function(cancel) -{ - cancel = cancel || false; - - if (this.editingCell != null) - { - if (this.textNode != null) - { - this.textNode.style.visibility = 'visible'; - this.textNode = null; - } - - if (!cancel && this.isModified()) - { - this.graph.labelChanged(this.editingCell, this.getCurrentValue(), this.trigger); - } - - this.editingCell = null; - this.trigger = null; - this.textarea.blur(); - this.textarea.parentNode.removeChild(this.textarea); - } -}; - -/** - * Function: getInitialValue - * - * Gets the initial editing value for the given cell. - */ -mxCellEditor.prototype.getInitialValue = function(state, trigger) -{ - return this.graph.getEditingValue(state.cell, trigger); -}; - -/** - * Function: getCurrentValue - * - * Returns the current editing value. - */ -mxCellEditor.prototype.getCurrentValue = function() -{ - return this.textarea.value.replace(/\r/g, ''); -}; - -/** - * Function: isHideLabel - * - * Returns true if the label should be hidden while the cell is being - * edited. - */ -mxCellEditor.prototype.isHideLabel = function(state) -{ - return true; -}; - -/** - * Function: getMinimumSize - * - * Returns the minimum width and height for editing the given state. - */ -mxCellEditor.prototype.getMinimumSize = function(state) -{ - var scale = this.graph.getView().scale; - - return new mxRectangle(0, 0, (state.text == null) ? 30 : state.text.size * scale + 20, - (this.textarea.style.textAlign == 'left') ? 120 : 40); -}; - -/** - * Function: getEditorBounds - * - * Returns the <mxRectangle> that defines the bounds of the editor. - */ -mxCellEditor.prototype.getEditorBounds = function(state) -{ - var isEdge = this.graph.getModel().isEdge(state.cell); - var scale = this.graph.getView().scale; - var minSize = this.getMinimumSize(state); - var minWidth = minSize.width; - var minHeight = minSize.height; - - var spacing = parseInt(state.style[mxConstants.STYLE_SPACING] || 2) * scale; - var spacingTop = (parseInt(state.style[mxConstants.STYLE_SPACING_TOP] || 0)) * scale + spacing; - var spacingRight = (parseInt(state.style[mxConstants.STYLE_SPACING_RIGHT] || 0)) * scale + spacing; - var spacingBottom = (parseInt(state.style[mxConstants.STYLE_SPACING_BOTTOM] || 0)) * scale + spacing; - var spacingLeft = (parseInt(state.style[mxConstants.STYLE_SPACING_LEFT] || 0)) * scale + spacing; - - var result = new mxRectangle(state.x, state.y, - Math.max(minWidth, state.width - spacingLeft - spacingRight), - Math.max(minHeight, state.height - spacingTop - spacingBottom)); - - if (isEdge) - { - result.x = state.absoluteOffset.x; - result.y = state.absoluteOffset.y; - - if (state.text != null && state.text.boundingBox != null) - { - // Workaround for label containing just spaces in which case - // the bounding box location contains negative numbers - if (state.text.boundingBox.x > 0) - { - result.x = state.text.boundingBox.x; - } - - if (state.text.boundingBox.y > 0) - { - result.y = state.text.boundingBox.y; - } - } - } - else if (state.text != null && state.text.boundingBox != null) - { - result.x = Math.min(result.x, state.text.boundingBox.x); - result.y = Math.min(result.y, state.text.boundingBox.y); - } - - result.x += spacingLeft; - result.y += spacingTop; - - if (state.text != null && state.text.boundingBox != null) - { - if (!isEdge) - { - result.width = Math.max(result.width, state.text.boundingBox.width); - result.height = Math.max(result.height, state.text.boundingBox.height); - } - else - { - result.width = Math.max(minWidth, state.text.boundingBox.width); - result.height = Math.max(minHeight, state.text.boundingBox.height); - } - } - - // Applies the horizontal and vertical label positions - if (this.graph.getModel().isVertex(state.cell)) - { - var horizontal = mxUtils.getValue(state.style, mxConstants.STYLE_LABEL_POSITION, mxConstants.ALIGN_CENTER); - - if (horizontal == mxConstants.ALIGN_LEFT) - { - result.x -= state.width; - } - else if (horizontal == mxConstants.ALIGN_RIGHT) - { - result.x += state.width; - } - - var vertical = mxUtils.getValue(state.style, mxConstants.STYLE_VERTICAL_LABEL_POSITION, mxConstants.ALIGN_MIDDLE); - - if (vertical == mxConstants.ALIGN_TOP) - { - result.y -= state.height; - } - else if (vertical == mxConstants.ALIGN_BOTTOM) - { - result.y += state.height; - } - } - - return result; -}; - -/** - * Function: getEmptyLabelText - * - * Returns the initial label value to be used of the label of the given - * cell is empty. This label is displayed and cleared on the first keystroke. - * This implementation returns <emptyLabelText>. - * - * Parameters: - * - * cell - <mxCell> for which a text for an empty editing box should be - * returned. - */ -mxCellEditor.prototype.getEmptyLabelText = function (cell) -{ - return this.emptyLabelText; -}; - -/** - * Function: getEditingCell - * - * Returns the cell that is currently being edited or null if no cell is - * being edited. - */ -mxCellEditor.prototype.getEditingCell = function () -{ - return this.editingCell; -}; - -/** - * Function: destroy - * - * Destroys the editor and removes all associated resources. - */ -mxCellEditor.prototype.destroy = function () -{ - if (this.textarea != null) - { - mxEvent.release(this.textarea); - - if (this.textarea.parentNode != null) - { - this.textarea.parentNode.removeChild(this.textarea); - } - - this.textarea = null; - } -}; diff --git a/src/js/view/mxCellOverlay.js b/src/js/view/mxCellOverlay.js deleted file mode 100644 index 316e2c4..0000000 --- a/src/js/view/mxCellOverlay.js +++ /dev/null @@ -1,233 +0,0 @@ -/** - * $Id: mxCellOverlay.js,v 1.18 2012-12-06 15:58:44 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -/** - * Class: mxCellOverlay - * - * Extends <mxEventSource> to implement a graph overlay, represented by an icon - * and a tooltip. Overlays can handle and fire <click> events and are added to - * the graph using <mxGraph.addCellOverlay>, and removed using - * <mxGraph.removeCellOverlay>, or <mxGraph.removeCellOverlays> to remove all overlays. - * The <mxGraph.getCellOverlays> function returns the array of overlays for a given - * cell in a graph. If multiple overlays exist for the same cell, then - * <getBounds> should be overridden in at least one of the overlays. - * - * Overlays appear on top of all cells in a special layer. If this is not - * desirable, then the image must be rendered as part of the shape or label of - * the cell instead. - * - * Example: - * - * The following adds a new overlays for a given vertex and selects the cell - * if the overlay is clicked. - * - * (code) - * var overlay = new mxCellOverlay(img, html); - * graph.addCellOverlay(vertex, overlay); - * overlay.addListener(mxEvent.CLICK, function(sender, evt) - * { - * var cell = evt.getProperty('cell'); - * graph.setSelectionCell(cell); - * }); - * (end) - * - * For cell overlays to be printed use <mxPrintPreview.printOverlays>. - * - * Event: mxEvent.CLICK - * - * Fires when the user clicks on the overlay. The <code>event</code> property - * contains the corresponding mouse event and the <code>cell</code> property - * contains the cell. For touch devices this is fired if the element receives - * a touchend event. - * - * Constructor: mxCellOverlay - * - * Constructs a new overlay using the given image and tooltip. - * - * Parameters: - * - * image - <mxImage> that represents the icon to be displayed. - * tooltip - Optional string that specifies the tooltip. - * align - Optional horizontal alignment for the overlay. Possible - * values are <ALIGN_LEFT>, <ALIGN_CENTER> and <ALIGN_RIGHT> - * (default). - * verticalAlign - Vertical alignment for the overlay. Possible - * values are <ALIGN_TOP>, <ALIGN_MIDDLE> and <ALIGN_BOTTOM> - * (default). - */ -function mxCellOverlay(image, tooltip, align, verticalAlign, offset, cursor) -{ - this.image = image; - this.tooltip = tooltip; - this.align = (align != null) ? align : this.align; - this.verticalAlign = (verticalAlign != null) ? verticalAlign : this.verticalAlign; - this.offset = (offset != null) ? offset : new mxPoint(); - this.cursor = (cursor != null) ? cursor : 'help'; -}; - -/** - * Extends mxEventSource. - */ -mxCellOverlay.prototype = new mxEventSource(); -mxCellOverlay.prototype.constructor = mxCellOverlay; - -/** - * Variable: image - * - * Holds the <mxImage> to be used as the icon. - */ -mxCellOverlay.prototype.image = null; - -/** - * Variable: tooltip - * - * Holds the optional string to be used as the tooltip. - */ -mxCellOverlay.prototype.tooltip = null; - -/** - * Variable: align - * - * Holds the horizontal alignment for the overlay. Default is - * <mxConstants.ALIGN_RIGHT>. For edges, the overlay always appears in the - * center of the edge. - */ -mxCellOverlay.prototype.align = mxConstants.ALIGN_RIGHT; - -/** - * Variable: verticalAlign - * - * Holds the vertical alignment for the overlay. Default is - * <mxConstants.ALIGN_BOTTOM>. For edges, the overlay always appears in the - * center of the edge. - */ -mxCellOverlay.prototype.verticalAlign = mxConstants.ALIGN_BOTTOM; - -/** - * Variable: offset - * - * Holds the offset as an <mxPoint>. The offset will be scaled according to the - * current scale. - */ -mxCellOverlay.prototype.offset = null; - -/** - * Variable: cursor - * - * Holds the cursor for the overlay. Default is 'help'. - */ -mxCellOverlay.prototype.cursor = null; - -/** - * Variable: defaultOverlap - * - * Defines the overlapping for the overlay, that is, the proportional distance - * from the origin to the point defined by the alignment. Default is 0.5. - */ -mxCellOverlay.prototype.defaultOverlap = 0.5; - -/** - * Function: getBounds - * - * Returns the bounds of the overlay for the given <mxCellState> as an - * <mxRectangle>. This should be overridden when using multiple overlays - * per cell so that the overlays do not overlap. - * - * The following example will place the overlay along an edge (where - * x=[-1..1] from the start to the end of the edge and y is the - * orthogonal offset in px). - * - * (code) - * overlay.getBounds = function(state) - * { - * var bounds = mxCellOverlay.prototype.getBounds.apply(this, arguments); - * - * if (state.view.graph.getModel().isEdge(state.cell)) - * { - * var pt = state.view.getPoint(state, {x: 0, y: 0, relative: true}); - * - * bounds.x = pt.x - bounds.width / 2; - * bounds.y = pt.y - bounds.height / 2; - * } - * - * return bounds; - * }; - * (end) - * - * Parameters: - * - * state - <mxCellState> that represents the current state of the - * associated cell. - */ -mxCellOverlay.prototype.getBounds = function(state) -{ - var isEdge = state.view.graph.getModel().isEdge(state.cell); - var s = state.view.scale; - var pt = null; - - var w = this.image.width; - var h = this.image.height; - - if (isEdge) - { - var pts = state.absolutePoints; - - if (pts.length % 2 == 1) - { - pt = pts[Math.floor(pts.length / 2)]; - } - else - { - var idx = pts.length / 2; - var p0 = pts[idx-1]; - var p1 = pts[idx]; - pt = new mxPoint(p0.x + (p1.x - p0.x) / 2, - p0.y + (p1.y - p0.y) / 2); - } - } - else - { - pt = new mxPoint(); - - if (this.align == mxConstants.ALIGN_LEFT) - { - pt.x = state.x; - } - else if (this.align == mxConstants.ALIGN_CENTER) - { - pt.x = state.x + state.width / 2; - } - else - { - pt.x = state.x + state.width; - } - - if (this.verticalAlign == mxConstants.ALIGN_TOP) - { - pt.y = state.y; - } - else if (this.verticalAlign == mxConstants.ALIGN_MIDDLE) - { - pt.y = state.y + state.height / 2; - } - else - { - pt.y = state.y + state.height; - } - } - - return new mxRectangle(pt.x - (w * this.defaultOverlap - this.offset.x) * s, - pt.y - (h * this.defaultOverlap - this.offset.y) * s, w * s, h * s); -}; - -/** - * Function: toString - * - * Returns the textual representation of the overlay to be used as the - * tooltip. This implementation returns <tooltip>. - */ -mxCellOverlay.prototype.toString = function() -{ - return this.tooltip; -}; diff --git a/src/js/view/mxCellRenderer.js b/src/js/view/mxCellRenderer.js deleted file mode 100644 index 6b506ad..0000000 --- a/src/js/view/mxCellRenderer.js +++ /dev/null @@ -1,1480 +0,0 @@ -/** - * $Id: mxCellRenderer.js,v 1.189 2012-11-20 09:06:07 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -/** - * Class: mxCellRenderer - * - * Renders cells into a document object model. The <defaultShapes> is a global - * map of shapename, constructor pairs that is used in all instances. You can - * get a list of all available shape names using the following code. - * - * In general the cell renderer is in charge of creating, redrawing and - * destroying the shape and label associated with a cell state, as well as - * some other graphical objects, namely controls and overlays. The shape - * hieararchy in the display (ie. the hierarchy in which the DOM nodes - * appear in the document) does not reflect the cell hierarchy. The shapes - * are a (flat) sequence of shapes and labels inside the draw pane of the - * graph view, with some exceptions, namely the HTML labels being placed - * directly inside the graph container for certain browsers. - * - * (code) - * mxLog.show(); - * for (var i in mxCellRenderer.prototype.defaultShapes) - * { - * mxLog.debug(i); - * } - * (end) - * - * Constructor: mxCellRenderer - * - * Constructs a new cell renderer with the following built-in shapes: - * arrow, rectangle, ellipse, rhombus, image, line, label, cylinder, - * swimlane, connector, actor and cloud. - */ -function mxCellRenderer() -{ - this.shapes = mxUtils.clone(this.defaultShapes); -}; - -/** - * Variable: shapes - * - * Array that maps from shape names to shape constructors. All entries - * in <defaultShapes> are added to this array. - */ -mxCellRenderer.prototype.shapes = null; - -/** - * Variable: defaultEdgeShape - * - * Defines the default shape for edges. Default is <mxConnector>. - */ -mxCellRenderer.prototype.defaultEdgeShape = mxConnector; - -/** - * Variable: defaultVertexShape - * - * Defines the default shape for vertices. Default is <mxRectangleShape>. - */ -mxCellRenderer.prototype.defaultVertexShape = mxRectangleShape; - -/** - * Variable: defaultShapes - * - * Static array that contains the globally registered shapes which are - * known to all instances of this class. For adding instance-specific - * shapes you should use <registerShape> on the instance. For adding - * a shape to this array you can use the following code: - * - * (code) - * mxCellRenderer.prototype.defaultShapes['myshape'] = myShape; - * (end) - * - * Where 'myshape' is the key under which the shape is to be registered - * and myShape is the name of the constructor function. - */ -mxCellRenderer.prototype.defaultShapes = new Object(); - -// Adds default shapes into the default shapes array -mxCellRenderer.prototype.defaultShapes[mxConstants.SHAPE_ARROW] = mxArrow; -mxCellRenderer.prototype.defaultShapes[mxConstants.SHAPE_RECTANGLE] = mxRectangleShape; -mxCellRenderer.prototype.defaultShapes[mxConstants.SHAPE_ELLIPSE] = mxEllipse; -mxCellRenderer.prototype.defaultShapes[mxConstants.SHAPE_DOUBLE_ELLIPSE] = mxDoubleEllipse; -mxCellRenderer.prototype.defaultShapes[mxConstants.SHAPE_RHOMBUS] = mxRhombus; -mxCellRenderer.prototype.defaultShapes[mxConstants.SHAPE_IMAGE] = mxImageShape; -mxCellRenderer.prototype.defaultShapes[mxConstants.SHAPE_LINE] = mxLine; -mxCellRenderer.prototype.defaultShapes[mxConstants.SHAPE_LABEL] = mxLabel; -mxCellRenderer.prototype.defaultShapes[mxConstants.SHAPE_CYLINDER] = mxCylinder; -mxCellRenderer.prototype.defaultShapes[mxConstants.SHAPE_SWIMLANE] = mxSwimlane; -mxCellRenderer.prototype.defaultShapes[mxConstants.SHAPE_CONNECTOR] = mxConnector; -mxCellRenderer.prototype.defaultShapes[mxConstants.SHAPE_ACTOR] = mxActor; -mxCellRenderer.prototype.defaultShapes[mxConstants.SHAPE_CLOUD] = mxCloud; -mxCellRenderer.prototype.defaultShapes[mxConstants.SHAPE_TRIANGLE] = mxTriangle; -mxCellRenderer.prototype.defaultShapes[mxConstants.SHAPE_HEXAGON] = mxHexagon; - -/** - * Function: registerShape - * - * Registers the given constructor under the specified key in this instance - * of the renderer. - * - * Example: - * - * (code) - * this.registerShape(mxConstants.SHAPE_RECTANGLE, mxRectangleShape); - * (end) - * - * Parameters: - * - * key - String representing the shape name. - * shape - Constructor of the <mxShape> subclass. - */ -mxCellRenderer.prototype.registerShape = function(key, shape) -{ - this.shapes[key] = shape; -}; - -/** - * Function: initialize - * - * Initializes the display for the given cell state. This is required once - * after the cell state has been created. This is invoked in - * mxGraphView.createState. - * - * Parameters: - * - * state - <mxCellState> for which the display should be initialized. - * rendering - Optional boolean that specifies if the cell should actually - * be initialized for any given DOM node. If this is false then init - * will not be called on the shape. - */ -mxCellRenderer.prototype.initialize = function(state, rendering) -{ - var model = state.view.graph.getModel(); - - if (state.view.graph.container != null && state.shape == null && - state.cell != state.view.currentRoot && - (model.isVertex(state.cell) || model.isEdge(state.cell))) - { - this.createShape(state); - - if (state.shape != null && (rendering == null || rendering)) - { - this.initializeShape(state); - - // Maintains the model order in the DOM - if (state.view.graph.ordered || model.isEdge(state.cell)) - { - //state.orderChanged = true; - state.invalidOrder = true; - } - else if (state.view.graph.keepEdgesInForeground && this.firstEdge != null) - { - if (this.firstEdge.parentNode == state.shape.node.parentNode) - { - this.insertState(state, this.firstEdge); - } - else - { - this.firstEdge = null; - } - } - - state.shape.scale = state.view.scale; - - this.createCellOverlays(state); - this.installListeners(state); - } - } -}; - -/** - * Function: initializeShape - * - * Initializes the shape in the given state by calling its init method with - * the correct container. - * - * Parameters: - * - * state - <mxCellState> for which the shape should be initialized. - */ -mxCellRenderer.prototype.initializeShape = function(state) -{ - state.shape.init(state.view.getDrawPane()); -}; - -/** - * Returns the previous state that has a shape inside the given parent. - */ -mxCellRenderer.prototype.getPreviousStateInContainer = function(state, container) -{ - var result = null; - var graph = state.view.graph; - var model = graph.getModel(); - var child = state.cell; - var p = model.getParent(child); - - while (p != null && result == null) - { - result = this.findPreviousStateInContainer(graph, p, child, container); - child = p; - p = model.getParent(child); - } - - return result; -}; - -/** - * Returns the previous state that has a shape inside the given parent. - */ -mxCellRenderer.prototype.findPreviousStateInContainer = function(graph, cell, stop, container) -{ - // Recurse first - var result = null; - var model = graph.getModel(); - - if (stop != null) - { - var start = cell.getIndex(stop); - - for (var i = start - 1; i >= 0 && result == null; i--) - { - result = this.findPreviousStateInContainer(graph, model.getChildAt(cell, i), null, container); - } - } - else - { - var childCount = model.getChildCount(cell); - - for (var i = childCount - 1; i >= 0 && result == null; i--) - { - result = this.findPreviousStateInContainer(graph, model.getChildAt(cell, i), null, container); - } - } - - if (result == null) - { - result = graph.view.getState(cell); - - if (result != null && (result.shape == null || result.shape.node == null || - result.shape.node.parentNode != container)) - { - result = null; - } - } - - return result; -}; - -/** - * Function: order - * - * Orders the DOM node of the shape for the given state according to the - * position of the corresponding cell in the graph model. - * - * Parameters: - * - * state - <mxCellState> whose shape's DOM node should be ordered. - */ -mxCellRenderer.prototype.order = function(state) -{ - var container = state.shape.node.parentNode; - var previous = this.getPreviousStateInContainer(state, container); - var nextNode = container.firstChild; - - if (previous != null) - { - nextNode = previous.shape.node; - - if (previous.text != null && previous.text.node != null && - previous.text.node.parentNode == container) - { - nextNode = previous.text.node; - } - - nextNode = nextNode.nextSibling; - } - - this.insertState(state, nextNode); -}; - -/** - * Function: orderEdge - * - * Orders the DOM node of the shape for the given edge's state according to - * the <mxGraph.keepEdgesInBackground> and <mxGraph.keepEdgesInBackground> - * rules. - * - * Parameters: - * - * state - <mxCellState> whose shape's DOM node should be ordered. - */ -mxCellRenderer.prototype.orderEdge = function(state) -{ - var view = state.view; - var model = view.graph.getModel(); - - // Moves edges to the foreground/background - if (view.graph.keepEdgesInForeground) - { - if (this.firstEdge == null || this.firstEdge.parentNode == null || - this.firstEdge.parentNode != state.shape.node.parentNode) - { - this.firstEdge = state.shape.node; - } - } - else if (view.graph.keepEdgesInBackground) - { - var node = state.shape.node; - var parent = node.parentNode; - - // Keeps the DOM node in front of its parent - var pcell = model.getParent(state.cell); - var pstate = view.getState(pcell); - - if (pstate != null && pstate.shape != null && pstate.shape.node != null) - { - var child = pstate.shape.node.nextSibling; - - if (child != null && child != node) - { - this.insertState(state, child); - } - } - else - { - var child = parent.firstChild; - - if (child != null && child != node) - { - this.insertState(state, child); - } - } - } -}; - -/** - * Function: insertState - * - * Inserts the given state before the given node into its parent. - * - * Parameters: - * - * state - <mxCellState> for which the shape should be created. - */ -mxCellRenderer.prototype.insertState = function(state, nextNode) -{ - state.shape.node.parentNode.insertBefore(state.shape.node, nextNode); - - if (state.text != null && state.text.node != null && - state.text.node.parentNode == state.shape.node.parentNode) - { - state.shape.node.parentNode.insertBefore(state.text.node, state.shape.node.nextSibling); - } -}; - -/** - * Function: createShape - * - * Creates the shape for the given cell state. The shape is configured - * using <configureShape>. - * - * Parameters: - * - * state - <mxCellState> for which the shape should be created. - */ -mxCellRenderer.prototype.createShape = function(state) -{ - if (state.style != null) - { - // Checks if there is a stencil for the name and creates - // a shape instance for the stencil if one exists - var key = state.style[mxConstants.STYLE_SHAPE]; - var stencil = mxStencilRegistry.getStencil(key); - - if (stencil != null) - { - state.shape = new mxStencilShape(stencil); - } - else - { - var ctor = this.getShapeConstructor(state); - state.shape = new ctor(); - } - - // Sets the initial bounds and points (will be updated in redraw) - state.shape.points = state.absolutePoints; - state.shape.bounds = new mxRectangle( - state.x, state.y, state.width, state.height); - state.shape.dialect = state.view.graph.dialect; - - this.configureShape(state); - } -}; - -/** - * Function: getShapeConstructor - * - * Returns the constructor to be used for creating the shape. - */ -mxCellRenderer.prototype.getShapeConstructor = function(state) -{ - var key = state.style[mxConstants.STYLE_SHAPE]; - var ctor = (key != null) ? this.shapes[key] : null; - - if (ctor == null) - { - ctor = (state.view.graph.getModel().isEdge(state.cell)) ? - this.defaultEdgeShape : this.defaultVertexShape; - } - - return ctor; -}; - -/** - * Function: configureShape - * - * Configures the shape for the given cell state. - * - * Parameters: - * - * state - <mxCellState> for which the shape should be configured. - */ -mxCellRenderer.prototype.configureShape = function(state) -{ - state.shape.apply(state); - var image = state.view.graph.getImage(state); - - if (image != null) - { - state.shape.image = image; - } - - var indicator = state.view.graph.getIndicatorColor(state); - var key = state.view.graph.getIndicatorShape(state); - var ctor = (key != null) ? this.shapes[key] : null; - - // Configures the indicator shape or image - if (indicator != null) - { - state.shape.indicatorShape = ctor; - state.shape.indicatorColor = indicator; - state.shape.indicatorGradientColor = - state.view.graph.getIndicatorGradientColor(state); - state.shape.indicatorDirection = - state.style[mxConstants.STYLE_INDICATOR_DIRECTION]; - } - else - { - var indicator = state.view.graph.getIndicatorImage(state); - - if (indicator != null) - { - state.shape.indicatorImage = indicator; - } - } - - this.postConfigureShape(state); -}; - -/** - * Function: postConfigureShape - * - * Replaces any reserved words used for attributes, eg. inherit, - * indicated or swimlane for colors in the shape for the given state. - * This implementation resolves these keywords on the fill, stroke - * and gradient color keys. - */ -mxCellRenderer.prototype.postConfigureShape = function(state) -{ - if (state.shape != null) - { - this.resolveColor(state, 'indicatorColor', mxConstants.STYLE_FILLCOLOR); - this.resolveColor(state, 'indicatorGradientColor', mxConstants.STYLE_GRADIENTCOLOR); - this.resolveColor(state, 'fill', mxConstants.STYLE_FILLCOLOR); - this.resolveColor(state, 'stroke', mxConstants.STYLE_STROKECOLOR); - this.resolveColor(state, 'gradient', mxConstants.STYLE_GRADIENTCOLOR); - } -}; - -/** - * Function: resolveColor - * - * Resolves special keywords 'inherit', 'indicated' and 'swimlane' and sets - * the respective color on the shape. - */ -mxCellRenderer.prototype.resolveColor = function(state, field, key) -{ - var value = state.shape[field]; - var graph = state.view.graph; - var referenced = null; - - if (value == 'inherit') - { - referenced = graph.model.getParent(state.cell); - } - else if (value == 'swimlane') - { - if (graph.model.getTerminal(state.cell, false) != null) - { - referenced = graph.model.getTerminal(state.cell, false); - } - else - { - referenced = state.cell; - } - - referenced = graph.getSwimlane(referenced); - key = graph.swimlaneIndicatorColorAttribute; - } - else if (value == 'indicated') - { - state.shape[field] = state.shape.indicatorColor; - } - - if (referenced != null) - { - var rstate = graph.getView().getState(referenced); - state.shape[field] = null; - - if (rstate != null) - { - if (rstate.shape != null && field != 'indicatorColor') - { - state.shape[field] = rstate.shape[field]; - } - else - { - state.shape[field] = rstate.style[key]; - } - } - } -}; - -/** - * Function: getLabelValue - * - * Returns the value to be used for the label. - * - * Parameters: - * - * state - <mxCellState> for which the label should be created. - */ -mxCellRenderer.prototype.getLabelValue = function(state) -{ - var graph = state.view.graph; - var value = graph.getLabel(state.cell); - - if (!graph.isHtmlLabel(state.cell) && !mxUtils.isNode(value) && - graph.dialect != mxConstants.DIALECT_SVG && value != null) - { - value = mxUtils.htmlEntities(value, false); - } - - return value; -}; - -/** - * Function: createLabel - * - * Creates the label for the given cell state. - * - * Parameters: - * - * state - <mxCellState> for which the label should be created. - */ -mxCellRenderer.prototype.createLabel = function(state, value) -{ - var graph = state.view.graph; - var isEdge = graph.getModel().isEdge(state.cell); - - if (state.style[mxConstants.STYLE_FONTSIZE] > 0 || - state.style[mxConstants.STYLE_FONTSIZE] == null) - { - // Avoids using DOM node for empty labels - var isForceHtml = (graph.isHtmlLabel(state.cell) || - (value != null && mxUtils.isNode(value))) && - graph.dialect == mxConstants.DIALECT_SVG; - - state.text = new mxText(value, new mxRectangle(), - (state.style[mxConstants.STYLE_ALIGN] || - mxConstants.ALIGN_CENTER), - graph.getVerticalAlign(state), - state.style[mxConstants.STYLE_FONTCOLOR], - state.style[mxConstants.STYLE_FONTFAMILY], - state.style[mxConstants.STYLE_FONTSIZE], - state.style[mxConstants.STYLE_FONTSTYLE], - state.style[mxConstants.STYLE_SPACING], - state.style[mxConstants.STYLE_SPACING_TOP], - state.style[mxConstants.STYLE_SPACING_RIGHT], - state.style[mxConstants.STYLE_SPACING_BOTTOM], - state.style[mxConstants.STYLE_SPACING_LEFT], - state.style[mxConstants.STYLE_HORIZONTAL], - state.style[mxConstants.STYLE_LABEL_BACKGROUNDCOLOR], - state.style[mxConstants.STYLE_LABEL_BORDERCOLOR], - graph.isWrapping(state.cell) && graph.isHtmlLabel(state.cell), - graph.isLabelClipped(state.cell), - state.style[mxConstants.STYLE_OVERFLOW], - state.style[mxConstants.STYLE_LABEL_PADDING]); - state.text.opacity = state.style[mxConstants.STYLE_TEXT_OPACITY]; - - state.text.dialect = (isForceHtml) ? - mxConstants.DIALECT_STRICTHTML : - state.view.graph.dialect; - this.initializeLabel(state); - - // Workaround for touch devices routing all events for a mouse - // gesture (down, move, up) via the initial DOM node. IE is even - // worse in that it redirects the event via the initial DOM node - // but the event source is the node under the mouse, so we need - // to check if this is the case and force getCellAt for the - // subsequent mouseMoves and the final mouseUp. - var forceGetCell = false; - - var getState = function(evt) - { - var result = state; - - if (mxClient.IS_TOUCH || forceGetCell) - { - var x = mxEvent.getClientX(evt); - var y = mxEvent.getClientY(evt); - - // Dispatches the drop event to the graph which - // consumes and executes the source function - var pt = mxUtils.convertPoint(graph.container, x, y); - result = graph.view.getState(graph.getCellAt(pt.x, pt.y)); - } - - return result; - }; - - // TODO: Add handling for gestures - var md = (mxClient.IS_TOUCH) ? 'touchstart' : 'mousedown'; - var mm = (mxClient.IS_TOUCH) ? 'touchmove' : 'mousemove'; - var mu = (mxClient.IS_TOUCH) ? 'touchend' : 'mouseup'; - - mxEvent.addListener(state.text.node, md, - mxUtils.bind(this, function(evt) - { - if (this.isLabelEvent(state, evt)) - { - graph.fireMouseEvent(mxEvent.MOUSE_DOWN, - new mxMouseEvent(evt, state)); - forceGetCell = graph.dialect != mxConstants.DIALECT_SVG && mxEvent.getSource(evt).nodeName == 'IMG'; - } - }) - ); - - mxEvent.addListener(state.text.node, mm, - mxUtils.bind(this, function(evt) - { - if (this.isLabelEvent(state, evt)) - { - graph.fireMouseEvent(mxEvent.MOUSE_MOVE, - new mxMouseEvent(evt, getState(evt))); - } - }) - ); - - mxEvent.addListener(state.text.node, mu, - mxUtils.bind(this, function(evt) - { - if (this.isLabelEvent(state, evt)) - { - graph.fireMouseEvent(mxEvent.MOUSE_UP, - new mxMouseEvent(evt, getState(evt))); - forceGetCell = false; - } - }) - ); - - mxEvent.addListener(state.text.node, 'dblclick', - mxUtils.bind(this, function(evt) - { - if (this.isLabelEvent(state, evt)) - { - graph.dblClick(evt, state.cell); - mxEvent.consume(evt); - } - }) - ); - } -}; - -/** - * Function: initializeLabel - * - * Initiailzes the label with a suitable container. - * - * Parameters: - * - * state - <mxCellState> whose label should be initialized. - */ -mxCellRenderer.prototype.initializeLabel = function(state) -{ - var graph = state.view.graph; - - if (state.text.dialect != mxConstants.DIALECT_SVG) - { - // Adds the text to the container if the dialect is not SVG and we - // have an SVG-based browser which doesn't support foreignObjects - if (mxClient.IS_SVG && mxClient.NO_FO) - { - state.text.init(graph.container); - } - else if (mxUtils.isVml(state.view.getDrawPane())) - { - if (state.shape.label != null) - { - state.text.init(state.shape.label); - } - else - { - state.text.init(state.shape.node); - } - } - } - - if (state.text.node == null) - { - state.text.init(state.view.getDrawPane()); - - if (state.shape != null && state.text != null) - { - state.shape.node.parentNode.insertBefore( - state.text.node, state.shape.node.nextSibling); - } - } -}; - -/** - * Function: createCellOverlays - * - * Creates the actual shape for showing the overlay for the given cell state. - * - * Parameters: - * - * state - <mxCellState> for which the overlay should be created. - */ -mxCellRenderer.prototype.createCellOverlays = function(state) -{ - var graph = state.view.graph; - var overlays = graph.getCellOverlays(state.cell); - var dict = null; - - if (overlays != null) - { - dict = new mxDictionary(); - - for (var i = 0; i < overlays.length; i++) - { - var shape = (state.overlays != null) ? state.overlays.remove(overlays[i]) : null; - - if (shape == null) - { - var tmp = new mxImageShape(new mxRectangle(), - overlays[i].image.src); - tmp.dialect = state.view.graph.dialect; - tmp.preserveImageAspect = false; - tmp.overlay = overlays[i]; - this.initializeOverlay(state, tmp); - this.installCellOverlayListeners(state, overlays[i], tmp); - - if (overlays[i].cursor != null) - { - tmp.node.style.cursor = overlays[i].cursor; - } - - dict.put(overlays[i], tmp); - } - else - { - dict.put(overlays[i], shape); - } - } - } - - // Removes unused - if (state.overlays != null) - { - state.overlays.visit(function(id, shape) - { - shape.destroy(); - }); - } - - state.overlays = dict; -}; - -/** - * Function: initializeOverlay - * - * Initializes the given overlay. - * - * Parameters: - * - * state - <mxCellState> for which the overlay should be created. - * overlay - <mxImageShape> that represents the overlay. - */ -mxCellRenderer.prototype.initializeOverlay = function(state, overlay) -{ - overlay.init(state.view.getOverlayPane()); -}; - -/** - * Function: installOverlayListeners - * - * Installs the listeners for the given <mxCellState>, <mxCellOverlay> and - * <mxShape> that represents the overlay. - */ -mxCellRenderer.prototype.installCellOverlayListeners = function(state, overlay, shape) -{ - var graph = state.view.graph; - - mxEvent.addListener(shape.node, 'click', function (evt) - { - if (graph.isEditing()) - { - graph.stopEditing(!graph.isInvokesStopCellEditing()); - } - - overlay.fireEvent(new mxEventObject(mxEvent.CLICK, - 'event', evt, 'cell', state.cell)); - }); - - var md = (mxClient.IS_TOUCH) ? 'touchstart' : 'mousedown'; - var mm = (mxClient.IS_TOUCH) ? 'touchmove' : 'mousemove'; - - mxEvent.addListener(shape.node, md, function (evt) - { - mxEvent.consume(evt); - }); - - mxEvent.addListener(shape.node, mm, function (evt) - { - graph.fireMouseEvent(mxEvent.MOUSE_MOVE, - new mxMouseEvent(evt, state)); - }); - - if (mxClient.IS_TOUCH) - { - mxEvent.addListener(shape.node, 'touchend', function (evt) - { - overlay.fireEvent(new mxEventObject(mxEvent.CLICK, - 'event', evt, 'cell', state.cell)); - }); - } -}; - -/** - * Function: createControl - * - * Creates the control for the given cell state. - * - * Parameters: - * - * state - <mxCellState> for which the control should be created. - */ -mxCellRenderer.prototype.createControl = function(state) -{ - var graph = state.view.graph; - var image = graph.getFoldingImage(state); - - if (graph.foldingEnabled && image != null) - { - if (state.control == null) - { - var b = new mxRectangle(0, 0, image.width, image.height); - state.control = new mxImageShape(b, image.src); - state.control.dialect = graph.dialect; - state.control.preserveImageAspect = false; - - this.initControl(state, state.control, true, function (evt) - { - if (graph.isEnabled()) - { - var collapse = !graph.isCellCollapsed(state.cell); - graph.foldCells(collapse, false, [state.cell]); - mxEvent.consume(evt); - } - }); - } - } - else if (state.control != null) - { - state.control.destroy(); - state.control = null; - } -}; - -/** - * Function: initControl - * - * Initializes the given control and returns the corresponding DOM node. - * - * Parameters: - * - * state - <mxCellState> for which the control should be initialized. - * control - <mxShape> to be initialized. - * handleEvents - Boolean indicating if mousedown and mousemove should fire events via the graph. - * clickHandler - Optional function to implement clicks on the control. - */ -mxCellRenderer.prototype.initControl = function(state, control, handleEvents, clickHandler) -{ - var graph = state.view.graph; - - // In the special case where the label is in HTML and the display is SVG the image - // should go into the graph container directly in order to be clickable. Otherwise - // it is obscured by the HTML label that overlaps the cell. - var isForceHtml = graph.isHtmlLabel(state.cell) && - mxClient.NO_FO && - graph.dialect == mxConstants.DIALECT_SVG; - - if (isForceHtml) - { - control.dialect = mxConstants.DIALECT_PREFERHTML; - control.init(graph.container); - control.node.style.zIndex = 1; - } - else - { - control.init(state.view.getOverlayPane()); - } - - var node = control.innerNode || control.node; - - if (clickHandler) - { - if (graph.isEnabled()) - { - node.style.cursor = 'pointer'; - } - - mxEvent.addListener(node, 'click', clickHandler); - } - - if (handleEvents) - { - var md = (mxClient.IS_TOUCH) ? 'touchstart' : 'mousedown'; - var mm = (mxClient.IS_TOUCH) ? 'touchmove' : 'mousemove'; - - mxEvent.addListener(node, md, function (evt) - { - graph.fireMouseEvent(mxEvent.MOUSE_DOWN, new mxMouseEvent(evt, state)); - mxEvent.consume(evt); - }); - - mxEvent.addListener(node, mm, function (evt) - { - graph.fireMouseEvent(mxEvent.MOUSE_MOVE, new mxMouseEvent(evt, state)); - }); - } - - return node; -}; - -/** - * Function: isShapeEvent - * - * Returns true if the event is for the shape of the given state. This - * implementation always returns true. - * - * Parameters: - * - * state - <mxCellState> whose shape fired the event. - * evt - Mouse event which was fired. - */ -mxCellRenderer.prototype.isShapeEvent = function(state, evt) -{ - return true; -}; - -/** - * Function: isLabelEvent - * - * Returns true if the event is for the label of the given state. This - * implementation always returns true. - * - * Parameters: - * - * state - <mxCellState> whose label fired the event. - * evt - Mouse event which was fired. - */ -mxCellRenderer.prototype.isLabelEvent = function(state, evt) -{ - return true; -}; - -/** - * Function: installListeners - * - * Installs the event listeners for the given cell state. - * - * Parameters: - * - * state - <mxCellState> for which the event listeners should be isntalled. - */ -mxCellRenderer.prototype.installListeners = function(state) -{ - var graph = state.view.graph; - - // Receives events from transparent backgrounds - if (graph.dialect == mxConstants.DIALECT_SVG) - { - var events = 'all'; - - // Disabled fill-events on non-filled edges - if (graph.getModel().isEdge(state.cell) && state.shape.stroke != null && - (state.shape.fill == null || state.shape.fill == mxConstants.NONE)) - { - events = 'visibleStroke'; - } - - // Specifies the event-processing on the shape - if (state.shape.innerNode != null) - { - state.shape.innerNode.setAttribute('pointer-events', events); - } - else - { - state.shape.node.setAttribute('pointer-events', events); - } - } - - // Workaround for touch devices routing all events for a mouse - // gesture (down, move, up) via the initial DOM node. Same for - // HTML images in all IE versions (VML images are working). - var getState = function(evt) - { - var result = state; - - if ((graph.dialect != mxConstants.DIALECT_SVG && mxEvent.getSource(evt).nodeName == 'IMG') || mxClient.IS_TOUCH) - { - var x = mxEvent.getClientX(evt); - var y = mxEvent.getClientY(evt); - - // Dispatches the drop event to the graph which - // consumes and executes the source function - var pt = mxUtils.convertPoint(graph.container, x, y); - result = graph.view.getState(graph.getCellAt(pt.x, pt.y)); - } - - return result; - }; - - // Experimental support for two-finger pinch to resize cells - var gestureInProgress = false; - - mxEvent.addListener(state.shape.node, 'gesturestart', - mxUtils.bind(this, function(evt) - { - // FIXME: Breaks encapsulation to reset the double - // tap event handling when gestures take place - graph.lastTouchTime = 0; - - gestureInProgress = true; - mxEvent.consume(evt); - }) - ); - - var md = (mxClient.IS_TOUCH) ? 'touchstart' : 'mousedown'; - var mm = (mxClient.IS_TOUCH) ? 'touchmove' : 'mousemove'; - var mu = (mxClient.IS_TOUCH) ? 'touchend' : 'mouseup'; - - mxEvent.addListener(state.shape.node, md, - mxUtils.bind(this, function(evt) - { - if (this.isShapeEvent(state, evt) && !gestureInProgress) - { - // Redirects events from the "event-transparent" region of - // a swimlane to the graph. This is only required in HTML, - // SVG and VML do not fire mouse events on transparent - // backgrounds. - graph.fireMouseEvent(mxEvent.MOUSE_DOWN, - new mxMouseEvent(evt, (state.shape != null && - mxEvent.getSource(evt) == state.shape.content) ? - null : state)); - } - else if (gestureInProgress) - { - mxEvent.consume(evt); - } - }) - ); - - mxEvent.addListener(state.shape.node, mm, - mxUtils.bind(this, function(evt) - { - if (this.isShapeEvent(state, evt) && !gestureInProgress) - { - graph.fireMouseEvent(mxEvent.MOUSE_MOVE, - new mxMouseEvent(evt, (state.shape != null && - mxEvent.getSource(evt) == state.shape.content) ? - null : getState(evt))); - } - else if (gestureInProgress) - { - mxEvent.consume(evt); - } - }) - ); - - mxEvent.addListener(state.shape.node, mu, - mxUtils.bind(this, function(evt) - { - if (this.isShapeEvent(state, evt) && !gestureInProgress) - { - graph.fireMouseEvent(mxEvent.MOUSE_UP, - new mxMouseEvent(evt, (state.shape != null && - mxEvent.getSource(evt) == state.shape.content) ? - null : getState(evt))); - } - else if (gestureInProgress) - { - mxEvent.consume(evt); - } - }) - ); - - // Experimental handling for gestures. Double-tap handling is implemented - // in mxGraph.fireMouseEvent. - var dc = (mxClient.IS_TOUCH) ? 'gestureend' : 'dblclick'; - - mxEvent.addListener(state.shape.node, dc, - mxUtils.bind(this, function(evt) - { - gestureInProgress = false; - - if (dc == 'gestureend') - { - // FIXME: Breaks encapsulation to reset the double - // tap event handling when gestures take place - graph.lastTouchTime = 0; - - if (graph.gestureEnabled) - { - graph.handleGesture(state, evt); - mxEvent.consume(evt); - } - } - else if (this.isShapeEvent(state, evt)) - { - graph.dblClick(evt, (state.shape != null && - mxEvent.getSource(evt) == state.shape.content) ? - null : state.cell); - mxEvent.consume(evt); - } - }) - ); -}; - -/** - * Function: redrawLabel - * - * Redraws the label for the given cell state. - * - * Parameters: - * - * state - <mxCellState> whose label should be redrawn. - */ -mxCellRenderer.prototype.redrawLabel = function(state) -{ - var value = this.getLabelValue(state); - - // FIXME: Add label always if HTML label and NO_FO - if (state.text == null && value != null && (mxUtils.isNode(value) || value.length > 0)) - { - this.createLabel(state, value); - } - else if (state.text != null && (value == null || value.length == 0)) - { - state.text.destroy(); - state.text = null; - } - - if (state.text != null) - { - var graph = state.view.graph; - var wrapping = graph.isWrapping(state.cell); - var clipping = graph.isLabelClipped(state.cell); - var bounds = this.getLabelBounds(state); - - if (state.text.value != value || state.text.isWrapping != wrapping || - state.text.isClipping != clipping || state.text.scale != state.view.scale || - !state.text.bounds.equals(bounds)) - { - state.text.value = value; - state.text.bounds = bounds; - state.text.scale = this.getTextScale(state); - state.text.isWrapping = wrapping; - state.text.isClipping = clipping; - - state.text.redraw(); - } - } -}; - -/** - * Function: getTextScale - * - * Returns the scaling used for the label of the given state - * - * Parameters: - * - * state - <mxCellState> whose label scale should be returned. - */ -mxCellRenderer.prototype.getTextScale = function(state) -{ - return state.view.scale; -}; - -/** - * Function: getLabelBounds - * - * Returns the bounds to be used to draw the label of the given state. - * - * Parameters: - * - * state - <mxCellState> whose label bounds should be returned. - */ -mxCellRenderer.prototype.getLabelBounds = function(state) -{ - var graph = state.view.graph; - var isEdge = graph.getModel().isEdge(state.cell); - var bounds = new mxRectangle(state.absoluteOffset.x, state.absoluteOffset.y); - - if (!isEdge) - { - bounds.x += state.x; - bounds.y += state.y; - - // Minimum of 1 fixes alignment bug in HTML labels - bounds.width = Math.max(1, state.width); - bounds.height = Math.max(1, state.height); - - if (graph.isSwimlane(state.cell)) - { - var scale = graph.view.scale; - var size = graph.getStartSize(state.cell); - - if (size.width > 0) - { - bounds.width = size.width * scale; - } - else if (size.height > 0) - { - bounds.height = size.height * scale; - } - } - } - - return bounds; -}; - -/** - * Function: redrawCellOverlays - * - * Redraws the overlays for the given cell state. - * - * Parameters: - * - * state - <mxCellState> whose overlays should be redrawn. - */ -mxCellRenderer.prototype.redrawCellOverlays = function(state) -{ - this.createCellOverlays(state); - - if (state.overlays != null) - { - state.overlays.visit(function(id, shape) - { - var bounds = shape.overlay.getBounds(state); - - if (shape.bounds == null || shape.scale != state.view.scale || - !shape.bounds.equals(bounds)) - { - shape.bounds = bounds; - shape.scale = state.view.scale; - shape.redraw(); - } - }); - } -}; - -/** - * Function: redrawControl - * - * Redraws the control for the given cell state. - * - * Parameters: - * - * state - <mxCellState> whose control should be redrawn. - */ -mxCellRenderer.prototype.redrawControl = function(state) -{ - if (state.control != null) - { - var bounds = this.getControlBounds(state); - var s = state.view.scale; - - if (state.control.scale != s || !state.control.bounds.equals(bounds)) - { - state.control.bounds = bounds; - state.control.scale = s; - state.control.redraw(); - } - } -}; - -/** - * Function: getControlBounds - * - * Returns the bounds to be used to draw the control (folding icon) of the - * given state. - */ -mxCellRenderer.prototype.getControlBounds = function(state) -{ - if (state.control != null) - { - var oldScale = state.control.scale; - var w = state.control.bounds.width / oldScale; - var h = state.control.bounds.height / oldScale; - var s = state.view.scale; - - return (state.view.graph.getModel().isEdge(state.cell)) ? - new mxRectangle(state.x + state.width / 2 - w / 2 * s, - state.y + state.height / 2 - h / 2 * s, w * s, h * s) - : new mxRectangle(state.x + w / 2 * s, - state.y + h / 2 * s, w * s, h * s); - } - - return null; -}; - -/** - * Function: redraw - * - * Updates the bounds or points and scale of the shapes for the given cell - * state. This is called in mxGraphView.validatePoints as the last step of - * updating all cells. - * - * Parameters: - * - * state - <mxCellState> for which the shapes should be updated. - * force - Optional boolean that specifies if the cell should be reconfiured - * and redrawn without any additional checks. - * rendering - Optional boolean that specifies if the cell should actually - * be drawn into the DOM. If this is false then redraw and/or reconfigure - * will not be called on the shape. - */ -mxCellRenderer.prototype.redraw = function(state, force, rendering) -{ - if (state.shape != null) - { - var model = state.view.graph.getModel(); - var isEdge = model.isEdge(state.cell); - reconfigure = (force != null) ? force : false; - - // Handles changes of the collapse icon - this.createControl(state); - - // Handles changes to the order in the DOM - if (state.orderChanged || state.invalidOrder) - { - if (state.view.graph.ordered) - { - this.order(state); - } - else - { - // Assert state.cell is edge - this.orderEdge(state); - } - - // Required to update inherited styles - reconfigure = state.orderChanged; - } - - delete state.invalidOrder; - delete state.orderChanged; - - // Checks if the style in the state is different from the style - // in the shape and re-applies the style if required - if (!reconfigure && !mxUtils.equalEntries(state.shape.style, state.style)) - { - reconfigure = true; - } - - // Reconfiures the shape after an order or style change - if (reconfigure) - { - this.configureShape(state); - state.shape.reconfigure(); - } - - // Redraws the cell if required - if (force || state.shape.bounds == null || state.shape.scale != state.view.scale || - !state.shape.bounds.equals(state) || - !mxUtils.equalPoints(state.shape.points, state.absolutePoints)) - { - // FIXME: Move indicator color update into shape.redraw -// var indicator = state.view.graph.getIndicatorColor(state); -// if (indicator != null) -// { -// state.shape.indicatorColor = indicator; -// } - - if (state.absolutePoints != null) - { - state.shape.points = state.absolutePoints.slice(); - } - else - { - state.shape.points = null; - } - - state.shape.bounds = new mxRectangle( - state.x, state.y, state.width, state.height); - state.shape.scale = state.view.scale; - - if (rendering == null || rendering) - { - state.shape.redraw(); - } - else - { - state.shape.updateBoundingBox(); - } - } - - // Updates the text label, overlays and control - if (rendering == null || rendering) - { - this.redrawLabel(state); - this.redrawCellOverlays(state); - this.redrawControl(state); - } - } -}; - -/** - * Function: destroy - * - * Destroys the shapes associated with the given cell state. - * - * Parameters: - * - * state - <mxCellState> for which the shapes should be destroyed. - */ -mxCellRenderer.prototype.destroy = function(state) -{ - if (state.shape != null) - { - if (state.text != null) - { - state.text.destroy(); - state.text = null; - } - - if (state.overlays != null) - { - state.overlays.visit(function(id, shape) - { - shape.destroy(); - }); - - state.overlays = null; - } - - if (state.control != null) - { - state.control.destroy(); - state.control = null; - } - - state.shape.destroy(); - state.shape = null; - } -}; diff --git a/src/js/view/mxCellState.js b/src/js/view/mxCellState.js deleted file mode 100644 index 7e7a3b0..0000000 --- a/src/js/view/mxCellState.js +++ /dev/null @@ -1,375 +0,0 @@ -/** - * $Id: mxCellState.js,v 1.42 2012-03-19 10:47:08 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -/** - * Class: mxCellState - * - * Represents the current state of a cell in a given <mxGraphView>. - * - * For edges, the edge label position is stored in <absoluteOffset>. - * - * The size for oversize labels can be retrieved using the boundingBox property - * of the <text> field as shown below. - * - * (code) - * var bbox = (state.text != null) ? state.text.boundingBox : null; - * (end) - * - * Constructor: mxCellState - * - * Constructs a new object that represents the current state of the given - * cell in the specified view. - * - * Parameters: - * - * view - <mxGraphView> that contains the state. - * cell - <mxCell> that this state represents. - * style - Array of key, value pairs that constitute the style. - */ -function mxCellState(view, cell, style) -{ - this.view = view; - this.cell = cell; - this.style = style; - - this.origin = new mxPoint(); - this.absoluteOffset = new mxPoint(); -}; - -/** - * Extends mxRectangle. - */ -mxCellState.prototype = new mxRectangle(); -mxCellState.prototype.constructor = mxCellState; - -/** - * Variable: view - * - * Reference to the enclosing <mxGraphView>. - */ -mxCellState.prototype.view = null; - -/** - * Variable: cell - * - * Reference to the <mxCell> that is represented by this state. - */ -mxCellState.prototype.cell = null; - -/** - * Variable: style - * - * Contains an array of key, value pairs that represent the style of the - * cell. - */ -mxCellState.prototype.style = null; - -/** - * Variable: invalid - * - * Specifies if the state is invalid. Default is true. - */ -mxCellState.prototype.invalid = true; - -/** - * Variable: invalidOrder - * - * Specifies if the cell has an invalid order. For internal use. Default is - * false. - */ -mxCellState.prototype.invalidOrder = false; - -/** - * Variable: orderChanged - * - * Specifies if the cell has changed order and the display needs to be - * updated. - */ -mxCellState.prototype.orderChanged = false; - -/** - * Variable: origin - * - * <mxPoint> that holds the origin for all child cells. Default is a new - * empty <mxPoint>. - */ -mxCellState.prototype.origin = null; - -/** - * Variable: absolutePoints - * - * Holds an array of <mxPoints> that represent the absolute points of an - * edge. - */ -mxCellState.prototype.absolutePoints = null; - -/** - * Variable: absoluteOffset - * - * <mxPoint> that holds the absolute offset. For edges, this is the - * absolute coordinates of the label position. For vertices, this is the - * offset of the label relative to the top, left corner of the vertex. - */ -mxCellState.prototype.absoluteOffset = null; - -/** - * Variable: visibleSourceState - * - * Caches the visible source terminal state. - */ -mxCellState.prototype.visibleSourceState = null; - -/** - * Variable: visibleTargetState - * - * Caches the visible target terminal state. - */ -mxCellState.prototype.visibleTargetState = null; - -/** - * Variable: terminalDistance - * - * Caches the distance between the end points for an edge. - */ -mxCellState.prototype.terminalDistance = 0; - -/** - * Variable: length - * - * Caches the length of an edge. - */ -mxCellState.prototype.length = 0; - -/** - * Variable: segments - * - * Array of numbers that represent the cached length of each segment of the - * edge. - */ -mxCellState.prototype.segments = null; - -/** - * Variable: shape - * - * Holds the <mxShape> that represents the cell graphically. - */ -mxCellState.prototype.shape = null; - -/** - * Variable: text - * - * Holds the <mxText> that represents the label of the cell. Thi smay be - * null if the cell has no label. - */ -mxCellState.prototype.text = null; - -/** - * Function: getPerimeterBounds - * - * Returns the <mxRectangle> that should be used as the perimeter of the - * cell. - * - * Parameters: - * - * border - Optional border to be added around the perimeter bounds. - * bounds - Optional <mxRectangle> to be used as the initial bounds. - */ -mxCellState.prototype.getPerimeterBounds = function (border, bounds) -{ - border = border || 0; - bounds = (bounds != null) ? bounds : new mxRectangle(this.x, this.y, this.width, this.height); - - if (this.shape != null && this.shape.stencil != null) - { - var aspect = this.shape.stencil.computeAspect(this, bounds, null); - - bounds.x = aspect.x; - bounds.y = aspect.y; - bounds.width = this.shape.stencil.w0 * aspect.width; - bounds.height = this.shape.stencil.h0 * aspect.height; - } - - if (border != 0) - { - bounds.grow(border); - } - - return bounds; -}; - -/** - * Function: setAbsoluteTerminalPoint - * - * Sets the first or last point in <absolutePoints> depending on isSource. - * - * Parameters: - * - * point - <mxPoint> that represents the terminal point. - * isSource - Boolean that specifies if the first or last point should - * be assigned. - */ -mxCellState.prototype.setAbsoluteTerminalPoint = function (point, isSource) -{ - if (isSource) - { - if (this.absolutePoints == null) - { - this.absolutePoints = []; - } - - if (this.absolutePoints.length == 0) - { - this.absolutePoints.push(point); - } - else - { - this.absolutePoints[0] = point; - } - } - else - { - if (this.absolutePoints == null) - { - this.absolutePoints = []; - this.absolutePoints.push(null); - this.absolutePoints.push(point); - } - else if (this.absolutePoints.length == 1) - { - this.absolutePoints.push(point); - } - else - { - this.absolutePoints[this.absolutePoints.length - 1] = point; - } - } -}; - -/** - * Function: setCursor - * - * Sets the given cursor on the shape and text shape. - */ -mxCellState.prototype.setCursor = function (cursor) -{ - if (this.shape != null) - { - this.shape.setCursor(cursor); - } - - if (this.text != null) - { - this.text.setCursor(cursor); - } -}; - -/** - * Function: getVisibleTerminal - * - * Returns the visible source or target terminal cell. - * - * Parameters: - * - * source - Boolean that specifies if the source or target cell should be - * returned. - */ -mxCellState.prototype.getVisibleTerminal = function (source) -{ - var tmp = this.getVisibleTerminalState(source); - - return (tmp != null) ? tmp.cell : null; -}; - -/** - * Function: getVisibleTerminalState - * - * Returns the visible source or target terminal state. - * - * Parameters: - * - * source - Boolean that specifies if the source or target state should be - * returned. - */ -mxCellState.prototype.getVisibleTerminalState = function (source) -{ - return (source) ? this.visibleSourceState : this.visibleTargetState; -}; - -/** - * Function: setVisibleTerminalState - * - * Sets the visible source or target terminal state. - * - * Parameters: - * - * terminalState - <mxCellState> that represents the terminal. - * source - Boolean that specifies if the source or target state should be set. - */ -mxCellState.prototype.setVisibleTerminalState = function (terminalState, source) -{ - if (source) - { - this.visibleSourceState = terminalState; - } - else - { - this.visibleTargetState = terminalState; - } -}; - -/** - * Destructor: destroy - * - * Destroys the state and all associated resources. - */ -mxCellState.prototype.destroy = function () -{ - this.view.graph.cellRenderer.destroy(this); -}; - -/** - * Function: clone - * - * Returns a clone of this <mxPoint>. - */ -mxCellState.prototype.clone = function() -{ - var clone = new mxCellState(this.view, this.cell, this.style); - - // Clones the absolute points - if (this.absolutePoints != null) - { - clone.absolutePoints = []; - - for (var i = 0; i < this.absolutePoints.length; i++) - { - clone.absolutePoints[i] = this.absolutePoints[i].clone(); - } - } - - if (this.origin != null) - { - clone.origin = this.origin.clone(); - } - - if (this.absoluteOffset != null) - { - clone.absoluteOffset = this.absoluteOffset.clone(); - } - - if (this.boundingBox != null) - { - clone.boundingBox = this.boundingBox.clone(); - } - - clone.terminalDistance = this.terminalDistance; - clone.segments = this.segments; - clone.length = this.length; - clone.x = this.x; - clone.y = this.y; - clone.width = this.width; - clone.height = this.height; - - return clone; -}; diff --git a/src/js/view/mxCellStatePreview.js b/src/js/view/mxCellStatePreview.js deleted file mode 100644 index b853748..0000000 --- a/src/js/view/mxCellStatePreview.js +++ /dev/null @@ -1,223 +0,0 @@ -/** - * $Id: mxCellStatePreview.js,v 1.6 2012-10-26 07:19:11 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -/** - * - * Class: mxCellStatePreview - * - * Implements a live preview for moving cells. - * - * Constructor: mxCellStatePreview - * - * Constructs a move preview for the given graph. - * - * Parameters: - * - * graph - Reference to the enclosing <mxGraph>. - */ -function mxCellStatePreview(graph) -{ - this.graph = graph; - this.deltas = new Object(); -}; - -/** - * Variable: graph - * - * Reference to the enclosing <mxGraph>. - */ -mxCellStatePreview.prototype.graph = null; - -/** - * Variable: deltas - * - * Reference to the enclosing <mxGraph>. - */ -mxCellStatePreview.prototype.deltas = null; - -/** - * Variable: count - * - * Contains the number of entries in the map. - */ -mxCellStatePreview.prototype.count = 0; - -/** - * Function: isEmpty - * - * Returns true if this contains no entries. - */ -mxCellStatePreview.prototype.isEmpty = function() -{ - return this.count == 0; -}; - -/** - * Function: moveState - */ -mxCellStatePreview.prototype.moveState = function(state, dx, dy, add, includeEdges) -{ - add = (add != null) ? add : true; - includeEdges = (includeEdges != null) ? includeEdges : true; - var id = mxCellPath.create(state.cell); - var delta = this.deltas[id]; - - if (delta == null) - { - delta = new mxPoint(dx, dy); - this.deltas[id] = delta; - this.count++; - } - else - { - if (add) - { - delta.X += dx; - delta.Y += dy; - } - else - { - delta.X = dx; - delta.Y = dy; - } - } - - if (includeEdges) - { - this.addEdges(state); - } - - return delta; -}; - -/** - * Function: show - */ -mxCellStatePreview.prototype.show = function(visitor) -{ - var model = this.graph.getModel(); - var root = model.getRoot(); - - // Translates the states in step - for (var id in this.deltas) - { - var cell = mxCellPath.resolve(root, id); - var state = this.graph.view.getState(cell); - var delta = this.deltas[id]; - var parentState = this.graph.view.getState( - model.getParent(cell)); - this.translateState(parentState, state, delta.x, delta.y); - } - - // Revalidates the states in step - for (var id in this.deltas) - { - var cell = mxCellPath.resolve(root, id); - var state = this.graph.view.getState(cell); - var delta = this.deltas[id]; - var parentState = this.graph.view.getState( - model.getParent(cell)); - this.revalidateState(parentState, state, delta.x, delta.y, visitor); - } -}; - -/** - * Function: translateState - */ -mxCellStatePreview.prototype.translateState = function(parentState, state, dx, dy) -{ - if (state != null) - { - var model = this.graph.getModel(); - - if (model.isVertex(state.cell)) - { - // LATER: Use hashtable to store initial state bounds - state.invalid = true; - this.graph.view.validateBounds(parentState, state.cell); - var geo = model.getGeometry(state.cell); - var id = mxCellPath.create(state.cell); - - // Moves selection cells and non-relative vertices in - // the first phase so that edge terminal points will - // be updated in the second phase - if ((dx != 0 || dy != 0) && geo != null && - (!geo.relative || this.deltas[id] != null)) - { - state.x += dx; - state.y += dy; - } - } - - var childCount = model.getChildCount(state.cell); - - for (var i = 0; i < childCount; i++) - { - this.translateState(state, this.graph.view.getState( - model.getChildAt(state.cell, i)), dx, dy); - } - } -}; - -/** - * Function: revalidateState - */ -mxCellStatePreview.prototype.revalidateState = function(parentState, state, dx, dy, visitor) -{ - if (state != null) - { - // Updates the edge terminal points and restores the - // (relative) positions of any (relative) children - state.invalid = true; - this.graph.view.validatePoints(parentState, state.cell); - - // Moves selection vertices which are relative - var id = mxCellPath.create(state.cell); - var model = this.graph.getModel(); - var geo = this.graph.getCellGeometry(state.cell); - - if ((dx != 0 || dy != 0) && geo != null && geo.relative && - model.isVertex(state.cell) && (parentState == null || - model.isVertex(parentState.cell) || this.deltas[id] != null)) - { - state.x += dx; - state.y += dy; - - this.graph.cellRenderer.redraw(state); - } - - // Invokes the visitor on the given state - if (visitor != null) - { - visitor(state); - } - - var childCount = model.getChildCount(state.cell); - - for (var i = 0; i < childCount; i++) - { - this.revalidateState(state, this.graph.view.getState(model.getChildAt( - state.cell, i)), dx, dy, visitor); - } - } -}; - -/** - * Function: addEdges - */ -mxCellStatePreview.prototype.addEdges = function(state) -{ - var model = this.graph.getModel(); - var edgeCount = model.getEdgeCount(state.cell); - - for (var i = 0; i < edgeCount; i++) - { - var s = this.graph.view.getState(model.getEdgeAt(state.cell, i)); - - if (s != null) - { - this.moveState(s, 0, 0); - } - } -}; diff --git a/src/js/view/mxConnectionConstraint.js b/src/js/view/mxConnectionConstraint.js deleted file mode 100644 index 70f457f..0000000 --- a/src/js/view/mxConnectionConstraint.js +++ /dev/null @@ -1,42 +0,0 @@ -/** - * $Id: mxConnectionConstraint.js,v 1.2 2010-04-29 09:33:52 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -/** - * Class: mxConnectionConstraint - * - * Defines an object that contains the constraints about how to connect one - * side of an edge to its terminal. - * - * Constructor: mxConnectionConstraint - * - * Constructs a new connection constraint for the given point and boolean - * arguments. - * - * Parameters: - * - * point - Optional <mxPoint> that specifies the fixed location of the point - * in relative coordinates. Default is null. - * perimeter - Optional boolean that specifies if the fixed point should be - * projected onto the perimeter of the terminal. Default is true. - */ -function mxConnectionConstraint(point, perimeter) -{ - this.point = point; - this.perimeter = (perimeter != null) ? perimeter : true; -}; - -/** - * Variable: point - * - * <mxPoint> that specifies the fixed location of the connection point. - */ -mxConnectionConstraint.prototype.point = null; - -/** - * Variable: perimeter - * - * Boolean that specifies if the point should be projected onto the perimeter - * of the terminal. - */ -mxConnectionConstraint.prototype.perimeter = null; diff --git a/src/js/view/mxEdgeStyle.js b/src/js/view/mxEdgeStyle.js deleted file mode 100644 index 41493d6..0000000 --- a/src/js/view/mxEdgeStyle.js +++ /dev/null @@ -1,1302 +0,0 @@ -/** - * $Id: mxEdgeStyle.js,v 1.68 2012-11-20 09:06:07 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -var mxEdgeStyle = -{ - /** - * Class: mxEdgeStyle - * - * Provides various edge styles to be used as the values for - * <mxConstants.STYLE_EDGE> in a cell style. - * - * Example: - * - * (code) - * var style = stylesheet.getDefaultEdgeStyle(); - * style[mxConstants.STYLE_EDGE] = mxEdgeStyle.ElbowConnector; - * (end) - * - * Sets the default edge style to <ElbowConnector>. - * - * Custom edge style: - * - * To write a custom edge style, a function must be added to the mxEdgeStyle - * object as follows: - * - * (code) - * mxEdgeStyle.MyStyle = function(state, source, target, points, result) - * { - * if (source != null && target != null) - * { - * var pt = new mxPoint(target.getCenterX(), source.getCenterY()); - * - * if (mxUtils.contains(source, pt.x, pt.y)) - * { - * pt.y = source.y + source.height; - * } - * - * result.push(pt); - * } - * }; - * (end) - * - * In the above example, a right angle is created using a point on the - * horizontal center of the target vertex and the vertical center of the source - * vertex. The code checks if that point intersects the source vertex and makes - * the edge straight if it does. The point is then added into the result array, - * which acts as the return value of the function. - * - * The new edge style should then be registered in the <mxStyleRegistry> as follows: - * (code) - * mxStyleRegistry.putValue('myEdgeStyle', mxEdgeStyle.MyStyle); - * (end) - * - * The custom edge style above can now be used in a specific edge as follows: - * - * (code) - * model.setStyle(edge, 'edgeStyle=myEdgeStyle'); - * (end) - * - * Note that the key of the <mxStyleRegistry> entry for the function should - * be used in string values, unless <mxGraphView.allowEval> is true, in - * which case you can also use mxEdgeStyle.MyStyle for the value in the - * cell style above. - * - * Or it can be used for all edges in the graph as follows: - * - * (code) - * var style = graph.getStylesheet().getDefaultEdgeStyle(); - * style[mxConstants.STYLE_EDGE] = mxEdgeStyle.MyStyle; - * (end) - * - * Note that the object can be used directly when programmatically setting - * the value, but the key in the <mxStyleRegistry> should be used when - * setting the value via a key, value pair in a cell style. - * - * Function: EntityRelation - * - * Implements an entity relation style for edges (as used in database - * schema diagrams). At the time the function is called, the result - * array contains a placeholder (null) for the first absolute point, - * that is, the point where the edge and source terminal are connected. - * The implementation of the style then adds all intermediate waypoints - * except for the last point, that is, the connection point between the - * edge and the target terminal. The first ant the last point in the - * result array are then replaced with mxPoints that take into account - * the terminal's perimeter and next point on the edge. - * - * Parameters: - * - * state - <mxCellState> that represents the edge to be updated. - * source - <mxCellState> that represents the source terminal. - * target - <mxCellState> that represents the target terminal. - * points - List of relative control points. - * result - Array of <mxPoints> that represent the actual points of the - * edge. - */ - EntityRelation: function (state, source, target, points, result) - { - var view = state.view; - var graph = view.graph; - var segment = mxUtils.getValue(state.style, - mxConstants.STYLE_SEGMENT, - mxConstants.ENTITY_SEGMENT) * view.scale; - - var pts = state.absolutePoints; - var p0 = pts[0]; - var pe = pts[pts.length-1]; - - var isSourceLeft = false; - - if (p0 != null) - { - source = new mxCellState(); - source.x = p0.x; - source.y = p0.y; - } - else if (source != null) - { - var constraint = mxUtils.getPortConstraints(source, state, true, mxConstants.DIRECTION_MASK_NONE); - - if (constraint != mxConstants.DIRECTION_MASK_NONE) - { - isSourceLeft = constraint == mxConstants.DIRECTION_MASK_WEST; - } - else - { - var sourceGeometry = graph.getCellGeometry(source.cell); - - if (sourceGeometry.relative) - { - isSourceLeft = sourceGeometry.x <= 0.5; - } - else if (target != null) - { - isSourceLeft = target.x + target.width < source.x; - } - } - } - else - { - return; - } - - var isTargetLeft = true; - - if (pe != null) - { - target = new mxCellState(); - target.x = pe.x; - target.y = pe.y; - } - else if (target != null) - { - var constraint = mxUtils.getPortConstraints(target, state, false, mxConstants.DIRECTION_MASK_NONE); - - if (constraint != mxConstants.DIRECTION_MASK_NONE) - { - isTargetLeft = constraint == mxConstants.DIRECTION_MASK_WEST; - } - else - { - var targetGeometry = graph.getCellGeometry(target.cell); - - if (targetGeometry.relative) - { - isTargetLeft = targetGeometry.x <= 0.5; - } - else if (source != null) - { - isTargetLeft = source.x + source.width < target.x; - } - } - } - - if (source != null && target != null) - { - var x0 = (isSourceLeft) ? source.x : source.x + source.width; - var y0 = view.getRoutingCenterY(source); - - var xe = (isTargetLeft) ? target.x : target.x + target.width; - var ye = view.getRoutingCenterY(target); - - var seg = segment; - - var dx = (isSourceLeft) ? -seg : seg; - var dep = new mxPoint(x0 + dx, y0); - - dx = (isTargetLeft) ? -seg : seg; - var arr = new mxPoint(xe + dx, ye); - - // Adds intermediate points if both go out on same side - if (isSourceLeft == isTargetLeft) - { - var x = (isSourceLeft) ? - Math.min(x0, xe)-segment : - Math.max(x0, xe)+segment; - - result.push(new mxPoint(x, y0)); - result.push(new mxPoint(x, ye)); - } - else if ((dep.x < arr.x) == isSourceLeft) - { - var midY = y0 + (ye - y0) / 2; - - result.push(dep); - result.push(new mxPoint(dep.x, midY)); - result.push(new mxPoint(arr.x, midY)); - result.push(arr); - } - else - { - result.push(dep); - result.push(arr); - } - } - }, - - /** - * Function: Loop - * - * Implements a self-reference, aka. loop. - */ - Loop: function (state, source, target, points, result) - { - if (source != null) - { - var view = state.view; - var graph = view.graph; - var pt = (points != null && points.length > 0) ? points[0] : null; - - if (pt != null) - { - pt = view.transformControlPoint(state, pt); - - if (mxUtils.contains(source, pt.x, pt.y)) - { - pt = null; - } - } - - var x = 0; - var dx = 0; - var y = 0; - var dy = 0; - - var seg = mxUtils.getValue(state.style, mxConstants.STYLE_SEGMENT, - graph.gridSize) * view.scale; - var dir = mxUtils.getValue(state.style, mxConstants.STYLE_DIRECTION, - mxConstants.DIRECTION_WEST); - - if (dir == mxConstants.DIRECTION_NORTH || - dir == mxConstants.DIRECTION_SOUTH) - { - x = view.getRoutingCenterX(source); - dx = seg; - } - else - { - y = view.getRoutingCenterY(source); - dy = seg; - } - - if (pt == null || - pt.x < source.x || - pt.x > source.x + source.width) - { - if (pt != null) - { - x = pt.x; - dy = Math.max(Math.abs(y - pt.y), dy); - } - else - { - if (dir == mxConstants.DIRECTION_NORTH) - { - y = source.y - 2 * dx; - } - else if (dir == mxConstants.DIRECTION_SOUTH) - { - y = source.y + source.height + 2 * dx; - } - else if (dir == mxConstants.DIRECTION_EAST) - { - x = source.x - 2 * dy; - } - else - { - x = source.x + source.width + 2 * dy; - } - } - } - else if (pt != null) - { - x = view.getRoutingCenterX(source); - dx = Math.max(Math.abs(x - pt.x), dy); - y = pt.y; - dy = 0; - } - - result.push(new mxPoint(x - dx, y - dy)); - result.push(new mxPoint(x + dx, y + dy)); - } - }, - - /** - * Function: ElbowConnector - * - * Uses either <SideToSide> or <TopToBottom> depending on the horizontal - * flag in the cell style. <SideToSide> is used if horizontal is true or - * unspecified. See <EntityRelation> for a description of the - * parameters. - */ - ElbowConnector: function (state, source, target, points, result) - { - var pt = (points != null && points.length > 0) ? points[0] : null; - - var vertical = false; - var horizontal = false; - - if (source != null && target != null) - { - if (pt != null) - { - var left = Math.min(source.x, target.x); - var right = Math.max(source.x + source.width, - target.x + target.width); - - var top = Math.min(source.y, target.y); - var bottom = Math.max(source.y + source.height, - target.y + target.height); - - pt = state.view.transformControlPoint(state, pt); - - vertical = pt.y < top || pt.y > bottom; - horizontal = pt.x < left || pt.x > right; - } - else - { - var left = Math.max(source.x, target.x); - var right = Math.min(source.x + source.width, - target.x + target.width); - - vertical = left == right; - - if (!vertical) - { - var top = Math.max(source.y, target.y); - var bottom = Math.min(source.y + source.height, - target.y + target.height); - - horizontal = top == bottom; - } - } - } - - if (!horizontal && (vertical || - state.style[mxConstants.STYLE_ELBOW] == mxConstants.ELBOW_VERTICAL)) - { - mxEdgeStyle.TopToBottom(state, source, target, points, result); - } - else - { - mxEdgeStyle.SideToSide(state, source, target, points, result); - } - }, - - /** - * Function: SideToSide - * - * Implements a vertical elbow edge. See <EntityRelation> for a description - * of the parameters. - */ - SideToSide: function (state, source, target, points, result) - { - var view = state.view; - var pt = (points != null && points.length > 0) ? points[0] : null; - var pts = state.absolutePoints; - var p0 = pts[0]; - var pe = pts[pts.length-1]; - - if (pt != null) - { - pt = view.transformControlPoint(state, pt); - } - - if (p0 != null) - { - source = new mxCellState(); - source.x = p0.x; - source.y = p0.y; - } - - if (pe != null) - { - target = new mxCellState(); - target.x = pe.x; - target.y = pe.y; - } - - if (source != null && target != null) - { - var l = Math.max(source.x, target.x); - var r = Math.min(source.x + source.width, - target.x + target.width); - - var x = (pt != null) ? pt.x : r + (l - r) / 2; - - var y1 = view.getRoutingCenterY(source); - var y2 = view.getRoutingCenterY(target); - - if (pt != null) - { - if (pt.y >= source.y && pt.y <= source.y + source.height) - { - y1 = pt.y; - } - - if (pt.y >= target.y && pt.y <= target.y + target.height) - { - y2 = pt.y; - } - } - - if (!mxUtils.contains(target, x, y1) && - !mxUtils.contains(source, x, y1)) - { - result.push(new mxPoint(x, y1)); - } - - if (!mxUtils.contains(target, x, y2) && - !mxUtils.contains(source, x, y2)) - { - result.push(new mxPoint(x, y2)); - } - - if (result.length == 1) - { - if (pt != null) - { - if (!mxUtils.contains(target, x, pt.y) && - !mxUtils.contains(source, x, pt.y)) - { - result.push(new mxPoint(x, pt.y)); - } - } - else - { - var t = Math.max(source.y, target.y); - var b = Math.min(source.y + source.height, - target.y + target.height); - - result.push(new mxPoint(x, t + (b - t) / 2)); - } - } - } - }, - - /** - * Function: TopToBottom - * - * Implements a horizontal elbow edge. See <EntityRelation> for a - * description of the parameters. - */ - TopToBottom: function(state, source, target, points, result) - { - var view = state.view; - var pt = (points != null && points.length > 0) ? points[0] : null; - var pts = state.absolutePoints; - var p0 = pts[0]; - var pe = pts[pts.length-1]; - - if (pt != null) - { - pt = view.transformControlPoint(state, pt); - } - - if (p0 != null) - { - source = new mxCellState(); - source.x = p0.x; - source.y = p0.y; - } - - if (pe != null) - { - target = new mxCellState(); - target.x = pe.x; - target.y = pe.y; - } - - if (source != null && target != null) - { - var t = Math.max(source.y, target.y); - var b = Math.min(source.y + source.height, - target.y + target.height); - - var x = view.getRoutingCenterX(source); - - if (pt != null && - pt.x >= source.x && - pt.x <= source.x + source.width) - { - x = pt.x; - } - - var y = (pt != null) ? pt.y : b + (t - b) / 2; - - if (!mxUtils.contains(target, x, y) && - !mxUtils.contains(source, x, y)) - { - result.push(new mxPoint(x, y)); - } - - if (pt != null && - pt.x >= target.x && - pt.x <= target.x + target.width) - { - x = pt.x; - } - else - { - x = view.getRoutingCenterX(target); - } - - if (!mxUtils.contains(target, x, y) && - !mxUtils.contains(source, x, y)) - { - result.push(new mxPoint(x, y)); - } - - if (result.length == 1) - { - if (pt != null && result.length == 1) - { - if (!mxUtils.contains(target, pt.x, y) && - !mxUtils.contains(source, pt.x, y)) - { - result.push(new mxPoint(pt.x, y)); - } - } - else - { - var l = Math.max(source.x, target.x); - var r = Math.min(source.x + source.width, - target.x + target.width); - - result.push(new mxPoint(l + (r - l) / 2, y)); - } - } - } - }, - - /** - * Function: SegmentConnector - * - * Implements an orthogonal edge style. Use <mxEdgeSegmentHandler> - * as an interactive handler for this style. - */ - SegmentConnector: function(state, source, target, hints, result) - { - // Creates array of all way- and terminalpoints - var pts = state.absolutePoints; - var horizontal = true; - var hint = null; - - // Adds the first point - var pt = pts[0]; - - if (pt == null && source != null) - { - pt = new mxPoint(state.view.getRoutingCenterX(source), state.view.getRoutingCenterY(source)); - } - else if (pt != null) - { - pt = pt.clone(); - } - - var lastInx = pts.length - 1; - - // Adds the waypoints - if (hints != null && hints.length > 0) - { - hint = state.view.transformControlPoint(state, hints[0]); - - var currentTerm = source; - var currentPt = pts[0]; - var hozChan = false; - var vertChan = false; - var currentHint = hint; - var hintsLen = hints.length; - - for (var i = 0; i < 2; i++) - { - var fixedVertAlign = currentPt != null && currentPt.x == currentHint.x; - var fixedHozAlign = currentPt != null && currentPt.y == currentHint.y; - var inHozChan = currentTerm != null && (currentHint.y >= currentTerm.y && - currentHint.y <= currentTerm.y + currentTerm.height); - var inVertChan = currentTerm != null && (currentHint.x >= currentTerm.x && - currentHint.x <= currentTerm.x + currentTerm.width); - - hozChan = fixedHozAlign || (currentPt == null && inHozChan); - vertChan = fixedVertAlign || (currentPt == null && inVertChan); - - if (currentPt != null && (!fixedHozAlign && !fixedVertAlign) && (inHozChan || inVertChan)) - { - horizontal = inHozChan ? false : true; - break; - } - - if (vertChan || hozChan) - { - horizontal = hozChan; - - if (i == 1) - { - // Work back from target end - horizontal = hints.length % 2 == 0 ? hozChan : vertChan; - } - - break; - } - - currentTerm = target; - currentPt = pts[lastInx]; - currentHint = state.view.transformControlPoint(state, hints[hintsLen - 1]); - } - - if (horizontal && ((pts[0] != null && pts[0].y != hint.y) || - (pts[0] == null && source != null && - (hint.y < source.y || hint.y > source.y + source.height)))) - { - result.push(new mxPoint(pt.x, hint.y)); - } - else if (!horizontal && ((pts[0] != null && pts[0].x != hint.x) || - (pts[0] == null && source != null && - (hint.x < source.x || hint.x > source.x + source.width)))) - { - result.push(new mxPoint(hint.x, pt.y)); - } - - if (horizontal) - { - pt.y = hint.y; - } - else - { - pt.x = hint.x; - } - - for (var i = 0; i < hints.length; i++) - { - horizontal = !horizontal; - hint = state.view.transformControlPoint(state, hints[i]); - -// mxLog.show(); -// mxLog.debug('hint', i, hint.x, hint.y); - - if (horizontal) - { - pt.y = hint.y; - } - else - { - pt.x = hint.x; - } - - result.push(pt.clone()); - } - } - else - { - hint = pt; - // FIXME: First click in connect preview toggles orientation - horizontal = true; - } - - // Adds the last point - pt = pts[lastInx]; - - if (pt == null && target != null) - { - pt = new mxPoint(state.view.getRoutingCenterX(target), state.view.getRoutingCenterY(target)); - } - - if (horizontal && ((pts[lastInx] != null && pts[lastInx].y != hint.y) || - (pts[lastInx] == null && target != null && - (hint.y < target.y || hint.y > target.y + target.height)))) - { - result.push(new mxPoint(pt.x, hint.y)); - } - else if (!horizontal && ((pts[lastInx] != null && pts[lastInx].x != hint.x) || - (pts[lastInx] == null && target != null && - (hint.x < target.x || hint.x > target.x + target.width)))) - { - result.push(new mxPoint(hint.x, pt.y)); - } - - // Removes bends inside the source terminal for floating ports - if (pts[0] == null && source != null) - { - while (result.length > 1 && mxUtils.contains(source, result[1].x, result[1].y)) - { - result = result.splice(1, 1); - } - } - - // Removes bends inside the target terminal - if (pts[lastInx] == null && target != null) - { - while (result.length > 1 && mxUtils.contains(target, result[result.length - 1].x, result[result.length - 1].y)) - { - result = result.splice(result.length - 1, 1); - } - } - - }, - - orthBuffer: 10, - - dirVectors: [ [ -1, 0 ], - [ 0, -1 ], [ 1, 0 ], [ 0, 1 ], [ -1, 0 ], [ 0, -1 ], [ 1, 0 ] ], - - wayPoints1: [ [ 0, 0], [ 0, 0], [ 0, 0], [ 0, 0], [ 0, 0], [ 0, 0], - [ 0, 0], [ 0, 0], [ 0, 0], [ 0, 0], [ 0, 0], [ 0, 0] ], - - routePatterns: [ - [ [ 513, 2308, 2081, 2562 ], [ 513, 1090, 514, 2184, 2114, 2561 ], - [ 513, 1090, 514, 2564, 2184, 2562 ], - [ 513, 2308, 2561, 1090, 514, 2568, 2308 ] ], - [ [ 514, 1057, 513, 2308, 2081, 2562 ], [ 514, 2184, 2114, 2561 ], - [ 514, 2184, 2562, 1057, 513, 2564, 2184 ], - [ 514, 1057, 513, 2568, 2308, 2561 ] ], - [ [ 1090, 514, 1057, 513, 2308, 2081, 2562 ], [ 2114, 2561 ], - [ 1090, 2562, 1057, 513, 2564, 2184 ], - [ 1090, 514, 1057, 513, 2308, 2561, 2568 ] ], - [ [ 2081, 2562 ], [ 1057, 513, 1090, 514, 2184, 2114, 2561 ], - [ 1057, 513, 1090, 514, 2184, 2562, 2564 ], - [ 1057, 2561, 1090, 514, 2568, 2308 ] ] ], - - inlineRoutePatterns: [ - [ null, [ 2114, 2568 ], null, null ], - [ null, [ 514, 2081, 2114, 2568 ] , null, null ], - [ null, [ 2114, 2561 ], null, null ], - [ [ 2081, 2562 ], [ 1057, 2114, 2568 ], - [ 2184, 2562 ], - null ] ], - vertexSeperations: [], - - limits: [ - [ 0, 0, 0, 0, 0, 0, 0, 0, 0 ], - [ 0, 0, 0, 0, 0, 0, 0, 0, 0 ] ], - - LEFT_MASK: 32, - - TOP_MASK: 64, - - RIGHT_MASK: 128, - - BOTTOM_MASK: 256, - - LEFT: 1, - - TOP: 2, - - RIGHT: 4, - - BOTTOM: 8, - - // TODO remove magic numbers - SIDE_MASK: 480, - //mxEdgeStyle.LEFT_MASK | mxEdgeStyle.TOP_MASK | mxEdgeStyle.RIGHT_MASK - //| mxEdgeStyle.BOTTOM_MASK, - - CENTER_MASK: 512, - - SOURCE_MASK: 1024, - - TARGET_MASK: 2048, - - VERTEX_MASK: 3072, - // mxEdgeStyle.SOURCE_MASK | mxEdgeStyle.TARGET_MASK, - - /** - * Function: OrthConnector - * - * Implements a local orthogonal router between the given - * cells. - */ - OrthConnector: function(state, source, target, points, result) - { - var graph = state.view.graph; - var sourceEdge = source == null ? false : graph.getModel().isEdge(source.cell); - var targetEdge = target == null ? false : graph.getModel().isEdge(target.cell); - - if ((points != null && points.length > 0) || (sourceEdge) || (targetEdge)) - { - mxEdgeStyle.SegmentConnector(state, source, target, points, result); - return; - } - - var pts = state.absolutePoints; - var p0 = pts[0]; - var pe = pts[pts.length-1]; - - var sourceX = source != null ? source.x : p0.x; - var sourceY = source != null ? source.y : p0.y; - var sourceWidth = source != null ? source.width : 1; - var sourceHeight = source != null ? source.height : 1; - - var targetX = target != null ? target.x : pe.x; - var targetY = target != null ? target.y : pe.y; - var targetWidth = target != null ? target.width : 1; - var targetHeight = target != null ? target.height : 1; - - var scaledOrthBuffer = state.view.scale * mxEdgeStyle.orthBuffer; - // Determine the side(s) of the source and target vertices - // that the edge may connect to - // portConstraint [source, target] - var portConstraint = [mxConstants.DIRECTION_MASK_ALL, mxConstants.DIRECTION_MASK_ALL]; - - if (source != null) - { - portConstraint[0] = mxUtils.getPortConstraints(source, state, true, - mxConstants.DIRECTION_MASK_ALL); - } - - if (target != null) - { - portConstraint[1] = mxUtils.getPortConstraints(target, state, false, - mxConstants.DIRECTION_MASK_ALL); - } - - var dir = [0, 0] ; - - // Work out which faces of the vertices present against each other - // in a way that would allow a 3-segment connection if port constraints - // permitted. - // geo -> [source, target] [x, y, width, height] - var geo = [ [sourceX, sourceY, sourceWidth, sourceHeight] , - [targetX, targetY, targetWidth, targetHeight] ]; - - for (var i = 0; i < 2; i++) - { - mxEdgeStyle.limits[i][1] = geo[i][0] - scaledOrthBuffer; - mxEdgeStyle.limits[i][2] = geo[i][1] - scaledOrthBuffer; - mxEdgeStyle.limits[i][4] = geo[i][0] + geo[i][2] + scaledOrthBuffer; - mxEdgeStyle.limits[i][8] = geo[i][1] + geo[i][3] + scaledOrthBuffer; - } - - // Work out which quad the target is in - var sourceCenX = geo[0][0] + geo[0][2] / 2.0; - var sourceCenY = geo[0][1] + geo[0][3] / 2.0; - var targetCenX = geo[1][0] + geo[1][2] / 2.0; - var targetCenY = geo[1][1] + geo[1][3] / 2.0; - - var dx = sourceCenX - targetCenX; - var dy = sourceCenY - targetCenY; - - var quad = 0; - - if (dx < 0) - { - if (dy < 0) - { - quad = 2; - } - else - { - quad = 1; - } - } - else - { - if (dy <= 0) - { - quad = 3; - - // Special case on x = 0 and negative y - if (dx == 0) - { - quad = 2; - } - } - } - - // Check for connection constraints - var currentTerm = null; - - if (source != null) - { - currentTerm = p0; - } - - var constraint = [ [0.5, 0.5] , [0.5, 0.5] ]; - - for (var i = 0; i < 2; i++) - { - if (currentTerm != null) - { - constraint[i][0] = (currentTerm.x - geo[i][0]) / geo[i][2]; - - if (constraint[i][0] < 0.01) - { - dir[i] = mxConstants.DIRECTION_MASK_WEST; - } - else if (constraint[i][0] > 0.99) - { - dir[i] = mxConstants.DIRECTION_MASK_EAST; - } - - constraint[i][1] = (currentTerm.y - geo[i][1]) / geo[i][3]; - - if (constraint[i][1] < 0.01) - { - dir[i] = mxConstants.DIRECTION_MASK_NORTH; - } - else if (constraint[i][1] > 0.99) - { - dir[i] = mxConstants.DIRECTION_MASK_SOUTH; - } - } - - currentTerm = null; - - if (target != null) - { - currentTerm = pe; - } - } - - var sourceTopDist = geo[0][1] - (geo[1][1] + geo[1][3]); - var sourceLeftDist = geo[0][0] - (geo[1][0] + geo[1][2]); - var sourceBottomDist = geo[1][1] - (geo[0][1] + geo[0][3]); - var sourceRightDist = geo[1][0] - (geo[0][0] + geo[0][2]); - - mxEdgeStyle.vertexSeperations[1] = Math.max( - sourceLeftDist - 2 * scaledOrthBuffer, 0); - mxEdgeStyle.vertexSeperations[2] = Math.max(sourceTopDist - 2 * scaledOrthBuffer, - 0); - mxEdgeStyle.vertexSeperations[4] = Math.max(sourceBottomDist - 2 - * scaledOrthBuffer, 0); - mxEdgeStyle.vertexSeperations[3] = Math.max(sourceRightDist - 2 - * scaledOrthBuffer, 0); - - //============================================================== - // Start of source and target direction determination - - // Work through the preferred orientations by relative positioning - // of the vertices and list them in preferred and available order - - var dirPref = []; - var horPref = []; - var vertPref = []; - - horPref[0] = (sourceLeftDist >= sourceRightDist) ? mxConstants.DIRECTION_MASK_WEST - : mxConstants.DIRECTION_MASK_EAST; - vertPref[0] = (sourceTopDist >= sourceBottomDist) ? mxConstants.DIRECTION_MASK_NORTH - : mxConstants.DIRECTION_MASK_SOUTH; - - horPref[1] = mxUtils.reversePortConstraints(horPref[0]); - vertPref[1] = mxUtils.reversePortConstraints(vertPref[0]); - - var preferredHorizDist = sourceLeftDist >= sourceRightDist ? sourceLeftDist - : sourceRightDist; - var preferredVertDist = sourceTopDist >= sourceBottomDist ? sourceTopDist - : sourceBottomDist; - - var prefOrdering = [ [0, 0] , [0, 0] ]; - var preferredOrderSet = false; - - // If the preferred port isn't available, switch it - for (var i = 0; i < 2; i++) - { - if (dir[i] != 0x0) - { - continue; - } - - if ((horPref[i] & portConstraint[i]) == 0) - { - horPref[i] = mxUtils.reversePortConstraints(horPref[i]); - } - - if ((vertPref[i] & portConstraint[i]) == 0) - { - vertPref[i] = mxUtils - .reversePortConstraints(vertPref[i]); - } - - prefOrdering[i][0] = vertPref[i]; - prefOrdering[i][1] = horPref[i]; - } - - if (preferredVertDist > scaledOrthBuffer * 2 - && preferredHorizDist > scaledOrthBuffer * 2) - { - // Possibility of two segment edge connection - if (((horPref[0] & portConstraint[0]) > 0) - && ((vertPref[1] & portConstraint[1]) > 0)) - { - prefOrdering[0][0] = horPref[0]; - prefOrdering[0][1] = vertPref[0]; - prefOrdering[1][0] = vertPref[1]; - prefOrdering[1][1] = horPref[1]; - preferredOrderSet = true; - } - else if (((vertPref[0] & portConstraint[0]) > 0) - && ((horPref[1] & portConstraint[1]) > 0)) - { - prefOrdering[0][0] = vertPref[0]; - prefOrdering[0][1] = horPref[0]; - prefOrdering[1][0] = horPref[1]; - prefOrdering[1][1] = vertPref[1]; - preferredOrderSet = true; - } - } - if (preferredVertDist > scaledOrthBuffer * 2 && !preferredOrderSet) - { - prefOrdering[0][0] = vertPref[0]; - prefOrdering[0][1] = horPref[0]; - prefOrdering[1][0] = vertPref[1]; - prefOrdering[1][1] = horPref[1]; - preferredOrderSet = true; - - } - if (preferredHorizDist > scaledOrthBuffer * 2 && !preferredOrderSet) - { - prefOrdering[0][0] = horPref[0]; - prefOrdering[0][1] = vertPref[0]; - prefOrdering[1][0] = horPref[1]; - prefOrdering[1][1] = vertPref[1]; - preferredOrderSet = true; - } - - // The source and target prefs are now an ordered list of - // the preferred port selections - // It the list can contain gaps, compact it - - for (var i = 0; i < 2; i++) - { - if (dir[i] != 0x0) - { - continue; - } - - if ((prefOrdering[i][0] & portConstraint[i]) == 0) - { - prefOrdering[i][0] = prefOrdering[i][1]; - } - - dirPref[i] = prefOrdering[i][0] & portConstraint[i]; - dirPref[i] |= (prefOrdering[i][1] & portConstraint[i]) << 8; - dirPref[i] |= (prefOrdering[1 - i][i] & portConstraint[i]) << 16; - dirPref[i] |= (prefOrdering[1 - i][1 - i] & portConstraint[i]) << 24; - - if ((dirPref[i] & 0xF) == 0) - { - dirPref[i] = dirPref[i] << 8; - } - if ((dirPref[i] & 0xF00) == 0) - { - dirPref[i] = (dirPref[i] & 0xF) | dirPref[i] >> 8; - } - if ((dirPref[i] & 0xF0000) == 0) - { - dirPref[i] = (dirPref[i] & 0xFFFF) - | ((dirPref[i] & 0xF000000) >> 8); - } - - dir[i] = dirPref[i] & 0xF; - - if (portConstraint[i] == mxConstants.DIRECTION_MASK_WEST - || portConstraint[i] == mxConstants.DIRECTION_MASK_NORTH - || portConstraint[i] == mxConstants.DIRECTION_MASK_EAST - || portConstraint[i] == mxConstants.DIRECTION_MASK_SOUTH) - { - dir[i] = portConstraint[i]; - } - } - - //============================================================== - // End of source and target direction determination - - var sourceIndex = dir[0] == mxConstants.DIRECTION_MASK_EAST ? 3 - : dir[0]; - var targetIndex = dir[1] == mxConstants.DIRECTION_MASK_EAST ? 3 - : dir[1]; - - sourceIndex -= quad; - targetIndex -= quad; - - if (sourceIndex < 1) - { - sourceIndex += 4; - } - if (targetIndex < 1) - { - targetIndex += 4; - } - - var routePattern = mxEdgeStyle.routePatterns[sourceIndex - 1][targetIndex - 1]; - - mxEdgeStyle.wayPoints1[0][0] = geo[0][0]; - mxEdgeStyle.wayPoints1[0][1] = geo[0][1]; - - switch (dir[0]) - { - case mxConstants.DIRECTION_MASK_WEST: - mxEdgeStyle.wayPoints1[0][0] -= scaledOrthBuffer; - mxEdgeStyle.wayPoints1[0][1] += constraint[0][1] * geo[0][3]; - break; - case mxConstants.DIRECTION_MASK_SOUTH: - mxEdgeStyle.wayPoints1[0][0] += constraint[0][0] * geo[0][2]; - mxEdgeStyle.wayPoints1[0][1] += geo[0][3] + scaledOrthBuffer; - break; - case mxConstants.DIRECTION_MASK_EAST: - mxEdgeStyle.wayPoints1[0][0] += geo[0][2] + scaledOrthBuffer; - mxEdgeStyle.wayPoints1[0][1] += constraint[0][1] * geo[0][3]; - break; - case mxConstants.DIRECTION_MASK_NORTH: - mxEdgeStyle.wayPoints1[0][0] += constraint[0][0] * geo[0][2]; - mxEdgeStyle.wayPoints1[0][1] -= scaledOrthBuffer; - break; - } - - var currentIndex = 0; - - // Orientation, 0 horizontal, 1 vertical - var lastOrientation = (dir[0] & (mxConstants.DIRECTION_MASK_EAST | mxConstants.DIRECTION_MASK_WEST)) > 0 ? 0 - : 1; - var initialOrientation = lastOrientation; - var currentOrientation = 0; - - for (var i = 0; i < routePattern.length; i++) - { - var nextDirection = routePattern[i] & 0xF; - - // Rotate the index of this direction by the quad - // to get the real direction - var directionIndex = nextDirection == mxConstants.DIRECTION_MASK_EAST ? 3 - : nextDirection; - - directionIndex += quad; - - if (directionIndex > 4) - { - directionIndex -= 4; - } - - var direction = mxEdgeStyle.dirVectors[directionIndex - 1]; - - currentOrientation = (directionIndex % 2 > 0) ? 0 : 1; - // Only update the current index if the point moved - // in the direction of the current segment move, - // otherwise the same point is moved until there is - // a segment direction change - if (currentOrientation != lastOrientation) - { - currentIndex++; - // Copy the previous way point into the new one - // We can't base the new position on index - 1 - // because sometime elbows turn out not to exist, - // then we'd have to rewind. - mxEdgeStyle.wayPoints1[currentIndex][0] = mxEdgeStyle.wayPoints1[currentIndex - 1][0]; - mxEdgeStyle.wayPoints1[currentIndex][1] = mxEdgeStyle.wayPoints1[currentIndex - 1][1]; - } - - var tar = (routePattern[i] & mxEdgeStyle.TARGET_MASK) > 0; - var sou = (routePattern[i] & mxEdgeStyle.SOURCE_MASK) > 0; - var side = (routePattern[i] & mxEdgeStyle.SIDE_MASK) >> 5; - side = side << quad; - - if (side > 0xF) - { - side = side >> 4; - } - - var center = (routePattern[i] & mxEdgeStyle.CENTER_MASK) > 0; - - if ((sou || tar) && side < 9) - { - var limit = 0; - var souTar = sou ? 0 : 1; - - if (center && currentOrientation == 0) - { - limit = geo[souTar][0] + constraint[souTar][0] * geo[souTar][2]; - } - else if (center) - { - limit = geo[souTar][1] + constraint[souTar][1] * geo[souTar][3]; - } - else - { - limit = mxEdgeStyle.limits[souTar][side]; - } - - if (currentOrientation == 0) - { - var lastX = mxEdgeStyle.wayPoints1[currentIndex][0]; - var deltaX = (limit - lastX) * direction[0]; - - if (deltaX > 0) - { - mxEdgeStyle.wayPoints1[currentIndex][0] += direction[0] - * deltaX; - } - } - else - { - var lastY = mxEdgeStyle.wayPoints1[currentIndex][1]; - var deltaY = (limit - lastY) * direction[1]; - - if (deltaY > 0) - { - mxEdgeStyle.wayPoints1[currentIndex][1] += direction[1] - * deltaY; - } - } - } - - else if (center) - { - // Which center we're travelling to depend on the current direction - mxEdgeStyle.wayPoints1[currentIndex][0] += direction[0] - * Math.abs(mxEdgeStyle.vertexSeperations[directionIndex] / 2); - mxEdgeStyle.wayPoints1[currentIndex][1] += direction[1] - * Math.abs(mxEdgeStyle.vertexSeperations[directionIndex] / 2); - } - - if (currentIndex > 0 - && mxEdgeStyle.wayPoints1[currentIndex][currentOrientation] == mxEdgeStyle.wayPoints1[currentIndex - 1][currentOrientation]) - { - currentIndex--; - } - else - { - lastOrientation = currentOrientation; - } - } - - for (var i = 0; i <= currentIndex; i++) - { - if (i == currentIndex) - { - // Last point can cause last segment to be in - // same direction as jetty/approach. If so, - // check the number of points is consistent - // with the relative orientation of source and target - // jettys. Same orientation requires an even - // number of turns (points), different requires - // odd. - var targetOrientation = (dir[1] & (mxConstants.DIRECTION_MASK_EAST | mxConstants.DIRECTION_MASK_WEST)) > 0 ? 0 - : 1; - var sameOrient = targetOrientation == initialOrientation ? 0 : 1; - - // (currentIndex + 1) % 2 is 0 for even number of points, - // 1 for odd - if (sameOrient != (currentIndex + 1) % 2) - { - // The last point isn't required - break; - } - } - - result.push(new mxPoint(mxEdgeStyle.wayPoints1[i][0], mxEdgeStyle.wayPoints1[i][1])); - } - }, - - getRoutePattern: function(dir, quad, dx, dy) - { - var sourceIndex = dir[0] == mxConstants.DIRECTION_MASK_EAST ? 3 - : dir[0]; - var targetIndex = dir[1] == mxConstants.DIRECTION_MASK_EAST ? 3 - : dir[1]; - - sourceIndex -= quad; - targetIndex -= quad; - - if (sourceIndex < 1) - { - sourceIndex += 4; - } - if (targetIndex < 1) - { - targetIndex += 4; - } - - var result = routePatterns[sourceIndex - 1][targetIndex - 1]; - - if (dx == 0 || dy == 0) - { - if (inlineRoutePatterns[sourceIndex - 1][targetIndex - 1] != null) - { - result = inlineRoutePatterns[sourceIndex - 1][targetIndex - 1]; - } - } - - return result; - } -};
\ No newline at end of file diff --git a/src/js/view/mxGraph.js b/src/js/view/mxGraph.js deleted file mode 100644 index 7c90f9b..0000000 --- a/src/js/view/mxGraph.js +++ /dev/null @@ -1,11176 +0,0 @@ -/** - * $Id: mxGraph.js,v 1.702 2012-12-13 15:07:34 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -/** - * Class: mxGraph - * - * Extends <mxEventSource> to implement a graph component for - * the browser. This is the main class of the package. To activate - * panning and connections use <setPanning> and <setConnectable>. - * For rubberband selection you must create a new instance of - * <mxRubberband>. The following listeners are added to - * <mouseListeners> by default: - * - * - <tooltipHandler>: <mxTooltipHandler> that displays tooltips - * - <panningHandler>: <mxPanningHandler> for panning and popup menus - * - <connectionHandler>: <mxConnectionHandler> for creating connections - * - <graphHandler>: <mxGraphHandler> for moving and cloning cells - * - * These listeners will be called in the above order if they are enabled. - * - * Background Images: - * - * To display a background image, set the image, image width and - * image height using <setBackgroundImage>. If one of the - * above values has changed then the <view>'s <mxGraphView.validate> - * should be invoked. - * - * Cell Images: - * - * To use images in cells, a shape must be specified in the default - * vertex style (or any named style). Possible shapes are - * <mxConstants.SHAPE_IMAGE> and <mxConstants.SHAPE_LABEL>. - * The code to change the shape used in the default vertex style, - * the following code is used: - * - * (code) - * var style = graph.getStylesheet().getDefaultVertexStyle(); - * style[mxConstants.STYLE_SHAPE] = mxConstants.SHAPE_IMAGE; - * (end) - * - * For the default vertex style, the image to be displayed can be - * specified in a cell's style using the <mxConstants.STYLE_IMAGE> - * key and the image URL as a value, for example: - * - * (code) - * image=http://www.example.com/image.gif - * (end) - * - * For a named style, the the stylename must be the first element - * of the cell style: - * - * (code) - * stylename;image=http://www.example.com/image.gif - * (end) - * - * A cell style can have any number of key=value pairs added, divided - * by a semicolon as follows: - * - * (code) - * [stylename;|key=value;] - * (end) - * - * Labels: - * - * The cell labels are defined by <getLabel> which uses <convertValueToString> - * if <labelsVisible> is true. If a label must be rendered as HTML markup, then - * <isHtmlLabel> should return true for the respective cell. If all labels - * contain HTML markup, <htmlLabels> can be set to true. NOTE: Enabling HTML - * labels carries a possible security risk (see the section on security in - * the manual). - * - * If wrapping is needed for a label, then <isHtmlLabel> and <isWrapping> must - * return true for the cell whose label should be wrapped. See <isWrapping> for - * an example. - * - * If clipping is needed to keep the rendering of a HTML label inside the - * bounds of its vertex, then <isClipping> should return true for the - * respective cell. - * - * By default, edge labels are movable and vertex labels are fixed. This can be - * changed by setting <edgeLabelsMovable> and <vertexLabelsMovable>, or by - * overriding <isLabelMovable>. - * - * In-place Editing: - * - * In-place editing is started with a doubleclick or by typing F2. - * Programmatically, <edit> is used to check if the cell is editable - * (<isCellEditable>) and call <startEditingAtCell>, which invokes - * <mxCellEditor.startEditing>. The editor uses the value returned - * by <getEditingValue> as the editing value. - * - * After in-place editing, <labelChanged> is called, which invokes - * <mxGraphModel.setValue>, which in turn calls - * <mxGraphModel.valueForCellChanged> via <mxValueChange>. - * - * The event that triggers in-place editing is passed through to the - * <cellEditor>, which may take special actions depending on the type of the - * event or mouse location, and is also passed to <getEditingValue>. The event - * is then passed back to the event processing functions which can perform - * specific actions based on the trigger event. - * - * Tooltips: - * - * Tooltips are implemented by <getTooltip>, which calls <getTooltipForCell> - * if a cell is under the mousepointer. The default implementation checks if - * the cell has a getTooltip function and calls it if it exists. Hence, in order - * to provide custom tooltips, the cell must provide a getTooltip function, or - * one of the two above functions must be overridden. - * - * Typically, for custom cell tooltips, the latter function is overridden as - * follows: - * - * (code) - * graph.getTooltipForCell = function(cell) - * { - * var label = this.convertValueToString(cell); - * return 'Tooltip for '+label; - * } - * (end) - * - * When using a config file, the function is overridden in the mxGraph section - * using the following entry: - * - * (code) - * <add as="getTooltipForCell"><![CDATA[ - * function(cell) - * { - * var label = this.convertValueToString(cell); - * return 'Tooltip for '+label; - * } - * ]]></add> - * (end) - * - * "this" refers to the graph in the implementation, so for example to check if - * a cell is an edge, you use this.getModel().isEdge(cell) - * - * For replacing the default implementation of <getTooltipForCell> (rather than - * replacing the function on a specific instance), the following code should be - * used after loading the JavaScript files, but before creating a new mxGraph - * instance using <mxGraph>: - * - * (code) - * mxGraph.prototype.getTooltipForCell = function(cell) - * { - * var label = this.convertValueToString(cell); - * return 'Tooltip for '+label; - * } - * (end) - * - * Shapes & Styles: - * - * The implementation of new shapes is demonstrated in the examples. We'll assume - * that we have implemented a custom shape with the name BoxShape which we want - * to use for drawing vertices. To use this shape, it must first be registered in - * the cell renderer as follows: - * - * (code) - * graph.cellRenderer.registerShape('box', BoxShape); - * (end) - * - * The code registers the BoxShape constructor under the name box in the cell - * renderer of the graph. The shape can now be referenced using the shape-key in - * a style definition. (The cell renderer contains a set of additional shapes, - * namely one for each constant with a SHAPE-prefix in <mxConstants>.) - * - * Styles are a collection of key, value pairs and a stylesheet is a collection - * of named styles. The names are referenced by the cellstyle, which is stored - * in <mxCell.style> with the following format: [stylename;|key=value;]. The - * string is resolved to a collection of key, value pairs, where the keys are - * overridden with the values in the string. - * - * When introducing a new shape, the name under which the shape is registered - * must be used in the stylesheet. There are three ways of doing this: - * - * - By changing the default style, so that all vertices will use the new - * shape - * - By defining a new style, so that only vertices with the respective - * cellstyle will use the new shape - * - By using shape=box in the cellstyle's optional list of key, value pairs - * to be overridden - * - * In the first case, the code to fetch and modify the default style for - * vertices is as follows: - * - * (code) - * var style = graph.getStylesheet().getDefaultVertexStyle(); - * style[mxConstants.STYLE_SHAPE] = 'box'; - * (end) - * - * The code takes the default vertex style, which is used for all vertices that - * do not have a specific cellstyle, and modifies the value for the shape-key - * in-place to use the new BoxShape for drawing vertices. This is done by - * assigning the box value in the second line, which refers to the name of the - * BoxShape in the cell renderer. - * - * In the second case, a collection of key, value pairs is created and then - * added to the stylesheet under a new name. In order to distinguish the - * shapename and the stylename we'll use boxstyle for the stylename: - * - * (code) - * var style = new Object(); - * style[mxConstants.STYLE_SHAPE] = 'box'; - * style[mxConstants.STYLE_STROKECOLOR] = '#000000'; - * style[mxConstants.STYLE_FONTCOLOR] = '#000000'; - * graph.getStylesheet().putCellStyle('boxstyle', style); - * (end) - * - * The code adds a new style with the name boxstyle to the stylesheet. To use - * this style with a cell, it must be referenced from the cellstyle as follows: - * - * (code) - * var vertex = graph.insertVertex(parent, null, 'Hello, World!', 20, 20, 80, 20, - * 'boxstyle'); - * (end) - * - * To summarize, each new shape must be registered in the <mxCellRenderer> with - * a unique name. That name is then used as the value of the shape-key in a - * default or custom style. If there are multiple custom shapes, then there - * should be a separate style for each shape. - * - * Inheriting Styles: - * - * For fill-, stroke-, gradient- and indicatorColors special keywords can be - * used. The inherit keyword for one of these colors will inherit the color - * for the same key from the parent cell. The swimlane keyword does the same, - * but inherits from the nearest swimlane in the ancestor hierarchy. Finally, - * the indicated keyword will use the color of the indicator as the color for - * the given key. - * - * Scrollbars: - * - * The <containers> overflow CSS property defines if scrollbars are used to - * display the graph. For values of 'auto' or 'scroll', the scrollbars will - * be shown. Note that the <resizeContainer> flag is normally not used - * together with scrollbars, as it will resize the container to match the - * size of the graph after each change. - * - * Multiplicities and Validation: - * - * To control the possible connections in mxGraph, <getEdgeValidationError> is - * used. The default implementation of the function uses <multiplicities>, - * which is an array of <mxMultiplicity>. Using this class allows to establish - * simple multiplicities, which are enforced by the graph. - * - * The <mxMultiplicity> uses <mxCell.is> to determine for which terminals it - * applies. The default implementation of <mxCell.is> works with DOM nodes (XML - * nodes) and checks if the given type parameter matches the nodeName of the - * node (case insensitive). Optionally, an attributename and value can be - * specified which are also checked. - * - * <getEdgeValidationError> is called whenever the connectivity of an edge - * changes. It returns an empty string or an error message if the edge is - * invalid or null if the edge is valid. If the returned string is not empty - * then it is displayed as an error message. - * - * <mxMultiplicity> allows to specify the multiplicity between a terminal and - * its possible neighbors. For example, if any rectangle may only be connected - * to, say, a maximum of two circles you can add the following rule to - * <multiplicities>: - * - * (code) - * graph.multiplicities.push(new mxMultiplicity( - * true, 'rectangle', null, null, 0, 2, ['circle'], - * 'Only 2 targets allowed', - * 'Only shape targets allowed')); - * (end) - * - * This will display the first error message whenever a rectangle is connected - * to more than two circles and the second error message if a rectangle is - * connected to anything but a circle. - * - * For certain multiplicities, such as a minimum of 1 connection, which cannot - * be enforced at cell creation time (unless the cell is created together with - * the connection), mxGraph offers <validate> which checks all multiplicities - * for all cells and displays the respective error messages in an overlay icon - * on the cells. - * - * If a cell is collapsed and contains validation errors, a respective warning - * icon is attached to the collapsed cell. - * - * Auto-Layout: - * - * For automatic layout, the <getLayout> hook is provided in <mxLayoutManager>. - * It can be overridden to return a layout algorithm for the children of a - * given cell. - * - * Unconnected edges: - * - * The default values for all switches are designed to meet the requirements of - * general diagram drawing applications. A very typical set of settings to - * avoid edges that are not connected is the following: - * - * (code) - * graph.setAllowDanglingEdges(false); - * graph.setDisconnectOnMove(false); - * (end) - * - * Setting the <cloneInvalidEdges> switch to true is optional. This switch - * controls if edges are inserted after a copy, paste or clone-drag if they are - * invalid. For example, edges are invalid if copied or control-dragged without - * having selected the corresponding terminals and allowDanglingEdges is - * false, in which case the edges will not be cloned if the switch is false. - * - * Output: - * - * To produce an XML representation for a diagram, the following code can be - * used. - * - * (code) - * var enc = new mxCodec(mxUtils.createXmlDocument()); - * var node = enc.encode(graph.getModel()); - * (end) - * - * This will produce an XML node than can be handled using the DOM API or - * turned into a string representation using the following code: - * - * (code) - * var xml = mxUtils.getXml(node); - * (end) - * - * To obtain a formatted string, mxUtils.getPrettyXml can be used instead. - * - * This string can now be stored in a local persistent storage (for example - * using Google Gears) or it can be passed to a backend using mxUtils.post as - * follows. The url variable is the URL of the Java servlet, PHP page or HTTP - * handler, depending on the server. - * - * (code) - * var xmlString = encodeURIComponent(mxUtils.getXml(node)); - * mxUtils.post(url, 'xml='+xmlString, function(req) - * { - * // Process server response using req of type mxXmlRequest - * }); - * (end) - * - * Input: - * - * To load an XML representation of a diagram into an existing graph object - * mxUtils.load can be used as follows. The url variable is the URL of the Java - * servlet, PHP page or HTTP handler that produces the XML string. - * - * (code) - * var xmlDoc = mxUtils.load(url).getXml(); - * var node = xmlDoc.documentElement; - * var dec = new mxCodec(node.ownerDocument); - * dec.decode(node, graph.getModel()); - * (end) - * - * For creating a page that loads the client and a diagram using a single - * request please refer to the deployment examples in the backends. - * - * Functional dependencies: - * - * (see images/callgraph.png) - * - * Resources: - * - * resources/graph - Language resources for mxGraph - * - * Group: Events - * - * Event: mxEvent.ROOT - * - * Fires if the root in the model has changed. This event has no properties. - * - * Event: mxEvent.ALIGN_CELLS - * - * Fires between begin- and endUpdate in <alignCells>. The <code>cells</code> - * and <code>align</code> properties contain the respective arguments that were - * passed to <alignCells>. - * - * Event: mxEvent.FLIP_EDGE - * - * Fires between begin- and endUpdate in <flipEdge>. The <code>edge</code> - * property contains the edge passed to <flipEdge>. - * - * Event: mxEvent.ORDER_CELLS - * - * Fires between begin- and endUpdate in <orderCells>. The <code>cells</code> - * and <code>back</code> properties contain the respective arguments that were - * passed to <orderCells>. - * - * Event: mxEvent.CELLS_ORDERED - * - * Fires between begin- and endUpdate in <cellsOrdered>. The <code>cells</code> - * and <code>back</code> arguments contain the respective arguments that were - * passed to <cellsOrdered>. - * - * Event: mxEvent.GROUP_CELLS - * - * Fires between begin- and endUpdate in <groupCells>. The <code>group</code>, - * <code>cells</code> and <code>border</code> arguments contain the respective - * arguments that were passed to <groupCells>. - * - * Event: mxEvent.UNGROUP_CELLS - * - * Fires between begin- and endUpdate in <ungroupCells>. The <code>cells</code> - * property contains the array of cells that was passed to <ungroupCells>. - * - * Event: mxEvent.REMOVE_CELLS_FROM_PARENT - * - * Fires between begin- and endUpdate in <removeCellsFromParent>. The - * <code>cells</code> property contains the array of cells that was passed to - * <removeCellsFromParent>. - * - * Event: mxEvent.ADD_CELLS - * - * Fires between begin- and endUpdate in <addCells>. The <code>cells</code>, - * <code>parent</code>, <code>index</code>, <code>source</code> and - * <code>target</code> properties contain the respective arguments that were - * passed to <addCells>. - * - * Event: mxEvent.CELLS_ADDED - * - * Fires between begin- and endUpdate in <cellsAdded>. The <code>cells</code>, - * <code>parent</code>, <code>index</code>, <code>source</code>, - * <code>target</code> and <code>absolute</code> properties contain the - * respective arguments that were passed to <cellsAdded>. - * - * Event: mxEvent.REMOVE_CELLS - * - * Fires between begin- and endUpdate in <removeCells>. The <code>cells</code> - * and <code>includeEdges</code> arguments contain the respective arguments - * that were passed to <removeCells>. - * - * Event: mxEvent.CELLS_REMOVED - * - * Fires between begin- and endUpdate in <cellsRemoved>. The <code>cells</code> - * argument contains the array of cells that was removed. - * - * Event: mxEvent.SPLIT_EDGE - * - * Fires between begin- and endUpdate in <splitEdge>. The <code>edge</code> - * property contains the edge to be splitted, the <code>cells</code>, - * <code>newEdge</code>, <code>dx</code> and <code>dy</code> properties contain - * the respective arguments that were passed to <splitEdge>. - * - * Event: mxEvent.TOGGLE_CELLS - * - * Fires between begin- and endUpdate in <toggleCells>. The <code>show</code>, - * <code>cells</code> and <code>includeEdges</code> properties contain the - * respective arguments that were passed to <toggleCells>. - * - * Event: mxEvent.FOLD_CELLS - * - * Fires between begin- and endUpdate in <foldCells>. The - * <code>collapse</code>, <code>cells</code> and <code>recurse</code> - * properties contain the respective arguments that were passed to <foldCells>. - * - * Event: mxEvent.CELLS_FOLDED - * - * Fires between begin- and endUpdate in cellsFolded. The - * <code>collapse</code>, <code>cells</code> and <code>recurse</code> - * properties contain the respective arguments that were passed to - * <cellsFolded>. - * - * Event: mxEvent.UPDATE_CELL_SIZE - * - * Fires between begin- and endUpdate in <updateCellSize>. The - * <code>cell</code> and <code>ignoreChildren</code> properties contain the - * respective arguments that were passed to <updateCellSize>. - * - * Event: mxEvent.RESIZE_CELLS - * - * Fires between begin- and endUpdate in <resizeCells>. The <code>cells</code> - * and <code>bounds</code> properties contain the respective arguments that - * were passed to <resizeCells>. - * - * Event: mxEvent.CELLS_RESIZED - * - * Fires between begin- and endUpdate in <cellsResized>. The <code>cells</code> - * and <code>bounds</code> properties contain the respective arguments that - * were passed to <cellsResized>. - * - * Event: mxEvent.MOVE_CELLS - * - * Fires between begin- and endUpdate in <moveCells>. The <code>cells</code>, - * <code>dx</code>, <code>dy</code>, <code>clone</code>, <code>target</code> - * and <code>event</code> properties contain the respective arguments that - * were passed to <moveCells>. - * - * Event: mxEvent.CELLS_MOVED - * - * Fires between begin- and endUpdate in <cellsMoved>. The <code>cells</code>, - * <code>dx</code>, <code>dy</code> and <code>disconnect</code> properties - * contain the respective arguments that were passed to <cellsMoved>. - * - * Event: mxEvent.CONNECT_CELL - * - * Fires between begin- and endUpdate in <connectCell>. The <code>edge</code>, - * <code>terminal</code> and <code>source</code> properties contain the - * respective arguments that were passed to <connectCell>. - * - * Event: mxEvent.CELL_CONNECTED - * - * Fires between begin- and endUpdate in <cellConnected>. The - * <code>edge</code>, <code>terminal</code> and <code>source</code> properties - * contain the respective arguments that were passed to <cellConnected>. - * - * Event: mxEvent.REFRESH - * - * Fires after <refresh> was executed. This event has no properties. - * - * Event: mxEvent.CLICK - * - * Fires in <click> after a click event. The <code>event</code> property - * contains the original mouse event and <code>cell</code> property contains - * the cell under the mouse or null if the background was clicked. - * - * To handle a click event, use the following code: - * - * (code) - * graph.addListener(mxEvent.CLICK, function(sender, evt) - * { - * var e = evt.getProperty('event'); // mouse event - * var cell = evt.getProperty('cell'); // cell may be null - * - * if (!evt.isConsumed()) - * { - * if (cell != null) - * { - * // Do something useful with cell and consume the event - * evt.consume(); - * } - * } - * }); - * (end) - * - * Event: mxEvent.DOUBLE_CLICK - * - * Fires in <dblClick> after a double click. The <code>event</code> property - * contains the original mouse event and the <code>cell</code> property - * contains the cell under the mouse or null if the background was clicked. - * - * Event: mxEvent.SIZE - * - * Fires after <sizeDidChange> was executed. The <code>bounds</code> property - * contains the new graph bounds. - * - * Event: mxEvent.START_EDITING - * - * Fires before the in-place editor starts in <startEditingAtCell>. The - * <code>cell</code> property contains the cell that is being edited and the - * <code>event</code> property contains the optional event argument that was - * passed to <startEditingAtCell>. - * - * Event: mxEvent.LABEL_CHANGED - * - * Fires between begin- and endUpdate in <cellLabelChanged>. The - * <code>cell</code> property contains the cell, the <code>value</code> - * property contains the new value for the cell and the optional - * <code>event</code> property contains the mouse event that started the edit. - * - * Event: mxEvent.ADD_OVERLAY - * - * Fires after an overlay is added in <addCellOverlay>. The <code>cell</code> - * property contains the cell and the <code>overlay</code> property contains - * the <mxCellOverlay> that was added. - * - * Event: mxEvent.REMOVE_OVERLAY - * - * Fires after an overlay is removed in <removeCellOverlay> and - * <removeCellOverlays>. The <code>cell</code> property contains the cell and - * the <code>overlay</code> property contains the <mxCellOverlay> that was - * removed. - * - * Constructor: mxGraph - * - * Constructs a new mxGraph in the specified container. Model is an optional - * mxGraphModel. If no model is provided, a new mxGraphModel instance is - * used as the model. The container must have a valid owner document prior - * to calling this function in Internet Explorer. RenderHint is a string to - * affect the display performance and rendering in IE, but not in SVG-based - * browsers. The parameter is mapped to <dialect>, which may - * be one of <mxConstants.DIALECT_SVG> for SVG-based browsers, - * <mxConstants.DIALECT_STRICTHTML> for fastest display mode, - * <mxConstants.DIALECT_PREFERHTML> for faster display mode, - * <mxConstants.DIALECT_MIXEDHTML> for fast and <mxConstants.DIALECT_VML> - * for exact display mode (slowest). The dialects are defined in mxConstants. - * The default values are DIALECT_SVG for SVG-based browsers and - * DIALECT_MIXED for IE. - * - * The possible values for the renderingHint parameter are explained below: - * - * fast - The parameter is based on the fact that the display performance is - * highly improved in IE if the VML is not contained within a VML group - * element. The lack of a group element only slightly affects the display while - * panning, but improves the performance by almost a factor of 2, while keeping - * the display sufficiently accurate. This also allows to render certain shapes as HTML - * if the display accuracy is not affected, which is implemented by - * <mxShape.isMixedModeHtml>. This is the default setting and is mapped to - * DIALECT_MIXEDHTML. - * faster - Same as fast, but more expensive shapes are avoided. This is - * controlled by <mxShape.preferModeHtml>. The default implementation will - * avoid gradients and rounded rectangles, but more significant shapes, such - * as rhombus, ellipse, actor and cylinder will be rendered accurately. This - * setting is mapped to DIALECT_PREFERHTML. - * fastest - Almost anything will be rendered in Html. This allows for - * rectangles, labels and images. This setting is mapped to - * DIALECT_STRICTHTML. - * exact - If accurate panning is required and if the diagram is small (up - * to 100 cells), then this value should be used. In this mode, a group is - * created that contains the VML. This allows for accurate panning and is - * mapped to DIALECT_VML. - * - * Example: - * - * To create a graph inside a DOM node with an id of graph: - * (code) - * var container = document.getElementById('graph'); - * var graph = new mxGraph(container); - * (end) - * - * Parameters: - * - * container - Optional DOM node that acts as a container for the graph. - * If this is null then the container can be initialized later using - * <init>. - * model - Optional <mxGraphModel> that constitutes the graph data. - * renderHint - Optional string that specifies the display accuracy and - * performance. Default is mxConstants.DIALECT_MIXEDHTML (for IE). - * stylesheet - Optional <mxStylesheet> to be used in the graph. - */ -function mxGraph(container, model, renderHint, stylesheet) -{ - // Initializes the variable in case the prototype has been - // modified to hold some listeners (which is possible because - // the createHandlers call is executed regardless of the - // arguments passed into the ctor). - this.mouseListeners = null; - - // Converts the renderHint into a dialect - this.renderHint = renderHint; - - if (mxClient.IS_SVG) - { - this.dialect = mxConstants.DIALECT_SVG; - } - else if (renderHint == mxConstants.RENDERING_HINT_EXACT && mxClient.IS_VML) - { - this.dialect = mxConstants.DIALECT_VML; - } - else if (renderHint == mxConstants.RENDERING_HINT_FASTEST) - { - this.dialect = mxConstants.DIALECT_STRICTHTML; - } - else if (renderHint == mxConstants.RENDERING_HINT_FASTER) - { - this.dialect = mxConstants.DIALECT_PREFERHTML; - } - else // default for VML - { - this.dialect = mxConstants.DIALECT_MIXEDHTML; - } - - // Initializes the main members that do not require a container - this.model = (model != null) ? model : new mxGraphModel(); - this.multiplicities = []; - this.imageBundles = []; - this.cellRenderer = this.createCellRenderer(); - this.setSelectionModel(this.createSelectionModel()); - this.setStylesheet((stylesheet != null) ? stylesheet : this.createStylesheet()); - this.view = this.createGraphView(); - - // Adds a graph model listener to update the view - this.graphModelChangeListener = mxUtils.bind(this, function(sender, evt) - { - this.graphModelChanged(evt.getProperty('edit').changes); - }); - - this.model.addListener(mxEvent.CHANGE, this.graphModelChangeListener); - - // Installs basic event handlers with disabled default settings. - this.createHandlers(); - - // Initializes the display if a container was specified - if (container != null) - { - this.init(container); - } - - this.view.revalidate(); -}; - -/** - * Installs the required language resources at class - * loading time. - */ -if (mxLoadResources) -{ - mxResources.add(mxClient.basePath+'/resources/graph'); -} - -/** - * Extends mxEventSource. - */ -mxGraph.prototype = new mxEventSource(); -mxGraph.prototype.constructor = mxGraph; - -/** - * Variable: EMPTY_ARRAY - * - * Immutable empty array instance. - */ -mxGraph.prototype.EMPTY_ARRAY = []; - -/** - * Group: Variables - */ - -/** - * Variable: mouseListeners - * - * Holds the mouse event listeners. See <fireMouseEvent>. - */ -mxGraph.prototype.mouseListeners = null; - -/** - * Variable: isMouseDown - * - * Holds the state of the mouse button. - */ -mxGraph.prototype.isMouseDown = false; - -/** - * Variable: model - * - * Holds the <mxGraphModel> that contains the cells to be displayed. - */ -mxGraph.prototype.model = null; - -/** - * Variable: view - * - * Holds the <mxGraphView> that caches the <mxCellStates> for the cells. - */ -mxGraph.prototype.view = null; - -/** - * Variable: stylesheet - * - * Holds the <mxStylesheet> that defines the appearance of the cells. - * - * - * Example: - * - * Use the following code to read a stylesheet into an existing graph. - * - * (code) - * var req = mxUtils.load('stylesheet.xml'); - * var root = req.getDocumentElement(); - * var dec = new mxCodec(root.ownerDocument); - * dec.decode(root, graph.stylesheet); - * (end) - */ -mxGraph.prototype.stylesheet = null; - -/** - * Variable: selectionModel - * - * Holds the <mxGraphSelectionModel> that models the current selection. - */ -mxGraph.prototype.selectionModel = null; - -/** - * Variable: cellEditor - * - * Holds the <mxCellEditor> that is used as the in-place editing. - */ -mxGraph.prototype.cellEditor = null; - -/** - * Variable: cellRenderer - * - * Holds the <mxCellRenderer> for rendering the cells in the graph. - */ -mxGraph.prototype.cellRenderer = null; - -/** - * Variable: multiplicities - * - * An array of <mxMultiplicities> describing the allowed - * connections in a graph. - */ -mxGraph.prototype.multiplicities = null; - -/** - * Variable: renderHint - * - * RenderHint as it was passed to the constructor. - */ -mxGraph.prototype.renderHint = null; - -/** - * Variable: dialect - * - * Dialect to be used for drawing the graph. Possible values are all - * constants in <mxConstants> with a DIALECT-prefix. - */ -mxGraph.prototype.dialect = null; - -/** - * Variable: gridSize - * - * Specifies the grid size. Default is 10. - */ -mxGraph.prototype.gridSize = 10; - -/** - * Variable: gridEnabled - * - * Specifies if the grid is enabled. This is used in <snap>. Default is - * true. - */ -mxGraph.prototype.gridEnabled = true; - -/** - * Variable: portsEnabled - * - * Specifies if ports are enabled. This is used in <cellConnected> to update - * the respective style. Default is true. - */ -mxGraph.prototype.portsEnabled = true; - -/** - * Variable: doubleTapEnabled - * - * Specifies if double taps on touch-based devices should be handled. Default - * is true. - */ -mxGraph.prototype.doubleTapEnabled = true; - -/** - * Variable: doubleTapTimeout - * - * Specifies the timeout for double taps. Default is 700 ms. - */ -mxGraph.prototype.doubleTapTimeout = 700; - -/** - * Variable: doubleTapTolerance - * - * Specifies the tolerance for double taps. Default is 25 pixels. - */ -mxGraph.prototype.doubleTapTolerance = 25; - -/** - * Variable: lastTouchX - * - * Holds the x-coordinate of the last touch event for double tap detection. - */ -mxGraph.prototype.lastTouchY = 0; - -/** - * Variable: lastTouchX - * - * Holds the y-coordinate of the last touch event for double tap detection. - */ -mxGraph.prototype.lastTouchY = 0; - -/** - * Variable: lastTouchTime - * - * Holds the time of the last touch event for double click detection. - */ -mxGraph.prototype.lastTouchTime = 0; - -/** - * Variable: gestureEnabled - * - * Specifies if the handleGesture method should be invoked. Default is true. This - * is an experimental feature for touch-based devices. - */ -mxGraph.prototype.gestureEnabled = true; - -/** - * Variable: tolerance - * - * Tolerance for a move to be handled as a single click. - * Default is 4 pixels. - */ -mxGraph.prototype.tolerance = 4; - -/** - * Variable: defaultOverlap - * - * Value returned by <getOverlap> if <isAllowOverlapParent> returns - * true for the given cell. <getOverlap> is used in <constrainChild> if - * <isConstrainChild> returns true. The value specifies the - * portion of the child which is allowed to overlap the parent. - */ -mxGraph.prototype.defaultOverlap = 0.5; - -/** - * Variable: defaultParent - * - * Specifies the default parent to be used to insert new cells. - * This is used in <getDefaultParent>. Default is null. - */ -mxGraph.prototype.defaultParent = null; - -/** - * Variable: alternateEdgeStyle - * - * Specifies the alternate edge style to be used if the main control point - * on an edge is being doubleclicked. Default is null. - */ -mxGraph.prototype.alternateEdgeStyle = null; - -/** - * Variable: backgroundImage - * - * Specifies the <mxImage> to be returned by <getBackgroundImage>. Default - * is null. - * - * Example: - * - * (code) - * var img = new mxImage('http://www.example.com/maps/examplemap.jpg', 1024, 768); - * graph.setBackgroundImage(img); - * graph.view.validate(); - * (end) - */ -mxGraph.prototype.backgroundImage = null; - -/** - * Variable: pageVisible - * - * Specifies if the background page should be visible. Default is false. - * Not yet implemented. - */ -mxGraph.prototype.pageVisible = false; - -/** - * Variable: pageBreaksVisible - * - * Specifies if a dashed line should be drawn between multiple pages. Default - * is false. If you change this value while a graph is being displayed then you - * should call <sizeDidChange> to force an update of the display. - */ -mxGraph.prototype.pageBreaksVisible = false; - -/** - * Variable: pageBreakColor - * - * Specifies the color for page breaks. Default is 'gray'. - */ -mxGraph.prototype.pageBreakColor = 'gray'; - -/** - * Variable: pageBreakDashed - * - * Specifies the page breaks should be dashed. Default is true. - */ -mxGraph.prototype.pageBreakDashed = true; - -/** - * Variable: minPageBreakDist - * - * Specifies the minimum distance for page breaks to be visible. Default is - * 20 (in pixels). - */ -mxGraph.prototype.minPageBreakDist = 20; - -/** - * Variable: preferPageSize - * - * Specifies if the graph size should be rounded to the next page number in - * <sizeDidChange>. This is only used if the graph container has scrollbars. - * Default is false. - */ -mxGraph.prototype.preferPageSize = false; - -/** - * Variable: pageFormat - * - * Specifies the page format for the background page. Default is - * <mxConstants.PAGE_FORMAT_A4_PORTRAIT>. This is used as the default in - * <mxPrintPreview> and for painting the background page if <pageVisible> is - * true and the pagebreaks if <pageBreaksVisible> is true. - */ -mxGraph.prototype.pageFormat = mxConstants.PAGE_FORMAT_A4_PORTRAIT; - -/** - * Variable: pageScale - * - * Specifies the scale of the background page. Default is 1.5. - * Not yet implemented. - */ -mxGraph.prototype.pageScale = 1.5; - -/** - * Variable: enabled - * - * Specifies the return value for <isEnabled>. Default is true. - */ -mxGraph.prototype.enabled = true; - -/** - * Variable: escapeEnabled - * - * Specifies if <mxKeyHandler> should invoke <escape> when the escape key - * is pressed. Default is true. - */ -mxGraph.prototype.escapeEnabled = true; - -/** - * Variable: invokesStopCellEditing - * - * If true, when editing is to be stopped by way of selection changing, - * data in diagram changing or other means stopCellEditing is invoked, and - * changes are saved. This is implemented in a focus handler in - * <mxCellEditor>. Default is true. - */ -mxGraph.prototype.invokesStopCellEditing = true; - -/** - * Variable: enterStopsCellEditing - * - * If true, pressing the enter key without pressing control or shift will stop - * editing and accept the new value. This is used in <mxCellEditor> to stop - * cell editing. Note: You can always use F2 and escape to stop editing. - * Default is false. - */ -mxGraph.prototype.enterStopsCellEditing = false; - -/** - * Variable: useScrollbarsForPanning - * - * Specifies if scrollbars should be used for panning in <panGraph> if - * any scrollbars are available. If scrollbars are enabled in CSS, but no - * scrollbars appear because the graph is smaller than the container size, - * then no panning occurs if this is true. Default is true. - */ -mxGraph.prototype.useScrollbarsForPanning = true; - -/** - * Variable: exportEnabled - * - * Specifies the return value for <canExportCell>. Default is true. - */ -mxGraph.prototype.exportEnabled = true; - -/** - * Variable: importEnabled - * - * Specifies the return value for <canImportCell>. Default is true. - */ -mxGraph.prototype.importEnabled = true; - -/** - * Variable: cellsLocked - * - * Specifies the return value for <isCellLocked>. Default is false. - */ -mxGraph.prototype.cellsLocked = false; - -/** - * Variable: cellsCloneable - * - * Specifies the return value for <isCellCloneable>. Default is true. - */ -mxGraph.prototype.cellsCloneable = true; - -/** - * Variable: foldingEnabled - * - * Specifies if folding (collapse and expand via an image icon in the graph - * should be enabled). Default is true. - */ -mxGraph.prototype.foldingEnabled = true; - -/** - * Variable: cellsEditable - * - * Specifies the return value for <isCellEditable>. Default is true. - */ -mxGraph.prototype.cellsEditable = true; - -/** - * Variable: cellsDeletable - * - * Specifies the return value for <isCellDeletable>. Default is true. - */ -mxGraph.prototype.cellsDeletable = true; - -/** - * Variable: cellsMovable - * - * Specifies the return value for <isCellMovable>. Default is true. - */ -mxGraph.prototype.cellsMovable = true; - -/** - * Variable: edgeLabelsMovable - * - * Specifies the return value for edges in <isLabelMovable>. Default is true. - */ -mxGraph.prototype.edgeLabelsMovable = true; - -/** - * Variable: vertexLabelsMovable - * - * Specifies the return value for vertices in <isLabelMovable>. Default is false. - */ -mxGraph.prototype.vertexLabelsMovable = false; - -/** - * Variable: dropEnabled - * - * Specifies the return value for <isDropEnabled>. Default is false. - */ -mxGraph.prototype.dropEnabled = false; - -/** - * Variable: splitEnabled - * - * Specifies if dropping onto edges should be enabled. Default is true. - */ -mxGraph.prototype.splitEnabled = true; - -/** - * Variable: cellsResizable - * - * Specifies the return value for <isCellResizable>. Default is true. - */ -mxGraph.prototype.cellsResizable = true; - -/** - * Variable: cellsBendable - * - * Specifies the return value for <isCellsBendable>. Default is true. - */ -mxGraph.prototype.cellsBendable = true; - -/** - * Variable: cellsSelectable - * - * Specifies the return value for <isCellSelectable>. Default is true. - */ -mxGraph.prototype.cellsSelectable = true; - -/** - * Variable: cellsDisconnectable - * - * Specifies the return value for <isCellDisconntable>. Default is true. - */ -mxGraph.prototype.cellsDisconnectable = true; - -/** - * Variable: autoSizeCells - * - * Specifies if the graph should automatically update the cell size after an - * edit. This is used in <isAutoSizeCell>. Default is false. - */ -mxGraph.prototype.autoSizeCells = false; - -/** - * Variable: autoScroll - * - * Specifies if the graph should automatically scroll if the mouse goes near - * the container edge while dragging. This is only taken into account if the - * container has scrollbars. Default is true. - * - * If you need this to work without scrollbars then set <ignoreScrollbars> to - * true. - */ -mxGraph.prototype.autoScroll = true; - -/** - * Variable: timerAutoScroll - * - * Specifies if timer-based autoscrolling should be used via mxPanningManager. - * Note that this disables the code in <scrollPointToVisible> and uses code in - * mxPanningManager instead. Note that <autoExtend> is disabled if this is - * true and that this should only be used with a scroll buffer or when - * scollbars are visible and scrollable in all directions. Default is false. - */ -mxGraph.prototype.timerAutoScroll = false; - -/** - * Variable: allowAutoPanning - * - * Specifies if panning via <panGraph> should be allowed to implement autoscroll - * if no scrollbars are available in <scrollPointToVisible>. Default is false. - */ -mxGraph.prototype.allowAutoPanning = false; - -/** - * Variable: ignoreScrollbars - * - * Specifies if the graph should automatically scroll regardless of the - * scrollbars. - */ -mxGraph.prototype.ignoreScrollbars = false; - -/** - * Variable: autoExtend - * - * Specifies if the size of the graph should be automatically extended if the - * mouse goes near the container edge while dragging. This is only taken into - * account if the container has scrollbars. Default is true. See <autoScroll>. - */ -mxGraph.prototype.autoExtend = true; - -/** - * Variable: maximumGraphBounds - * - * <mxRectangle> that specifies the area in which all cells in the diagram - * should be placed. Uses in <getMaximumGraphBounds>. Use a width or height of - * 0 if you only want to give a upper, left corner. - */ -mxGraph.prototype.maximumGraphBounds = null; - -/** - * Variable: minimumGraphSize - * - * <mxRectangle> that specifies the minimum size of the graph. This is ignored - * if the graph container has no scrollbars. Default is null. - */ -mxGraph.prototype.minimumGraphSize = null; - -/** - * Variable: minimumContainerSize - * - * <mxRectangle> that specifies the minimum size of the <container> if - * <resizeContainer> is true. - */ -mxGraph.prototype.minimumContainerSize = null; - -/** - * Variable: maximumContainerSize - * - * <mxRectangle> that specifies the maximum size of the container if - * <resizeContainer> is true. - */ -mxGraph.prototype.maximumContainerSize = null; - -/** - * Variable: resizeContainer - * - * Specifies if the container should be resized to the graph size when - * the graph size has changed. Default is false. - */ -mxGraph.prototype.resizeContainer = false; - -/** - * Variable: border - * - * Border to be added to the bottom and right side when the container is - * being resized after the graph has been changed. Default is 0. - */ -mxGraph.prototype.border = 0; - -/** - * Variable: ordered - * - * Specifies if the display should reflect the order of the cells in - * the model. Default is true. This has precendence over - * <keepEdgesInBackground> and <keepEdgesInForeground>. - */ -mxGraph.prototype.ordered = true; - -/** - * Variable: keepEdgesInForeground - * - * Specifies if edges should appear in the foreground regardless of their - * order in the model. This has precendence over <keepEdgeInBackground>, - * but not over <ordered>. Default is false. - */ -mxGraph.prototype.keepEdgesInForeground = false; - -/** - * Variable: keepEdgesInBackground - * - * Specifies if edges should appear in the background regardless of their - * order in the model. <ordered> and <keepEdgesInForeground> have - * precedence over this setting. Default is true. - */ -mxGraph.prototype.keepEdgesInBackground = true; - -/** - * Variable: allowNegativeCoordinates - * - * Specifies if negative coordinates for vertices are allowed. Default is true. - */ -mxGraph.prototype.allowNegativeCoordinates = true; - -/** - * Variable: constrainChildren - * - * Specifies the return value for <isConstrainChildren>. Default is - * true. - */ -mxGraph.prototype.constrainChildren = true; - -/** - * Variable: extendParents - * - * Specifies if a parent should contain the child bounds after a resize of - * the child. Default is true. - */ -mxGraph.prototype.extendParents = true; - -/** - * Variable: extendParentsOnAdd - * - * Specifies if parents should be extended according to the <extendParents> - * switch if cells are added. Default is true. - */ -mxGraph.prototype.extendParentsOnAdd = true; - -/** - * Variable: collapseToPreferredSize - * - * Specifies if the cell size should be changed to the preferred size when - * a cell is first collapsed. Default is true. - */ -mxGraph.prototype.collapseToPreferredSize = true; - -/** - * Variable: zoomFactor - * - * Specifies the factor used for <zoomIn> and <zoomOut>. Default is 1.2 - * (120%). - */ -mxGraph.prototype.zoomFactor = 1.2; - -/** - * Variable: keepSelectionVisibleOnZoom - * - * Specifies if the viewport should automatically contain the selection cells - * after a zoom operation. Default is false. - */ -mxGraph.prototype.keepSelectionVisibleOnZoom = false; - -/** - * Variable: centerZoom - * - * Specifies if the zoom operations should go into the center of the actual - * diagram rather than going from top, left. Default is true. - */ -mxGraph.prototype.centerZoom = true; - -/** - * Variable: resetViewOnRootChange - * - * Specifies if the scale and translate should be reset if the root changes in - * the model. Default is true. - */ -mxGraph.prototype.resetViewOnRootChange = true; - -/** - * Variable: resetEdgesOnResize - * - * Specifies if edge control points should be reset after the resize of a - * connected cell. Default is false. - */ -mxGraph.prototype.resetEdgesOnResize = false; - -/** - * Variable: resetEdgesOnMove - * - * Specifies if edge control points should be reset after the move of a - * connected cell. Default is false. - */ -mxGraph.prototype.resetEdgesOnMove = false; - -/** - * Variable: resetEdgesOnConnect - * - * Specifies if edge control points should be reset after the the edge has been - * reconnected. Default is true. - */ -mxGraph.prototype.resetEdgesOnConnect = true; - -/** - * Variable: allowLoops - * - * Specifies if loops (aka self-references) are allowed. Default is false. - */ -mxGraph.prototype.allowLoops = false; - -/** - * Variable: defaultLoopStyle - * - * <mxEdgeStyle> to be used for loops. This is a fallback for loops if the - * <mxConstants.STYLE_LOOP> is undefined. Default is <mxEdgeStyle.Loop>. - */ -mxGraph.prototype.defaultLoopStyle = mxEdgeStyle.Loop; - -/** - * Variable: multigraph - * - * Specifies if multiple edges in the same direction between the same pair of - * vertices are allowed. Default is true. - */ -mxGraph.prototype.multigraph = true; - -/** - * Variable: connectableEdges - * - * Specifies if edges are connectable. Default is false. This overrides the - * connectable field in edges. - */ -mxGraph.prototype.connectableEdges = false; - -/** - * Variable: allowDanglingEdges - * - * Specifies if edges with disconnected terminals are allowed in the graph. - * Default is true. - */ -mxGraph.prototype.allowDanglingEdges = true; - -/** - * Variable: cloneInvalidEdges - * - * Specifies if edges that are cloned should be validated and only inserted - * if they are valid. Default is true. - */ -mxGraph.prototype.cloneInvalidEdges = false; - -/** - * Variable: disconnectOnMove - * - * Specifies if edges should be disconnected from their terminals when they - * are moved. Default is true. - */ -mxGraph.prototype.disconnectOnMove = true; - -/** - * Variable: labelsVisible - * - * Specifies if labels should be visible. This is used in <getLabel>. Default - * is true. - */ -mxGraph.prototype.labelsVisible = true; - -/** - * Variable: htmlLabels - * - * Specifies the return value for <isHtmlLabel>. Default is false. - */ -mxGraph.prototype.htmlLabels = false; - -/** - * Variable: swimlaneSelectionEnabled - * - * Specifies if swimlanes should be selectable via the content if the - * mouse is released. Default is true. - */ -mxGraph.prototype.swimlaneSelectionEnabled = true; - -/** - * Variable: swimlaneNesting - * - * Specifies if nesting of swimlanes is allowed. Default is true. - */ -mxGraph.prototype.swimlaneNesting = true; - -/** - * Variable: swimlaneIndicatorColorAttribute - * - * The attribute used to find the color for the indicator if the indicator - * color is set to 'swimlane'. Default is <mxConstants.STYLE_FILLCOLOR>. - */ -mxGraph.prototype.swimlaneIndicatorColorAttribute = mxConstants.STYLE_FILLCOLOR; - -/** - * Variable: imageBundles - * - * Holds the list of image bundles. - */ -mxGraph.prototype.imageBundles = null; - -/** - * Variable: minFitScale - * - * Specifies the minimum scale to be applied in <fit>. Default is 0.1. Set this - * to null to allow any value. - */ -mxGraph.prototype.minFitScale = 0.1; - -/** - * Variable: maxFitScale - * - * Specifies the maximum scale to be applied in <fit>. Default is 8. Set this - * to null to allow any value. - */ -mxGraph.prototype.maxFitScale = 8; - -/** - * Variable: panDx - * - * Current horizontal panning value. Default is 0. - */ -mxGraph.prototype.panDx = 0; - -/** - * Variable: panDy - * - * Current vertical panning value. Default is 0. - */ -mxGraph.prototype.panDy = 0; - -/** - * Variable: collapsedImage - * - * Specifies the <mxImage> to indicate a collapsed state. - * Default value is mxClient.imageBasePath + '/collapsed.gif' - */ -mxGraph.prototype.collapsedImage = new mxImage(mxClient.imageBasePath + '/collapsed.gif', 9, 9); - -/** - * Variable: expandedImage - * - * Specifies the <mxImage> to indicate a expanded state. - * Default value is mxClient.imageBasePath + '/expanded.gif' - */ -mxGraph.prototype.expandedImage = new mxImage(mxClient.imageBasePath + '/expanded.gif', 9, 9); - -/** - * Variable: warningImage - * - * Specifies the <mxImage> for the image to be used to display a warning - * overlay. See <setCellWarning>. Default value is mxClient.imageBasePath + - * '/warning'. The extension for the image depends on the platform. It is - * '.png' on the Mac and '.gif' on all other platforms. - */ -mxGraph.prototype.warningImage = new mxImage(mxClient.imageBasePath + '/warning'+ - ((mxClient.IS_MAC) ? '.png' : '.gif'), 16, 16); - -/** - * Variable: alreadyConnectedResource - * - * Specifies the resource key for the error message to be displayed in - * non-multigraphs when two vertices are already connected. If the resource - * for this key does not exist then the value is used as the error message. - * Default is 'alreadyConnected'. - */ -mxGraph.prototype.alreadyConnectedResource = (mxClient.language != 'none') ? 'alreadyConnected' : ''; - -/** - * Variable: containsValidationErrorsResource - * - * Specifies the resource key for the warning message to be displayed when - * a collapsed cell contains validation errors. If the resource for this - * key does not exist then the value is used as the warning message. - * Default is 'containsValidationErrors'. - */ -mxGraph.prototype.containsValidationErrorsResource = (mxClient.language != 'none') ? 'containsValidationErrors' : ''; - -/** - * Variable: collapseExpandResource - * - * Specifies the resource key for the tooltip on the collapse/expand icon. - * If the resource for this key does not exist then the value is used as - * the tooltip. Default is 'collapse-expand'. - */ -mxGraph.prototype.collapseExpandResource = (mxClient.language != 'none') ? 'collapse-expand' : ''; - -/** - * Function: init - * - * Initializes the <container> and creates the respective datastructures. - * - * Parameters: - * - * container - DOM node that will contain the graph display. - */ - mxGraph.prototype.init = function(container) - { - this.container = container; - - // Initializes the in-place editor - this.cellEditor = this.createCellEditor(); - - // Initializes the container using the view - this.view.init(); - - // Updates the size of the container for the current graph - this.sizeDidChange(); - - // Automatic deallocation of memory - if (mxClient.IS_IE) - { - mxEvent.addListener(window, 'unload', mxUtils.bind(this, function() - { - this.destroy(); - })); - - // Disable shift-click for text - mxEvent.addListener(container, 'selectstart', - mxUtils.bind(this, function() - { - return this.isEditing(); - }) - ); - } -}; - -/** - * Function: createHandlers - * - * Creates the tooltip-, panning-, connection- and graph-handler (in this - * order). This is called in the constructor before <init> is called. - */ -mxGraph.prototype.createHandlers = function(container) -{ - this.tooltipHandler = new mxTooltipHandler(this); - this.tooltipHandler.setEnabled(false); - this.panningHandler = new mxPanningHandler(this); - this.panningHandler.panningEnabled = false; - this.selectionCellsHandler = new mxSelectionCellsHandler(this); - this.connectionHandler = new mxConnectionHandler(this); - this.connectionHandler.setEnabled(false); - this.graphHandler = new mxGraphHandler(this); -}; - -/** - * Function: createSelectionModel - * - * Creates a new <mxGraphSelectionModel> to be used in this graph. - */ -mxGraph.prototype.createSelectionModel = function() -{ - return new mxGraphSelectionModel(this); -}; - -/** - * Function: createStylesheet - * - * Creates a new <mxGraphSelectionModel> to be used in this graph. - */ -mxGraph.prototype.createStylesheet = function() -{ - return new mxStylesheet(); -}; - -/** - * Function: createGraphView - * - * Creates a new <mxGraphView> to be used in this graph. - */ -mxGraph.prototype.createGraphView = function() -{ - return new mxGraphView(this); -}; - -/** - * Function: createCellRenderer - * - * Creates a new <mxCellRenderer> to be used in this graph. - */ -mxGraph.prototype.createCellRenderer = function() -{ - return new mxCellRenderer(); -}; - -/** - * Function: createCellEditor - * - * Creates a new <mxCellEditor> to be used in this graph. - */ -mxGraph.prototype.createCellEditor = function() -{ - return new mxCellEditor(this); -}; - -/** - * Function: getModel - * - * Returns the <mxGraphModel> that contains the cells. - */ -mxGraph.prototype.getModel = function() -{ - return this.model; -}; - -/** - * Function: getView - * - * Returns the <mxGraphView> that contains the <mxCellStates>. - */ -mxGraph.prototype.getView = function() -{ - return this.view; -}; - -/** - * Function: getStylesheet - * - * Returns the <mxStylesheet> that defines the style. - */ -mxGraph.prototype.getStylesheet = function() -{ - return this.stylesheet; -}; - -/** - * Function: setStylesheet - * - * Sets the <mxStylesheet> that defines the style. - */ -mxGraph.prototype.setStylesheet = function(stylesheet) -{ - this.stylesheet = stylesheet; -}; - -/** - * Function: getSelectionModel - * - * Returns the <mxGraphSelectionModel> that contains the selection. - */ -mxGraph.prototype.getSelectionModel = function() -{ - return this.selectionModel; -}; - -/** - * Function: setSelectionModel - * - * Sets the <mxSelectionModel> that contains the selection. - */ -mxGraph.prototype.setSelectionModel = function(selectionModel) -{ - this.selectionModel = selectionModel; -}; - -/** - * Function: getSelectionCellsForChanges - * - * Returns the cells to be selected for the given array of changes. - */ -mxGraph.prototype.getSelectionCellsForChanges = function(changes) -{ - var cells = []; - - for (var i = 0; i < changes.length; i++) - { - var change = changes[i]; - - if (change.constructor != mxRootChange) - { - var cell = null; - - if (change instanceof mxChildChange && change.previous == null) - { - cell = change.child; - } - else if (change.cell != null && change.cell instanceof mxCell) - { - cell = change.cell; - } - - if (cell != null && mxUtils.indexOf(cells, cell) < 0) - { - cells.push(cell); - } - } - } - - return this.getModel().getTopmostCells(cells); -}; - -/** - * Function: graphModelChanged - * - * Called when the graph model changes. Invokes <processChange> on each - * item of the given array to update the view accordingly. - * - * Parameters: - * - * changes - Array that contains the individual changes. - */ -mxGraph.prototype.graphModelChanged = function(changes) -{ - for (var i = 0; i < changes.length; i++) - { - this.processChange(changes[i]); - } - - this.removeSelectionCells(this.getRemovedCellsForChanges(changes)); - - this.view.validate(); - this.sizeDidChange(); -}; - -/** - * Function: getRemovedCellsForChanges - * - * Returns the cells that have been removed from the model. - */ -mxGraph.prototype.getRemovedCellsForChanges = function(changes) -{ - var result = []; - - for (var i = 0; i < changes.length; i++) - { - var change = changes[i]; - - // Resets the view settings, removes all cells and clears - // the selection if the root changes. - if (change instanceof mxRootChange) - { - break; - } - else if (change instanceof mxChildChange) - { - if (change.previous != null && change.parent == null) - { - result = result.concat(this.model.getDescendants(change.child)); - } - } - else if (change instanceof mxVisibleChange) - { - result = result.concat(this.model.getDescendants(change.cell)); - } - } - - return result; -}; - -/** - * Function: processChange - * - * Processes the given change and invalidates the respective cached data - * in <view>. This fires a <root> event if the root has changed in the - * model. - * - * Parameters: - * - * change - Object that represents the change on the model. - */ -mxGraph.prototype.processChange = function(change) -{ - // Resets the view settings, removes all cells and clears - // the selection if the root changes. - if (change instanceof mxRootChange) - { - this.clearSelection(); - this.removeStateForCell(change.previous); - - if (this.resetViewOnRootChange) - { - this.view.scale = 1; - this.view.translate.x = 0; - this.view.translate.y = 0; - } - - this.fireEvent(new mxEventObject(mxEvent.ROOT)); - } - - // Adds or removes a child to the view by online invaliding - // the minimal required portions of the cache, namely, the - // old and new parent and the child. - else if (change instanceof mxChildChange) - { - var newParent = this.model.getParent(change.child); - - if (newParent != null) - { - // Flags the cell for updating the order in the renderer - this.view.invalidate(change.child, true, false, change.previous != null); - } - else - { - this.removeStateForCell(change.child); - - // Handles special case of current root of view being removed - if (this.view.currentRoot == change.child) - { - this.home(); - } - } - - if (newParent != change.previous) - { - // Refreshes the collapse/expand icons on the parents - if (newParent != null) - { - this.view.invalidate(newParent, false, false); - } - - if (change.previous != null) - { - this.view.invalidate(change.previous, false, false); - } - } - } - - // Handles two special cases where the shape does not need to be - // recreated from scratch, it only need to be invalidated. - else if (change instanceof mxTerminalChange || - change instanceof mxGeometryChange) - { - this.view.invalidate(change.cell); - } - - // Handles two special cases where only the shape, but no - // descendants need to be recreated - else if (change instanceof mxValueChange) - { - this.view.invalidate(change.cell, false, false); - } - - // Requires a new mxShape in JavaScript - else if (change instanceof mxStyleChange) - { - this.view.invalidate(change.cell, true, true, false); - this.view.removeState(change.cell); - } - - // Removes the state from the cache by default - else if (change.cell != null && - change.cell instanceof mxCell) - { - this.removeStateForCell(change.cell); - } -}; - -/** - * Function: removeStateForCell - * - * Removes all cached information for the given cell and its descendants. - * This is called when a cell was removed from the model. - * - * Paramters: - * - * cell - <mxCell> that was removed from the model. - */ -mxGraph.prototype.removeStateForCell = function(cell) -{ - var childCount = this.model.getChildCount(cell); - - for (var i = 0; i < childCount; i++) - { - this.removeStateForCell(this.model.getChildAt(cell, i)); - } - - this.view.removeState(cell); -}; - -/** - * Group: Overlays - */ - -/** - * Function: addCellOverlay - * - * Adds an <mxCellOverlay> for the specified cell. This method fires an - * <addoverlay> event and returns the new <mxCellOverlay>. - * - * Parameters: - * - * cell - <mxCell> to add the overlay for. - * overlay - <mxCellOverlay> to be added for the cell. - */ -mxGraph.prototype.addCellOverlay = function(cell, overlay) -{ - if (cell.overlays == null) - { - cell.overlays = []; - } - - cell.overlays.push(overlay); - - var state = this.view.getState(cell); - - // Immediately updates the cell display if the state exists - if (state != null) - { - this.cellRenderer.redraw(state); - } - - this.fireEvent(new mxEventObject(mxEvent.ADD_OVERLAY, - 'cell', cell, 'overlay', overlay)); - - return overlay; -}; - -/** - * Function: getCellOverlays - * - * Returns the array of <mxCellOverlays> for the given cell or null, if - * no overlays are defined. - * - * Parameters: - * - * cell - <mxCell> whose overlays should be returned. - */ -mxGraph.prototype.getCellOverlays = function(cell) -{ - return cell.overlays; -}; - -/** - * Function: removeCellOverlay - * - * Removes and returns the given <mxCellOverlay> from the given cell. This - * method fires a <removeoverlay> event. If no overlay is given, then all - * overlays are removed using <removeOverlays>. - * - * Parameters: - * - * cell - <mxCell> whose overlay should be removed. - * overlay - Optional <mxCellOverlay> to be removed. - */ -mxGraph.prototype.removeCellOverlay = function(cell, overlay) -{ - if (overlay == null) - { - this.removeCellOverlays(cell); - } - else - { - var index = mxUtils.indexOf(cell.overlays, overlay); - - if (index >= 0) - { - cell.overlays.splice(index, 1); - - if (cell.overlays.length == 0) - { - cell.overlays = null; - } - - // Immediately updates the cell display if the state exists - var state = this.view.getState(cell); - - if (state != null) - { - this.cellRenderer.redraw(state); - } - - this.fireEvent(new mxEventObject(mxEvent.REMOVE_OVERLAY, - 'cell', cell, 'overlay', overlay)); - } - else - { - overlay = null; - } - } - - return overlay; -}; - -/** - * Function: removeCellOverlays - * - * Removes all <mxCellOverlays> from the given cell. This method - * fires a <removeoverlay> event for each <mxCellOverlay> and returns - * the array of <mxCellOverlays> that was removed from the cell. - * - * Parameters: - * - * cell - <mxCell> whose overlays should be removed - */ -mxGraph.prototype.removeCellOverlays = function(cell) -{ - var overlays = cell.overlays; - - if (overlays != null) - { - cell.overlays = null; - - // Immediately updates the cell display if the state exists - var state = this.view.getState(cell); - - if (state != null) - { - this.cellRenderer.redraw(state); - } - - for (var i = 0; i < overlays.length; i++) - { - this.fireEvent(new mxEventObject(mxEvent.REMOVE_OVERLAY, - 'cell', cell, 'overlay', overlays[i])); - } - } - - return overlays; -}; - -/** - * Function: clearCellOverlays - * - * Removes all <mxCellOverlays> in the graph for the given cell and all its - * descendants. If no cell is specified then all overlays are removed from - * the graph. This implementation uses <removeCellOverlays> to remove the - * overlays from the individual cells. - * - * Parameters: - * - * cell - Optional <mxCell> that represents the root of the subtree to - * remove the overlays from. Default is the root in the model. - */ -mxGraph.prototype.clearCellOverlays = function(cell) -{ - cell = (cell != null) ? cell : this.model.getRoot(); - this.removeCellOverlays(cell); - - // Recursively removes all overlays from the children - var childCount = this.model.getChildCount(cell); - - for (var i = 0; i < childCount; i++) - { - var child = this.model.getChildAt(cell, i); - this.clearCellOverlays(child); // recurse - } -}; - -/** - * Function: setCellWarning - * - * Creates an overlay for the given cell using the warning and image or - * <warningImage> and returns the new <mxCellOverlay>. The warning is - * displayed as a tooltip in a red font and may contain HTML markup. If - * the warning is null or a zero length string, then all overlays are - * removed from the cell. - * - * Example: - * - * (code) - * graph.setCellWarning(cell, '<b>Warning:</b>: Hello, World!'); - * (end) - * - * Parameters: - * - * cell - <mxCell> whose warning should be set. - * warning - String that represents the warning to be displayed. - * img - Optional <mxImage> to be used for the overlay. Default is - * <warningImage>. - * isSelect - Optional boolean indicating if a click on the overlay - * should select the corresponding cell. Default is false. - */ -mxGraph.prototype.setCellWarning = function(cell, warning, img, isSelect) -{ - if (warning != null && warning.length > 0) - { - img = (img != null) ? img : this.warningImage; - - // Creates the overlay with the image and warning - var overlay = new mxCellOverlay(img, - '<font color=red>'+warning+'</font>'); - - // Adds a handler for single mouseclicks to select the cell - if (isSelect) - { - overlay.addListener(mxEvent.CLICK, - mxUtils.bind(this, function(sender, evt) - { - if (this.isEnabled()) - { - this.setSelectionCell(cell); - } - }) - ); - } - - // Sets and returns the overlay in the graph - return this.addCellOverlay(cell, overlay); - } - else - { - this.removeCellOverlays(cell); - } - - return null; -}; - -/** - * Group: In-place editing - */ - -/** - * Function: startEditing - * - * Calls <startEditingAtCell> using the given cell or the first selection - * cell. - * - * Parameters: - * - * evt - Optional mouse event that triggered the editing. - */ -mxGraph.prototype.startEditing = function(evt) -{ - this.startEditingAtCell(null, evt); -}; - -/** - * Function: startEditingAtCell - * - * Fires a <startEditing> event and invokes <mxCellEditor.startEditing> - * on <editor>. - * - * Parameters: - * - * cell - <mxCell> to start the in-place editor for. - * evt - Optional mouse event that triggered the editing. - */ -mxGraph.prototype.startEditingAtCell = function(cell, evt) -{ - if (cell == null) - { - cell = this.getSelectionCell(); - - if (cell != null && !this.isCellEditable(cell)) - { - cell = null; - } - } - - if (cell != null) - { - this.fireEvent(new mxEventObject(mxEvent.START_EDITING, - 'cell', cell, 'event', evt)); - this.cellEditor.startEditing(cell, evt); - } -}; - -/** - * Function: getEditingValue - * - * Returns the initial value for in-place editing. This implementation - * returns <convertValueToString> for the given cell. If this function is - * overridden, then <mxGraphModel.valueForCellChanged> should take care - * of correctly storing the actual new value inside the user object. - * - * Parameters: - * - * cell - <mxCell> for which the initial editing value should be returned. - * evt - Optional mouse event that triggered the editor. - */ -mxGraph.prototype.getEditingValue = function(cell, evt) -{ - return this.convertValueToString(cell); -}; - -/** - * Function: stopEditing - * - * Stops the current editing. - * - * Parameters: - * - * cancel - Boolean that specifies if the current editing value - * should be stored. - */ -mxGraph.prototype.stopEditing = function(cancel) -{ - this.cellEditor.stopEditing(cancel); -}; - -/** - * Function: labelChanged - * - * Sets the label of the specified cell to the given value using - * <cellLabelChanged> and fires <mxEvent.LABEL_CHANGED> while the - * transaction is in progress. Returns the cell whose label was changed. - * - * Parameters: - * - * cell - <mxCell> whose label should be changed. - * value - New label to be assigned. - * evt - Optional event that triggered the change. - */ -mxGraph.prototype.labelChanged = function(cell, value, evt) -{ - this.model.beginUpdate(); - try - { - this.cellLabelChanged(cell, value, this.isAutoSizeCell(cell)); - this.fireEvent(new mxEventObject(mxEvent.LABEL_CHANGED, - 'cell', cell, 'value', value, 'event', evt)); - } - finally - { - this.model.endUpdate(); - } - - return cell; -}; - -/** - * Function: cellLabelChanged - * - * Sets the new label for a cell. If autoSize is true then - * <cellSizeUpdated> will be called. - * - * In the following example, the function is extended to map changes to - * attributes in an XML node, as shown in <convertValueToString>. - * Alternatively, the handling of this can be implemented as shown in - * <mxGraphModel.valueForCellChanged> without the need to clone the - * user object. - * - * (code) - * var graphCellLabelChanged = graph.cellLabelChanged; - * graph.cellLabelChanged = function(cell, newValue, autoSize) - * { - * // Cloned for correct undo/redo - * var elt = cell.value.cloneNode(true); - * elt.setAttribute('label', newValue); - * - * newValue = elt; - * graphCellLabelChanged.apply(this, arguments); - * }; - * (end) - * - * Parameters: - * - * cell - <mxCell> whose label should be changed. - * value - New label to be assigned. - * autoSize - Boolean that specifies if <cellSizeUpdated> should be called. - */ -mxGraph.prototype.cellLabelChanged = function(cell, value, autoSize) -{ - this.model.beginUpdate(); - try - { - this.model.setValue(cell, value); - - if (autoSize) - { - this.cellSizeUpdated(cell, false); - } - } - finally - { - this.model.endUpdate(); - } -}; - -/** - * Group: Event processing - */ - -/** - * Function: escape - * - * Processes an escape keystroke. - * - * Parameters: - * - * evt - Mouseevent that represents the keystroke. - */ -mxGraph.prototype.escape = function(evt) -{ - this.stopEditing(true); - this.connectionHandler.reset(); - this.graphHandler.reset(); - - // Cancels all cell-based editing - var cells = this.getSelectionCells(); - - for (var i = 0; i < cells.length; i++) - { - var state = this.view.getState(cells[i]); - - if (state != null && state.handler != null) - { - state.handler.reset(); - } - } -}; - -/** - * Function: click - * - * Processes a singleclick on an optional cell and fires a <click> event. - * The click event is fired initially. If the graph is enabled and the - * event has not been consumed, then the cell is selected using - * <selectCellForEvent> or the selection is cleared using - * <clearSelection>. The events consumed state is set to true if the - * corresponding <mxMouseEvent> has been consumed. - * - * Parameters: - * - * me - <mxMouseEvent> that represents the single click. - */ -mxGraph.prototype.click = function(me) -{ - var evt = me.getEvent(); - var cell = me.getCell(); - var mxe = new mxEventObject(mxEvent.CLICK, 'event', evt, 'cell', cell); - - if (me.isConsumed()) - { - mxe.consume(); - } - - this.fireEvent(mxe); - - // Handles the event if it has not been consumed - if (this.isEnabled() && !mxEvent.isConsumed(evt) && !mxe.isConsumed()) - { - if (cell != null) - { - this.selectCellForEvent(cell, evt); - } - else - { - var swimlane = null; - - if (this.isSwimlaneSelectionEnabled()) - { - // Gets the swimlane at the location (includes - // content area of swimlanes) - swimlane = this.getSwimlaneAt(me.getGraphX(), me.getGraphY()); - } - - // Selects the swimlane and consumes the event - if (swimlane != null) - { - this.selectCellForEvent(swimlane, evt); - } - - // Ignores the event if the control key is pressed - else if (!this.isToggleEvent(evt)) - { - this.clearSelection(); - } - } - } -}; - -/** - * Function: dblClick - * - * Processes a doubleclick on an optional cell and fires a <dblclick> - * event. The event is fired initially. If the graph is enabled and the - * event has not been consumed, then <edit> is called with the given - * cell. The event is ignored if no cell was specified. - * - * Example for overriding this method. - * - * (code) - * graph.dblClick = function(evt, cell) - * { - * var mxe = new mxEventObject(mxEvent.DOUBLE_CLICK, 'event', evt, 'cell', cell); - * this.fireEvent(mxe); - * - * if (this.isEnabled() && !mxEvent.isConsumed(evt) && !mxe.isConsumed()) - * { - * mxUtils.alert('Hello, World!'); - * mxe.consume(); - * } - * } - * (end) - * - * Example listener for this event. - * - * (code) - * graph.addListener(mxEvent.DOUBLE_CLICK, function(sender, evt) - * { - * var cell = evt.getProperty('cell'); - * // do something with the cell... - * }); - * (end) - * - * Parameters: - * - * evt - Mouseevent that represents the doubleclick. - * cell - Optional <mxCell> under the mousepointer. - */ -mxGraph.prototype.dblClick = function(evt, cell) -{ - var mxe = new mxEventObject(mxEvent.DOUBLE_CLICK, 'event', evt, 'cell', cell); - this.fireEvent(mxe); - - // Handles the event if it has not been consumed - if (this.isEnabled() && !mxEvent.isConsumed(evt) && !mxe.isConsumed() && - cell != null && this.isCellEditable(cell)) - { - this.startEditingAtCell(cell, evt); - } -}; - -/** - * Function: scrollPointToVisible - * - * Scrolls the graph to the given point, extending the graph container if - * specified. - */ -mxGraph.prototype.scrollPointToVisible = function(x, y, extend, border) -{ - if (!this.timerAutoScroll && (this.ignoreScrollbars || mxUtils.hasScrollbars(this.container))) - { - var c = this.container; - border = (border != null) ? border : 20; - - if (x >= c.scrollLeft && y >= c.scrollTop && x <= c.scrollLeft + c.clientWidth && - y <= c.scrollTop + c.clientHeight) - { - var dx = c.scrollLeft + c.clientWidth - x; - - if (dx < border) - { - var old = c.scrollLeft; - c.scrollLeft += border - dx; - - // Automatically extends the canvas size to the bottom, right - // if the event is outside of the canvas and the edge of the - // canvas has been reached. Notes: Needs fix for IE. - if (extend && old == c.scrollLeft) - { - if (this.dialect == mxConstants.DIALECT_SVG) - { - var root = this.view.getDrawPane().ownerSVGElement; - var width = this.container.scrollWidth + border - dx; - - // Updates the clipping region. This is an expensive - // operation that should not be executed too often. - root.setAttribute('width', width); - } - else - { - var width = Math.max(c.clientWidth, c.scrollWidth) + border - dx; - var canvas = this.view.getCanvas(); - canvas.style.width = width + 'px'; - } - - c.scrollLeft += border - dx; - } - } - else - { - dx = x - c.scrollLeft; - - if (dx < border) - { - c.scrollLeft -= border - dx; - } - } - - var dy = c.scrollTop + c.clientHeight - y; - - if (dy < border) - { - var old = c.scrollTop; - c.scrollTop += border - dy; - - if (old == c.scrollTop && extend) - { - if (this.dialect == mxConstants.DIALECT_SVG) - { - var root = this.view.getDrawPane().ownerSVGElement; - var height = this.container.scrollHeight + border - dy; - - // Updates the clipping region. This is an expensive - // operation that should not be executed too often. - root.setAttribute('height', height); - } - else - { - var height = Math.max(c.clientHeight, c.scrollHeight) + border - dy; - var canvas = this.view.getCanvas(); - canvas.style.height = height + 'px'; - } - - c.scrollTop += border - dy; - } - } - else - { - dy = y - c.scrollTop; - - if (dy < border) - { - c.scrollTop -= border - dy; - } - } - } - } - else if (this.allowAutoPanning && !this.panningHandler.active) - { - if (this.panningManager == null) - { - this.panningManager = this.createPanningManager(); - } - - this.panningManager.panTo(x + this.panDx, y + this.panDy); - } -}; - - -/** - * Function: createPanningManager - * - * Creates and returns an <mxPanningManager>. - */ -mxGraph.prototype.createPanningManager = function() -{ - return new mxPanningManager(this); -}; - -/** - * Function: getBorderSizes - * - * Returns the size of the border and padding on all four sides of the - * container. The left, top, right and bottom borders are stored in the x, y, - * width and height of the returned <mxRectangle>, respectively. - */ -mxGraph.prototype.getBorderSizes = function() -{ - // Helper function to handle string values for border widths (approx) - function parseBorder(value) - { - var result = 0; - - if (value == 'thin') - { - result = 2; - } - else if (value == 'medium') - { - result = 4; - } - else if (value == 'thick') - { - result = 6; - } - else - { - result = parseInt(value); - } - - if (isNaN(result)) - { - result = 0; - } - - return result; - } - - var style = mxUtils.getCurrentStyle(this.container); - var result = new mxRectangle(); - result.x = parseBorder(style.borderLeftWidth) + parseInt(style.paddingLeft || 0); - result.y = parseBorder(style.borderTopWidth) + parseInt(style.paddingTop || 0); - result.width = parseBorder(style.borderRightWidth) + parseInt(style.paddingRight || 0); - result.height = parseBorder(style.borderBottomWidth) + parseInt(style.paddingBottom || 0); - - return result; -}; - - -/** - * Function: getPreferredPageSize - * - * Returns the preferred size of the background page if <preferPageSize> is true. - */ -mxGraph.prototype.getPreferredPageSize = function(bounds, width, height) -{ - var scale = this.view.scale; - var tr = this.view.translate; - var fmt = this.pageFormat; - var ps = scale * this.pageScale; - var page = new mxRectangle(0, 0, fmt.width * ps, fmt.height * ps); - - var hCount = (this.pageBreaksVisible) ? Math.ceil(width / page.width) : 1; - var vCount = (this.pageBreaksVisible) ? Math.ceil(height / page.height) : 1; - - return new mxRectangle(0, 0, hCount * page.width + 2 + tr.x / scale, vCount * page.height + 2 + tr.y / scale); -}; - -/** - * Function: sizeDidChange - * - * Called when the size of the graph has changed. This implementation fires - * a <size> event after updating the clipping region of the SVG element in - * SVG-bases browsers. - */ -mxGraph.prototype.sizeDidChange = function() -{ - var bounds = this.getGraphBounds(); - - if (this.container != null) - { - var border = this.getBorder(); - - var width = Math.max(0, bounds.x + bounds.width + 1 + border); - var height = Math.max(0, bounds.y + bounds.height + 1 + border); - - if (this.minimumContainerSize != null) - { - width = Math.max(width, this.minimumContainerSize.width); - height = Math.max(height, this.minimumContainerSize.height); - } - - if (this.resizeContainer) - { - this.doResizeContainer(width, height); - } - - if (this.preferPageSize || (!mxClient.IS_IE && this.pageVisible)) - { - var size = this.getPreferredPageSize(bounds, width, height); - - if (size != null) - { - width = size.width; - height = size.height; - } - } - - if (this.minimumGraphSize != null) - { - width = Math.max(width, this.minimumGraphSize.width * this.view.scale); - height = Math.max(height, this.minimumGraphSize.height * this.view.scale); - } - - width = Math.ceil(width - 1); - height = Math.ceil(height - 1); - - if (this.dialect == mxConstants.DIALECT_SVG) - { - var root = this.view.getDrawPane().ownerSVGElement; - - root.style.minWidth = Math.max(1, width) + 'px'; - root.style.minHeight = Math.max(1, height) + 'px'; - } - else - { - if (mxClient.IS_QUIRKS) - { - // Quirks mode has no minWidth/minHeight support - this.view.updateHtmlCanvasSize(Math.max(1, width), Math.max(1, height)); - } - else - { - this.view.canvas.style.minWidth = Math.max(1, width) + 'px'; - this.view.canvas.style.minHeight = Math.max(1, height) + 'px'; - } - } - - this.updatePageBreaks(this.pageBreaksVisible, width - 1, height - 1); - } - - this.fireEvent(new mxEventObject(mxEvent.SIZE, 'bounds', bounds)); -}; - -/** - * Function: doResizeContainer - * - * Resizes the container for the given graph width and height. - */ -mxGraph.prototype.doResizeContainer = function(width, height) -{ - // Fixes container size for different box models - if (mxClient.IS_IE) - { - if (mxClient.IS_QUIRKS) - { - var borders = this.getBorderSizes(); - - // max(2, ...) required for native IE8 in quirks mode - width += Math.max(2, borders.x + borders.width + 1); - height += Math.max(2, borders.y + borders.height + 1); - } - else if (document.documentMode >= 9) - { - width += 3; - height += 5; - } - else - { - width += 1; - height += 1; - } - } - else - { - height += 1; - } - - if (this.maximumContainerSize != null) - { - width = Math.min(this.maximumContainerSize.width, width); - height = Math.min(this.maximumContainerSize.height, height); - } - - this.container.style.width = Math.ceil(width) + 'px'; - this.container.style.height = Math.ceil(height) + 'px'; -}; - -/** - * Function: redrawPageBreaks - * - * Invokes from <sizeDidChange> to redraw the page breaks. - * - * Parameters: - * - * visible - Boolean that specifies if page breaks should be shown. - * width - Specifies the width of the container in pixels. - * height - Specifies the height of the container in pixels. - */ -mxGraph.prototype.updatePageBreaks = function(visible, width, height) -{ - var scale = this.view.scale; - var tr = this.view.translate; - var fmt = this.pageFormat; - var ps = scale * this.pageScale; - var bounds = new mxRectangle(scale * tr.x, scale * tr.y, - fmt.width * ps, fmt.height * ps); - - // Does not show page breaks if the scale is too small - visible = visible && Math.min(bounds.width, bounds.height) > this.minPageBreakDist; - - // Draws page breaks independent of translate. To ignore - // the translate set bounds.x/y = 0. Note that modulo - // in JavaScript has a bug, so use mxUtils instead. - bounds.x = mxUtils.mod(bounds.x, bounds.width); - bounds.y = mxUtils.mod(bounds.y, bounds.height); - - var horizontalCount = (visible) ? Math.ceil((width - bounds.x) / bounds.width) : 0; - var verticalCount = (visible) ? Math.ceil((height - bounds.y) / bounds.height) : 0; - var right = width; - var bottom = height; - - if (this.horizontalPageBreaks == null && horizontalCount > 0) - { - this.horizontalPageBreaks = []; - } - - if (this.horizontalPageBreaks != null) - { - for (var i = 0; i <= horizontalCount; i++) - { - var pts = [new mxPoint(bounds.x + i * bounds.width, 1), - new mxPoint(bounds.x + i * bounds.width, bottom)]; - - if (this.horizontalPageBreaks[i] != null) - { - this.horizontalPageBreaks[i].scale = 1; - this.horizontalPageBreaks[i].points = pts; - this.horizontalPageBreaks[i].redraw(); - } - else - { - var pageBreak = new mxPolyline(pts, this.pageBreakColor, this.scale); - pageBreak.dialect = this.dialect; - pageBreak.isDashed = this.pageBreakDashed; - pageBreak.scale = scale; - pageBreak.crisp = true; - pageBreak.init(this.view.backgroundPane); - pageBreak.redraw(); - - this.horizontalPageBreaks[i] = pageBreak; - } - } - - for (var i = horizontalCount; i < this.horizontalPageBreaks.length; i++) - { - this.horizontalPageBreaks[i].destroy(); - } - - this.horizontalPageBreaks.splice(horizontalCount, this.horizontalPageBreaks.length - horizontalCount); - } - - if (this.verticalPageBreaks == null && verticalCount > 0) - { - this.verticalPageBreaks = []; - } - - if (this.verticalPageBreaks != null) - { - for (var i = 0; i <= verticalCount; i++) - { - var pts = [new mxPoint(1, bounds.y + i * bounds.height), - new mxPoint(right, bounds.y + i * bounds.height)]; - - if (this.verticalPageBreaks[i] != null) - { - this.verticalPageBreaks[i].scale = 1; - this.verticalPageBreaks[i].points = pts; - this.verticalPageBreaks[i].redraw(); - } - else - { - var pageBreak = new mxPolyline(pts, this.pageBreakColor, scale); - pageBreak.dialect = this.dialect; - pageBreak.isDashed = this.pageBreakDashed; - pageBreak.scale = scale; - pageBreak.crisp = true; - pageBreak.init(this.view.backgroundPane); - pageBreak.redraw(); - - this.verticalPageBreaks[i] = pageBreak; - } - } - - for (var i = verticalCount; i < this.verticalPageBreaks.length; i++) - { - this.verticalPageBreaks[i].destroy(); - } - - this.verticalPageBreaks.splice(verticalCount, this.verticalPageBreaks.length - verticalCount); - } -}; - -/** - * Group: Cell styles - */ - -/** - * Function: getCellStyle - * - * Returns an array of key, value pairs representing the cell style for the - * given cell. If no string is defined in the model that specifies the - * style, then the default style for the cell is returned or <EMPTY_ARRAY>, - * if not style can be found. Note: You should try and get the cell state - * for the given cell and use the cached style in the state before using - * this method. - * - * Parameters: - * - * cell - <mxCell> whose style should be returned as an array. - */ -mxGraph.prototype.getCellStyle = function(cell) -{ - var stylename = this.model.getStyle(cell); - var style = null; - - // Gets the default style for the cell - if (this.model.isEdge(cell)) - { - style = this.stylesheet.getDefaultEdgeStyle(); - } - else - { - style = this.stylesheet.getDefaultVertexStyle(); - } - - // Resolves the stylename using the above as the default - if (stylename != null) - { - style = this.postProcessCellStyle(this.stylesheet.getCellStyle(stylename, style)); - } - - // Returns a non-null value if no style can be found - if (style == null) - { - style = mxGraph.prototype.EMPTY_ARRAY; - } - - return style; -}; - -/** - * Function: postProcessCellStyle - * - * Tries to resolve the value for the image style in the image bundles and - * turns short data URIs as defined in mxImageBundle to data URIs as - * defined in RFC 2397 of the IETF. - */ -mxGraph.prototype.postProcessCellStyle = function(style) -{ - if (style != null) - { - var key = style[mxConstants.STYLE_IMAGE]; - var image = this.getImageFromBundles(key); - - if (image != null) - { - style[mxConstants.STYLE_IMAGE] = image; - } - else - { - image = key; - } - - // Converts short data uris to normal data uris - if (image != null && image.substring(0, 11) == "data:image/") - { - var comma = image.indexOf(','); - - if (comma > 0) - { - image = image.substring(0, comma) + ";base64," - + image.substring(comma + 1); - } - - style[mxConstants.STYLE_IMAGE] = image; - } - } - - return style; -}; - -/** - * Function: setCellStyle - * - * Sets the style of the specified cells. If no cells are given, then the - * selection cells are changed. - * - * Parameters: - * - * style - String representing the new style of the cells. - * cells - Optional array of <mxCells> to set the style for. Default is the - * selection cells. - */ -mxGraph.prototype.setCellStyle = function(style, cells) -{ - cells = cells || this.getSelectionCells(); - - if (cells != null) - { - this.model.beginUpdate(); - try - { - for (var i = 0; i < cells.length; i++) - { - this.model.setStyle(cells[i], style); - } - } - finally - { - this.model.endUpdate(); - } - } -}; - -/** - * Function: toggleCellStyle - * - * Toggles the boolean value for the given key in the style of the - * given cell. If no cell is specified then the selection cell is - * used. - * - * Parameter: - * - * key - String representing the key for the boolean value to be toggled. - * defaultValue - Optional boolean default value if no value is defined. - * Default is false. - * cell - Optional <mxCell> whose style should be modified. Default is - * the selection cell. - */ -mxGraph.prototype.toggleCellStyle = function(key, defaultValue, cell) -{ - cell = cell || this.getSelectionCell(); - - this.toggleCellStyles(key, defaultValue, [cell]); -}; - -/** - * Function: toggleCellStyles - * - * Toggles the boolean value for the given key in the style of the given - * cells. If no cells are specified, then the selection cells are used. For - * example, this can be used to toggle <mxConstants.STYLE_ROUNDED> or any - * other style with a boolean value. - * - * Parameter: - * - * key - String representing the key for the boolean value to be toggled. - * defaultValue - Optional boolean default value if no value is defined. - * Default is false. - * cells - Optional array of <mxCells> whose styles should be modified. - * Default is the selection cells. - */ -mxGraph.prototype.toggleCellStyles = function(key, defaultValue, cells) -{ - defaultValue = (defaultValue != null) ? defaultValue : false; - cells = cells || this.getSelectionCells(); - - if (cells != null && cells.length > 0) - { - var state = this.view.getState(cells[0]); - var style = (state != null) ? state.style : this.getCellStyle(cells[0]); - - if (style != null) - { - var val = (mxUtils.getValue(style, key, defaultValue)) ? 0 : 1; - this.setCellStyles(key, val, cells); - } - } -}; - -/** - * Function: setCellStyles - * - * Sets the key to value in the styles of the given cells. This will modify - * the existing cell styles in-place and override any existing assignment - * for the given key. If no cells are specified, then the selection cells - * are changed. If no value is specified, then the respective key is - * removed from the styles. - * - * Parameters: - * - * key - String representing the key to be assigned. - * value - String representing the new value for the key. - * cells - Optional array of <mxCells> to change the style for. Default is - * the selection cells. - */ -mxGraph.prototype.setCellStyles = function(key, value, cells) -{ - cells = cells || this.getSelectionCells(); - mxUtils.setCellStyles(this.model, cells, key, value); -}; - -/** - * Function: toggleCellStyleFlags - * - * Toggles the given bit for the given key in the styles of the specified - * cells. - * - * Parameters: - * - * key - String representing the key to toggle the flag in. - * flag - Integer that represents the bit to be toggled. - * cells - Optional array of <mxCells> to change the style for. Default is - * the selection cells. - */ -mxGraph.prototype.toggleCellStyleFlags = function(key, flag, cells) -{ - this.setCellStyleFlags(key, flag, null, cells); -}; - -/** - * Function: setCellStyleFlags - * - * Sets or toggles the given bit for the given key in the styles of the - * specified cells. - * - * Parameters: - * - * key - String representing the key to toggle the flag in. - * flag - Integer that represents the bit to be toggled. - * value - Boolean value to be used or null if the value should be toggled. - * cells - Optional array of <mxCells> to change the style for. Default is - * the selection cells. - */ -mxGraph.prototype.setCellStyleFlags = function(key, flag, value, cells) -{ - cells = cells || this.getSelectionCells(); - - if (cells != null && cells.length > 0) - { - if (value == null) - { - var state = this.view.getState(cells[0]); - var style = (state != null) ? state.style : this.getCellStyle(cells[0]); - - if (style != null) - { - var current = parseInt(style[key] || 0); - value = !((current & flag) == flag); - } - } - - mxUtils.setCellStyleFlags(this.model, cells, key, flag, value); - } -}; - -/** - * Group: Cell alignment and orientation - */ - -/** - * Function: alignCells - * - * Aligns the given cells vertically or horizontally according to the given - * alignment using the optional parameter as the coordinate. - * - * Parameters: - * - * align - Specifies the alignment. Possible values are all constants in - * mxConstants with an ALIGN prefix. - * cells - Array of <mxCells> to be aligned. - * param - Optional coordinate for the alignment. - */ -mxGraph.prototype.alignCells = function(align, cells, param) -{ - if (cells == null) - { - cells = this.getSelectionCells(); - } - - if (cells != null && cells.length > 1) - { - // Finds the required coordinate for the alignment - if (param == null) - { - for (var i = 0; i < cells.length; i++) - { - var geo = this.getCellGeometry(cells[i]); - - if (geo != null && !this.model.isEdge(cells[i])) - { - if (param == null) - { - if (align == mxConstants.ALIGN_CENTER) - { - param = geo.x + geo.width / 2; - break; - } - else if (align == mxConstants.ALIGN_RIGHT) - { - param = geo.x + geo.width; - } - else if (align == mxConstants.ALIGN_TOP) - { - param = geo.y; - } - else if (align == mxConstants.ALIGN_MIDDLE) - { - param = geo.y + geo.height / 2; - break; - } - else if (align == mxConstants.ALIGN_BOTTOM) - { - param = geo.y + geo.height; - } - else - { - param = geo.x; - } - } - else - { - if (align == mxConstants.ALIGN_RIGHT) - { - param = Math.max(param, geo.x + geo.width); - } - else if (align == mxConstants.ALIGN_TOP) - { - param = Math.min(param, geo.y); - } - else if (align == mxConstants.ALIGN_BOTTOM) - { - param = Math.max(param, geo.y + geo.height); - } - else - { - param = Math.min(param, geo.x); - } - } - } - } - } - - // Aligns the cells to the coordinate - if (param != null) - { - this.model.beginUpdate(); - try - { - for (var i = 0; i < cells.length; i++) - { - var geo = this.getCellGeometry(cells[i]); - - if (geo != null && !this.model.isEdge(cells[i])) - { - geo = geo.clone(); - - if (align == mxConstants.ALIGN_CENTER) - { - geo.x = param - geo.width / 2; - } - else if (align == mxConstants.ALIGN_RIGHT) - { - geo.x = param - geo.width; - } - else if (align == mxConstants.ALIGN_TOP) - { - geo.y = param; - } - else if (align == mxConstants.ALIGN_MIDDLE) - { - geo.y = param - geo.height / 2; - } - else if (align == mxConstants.ALIGN_BOTTOM) - { - geo.y = param - geo.height; - } - else - { - geo.x = param; - } - - this.model.setGeometry(cells[i], geo); - } - } - - this.fireEvent(new mxEventObject(mxEvent.ALIGN_CELLS, - 'align', align, 'cells', cells)); - } - finally - { - this.model.endUpdate(); - } - } - } - - return cells; -}; - -/** - * Function: flipEdge - * - * Toggles the style of the given edge between null (or empty) and - * <alternateEdgeStyle>. This method fires <mxEvent.FLIP_EDGE> while the - * transaction is in progress. Returns the edge that was flipped. - * - * Here is an example that overrides this implementation to invert the - * value of <mxConstants.STYLE_ELBOW> without removing any existing styles. - * - * (code) - * graph.flipEdge = function(edge) - * { - * if (edge != null) - * { - * var state = this.view.getState(edge); - * var style = (state != null) ? state.style : this.getCellStyle(edge); - * - * if (style != null) - * { - * var elbow = mxUtils.getValue(style, mxConstants.STYLE_ELBOW, - * mxConstants.ELBOW_HORIZONTAL); - * var value = (elbow == mxConstants.ELBOW_HORIZONTAL) ? - * mxConstants.ELBOW_VERTICAL : mxConstants.ELBOW_HORIZONTAL; - * this.setCellStyles(mxConstants.STYLE_ELBOW, value, [edge]); - * } - * } - * }; - * (end) - * - * Parameters: - * - * edge - <mxCell> whose style should be changed. - */ -mxGraph.prototype.flipEdge = function(edge) -{ - if (edge != null && - this.alternateEdgeStyle != null) - { - this.model.beginUpdate(); - try - { - var style = this.model.getStyle(edge); - - if (style == null || style.length == 0) - { - this.model.setStyle(edge, this.alternateEdgeStyle); - } - else - { - this.model.setStyle(edge, null); - } - - // Removes all existing control points - this.resetEdge(edge); - this.fireEvent(new mxEventObject(mxEvent.FLIP_EDGE, 'edge', edge)); - } - finally - { - this.model.endUpdate(); - } - } - - return edge; -}; - -/** - * Function: addImageBundle - * - * Adds the specified <mxImageBundle>. - */ -mxGraph.prototype.addImageBundle = function(bundle) -{ - this.imageBundles.push(bundle); -}; - -/** - * Function: removeImageBundle - * - * Removes the specified <mxImageBundle>. - */ -mxGraph.prototype.removeImageBundle = function(bundle) -{ - var tmp = []; - - for (var i = 0; i < this.imageBundles.length; i++) - { - if (this.imageBundles[i] != bundle) - { - tmp.push(this.imageBundles[i]); - } - } - - this.imageBundles = tmp; -}; - -/** - * Function: getImageFromBundles - * - * Searches all <imageBundles> for the specified key and returns the value - * for the first match or null if the key is not found. - */ -mxGraph.prototype.getImageFromBundles = function(key) -{ - if (key != null) - { - for (var i = 0; i < this.imageBundles.length; i++) - { - var image = this.imageBundles[i].getImage(key); - - if (image != null) - { - return image; - } - } - } - - return null; -}; - -/** - * Group: Order - */ - -/** - * Function: orderCells - * - * Moves the given cells to the front or back. The change is carried out - * using <cellsOrdered>. This method fires <mxEvent.ORDER_CELLS> while the - * transaction is in progress. - * - * Parameters: - * - * back - Boolean that specifies if the cells should be moved to back. - * cells - Array of <mxCells> to move to the background. If null is - * specified then the selection cells are used. - */ - mxGraph.prototype.orderCells = function(back, cells) - { - if (cells == null) - { - cells = mxUtils.sortCells(this.getSelectionCells(), true); - } - - this.model.beginUpdate(); - try - { - this.cellsOrdered(cells, back); - this.fireEvent(new mxEventObject(mxEvent.ORDER_CELLS, - 'back', back, 'cells', cells)); - } - finally - { - this.model.endUpdate(); - } - - return cells; - }; - -/** - * Function: cellsOrdered - * - * Moves the given cells to the front or back. This method fires - * <mxEvent.CELLS_ORDERED> while the transaction is in progress. - * - * Parameters: - * - * cells - Array of <mxCells> whose order should be changed. - * back - Boolean that specifies if the cells should be moved to back. - */ - mxGraph.prototype.cellsOrdered = function(cells, back) - { - if (cells != null) - { - this.model.beginUpdate(); - try - { - for (var i = 0; i < cells.length; i++) - { - var parent = this.model.getParent(cells[i]); - - if (back) - { - this.model.add(parent, cells[i], i); - } - else - { - this.model.add(parent, cells[i], - this.model.getChildCount(parent) - 1); - } - } - - this.fireEvent(new mxEventObject(mxEvent.CELLS_ORDERED, - 'back', back, 'cells', cells)); - } - finally - { - this.model.endUpdate(); - } - } -}; - -/** - * Group: Grouping - */ - -/** - * Function: groupCells - * - * Adds the cells into the given group. The change is carried out using - * <cellsAdded>, <cellsMoved> and <cellsResized>. This method fires - * <mxEvent.GROUP_CELLS> while the transaction is in progress. Returns the - * new group. A group is only created if there is at least one entry in the - * given array of cells. - * - * Parameters: - * - * group - <mxCell> that represents the target group. If null is specified - * then a new group is created using <createGroupCell>. - * border - Optional integer that specifies the border between the child - * area and the group bounds. Default is 0. - * cells - Optional array of <mxCells> to be grouped. If null is specified - * then the selection cells are used. - */ -mxGraph.prototype.groupCells = function(group, border, cells) -{ - if (cells == null) - { - cells = mxUtils.sortCells(this.getSelectionCells(), true); - } - - cells = this.getCellsForGroup(cells); - - if (group == null) - { - group = this.createGroupCell(cells); - } - - var bounds = this.getBoundsForGroup(group, cells, border); - - if (cells.length > 0 && bounds != null) - { - // Uses parent of group or previous parent of first child - var parent = this.model.getParent(group); - - if (parent == null) - { - parent = this.model.getParent(cells[0]); - } - - this.model.beginUpdate(); - try - { - // Checks if the group has a geometry and - // creates one if one does not exist - if (this.getCellGeometry(group) == null) - { - this.model.setGeometry(group, new mxGeometry()); - } - - // Adds the children into the group and moves - var index = this.model.getChildCount(group); - this.cellsAdded(cells, group, index, null, null, false, false); - this.cellsMoved(cells, -bounds.x, -bounds.y, false, true); - - // Adds the group into the parent and resizes - index = this.model.getChildCount(parent); - this.cellsAdded([group], parent, index, null, null, false); - this.cellsResized([group], [bounds]); - - this.fireEvent(new mxEventObject(mxEvent.GROUP_CELLS, - 'group', group, 'border', border, 'cells', cells)); - } - finally - { - this.model.endUpdate(); - } - } - - return group; -}; - -/** - * Function: getCellsForGroup - * - * Returns the cells with the same parent as the first cell - * in the given array. - */ -mxGraph.prototype.getCellsForGroup = function(cells) -{ - var result = []; - - if (cells != null && cells.length > 0) - { - var parent = this.model.getParent(cells[0]); - result.push(cells[0]); - - // Filters selection cells with the same parent - for (var i = 1; i < cells.length; i++) - { - if (this.model.getParent(cells[i]) == parent) - { - result.push(cells[i]); - } - } - } - - return result; -}; - -/** - * Function: getBoundsForGroup - * - * Returns the bounds to be used for the given group and children. - */ -mxGraph.prototype.getBoundsForGroup = function(group, children, border) -{ - var result = this.getBoundingBoxFromGeometry(children); - - if (result != null) - { - if (this.isSwimlane(group)) - { - var size = this.getStartSize(group); - - result.x -= size.width; - result.y -= size.height; - result.width += size.width; - result.height += size.height; - } - - // Adds the border - result.x -= border; - result.y -= border; - result.width += 2 * border; - result.height += 2 * border; - } - - return result; -}; - -/** - * Function: createGroupCell - * - * Hook for creating the group cell to hold the given array of <mxCells> if - * no group cell was given to the <group> function. - * - * The following code can be used to set the style of new group cells. - * - * (code) - * var graphCreateGroupCell = graph.createGroupCell; - * graph.createGroupCell = function(cells) - * { - * var group = graphCreateGroupCell.apply(this, arguments); - * group.setStyle('group'); - * - * return group; - * }; - */ -mxGraph.prototype.createGroupCell = function(cells) -{ - var group = new mxCell(''); - group.setVertex(true); - group.setConnectable(false); - - return group; -}; - -/** - * Function: ungroupCells - * - * Ungroups the given cells by moving the children the children to their - * parents parent and removing the empty groups. Returns the children that - * have been removed from the groups. - * - * Parameters: - * - * cells - Array of cells to be ungrouped. If null is specified then the - * selection cells are used. - */ -mxGraph.prototype.ungroupCells = function(cells) -{ - var result = []; - - if (cells == null) - { - cells = this.getSelectionCells(); - - // Finds the cells with children - var tmp = []; - - for (var i = 0; i < cells.length; i++) - { - if (this.model.getChildCount(cells[i]) > 0) - { - tmp.push(cells[i]); - } - } - - cells = tmp; - } - - if (cells != null && cells.length > 0) - { - this.model.beginUpdate(); - try - { - for (var i = 0; i < cells.length; i++) - { - var children = this.model.getChildren(cells[i]); - - if (children != null && children.length > 0) - { - children = children.slice(); - var parent = this.model.getParent(cells[i]); - var index = this.model.getChildCount(parent); - - this.cellsAdded(children, parent, index, null, null, true); - result = result.concat(children); - } - } - - this.cellsRemoved(this.addAllEdges(cells)); - this.fireEvent(new mxEventObject(mxEvent.UNGROUP_CELLS, - 'cells', cells)); - } - finally - { - this.model.endUpdate(); - } - } - - return result; -}; - -/** - * Function: removeCellsFromParent - * - * Removes the specified cells from their parents and adds them to the - * default parent. Returns the cells that were removed from their parents. - * - * Parameters: - * - * cells - Array of <mxCells> to be removed from their parents. - */ -mxGraph.prototype.removeCellsFromParent = function(cells) -{ - if (cells == null) - { - cells = this.getSelectionCells(); - } - - this.model.beginUpdate(); - try - { - var parent = this.getDefaultParent(); - var index = this.model.getChildCount(parent); - - this.cellsAdded(cells, parent, index, null, null, true); - this.fireEvent(new mxEventObject(mxEvent.REMOVE_CELLS_FROM_PARENT, - 'cells', cells)); - } - finally - { - this.model.endUpdate(); - } - - return cells; -}; - -/** - * Function: updateGroupBounds - * - * Updates the bounds of the given array of groups so that it includes - * all child vertices. - * - * Parameters: - * - * cells - The groups whose bounds should be updated. - * border - Optional border to be added in the group. Default is 0. - * moveGroup - Optional boolean that allows the group to be moved. Default - * is false. - */ -mxGraph.prototype.updateGroupBounds = function(cells, border, moveGroup) -{ - if (cells == null) - { - cells = this.getSelectionCells(); - } - - border = (border != null) ? border : 0; - moveGroup = (moveGroup != null) ? moveGroup : false; - - this.model.beginUpdate(); - try - { - for (var i = 0; i < cells.length; i++) - { - var geo = this.getCellGeometry(cells[i]); - - if (geo != null) - { - var children = this.getChildCells(cells[i]); - - if (children != null && children.length > 0) - { - var childBounds = this.getBoundingBoxFromGeometry(children); - - if (childBounds.width > 0 && childBounds.height > 0) - { - var size = (this.isSwimlane(cells[i])) ? - this.getStartSize(cells[i]) : new mxRectangle(); - - geo = geo.clone(); - - if (moveGroup) - { - geo.x += childBounds.x - size.width - border; - geo.y += childBounds.y - size.height - border; - } - - geo.width = childBounds.width + size.width + 2 * border; - geo.height = childBounds.height + size.height + 2 * border; - - this.model.setGeometry(cells[i], geo); - this.moveCells(children, -childBounds.x + size.width + border, - -childBounds.y + size.height + border); - } - } - } - } - } - finally - { - this.model.endUpdate(); - } - - return cells; -}; - -/** - * Group: Cell cloning, insertion and removal - */ - -/** - * Function: cloneCells - * - * Returns the clones for the given cells. If the terminal of an edge is - * not in the given array, then the respective end is assigned a terminal - * point and the terminal is removed. - * - * Parameters: - * - * cells - Array of <mxCells> to be cloned. - * allowInvalidEdges - Optional boolean that specifies if invalid edges - * should be cloned. Default is true. - */ -mxGraph.prototype.cloneCells = function(cells, allowInvalidEdges) -{ - allowInvalidEdges = (allowInvalidEdges != null) ? allowInvalidEdges : true; - var clones = null; - - if (cells != null) - { - // Creates a hashtable for cell lookups - var hash = new Object(); - var tmp = []; - - for (var i = 0; i < cells.length; i++) - { - var id = mxCellPath.create(cells[i]); - hash[id] = cells[i]; - tmp.push(cells[i]); - } - - if (tmp.length > 0) - { - var scale = this.view.scale; - var trans = this.view.translate; - clones = this.model.cloneCells(cells, true); - - for (var i = 0; i < cells.length; i++) - { - if (!allowInvalidEdges && this.model.isEdge(clones[i]) && - this.getEdgeValidationError(clones[i], - this.model.getTerminal(clones[i], true), - this.model.getTerminal(clones[i], false)) != null) - { - clones[i] = null; - } - else - { - var g = this.model.getGeometry(clones[i]); - - if (g != null) - { - var state = this.view.getState(cells[i]); - var pstate = this.view.getState( - this.model.getParent(cells[i])); - - if (state != null && pstate != null) - { - var dx = pstate.origin.x; - var dy = pstate.origin.y; - - if (this.model.isEdge(clones[i])) - { - var pts = state.absolutePoints; - - // Checks if the source is cloned or sets the terminal point - var src = this.model.getTerminal(cells[i], true); - var srcId = mxCellPath.create(src); - - while (src != null && hash[srcId] == null) - { - src = this.model.getParent(src); - srcId = mxCellPath.create(src); - } - - if (src == null) - { - g.setTerminalPoint( - new mxPoint(pts[0].x / scale - trans.x, - pts[0].y / scale - trans.y), true); - } - - // Checks if the target is cloned or sets the terminal point - var trg = this.model.getTerminal(cells[i], false); - var trgId = mxCellPath.create(trg); - - while (trg != null && hash[trgId] == null) - { - trg = this.model.getParent(trg); - trgId = mxCellPath.create(trg); - } - - if (trg == null) - { - var n = pts.length - 1; - g.setTerminalPoint( - new mxPoint(pts[n].x / scale - trans.x, - pts[n].y / scale - trans.y), false); - } - - // Translates the control points - var points = g.points; - - if (points != null) - { - for (var j = 0; j < points.length; j++) - { - points[j].x += dx; - points[j].y += dy; - } - } - } - else - { - g.x += dx; - g.y += dy; - } - } - } - } - } - } - else - { - clones = []; - } - } - - return clones; -}; - -/** - * Function: insertVertex - * - * Adds a new vertex into the given parent <mxCell> using value as the user - * object and the given coordinates as the <mxGeometry> of the new vertex. - * The id and style are used for the respective properties of the new - * <mxCell>, which is returned. - * - * When adding new vertices from a mouse event, one should take into - * account the offset of the graph container and the scale and translation - * of the view in order to find the correct unscaled, untranslated - * coordinates using <mxGraph.getPointForEvent> as follows: - * - * (code) - * var pt = graph.getPointForEvent(evt); - * var parent = graph.getDefaultParent(); - * graph.insertVertex(parent, null, - * 'Hello, World!', x, y, 220, 30); - * (end) - * - * For adding image cells, the style parameter can be assigned as - * - * (code) - * stylename;image=imageUrl - * (end) - * - * See <mxGraph> for more information on using images. - * - * Parameters: - * - * parent - <mxCell> that specifies the parent of the new vertex. - * id - Optional string that defines the Id of the new vertex. - * value - Object to be used as the user object. - * x - Integer that defines the x coordinate of the vertex. - * y - Integer that defines the y coordinate of the vertex. - * width - Integer that defines the width of the vertex. - * height - Integer that defines the height of the vertex. - * style - Optional string that defines the cell style. - * relative - Optional boolean that specifies if the geometry is relative. - * Default is false. - */ -mxGraph.prototype.insertVertex = function(parent, id, value, - x, y, width, height, style, relative) -{ - var vertex = this.createVertex(parent, id, value, x, y, width, height, style, relative); - - return this.addCell(vertex, parent); -}; - -/** - * Function: createVertex - * - * Hook method that creates the new vertex for <insertVertex>. - */ -mxGraph.prototype.createVertex = function(parent, id, value, - x, y, width, height, style, relative) -{ - // Creates the geometry for the vertex - var geometry = new mxGeometry(x, y, width, height); - geometry.relative = (relative != null) ? relative : false; - - // Creates the vertex - var vertex = new mxCell(value, geometry, style); - vertex.setId(id); - vertex.setVertex(true); - vertex.setConnectable(true); - - return vertex; -}; - -/** - * Function: insertEdge - * - * Adds a new edge into the given parent <mxCell> using value as the user - * object and the given source and target as the terminals of the new edge. - * The id and style are used for the respective properties of the new - * <mxCell>, which is returned. - * - * Parameters: - * - * parent - <mxCell> that specifies the parent of the new edge. - * id - Optional string that defines the Id of the new edge. - * value - JavaScript object to be used as the user object. - * source - <mxCell> that defines the source of the edge. - * target - <mxCell> that defines the target of the edge. - * style - Optional string that defines the cell style. - */ -mxGraph.prototype.insertEdge = function(parent, id, value, source, target, style) -{ - var edge = this.createEdge(parent, id, value, source, target, style); - - return this.addEdge(edge, parent, source, target); -}; - -/** - * Function: createEdge - * - * Hook method that creates the new edge for <insertEdge>. This - * implementation does not set the source and target of the edge, these - * are set when the edge is added to the model. - * - */ -mxGraph.prototype.createEdge = function(parent, id, value, source, target, style) -{ - // Creates the edge - var edge = new mxCell(value, new mxGeometry(), style); - edge.setId(id); - edge.setEdge(true); - edge.geometry.relative = true; - - return edge; -}; - -/** - * Function: addEdge - * - * Adds the edge to the parent and connects it to the given source and - * target terminals. This is a shortcut method. Returns the edge that was - * added. - * - * Parameters: - * - * edge - <mxCell> to be inserted into the given parent. - * parent - <mxCell> that represents the new parent. If no parent is - * given then the default parent is used. - * source - Optional <mxCell> that represents the source terminal. - * target - Optional <mxCell> that represents the target terminal. - * index - Optional index to insert the cells at. Default is to append. - */ -mxGraph.prototype.addEdge = function(edge, parent, source, target, index) -{ - return this.addCell(edge, parent, index, source, target); -}; - -/** - * Function: addCell - * - * Adds the cell to the parent and connects it to the given source and - * target terminals. This is a shortcut method. Returns the cell that was - * added. - * - * Parameters: - * - * cell - <mxCell> to be inserted into the given parent. - * parent - <mxCell> that represents the new parent. If no parent is - * given then the default parent is used. - * index - Optional index to insert the cells at. Default is to append. - * source - Optional <mxCell> that represents the source terminal. - * target - Optional <mxCell> that represents the target terminal. - */ -mxGraph.prototype.addCell = function(cell, parent, index, source, target) -{ - return this.addCells([cell], parent, index, source, target)[0]; -}; - -/** - * Function: addCells - * - * Adds the cells to the parent at the given index, connecting each cell to - * the optional source and target terminal. The change is carried out using - * <cellsAdded>. This method fires <mxEvent.ADD_CELLS> while the - * transaction is in progress. Returns the cells that were added. - * - * Parameters: - * - * cells - Array of <mxCells> to be inserted. - * parent - <mxCell> that represents the new parent. If no parent is - * given then the default parent is used. - * index - Optional index to insert the cells at. Default is to append. - * source - Optional source <mxCell> for all inserted cells. - * target - Optional target <mxCell> for all inserted cells. - */ -mxGraph.prototype.addCells = function(cells, parent, index, source, target) -{ - if (parent == null) - { - parent = this.getDefaultParent(); - } - - if (index == null) - { - index = this.model.getChildCount(parent); - } - - this.model.beginUpdate(); - try - { - this.cellsAdded(cells, parent, index, source, target, false, true); - this.fireEvent(new mxEventObject(mxEvent.ADD_CELLS, 'cells', cells, - 'parent', parent, 'index', index, 'source', source, 'target', target)); - } - finally - { - this.model.endUpdate(); - } - - return cells; -}; - -/** - * Function: cellsAdded - * - * Adds the specified cells to the given parent. This method fires - * <mxEvent.CELLS_ADDED> while the transaction is in progress. - */ -mxGraph.prototype.cellsAdded = function(cells, parent, index, source, target, absolute, constrain) -{ - if (cells != null && parent != null && index != null) - { - this.model.beginUpdate(); - try - { - var parentState = (absolute) ? this.view.getState(parent) : null; - var o1 = (parentState != null) ? parentState.origin : null; - var zero = new mxPoint(0, 0); - - for (var i = 0; i < cells.length; i++) - { - if (cells[i] == null) - { - index--; - } - else - { - var previous = this.model.getParent(cells[i]); - - // Keeps the cell at its absolute location - if (o1 != null && cells[i] != parent && parent != previous) - { - var oldState = this.view.getState(previous); - var o2 = (oldState != null) ? oldState.origin : zero; - var geo = this.model.getGeometry(cells[i]); - - if (geo != null) - { - var dx = o2.x - o1.x; - var dy = o2.y - o1.y; - - // FIXME: Cells should always be inserted first before any other edit - // to avoid forward references in sessions. - geo = geo.clone(); - geo.translate(dx, dy); - - if (!geo.relative && this.model.isVertex(cells[i]) && - !this.isAllowNegativeCoordinates()) - { - geo.x = Math.max(0, geo.x); - geo.y = Math.max(0, geo.y); - } - - this.model.setGeometry(cells[i], geo); - } - } - - // Decrements all following indices - // if cell is already in parent - if (parent == previous) - { - index--; - } - - this.model.add(parent, cells[i], index + i); - - // Extends the parent - if (this.isExtendParentsOnAdd() && this.isExtendParent(cells[i])) - { - this.extendParent(cells[i]); - } - - // Constrains the child - if (constrain == null || constrain) - { - this.constrainChild(cells[i]); - } - - // Sets the source terminal - if (source != null) - { - this.cellConnected(cells[i], source, true); - } - - // Sets the target terminal - if (target != null) - { - this.cellConnected(cells[i], target, false); - } - } - } - - this.fireEvent(new mxEventObject(mxEvent.CELLS_ADDED, 'cells', cells, - 'parent', parent, 'index', index, 'source', source, 'target', target, - 'absolute', absolute)); - } - finally - { - this.model.endUpdate(); - } - } -}; - -/** - * Function: removeCells - * - * Removes the given cells from the graph including all connected edges if - * includeEdges is true. The change is carried out using <cellsRemoved>. - * This method fires <mxEvent.REMOVE_CELLS> while the transaction is in - * progress. The removed cells are returned as an array. - * - * Parameters: - * - * cells - Array of <mxCells> to remove. If null is specified then the - * selection cells which are deletable are used. - * includeEdges - Optional boolean which specifies if all connected edges - * should be removed as well. Default is true. - */ -mxGraph.prototype.removeCells = function(cells, includeEdges) -{ - includeEdges = (includeEdges != null) ? includeEdges : true; - - if (cells == null) - { - cells = this.getDeletableCells(this.getSelectionCells()); - } - - // Adds all edges to the cells - if (includeEdges) - { - cells = this.getDeletableCells(this.addAllEdges(cells)); - } - - this.model.beginUpdate(); - try - { - this.cellsRemoved(cells); - this.fireEvent(new mxEventObject(mxEvent.REMOVE_CELLS, - 'cells', cells, 'includeEdges', includeEdges)); - } - finally - { - this.model.endUpdate(); - } - - return cells; -}; - -/** - * Function: cellsRemoved - * - * Removes the given cells from the model. This method fires - * <mxEvent.CELLS_REMOVED> while the transaction is in progress. - * - * Parameters: - * - * cells - Array of <mxCells> to remove. - */ -mxGraph.prototype.cellsRemoved = function(cells) -{ - if (cells != null && cells.length > 0) - { - var scale = this.view.scale; - var tr = this.view.translate; - - this.model.beginUpdate(); - try - { - // Creates hashtable for faster lookup - var hash = new Object(); - - for (var i = 0; i < cells.length; i++) - { - var id = mxCellPath.create(cells[i]); - hash[id] = cells[i]; - } - - for (var i = 0; i < cells.length; i++) - { - // Disconnects edges which are not in cells - var edges = this.getConnections(cells[i]); - - for (var j = 0; j < edges.length; j++) - { - var id = mxCellPath.create(edges[j]); - - if (hash[id] == null) - { - var geo = this.model.getGeometry(edges[j]); - - if (geo != null) - { - var state = this.view.getState(edges[j]); - - if (state != null) - { - geo = geo.clone(); - var source = state.getVisibleTerminal(true) == cells[i]; - var pts = state.absolutePoints; - var n = (source) ? 0 : pts.length - 1; - - geo.setTerminalPoint( - new mxPoint(pts[n].x / scale - tr.x, - pts[n].y / scale - tr.y), source); - this.model.setTerminal(edges[j], null, source); - this.model.setGeometry(edges[j], geo); - } - } - } - } - - this.model.remove(cells[i]); - } - - this.fireEvent(new mxEventObject(mxEvent.CELLS_REMOVED, - 'cells', cells)); - } - finally - { - this.model.endUpdate(); - } - } -}; - -/** - * Function: splitEdge - * - * Splits the given edge by adding the newEdge between the previous source - * and the given cell and reconnecting the source of the given edge to the - * given cell. This method fires <mxEvent.SPLIT_EDGE> while the transaction - * is in progress. Returns the new edge that was inserted. - * - * Parameters: - * - * edge - <mxCell> that represents the edge to be splitted. - * cells - <mxCells> that represents the cells to insert into the edge. - * newEdge - <mxCell> that represents the edge to be inserted. - * dx - Optional integer that specifies the vector to move the cells. - * dy - Optional integer that specifies the vector to move the cells. - */ -mxGraph.prototype.splitEdge = function(edge, cells, newEdge, dx, dy) -{ - dx = dx || 0; - dy = dy || 0; - - if (newEdge == null) - { - newEdge = this.cloneCells([edge])[0]; - } - - var parent = this.model.getParent(edge); - var source = this.model.getTerminal(edge, true); - - this.model.beginUpdate(); - try - { - this.cellsMoved(cells, dx, dy, false, false); - this.cellsAdded(cells, parent, this.model.getChildCount(parent), null, null, - true); - this.cellsAdded([newEdge], parent, this.model.getChildCount(parent), - source, cells[0], false); - this.cellConnected(edge, cells[0], true); - this.fireEvent(new mxEventObject(mxEvent.SPLIT_EDGE, 'edge', edge, - 'cells', cells, 'newEdge', newEdge, 'dx', dx, 'dy', dy)); - } - finally - { - this.model.endUpdate(); - } - - return newEdge; -}; - -/** - * Group: Cell visibility - */ - -/** - * Function: toggleCells - * - * Sets the visible state of the specified cells and all connected edges - * if includeEdges is true. The change is carried out using <cellsToggled>. - * This method fires <mxEvent.TOGGLE_CELLS> while the transaction is in - * progress. Returns the cells whose visible state was changed. - * - * Parameters: - * - * show - Boolean that specifies the visible state to be assigned. - * cells - Array of <mxCells> whose visible state should be changed. If - * null is specified then the selection cells are used. - * includeEdges - Optional boolean indicating if the visible state of all - * connected edges should be changed as well. Default is true. - */ -mxGraph.prototype.toggleCells = function(show, cells, includeEdges) -{ - if (cells == null) - { - cells = this.getSelectionCells(); - } - - // Adds all connected edges recursively - if (includeEdges) - { - cells = this.addAllEdges(cells); - } - - this.model.beginUpdate(); - try - { - this.cellsToggled(cells, show); - this.fireEvent(new mxEventObject(mxEvent.TOGGLE_CELLS, - 'show', show, 'cells', cells, 'includeEdges', includeEdges)); - } - finally - { - this.model.endUpdate(); - } - - return cells; -}; - -/** - * Function: cellsToggled - * - * Sets the visible state of the specified cells. - * - * Parameters: - * - * cells - Array of <mxCells> whose visible state should be changed. - * show - Boolean that specifies the visible state to be assigned. - */ -mxGraph.prototype.cellsToggled = function(cells, show) -{ - if (cells != null && cells.length > 0) - { - this.model.beginUpdate(); - try - { - for (var i = 0; i < cells.length; i++) - { - this.model.setVisible(cells[i], show); - } - } - finally - { - this.model.endUpdate(); - } - } -}; - -/** - * Group: Folding - */ - -/** - * Function: foldCells - * - * Sets the collapsed state of the specified cells and all descendants - * if recurse is true. The change is carried out using <cellsFolded>. - * This method fires <mxEvent.FOLD_CELLS> while the transaction is in - * progress. Returns the cells whose collapsed state was changed. - * - * Parameters: - * - * collapsed - Boolean indicating the collapsed state to be assigned. - * recurse - Optional boolean indicating if the collapsed state of all - * descendants should be set. Default is false. - * cells - Array of <mxCells> whose collapsed state should be set. If - * null is specified then the foldable selection cells are used. - * checkFoldable - Optional boolean indicating of isCellFoldable should be - * checked. Default is false. - */ -mxGraph.prototype.foldCells = function(collapse, recurse, cells, checkFoldable) -{ - recurse = (recurse != null) ? recurse : false; - - if (cells == null) - { - cells = this.getFoldableCells(this.getSelectionCells(), collapse); - } - - this.stopEditing(false); - - this.model.beginUpdate(); - try - { - this.cellsFolded(cells, collapse, recurse, checkFoldable); - this.fireEvent(new mxEventObject(mxEvent.FOLD_CELLS, - 'collapse', collapse, 'recurse', recurse, 'cells', cells)); - } - finally - { - this.model.endUpdate(); - } - - return cells; -}; - -/** - * Function: cellsFolded - * - * Sets the collapsed state of the specified cells. This method fires - * <mxEvent.CELLS_FOLDED> while the transaction is in progress. Returns the - * cells whose collapsed state was changed. - * - * Parameters: - * - * cells - Array of <mxCells> whose collapsed state should be set. - * collapsed - Boolean indicating the collapsed state to be assigned. - * recurse - Boolean indicating if the collapsed state of all descendants - * should be set. - * checkFoldable - Optional boolean indicating of isCellFoldable should be - * checked. Default is false. - */ -mxGraph.prototype.cellsFolded = function(cells, collapse, recurse, checkFoldable) -{ - if (cells != null && cells.length > 0) - { - this.model.beginUpdate(); - try - { - for (var i = 0; i < cells.length; i++) - { - if ((!checkFoldable || this.isCellFoldable(cells[i], collapse)) && - collapse != this.isCellCollapsed(cells[i])) - { - this.model.setCollapsed(cells[i], collapse); - this.swapBounds(cells[i], collapse); - - if (this.isExtendParent(cells[i])) - { - this.extendParent(cells[i]); - } - - if (recurse) - { - var children = this.model.getChildren(cells[i]); - this.foldCells(children, collapse, recurse); - } - } - } - - this.fireEvent(new mxEventObject(mxEvent.CELLS_FOLDED, - 'cells', cells, 'collapse', collapse, 'recurse', recurse)); - } - finally - { - this.model.endUpdate(); - } - } -}; - -/** - * Function: swapBounds - * - * Swaps the alternate and the actual bounds in the geometry of the given - * cell invoking <updateAlternateBounds> before carrying out the swap. - * - * Parameters: - * - * cell - <mxCell> for which the bounds should be swapped. - * willCollapse - Boolean indicating if the cell is going to be collapsed. - */ -mxGraph.prototype.swapBounds = function(cell, willCollapse) -{ - if (cell != null) - { - var geo = this.model.getGeometry(cell); - - if (geo != null) - { - geo = geo.clone(); - - this.updateAlternateBounds(cell, geo, willCollapse); - geo.swap(); - - this.model.setGeometry(cell, geo); - } - } -}; - -/** - * Function: updateAlternateBounds - * - * Updates or sets the alternate bounds in the given geometry for the given - * cell depending on whether the cell is going to be collapsed. If no - * alternate bounds are defined in the geometry and - * <collapseToPreferredSize> is true, then the preferred size is used for - * the alternate bounds. The top, left corner is always kept at the same - * location. - * - * Parameters: - * - * cell - <mxCell> for which the geometry is being udpated. - * g - <mxGeometry> for which the alternate bounds should be updated. - * willCollapse - Boolean indicating if the cell is going to be collapsed. - */ -mxGraph.prototype.updateAlternateBounds = function(cell, geo, willCollapse) -{ - if (cell != null && geo != null) - { - if (geo.alternateBounds == null) - { - var bounds = geo; - - if (this.collapseToPreferredSize) - { - var tmp = this.getPreferredSizeForCell(cell); - - if (tmp != null) - { - bounds = tmp; - var state = this.view.getState(cell); - var style = (state != null) ? state.style : this.getCellStyle(cell); - - var startSize = mxUtils.getValue(style, mxConstants.STYLE_STARTSIZE); - - if (startSize > 0) - { - bounds.height = Math.max(bounds.height, startSize); - } - } - } - - geo.alternateBounds = new mxRectangle( - geo.x, geo.y, bounds.width, bounds.height); - } - else - { - geo.alternateBounds.x = geo.x; - geo.alternateBounds.y = geo.y; - } - } -}; - -/** - * Function: addAllEdges - * - * Returns an array with the given cells and all edges that are connected - * to a cell or one of its descendants. - */ -mxGraph.prototype.addAllEdges = function(cells) -{ - var allCells = cells.slice(); // FIXME: Required? - allCells = allCells.concat(this.getAllEdges(cells)); - - return allCells; -}; - -/** - * Function: getAllEdges - * - * Returns all edges connected to the given cells or its descendants. - */ -mxGraph.prototype.getAllEdges = function(cells) -{ - var edges = []; - - if (cells != null) - { - for (var i = 0; i < cells.length; i++) - { - var edgeCount = this.model.getEdgeCount(cells[i]); - - for (var j = 0; j < edgeCount; j++) - { - edges.push(this.model.getEdgeAt(cells[i], j)); - } - - // Recurses - var children = this.model.getChildren(cells[i]); - edges = edges.concat(this.getAllEdges(children)); - } - } - - return edges; -}; - -/** - * Group: Cell sizing - */ - -/** - * Function: updateCellSize - * - * Updates the size of the given cell in the model using <cellSizeUpdated>. - * This method fires <mxEvent.UPDATE_CELL_SIZE> while the transaction is in - * progress. Returns the cell whose size was updated. - * - * Parameters: - * - * cell - <mxCell> whose size should be updated. - */ -mxGraph.prototype.updateCellSize = function(cell, ignoreChildren) -{ - ignoreChildren = (ignoreChildren != null) ? ignoreChildren : false; - - this.model.beginUpdate(); - try - { - this.cellSizeUpdated(cell, ignoreChildren); - this.fireEvent(new mxEventObject(mxEvent.UPDATE_CELL_SIZE, - 'cell', cell, 'ignoreChildren', ignoreChildren)); - } - finally - { - this.model.endUpdate(); - } - - return cell; -}; - -/** - * Function: cellSizeUpdated - * - * Updates the size of the given cell in the model using - * <getPreferredSizeForCell> to get the new size. - * - * Parameters: - * - * cell - <mxCell> for which the size should be changed. - */ -mxGraph.prototype.cellSizeUpdated = function(cell, ignoreChildren) -{ - if (cell != null) - { - this.model.beginUpdate(); - try - { - var size = this.getPreferredSizeForCell(cell); - var geo = this.model.getGeometry(cell); - - if (size != null && geo != null) - { - var collapsed = this.isCellCollapsed(cell); - geo = geo.clone(); - - if (this.isSwimlane(cell)) - { - var state = this.view.getState(cell); - var style = (state != null) ? state.style : this.getCellStyle(cell); - var cellStyle = this.model.getStyle(cell); - - if (cellStyle == null) - { - cellStyle = ''; - } - - if (mxUtils.getValue(style, mxConstants.STYLE_HORIZONTAL, true)) - { - cellStyle = mxUtils.setStyle(cellStyle, - mxConstants.STYLE_STARTSIZE, size.height + 8); - - if (collapsed) - { - geo.height = size.height + 8; - } - - geo.width = size.width; - } - else - { - cellStyle = mxUtils.setStyle(cellStyle, - mxConstants.STYLE_STARTSIZE, size.width + 8); - - if (collapsed) - { - geo.width = size.width + 8; - } - - geo.height = size.height; - } - - this.model.setStyle(cell, cellStyle); - } - else - { - geo.width = size.width; - geo.height = size.height; - } - - if (!ignoreChildren && !collapsed) - { - var bounds = this.view.getBounds(this.model.getChildren(cell)); - - if (bounds != null) - { - var tr = this.view.translate; - var scale = this.view.scale; - - var width = (bounds.x + bounds.width) / scale - geo.x - tr.x; - var height = (bounds.y + bounds.height) / scale - geo.y - tr.y; - - geo.width = Math.max(geo.width, width); - geo.height = Math.max(geo.height, height); - } - } - - this.cellsResized([cell], [geo]); - } - } - finally - { - this.model.endUpdate(); - } - } -}; - -/** - * Function: getPreferredSizeForCell - * - * Returns the preferred width and height of the given <mxCell> as an - * <mxRectangle>. - * - * Parameters: - * - * cell - <mxCell> for which the preferred size should be returned. - */ -mxGraph.prototype.getPreferredSizeForCell = function(cell) -{ - var result = null; - - if (cell != null) - { - var state = this.view.getState(cell); - var style = (state != null) ? state.style : this.getCellStyle(cell); - - if (style != null && !this.model.isEdge(cell)) - { - var fontSize = style[mxConstants.STYLE_FONTSIZE] || mxConstants.DEFAULT_FONTSIZE; - var dx = 0; - var dy = 0; - - // Adds dimension of image if shape is a label - if (this.getImage(state) != null || style[mxConstants.STYLE_IMAGE] != null) - { - if (style[mxConstants.STYLE_SHAPE] == mxConstants.SHAPE_LABEL) - { - if (style[mxConstants.STYLE_VERTICAL_ALIGN] == mxConstants.ALIGN_MIDDLE) - { - dx += parseFloat(style[mxConstants.STYLE_IMAGE_WIDTH]) || mxLabel.prototype.imageSize; - } - - if (style[mxConstants.STYLE_ALIGN] != mxConstants.ALIGN_CENTER) - { - dy += parseFloat(style[mxConstants.STYLE_IMAGE_HEIGHT]) || mxLabel.prototype.imageSize; - } - } - } - - // Adds spacings - dx += 2 * (style[mxConstants.STYLE_SPACING] || 0); - dx += style[mxConstants.STYLE_SPACING_LEFT] || 0; - dx += style[mxConstants.STYLE_SPACING_RIGHT] || 0; - - dy += 2 * (style[mxConstants.STYLE_SPACING] || 0); - dy += style[mxConstants.STYLE_SPACING_TOP] || 0; - dy += style[mxConstants.STYLE_SPACING_BOTTOM] || 0; - - // Add spacing for collapse/expand icon - // LATER: Check alignment and use constants - // for image spacing - var image = this.getFoldingImage(state); - - if (image != null) - { - dx += image.width + 8; - } - - // Adds space for label - var value = this.getLabel(cell); - - if (value != null && value.length > 0) - { - if (!this.isHtmlLabel(cell)) - { - value = value.replace(/\n/g, '<br>'); - } - - var size = mxUtils.getSizeForString(value, - fontSize, style[mxConstants.STYLE_FONTFAMILY]); - var width = size.width + dx; - var height = size.height + dy; - - if (!mxUtils.getValue(style, mxConstants.STYLE_HORIZONTAL, true)) - { - var tmp = height; - - height = width; - width = tmp; - } - - if (this.gridEnabled) - { - width = this.snap(width + this.gridSize / 2); - height = this.snap(height + this.gridSize / 2); - } - - result = new mxRectangle(0, 0, width, height); - } - else - { - var gs2 = 4 * this.gridSize; - result = new mxRectangle(0, 0, gs2, gs2); - } - } - } - - return result; -}; - -/** - * Function: handleGesture - * - * Invokes if a gesture event has been detected on a cell state. - * - * Parameters: - * - * state - <mxCellState> which was pinched. - * evt - Object that represents the gesture event. - */ -mxGraph.prototype.handleGesture = function(state, evt) -{ - if (Math.abs(1 - evt.scale) > 0.2) - { - var scale = this.view.scale; - var tr = this.view.translate; - - var w = state.width * evt.scale; - var h = state.height * evt.scale; - var x = state.x - (w - state.width) / 2; - var y = state.y - (h - state.height) / 2; - - var bounds = new mxRectangle(this.snap(x / scale) - tr.x, - this.snap(y / scale) - tr.y, - this.snap(w / scale), this.snap(h / scale)); - this.resizeCell(state.cell, bounds); - } -}; - -/** - * Function: resizeCell - * - * Sets the bounds of the given cell using <resizeCells>. Returns the - * cell which was passed to the function. - * - * Parameters: - * - * cell - <mxCell> whose bounds should be changed. - * bounds - <mxRectangle> that represents the new bounds. - */ -mxGraph.prototype.resizeCell = function(cell, bounds) -{ - return this.resizeCells([cell], [bounds])[0]; -}; - -/** - * Function: resizeCells - * - * Sets the bounds of the given cells and fires a <mxEvent.RESIZE_CELLS> - * event while the transaction is in progress. Returns the cells which - * have been passed to the function. - * - * Parameters: - * - * cells - Array of <mxCells> whose bounds should be changed. - * bounds - Array of <mxRectangles> that represent the new bounds. - */ -mxGraph.prototype.resizeCells = function(cells, bounds) -{ - this.model.beginUpdate(); - try - { - this.cellsResized(cells, bounds); - this.fireEvent(new mxEventObject(mxEvent.RESIZE_CELLS, - 'cells', cells, 'bounds', bounds)); - } - finally - { - this.model.endUpdate(); - } - - return cells; -}; - -/** - * Function: cellsResized - * - * Sets the bounds of the given cells and fires a <mxEvent.CELLS_RESIZED> - * event. If <extendParents> is true, then the parent is extended if a - * child size is changed so that it overlaps with the parent. - * - * Parameters: - * - * cells - Array of <mxCells> whose bounds should be changed. - * bounds - Array of <mxRectangles> that represent the new bounds. - */ -mxGraph.prototype.cellsResized = function(cells, bounds) -{ - if (cells != null && bounds != null && cells.length == bounds.length) - { - this.model.beginUpdate(); - try - { - for (var i = 0; i < cells.length; i++) - { - var tmp = bounds[i]; - var geo = this.model.getGeometry(cells[i]); - - if (geo != null && (geo.x != tmp.x || geo.y != tmp.y || - geo.width != tmp.width || geo.height != tmp.height)) - { - geo = geo.clone(); - - if (geo.relative) - { - var offset = geo.offset; - - if (offset != null) - { - offset.x += tmp.x - geo.x; - offset.y += tmp.y - geo.y; - } - } - else - { - geo.x = tmp.x; - geo.y = tmp.y; - } - - geo.width = tmp.width; - geo.height = tmp.height; - - if (!geo.relative && this.model.isVertex(cells[i]) && - !this.isAllowNegativeCoordinates()) - { - geo.x = Math.max(0, geo.x); - geo.y = Math.max(0, geo.y); - } - - this.model.setGeometry(cells[i], geo); - - if (this.isExtendParent(cells[i])) - { - this.extendParent(cells[i]); - } - } - } - - if (this.resetEdgesOnResize) - { - this.resetEdges(cells); - } - - this.fireEvent(new mxEventObject(mxEvent.CELLS_RESIZED, - 'cells', cells, 'bounds', bounds)); - } - finally - { - this.model.endUpdate(); - } - } -}; - -/** - * Function: extendParent - * - * Resizes the parents recursively so that they contain the complete area - * of the resized child cell. - * - * Parameters: - * - * cell - <mxCell> that has been resized. - */ -mxGraph.prototype.extendParent = function(cell) -{ - if (cell != null) - { - var parent = this.model.getParent(cell); - var p = this.model.getGeometry(parent); - - if (parent != null && p != null && !this.isCellCollapsed(parent)) - { - var geo = this.model.getGeometry(cell); - - if (geo != null && (p.width < geo.x + geo.width || - p.height < geo.y + geo.height)) - { - p = p.clone(); - - p.width = Math.max(p.width, geo.x + geo.width); - p.height = Math.max(p.height, geo.y + geo.height); - - this.cellsResized([parent], [p]); - } - } - } -}; - -/** - * Group: Cell moving - */ - -/** - * Function: importCells - * - * Clones and inserts the given cells into the graph using the move - * method and returns the inserted cells. This shortcut is used if - * cells are inserted via datatransfer. - */ -mxGraph.prototype.importCells = function(cells, dx, dy, target, evt) -{ - return this.moveCells(cells, dx, dy, true, target, evt); -}; - -/** - * Function: moveCells - * - * Moves or clones the specified cells and moves the cells or clones by the - * given amount, adding them to the optional target cell. The evt is the - * mouse event as the mouse was released. The change is carried out using - * <cellsMoved>. This method fires <mxEvent.MOVE_CELLS> while the - * transaction is in progress. Returns the cells that were moved. - * - * Use the following code to move all cells in the graph. - * - * (code) - * graph.moveCells(graph.getChildCells(null, true, true), 10, 10); - * (end) - * - * Parameters: - * - * cells - Array of <mxCells> to be moved, cloned or added to the target. - * dx - Integer that specifies the x-coordinate of the vector. Default is 0. - * dy - Integer that specifies the y-coordinate of the vector. Default is 0. - * clone - Boolean indicating if the cells should be cloned. Default is false. - * target - <mxCell> that represents the new parent of the cells. - * evt - Mouseevent that triggered the invocation. - */ -mxGraph.prototype.moveCells = function(cells, dx, dy, clone, target, evt) -{ - dx = (dx != null) ? dx : 0; - dy = (dy != null) ? dy : 0; - clone = (clone != null) ? clone : false; - - if (cells != null && (dx != 0 || dy != 0 || clone || target != null)) - { - this.model.beginUpdate(); - try - { - if (clone) - { - cells = this.cloneCells(cells, this.isCloneInvalidEdges()); - - if (target == null) - { - target = this.getDefaultParent(); - } - } - - // FIXME: Cells should always be inserted first before any other edit - // to avoid forward references in sessions. - // Need to disable allowNegativeCoordinates if target not null to - // allow for temporary negative numbers until cellsAdded is called. - var previous = this.isAllowNegativeCoordinates(); - - if (target != null) - { - this.setAllowNegativeCoordinates(true); - } - - this.cellsMoved(cells, dx, dy, !clone && this.isDisconnectOnMove() - && this.isAllowDanglingEdges(), target == null); - - this.setAllowNegativeCoordinates(previous); - - if (target != null) - { - var index = this.model.getChildCount(target); - this.cellsAdded(cells, target, index, null, null, true); - } - - // Dispatches a move event - this.fireEvent(new mxEventObject(mxEvent.MOVE_CELLS, 'cells', cells, - 'dx', dx, 'dy', dy, 'clone', clone, 'target', target, 'event', evt)); - } - finally - { - this.model.endUpdate(); - } - } - - return cells; -}; - -/** - * Function: cellsMoved - * - * Moves the specified cells by the given vector, disconnecting the cells - * using disconnectGraph is disconnect is true. This method fires - * <mxEvent.CELLS_MOVED> while the transaction is in progress. - */ -mxGraph.prototype.cellsMoved = function(cells, dx, dy, disconnect, constrain) -{ - if (cells != null && (dx != 0 || dy != 0)) - { - this.model.beginUpdate(); - try - { - if (disconnect) - { - this.disconnectGraph(cells); - } - - for (var i = 0; i < cells.length; i++) - { - this.translateCell(cells[i], dx, dy); - - if (constrain) - { - this.constrainChild(cells[i]); - } - } - - if (this.resetEdgesOnMove) - { - this.resetEdges(cells); - } - - this.fireEvent(new mxEventObject(mxEvent.CELLS_MOVED, - 'cells', cells, 'dx', dy, 'dy', dy, 'disconnect', disconnect)); - } - finally - { - this.model.endUpdate(); - } - } -}; - -/** - * Function: translateCell - * - * Translates the geometry of the given cell and stores the new, - * translated geometry in the model as an atomic change. - */ -mxGraph.prototype.translateCell = function(cell, dx, dy) -{ - var geo = this.model.getGeometry(cell); - - if (geo != null) - { - geo = geo.clone(); - geo.translate(dx, dy); - - if (!geo.relative && this.model.isVertex(cell) && !this.isAllowNegativeCoordinates()) - { - geo.x = Math.max(0, geo.x); - geo.y = Math.max(0, geo.y); - } - - if (geo.relative && !this.model.isEdge(cell)) - { - if (geo.offset == null) - { - geo.offset = new mxPoint(dx, dy); - } - else - { - geo.offset.x += dx; - geo.offset.y += dy; - } - } - - this.model.setGeometry(cell, geo); - } -}; - -/** - * Function: getCellContainmentArea - * - * Returns the <mxRectangle> inside which a cell is to be kept. - * - * Parameters: - * - * cell - <mxCell> for which the area should be returned. - */ -mxGraph.prototype.getCellContainmentArea = function(cell) -{ - if (cell != null && !this.model.isEdge(cell)) - { - var parent = this.model.getParent(cell); - - if (parent == this.getDefaultParent() || parent == this.getCurrentRoot()) - { - return this.getMaximumGraphBounds(); - } - else if (parent != null && parent != this.getDefaultParent()) - { - var g = this.model.getGeometry(parent); - - if (g != null) - { - var x = 0; - var y = 0; - var w = g.width; - var h = g.height; - - if (this.isSwimlane(parent)) - { - var size = this.getStartSize(parent); - - x = size.width; - w -= size.width; - y = size.height; - h -= size.height; - } - - return new mxRectangle(x, y, w, h); - } - } - } - - return null; -}; - -/** - * Function: getMaximumGraphBounds - * - * Returns the bounds inside which the diagram should be kept as an - * <mxRectangle>. - */ -mxGraph.prototype.getMaximumGraphBounds = function() -{ - return this.maximumGraphBounds; -}; - -/** - * Function: constrainChild - * - * Keeps the given cell inside the bounds returned by - * <getCellContainmentArea> for its parent, according to the rules defined by - * <getOverlap> and <isConstrainChild>. This modifies the cell's geometry - * in-place and does not clone it. - * - * Parameters: - * - * cells - <mxCell> which should be constrained. - */ -mxGraph.prototype.constrainChild = function(cell) -{ - if (cell != null) - { - var geo = this.model.getGeometry(cell); - var area = (this.isConstrainChild(cell)) ? - this.getCellContainmentArea(cell) : - this.getMaximumGraphBounds(); - - if (geo != null && area != null) - { - // Keeps child within the content area of the parent - if (!geo.relative && (geo.x < area.x || geo.y < area.y || - area.width < geo.x + geo.width || area.height < geo.y + geo.height)) - { - var overlap = this.getOverlap(cell); - - if (area.width > 0) - { - geo.x = Math.min(geo.x, area.x + area.width - - (1 - overlap) * geo.width); - } - - if (area.height > 0) - { - geo.y = Math.min(geo.y, area.y + area.height - - (1 - overlap) * geo.height); - } - - geo.x = Math.max(geo.x, area.x - geo.width * overlap); - geo.y = Math.max(geo.y, area.y - geo.height * overlap); - } - } - } -}; - -/** - * Function: resetEdges - * - * Resets the control points of the edges that are connected to the given - * cells if not both ends of the edge are in the given cells array. - * - * Parameters: - * - * cells - Array of <mxCells> for which the connected edges should be - * reset. - */ -mxGraph.prototype.resetEdges = function(cells) -{ - if (cells != null) - { - // Prepares a hashtable for faster cell lookups - var hash = new Object(); - - for (var i = 0; i < cells.length; i++) - { - var id = mxCellPath.create(cells[i]); - hash[id] = cells[i]; - } - - this.model.beginUpdate(); - try - { - for (var i = 0; i < cells.length; i++) - { - var edges = this.model.getEdges(cells[i]); - - if (edges != null) - { - for (var j = 0; j < edges.length; j++) - { - var state = this.view.getState(edges[j]); - - var source = (state != null) ? state.getVisibleTerminal(true) : this.view.getVisibleTerminal(edges[j], true); - var target = (state != null) ? state.getVisibleTerminal(false) : this.view.getVisibleTerminal(edges[j], false); - - var sourceId = mxCellPath.create(source); - var targetId = mxCellPath.create(target); - - // Checks if one of the terminals is not in the given array - if (hash[sourceId] == null || hash[targetId] == null) - { - this.resetEdge(edges[j]); - } - } - } - - this.resetEdges(this.model.getChildren(cells[i])); - } - } - finally - { - this.model.endUpdate(); - } - } -}; - -/** - * Function: resetEdge - * - * Resets the control points of the given edge. - * - * Parameters: - * - * edge - <mxCell> whose points should be reset. - */ -mxGraph.prototype.resetEdge = function(edge) -{ - var geo = this.model.getGeometry(edge); - - // Resets the control points - if (geo != null && geo.points != null && geo.points.length > 0) - { - geo = geo.clone(); - geo.points = []; - this.model.setGeometry(edge, geo); - } - - return edge; -}; - -/** - * Group: Cell connecting and connection constraints - */ - -/** - * Function: getAllConnectionConstraints - * - * Returns an array of all <mxConnectionConstraints> for the given terminal. If - * the shape of the given terminal is a <mxStencilShape> then the constraints - * of the corresponding <mxStencil> are returned. - * - * Parameters: - * - * terminal - <mxCellState> that represents the terminal. - * source - Boolean that specifies if the terminal is the source or target. - */ -mxGraph.prototype.getAllConnectionConstraints = function(terminal, source) -{ - if (terminal != null && terminal.shape != null && - terminal.shape instanceof mxStencilShape) - { - if (terminal.shape.stencil != null) - { - return terminal.shape.stencil.constraints; - } - } - - return null; -}; - -/** - * Function: getConnectionConstraint - * - * Returns an <mxConnectionConstraint> that describes the given connection - * point. This result can then be passed to <getConnectionPoint>. - * - * Parameters: - * - * edge - <mxCellState> that represents the edge. - * terminal - <mxCellState> that represents the terminal. - * source - Boolean indicating if the terminal is the source or target. - */ -mxGraph.prototype.getConnectionConstraint = function(edge, terminal, source) -{ - var point = null; - var x = edge.style[(source) ? - mxConstants.STYLE_EXIT_X : - mxConstants.STYLE_ENTRY_X]; - - if (x != null) - { - var y = edge.style[(source) ? - mxConstants.STYLE_EXIT_Y : - mxConstants.STYLE_ENTRY_Y]; - - if (y != null) - { - point = new mxPoint(parseFloat(x), parseFloat(y)); - } - } - - var perimeter = false; - - if (point != null) - { - perimeter = mxUtils.getValue(edge.style, (source) ? mxConstants.STYLE_EXIT_PERIMETER : - mxConstants.STYLE_ENTRY_PERIMETER, true); - } - - return new mxConnectionConstraint(point, perimeter); -}; - -/** - * Function: setConnectionConstraint - * - * Sets the <mxConnectionConstraint> that describes the given connection point. - * If no constraint is given then nothing is changed. To remove an existing - * constraint from the given edge, use an empty constraint instead. - * - * Parameters: - * - * edge - <mxCell> that represents the edge. - * terminal - <mxCell> that represents the terminal. - * source - Boolean indicating if the terminal is the source or target. - * constraint - Optional <mxConnectionConstraint> to be used for this - * connection. - */ -mxGraph.prototype.setConnectionConstraint = function(edge, terminal, source, constraint) -{ - if (constraint != null) - { - this.model.beginUpdate(); - try - { - if (constraint == null || constraint.point == null) - { - this.setCellStyles((source) ? mxConstants.STYLE_EXIT_X : - mxConstants.STYLE_ENTRY_X, null, [edge]); - this.setCellStyles((source) ? mxConstants.STYLE_EXIT_Y : - mxConstants.STYLE_ENTRY_Y, null, [edge]); - this.setCellStyles((source) ? mxConstants.STYLE_EXIT_PERIMETER : - mxConstants.STYLE_ENTRY_PERIMETER, null, [edge]); - } - else if (constraint.point != null) - { - this.setCellStyles((source) ? mxConstants.STYLE_EXIT_X : - mxConstants.STYLE_ENTRY_X, constraint.point.x, [edge]); - this.setCellStyles((source) ? mxConstants.STYLE_EXIT_Y : - mxConstants.STYLE_ENTRY_Y, constraint.point.y, [edge]); - - // Only writes 0 since 1 is default - if (!constraint.perimeter) - { - this.setCellStyles((source) ? mxConstants.STYLE_EXIT_PERIMETER : - mxConstants.STYLE_ENTRY_PERIMETER, '0', [edge]); - } - else - { - this.setCellStyles((source) ? mxConstants.STYLE_EXIT_PERIMETER : - mxConstants.STYLE_ENTRY_PERIMETER, null, [edge]); - } - } - } - finally - { - this.model.endUpdate(); - } - } -}; - -/** - * Function: getConnectionPoint - * - * Returns the nearest point in the list of absolute points or the center - * of the opposite terminal. - * - * Parameters: - * - * vertex - <mxCellState> that represents the vertex. - * constraint - <mxConnectionConstraint> that represents the connection point - * constraint as returned by <getConnectionConstraint>. - */ -mxGraph.prototype.getConnectionPoint = function(vertex, constraint) -{ - var point = null; - - if (vertex != null) - { - var bounds = this.view.getPerimeterBounds(vertex); - var cx = new mxPoint(bounds.getCenterX(), bounds.getCenterY()); - - var direction = vertex.style[mxConstants.STYLE_DIRECTION]; - var r1 = 0; - - // Bounds need to be rotated by 90 degrees for further computation - if (direction != null) - { - if (direction == 'north') - { - r1 += 270; - } - else if (direction == 'west') - { - r1 += 180; - } - else if (direction == 'south') - { - r1 += 90; - } - - // Bounds need to be rotated by 90 degrees for further computation - if (direction == 'north' || direction == 'south') - { - bounds.x += bounds.width / 2 - bounds.height / 2; - bounds.y += bounds.height / 2 - bounds.width / 2; - var tmp = bounds.width; - bounds.width = bounds.height; - bounds.height = tmp; - } - } - - if (constraint.point != null) - { - var sx = 1; - var sy = 1; - var dx = 0; - var dy = 0; - - // LATER: Add flipping support for image shapes - if (vertex.shape instanceof mxStencilShape) - { - var flipH = vertex.style[mxConstants.STYLE_STENCIL_FLIPH]; - var flipV = vertex.style[mxConstants.STYLE_STENCIL_FLIPV]; - - if (direction == 'north' || direction == 'south') - { - var tmp = flipH; - flipH = flipV; - flipV = tmp; - } - - if (flipH) - { - sx = -1; - dx = -bounds.width; - } - - if (flipV) - { - sy = -1; - dy = -bounds.height ; - } - } - - point = new mxPoint(bounds.x + constraint.point.x * bounds.width * sx - dx, - bounds.y + constraint.point.y * bounds.height * sy - dy); - } - - // Rotation for direction before projection on perimeter - var r2 = vertex.style[mxConstants.STYLE_ROTATION] || 0; - - if (constraint.perimeter) - { - if (r1 != 0 && point != null) - { - // Only 90 degrees steps possible here so no trig needed - var cos = 0; - var sin = 0; - - if (r1 == 90) - { - sin = 1; - } - else if (r1 == 180) - { - cos = -1; - } - else if (r2 == 270) - { - sin = -1; - } - - point = mxUtils.getRotatedPoint(point, cos, sin, cx); - } - - if (point != null && constraint.perimeter) - { - point = this.view.getPerimeterPoint(vertex, point, false); - } - } - else - { - r2 += r1; - } - - // Generic rotation after projection on perimeter - if (r2 != 0 && point != null) - { - var rad = mxUtils.toRadians(r2); - var cos = Math.cos(rad); - var sin = Math.sin(rad); - - point = mxUtils.getRotatedPoint(point, cos, sin, cx); - } - } - - return point; -}; - -/** - * Function: connectCell - * - * Connects the specified end of the given edge to the given terminal - * using <cellConnected> and fires <mxEvent.CONNECT_CELL> while the - * transaction is in progress. Returns the updated edge. - * - * Parameters: - * - * edge - <mxCell> whose terminal should be updated. - * terminal - <mxCell> that represents the new terminal to be used. - * source - Boolean indicating if the new terminal is the source or target. - * constraint - Optional <mxConnectionConstraint> to be used for this - * connection. - */ -mxGraph.prototype.connectCell = function(edge, terminal, source, constraint) -{ - this.model.beginUpdate(); - try - { - var previous = this.model.getTerminal(edge, source); - this.cellConnected(edge, terminal, source, constraint); - this.fireEvent(new mxEventObject(mxEvent.CONNECT_CELL, - 'edge', edge, 'terminal', terminal, 'source', source, - 'previous', previous)); - } - finally - { - this.model.endUpdate(); - } - - return edge; -}; - -/** - * Function: cellConnected - * - * Sets the new terminal for the given edge and resets the edge points if - * <resetEdgesOnConnect> is true. This method fires - * <mxEvent.CELL_CONNECTED> while the transaction is in progress. - * - * Parameters: - * - * edge - <mxCell> whose terminal should be updated. - * terminal - <mxCell> that represents the new terminal to be used. - * source - Boolean indicating if the new terminal is the source or target. - * constraint - <mxConnectionConstraint> to be used for this connection. - */ -mxGraph.prototype.cellConnected = function(edge, terminal, source, constraint) -{ - if (edge != null) - { - this.model.beginUpdate(); - try - { - var previous = this.model.getTerminal(edge, source); - - // Updates the constraint - this.setConnectionConstraint(edge, terminal, source, constraint); - - // Checks if the new terminal is a port, uses the ID of the port in the - // style and the parent of the port as the actual terminal of the edge. - if (this.isPortsEnabled()) - { - var id = null; - - if (this.isPort(terminal)) - { - id = terminal.getId(); - terminal = this.getTerminalForPort(terminal, source); - } - - // Sets or resets all previous information for connecting to a child port - var key = (source) ? mxConstants.STYLE_SOURCE_PORT : - mxConstants.STYLE_TARGET_PORT; - this.setCellStyles(key, id, [edge]); - } - - this.model.setTerminal(edge, terminal, source); - - if (this.resetEdgesOnConnect) - { - this.resetEdge(edge); - } - - this.fireEvent(new mxEventObject(mxEvent.CELL_CONNECTED, - 'edge', edge, 'terminal', terminal, 'source', source, - 'previous', previous)); - } - finally - { - this.model.endUpdate(); - } - } -}; - -/** - * Function: disconnectGraph - * - * Disconnects the given edges from the terminals which are not in the - * given array. - * - * Parameters: - * - * cells - Array of <mxCells> to be disconnected. - */ -mxGraph.prototype.disconnectGraph = function(cells) -{ - if (cells != null) - { - this.model.beginUpdate(); - try - { - var scale = this.view.scale; - var tr = this.view.translate; - - // Prepares a hashtable for faster cell lookups - var hash = new Object(); - - for (var i = 0; i < cells.length; i++) - { - var id = mxCellPath.create(cells[i]); - hash[id] = cells[i]; - } - - for (var i = 0; i < cells.length; i++) - { - if (this.model.isEdge(cells[i])) - { - var geo = this.model.getGeometry(cells[i]); - - if (geo != null) - { - var state = this.view.getState(cells[i]); - var pstate = this.view.getState( - this.model.getParent(cells[i])); - - if (state != null && - pstate != null) - { - geo = geo.clone(); - - var dx = -pstate.origin.x; - var dy = -pstate.origin.y; - var pts = state.absolutePoints; - - var src = this.model.getTerminal(cells[i], true); - - if (src != null && this.isCellDisconnectable(cells[i], src, true)) - { - var srcId = mxCellPath.create(src); - - while (src != null && hash[srcId] == null) - { - src = this.model.getParent(src); - srcId = mxCellPath.create(src); - } - - if (src == null) - { - geo.setTerminalPoint( - new mxPoint(pts[0].x / scale - tr.x + dx, - pts[0].y / scale - tr.y + dy), true); - this.model.setTerminal(cells[i], null, true); - } - } - - var trg = this.model.getTerminal(cells[i], false); - - if (trg != null && this.isCellDisconnectable(cells[i], trg, false)) - { - var trgId = mxCellPath.create(trg); - - while (trg != null && hash[trgId] == null) - { - trg = this.model.getParent(trg); - trgId = mxCellPath.create(trg); - } - - if (trg == null) - { - var n = pts.length - 1; - geo.setTerminalPoint( - new mxPoint(pts[n].x / scale - tr.x + dx, - pts[n].y / scale - tr.y + dy), false); - this.model.setTerminal(cells[i], null, false); - } - } - - this.model.setGeometry(cells[i], geo); - } - } - } - } - } - finally - { - this.model.endUpdate(); - } - } -}; - -/** - * Group: Drilldown - */ - -/** - * Function: getCurrentRoot - * - * Returns the current root of the displayed cell hierarchy. This is a - * shortcut to <mxGraphView.currentRoot> in <view>. - */ - mxGraph.prototype.getCurrentRoot = function() - { - return this.view.currentRoot; - }; - - /** - * Function: getTranslateForRoot - * - * Returns the translation to be used if the given cell is the root cell as - * an <mxPoint>. This implementation returns null. - * - * Example: - * - * To keep the children at their absolute position while stepping into groups, - * this function can be overridden as follows. - * - * (code) - * var offset = new mxPoint(0, 0); - * - * while (cell != null) - * { - * var geo = this.model.getGeometry(cell); - * - * if (geo != null) - * { - * offset.x -= geo.x; - * offset.y -= geo.y; - * } - * - * cell = this.model.getParent(cell); - * } - * - * return offset; - * (end) - * - * Parameters: - * - * cell - <mxCell> that represents the root. - */ -mxGraph.prototype.getTranslateForRoot = function(cell) -{ - return null; -}; - -/** - * Function: isPort - * - * Returns true if the given cell is a "port", that is, when connecting to - * it, the cell returned by getTerminalForPort should be used as the - * terminal and the port should be referenced by the ID in either the - * mxConstants.STYLE_SOURCE_PORT or the or the - * mxConstants.STYLE_TARGET_PORT. Note that a port should not be movable. - * This implementation always returns false. - * - * A typical implementation is the following: - * - * (code) - * graph.isPort = function(cell) - * { - * var geo = this.getCellGeometry(cell); - * - * return (geo != null) ? geo.relative : false; - * }; - * (end) - * - * Parameters: - * - * cell - <mxCell> that represents the port. - */ -mxGraph.prototype.isPort = function(cell) -{ - return false; -}; - -/** - * Function: getTerminalForPort - * - * Returns the terminal to be used for a given port. This implementation - * always returns the parent cell. - * - * Parameters: - * - * cell - <mxCell> that represents the port. - * source - If the cell is the source or target port. - */ -mxGraph.prototype.getTerminalForPort = function(cell, source) -{ - return this.model.getParent(cell); -}; - -/** - * Function: getChildOffsetForCell - * - * Returns the offset to be used for the cells inside the given cell. The - * root and layer cells may be identified using <mxGraphModel.isRoot> and - * <mxGraphModel.isLayer>. For all other current roots, the - * <mxGraphView.currentRoot> field points to the respective cell, so that - * the following holds: cell == this.view.currentRoot. This implementation - * returns null. - * - * Parameters: - * - * cell - <mxCell> whose offset should be returned. - */ -mxGraph.prototype.getChildOffsetForCell = function(cell) -{ - return null; -}; - -/** - * Function: enterGroup - * - * Uses the given cell as the root of the displayed cell hierarchy. If no - * cell is specified then the selection cell is used. The cell is only used - * if <isValidRoot> returns true. - * - * Parameters: - * - * cell - Optional <mxCell> to be used as the new root. Default is the - * selection cell. - */ -mxGraph.prototype.enterGroup = function(cell) -{ - cell = cell || this.getSelectionCell(); - - if (cell != null && this.isValidRoot(cell)) - { - this.view.setCurrentRoot(cell); - this.clearSelection(); - } -}; - -/** - * Function: exitGroup - * - * Changes the current root to the next valid root in the displayed cell - * hierarchy. - */ -mxGraph.prototype.exitGroup = function() -{ - var root = this.model.getRoot(); - var current = this.getCurrentRoot(); - - if (current != null) - { - var next = this.model.getParent(current); - - // Finds the next valid root in the hierarchy - while (next != root && !this.isValidRoot(next) && - this.model.getParent(next) != root) - { - next = this.model.getParent(next); - } - - // Clears the current root if the new root is - // the model's root or one of the layers. - if (next == root || this.model.getParent(next) == root) - { - this.view.setCurrentRoot(null); - } - else - { - this.view.setCurrentRoot(next); - } - - var state = this.view.getState(current); - - // Selects the previous root in the graph - if (state != null) - { - this.setSelectionCell(current); - } - } -}; - -/** - * Function: home - * - * Uses the root of the model as the root of the displayed cell hierarchy - * and selects the previous root. - */ -mxGraph.prototype.home = function() -{ - var current = this.getCurrentRoot(); - - if (current != null) - { - this.view.setCurrentRoot(null); - var state = this.view.getState(current); - - if (state != null) - { - this.setSelectionCell(current); - } - } -}; - -/** - * Function: isValidRoot - * - * Returns true if the given cell is a valid root for the cell display - * hierarchy. This implementation returns true for all non-null values. - * - * Parameters: - * - * cell - <mxCell> which should be checked as a possible root. - */ -mxGraph.prototype.isValidRoot = function(cell) -{ - return (cell != null); -}; - -/** - * Group: Graph display - */ - -/** - * Function: getGraphBounds - * - * Returns the bounds of the visible graph. Shortcut to - * <mxGraphView.getGraphBounds>. See also: <getBoundingBoxFromGeometry>. - */ - mxGraph.prototype.getGraphBounds = function() - { - return this.view.getGraphBounds(); - }; - -/** - * Function: getCellBounds - * - * Returns the scaled, translated bounds for the given cell. See - * <mxGraphView.getBounds> for arrays. - * - * Parameters: - * - * cell - <mxCell> whose bounds should be returned. - * includeEdge - Optional boolean that specifies if the bounds of - * the connected edges should be included. Default is false. - * includeDescendants - Optional boolean that specifies if the bounds - * of all descendants should be included. Default is false. - */ -mxGraph.prototype.getCellBounds = function(cell, includeEdges, includeDescendants) -{ - var cells = [cell]; - - // Includes all connected edges - if (includeEdges) - { - cells = cells.concat(this.model.getEdges(cell)); - } - - var result = this.view.getBounds(cells); - - // Recursively includes the bounds of the children - if (includeDescendants) - { - var childCount = this.model.getChildCount(cell); - - for (var i = 0; i < childCount; i++) - { - var tmp = this.getCellBounds(this.model.getChildAt(cell, i), - includeEdges, true); - - if (result != null) - { - result.add(tmp); - } - else - { - result = tmp; - } - } - } - - return result; -}; - -/** - * Function: getBoundingBoxFromGeometry - * - * Returns the bounding box for the geometries of the vertices in the - * given array of cells. This can be used to find the graph bounds during - * a layout operation (ie. before the last endUpdate) as follows: - * - * (code) - * var cells = graph.getChildCells(graph.getDefaultParent(), true, true); - * var bounds = graph.getBoundingBoxFromGeometry(cells, true); - * (end) - * - * This can then be used to move cells to the origin: - * - * (code) - * if (bounds.x < 0 || bounds.y < 0) - * { - * graph.moveCells(cells, -Math.min(bounds.x, 0), -Math.min(bounds.y, 0)) - * } - * (end) - * - * Or to translate the graph view: - * - * (code) - * if (bounds.x < 0 || bounds.y < 0) - * { - * graph.view.setTranslate(-Math.min(bounds.x, 0), -Math.min(bounds.y, 0)); - * } - * (end) - * - * Parameters: - * - * cells - Array of <mxCells> whose bounds should be returned. - * includeEdges - Specifies if edge bounds should be included by computing - * the bounding box for all points its geometry. Default is false. - */ -mxGraph.prototype.getBoundingBoxFromGeometry = function(cells, includeEdges) -{ - includeEdges = (includeEdges != null) ? includeEdges : false; - var result = null; - - if (cells != null) - { - for (var i = 0; i < cells.length; i++) - { - if (includeEdges || this.model.isVertex(cells[i])) - { - // Computes the bounding box for the points in the geometry - var geo = this.getCellGeometry(cells[i]); - - if (geo != null) - { - var pts = geo.points; - - if (pts != null && pts.length > 0) - { - var tmp = new mxRectangle(pts[0].x, pts[0].y, 0, 0); - var addPoint = function(pt) - { - if (pt != null) - { - tmp.add(new mxRectangle(pt.x, pt.y, 0, 0)); - } - }; - - for (var j = 1; j < pts.length; j++) - { - addPoint(pts[j]); - } - - addPoint(geo.getTerminalPoint(true)); - addPoint(geo.getTerminalPoint(false)); - } - - if (result == null) - { - result = new mxRectangle(geo.x, geo.y, geo.width, geo.height); - } - else - { - result.add(geo); - } - } - } - } - } - - return result; -}; - -/** - * Function: refresh - * - * Clears all cell states or the states for the hierarchy starting at the - * given cell and validates the graph. This fires a refresh event as the - * last step. - * - * Parameters: - * - * cell - Optional <mxCell> for which the cell states should be cleared. - */ -mxGraph.prototype.refresh = function(cell) -{ - this.view.clear(cell, cell == null); - this.view.validate(); - this.sizeDidChange(); - this.fireEvent(new mxEventObject(mxEvent.REFRESH)); -}; - -/** - * Function: snap - * - * Snaps the given numeric value to the grid if <gridEnabled> is true. - * - * Parameters: - * - * value - Numeric value to be snapped to the grid. - */ -mxGraph.prototype.snap = function(value) -{ - if (this.gridEnabled) - { - value = Math.round(value / this.gridSize ) * this.gridSize; - } - - return value; -}; - -/** - * Function: panGraph - * - * Shifts the graph display by the given amount. This is used to preview - * panning operations, use <mxGraphView.setTranslate> to set a persistent - * translation of the view. Fires <mxEvent.PAN>. - * - * Parameters: - * - * dx - Amount to shift the graph along the x-axis. - * dy - Amount to shift the graph along the y-axis. - */ -mxGraph.prototype.panGraph = function(dx, dy) -{ - if (this.useScrollbarsForPanning && mxUtils.hasScrollbars(this.container)) - { - this.container.scrollLeft = -dx; - this.container.scrollTop = -dy; - } - else - { - var canvas = this.view.getCanvas(); - - if (this.dialect == mxConstants.DIALECT_SVG) - { - // Puts everything inside the container in a DIV so that it - // can be moved without changing the state of the container - if (dx == 0 && dy == 0) - { - // Workaround for ignored removeAttribute on SVG element in IE9 standards - if (mxClient.IS_IE) - { - canvas.setAttribute('transform', 'translate('+ dx + ',' + dy + ')'); - } - else - { - canvas.removeAttribute('transform'); - } - - if (this.shiftPreview1 != null) - { - var child = this.shiftPreview1.firstChild; - - while (child != null) - { - var next = child.nextSibling; - this.container.appendChild(child); - child = next; - } - - this.shiftPreview1.parentNode.removeChild(this.shiftPreview1); - this.shiftPreview1 = null; - - this.container.appendChild(canvas.parentNode); - - child = this.shiftPreview2.firstChild; - - while (child != null) - { - var next = child.nextSibling; - this.container.appendChild(child); - child = next; - } - - this.shiftPreview2.parentNode.removeChild(this.shiftPreview2); - this.shiftPreview2 = null; - } - } - else - { - canvas.setAttribute('transform', 'translate('+ dx + ',' + dy + ')'); - - if (this.shiftPreview1 == null) - { - // Needs two divs for stuff before and after the SVG element - this.shiftPreview1 = document.createElement('div'); - this.shiftPreview1.style.position = 'absolute'; - this.shiftPreview1.style.overflow = 'visible'; - - this.shiftPreview2 = document.createElement('div'); - this.shiftPreview2.style.position = 'absolute'; - this.shiftPreview2.style.overflow = 'visible'; - - var current = this.shiftPreview1; - var child = this.container.firstChild; - - while (child != null) - { - var next = child.nextSibling; - - // SVG element is moved via transform attribute - if (child != canvas.parentNode) - { - current.appendChild(child); - } - else - { - current = this.shiftPreview2; - } - - child = next; - } - - this.container.insertBefore(this.shiftPreview1, canvas.parentNode); - this.container.appendChild(this.shiftPreview2); - } - - this.shiftPreview1.style.left = dx + 'px'; - this.shiftPreview1.style.top = dy + 'px'; - this.shiftPreview2.style.left = dx + 'px'; - this.shiftPreview2.style.top = dy + 'px'; - } - } - else - { - canvas.style.left = dx + 'px'; - canvas.style.top = dy + 'px'; - } - - this.panDx = dx; - this.panDy = dy; - - this.fireEvent(new mxEventObject(mxEvent.PAN)); - } -}; - -/** - * Function: zoomIn - * - * Zooms into the graph by <zoomFactor>. - */ -mxGraph.prototype.zoomIn = function() -{ - this.zoom(this.zoomFactor); -}; - -/** - * Function: zoomOut - * - * Zooms out of the graph by <zoomFactor>. - */ -mxGraph.prototype.zoomOut = function() -{ - this.zoom(1 / this.zoomFactor); -}; - -/** - * Function: zoomActual - * - * Resets the zoom and panning in the view. - */ -mxGraph.prototype.zoomActual = function() -{ - if (this.view.scale == 1) - { - this.view.setTranslate(0, 0); - } - else - { - this.view.translate.x = 0; - this.view.translate.y = 0; - - this.view.setScale(1); - } -}; - -/** - * Function: zoomTo - * - * Zooms the graph to the given scale with an optional boolean center - * argument, which is passd to <zoom>. - */ -mxGraph.prototype.zoomTo = function(scale, center) -{ - this.zoom(scale / this.view.scale, center); -}; - -/** - * Function: zoom - * - * Zooms the graph using the given factor. Center is an optional boolean - * argument that keeps the graph scrolled to the center. If the center argument - * is omitted, then <centerZoom> will be used as its value. - */ -mxGraph.prototype.zoom = function(factor, center) -{ - center = (center != null) ? center : this.centerZoom; - var scale = this.view.scale * factor; - var state = this.view.getState(this.getSelectionCell()); - - if (this.keepSelectionVisibleOnZoom && state != null) - { - var rect = new mxRectangle( - state.x * factor, - state.y * factor, - state.width * factor, - state.height * factor); - - // Refreshes the display only once if a - // scroll is carried out - this.view.scale = scale; - - if (!this.scrollRectToVisible(rect)) - { - this.view.revalidate(); - - // Forces an event to be fired but does not revalidate again - this.view.setScale(scale); - } - } - else if (center && !mxUtils.hasScrollbars(this.container)) - { - var dx = this.container.offsetWidth; - var dy = this.container.offsetHeight; - - if (factor > 1) - { - var f = (factor -1) / (scale * 2); - dx *= -f; - dy *= -f; - } - else - { - var f = (1/factor -1) / (this.view.scale * 2); - dx *= f; - dy *= f; - } - - this.view.scaleAndTranslate(scale, - this.view.translate.x + dx, - this.view.translate.y + dy); - } - else - { - this.view.setScale(scale); - - if (mxUtils.hasScrollbars(this.container)) - { - var dx = 0; - var dy = 0; - - if (center) - { - dx = this.container.offsetWidth * (factor - 1) / 2; - dy = this.container.offsetHeight * (factor - 1) / 2; - } - - this.container.scrollLeft = Math.round(this.container.scrollLeft * factor + dx); - this.container.scrollTop = Math.round(this.container.scrollTop * factor + dy); - } - } -}; - -/** - * Function: zoomToRect - * - * Zooms the graph to the specified rectangle. If the rectangle does not have same aspect - * ratio as the display container, it is increased in the smaller relative dimension only - * until the aspect match. The original rectangle is centralised within this expanded one. - * - * Note that the input rectangular must be un-scaled and un-translated. - * - * Parameters: - * - * rect - The un-scaled and un-translated rectangluar region that should be just visible - * after the operation - */ -mxGraph.prototype.zoomToRect = function(rect) -{ - var scaleX = this.container.clientWidth / rect.width; - var scaleY = this.container.clientHeight / rect.height; - var aspectFactor = scaleX / scaleY; - - // Remove any overlap of the rect outside the client area - rect.x = Math.max(0, rect.x); - rect.y = Math.max(0, rect.y); - var rectRight = Math.min(this.container.scrollWidth, rect.x + rect.width); - var rectBottom = Math.min(this.container.scrollHeight, rect.y + rect.height); - rect.width = rectRight - rect.x; - rect.height = rectBottom - rect.y; - - // The selection area has to be increased to the same aspect - // ratio as the container, centred around the centre point of the - // original rect passed in. - if (aspectFactor < 1.0) - { - // Height needs increasing - var newHeight = rect.height / aspectFactor; - var deltaHeightBuffer = (newHeight - rect.height) / 2.0; - rect.height = newHeight; - - // Assign up to half the buffer to the upper part of the rect, not crossing 0 - // put the rest on the bottom - var upperBuffer = Math.min(rect.y , deltaHeightBuffer); - rect.y = rect.y - upperBuffer; - - // Check if the bottom has extended too far - rectBottom = Math.min(this.container.scrollHeight, rect.y + rect.height); - rect.height = rectBottom - rect.y; - } - else - { - // Width needs increasing - var newWidth = rect.width * aspectFactor; - var deltaWidthBuffer = (newWidth - rect.width) / 2.0; - rect.width = newWidth; - - // Assign up to half the buffer to the upper part of the rect, not crossing 0 - // put the rest on the bottom - var leftBuffer = Math.min(rect.x , deltaWidthBuffer); - rect.x = rect.x - leftBuffer; - - // Check if the right hand side has extended too far - rectRight = Math.min(this.container.scrollWidth, rect.x + rect.width); - rect.width = rectRight - rect.x; - } - - var scale = this.container.clientWidth / rect.width; - - if (!mxUtils.hasScrollbars(this.container)) - { - this.view.scaleAndTranslate(scale, -rect.x, -rect.y); - } - else - { - this.view.setScale(scale); - this.container.scrollLeft = Math.round(rect.x * scale); - this.container.scrollTop = Math.round(rect.y * scale); - } -}; - -/** - * Function: fit - * - * Scales the graph such that the complete diagram fits into <container> and - * returns the current scale in the view. To fit an initial graph prior to - * rendering, set <mxGraphView.rendering> to false prior to changing the model - * and execute the following after changing the model. - * - * (code) - * graph.fit(); - * graph.view.rendering = true; - * graph.refresh(); - * (end) - * - * Parameters: - * - * border - Optional number that specifies the border. Default is 0. - * keepOrigin - Optional boolean that specifies if the translate should be - * changed. Default is false. - */ -mxGraph.prototype.fit = function(border, keepOrigin) -{ - if (this.container != null) - { - border = (border != null) ? border : 0; - keepOrigin = (keepOrigin != null) ? keepOrigin : false; - - var w1 = this.container.clientWidth; - var h1 = this.container.clientHeight; - - var bounds = this.view.getGraphBounds(); - - if (keepOrigin && bounds.x != null && bounds.y != null) - { - bounds.width += bounds.x; - bounds.height += bounds.y; - bounds.x = 0; - bounds.y = 0; - } - - var s = this.view.scale; - var w2 = bounds.width / s; - var h2 = bounds.height / s; - - // Fits to the size of the background image if required - if (this.backgroundImage != null) - { - w2 = Math.max(w2, this.backgroundImage.width - bounds.x / s); - h2 = Math.max(h2, this.backgroundImage.height - bounds.y / s); - } - - var b = (keepOrigin) ? border : 2 * border; - var s2 = Math.floor(Math.min(w1 / (w2 + b), h1 / (h2 + b)) * 100) / 100; - - if (this.minFitScale != null) - { - s2 = Math.max(s2, this.minFitScale); - } - - if (this.maxFitScale != null) - { - s2 = Math.min(s2, this.maxFitScale); - } - - if (!keepOrigin) - { - if (!mxUtils.hasScrollbars(this.container)) - { - var x0 = (bounds.x != null) ? Math.floor(this.view.translate.x - bounds.x / s + border + 1) : border; - var y0 = (bounds.y != null) ? Math.floor(this.view.translate.y - bounds.y / s + border + 1) : border; - - this.view.scaleAndTranslate(s2, x0, y0); - } - else - { - this.view.setScale(s2); - - if (bounds.x != null) - { - this.container.scrollLeft = Math.round(bounds.x / s) * s2 - border - - Math.max(0, (this.container.clientWidth - w2 * s2) / 2); - } - - if (bounds.y != null) - { - this.container.scrollTop = Math.round(bounds.y / s) * s2 - border - - Math.max(0, (this.container.clientHeight - h2 * s2) / 2); - } - } - } - else if (this.view.scale != s2) - { - this.view.setScale(s2); - } - } - - return this.view.scale; -}; - -/** - * Function: scrollCellToVisible - * - * Pans the graph so that it shows the given cell. Optionally the cell may - * be centered in the container. - * - * To center a given graph if the <container> has no scrollbars, use the following code. - * - * [code] - * var bounds = graph.getGraphBounds(); - * graph.view.setTranslate(-bounds.x - (bounds.width - container.clientWidth) / 2, - * -bounds.y - (bounds.height - container.clientHeight) / 2); - * [/code] - * - * Parameters: - * - * cell - <mxCell> to be made visible. - * center - Optional boolean flag. Default is false. - */ -mxGraph.prototype.scrollCellToVisible = function(cell, center) -{ - var x = -this.view.translate.x; - var y = -this.view.translate.y; - - var state = this.view.getState(cell); - - if (state != null) - { - var bounds = new mxRectangle(x + state.x, y + state.y, state.width, - state.height); - - if (center && this.container != null) - { - var w = this.container.clientWidth; - var h = this.container.clientHeight; - - bounds.x = bounds.getCenterX() - w / 2; - bounds.width = w; - bounds.y = bounds.getCenterY() - h / 2; - bounds.height = h; - } - - if (this.scrollRectToVisible(bounds)) - { - // Triggers an update via the view's event source - this.view.setTranslate(this.view.translate.x, this.view.translate.y); - } - } -}; - -/** - * Function: scrollRectToVisible - * - * Pans the graph so that it shows the given rectangle. - * - * Parameters: - * - * rect - <mxRectangle> to be made visible. - */ -mxGraph.prototype.scrollRectToVisible = function(rect) -{ - var isChanged = false; - - if (rect != null) - { - var w = this.container.offsetWidth; - var h = this.container.offsetHeight; - - var widthLimit = Math.min(w, rect.width); - var heightLimit = Math.min(h, rect.height); - - if (mxUtils.hasScrollbars(this.container)) - { - var c = this.container; - rect.x += this.view.translate.x; - rect.y += this.view.translate.y; - var dx = c.scrollLeft - rect.x; - var ddx = Math.max(dx - c.scrollLeft, 0); - - if (dx > 0) - { - c.scrollLeft -= dx + 2; - } - else - { - dx = rect.x + widthLimit - c.scrollLeft - c.clientWidth; - - if (dx > 0) - { - c.scrollLeft += dx + 2; - } - } - - var dy = c.scrollTop - rect.y; - var ddy = Math.max(0, dy - c.scrollTop); - - if (dy > 0) - { - c.scrollTop -= dy + 2; - } - else - { - dy = rect.y + heightLimit - c.scrollTop - c.clientHeight; - - if (dy > 0) - { - c.scrollTop += dy + 2; - } - } - - if (!this.useScrollbarsForPanning && (ddx != 0 || ddy != 0)) - { - this.view.setTranslate(ddx, ddy); - } - } - else - { - var x = -this.view.translate.x; - var y = -this.view.translate.y; - - var s = this.view.scale; - - if (rect.x + widthLimit > x + w) - { - this.view.translate.x -= (rect.x + widthLimit - w - x) / s; - isChanged = true; - } - - if (rect.y + heightLimit > y + h) - { - this.view.translate.y -= (rect.y + heightLimit - h - y) / s; - isChanged = true; - } - - if (rect.x < x) - { - this.view.translate.x += (x - rect.x) / s; - isChanged = true; - } - - if (rect.y < y) - { - this.view.translate.y += (y - rect.y) / s; - isChanged = true; - } - - if (isChanged) - { - this.view.refresh(); - - // Repaints selection marker (ticket 18) - if (this.selectionCellsHandler != null) - { - this.selectionCellsHandler.refresh(); - } - } - } - } - - return isChanged; -}; - -/** - * Function: getCellGeometry - * - * Returns the <mxGeometry> for the given cell. This implementation uses - * <mxGraphModel.getGeometry>. Subclasses can override this to implement - * specific geometries for cells in only one graph, that is, it can return - * geometries that depend on the current state of the view. - * - * Parameters: - * - * cell - <mxCell> whose geometry should be returned. - */ -mxGraph.prototype.getCellGeometry = function(cell) -{ - return this.model.getGeometry(cell); -}; - -/** - * Function: isCellVisible - * - * Returns true if the given cell is visible in this graph. This - * implementation uses <mxGraphModel.isVisible>. Subclassers can override - * this to implement specific visibility for cells in only one graph, that - * is, without affecting the visible state of the cell. - * - * When using dynamic filter expressions for cell visibility, then the - * graph should be revalidated after the filter expression has changed. - * - * Parameters: - * - * cell - <mxCell> whose visible state should be returned. - */ -mxGraph.prototype.isCellVisible = function(cell) -{ - return this.model.isVisible(cell); -}; - -/** - * Function: isCellCollapsed - * - * Returns true if the given cell is collapsed in this graph. This - * implementation uses <mxGraphModel.isCollapsed>. Subclassers can override - * this to implement specific collapsed states for cells in only one graph, - * that is, without affecting the collapsed state of the cell. - * - * When using dynamic filter expressions for the collapsed state, then the - * graph should be revalidated after the filter expression has changed. - * - * Parameters: - * - * cell - <mxCell> whose collapsed state should be returned. - */ -mxGraph.prototype.isCellCollapsed = function(cell) -{ - return this.model.isCollapsed(cell); -}; - -/** - * Function: isCellConnectable - * - * Returns true if the given cell is connectable in this graph. This - * implementation uses <mxGraphModel.isConnectable>. Subclassers can override - * this to implement specific connectable states for cells in only one graph, - * that is, without affecting the connectable state of the cell in the model. - * - * Parameters: - * - * cell - <mxCell> whose connectable state should be returned. - */ -mxGraph.prototype.isCellConnectable = function(cell) -{ - return this.model.isConnectable(cell); -}; - -/** - * Function: isOrthogonal - * - * Returns true if perimeter points should be computed such that the - * resulting edge has only horizontal or vertical segments. - * - * Parameters: - * - * edge - <mxCellState> that represents the edge. - */ -mxGraph.prototype.isOrthogonal = function(edge) -{ - var orthogonal = edge.style[mxConstants.STYLE_ORTHOGONAL]; - - if (orthogonal != null) - { - return orthogonal; - } - - var tmp = this.view.getEdgeStyle(edge); - - return tmp == mxEdgeStyle.SegmentConnector || - tmp == mxEdgeStyle.ElbowConnector || - tmp == mxEdgeStyle.SideToSide || - tmp == mxEdgeStyle.TopToBottom || - tmp == mxEdgeStyle.EntityRelation || - tmp == mxEdgeStyle.OrthConnector; -}; - -/** - * Function: isLoop - * - * Returns true if the given cell state is a loop. - * - * Parameters: - * - * state - <mxCellState> that represents a potential loop. - */ -mxGraph.prototype.isLoop = function(state) -{ - var src = state.getVisibleTerminalState(true); - var trg = state.getVisibleTerminalState(false); - - return (src != null && src == trg); -}; - -/** - * Function: isCloneEvent - * - * Returns true if the given event is a clone event. This implementation - * returns true if control is pressed. - */ -mxGraph.prototype.isCloneEvent = function(evt) -{ - return mxEvent.isControlDown(evt); -}; - -/** - * Function: isToggleEvent - * - * Returns true if the given event is a toggle event. This implementation - * returns true if the meta key (Cmd) is pressed on Macs or if control is - * pressed on any other platform. - */ -mxGraph.prototype.isToggleEvent = function(evt) -{ - return (mxClient.IS_MAC) ? mxEvent.isMetaDown(evt) : mxEvent.isControlDown(evt); -}; - -/** - * Function: isGridEnabledEvent - * - * Returns true if the given mouse event should be aligned to the grid. - */ -mxGraph.prototype.isGridEnabledEvent = function(evt) -{ - return evt != null && !mxEvent.isAltDown(evt); -}; - -/** - * Function: isConstrainedEvent - * - * Returns true if the given mouse event should be aligned to the grid. - */ -mxGraph.prototype.isConstrainedEvent = function(evt) -{ - return mxEvent.isShiftDown(evt); -}; - -/** - * Function: isForceMarqueeEvent - * - * Returns true if the given event forces marquee selection. This implementation - * returns true if alt is pressed. - */ -mxGraph.prototype.isForceMarqueeEvent = function(evt) -{ - return mxEvent.isAltDown(evt); -}; - -/** - * Group: Validation - */ - -/** - * Function: validationAlert - * - * Displays the given validation error in a dialog. This implementation uses - * mxUtils.alert. - */ -mxGraph.prototype.validationAlert = function(message) -{ - mxUtils.alert(message); -}; - -/** - * Function: isEdgeValid - * - * Checks if the return value of <getEdgeValidationError> for the given - * arguments is null. - * - * Parameters: - * - * edge - <mxCell> that represents the edge to validate. - * source - <mxCell> that represents the source terminal. - * target - <mxCell> that represents the target terminal. - */ -mxGraph.prototype.isEdgeValid = function(edge, source, target) -{ - return this.getEdgeValidationError(edge, source, target) == null; -}; - -/** - * Function: getEdgeValidationError - * - * Returns the validation error message to be displayed when inserting or - * changing an edges' connectivity. A return value of null means the edge - * is valid, a return value of '' means it's not valid, but do not display - * an error message. Any other (non-empty) string returned from this method - * is displayed as an error message when trying to connect an edge to a - * source and target. This implementation uses the <multiplicities>, and - * checks <multigraph>, <allowDanglingEdges> and <allowLoops> to generate - * validation errors. - * - * For extending this method with specific checks for source/target cells, - * the method can be extended as follows. Returning an empty string means - * the edge is invalid with no error message, a non-null string specifies - * the error message, and null means the edge is valid. - * - * (code) - * graph.getEdgeValidationError = function(edge, source, target) - * { - * if (source != null && target != null && - * this.model.getValue(source) != null && - * this.model.getValue(target) != null) - * { - * if (target is not valid for source) - * { - * return 'Invalid Target'; - * } - * } - * - * // "Supercall" - * return mxGraph.prototype.getEdgeValidationError.apply(this, arguments); - * } - * (end) - * - * Parameters: - * - * edge - <mxCell> that represents the edge to validate. - * source - <mxCell> that represents the source terminal. - * target - <mxCell> that represents the target terminal. - */ -mxGraph.prototype.getEdgeValidationError = function(edge, source, target) -{ - if (edge != null && !this.isAllowDanglingEdges() && (source == null || target == null)) - { - return ''; - } - - if (edge != null && this.model.getTerminal(edge, true) == null && - this.model.getTerminal(edge, false) == null) - { - return null; - } - - // Checks if we're dealing with a loop - if (!this.allowLoops && source == target && source != null) - { - return ''; - } - - // Checks if the connection is generally allowed - if (!this.isValidConnection(source, target)) - { - return ''; - } - - if (source != null && target != null) - { - var error = ''; - - // Checks if the cells are already connected - // and adds an error message if required - if (!this.multigraph) - { - var tmp = this.model.getEdgesBetween(source, target, true); - - // Checks if the source and target are not connected by another edge - if (tmp.length > 1 || (tmp.length == 1 && tmp[0] != edge)) - { - error += (mxResources.get(this.alreadyConnectedResource) || - this.alreadyConnectedResource)+'\n'; - } - } - - // Gets the number of outgoing edges from the source - // and the number of incoming edges from the target - // without counting the edge being currently changed. - var sourceOut = this.model.getDirectedEdgeCount(source, true, edge); - var targetIn = this.model.getDirectedEdgeCount(target, false, edge); - - // Checks the change against each multiplicity rule - if (this.multiplicities != null) - { - for (var i = 0; i < this.multiplicities.length; i++) - { - var err = this.multiplicities[i].check(this, edge, source, - target, sourceOut, targetIn); - - if (err != null) - { - error += err; - } - } - } - - // Validates the source and target terminals independently - var err = this.validateEdge(edge, source, target); - - if (err != null) - { - error += err; - } - - return (error.length > 0) ? error : null; - } - - return (this.allowDanglingEdges) ? null : ''; -}; - -/** - * Function: validateEdge - * - * Hook method for subclassers to return an error message for the given - * edge and terminals. This implementation returns null. - * - * Parameters: - * - * edge - <mxCell> that represents the edge to validate. - * source - <mxCell> that represents the source terminal. - * target - <mxCell> that represents the target terminal. - */ -mxGraph.prototype.validateEdge = function(edge, source, target) -{ - return null; -}; - -/** - * Function: validateGraph - * - * Validates the graph by validating each descendant of the given cell or - * the root of the model. Context is an object that contains the validation - * state for the complete validation run. The validation errors are - * attached to their cells using <setCellWarning>. This function returns true - * if no validation errors exist in the graph. - * - * Paramters: - * - * cell - Optional <mxCell> to start the validation recursion. Default is - * the graph root. - * context - Object that represents the global validation state. - */ -mxGraph.prototype.validateGraph = function(cell, context) -{ - cell = (cell != null) ? cell : this.model.getRoot(); - context = (context != null) ? context : new Object(); - - var isValid = true; - var childCount = this.model.getChildCount(cell); - - for (var i = 0; i < childCount; i++) - { - var tmp = this.model.getChildAt(cell, i); - var ctx = context; - - if (this.isValidRoot(tmp)) - { - ctx = new Object(); - } - - var warn = this.validateGraph(tmp, ctx); - - if (warn != null) - { - this.setCellWarning(tmp, warn.replace(/\n/g, '<br>')); - } - else - { - this.setCellWarning(tmp, null); - } - - isValid = isValid && warn == null; - } - - var warning = ''; - - // Adds error for invalid children if collapsed (children invisible) - if (this.isCellCollapsed(cell) && !isValid) - { - warning += (mxResources.get(this.containsValidationErrorsResource) || - this.containsValidationErrorsResource)+'\n'; - } - - // Checks edges and cells using the defined multiplicities - if (this.model.isEdge(cell)) - { - warning += this.getEdgeValidationError(cell, - this.model.getTerminal(cell, true), - this.model.getTerminal(cell, false)) || ''; - } - else - { - warning += this.getCellValidationError(cell) || ''; - } - - // Checks custom validation rules - var err = this.validateCell(cell, context); - - if (err != null) - { - warning += err; - } - - // Updates the display with the warning icons - // before any potential alerts are displayed. - // LATER: Move this into addCellOverlay. Redraw - // should check if overlay was added or removed. - if (this.model.getParent(cell) == null) - { - this.view.validate(); - } - - return (warning.length > 0 || !isValid) ? warning : null; -}; - -/** - * Function: getCellValidationError - * - * Checks all <multiplicities> that cannot be enforced while the graph is - * being modified, namely, all multiplicities that require a minimum of - * 1 edge. - * - * Parameters: - * - * cell - <mxCell> for which the multiplicities should be checked. - */ -mxGraph.prototype.getCellValidationError = function(cell) -{ - var outCount = this.model.getDirectedEdgeCount(cell, true); - var inCount = this.model.getDirectedEdgeCount(cell, false); - var value = this.model.getValue(cell); - var error = ''; - - if (this.multiplicities != null) - { - for (var i = 0; i < this.multiplicities.length; i++) - { - var rule = this.multiplicities[i]; - - if (rule.source && mxUtils.isNode(value, rule.type, - rule.attr, rule.value) && ((rule.max == 0 && outCount > 0) || - (rule.min == 1 && outCount == 0) || (rule.max == 1 && outCount > 1))) - { - error += rule.countError + '\n'; - } - else if (!rule.source && mxUtils.isNode(value, rule.type, - rule.attr, rule.value) && ((rule.max == 0 && inCount > 0) || - (rule.min == 1 && inCount == 0) || (rule.max == 1 && inCount > 1))) - { - error += rule.countError + '\n'; - } - } - } - - return (error.length > 0) ? error : null; -}; - -/** - * Function: validateCell - * - * Hook method for subclassers to return an error message for the given - * cell and validation context. This implementation returns null. Any HTML - * breaks will be converted to linefeeds in the calling method. - * - * Parameters: - * - * cell - <mxCell> that represents the cell to validate. - * context - Object that represents the global validation state. - */ -mxGraph.prototype.validateCell = function(cell, context) -{ - return null; -}; - -/** - * Group: Graph appearance - */ - -/** - * Function: getBackgroundImage - * - * Returns the <backgroundImage> as an <mxImage>. - */ -mxGraph.prototype.getBackgroundImage = function() -{ - return this.backgroundImage; -}; - -/** - * Function: setBackgroundImage - * - * Sets the new <backgroundImage>. - * - * Parameters: - * - * image - New <mxImage> to be used for the background. - */ -mxGraph.prototype.setBackgroundImage = function(image) -{ - this.backgroundImage = image; -}; - -/** - * Function: getFoldingImage - * - * Returns the <mxImage> used to display the collapsed state of - * the specified cell state. This returns null for all edges. - */ -mxGraph.prototype.getFoldingImage = function(state) -{ - if (state != null && this.foldingEnabled && !this.getModel().isEdge(state.cell)) - { - var tmp = this.isCellCollapsed(state.cell); - - if (this.isCellFoldable(state.cell, !tmp)) - { - return (tmp) ? this.collapsedImage : this.expandedImage; - } - } - - return null; -}; - -/** - * Function: convertValueToString - * - * Returns the textual representation for the given cell. This - * implementation returns the nodename or string-representation of the user - * object. - * - * Example: - * - * The following returns the label attribute from the cells user - * object if it is an XML node. - * - * (code) - * graph.convertValueToString = function(cell) - * { - * return cell.getAttribute('label'); - * } - * (end) - * - * See also: <cellLabelChanged>. - * - * Parameters: - * - * cell - <mxCell> whose textual representation should be returned. - */ -mxGraph.prototype.convertValueToString = function(cell) -{ - var value = this.model.getValue(cell); - - if (value != null) - { - if (mxUtils.isNode(value)) - { - return value.nodeName; - } - else if (typeof(value.toString) == 'function') - { - return value.toString(); - } - } - - return ''; -}; - -/** - * Function: getLabel - * - * Returns a string or DOM node that represents the label for the given - * cell. This implementation uses <convertValueToString> if <labelsVisible> - * is true. Otherwise it returns an empty string. - * - * To truncate label to match the size of the cell, the following code - * can be used. - * - * (code) - * graph.getLabel = function(cell) - * { - * var label = mxGraph.prototype.getLabel.apply(this, arguments); - * - * if (label != null && this.model.isVertex(cell)) - * { - * var geo = this.getCellGeometry(cell); - * - * if (geo != null) - * { - * var max = parseInt(geo.width / 8); - * - * if (label.length > max) - * { - * label = label.substring(0, max)+'...'; - * } - * } - * } - * return mxUtils.htmlEntities(label); - * } - * (end) - * - * A resize listener is needed in the graph to force a repaint of the label - * after a resize. - * - * (code) - * graph.addListener(mxEvent.RESIZE_CELLS, function(sender, evt) - * { - * var cells = evt.getProperty('cells'); - * - * for (var i = 0; i < cells.length; i++) - * { - * this.view.removeState(cells[i]); - * } - * }); - * (end) - * - * Parameters: - * - * cell - <mxCell> whose label should be returned. - */ -mxGraph.prototype.getLabel = function(cell) -{ - var result = ''; - - if (this.labelsVisible && cell != null) - { - var state = this.view.getState(cell); - var style = (state != null) ? state.style : this.getCellStyle(cell); - - if (!mxUtils.getValue(style, mxConstants.STYLE_NOLABEL, false)) - { - result = this.convertValueToString(cell); - } - } - - return result; -}; - -/** - * Function: isHtmlLabel - * - * Returns true if the label must be rendered as HTML markup. The default - * implementation returns <htmlLabels>. - * - * Parameters: - * - * cell - <mxCell> whose label should be displayed as HTML markup. - */ -mxGraph.prototype.isHtmlLabel = function(cell) -{ - return this.isHtmlLabels(); -}; - -/** - * Function: isHtmlLabels - * - * Returns <htmlLabels>. - */ -mxGraph.prototype.isHtmlLabels = function() -{ - return this.htmlLabels; -}; - -/** - * Function: setHtmlLabels - * - * Sets <htmlLabels>. - */ -mxGraph.prototype.setHtmlLabels = function(value) -{ - this.htmlLabels = value; -}; - -/** - * Function: isWrapping - * - * This enables wrapping for HTML labels. - * - * Returns true if no white-space CSS style directive should be used for - * displaying the given cells label. This implementation returns true if - * <mxConstants.STYLE_WHITE_SPACE> in the style of the given cell is 'wrap'. - * - * This is used as a workaround for IE ignoring the white-space directive - * of child elements if the directive appears in a parent element. It - * should be overridden to return true if a white-space directive is used - * in the HTML markup that represents the given cells label. In order for - * HTML markup to work in labels, <isHtmlLabel> must also return true - * for the given cell. - * - * Example: - * - * (code) - * graph.getLabel = function(cell) - * { - * var tmp = mxGraph.prototype.getLabel.apply(this, arguments); // "supercall" - * - * if (this.model.isEdge(cell)) - * { - * tmp = '<div style="width: 150px; white-space:normal;">'+tmp+'</div>'; - * } - * - * return tmp; - * } - * - * graph.isWrapping = function(state) - * { - * return this.model.isEdge(state.cell); - * } - * (end) - * - * Makes sure no edge label is wider than 150 pixels, otherwise the content - * is wrapped. Note: No width must be specified for wrapped vertex labels as - * the vertex defines the width in its geometry. - * - * Parameters: - * - * state - <mxCell> whose label should be wrapped. - */ -mxGraph.prototype.isWrapping = function(cell) -{ - var state = this.view.getState(cell); - var style = (state != null) ? state.style : this.getCellStyle(cell); - - return (style != null) ? style[mxConstants.STYLE_WHITE_SPACE] == 'wrap' : false; -}; - -/** - * Function: isLabelClipped - * - * Returns true if the overflow portion of labels should be hidden. If this - * returns true then vertex labels will be clipped to the size of the vertices. - * This implementation returns true if <mxConstants.STYLE_OVERFLOW> in the - * style of the given cell is 'hidden'. - * - * Parameters: - * - * state - <mxCell> whose label should be clipped. - */ -mxGraph.prototype.isLabelClipped = function(cell) -{ - var state = this.view.getState(cell); - var style = (state != null) ? state.style : this.getCellStyle(cell); - - return (style != null) ? style[mxConstants.STYLE_OVERFLOW] == 'hidden' : false; -}; - -/** - * Function: getTooltip - * - * Returns the string or DOM node that represents the tooltip for the given - * state, node and coordinate pair. This implementation checks if the given - * node is a folding icon or overlay and returns the respective tooltip. If - * this does not result in a tooltip, the handler for the cell is retrieved - * from <selectionCellsHandler> and the optional getTooltipForNode method is - * called. If no special tooltip exists here then <getTooltipForCell> is used - * with the cell in the given state as the argument to return a tooltip for the - * given state. - * - * Parameters: - * - * state - <mxCellState> whose tooltip should be returned. - * node - DOM node that is currently under the mouse. - * x - X-coordinate of the mouse. - * y - Y-coordinate of the mouse. - */ -mxGraph.prototype.getTooltip = function(state, node, x, y) -{ - var tip = null; - - if (state != null) - { - // Checks if the mouse is over the folding icon - if (state.control != null && (node == state.control.node || - node.parentNode == state.control.node)) - { - tip = this.collapseExpandResource; - tip = mxResources.get(tip) || tip; - } - - if (tip == null && state.overlays != null) - { - state.overlays.visit(function(id, shape) - { - // LATER: Exit loop if tip is not null - if (tip == null && (node == shape.node || node.parentNode == shape.node)) - { - tip = shape.overlay.toString(); - } - }); - } - - if (tip == null) - { - var handler = this.selectionCellsHandler.getHandler(state.cell); - - if (handler != null && typeof(handler.getTooltipForNode) == 'function') - { - tip = handler.getTooltipForNode(node); - } - } - - if (tip == null) - { - tip = this.getTooltipForCell(state.cell); - } - } - - return tip; -}; - -/** - * Function: getTooltipForCell - * - * Returns the string or DOM node to be used as the tooltip for the given - * cell. This implementation uses the cells getTooltip function if it - * exists, or else it returns <convertValueToString> for the cell. - * - * Example: - * - * (code) - * graph.getTooltipForCell = function(cell) - * { - * return 'Hello, World!'; - * } - * (end) - * - * Replaces all tooltips with the string Hello, World! - * - * Parameters: - * - * cell - <mxCell> whose tooltip should be returned. - */ -mxGraph.prototype.getTooltipForCell = function(cell) -{ - var tip = null; - - if (cell != null && cell.getTooltip != null) - { - tip = cell.getTooltip(); - } - else - { - tip = this.convertValueToString(cell); - } - - return tip; -}; - -/** - * Function: getCursorForCell - * - * Returns the cursor value to be used for the CSS of the shape for the - * given cell. This implementation returns null. - * - * Parameters: - * - * cell - <mxCell> whose cursor should be returned. - */ -mxGraph.prototype.getCursorForCell = function(cell) -{ - return null; -}; - -/** - * Function: getStartSize - * - * Returns the start size of the given swimlane, that is, the width or - * height of the part that contains the title, depending on the - * horizontal style. The return value is an <mxRectangle> with either - * width or height set as appropriate. - * - * Parameters: - * - * swimlane - <mxCell> whose start size should be returned. - */ -mxGraph.prototype.getStartSize = function(swimlane) -{ - var result = new mxRectangle(); - var state = this.view.getState(swimlane); - var style = (state != null) ? state.style : this.getCellStyle(swimlane); - - if (style != null) - { - var size = parseInt(mxUtils.getValue(style, - mxConstants.STYLE_STARTSIZE, mxConstants.DEFAULT_STARTSIZE)); - - if (mxUtils.getValue(style, mxConstants.STYLE_HORIZONTAL, true)) - { - result.height = size; - } - else - { - result.width = size; - } - } - - return result; -}; - -/** - * Function: getImage - * - * Returns the image URL for the given cell state. This implementation - * returns the value stored under <mxConstants.STYLE_IMAGE> in the cell - * style. - * - * Parameters: - * - * state - <mxCellState> whose image URL should be returned. - */ -mxGraph.prototype.getImage = function(state) -{ - return (state != null && state.style != null) ? - state.style[mxConstants.STYLE_IMAGE] : null; -}; - -/** - * Function: getVerticalAlign - * - * Returns the vertical alignment for the given cell state. This - * implementation returns the value stored under - * <mxConstants.STYLE_VERTICAL_ALIGN> in the cell style. - * - * Parameters: - * - * state - <mxCellState> whose vertical alignment should be - * returned. - */ -mxGraph.prototype.getVerticalAlign = function(state) -{ - return (state != null && state.style != null) ? - (state.style[mxConstants.STYLE_VERTICAL_ALIGN] || - mxConstants.ALIGN_MIDDLE ): - null; -}; - -/** - * Function: getIndicatorColor - * - * Returns the indicator color for the given cell state. This - * implementation returns the value stored under - * <mxConstants.STYLE_INDICATOR_COLOR> in the cell style. - * - * Parameters: - * - * state - <mxCellState> whose indicator color should be - * returned. - */ -mxGraph.prototype.getIndicatorColor = function(state) -{ - return (state != null && state.style != null) ? - state.style[mxConstants.STYLE_INDICATOR_COLOR] : null; -}; - -/** - * Function: getIndicatorGradientColor - * - * Returns the indicator gradient color for the given cell state. This - * implementation returns the value stored under - * <mxConstants.STYLE_INDICATOR_GRADIENTCOLOR> in the cell style. - * - * Parameters: - * - * state - <mxCellState> whose indicator gradient color should be - * returned. - */ -mxGraph.prototype.getIndicatorGradientColor = function(state) -{ - return (state != null && state.style != null) ? - state.style[mxConstants.STYLE_INDICATOR_GRADIENTCOLOR] : null; -}; - -/** - * Function: getIndicatorShape - * - * Returns the indicator shape for the given cell state. This - * implementation returns the value stored under - * <mxConstants.STYLE_INDICATOR_SHAPE> in the cell style. - * - * Parameters: - * - * state - <mxCellState> whose indicator shape should be returned. - */ -mxGraph.prototype.getIndicatorShape = function(state) -{ - return (state != null && state.style != null) ? - state.style[mxConstants.STYLE_INDICATOR_SHAPE] : null; -}; - -/** - * Function: getIndicatorImage - * - * Returns the indicator image for the given cell state. This - * implementation returns the value stored under - * <mxConstants.STYLE_INDICATOR_IMAGE> in the cell style. - * - * Parameters: - * - * state - <mxCellState> whose indicator image should be returned. - */ -mxGraph.prototype.getIndicatorImage = function(state) -{ - return (state != null && state.style != null) ? - state.style[mxConstants.STYLE_INDICATOR_IMAGE] : null; -}; - -/** - * Function: getBorder - * - * Returns the value of <border>. - */ -mxGraph.prototype.getBorder = function() -{ - return this.border; -}; - -/** - * Function: setBorder - * - * Sets the value of <border>. - * - * Parameters: - * - * value - Positive integer that represents the border to be used. - */ -mxGraph.prototype.setBorder = function(value) -{ - this.border = value; -}; - -/** - * Function: isSwimlane - * - * Returns true if the given cell is a swimlane in the graph. A swimlane is - * a container cell with some specific behaviour. This implementation - * checks if the shape associated with the given cell is a <mxSwimlane>. - * - * Parameters: - * - * cell - <mxCell> to be checked. - */ -mxGraph.prototype.isSwimlane = function (cell) -{ - if (cell != null) - { - if (this.model.getParent(cell) != this.model.getRoot()) - { - var state = this.view.getState(cell); - var style = (state != null) ? state.style : this.getCellStyle(cell); - - if (style != null && !this.model.isEdge(cell)) - { - return style[mxConstants.STYLE_SHAPE] == - mxConstants.SHAPE_SWIMLANE; - } - } - } - - return false; -}; - -/** - * Group: Graph behaviour - */ - -/** - * Function: isResizeContainer - * - * Returns <resizeContainer>. - */ -mxGraph.prototype.isResizeContainer = function() -{ - return this.resizeContainer; -}; - -/** - * Function: setResizeContainer - * - * Sets <resizeContainer>. - * - * Parameters: - * - * value - Boolean indicating if the container should be resized. - */ -mxGraph.prototype.setResizeContainer = function(value) -{ - this.resizeContainer = value; -}; - -/** - * Function: isEnabled - * - * Returns true if the graph is <enabled>. - */ -mxGraph.prototype.isEnabled = function() -{ - return this.enabled; -}; - -/** - * Function: setEnabled - * - * Specifies if the graph should allow any interactions. This - * implementation updates <enabled>. - * - * Parameters: - * - * value - Boolean indicating if the graph should be enabled. - */ -mxGraph.prototype.setEnabled = function(value) -{ - this.enabled = value; -}; - -/** - * Function: isEscapeEnabled - * - * Returns <escapeEnabled>. - */ -mxGraph.prototype.isEscapeEnabled = function() -{ - return this.escapeEnabled; -}; - -/** - * Function: setEscapeEnabled - * - * Sets <escapeEnabled>. - * - * Parameters: - * - * enabled - Boolean indicating if escape should be enabled. - */ -mxGraph.prototype.setEscapeEnabled = function(value) -{ - this.escapeEnabled = value; -}; - -/** - * Function: isInvokesStopCellEditing - * - * Returns <invokesStopCellEditing>. - */ -mxGraph.prototype.isInvokesStopCellEditing = function() -{ - return this.invokesStopCellEditing; -}; - -/** - * Function: setInvokesStopCellEditing - * - * Sets <invokesStopCellEditing>. - */ -mxGraph.prototype.setInvokesStopCellEditing = function(value) -{ - this.invokesStopCellEditing = value; -}; - -/** - * Function: isEnterStopsCellEditing - * - * Returns <enterStopsCellEditing>. - */ -mxGraph.prototype.isEnterStopsCellEditing = function() -{ - return this.enterStopsCellEditing; -}; - -/** - * Function: setEnterStopsCellEditing - * - * Sets <enterStopsCellEditing>. - */ -mxGraph.prototype.setEnterStopsCellEditing = function(value) -{ - this.enterStopsCellEditing = value; -}; - -/** - * Function: isCellLocked - * - * Returns true if the given cell may not be moved, sized, bended, - * disconnected, edited or selected. This implementation returns true for - * all vertices with a relative geometry if <locked> is false. - * - * Parameters: - * - * cell - <mxCell> whose locked state should be returned. - */ -mxGraph.prototype.isCellLocked = function(cell) -{ - var geometry = this.model.getGeometry(cell); - - return this.isCellsLocked() || (geometry != null && - this.model.isVertex(cell) && geometry.relative); -}; - -/** - * Function: isCellsLocked - * - * Returns true if the given cell may not be moved, sized, bended, - * disconnected, edited or selected. This implementation returns true for - * all vertices with a relative geometry if <locked> is false. - * - * Parameters: - * - * cell - <mxCell> whose locked state should be returned. - */ -mxGraph.prototype.isCellsLocked = function() -{ - return this.cellsLocked; -}; - -/** - * Function: setLocked - * - * Sets if any cell may be moved, sized, bended, disconnected, edited or - * selected. - * - * Parameters: - * - * value - Boolean that defines the new value for <cellsLocked>. - */ -mxGraph.prototype.setCellsLocked = function(value) -{ - this.cellsLocked = value; -}; - -/** - * Function: getCloneableCells - * - * Returns the cells which may be exported in the given array of cells. - */ -mxGraph.prototype.getCloneableCells = function(cells) -{ - return this.model.filterCells(cells, mxUtils.bind(this, function(cell) - { - return this.isCellCloneable(cell); - })); -}; - -/** - * Function: isCellCloneable - * - * Returns true if the given cell is cloneable. This implementation returns - * <isCellsCloneable> for all cells unless a cell style specifies - * <mxConstants.STYLE_CLONEABLE> to be 0. - * - * Parameters: - * - * cell - Optional <mxCell> whose cloneable state should be returned. - */ -mxGraph.prototype.isCellCloneable = function(cell) -{ - var state = this.view.getState(cell); - var style = (state != null) ? state.style : this.getCellStyle(cell); - - return this.isCellsCloneable() && style[mxConstants.STYLE_CLONEABLE] != 0; -}; - -/** - * Function: isCellsCloneable - * - * Returns <cellsCloneable>, that is, if the graph allows cloning of cells - * by using control-drag. - */ -mxGraph.prototype.isCellsCloneable = function() -{ - return this.cellsCloneable; -}; - -/** - * Function: setCellsCloneable - * - * Specifies if the graph should allow cloning of cells by holding down the - * control key while cells are being moved. This implementation updates - * <cellsCloneable>. - * - * Parameters: - * - * value - Boolean indicating if the graph should be cloneable. - */ -mxGraph.prototype.setCellsCloneable = function(value) -{ - this.cellsCloneable = value; -}; - -/** - * Function: getExportableCells - * - * Returns the cells which may be exported in the given array of cells. - */ -mxGraph.prototype.getExportableCells = function(cells) -{ - return this.model.filterCells(cells, mxUtils.bind(this, function(cell) - { - return this.canExportCell(cell); - })); -}; - -/** - * Function: canExportCell - * - * Returns true if the given cell may be exported to the clipboard. This - * implementation returns <exportEnabled> for all cells. - * - * Parameters: - * - * cell - <mxCell> that represents the cell to be exported. - */ -mxGraph.prototype.canExportCell = function(cell) -{ - return this.exportEnabled; -}; - -/** - * Function: getImportableCells - * - * Returns the cells which may be imported in the given array of cells. - */ -mxGraph.prototype.getImportableCells = function(cells) -{ - return this.model.filterCells(cells, mxUtils.bind(this, function(cell) - { - return this.canImportCell(cell); - })); -}; - -/** - * Function: canImportCell - * - * Returns true if the given cell may be imported from the clipboard. - * This implementation returns <importEnabled> for all cells. - * - * Parameters: - * - * cell - <mxCell> that represents the cell to be imported. - */ -mxGraph.prototype.canImportCell = function(cell) -{ - return this.importEnabled; -}; - -/** - * Function: isCellSelectable - * - * Returns true if the given cell is selectable. This implementation - * returns <cellsSelectable>. - * - * To add a new style for making cells (un)selectable, use the following code. - * - * (code) - * mxGraph.prototype.isCellSelectable = function(cell) - * { - * var state = this.view.getState(cell); - * var style = (state != null) ? state.style : this.getCellStyle(cell); - * - * return this.isCellsSelectable() && !this.isCellLocked(cell) && style['selectable'] != 0; - * }; - * (end) - * - * You can then use the new style as shown in this example. - * - * (code) - * graph.insertVertex(parent, null, 'Hello,', 20, 20, 80, 30, 'selectable=0'); - * (end) - * - * Parameters: - * - * cell - <mxCell> whose selectable state should be returned. - */ -mxGraph.prototype.isCellSelectable = function(cell) -{ - return this.isCellsSelectable(); -}; - -/** - * Function: isCellsSelectable - * - * Returns <cellsSelectable>. - */ -mxGraph.prototype.isCellsSelectable = function() -{ - return this.cellsSelectable; -}; - -/** - * Function: setCellsSelectable - * - * Sets <cellsSelectable>. - */ -mxGraph.prototype.setCellsSelectable = function(value) -{ - this.cellsSelectable = value; -}; - -/** - * Function: getDeletableCells - * - * Returns the cells which may be exported in the given array of cells. - */ -mxGraph.prototype.getDeletableCells = function(cells) -{ - return this.model.filterCells(cells, mxUtils.bind(this, function(cell) - { - return this.isCellDeletable(cell); - })); -}; - -/** - * Function: isCellDeletable - * - * Returns true if the given cell is moveable. This returns - * <cellsDeletable> for all given cells if a cells style does not specify - * <mxConstants.STYLE_DELETABLE> to be 0. - * - * Parameters: - * - * cell - <mxCell> whose deletable state should be returned. - */ -mxGraph.prototype.isCellDeletable = function(cell) -{ - var state = this.view.getState(cell); - var style = (state != null) ? state.style : this.getCellStyle(cell); - - return this.isCellsDeletable() && style[mxConstants.STYLE_DELETABLE] != 0; -}; - -/** - * Function: isCellsDeletable - * - * Returns <cellsDeletable>. - */ -mxGraph.prototype.isCellsDeletable = function() -{ - return this.cellsDeletable; -}; - -/** - * Function: setCellsDeletable - * - * Sets <cellsDeletable>. - * - * Parameters: - * - * value - Boolean indicating if the graph should allow deletion of cells. - */ -mxGraph.prototype.setCellsDeletable = function(value) -{ - this.cellsDeletable = value; -}; - -/** - * Function: isLabelMovable - * - * Returns true if the given edges's label is moveable. This returns - * <movable> for all given cells if <isLocked> does not return true - * for the given cell. - * - * Parameters: - * - * cell - <mxCell> whose label should be moved. - */ -mxGraph.prototype.isLabelMovable = function(cell) -{ - return !this.isCellLocked(cell) && - ((this.model.isEdge(cell) && this.edgeLabelsMovable) || - (this.model.isVertex(cell) && this.vertexLabelsMovable)); -}; - -/** - * Function: getMovableCells - * - * Returns the cells which are movable in the given array of cells. - */ -mxGraph.prototype.getMovableCells = function(cells) -{ - return this.model.filterCells(cells, mxUtils.bind(this, function(cell) - { - return this.isCellMovable(cell); - })); -}; - -/** - * Function: isCellMovable - * - * Returns true if the given cell is moveable. This returns <cellsMovable> - * for all given cells if <isCellLocked> does not return true for the given - * cell and its style does not specify <mxConstants.STYLE_MOVABLE> to be 0. - * - * Parameters: - * - * cell - <mxCell> whose movable state should be returned. - */ -mxGraph.prototype.isCellMovable = function(cell) -{ - var state = this.view.getState(cell); - var style = (state != null) ? state.style : this.getCellStyle(cell); - - return this.isCellsMovable() && !this.isCellLocked(cell) && style[mxConstants.STYLE_MOVABLE] != 0; -}; - -/** - * Function: isCellsMovable - * - * Returns <cellsMovable>. - */ -mxGraph.prototype.isCellsMovable = function() -{ - return this.cellsMovable; -}; - -/** - * Function: setCellsMovable - * - * Specifies if the graph should allow moving of cells. This implementation - * updates <cellsMsovable>. - * - * Parameters: - * - * value - Boolean indicating if the graph should allow moving of cells. - */ -mxGraph.prototype.setCellsMovable = function(value) -{ - this.cellsMovable = value; -}; - -/** - * Function: isGridEnabled - * - * Returns <gridEnabled> as a boolean. - */ -mxGraph.prototype.isGridEnabled = function() -{ - return this.gridEnabled; -}; - -/** - * Function: setGridEnabled - * - * Specifies if the grid should be enabled. - * - * Parameters: - * - * value - Boolean indicating if the grid should be enabled. - */ -mxGraph.prototype.setGridEnabled = function(value) -{ - this.gridEnabled = value; -}; - -/** - * Function: isPortsEnabled - * - * Returns <portsEnabled> as a boolean. - */ -mxGraph.prototype.isPortsEnabled = function() -{ - return this.portsEnabled; -}; - -/** - * Function: setPortsEnabled - * - * Specifies if the ports should be enabled. - * - * Parameters: - * - * value - Boolean indicating if the ports should be enabled. - */ -mxGraph.prototype.setPortsEnabled = function(value) -{ - this.portsEnabled = value; -}; - -/** - * Function: getGridSize - * - * Returns <gridSize>. - */ -mxGraph.prototype.getGridSize = function() -{ - return this.gridSize; -}; - -/** - * Function: setGridSize - * - * Sets <gridSize>. - */ -mxGraph.prototype.setGridSize = function(value) -{ - this.gridSize = value; -}; - -/** - * Function: getTolerance - * - * Returns <tolerance>. - */ -mxGraph.prototype.getTolerance = function() -{ - return this.tolerance; -}; - -/** - * Function: setTolerance - * - * Sets <tolerance>. - */ -mxGraph.prototype.setTolerance = function(value) -{ - this.tolerance = value; -}; - -/** - * Function: isVertexLabelsMovable - * - * Returns <vertexLabelsMovable>. - */ -mxGraph.prototype.isVertexLabelsMovable = function() -{ - return this.vertexLabelsMovable; -}; - -/** - * Function: setVertexLabelsMovable - * - * Sets <vertexLabelsMovable>. - */ -mxGraph.prototype.setVertexLabelsMovable = function(value) -{ - this.vertexLabelsMovable = value; -}; - -/** - * Function: isEdgeLabelsMovable - * - * Returns <edgeLabelsMovable>. - */ -mxGraph.prototype.isEdgeLabelsMovable = function() -{ - return this.edgeLabelsMovable; -}; - -/** - * Function: isEdgeLabelsMovable - * - * Sets <edgeLabelsMovable>. - */ -mxGraph.prototype.setEdgeLabelsMovable = function(value) -{ - this.edgeLabelsMovable = value; -}; - -/** - * Function: isSwimlaneNesting - * - * Returns <swimlaneNesting> as a boolean. - */ -mxGraph.prototype.isSwimlaneNesting = function() -{ - return this.swimlaneNesting; -}; - -/** - * Function: setSwimlaneNesting - * - * Specifies if swimlanes can be nested by drag and drop. This is only - * taken into account if dropEnabled is true. - * - * Parameters: - * - * value - Boolean indicating if swimlanes can be nested. - */ -mxGraph.prototype.setSwimlaneNesting = function(value) -{ - this.swimlaneNesting = value; -}; - -/** - * Function: isSwimlaneSelectionEnabled - * - * Returns <swimlaneSelectionEnabled> as a boolean. - */ -mxGraph.prototype.isSwimlaneSelectionEnabled = function() -{ - return this.swimlaneSelectionEnabled; -}; - -/** - * Function: setSwimlaneSelectionEnabled - * - * Specifies if swimlanes should be selected if the mouse is released - * over their content area. - * - * Parameters: - * - * value - Boolean indicating if swimlanes content areas - * should be selected when the mouse is released over them. - */ -mxGraph.prototype.setSwimlaneSelectionEnabled = function(value) -{ - this.swimlaneSelectionEnabled = value; -}; - -/** - * Function: isMultigraph - * - * Returns <multigraph> as a boolean. - */ -mxGraph.prototype.isMultigraph = function() -{ - return this.multigraph; -}; - -/** - * Function: setMultigraph - * - * Specifies if the graph should allow multiple connections between the - * same pair of vertices. - * - * Parameters: - * - * value - Boolean indicating if the graph allows multiple connections - * between the same pair of vertices. - */ -mxGraph.prototype.setMultigraph = function(value) -{ - this.multigraph = value; -}; - -/** - * Function: isAllowLoops - * - * Returns <allowLoops> as a boolean. - */ -mxGraph.prototype.isAllowLoops = function() -{ - return this.allowLoops; -}; - -/** - * Function: setAllowDanglingEdges - * - * Specifies if dangling edges are allowed, that is, if edges are allowed - * that do not have a source and/or target terminal defined. - * - * Parameters: - * - * value - Boolean indicating if dangling edges are allowed. - */ -mxGraph.prototype.setAllowDanglingEdges = function(value) -{ - this.allowDanglingEdges = value; -}; - -/** - * Function: isAllowDanglingEdges - * - * Returns <allowDanglingEdges> as a boolean. - */ -mxGraph.prototype.isAllowDanglingEdges = function() -{ - return this.allowDanglingEdges; -}; - -/** - * Function: setConnectableEdges - * - * Specifies if edges should be connectable. - * - * Parameters: - * - * value - Boolean indicating if edges should be connectable. - */ -mxGraph.prototype.setConnectableEdges = function(value) -{ - this.connectableEdges = value; -}; - -/** - * Function: isConnectableEdges - * - * Returns <connectableEdges> as a boolean. - */ -mxGraph.prototype.isConnectableEdges = function() -{ - return this.connectableEdges; -}; - -/** - * Function: setCloneInvalidEdges - * - * Specifies if edges should be inserted when cloned but not valid wrt. - * <getEdgeValidationError>. If false such edges will be silently ignored. - * - * Parameters: - * - * value - Boolean indicating if cloned invalid edges should be - * inserted into the graph or ignored. - */ -mxGraph.prototype.setCloneInvalidEdges = function(value) -{ - this.cloneInvalidEdges = value; -}; - -/** - * Function: isCloneInvalidEdges - * - * Returns <cloneInvalidEdges> as a boolean. - */ -mxGraph.prototype.isCloneInvalidEdges = function() -{ - return this.cloneInvalidEdges; -}; - -/** - * Function: setAllowLoops - * - * Specifies if loops are allowed. - * - * Parameters: - * - * value - Boolean indicating if loops are allowed. - */ -mxGraph.prototype.setAllowLoops = function(value) -{ - this.allowLoops = value; -}; - -/** - * Function: isDisconnectOnMove - * - * Returns <disconnectOnMove> as a boolean. - */ -mxGraph.prototype.isDisconnectOnMove = function() -{ - return this.disconnectOnMove; -}; - -/** - * Function: setDisconnectOnMove - * - * Specifies if edges should be disconnected when moved. (Note: Cloned - * edges are always disconnected.) - * - * Parameters: - * - * value - Boolean indicating if edges should be disconnected - * when moved. - */ -mxGraph.prototype.setDisconnectOnMove = function(value) -{ - this.disconnectOnMove = value; -}; - -/** - * Function: isDropEnabled - * - * Returns <dropEnabled> as a boolean. - */ -mxGraph.prototype.isDropEnabled = function() -{ - return this.dropEnabled; -}; - -/** - * Function: setDropEnabled - * - * Specifies if the graph should allow dropping of cells onto or into other - * cells. - * - * Parameters: - * - * dropEnabled - Boolean indicating if the graph should allow dropping - * of cells into other cells. - */ -mxGraph.prototype.setDropEnabled = function(value) -{ - this.dropEnabled = value; -}; - -/** - * Function: isSplitEnabled - * - * Returns <splitEnabled> as a boolean. - */ -mxGraph.prototype.isSplitEnabled = function() -{ - return this.splitEnabled; -}; - -/** - * Function: setSplitEnabled - * - * Specifies if the graph should allow dropping of cells onto or into other - * cells. - * - * Parameters: - * - * dropEnabled - Boolean indicating if the graph should allow dropping - * of cells into other cells. - */ -mxGraph.prototype.setSplitEnabled = function(value) -{ - this.splitEnabled = value; -}; - -/** - * Function: isCellResizable - * - * Returns true if the given cell is resizable. This returns - * <cellsResizable> for all given cells if <isCellLocked> does not return - * true for the given cell and its style does not specify - * <mxConstants.STYLE_RESIZABLE> to be 0. - * - * Parameters: - * - * cell - <mxCell> whose resizable state should be returned. - */ -mxGraph.prototype.isCellResizable = function(cell) -{ - var state = this.view.getState(cell); - var style = (state != null) ? state.style : this.getCellStyle(cell); - - return this.isCellsResizable() && !this.isCellLocked(cell) && style[mxConstants.STYLE_RESIZABLE] != 0; -}; - -/** - * Function: isCellsResizable - * - * Returns <cellsResizable>. - */ -mxGraph.prototype.isCellsResizable = function() -{ - return this.cellsResizable; -}; - -/** - * Function: setCellsResizable - * - * Specifies if the graph should allow resizing of cells. This - * implementation updates <cellsResizable>. - * - * Parameters: - * - * value - Boolean indicating if the graph should allow resizing of - * cells. - */ -mxGraph.prototype.setCellsResizable = function(value) -{ - this.cellsResizable = value; -}; - -/** - * Function: isTerminalPointMovable - * - * Returns true if the given terminal point is movable. This is independent - * from <isCellConnectable> and <isCellDisconnectable> and controls if terminal - * points can be moved in the graph if the edge is not connected. Note that it - * is required for this to return true to connect unconnected edges. This - * implementation returns true. - * - * Parameters: - * - * cell - <mxCell> whose terminal point should be moved. - * source - Boolean indicating if the source or target terminal should be moved. - */ -mxGraph.prototype.isTerminalPointMovable = function(cell, source) -{ - return true; -}; - -/** - * Function: isCellBendable - * - * Returns true if the given cell is bendable. This returns <cellsBendable> - * for all given cells if <isLocked> does not return true for the given - * cell and its style does not specify <mxConstants.STYLE_BENDABLE> to be 0. - * - * Parameters: - * - * cell - <mxCell> whose bendable state should be returned. - */ -mxGraph.prototype.isCellBendable = function(cell) -{ - var state = this.view.getState(cell); - var style = (state != null) ? state.style : this.getCellStyle(cell); - - return this.isCellsBendable() && !this.isCellLocked(cell) && style[mxConstants.STYLE_BENDABLE] != 0; -}; - -/** - * Function: isCellsBendable - * - * Returns <cellsBenadable>. - */ -mxGraph.prototype.isCellsBendable = function() -{ - return this.cellsBendable; -}; - -/** - * Function: setCellsBendable - * - * Specifies if the graph should allow bending of edges. This - * implementation updates <bendable>. - * - * Parameters: - * - * value - Boolean indicating if the graph should allow bending of - * edges. - */ -mxGraph.prototype.setCellsBendable = function(value) -{ - this.cellsBendable = value; -}; - -/** - * Function: isCellEditable - * - * Returns true if the given cell is editable. This returns <cellsEditable> for - * all given cells if <isCellLocked> does not return true for the given cell - * and its style does not specify <mxConstants.STYLE_EDITABLE> to be 0. - * - * Parameters: - * - * cell - <mxCell> whose editable state should be returned. - */ -mxGraph.prototype.isCellEditable = function(cell) -{ - var state = this.view.getState(cell); - var style = (state != null) ? state.style : this.getCellStyle(cell); - - return this.isCellsEditable() && !this.isCellLocked(cell) && style[mxConstants.STYLE_EDITABLE] != 0; -}; - -/** - * Function: isCellsEditable - * - * Returns <cellsEditable>. - */ -mxGraph.prototype.isCellsEditable = function() -{ - return this.cellsEditable; -}; - -/** - * Function: setCellsEditable - * - * Specifies if the graph should allow in-place editing for cell labels. - * This implementation updates <cellsEditable>. - * - * Parameters: - * - * value - Boolean indicating if the graph should allow in-place - * editing. - */ -mxGraph.prototype.setCellsEditable = function(value) -{ - this.cellsEditable = value; -}; - -/** - * Function: isCellDisconnectable - * - * Returns true if the given cell is disconnectable from the source or - * target terminal. This returns <isCellsDisconnectable> for all given - * cells if <isCellLocked> does not return true for the given cell. - * - * Parameters: - * - * cell - <mxCell> whose disconnectable state should be returned. - * terminal - <mxCell> that represents the source or target terminal. - * source - Boolean indicating if the source or target terminal is to be - * disconnected. - */ -mxGraph.prototype.isCellDisconnectable = function(cell, terminal, source) -{ - return this.isCellsDisconnectable() && !this.isCellLocked(cell); -}; - -/** - * Function: isCellsDisconnectable - * - * Returns <cellsDisconnectable>. - */ -mxGraph.prototype.isCellsDisconnectable = function() -{ - return this.cellsDisconnectable; -}; - -/** - * Function: setCellsDisconnectable - * - * Sets <cellsDisconnectable>. - */ -mxGraph.prototype.setCellsDisconnectable = function(value) -{ - this.cellsDisconnectable = value; -}; - -/** - * Function: isValidSource - * - * Returns true if the given cell is a valid source for new connections. - * This implementation returns true for all non-null values and is - * called by is called by <isValidConnection>. - * - * Parameters: - * - * cell - <mxCell> that represents a possible source or null. - */ -mxGraph.prototype.isValidSource = function(cell) -{ - return (cell == null && this.allowDanglingEdges) || - (cell != null && (!this.model.isEdge(cell) || - this.connectableEdges) && this.isCellConnectable(cell)); -}; - -/** - * Function: isValidTarget - * - * Returns <isValidSource> for the given cell. This is called by - * <isValidConnection>. - * - * Parameters: - * - * cell - <mxCell> that represents a possible target or null. - */ -mxGraph.prototype.isValidTarget = function(cell) -{ - return this.isValidSource(cell); -}; - -/** - * Function: isValidConnection - * - * Returns true if the given target cell is a valid target for source. - * This is a boolean implementation for not allowing connections between - * certain pairs of vertices and is called by <getEdgeValidationError>. - * This implementation returns true if <isValidSource> returns true for - * the source and <isValidTarget> returns true for the target. - * - * Parameters: - * - * source - <mxCell> that represents the source cell. - * target - <mxCell> that represents the target cell. - */ -mxGraph.prototype.isValidConnection = function(source, target) -{ - return this.isValidSource(source) && this.isValidTarget(target); -}; - -/** - * Function: setConnectable - * - * Specifies if the graph should allow new connections. This implementation - * updates <mxConnectionHandler.enabled> in <connectionHandler>. - * - * Parameters: - * - * connectable - Boolean indicating if new connections should be allowed. - */ -mxGraph.prototype.setConnectable = function(connectable) -{ - this.connectionHandler.setEnabled(connectable); -}; - -/** - * Function: isConnectable - * - * Returns true if the <connectionHandler> is enabled. - */ -mxGraph.prototype.isConnectable = function(connectable) -{ - return this.connectionHandler.isEnabled(); -}; - -/** - * Function: setTooltips - * - * Specifies if tooltips should be enabled. This implementation updates - * <mxTooltipHandler.enabled> in <tooltipHandler>. - * - * Parameters: - * - * enabled - Boolean indicating if tooltips should be enabled. - */ -mxGraph.prototype.setTooltips = function (enabled) -{ - this.tooltipHandler.setEnabled(enabled); -}; - -/** - * Function: setPanning - * - * Specifies if panning should be enabled. This implementation updates - * <mxPanningHandler.panningEnabled> in <panningHandler>. - * - * Parameters: - * - * enabled - Boolean indicating if panning should be enabled. - */ -mxGraph.prototype.setPanning = function(enabled) -{ - this.panningHandler.panningEnabled = enabled; -}; - -/** - * Function: isEditing - * - * Returns true if the given cell is currently being edited. - * If no cell is specified then this returns true if any - * cell is currently being edited. - * - * Parameters: - * - * cell - <mxCell> that should be checked. - */ -mxGraph.prototype.isEditing = function(cell) -{ - if (this.cellEditor != null) - { - var editingCell = this.cellEditor.getEditingCell(); - - return (cell == null) ? - editingCell != null : - cell == editingCell; - } - - return false; -}; - -/** - * Function: isAutoSizeCell - * - * Returns true if the size of the given cell should automatically be - * updated after a change of the label. This implementation returns - * <autoSizeCells> or checks if the cell style does specify - * <mxConstants.STYLE_AUTOSIZE> to be 1. - * - * Parameters: - * - * cell - <mxCell> that should be resized. - */ -mxGraph.prototype.isAutoSizeCell = function(cell) -{ - var state = this.view.getState(cell); - var style = (state != null) ? state.style : this.getCellStyle(cell); - - return this.isAutoSizeCells() || style[mxConstants.STYLE_AUTOSIZE] == 1; -}; - -/** - * Function: isAutoSizeCells - * - * Returns <autoSizeCells>. - */ -mxGraph.prototype.isAutoSizeCells = function() -{ - return this.autoSizeCells; -}; - -/** - * Function: setAutoSizeCells - * - * Specifies if cell sizes should be automatically updated after a label - * change. This implementation sets <autoSizeCells> to the given parameter. - * - * Parameters: - * - * value - Boolean indicating if cells should be resized - * automatically. - */ -mxGraph.prototype.setAutoSizeCells = function(value) -{ - this.autoSizeCells = value; -}; - -/** - * Function: isExtendParent - * - * Returns true if the parent of the given cell should be extended if the - * child has been resized so that it overlaps the parent. This - * implementation returns <isExtendParents> if the cell is not an edge. - * - * Parameters: - * - * cell - <mxCell> that has been resized. - */ -mxGraph.prototype.isExtendParent = function(cell) -{ - return !this.getModel().isEdge(cell) && this.isExtendParents(); -}; - -/** - * Function: isExtendParents - * - * Returns <extendParents>. - */ -mxGraph.prototype.isExtendParents = function() -{ - return this.extendParents; -}; - -/** - * Function: setExtendParents - * - * Sets <extendParents>. - * - * Parameters: - * - * value - New boolean value for <extendParents>. - */ -mxGraph.prototype.setExtendParents = function(value) -{ - this.extendParents = value; -}; - -/** - * Function: isExtendParentsOnAdd - * - * Returns <extendParentsOnAdd>. - */ -mxGraph.prototype.isExtendParentsOnAdd = function() -{ - return this.extendParentsOnAdd; -}; - -/** - * Function: setExtendParentsOnAdd - * - * Sets <extendParentsOnAdd>. - * - * Parameters: - * - * value - New boolean value for <extendParentsOnAdd>. - */ -mxGraph.prototype.setExtendParentsOnAdd = function(value) -{ - this.extendParentsOnAdd = value; -}; - -/** - * Function: isConstrainChild - * - * Returns true if the given cell should be kept inside the bounds of its - * parent according to the rules defined by <getOverlap> and - * <isAllowOverlapParent>. This implementation returns false for all children - * of edges and <isConstrainChildren> otherwise. - * - * Parameters: - * - * cell - <mxCell> that should be constrained. - */ -mxGraph.prototype.isConstrainChild = function(cell) -{ - return this.isConstrainChildren() && !this.getModel().isEdge(this.getModel().getParent(cell)); - -}; - -/** - * Function: isConstrainChildren - * - * Returns <constrainChildren>. - */ -mxGraph.prototype.isConstrainChildren = function() -{ - return this.constrainChildren; -}; - -/** - * Function: setConstrainChildren - * - * Sets <constrainChildren>. - */ -mxGraph.prototype.setConstrainChildren = function(value) -{ - this.constrainChildren = value; -}; - -/** - * Function: isConstrainChildren - * - * Returns <allowNegativeCoordinates>. - */ -mxGraph.prototype.isAllowNegativeCoordinates = function() -{ - return this.allowNegativeCoordinates; -}; - -/** - * Function: setConstrainChildren - * - * Sets <allowNegativeCoordinates>. - */ -mxGraph.prototype.setAllowNegativeCoordinates = function(value) -{ - this.allowNegativeCoordinates = value; -}; - -/** - * Function: getOverlap - * - * Returns a decimal number representing the amount of the width and height - * of the given cell that is allowed to overlap its parent. A value of 0 - * means all children must stay inside the parent, 1 means the child is - * allowed to be placed outside of the parent such that it touches one of - * the parents sides. If <isAllowOverlapParent> returns false for the given - * cell, then this method returns 0. - * - * Parameters: - * - * cell - <mxCell> for which the overlap ratio should be returned. - */ -mxGraph.prototype.getOverlap = function(cell) -{ - return (this.isAllowOverlapParent(cell)) ? this.defaultOverlap : 0; -}; - -/** - * Function: isAllowOverlapParent - * - * Returns true if the given cell is allowed to be placed outside of the - * parents area. - * - * Parameters: - * - * cell - <mxCell> that represents the child to be checked. - */ -mxGraph.prototype.isAllowOverlapParent = function(cell) -{ - return false; -}; - -/** - * Function: getFoldableCells - * - * Returns the cells which are movable in the given array of cells. - */ -mxGraph.prototype.getFoldableCells = function(cells, collapse) -{ - return this.model.filterCells(cells, mxUtils.bind(this, function(cell) - { - return this.isCellFoldable(cell, collapse); - })); -}; - -/** - * Function: isCellFoldable - * - * Returns true if the given cell is foldable. This implementation - * returns true if the cell has at least one child and its style - * does not specify <mxConstants.STYLE_FOLDABLE> to be 0. - * - * Parameters: - * - * cell - <mxCell> whose foldable state should be returned. - */ -mxGraph.prototype.isCellFoldable = function(cell, collapse) -{ - var state = this.view.getState(cell); - var style = (state != null) ? state.style : this.getCellStyle(cell); - - return this.model.getChildCount(cell) > 0 && style[mxConstants.STYLE_FOLDABLE] != 0; -}; - -/** - * Function: isValidDropTarget - * - * Returns true if the given cell is a valid drop target for the specified - * cells. If the given cell is an edge, then <isSplitDropTarget> is used, - * else <isParentDropTarget> is used to compute the return value. - * - * Parameters: - * - * cell - <mxCell> that represents the possible drop target. - * cells - <mxCells> that should be dropped into the target. - * evt - Mouseevent that triggered the invocation. - */ -mxGraph.prototype.isValidDropTarget = function(cell, cells, evt) -{ - return cell != null && ((this.isSplitEnabled() && - this.isSplitTarget(cell, cells, evt)) || (!this.model.isEdge(cell) && - (this.isSwimlane(cell) || (this.model.getChildCount(cell) > 0 && - !this.isCellCollapsed(cell))))); -}; - -/** - * Function: isSplitTarget - * - * Returns true if the given edge may be splitted into two edges with the - * given cell as a new terminal between the two. - * - * Parameters: - * - * target - <mxCell> that represents the edge to be splitted. - * cells - <mxCells> that should split the edge. - * evt - Mouseevent that triggered the invocation. - */ -mxGraph.prototype.isSplitTarget = function(target, cells, evt) -{ - if (this.model.isEdge(target) && cells != null && cells.length == 1 && - this.isCellConnectable(cells[0]) && this.getEdgeValidationError(target, - this.model.getTerminal(target, true), cells[0]) == null) - { - var src = this.model.getTerminal(target, true); - var trg = this.model.getTerminal(target, false); - - return (!this.model.isAncestor(cells[0], src) && - !this.model.isAncestor(cells[0], trg)); - } - - return false; -}; - -/** - * Function: getDropTarget - * - * Returns the given cell if it is a drop target for the given cells or the - * nearest ancestor that may be used as a drop target for the given cells. - * If the given array contains a swimlane and <swimlaneNesting> is false - * then this always returns null. If no cell is given, then the bottommost - * swimlane at the location of the given event is returned. - * - * This function should only be used if <isDropEnabled> returns true. - * - * Parameters: - * - * cells - Array of <mxCells> which are to be dropped onto the target. - * evt - Mouseevent for the drag and drop. - * cell - <mxCell> that is under the mousepointer. - */ -mxGraph.prototype.getDropTarget = function(cells, evt, cell) -{ - if (!this.isSwimlaneNesting()) - { - for (var i = 0; i < cells.length; i++) - { - if (this.isSwimlane(cells[i])) - { - return null; - } - } - } - - var pt = mxUtils.convertPoint(this.container, - mxEvent.getClientX(evt), mxEvent.getClientY(evt)); - pt.x -= this.panDx; - pt.y -= this.panDy; - var swimlane = this.getSwimlaneAt(pt.x, pt.y); - - if (cell == null) - { - cell = swimlane; - } - else if (swimlane != null) - { - // Checks if the cell is an ancestor of the swimlane - // under the mouse and uses the swimlane in that case - var tmp = this.model.getParent(swimlane); - - while (tmp != null && this.isSwimlane(tmp) && tmp != cell) - { - tmp = this.model.getParent(tmp); - } - - if (tmp == cell) - { - cell = swimlane; - } - } - - while (cell != null && !this.isValidDropTarget(cell, cells, evt) && - !this.model.isLayer(cell)) - { - cell = this.model.getParent(cell); - } - - return (!this.model.isLayer(cell) && mxUtils.indexOf(cells, cell) < 0) ? cell : null; -}; - -/** - * Group: Cell retrieval - */ - -/** - * Function: getDefaultParent - * - * Returns <defaultParent> or <mxGraphView.currentRoot> or the first child - * child of <mxGraphModel.root> if both are null. The value returned by - * this function should be used as the parent for new cells (aka default - * layer). - */ -mxGraph.prototype.getDefaultParent = function() -{ - var parent = this.defaultParent; - - if (parent == null) - { - parent = this.getCurrentRoot(); - - if (parent == null) - { - var root = this.model.getRoot(); - parent = this.model.getChildAt(root, 0); - } - } - - return parent; -}; - -/** - * Function: setDefaultParent - * - * Sets the <defaultParent> to the given cell. Set this to null to return - * the first child of the root in getDefaultParent. - */ -mxGraph.prototype.setDefaultParent = function(cell) -{ - this.defaultParent = cell; -}; - -/** - * Function: getSwimlane - * - * Returns the nearest ancestor of the given cell which is a swimlane, or - * the given cell, if it is itself a swimlane. - * - * Parameters: - * - * cell - <mxCell> for which the ancestor swimlane should be returned. - */ -mxGraph.prototype.getSwimlane = function(cell) -{ - while (cell != null && !this.isSwimlane(cell)) - { - cell = this.model.getParent(cell); - } - - return cell; -}; - -/** - * Function: getSwimlaneAt - * - * Returns the bottom-most swimlane that intersects the given point (x, y) - * in the cell hierarchy that starts at the given parent. - * - * Parameters: - * - * x - X-coordinate of the location to be checked. - * y - Y-coordinate of the location to be checked. - * parent - <mxCell> that should be used as the root of the recursion. - * Default is <defaultParent>. - */ -mxGraph.prototype.getSwimlaneAt = function (x, y, parent) -{ - parent = parent || this.getDefaultParent(); - - if (parent != null) - { - var childCount = this.model.getChildCount(parent); - - for (var i = 0; i < childCount; i++) - { - var child = this.model.getChildAt(parent, i); - var result = this.getSwimlaneAt(x, y, child); - - if (result != null) - { - return result; - } - else if (this.isSwimlane(child)) - { - var state = this.view.getState(child); - - if (this.intersects(state, x, y)) - { - return child; - } - } - } - } - - return null; -}; - -/** - * Function: getCellAt - * - * Returns the bottom-most cell that intersects the given point (x, y) in - * the cell hierarchy starting at the given parent. This will also return - * swimlanes if the given location intersects the content area of the - * swimlane. If this is not desired, then the <hitsSwimlaneContent> may be - * used if the returned cell is a swimlane to determine if the location - * is inside the content area or on the actual title of the swimlane. - * - * Parameters: - * - * x - X-coordinate of the location to be checked. - * y - Y-coordinate of the location to be checked. - * parent - <mxCell> that should be used as the root of the recursion. - * Default is <defaultParent>. - * vertices - Optional boolean indicating if vertices should be returned. - * Default is true. - * edges - Optional boolean indicating if edges should be returned. Default - * is true. - */ -mxGraph.prototype.getCellAt = function(x, y, parent, vertices, edges) -{ - vertices = (vertices != null) ? vertices : true; - edges = (edges != null) ? edges : true; - parent = (parent != null) ? parent : this.getDefaultParent(); - - if (parent != null) - { - var childCount = this.model.getChildCount(parent); - - for (var i = childCount - 1; i >= 0; i--) - { - var cell = this.model.getChildAt(parent, i); - var result = this.getCellAt(x, y, cell, vertices, edges); - - if (result != null) - { - return result; - } - else if (this.isCellVisible(cell) && (edges && this.model.isEdge(cell) || - vertices && this.model.isVertex(cell))) - { - var state = this.view.getState(cell); - - if (this.intersects(state, x, y)) - { - return cell; - } - } - } - } - - return null; -}; - -/** - * Function: intersects - * - * Returns the bottom-most cell that intersects the given point (x, y) in - * the cell hierarchy that starts at the given parent. - * - * Parameters: - * - * state - <mxCellState> that represents the cell state. - * x - X-coordinate of the location to be checked. - * y - Y-coordinate of the location to be checked. - */ -mxGraph.prototype.intersects = function(state, x, y) -{ - if (state != null) - { - var pts = state.absolutePoints; - - if (pts != null) - { - var t2 = this.tolerance * this.tolerance; - - var pt = pts[0]; - - for (var i = 1; i<pts.length; i++) - { - var next = pts[i]; - var dist = mxUtils.ptSegDistSq( - pt.x, pt.y, next.x, next.y, x, y); - - if (dist <= t2) - { - return true; - } - - pt = next; - } - } - else if (mxUtils.contains(state, x, y)) - { - return true; - } - } - - return false; -}; - -/** - * Function: hitsSwimlaneContent - * - * Returns true if the given coordinate pair is inside the content - * are of the given swimlane. - * - * Parameters: - * - * swimlane - <mxCell> that specifies the swimlane. - * x - X-coordinate of the mouse event. - * y - Y-coordinate of the mouse event. - */ -mxGraph.prototype.hitsSwimlaneContent = function(swimlane, x, y) -{ - var state = this.getView().getState(swimlane); - var size = this.getStartSize(swimlane); - - if (state != null) - { - var scale = this.getView().getScale(); - x -= state.x; - y -= state.y; - - if (size.width > 0 && x > 0 && x > size.width * scale) - { - return true; - } - else if (size.height > 0 && y > 0 && y > size.height * scale) - { - return true; - } - } - - return false; -}; - -/** - * Function: getChildVertices - * - * Returns the visible child vertices of the given parent. - * - * Parameters: - * - * parent - <mxCell> whose children should be returned. - */ -mxGraph.prototype.getChildVertices = function(parent) -{ - return this.getChildCells(parent, true, false); -}; - -/** - * Function: getChildEdges - * - * Returns the visible child edges of the given parent. - * - * Parameters: - * - * parent - <mxCell> whose child vertices should be returned. - */ -mxGraph.prototype.getChildEdges = function(parent) -{ - return this.getChildCells(parent, false, true); -}; - -/** - * Function: getChildCells - * - * Returns the visible child vertices or edges in the given parent. If - * vertices and edges is false, then all children are returned. - * - * Parameters: - * - * parent - <mxCell> whose children should be returned. - * vertices - Optional boolean that specifies if child vertices should - * be returned. Default is false. - * edges - Optional boolean that specifies if child edges should - * be returned. Default is false. - */ -mxGraph.prototype.getChildCells = function(parent, vertices, edges) -{ - parent = (parent != null) ? parent : this.getDefaultParent(); - vertices = (vertices != null) ? vertices : false; - edges = (edges != null) ? edges : false; - - var cells = this.model.getChildCells(parent, vertices, edges); - var result = []; - - // Filters out the non-visible child cells - for (var i = 0; i < cells.length; i++) - { - if (this.isCellVisible(cells[i])) - { - result.push(cells[i]); - } - } - - return result; -}; - -/** - * Function: getConnections - * - * Returns all visible edges connected to the given cell without loops. - * - * Parameters: - * - * cell - <mxCell> whose connections should be returned. - * parent - Optional parent of the opposite end for a connection to be - * returned. - */ -mxGraph.prototype.getConnections = function(cell, parent) -{ - return this.getEdges(cell, parent, true, true, false); -}; - -/** - * Function: getIncomingEdges - * - * Returns the visible incoming edges for the given cell. If the optional - * parent argument is specified, then only child edges of the given parent - * are returned. - * - * Parameters: - * - * cell - <mxCell> whose incoming edges should be returned. - * parent - Optional parent of the opposite end for an edge to be - * returned. - */ -mxGraph.prototype.getIncomingEdges = function(cell, parent) -{ - return this.getEdges(cell, parent, true, false, false); -}; - -/** - * Function: getOutgoingEdges - * - * Returns the visible outgoing edges for the given cell. If the optional - * parent argument is specified, then only child edges of the given parent - * are returned. - * - * Parameters: - * - * cell - <mxCell> whose outgoing edges should be returned. - * parent - Optional parent of the opposite end for an edge to be - * returned. - */ -mxGraph.prototype.getOutgoingEdges = function(cell, parent) -{ - return this.getEdges(cell, parent, false, true, false); -}; - -/** - * Function: getEdges - * - * Returns the incoming and/or outgoing edges for the given cell. - * If the optional parent argument is specified, then only edges are returned - * where the opposite is in the given parent cell. If at least one of incoming - * or outgoing is true, then loops are ignored, if both are false, then all - * edges connected to the given cell are returned including loops. - * - * Parameters: - * - * cell - <mxCell> whose edges should be returned. - * parent - Optional parent of the opposite end for an edge to be - * returned. - * incoming - Optional boolean that specifies if incoming edges should - * be included in the result. Default is true. - * outgoing - Optional boolean that specifies if outgoing edges should - * be included in the result. Default is true. - * includeLoops - Optional boolean that specifies if loops should be - * included in the result. Default is true. - * recurse - Optional boolean the specifies if the parent specified only - * need be an ancestral parent, true, or the direct parent, false. - * Default is false - */ -mxGraph.prototype.getEdges = function(cell, parent, incoming, outgoing, includeLoops, recurse) -{ - incoming = (incoming != null) ? incoming : true; - outgoing = (outgoing != null) ? outgoing : true; - includeLoops = (includeLoops != null) ? includeLoops : true; - recurse = (recurse != null) ? recurse : false; - - var edges = []; - var isCollapsed = this.isCellCollapsed(cell); - var childCount = this.model.getChildCount(cell); - - for (var i = 0; i < childCount; i++) - { - var child = this.model.getChildAt(cell, i); - - if (isCollapsed || !this.isCellVisible(child)) - { - edges = edges.concat(this.model.getEdges(child, incoming, outgoing)); - } - } - - edges = edges.concat(this.model.getEdges(cell, incoming, outgoing)); - var result = []; - - for (var i = 0; i < edges.length; i++) - { - var state = this.view.getState(edges[i]); - - var source = (state != null) ? state.getVisibleTerminal(true) : this.view.getVisibleTerminal(edges[i], true); - var target = (state != null) ? state.getVisibleTerminal(false) : this.view.getVisibleTerminal(edges[i], false); - - if ((includeLoops && source == target) || ((source != target) && ((incoming && - target == cell && (parent == null || this.isValidAncestor(source, parent, recurse))) || - (outgoing && source == cell && (parent == null || - this.isValidAncestor(target, parent, recurse)))))) - { - result.push(edges[i]); - } - } - - return result; -}; - -/** - * Function: isValidAncestor - * - * Returns whether or not the specified parent is a valid - * ancestor of the specified cell, either direct or indirectly - * based on whether ancestor recursion is enabled. - * - * Parameters: - * - * cell - <mxCell> the possible child cell - * parent - <mxCell> the possible parent cell - * recurse - boolean whether or not to recurse the child ancestors - */ -mxGraph.prototype.isValidAncestor = function(cell, parent, recurse) -{ - return (recurse ? this.model.isAncestor(parent, cell) : this.model - .getParent(cell) == parent); -}; - -/** - * Function: getOpposites - * - * Returns all distinct visible opposite cells for the specified terminal - * on the given edges. - * - * Parameters: - * - * edges - Array of <mxCells> that contains the edges whose opposite - * terminals should be returned. - * terminal - Terminal that specifies the end whose opposite should be - * returned. - * source - Optional boolean that specifies if source terminals should be - * included in the result. Default is true. - * targets - Optional boolean that specifies if targer terminals should be - * included in the result. Default is true. - */ -mxGraph.prototype.getOpposites = function(edges, terminal, sources, targets) -{ - sources = (sources != null) ? sources : true; - targets = (targets != null) ? targets : true; - - var terminals = []; - - // Implements set semantic on the terminals array using a string - // representation of each cell in an associative array lookup - var hash = new Object(); - - if (edges != null) - { - for (var i = 0; i < edges.length; i++) - { - var state = this.view.getState(edges[i]); - - var source = (state != null) ? state.getVisibleTerminal(true) : this.view.getVisibleTerminal(edges[i], true); - var target = (state != null) ? state.getVisibleTerminal(false) : this.view.getVisibleTerminal(edges[i], false); - - // Checks if the terminal is the source of the edge and if the - // target should be stored in the result - if (source == terminal && target != null && - target != terminal && targets) - { - var id = mxCellPath.create(target); - - if (hash[id] == null) - { - hash[id] = target; - terminals.push(target); - } - } - - // Checks if the terminal is the taget of the edge and if the - // source should be stored in the result - else if (target == terminal && source != null && - source != terminal && sources) - { - var id = mxCellPath.create(source); - - if (hash[id] == null) - { - hash[id] = source; - terminals.push(source); - } - } - } - } - - return terminals; -}; - -/** - * Function: getEdgesBetween - * - * Returns the edges between the given source and target. This takes into - * account collapsed and invisible cells and returns the connected edges - * as displayed on the screen. - * - * Parameters: - * - * source - - * target - - * directed - - */ -mxGraph.prototype.getEdgesBetween = function(source, target, directed) -{ - directed = (directed != null) ? directed : false; - var edges = this.getEdges(source); - var result = []; - - // Checks if the edge is connected to the correct - // cell and returns the first match - for (var i = 0; i < edges.length; i++) - { - var state = this.view.getState(edges[i]); - - var src = (state != null) ? state.getVisibleTerminal(true) : this.view.getVisibleTerminal(edges[i], true); - var trg = (state != null) ? state.getVisibleTerminal(false) : this.view.getVisibleTerminal(edges[i], false); - - if ((src == source && trg == target) || (!directed && src == target && trg == source)) - { - result.push(edges[i]); - } - } - - return result; -}; - -/** - * Function: getPointForEvent - * - * Returns an <mxPoint> representing the given event in the unscaled, - * non-translated coordinate space of <container> and applies the grid. - * - * Parameters: - * - * evt - Mousevent that contains the mouse pointer location. - * addOffset - Optional boolean that specifies if the position should be - * offset by half of the <gridSize>. Default is true. - */ - mxGraph.prototype.getPointForEvent = function(evt, addOffset) - { - var p = mxUtils.convertPoint(this.container, - mxEvent.getClientX(evt), mxEvent.getClientY(evt)); - - var s = this.view.scale; - var tr = this.view.translate; - var off = (addOffset != false) ? this.gridSize / 2 : 0; - - p.x = this.snap(p.x / s - tr.x - off); - p.y = this.snap(p.y / s - tr.y - off); - - return p; - }; - -/** - * Function: getCells - * - * Returns the children of the given parent that are contained in the given - * rectangle (x, y, width, height). The result is added to the optional - * result array, which is returned from the function. If no result array - * is specified then a new array is created and returned. - * - * Parameters: - * - * x - X-coordinate of the rectangle. - * y - Y-coordinate of the rectangle. - * width - Width of the rectangle. - * height - Height of the rectangle. - * parent - <mxCell> whose children should be checked. Default is - * <defaultParent>. - * result - Optional array to store the result in. - */ -mxGraph.prototype.getCells = function(x, y, width, height, parent, result) -{ - result = (result != null) ? result : []; - - if (width > 0 || height > 0) - { - var right = x + width; - var bottom = y + height; - - parent = parent || this.getDefaultParent(); - - if (parent != null) - { - var childCount = this.model.getChildCount(parent); - - for (var i = 0; i < childCount; i++) - { - var cell = this.model.getChildAt(parent, i); - var state = this.view.getState(cell); - - if (this.isCellVisible(cell) && state != null) - { - if (state.x >= x && state.y >= y && - state.x + state.width <= right && - state.y + state.height <= bottom) - { - result.push(cell); - } - else - { - this.getCells(x, y, width, height, cell, result); - } - } - } - } - } - - return result; -}; - -/** - * Function: getCellsBeyond - * - * Returns the children of the given parent that are contained in the - * halfpane from the given point (x0, y0) rightwards and/or downwards - * depending on rightHalfpane and bottomHalfpane. - * - * Parameters: - * - * x0 - X-coordinate of the origin. - * y0 - Y-coordinate of the origin. - * parent - Optional <mxCell> whose children should be checked. Default is - * <defaultParent>. - * rightHalfpane - Boolean indicating if the cells in the right halfpane - * from the origin should be returned. - * bottomHalfpane - Boolean indicating if the cells in the bottom halfpane - * from the origin should be returned. - */ -mxGraph.prototype.getCellsBeyond = function(x0, y0, parent, rightHalfpane, bottomHalfpane) -{ - var result = []; - - if (rightHalfpane || bottomHalfpane) - { - if (parent == null) - { - parent = this.getDefaultParent(); - } - - if (parent != null) - { - var childCount = this.model.getChildCount(parent); - - for (var i = 0; i < childCount; i++) - { - var child = this.model.getChildAt(parent, i); - var state = this.view.getState(child); - - if (this.isCellVisible(child) && state != null) - { - if ((!rightHalfpane || - state.x >= x0) && - (!bottomHalfpane || - state.y >= y0)) - { - result.push(child); - } - } - } - } - } - - return result; -}; - -/** - * Function: findTreeRoots - * - * Returns all children in the given parent which do not have incoming - * edges. If the result is empty then the with the greatest difference - * between incoming and outgoing edges is returned. - * - * Parameters: - * - * parent - <mxCell> whose children should be checked. - * isolate - Optional boolean that specifies if edges should be ignored if - * the opposite end is not a child of the given parent cell. Default is - * false. - * invert - Optional boolean that specifies if outgoing or incoming edges - * should be counted for a tree root. If false then outgoing edges will be - * counted. Default is false. - */ -mxGraph.prototype.findTreeRoots = function(parent, isolate, invert) -{ - isolate = (isolate != null) ? isolate : false; - invert = (invert != null) ? invert : false; - var roots = []; - - if (parent != null) - { - var model = this.getModel(); - var childCount = model.getChildCount(parent); - var best = null; - var maxDiff = 0; - - for (var i=0; i<childCount; i++) - { - var cell = model.getChildAt(parent, i); - - if (this.model.isVertex(cell) && this.isCellVisible(cell)) - { - var conns = this.getConnections(cell, (isolate) ? parent : null); - var fanOut = 0; - var fanIn = 0; - - for (var j = 0; j < conns.length; j++) - { - var src = this.view.getVisibleTerminal(conns[j], true); - - if (src == cell) - { - fanOut++; - } - else - { - fanIn++; - } - } - - if ((invert && fanOut == 0 && fanIn > 0) || - (!invert && fanIn == 0 && fanOut > 0)) - { - roots.push(cell); - } - - var diff = (invert) ? fanIn - fanOut : fanOut - fanIn; - - if (diff > maxDiff) - { - maxDiff = diff; - best = cell; - } - } - } - - if (roots.length == 0 && best != null) - { - roots.push(best); - } - } - - return roots; -}; - -/** - * Function: traverse - * - * Traverses the (directed) graph invoking the given function for each - * visited vertex and edge. The function is invoked with the current vertex - * and the incoming edge as a parameter. This implementation makes sure - * each vertex is only visited once. The function may return false if the - * traversal should stop at the given vertex. - * - * Example: - * - * (code) - * mxLog.show(); - * var cell = graph.getSelectionCell(); - * graph.traverse(cell, false, function(vertex, edge) - * { - * mxLog.debug(graph.getLabel(vertex)); - * }); - * (end) - * - * Parameters: - * - * vertex - <mxCell> that represents the vertex where the traversal starts. - * directed - Optional boolean indicating if edges should only be traversed - * from source to target. Default is true. - * func - Visitor function that takes the current vertex and the incoming - * edge as arguments. The traversal stops if the function returns false. - * edge - Optional <mxCell> that represents the incoming edge. This is - * null for the first step of the traversal. - * visited - Optional array of cell paths for the visited cells. - */ -mxGraph.prototype.traverse = function(vertex, directed, func, edge, visited) -{ - if (func != null && vertex != null) - { - directed = (directed != null) ? directed : true; - visited = visited || []; - var id = mxCellPath.create(vertex); - - if (visited[id] == null) - { - visited[id] = vertex; - var result = func(vertex, edge); - - if (result == null || result) - { - var edgeCount = this.model.getEdgeCount(vertex); - - if (edgeCount > 0) - { - for (var i = 0; i < edgeCount; i++) - { - var e = this.model.getEdgeAt(vertex, i); - var isSource = this.model.getTerminal(e, true) == vertex; - - if (!directed || isSource) - { - var next = this.model.getTerminal(e, !isSource); - this.traverse(next, directed, func, e, visited); - } - } - } - } - } - } -}; - -/** - * Group: Selection - */ - -/** - * Function: isCellSelected - * - * Returns true if the given cell is selected. - * - * Parameters: - * - * cell - <mxCell> for which the selection state should be returned. - */ -mxGraph.prototype.isCellSelected = function(cell) -{ - return this.getSelectionModel().isSelected(cell); -}; - -/** - * Function: isSelectionEmpty - * - * Returns true if the selection is empty. - */ -mxGraph.prototype.isSelectionEmpty = function() -{ - return this.getSelectionModel().isEmpty(); -}; - -/** - * Function: clearSelection - * - * Clears the selection using <mxGraphSelectionModel.clear>. - */ -mxGraph.prototype.clearSelection = function() -{ - return this.getSelectionModel().clear(); -}; - -/** - * Function: getSelectionCount - * - * Returns the number of selected cells. - */ -mxGraph.prototype.getSelectionCount = function() -{ - return this.getSelectionModel().cells.length; -}; - -/** - * Function: getSelectionCell - * - * Returns the first cell from the array of selected <mxCells>. - */ -mxGraph.prototype.getSelectionCell = function() -{ - return this.getSelectionModel().cells[0]; -}; - -/** - * Function: getSelectionCells - * - * Returns the array of selected <mxCells>. - */ -mxGraph.prototype.getSelectionCells = function() -{ - return this.getSelectionModel().cells.slice(); -}; - -/** - * Function: setSelectionCell - * - * Sets the selection cell. - * - * Parameters: - * - * cell - <mxCell> to be selected. - */ -mxGraph.prototype.setSelectionCell = function(cell) -{ - this.getSelectionModel().setCell(cell); -}; - -/** - * Function: setSelectionCells - * - * Sets the selection cell. - * - * Parameters: - * - * cells - Array of <mxCells> to be selected. - */ -mxGraph.prototype.setSelectionCells = function(cells) -{ - this.getSelectionModel().setCells(cells); -}; - -/** - * Function: addSelectionCell - * - * Adds the given cell to the selection. - * - * Parameters: - * - * cell - <mxCell> to be add to the selection. - */ -mxGraph.prototype.addSelectionCell = function(cell) -{ - this.getSelectionModel().addCell(cell); -}; - -/** - * Function: addSelectionCells - * - * Adds the given cells to the selection. - * - * Parameters: - * - * cells - Array of <mxCells> to be added to the selection. - */ -mxGraph.prototype.addSelectionCells = function(cells) -{ - this.getSelectionModel().addCells(cells); -}; - -/** - * Function: removeSelectionCell - * - * Removes the given cell from the selection. - * - * Parameters: - * - * cell - <mxCell> to be removed from the selection. - */ -mxGraph.prototype.removeSelectionCell = function(cell) -{ - this.getSelectionModel().removeCell(cell); -}; - -/** - * Function: removeSelectionCells - * - * Removes the given cells from the selection. - * - * Parameters: - * - * cells - Array of <mxCells> to be removed from the selection. - */ -mxGraph.prototype.removeSelectionCells = function(cells) -{ - this.getSelectionModel().removeCells(cells); -}; - -/** - * Function: selectRegion - * - * Selects and returns the cells inside the given rectangle for the - * specified event. - * - * Parameters: - * - * rect - <mxRectangle> that represents the region to be selected. - * evt - Mouseevent that triggered the selection. - */ -mxGraph.prototype.selectRegion = function(rect, evt) -{ - var cells = this.getCells(rect.x, rect.y, rect.width, rect.height); - this.selectCellsForEvent(cells, evt); - - return cells; -}; - -/** - * Function: selectNextCell - * - * Selects the next cell. - */ -mxGraph.prototype.selectNextCell = function() -{ - this.selectCell(true); -}; - -/** - * Function: selectPreviousCell - * - * Selects the previous cell. - */ -mxGraph.prototype.selectPreviousCell = function() -{ - this.selectCell(); -}; - -/** - * Function: selectParentCell - * - * Selects the parent cell. - */ -mxGraph.prototype.selectParentCell = function() -{ - this.selectCell(false, true); -}; - -/** - * Function: selectChildCell - * - * Selects the first child cell. - */ -mxGraph.prototype.selectChildCell = function() -{ - this.selectCell(false, false, true); -}; - -/** - * Function: selectCell - * - * Selects the next, parent, first child or previous cell, if all arguments - * are false. - * - * Parameters: - * - * isNext - Boolean indicating if the next cell should be selected. - * isParent - Boolean indicating if the parent cell should be selected. - * isChild - Boolean indicating if the first child cell should be selected. - */ -mxGraph.prototype.selectCell = function(isNext, isParent, isChild) -{ - var sel = this.selectionModel; - var cell = (sel.cells.length > 0) ? sel.cells[0] : null; - - if (sel.cells.length > 1) - { - sel.clear(); - } - - var parent = (cell != null) ? - this.model.getParent(cell) : - this.getDefaultParent(); - - var childCount = this.model.getChildCount(parent); - - if (cell == null && childCount > 0) - { - var child = this.model.getChildAt(parent, 0); - this.setSelectionCell(child); - } - else if ((cell == null || isParent) && - this.view.getState(parent) != null && - this.model.getGeometry(parent) != null) - { - if (this.getCurrentRoot() != parent) - { - this.setSelectionCell(parent); - } - } - else if (cell != null && isChild) - { - var tmp = this.model.getChildCount(cell); - - if (tmp > 0) - { - var child = this.model.getChildAt(cell, 0); - this.setSelectionCell(child); - } - } - else if (childCount > 0) - { - var i = parent.getIndex(cell); - - if (isNext) - { - i++; - var child = this.model.getChildAt(parent, i % childCount); - this.setSelectionCell(child); - } - else - { - i--; - var index = (i < 0) ? childCount - 1 : i; - var child = this.model.getChildAt(parent, index); - this.setSelectionCell(child); - } - } -}; - -/** - * Function: selectAll - * - * Selects all children of the given parent cell or the children of the - * default parent if no parent is specified. To select leaf vertices and/or - * edges use <selectCells>. - * - * Parameters: - * - * parent - Optional <mxCell> whose children should be selected. - * Default is <defaultParent>. - */ -mxGraph.prototype.selectAll = function(parent) -{ - parent = parent || this.getDefaultParent(); - - var children = this.model.getChildren(parent); - - if (children != null) - { - this.setSelectionCells(children); - } -}; - -/** - * Function: selectVertices - * - * Select all vertices inside the given parent or the default parent. - */ -mxGraph.prototype.selectVertices = function(parent) -{ - this.selectCells(true, false, parent); -}; - -/** - * Function: selectVertices - * - * Select all vertices inside the given parent or the default parent. - */ -mxGraph.prototype.selectEdges = function(parent) -{ - this.selectCells(false, true, parent); -}; - -/** - * Function: selectCells - * - * Selects all vertices and/or edges depending on the given boolean - * arguments recursively, starting at the given parent or the default - * parent if no parent is specified. Use <selectAll> to select all cells. - * - * Parameters: - * - * vertices - Boolean indicating if vertices should be selected. - * edges - Boolean indicating if edges should be selected. - * parent - Optional <mxCell> that acts as the root of the recursion. - * Default is <defaultParent>. - */ -mxGraph.prototype.selectCells = function(vertices, edges, parent) -{ - parent = parent || this.getDefaultParent(); - - var filter = mxUtils.bind(this, function(cell) - { - return this.view.getState(cell) != null && - this.model.getChildCount(cell) == 0 && - ((this.model.isVertex(cell) && vertices) || - (this.model.isEdge(cell) && edges)); - }); - - var cells = this.model.filterDescendants(filter, parent); - this.setSelectionCells(cells); -}; - -/** - * Function: selectCellForEvent - * - * Selects the given cell by either adding it to the selection or - * replacing the selection depending on whether the given mouse event is a - * toggle event. - * - * Parameters: - * - * cell - <mxCell> to be selected. - * evt - Optional mouseevent that triggered the selection. - */ -mxGraph.prototype.selectCellForEvent = function(cell, evt) -{ - var isSelected = this.isCellSelected(cell); - - if (this.isToggleEvent(evt)) - { - if (isSelected) - { - this.removeSelectionCell(cell); - } - else - { - this.addSelectionCell(cell); - } - } - else if (!isSelected || this.getSelectionCount() != 1) - { - this.setSelectionCell(cell); - } -}; - -/** - * Function: selectCellsForEvent - * - * Selects the given cells by either adding them to the selection or - * replacing the selection depending on whether the given mouse event is a - * toggle event. - * - * Parameters: - * - * cells - Array of <mxCells> to be selected. - * evt - Optional mouseevent that triggered the selection. - */ -mxGraph.prototype.selectCellsForEvent = function(cells, evt) -{ - if (this.isToggleEvent(evt)) - { - this.addSelectionCells(cells); - } - else - { - this.setSelectionCells(cells); - } -}; - -/** - * Group: Selection state - */ - -/** - * Function: createHandler - * - * Creates a new handler for the given cell state. This implementation - * returns a new <mxEdgeHandler> of the corresponding cell is an edge, - * otherwise it returns an <mxVertexHandler>. - * - * Parameters: - * - * state - <mxCellState> whose handler should be created. - */ -mxGraph.prototype.createHandler = function(state) -{ - var result = null; - - if (state != null) - { - if (this.model.isEdge(state.cell)) - { - var style = this.view.getEdgeStyle(state); - - if (this.isLoop(state) || - style == mxEdgeStyle.ElbowConnector || - style == mxEdgeStyle.SideToSide || - style == mxEdgeStyle.TopToBottom) - { - result = new mxElbowEdgeHandler(state); - } - else if (style == mxEdgeStyle.SegmentConnector || - style == mxEdgeStyle.OrthConnector) - { - result = new mxEdgeSegmentHandler(state); - } - else - { - result = new mxEdgeHandler(state); - } - } - else - { - result = new mxVertexHandler(state); - } - } - - return result; -}; - -/** - * Group: Graph events - */ - -/** - * Function: addMouseListener - * - * Adds a listener to the graph event dispatch loop. The listener - * must implement the mouseDown, mouseMove and mouseUp methods - * as shown in the <mxMouseEvent> class. - * - * Parameters: - * - * listener - Listener to be added to the graph event listeners. - */ -mxGraph.prototype.addMouseListener = function(listener) -{ - if (this.mouseListeners == null) - { - this.mouseListeners = []; - } - - this.mouseListeners.push(listener); -}; - -/** - * Function: removeMouseListener - * - * Removes the specified graph listener. - * - * Parameters: - * - * listener - Listener to be removed from the graph event listeners. - */ -mxGraph.prototype.removeMouseListener = function(listener) -{ - if (this.mouseListeners != null) - { - for (var i = 0; i < this.mouseListeners.length; i++) - { - if (this.mouseListeners[i] == listener) - { - this.mouseListeners.splice(i, 1); - break; - } - } - } -}; - -/** - * Function: updateMouseEvent - * - * Sets the graphX and graphY properties if the given <mxMouseEvent> if - * required. - */ -mxGraph.prototype.updateMouseEvent = function(me) -{ - if (me.graphX == null || me.graphY == null) - { - var pt = mxUtils.convertPoint(this.container, me.getX(), me.getY()); - - me.graphX = pt.x - this.panDx; - me.graphY = pt.y - this.panDy; - } -}; - -/** - * Function: fireMouseEvent - * - * Dispatches the given event in the graph event dispatch loop. Possible - * event names are <mxEvent.MOUSE_DOWN>, <mxEvent.MOUSE_MOVE> and - * <mxEvent.MOUSE_UP>. All listeners are invoked for all events regardless - * of the consumed state of the event. - * - * Parameters: - * - * evtName - String that specifies the type of event to be dispatched. - * me - <mxMouseEvent> to be fired. - * sender - Optional sender argument. Default is this. - */ -mxGraph.prototype.fireMouseEvent = function(evtName, me, sender) -{ - if (sender == null) - { - sender = this; - } - - // Updates the graph coordinates in the event - this.updateMouseEvent(me); - - // Makes sure we have a uniform event-sequence across all - // browsers for a double click. Since evt.detail == 2 is only - // available on Firefox we use the fact that each mousedown - // must be followed by a mouseup, all out-of-sync downs - // will be dropped silently. - if (evtName == mxEvent.MOUSE_DOWN) - { - this.isMouseDown = true; - } - - // Detects and processes double taps for touch-based devices - // which do not have native double click events - if (mxClient.IS_TOUCH && this.doubleTapEnabled && evtName == mxEvent.MOUSE_DOWN) - { - var currentTime = new Date().getTime(); - - if (currentTime - this.lastTouchTime < this.doubleTapTimeout && - Math.abs(this.lastTouchX - me.getX()) < this.doubleTapTolerance && - Math.abs(this.lastTouchY - me.getY()) < this.doubleTapTolerance) - { - // FIXME: The actual editing should start on MOUSE_UP event but - // the detection of the double click should use the mouse_down event - // to make it consistent with behaviour in browser with mouse. - this.lastTouchTime = 0; - this.dblClick(me.getEvent(), me.getCell()); - - // Stop bubbling but do not consume to make sure the device - // can bring up the virtual keyboard for editing - me.getEvent().cancelBubble = true; - } - else - { - this.lastTouchX = me.getX(); - this.lastTouchY = me.getY(); - this.lastTouchTime = currentTime; - } - } - - // Workaround for IE9 standards mode ignoring tolerance for double clicks - var noDoubleClick = me.getEvent().detail/*clickCount*/ != 2; - - if (mxClient.IS_IE && document.compatMode == 'CSS1Compat') - { - if ((this.lastMouseX != null && Math.abs(this.lastMouseX - me.getX()) > this.doubleTapTolerance) || - (this.lastMouseY != null && Math.abs(this.lastMouseY - me.getY()) > this.doubleTapTolerance)) - { - noDoubleClick = true; - } - - if (evtName == mxEvent.MOUSE_UP) - { - this.lastMouseX = me.getX(); - this.lastMouseY = me.getY(); - } - } - - // Filters too many mouse ups when the mouse is down - if ((evtName != mxEvent.MOUSE_UP || this.isMouseDown) && noDoubleClick) - { - if (evtName == mxEvent.MOUSE_UP) - { - this.isMouseDown = false; - } - - if (!this.isEditing() && (mxClient.IS_OP || mxClient.IS_SF || mxClient.IS_GC || - (mxClient.IS_IE && mxClient.IS_SVG) || me.getEvent().target != this.container)) - { - if (evtName == mxEvent.MOUSE_MOVE && this.isMouseDown && this.autoScroll) - { - this.scrollPointToVisible(me.getGraphX(), me.getGraphY(), this.autoExtend); - } - - if (this.mouseListeners != null) - { - var args = [sender, me]; - - // Does not change returnValue in Opera - me.getEvent().returnValue = true; - - for (var i = 0; i < this.mouseListeners.length; i++) - { - var l = this.mouseListeners[i]; - - if (evtName == mxEvent.MOUSE_DOWN) - { - l.mouseDown.apply(l, args); - } - else if (evtName == mxEvent.MOUSE_MOVE) - { - l.mouseMove.apply(l, args); - } - else if (evtName == mxEvent.MOUSE_UP) - { - l.mouseUp.apply(l, args); - } - } - } - - // Invokes the click handler - if (evtName == mxEvent.MOUSE_UP) - { - this.click(me); - } - } - } - else if (evtName == mxEvent.MOUSE_UP) - { - this.isMouseDown = false; - } -}; - -/** - * Function: destroy - * - * Destroys the graph and all its resources. - */ -mxGraph.prototype.destroy = function() -{ - if (!this.destroyed) - { - this.destroyed = true; - - if (this.tooltipHandler != null) - { - this.tooltipHandler.destroy(); - } - - if (this.selectionCellsHandler != null) - { - this.selectionCellsHandler.destroy(); - } - - if (this.panningHandler != null) - { - this.panningHandler.destroy(); - } - - if (this.connectionHandler != null) - { - this.connectionHandler.destroy(); - } - - if (this.graphHandler != null) - { - this.graphHandler.destroy(); - } - - if (this.cellEditor != null) - { - this.cellEditor.destroy(); - } - - if (this.view != null) - { - this.view.destroy(); - } - - if (this.model != null && this.graphModelChangeListener != null) - { - this.model.removeListener(this.graphModelChangeListener); - this.graphModelChangeListener = null; - } - - this.container = null; - } -}; diff --git a/src/js/view/mxGraphSelectionModel.js b/src/js/view/mxGraphSelectionModel.js deleted file mode 100644 index 5cd16a8..0000000 --- a/src/js/view/mxGraphSelectionModel.js +++ /dev/null @@ -1,435 +0,0 @@ -/** - * $Id: mxGraphSelectionModel.js,v 1.14 2011-11-25 10:16:08 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -/** - * Class: mxGraphSelectionModel - * - * Implements the selection model for a graph. Here is a listener that handles - * all removed selection cells. - * - * (code) - * graph.getSelectionModel().addListener(mxEvent.CHANGE, function(sender, evt) - * { - * var cells = evt.getProperty('added'); - * - * for (var i = 0; i < cells.length; i++) - * { - * // Handle cells[i]... - * } - * }); - * (end) - * - * Event: mxEvent.UNDO - * - * Fires after the selection was changed in <changeSelection>. The - * <code>edit</code> property contains the <mxUndoableEdit> which contains the - * <mxSelectionChange>. - * - * Event: mxEvent.CHANGE - * - * Fires after the selection changes by executing an <mxSelectionChange>. The - * <code>added</code> and <code>removed</code> properties contain arrays of - * cells that have been added to or removed from the selection, respectively. - * - * Constructor: mxGraphSelectionModel - * - * Constructs a new graph selection model for the given <mxGraph>. - * - * Parameters: - * - * graph - Reference to the enclosing <mxGraph>. - */ -function mxGraphSelectionModel(graph) -{ - this.graph = graph; - this.cells = []; -}; - -/** - * Extends mxEventSource. - */ -mxGraphSelectionModel.prototype = new mxEventSource(); -mxGraphSelectionModel.prototype.constructor = mxGraphSelectionModel; - -/** - * Variable: doneResource - * - * Specifies the resource key for the status message after a long operation. - * If the resource for this key does not exist then the value is used as - * the status message. Default is 'done'. - */ -mxGraphSelectionModel.prototype.doneResource = (mxClient.language != 'none') ? 'done' : ''; - -/** - * Variable: updatingSelectionResource - * - * Specifies the resource key for the status message while the selection is - * being updated. If the resource for this key does not exist then the - * value is used as the status message. Default is 'updatingSelection'. - */ -mxGraphSelectionModel.prototype.updatingSelectionResource = (mxClient.language != 'none') ? 'updatingSelection' : ''; - -/** - * Variable: graph - * - * Reference to the enclosing <mxGraph>. - */ -mxGraphSelectionModel.prototype.graph = null; - -/** - * Variable: singleSelection - * - * Specifies if only one selected item at a time is allowed. - * Default is false. - */ -mxGraphSelectionModel.prototype.singleSelection = false; - -/** - * Function: isSingleSelection - * - * Returns <singleSelection> as a boolean. - */ -mxGraphSelectionModel.prototype.isSingleSelection = function() -{ - return this.singleSelection; -}; - -/** - * Function: setSingleSelection - * - * Sets the <singleSelection> flag. - * - * Parameters: - * - * singleSelection - Boolean that specifies the new value for - * <singleSelection>. - */ -mxGraphSelectionModel.prototype.setSingleSelection = function(singleSelection) -{ - this.singleSelection = singleSelection; -}; - -/** - * Function: isSelected - * - * Returns true if the given <mxCell> is selected. - */ -mxGraphSelectionModel.prototype.isSelected = function(cell) -{ - if (cell != null) - { - return mxUtils.indexOf(this.cells, cell) >= 0; - } - - return false; -}; - -/** - * Function: isEmpty - * - * Returns true if no cells are currently selected. - */ -mxGraphSelectionModel.prototype.isEmpty = function() -{ - return this.cells.length == 0; -}; - -/** - * Function: clear - * - * Clears the selection and fires a <change> event if the selection was not - * empty. - */ -mxGraphSelectionModel.prototype.clear = function() -{ - this.changeSelection(null, this.cells); -}; - -/** - * Function: setCell - * - * Selects the specified <mxCell> using <setCells>. - * - * Parameters: - * - * cell - <mxCell> to be selected. - */ -mxGraphSelectionModel.prototype.setCell = function(cell) -{ - if (cell != null) - { - this.setCells([cell]); - } -}; - -/** - * Function: setCells - * - * Selects the given array of <mxCells> and fires a <change> event. - * - * Parameters: - * - * cells - Array of <mxCells> to be selected. - */ -mxGraphSelectionModel.prototype.setCells = function(cells) -{ - if (cells != null) - { - if (this.singleSelection) - { - cells = [this.getFirstSelectableCell(cells)]; - } - - var tmp = []; - - for (var i = 0; i < cells.length; i++) - { - if (this.graph.isCellSelectable(cells[i])) - { - tmp.push(cells[i]); - } - } - - this.changeSelection(tmp, this.cells); - } -}; - -/** - * Function: getFirstSelectableCell - * - * Returns the first selectable cell in the given array of cells. - */ -mxGraphSelectionModel.prototype.getFirstSelectableCell = function(cells) -{ - if (cells != null) - { - for (var i = 0; i < cells.length; i++) - { - if (this.graph.isCellSelectable(cells[i])) - { - return cells[i]; - } - } - } - - return null; -}; - -/** - * Function: addCell - * - * Adds the given <mxCell> to the selection and fires a <select> event. - * - * Parameters: - * - * cell - <mxCell> to add to the selection. - */ -mxGraphSelectionModel.prototype.addCell = function(cell) -{ - if (cell != null) - { - this.addCells([cell]); - } -}; - -/** - * Function: addCells - * - * Adds the given array of <mxCells> to the selection and fires a <select> - * event. - * - * Parameters: - * - * cells - Array of <mxCells> to add to the selection. - */ -mxGraphSelectionModel.prototype.addCells = function(cells) -{ - if (cells != null) - { - var remove = null; - - if (this.singleSelection) - { - remove = this.cells; - cells = [this.getFirstSelectableCell(cells)]; - } - - var tmp = []; - - for (var i = 0; i < cells.length; i++) - { - if (!this.isSelected(cells[i]) && - this.graph.isCellSelectable(cells[i])) - { - tmp.push(cells[i]); - } - } - - this.changeSelection(tmp, remove); - } -}; - -/** - * Function: removeCell - * - * Removes the specified <mxCell> from the selection and fires a <select> - * event for the remaining cells. - * - * Parameters: - * - * cell - <mxCell> to remove from the selection. - */ -mxGraphSelectionModel.prototype.removeCell = function(cell) -{ - if (cell != null) - { - this.removeCells([cell]); - } -}; - -/** - * Function: removeCells - */ -mxGraphSelectionModel.prototype.removeCells = function(cells) -{ - if (cells != null) - { - var tmp = []; - - for (var i = 0; i < cells.length; i++) - { - if (this.isSelected(cells[i])) - { - tmp.push(cells[i]); - } - } - - this.changeSelection(null, tmp); - } -}; - -/** - * Function: changeSelection - * - * Inner callback to add the specified <mxCell> to the selection. No event - * is fired in this implementation. - * - * Paramters: - * - * cell - <mxCell> to add to the selection. - */ -mxGraphSelectionModel.prototype.changeSelection = function(added, removed) -{ - if ((added != null && - added.length > 0 && - added[0] != null) || - (removed != null && - removed.length > 0 && - removed[0] != null)) - { - var change = new mxSelectionChange(this, added, removed); - change.execute(); - var edit = new mxUndoableEdit(this, false); - edit.add(change); - this.fireEvent(new mxEventObject(mxEvent.UNDO, 'edit', edit)); - } -}; - -/** - * Function: cellAdded - * - * Inner callback to add the specified <mxCell> to the selection. No event - * is fired in this implementation. - * - * Paramters: - * - * cell - <mxCell> to add to the selection. - */ -mxGraphSelectionModel.prototype.cellAdded = function(cell) -{ - if (cell != null && - !this.isSelected(cell)) - { - this.cells.push(cell); - } -}; - -/** - * Function: cellRemoved - * - * Inner callback to remove the specified <mxCell> from the selection. No - * event is fired in this implementation. - * - * Parameters: - * - * cell - <mxCell> to remove from the selection. - */ -mxGraphSelectionModel.prototype.cellRemoved = function(cell) -{ - if (cell != null) - { - var index = mxUtils.indexOf(this.cells, cell); - - if (index >= 0) - { - this.cells.splice(index, 1); - } - } -}; - -/** - * Class: mxSelectionChange - * - * Action to change the current root in a view. - * - * Constructor: mxCurrentRootChange - * - * Constructs a change of the current root in the given view. - */ -function mxSelectionChange(selectionModel, added, removed) -{ - this.selectionModel = selectionModel; - this.added = (added != null) ? added.slice() : null; - this.removed = (removed != null) ? removed.slice() : null; -}; - -/** - * Function: execute - * - * Changes the current root of the view. - */ -mxSelectionChange.prototype.execute = function() -{ - var t0 = mxLog.enter('mxSelectionChange.execute'); - window.status = mxResources.get( - this.selectionModel.updatingSelectionResource) || - this.selectionModel.updatingSelectionResource; - - if (this.removed != null) - { - for (var i = 0; i < this.removed.length; i++) - { - this.selectionModel.cellRemoved(this.removed[i]); - } - } - - if (this.added != null) - { - for (var i = 0; i < this.added.length; i++) - { - this.selectionModel.cellAdded(this.added[i]); - } - } - - var tmp = this.added; - this.added = this.removed; - this.removed = tmp; - - window.status = mxResources.get(this.selectionModel.doneResource) || - this.selectionModel.doneResource; - mxLog.leave('mxSelectionChange.execute', t0); - - this.selectionModel.fireEvent(new mxEventObject(mxEvent.CHANGE, - 'added', this.added, 'removed', this.removed)); -}; diff --git a/src/js/view/mxGraphView.js b/src/js/view/mxGraphView.js deleted file mode 100644 index 0ef2dc8..0000000 --- a/src/js/view/mxGraphView.js +++ /dev/null @@ -1,2545 +0,0 @@ -/** - * $Id: mxGraphView.js,v 1.195 2012-11-20 09:06:07 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -/** - * Class: mxGraphView - * - * Extends <mxEventSource> to implement a view for a graph. This class is in - * charge of computing the absolute coordinates for the relative child - * geometries, the points for perimeters and edge styles and keeping them - * cached in <mxCellStates> for faster retrieval. The states are updated - * whenever the model or the view state (translate, scale) changes. The scale - * and translate are honoured in the bounds. - * - * Event: mxEvent.UNDO - * - * Fires after the root was changed in <setCurrentRoot>. The <code>edit</code> - * property contains the <mxUndoableEdit> which contains the - * <mxCurrentRootChange>. - * - * Event: mxEvent.SCALE_AND_TRANSLATE - * - * Fires after the scale and translate have been changed in <scaleAndTranslate>. - * The <code>scale</code>, <code>previousScale</code>, <code>translate</code> - * and <code>previousTranslate</code> properties contain the new and previous - * scale and translate, respectively. - * - * Event: mxEvent.SCALE - * - * Fires after the scale was changed in <setScale>. The <code>scale</code> and - * <code>previousScale</code> properties contain the new and previous scale. - * - * Event: mxEvent.TRANSLATE - * - * Fires after the translate was changed in <setTranslate>. The - * <code>translate</code> and <code>previousTranslate</code> properties contain - * the new and previous value for translate. - * - * Event: mxEvent.DOWN and mxEvent.UP - * - * Fire if the current root is changed by executing an <mxCurrentRootChange>. - * The event name depends on the location of the root in the cell hierarchy - * with respect to the current root. The <code>root</code> and - * <code>previous</code> properties contain the new and previous root, - * respectively. - * - * Constructor: mxGraphView - * - * Constructs a new view for the given <mxGraph>. - * - * Parameters: - * - * graph - Reference to the enclosing <mxGraph>. - */ -function mxGraphView(graph) -{ - this.graph = graph; - this.translate = new mxPoint(); - this.graphBounds = new mxRectangle(); - this.states = new mxDictionary(); -}; - -/** - * Extends mxEventSource. - */ -mxGraphView.prototype = new mxEventSource(); -mxGraphView.prototype.constructor = mxGraphView; - -/** - * - */ -mxGraphView.prototype.EMPTY_POINT = new mxPoint(); - -/** - * Variable: doneResource - * - * Specifies the resource key for the status message after a long operation. - * If the resource for this key does not exist then the value is used as - * the status message. Default is 'done'. - */ -mxGraphView.prototype.doneResource = (mxClient.language != 'none') ? 'done' : ''; - -/** - * Function: updatingDocumentResource - * - * Specifies the resource key for the status message while the document is - * being updated. If the resource for this key does not exist then the - * value is used as the status message. Default is 'updatingDocument'. - */ -mxGraphView.prototype.updatingDocumentResource = (mxClient.language != 'none') ? 'updatingDocument' : ''; - -/** - * Variable: allowEval - * - * Specifies if string values in cell styles should be evaluated using - * <mxUtils.eval>. This will only be used if the string values can't be mapped - * to objects using <mxStyleRegistry>. Default is false. NOTE: Enabling this - * switch carries a possible security risk (see the section on security in - * the manual). - */ -mxGraphView.prototype.allowEval = false; - -/** - * Variable: captureDocumentGesture - * - * Specifies if a gesture should be captured when it goes outside of the - * graph container. Default is true. - */ -mxGraphView.prototype.captureDocumentGesture = true; - -/** - * Variable: rendering - * - * Specifies if shapes should be created, updated and destroyed using the - * methods of <mxCellRenderer> in <graph>. Default is true. - */ -mxGraphView.prototype.rendering = true; - -/** - * Variable: graph - * - * Reference to the enclosing <mxGraph>. - */ -mxGraphView.prototype.graph = null; - -/** - * Variable: currentRoot - * - * <mxCell> that acts as the root of the displayed cell hierarchy. - */ -mxGraphView.prototype.currentRoot = null; - -/** - * Variable: graphBounds - * - * <mxRectangle> that caches the scales, translated bounds of the current view. - */ -mxGraphView.prototype.graphBounds = null; - -/** - * Variable: scale - * - * Specifies the scale. Default is 1 (100%). - */ -mxGraphView.prototype.scale = 1; - -/** - * Variable: translate - * - * <mxPoint> that specifies the current translation. Default is a new - * empty <mxPoint>. - */ -mxGraphView.prototype.translate = null; - -/** - * Variable: updateStyle - * - * Specifies if the style should be updated in each validation step. If this - * is false then the style is only updated if the state is created or if the - * style of the cell was changed. Default is false. - */ -mxGraphView.prototype.updateStyle = false; - -/** - * Function: getGraphBounds - * - * Returns <graphBounds>. - */ -mxGraphView.prototype.getGraphBounds = function() -{ - return this.graphBounds; -}; - -/** - * Function: setGraphBounds - * - * Sets <graphBounds>. - */ -mxGraphView.prototype.setGraphBounds = function(value) -{ - this.graphBounds = value; -}; - -/** - * Function: getBounds - * - * Returns the bounds (on the screen) for the given array of <mxCells>. - * - * Parameters: - * - * cells - Array of <mxCells> to return the bounds for. - */ -mxGraphView.prototype.getBounds = function(cells) -{ - var result = null; - - if (cells != null && cells.length > 0) - { - var model = this.graph.getModel(); - - for (var i = 0; i < cells.length; i++) - { - if (model.isVertex(cells[i]) || model.isEdge(cells[i])) - { - var state = this.getState(cells[i]); - - if (state != null) - { - if (result == null) - { - result = new mxRectangle(state.x, state.y, - state.width, state.height); - } - else - { - result.add(state); - } - } - } - } - } - - return result; -}; - -/** - * Function: setCurrentRoot - * - * Sets and returns the current root and fires an <undo> event before - * calling <mxGraph.sizeDidChange>. - * - * Parameters: - * - * root - <mxCell> that specifies the root of the displayed cell hierarchy. - */ -mxGraphView.prototype.setCurrentRoot = function(root) -{ - if (this.currentRoot != root) - { - var change = new mxCurrentRootChange(this, root); - change.execute(); - var edit = new mxUndoableEdit(this, false); - edit.add(change); - this.fireEvent(new mxEventObject(mxEvent.UNDO, 'edit', edit)); - this.graph.sizeDidChange(); - } - - return root; -}; - -/** - * Function: scaleAndTranslate - * - * Sets the scale and translation and fires a <scale> and <translate> event - * before calling <revalidate> followed by <mxGraph.sizeDidChange>. - * - * Parameters: - * - * scale - Decimal value that specifies the new scale (1 is 100%). - * dx - X-coordinate of the translation. - * dy - Y-coordinate of the translation. - */ -mxGraphView.prototype.scaleAndTranslate = function(scale, dx, dy) -{ - var previousScale = this.scale; - var previousTranslate = new mxPoint(this.translate.x, this.translate.y); - - if (this.scale != scale || this.translate.x != dx || this.translate.y != dy) - { - this.scale = scale; - - this.translate.x = dx; - this.translate.y = dy; - - if (this.isEventsEnabled()) - { - this.revalidate(); - this.graph.sizeDidChange(); - } - } - - this.fireEvent(new mxEventObject(mxEvent.SCALE_AND_TRANSLATE, - 'scale', scale, 'previousScale', previousScale, - 'translate', this.translate, 'previousTranslate', previousTranslate)); -}; - -/** - * Function: getScale - * - * Returns the <scale>. - */ -mxGraphView.prototype.getScale = function() -{ - return this.scale; -}; - -/** - * Function: setScale - * - * Sets the scale and fires a <scale> event before calling <revalidate> followed - * by <mxGraph.sizeDidChange>. - * - * Parameters: - * - * value - Decimal value that specifies the new scale (1 is 100%). - */ -mxGraphView.prototype.setScale = function(value) -{ - var previousScale = this.scale; - - if (this.scale != value) - { - this.scale = value; - - if (this.isEventsEnabled()) - { - this.revalidate(); - this.graph.sizeDidChange(); - } - } - - this.fireEvent(new mxEventObject(mxEvent.SCALE, - 'scale', value, 'previousScale', previousScale)); -}; - -/** - * Function: getTranslate - * - * Returns the <translate>. - */ -mxGraphView.prototype.getTranslate = function() -{ - return this.translate; -}; - -/** - * Function: setTranslate - * - * Sets the translation and fires a <translate> event before calling - * <revalidate> followed by <mxGraph.sizeDidChange>. The translation is the - * negative of the origin. - * - * Parameters: - * - * dx - X-coordinate of the translation. - * dy - Y-coordinate of the translation. - */ -mxGraphView.prototype.setTranslate = function(dx, dy) -{ - var previousTranslate = new mxPoint(this.translate.x, this.translate.y); - - if (this.translate.x != dx || this.translate.y != dy) - { - this.translate.x = dx; - this.translate.y = dy; - - if (this.isEventsEnabled()) - { - this.revalidate(); - this.graph.sizeDidChange(); - } - } - - this.fireEvent(new mxEventObject(mxEvent.TRANSLATE, - 'translate', this.translate, 'previousTranslate', previousTranslate)); -}; - -/** - * Function: refresh - * - * Clears the view if <currentRoot> is not null and revalidates. - */ -mxGraphView.prototype.refresh = function() -{ - if (this.currentRoot != null) - { - this.clear(); - } - - this.revalidate(); -}; - -/** - * Function: revalidate - * - * Revalidates the complete view with all cell states. - */ -mxGraphView.prototype.revalidate = function() -{ - this.invalidate(); - this.validate(); -}; - -/** - * Function: clear - * - * Removes the state of the given cell and all descendants if the given - * cell is not the current root. - * - * Parameters: - * - * cell - Optional <mxCell> for which the state should be removed. Default - * is the root of the model. - * force - Boolean indicating if the current root should be ignored for - * recursion. - */ -mxGraphView.prototype.clear = function(cell, force, recurse) -{ - var model = this.graph.getModel(); - cell = cell || model.getRoot(); - force = (force != null) ? force : false; - recurse = (recurse != null) ? recurse : true; - - this.removeState(cell); - - if (recurse && (force || cell != this.currentRoot)) - { - var childCount = model.getChildCount(cell); - - for (var i = 0; i < childCount; i++) - { - this.clear(model.getChildAt(cell, i), force); - } - } - else - { - this.invalidate(cell); - } -}; - -/** - * Function: invalidate - * - * Invalidates the state of the given cell, all its descendants and - * connected edges. - * - * Parameters: - * - * cell - Optional <mxCell> to be invalidated. Default is the root of the - * model. - */ -mxGraphView.prototype.invalidate = function(cell, recurse, includeEdges, orderChanged) -{ - var model = this.graph.getModel(); - cell = cell || model.getRoot(); - recurse = (recurse != null) ? recurse : true; - includeEdges = (includeEdges != null) ? includeEdges : true; - orderChanged = (orderChanged != null) ? orderChanged : false; - - var state = this.getState(cell); - - if (state != null) - { - state.invalid = true; - - if (orderChanged) - { - state.orderChanged = true; - } - } - - // Recursively invalidates all descendants - if (recurse) - { - var childCount = model.getChildCount(cell); - - for (var i = 0; i < childCount; i++) - { - var child = model.getChildAt(cell, i); - this.invalidate(child, recurse, includeEdges, orderChanged); - } - } - - // Propagates invalidation to all connected edges - if (includeEdges) - { - var edgeCount = model.getEdgeCount(cell); - - for (var i = 0; i < edgeCount; i++) - { - this.invalidate(model.getEdgeAt(cell, i), recurse, includeEdges); - } - } -}; - -/** - * Function: validate - * - * First validates all bounds and then validates all points recursively on - * all visible cells starting at the given cell. Finally the background - * is validated using <validateBackground>. - * - * Parameters: - * - * cell - Optional <mxCell> to be used as the root of the validation. - * Default is <currentRoot> or the root of the model. - */ -mxGraphView.prototype.validate = function(cell) -{ - var t0 = mxLog.enter('mxGraphView.validate'); - window.status = mxResources.get(this.updatingDocumentResource) || - this.updatingDocumentResource; - - cell = cell || ((this.currentRoot != null) ? - this.currentRoot : - this.graph.getModel().getRoot()); - this.validateBounds(null, cell); - var graphBounds = this.validatePoints(null, cell); - - if (graphBounds == null) - { - graphBounds = new mxRectangle(); - } - - this.setGraphBounds(graphBounds); - this.validateBackground(); - - window.status = mxResources.get(this.doneResource) || - this.doneResource; - mxLog.leave('mxGraphView.validate', t0); -}; - -/** - * Function: createBackgroundPageShape - * - * Creates and returns the shape used as the background page. - * - * Parameters: - * - * bounds - <mxRectangle> that represents the bounds of the shape. - */ -mxGraphView.prototype.createBackgroundPageShape = function(bounds) -{ - return new mxRectangleShape(bounds, 'white', 'black'); -}; - -/** - * Function: validateBackground - * - * Validates the background image. - */ -mxGraphView.prototype.validateBackground = function() -{ - var bg = this.graph.getBackgroundImage(); - - if (bg != null) - { - if (this.backgroundImage == null || this.backgroundImage.image != bg.src) - { - if (this.backgroundImage != null) - { - this.backgroundImage.destroy(); - } - - var bounds = new mxRectangle(0, 0, 1, 1); - - this.backgroundImage = new mxImageShape(bounds, bg.src); - this.backgroundImage.dialect = this.graph.dialect; - this.backgroundImage.init(this.backgroundPane); - this.backgroundImage.redraw(); - } - - this.redrawBackgroundImage(this.backgroundImage, bg); - } - else if (this.backgroundImage != null) - { - this.backgroundImage.destroy(); - this.backgroundImage = null; - } - - if (this.graph.pageVisible) - { - var bounds = this.getBackgroundPageBounds(); - - if (this.backgroundPageShape == null) - { - this.backgroundPageShape = this.createBackgroundPageShape(bounds); - this.backgroundPageShape.scale = this.scale; - this.backgroundPageShape.isShadow = true; - this.backgroundPageShape.dialect = this.graph.dialect; - this.backgroundPageShape.init(this.backgroundPane); - this.backgroundPageShape.redraw(); - - // Adds listener for double click handling on background - mxEvent.addListener(this.backgroundPageShape.node, 'dblclick', - mxUtils.bind(this, function(evt) - { - this.graph.dblClick(evt); - }) - ); - - var md = (mxClient.IS_TOUCH) ? 'touchstart' : 'mousedown'; - var mm = (mxClient.IS_TOUCH) ? 'touchmove' : 'mousemove'; - var mu = (mxClient.IS_TOUCH) ? 'touchend' : 'mouseup'; - - // Adds basic listeners for graph event dispatching outside of the - // container and finishing the handling of a single gesture - mxEvent.addListener(this.backgroundPageShape.node, md, - mxUtils.bind(this, function(evt) - { - this.graph.fireMouseEvent(mxEvent.MOUSE_DOWN, new mxMouseEvent(evt)); - }) - ); - mxEvent.addListener(this.backgroundPageShape.node, mm, - mxUtils.bind(this, function(evt) - { - // Hides the tooltip if mouse is outside container - if (this.graph.tooltipHandler != null && - this.graph.tooltipHandler.isHideOnHover()) - { - this.graph.tooltipHandler.hide(); - } - - if (this.graph.isMouseDown && - !mxEvent.isConsumed(evt)) - { - this.graph.fireMouseEvent(mxEvent.MOUSE_MOVE, - new mxMouseEvent(evt)); - } - }) - ); - mxEvent.addListener(this.backgroundPageShape.node, mu, - mxUtils.bind(this, function(evt) - { - this.graph.fireMouseEvent(mxEvent.MOUSE_UP, - new mxMouseEvent(evt)); - }) - ); - } - else - { - this.backgroundPageShape.scale = this.scale; - this.backgroundPageShape.bounds = bounds; - this.backgroundPageShape.redraw(); - } - } - else if (this.backgroundPageShape != null) - { - this.backgroundPageShape.destroy(); - this.backgroundPageShape = null; - } -}; - -/** - * Function: getBackgroundPageBounds - * - * Returns the bounds for the background page. - */ -mxGraphView.prototype.getBackgroundPageBounds = function() -{ - var fmt = this.graph.pageFormat; - var ps = this.scale * this.graph.pageScale; - var bounds = new mxRectangle(this.scale * this.translate.x, this.scale * this.translate.y, - fmt.width * ps, fmt.height * ps); - - return bounds; -}; - -/** - * Function: redrawBackgroundImage - * - * Updates the bounds and redraws the background image. - * - * Example: - * - * If the background image should not be scaled, this can be replaced with - * the following. - * - * (code) - * mxGraphView.prototype.redrawBackground = function(backgroundImage, bg) - * { - * backgroundImage.bounds.x = this.translate.x; - * backgroundImage.bounds.y = this.translate.y; - * backgroundImage.bounds.width = bg.width; - * backgroundImage.bounds.height = bg.height; - * - * backgroundImage.redraw(); - * }; - * (end) - * - * Parameters: - * - * backgroundImage - <mxImageShape> that represents the background image. - * bg - <mxImage> that specifies the image and its dimensions. - */ -mxGraphView.prototype.redrawBackgroundImage = function(backgroundImage, bg) -{ - backgroundImage.scale = this.scale; - backgroundImage.bounds.x = this.scale * this.translate.x; - backgroundImage.bounds.y = this.scale * this.translate.y; - backgroundImage.bounds.width = this.scale * bg.width; - backgroundImage.bounds.height = this.scale * bg.height; - - backgroundImage.redraw(); -}; - -/** - * Function: validateBounds - * - * Validates the bounds of the given parent's child using the given parent - * state as the origin for the child. The validation is carried out - * recursively for all non-collapsed descendants. - * - * Parameters: - * - * parentState - <mxCellState> for the given parent. - * cell - <mxCell> for which the bounds in the state should be updated. - */ -mxGraphView.prototype.validateBounds = function(parentState, cell) -{ - var model = this.graph.getModel(); - var state = this.getState(cell, true); - - if (state != null && state.invalid) - { - if (!this.graph.isCellVisible(cell)) - { - this.removeState(cell); - } - - // Updates the cell state's origin - else if (cell != this.currentRoot && parentState != null) - { - state.absoluteOffset.x = 0; - state.absoluteOffset.y = 0; - state.origin.x = parentState.origin.x; - state.origin.y = parentState.origin.y; - var geo = this.graph.getCellGeometry(cell); - - if (geo != null) - { - if (!model.isEdge(cell)) - { - var offset = geo.offset || this.EMPTY_POINT; - - if (geo.relative) - { - state.origin.x += geo.x * parentState.width / - this.scale + offset.x; - state.origin.y += geo.y * parentState.height / - this.scale + offset.y; - } - else - { - state.absoluteOffset.x = this.scale * offset.x; - state.absoluteOffset.y = this.scale * offset.y; - state.origin.x += geo.x; - state.origin.y += geo.y; - } - } - - // Updates cell state's bounds - state.x = this.scale * (this.translate.x + state.origin.x); - state.y = this.scale * (this.translate.y + state.origin.y); - state.width = this.scale * geo.width; - state.height = this.scale * geo.height; - - if (model.isVertex(cell)) - { - this.updateVertexLabelOffset(state); - } - } - } - - // Applies child offset to origin - var offset = this.graph.getChildOffsetForCell(cell); - - if (offset != null) - { - state.origin.x += offset.x; - state.origin.y += offset.y; - } - } - - // Recursively validates the child bounds - if (state != null && (!this.graph.isCellCollapsed(cell) || - cell == this.currentRoot)) - { - var childCount = model.getChildCount(cell); - - for (var i = 0; i < childCount; i++) - { - var child = model.getChildAt(cell, i); - this.validateBounds(state, child); - } - } -}; - -/** - * Function: updateVertexLabelOffset - * - * Updates the absoluteOffset of the given vertex cell state. This takes - * into account the label position styles. - * - * Parameters: - * - * state - <mxCellState> whose absolute offset should be updated. - */ -mxGraphView.prototype.updateVertexLabelOffset = function(state) -{ - var horizontal = mxUtils.getValue(state.style, - mxConstants.STYLE_LABEL_POSITION, - mxConstants.ALIGN_CENTER); - - if (horizontal == mxConstants.ALIGN_LEFT) - { - state.absoluteOffset.x -= state.width; - } - else if (horizontal == mxConstants.ALIGN_RIGHT) - { - state.absoluteOffset.x += state.width; - } - - var vertical = mxUtils.getValue(state.style, - mxConstants.STYLE_VERTICAL_LABEL_POSITION, - mxConstants.ALIGN_MIDDLE); - - if (vertical == mxConstants.ALIGN_TOP) - { - state.absoluteOffset.y -= state.height; - } - else if (vertical == mxConstants.ALIGN_BOTTOM) - { - state.absoluteOffset.y += state.height; - } -}; - -/** - * Function: validatePoints - * - * Validates the points for the state of the given cell recursively if the - * cell is not collapsed and returns the bounding box of all visited states - * as an <mxRectangle>. - * - * Parameters: - * - * parentState - <mxCellState> for the parent cell. - * cell - <mxCell> whose points in the state should be updated. - */ -mxGraphView.prototype.validatePoints = function(parentState, cell) -{ - var model = this.graph.getModel(); - var state = this.getState(cell); - var bbox = null; - - if (state != null) - { - if (state.invalid) - { - var geo = this.graph.getCellGeometry(cell); - - if (geo != null && model.isEdge(cell)) - { - // Updates the points on the source terminal if its an edge - var source = this.getState(this.getVisibleTerminal(cell, true)); - state.setVisibleTerminalState(source, true); - - if (source != null && model.isEdge(source.cell) && - !model.isAncestor(source.cell, cell)) - { - var tmp = this.getState(model.getParent(source.cell)); - this.validatePoints(tmp, source.cell); - } - - // Updates the points on the target terminal if its an edge - var target = this.getState(this.getVisibleTerminal(cell, false)); - state.setVisibleTerminalState(target, false); - - if (target != null && model.isEdge(target.cell) && - !model.isAncestor(target.cell, cell)) - { - var tmp = this.getState(model.getParent(target.cell)); - this.validatePoints(tmp, target.cell); - } - - this.updateFixedTerminalPoints(state, source, target); - this.updatePoints(state, geo.points, source, target); - this.updateFloatingTerminalPoints(state, source, target); - this.updateEdgeBounds(state); - this.updateEdgeLabelOffset(state); - } - else if (geo != null && geo.relative && parentState != null && - model.isEdge(parentState.cell)) - { - var origin = this.getPoint(parentState, geo); - - if (origin != null) - { - state.x = origin.x; - state.y = origin.y; - - origin.x = (origin.x / this.scale) - this.translate.x; - origin.y = (origin.y / this.scale) - this.translate.y; - state.origin = origin; - - this.childMoved(parentState, state); - } - } - - state.invalid = false; - - if (cell != this.currentRoot) - { - // NOTE: Label bounds currently ignored if rendering is false - this.graph.cellRenderer.redraw(state, false, this.isRendering()); - } - } - - if (model.isEdge(cell) || model.isVertex(cell)) - { - if (state.shape != null && state.shape.boundingBox != null) - { - bbox = state.shape.boundingBox.clone(); - } - - if (state.text != null && !this.graph.isLabelClipped(state.cell)) - { - // Adds label bounding box to graph bounds - if (state.text.boundingBox != null) - { - if (bbox != null) - { - bbox.add(state.text.boundingBox); - } - else - { - bbox = state.text.boundingBox.clone(); - } - } - } - } - } - - if (state != null && (!this.graph.isCellCollapsed(cell) || - cell == this.currentRoot)) - { - var childCount = model.getChildCount(cell); - - for (var i = 0; i < childCount; i++) - { - var child = model.getChildAt(cell, i); - var bounds = this.validatePoints(state, child); - - if (bounds != null) - { - if (bbox == null) - { - bbox = bounds; - } - else - { - bbox.add(bounds); - } - } - } - } - - return bbox; -}; - -/** - * Function: childMoved - * - * Invoked when a child state was moved as a result of late evaluation - * of its position. This is invoked for relative edge children whose - * position can only be determined after the points of the parent edge - * are updated in validatePoints, and validates the bounds of all - * descendants of the child using validateBounds. - * - * Parameters: - * - * parent - <mxCellState> that represents the parent state. - * child - <mxCellState> that represents the child state. - */ -mxGraphView.prototype.childMoved = function(parent, child) -{ - var cell = child.cell; - - // Children of relative edge children need to validate - // their bounds after their parent state was updated - if (!this.graph.isCellCollapsed(cell) || cell == this.currentRoot) - { - var model = this.graph.getModel(); - var childCount = model.getChildCount(cell); - - for (var i = 0; i < childCount; i++) - { - this.validateBounds(child, model.getChildAt(cell, i)); - } - } -}; - -/** - * Function: updateFixedTerminalPoints - * - * Sets the initial absolute terminal points in the given state before the edge - * style is computed. - * - * Parameters: - * - * edge - <mxCellState> whose initial terminal points should be updated. - * source - <mxCellState> which represents the source terminal. - * target - <mxCellState> which represents the target terminal. - */ -mxGraphView.prototype.updateFixedTerminalPoints = function(edge, source, target) -{ - this.updateFixedTerminalPoint(edge, source, true, - this.graph.getConnectionConstraint(edge, source, true)); - this.updateFixedTerminalPoint(edge, target, false, - this.graph.getConnectionConstraint(edge, target, false)); -}; - -/** - * Function: updateFixedTerminalPoint - * - * Sets the fixed source or target terminal point on the given edge. - * - * Parameters: - * - * edge - <mxCellState> whose terminal point should be updated. - * terminal - <mxCellState> which represents the actual terminal. - * source - Boolean that specifies if the terminal is the source. - * constraint - <mxConnectionConstraint> that specifies the connection. - */ -mxGraphView.prototype.updateFixedTerminalPoint = function(edge, terminal, source, constraint) -{ - var pt = null; - - if (constraint != null) - { - pt = this.graph.getConnectionPoint(terminal, constraint); - } - - if (pt == null && terminal == null) - { - var s = this.scale; - var tr = this.translate; - var orig = edge.origin; - var geo = this.graph.getCellGeometry(edge.cell); - pt = geo.getTerminalPoint(source); - - if (pt != null) - { - pt = new mxPoint(s * (tr.x + pt.x + orig.x), - s * (tr.y + pt.y + orig.y)); - } - } - - edge.setAbsoluteTerminalPoint(pt, source); -}; - -/** - * Function: updatePoints - * - * Updates the absolute points in the given state using the specified array - * of <mxPoints> as the relative points. - * - * Parameters: - * - * edge - <mxCellState> whose absolute points should be updated. - * points - Array of <mxPoints> that constitute the relative points. - * source - <mxCellState> that represents the source terminal. - * target - <mxCellState> that represents the target terminal. - */ -mxGraphView.prototype.updatePoints = function(edge, points, source, target) -{ - if (edge != null) - { - var pts = []; - pts.push(edge.absolutePoints[0]); - var edgeStyle = this.getEdgeStyle(edge, points, source, target); - - if (edgeStyle != null) - { - var src = this.getTerminalPort(edge, source, true); - var trg = this.getTerminalPort(edge, target, false); - - edgeStyle(edge, src, trg, points, pts); - } - else if (points != null) - { - for (var i = 0; i < points.length; i++) - { - if (points[i] != null) - { - var pt = mxUtils.clone(points[i]); - pts.push(this.transformControlPoint(edge, pt)); - } - } - } - - var tmp = edge.absolutePoints; - pts.push(tmp[tmp.length-1]); - - edge.absolutePoints = pts; - } -}; - -/** - * Function: transformControlPoint - * - * Transforms the given control point to an absolute point. - */ -mxGraphView.prototype.transformControlPoint = function(state, pt) -{ - var orig = state.origin; - - return new mxPoint(this.scale * (pt.x + this.translate.x + orig.x), - this.scale * (pt.y + this.translate.y + orig.y)); -}; - -/** - * Function: getEdgeStyle - * - * Returns the edge style function to be used to render the given edge - * state. - */ -mxGraphView.prototype.getEdgeStyle = function(edge, points, source, target) -{ - var edgeStyle = (source != null && source == target) ? - mxUtils.getValue(edge.style, mxConstants.STYLE_LOOP, - this.graph.defaultLoopStyle) : - (!mxUtils.getValue(edge.style, - mxConstants.STYLE_NOEDGESTYLE, false) ? - edge.style[mxConstants.STYLE_EDGE] : - null); - - // Converts string values to objects - if (typeof(edgeStyle) == "string") - { - var tmp = mxStyleRegistry.getValue(edgeStyle); - - if (tmp == null && this.isAllowEval()) - { - tmp = mxUtils.eval(edgeStyle); - } - - edgeStyle = tmp; - } - - if (typeof(edgeStyle) == "function") - { - return edgeStyle; - } - - return null; -}; - -/** - * Function: updateFloatingTerminalPoints - * - * Updates the terminal points in the given state after the edge style was - * computed for the edge. - * - * Parameters: - * - * state - <mxCellState> whose terminal points should be updated. - * source - <mxCellState> that represents the source terminal. - * target - <mxCellState> that represents the target terminal. - */ -mxGraphView.prototype.updateFloatingTerminalPoints = function(state, source, target) -{ - var pts = state.absolutePoints; - var p0 = pts[0]; - var pe = pts[pts.length - 1]; - - if (pe == null && target != null) - { - this.updateFloatingTerminalPoint(state, target, source, false); - } - - if (p0 == null && source != null) - { - this.updateFloatingTerminalPoint(state, source, target, true); - } -}; - -/** - * Function: updateFloatingTerminalPoint - * - * Updates the absolute terminal point in the given state for the given - * start and end state, where start is the source if source is true. - * - * Parameters: - * - * edge - <mxCellState> whose terminal point should be updated. - * start - <mxCellState> for the terminal on "this" side of the edge. - * end - <mxCellState> for the terminal on the other side of the edge. - * source - Boolean indicating if start is the source terminal state. - */ -mxGraphView.prototype.updateFloatingTerminalPoint = function(edge, start, end, source) -{ - start = this.getTerminalPort(edge, start, source); - var next = this.getNextPoint(edge, end, source); - - var alpha = mxUtils.toRadians(Number(start.style[mxConstants.STYLE_ROTATION] || '0')); - var center = new mxPoint(start.getCenterX(), start.getCenterY()); - - if (alpha != 0) - { - var cos = Math.cos(-alpha); - var sin = Math.sin(-alpha); - next = mxUtils.getRotatedPoint(next, cos, sin, center); - } - - var border = parseFloat(edge.style[mxConstants.STYLE_PERIMETER_SPACING] || 0); - border += parseFloat(edge.style[(source) ? - mxConstants.STYLE_SOURCE_PERIMETER_SPACING : - mxConstants.STYLE_TARGET_PERIMETER_SPACING] || 0); - var pt = this.getPerimeterPoint(start, next, this.graph.isOrthogonal(edge), border); - - if (alpha != 0) - { - var cos = Math.cos(alpha); - var sin = Math.sin(alpha); - pt = mxUtils.getRotatedPoint(pt, cos, sin, center); - } - - edge.setAbsoluteTerminalPoint(pt, source); -}; - -/** - * Function: getTerminalPort - * - * Returns an <mxCellState> that represents the source or target terminal or - * port for the given edge. - * - * Parameters: - * - * state - <mxCellState> that represents the state of the edge. - * terminal - <mxCellState> that represents the terminal. - * source - Boolean indicating if the given terminal is the source terminal. - */ -mxGraphView.prototype.getTerminalPort = function(state, terminal, source) -{ - var key = (source) ? mxConstants.STYLE_SOURCE_PORT : - mxConstants.STYLE_TARGET_PORT; - var id = mxUtils.getValue(state.style, key); - - if (id != null) - { - var tmp = this.getState(this.graph.getModel().getCell(id)); - - // Only uses ports where a cell state exists - if (tmp != null) - { - terminal = tmp; - } - } - - return terminal; -}; - -/** - * Function: getPerimeterPoint - * - * Returns an <mxPoint> that defines the location of the intersection point between - * the perimeter and the line between the center of the shape and the given point. - * - * Parameters: - * - * terminal - <mxCellState> for the source or target terminal. - * next - <mxPoint> that lies outside of the given terminal. - * orthogonal - Boolean that specifies if the orthogonal projection onto - * the perimeter should be returned. If this is false then the intersection - * of the perimeter and the line between the next and the center point is - * returned. - * border - Optional border between the perimeter and the shape. - */ -mxGraphView.prototype.getPerimeterPoint = function(terminal, next, orthogonal, border) -{ - var point = null; - - if (terminal != null) - { - var perimeter = this.getPerimeterFunction(terminal); - - if (perimeter != null && next != null) - { - var bounds = this.getPerimeterBounds(terminal, border); - - if (bounds.width > 0 || bounds.height > 0) - { - point = perimeter(bounds, terminal, next, orthogonal); - } - } - - if (point == null) - { - point = this.getPoint(terminal); - } - } - - return point; -}; - -/** - * Function: getRoutingCenterX - * - * Returns the x-coordinate of the center point for automatic routing. - */ -mxGraphView.prototype.getRoutingCenterX = function (state) -{ - var f = (state.style != null) ? parseFloat(state.style - [mxConstants.STYLE_ROUTING_CENTER_X]) || 0 : 0; - - return state.getCenterX() + f * state.width; -}; - -/** - * Function: getRoutingCenterY - * - * Returns the y-coordinate of the center point for automatic routing. - */ -mxGraphView.prototype.getRoutingCenterY = function (state) -{ - var f = (state.style != null) ? parseFloat(state.style - [mxConstants.STYLE_ROUTING_CENTER_Y]) || 0 : 0; - - return state.getCenterY() + f * state.height; -}; - -/** - * Function: getPerimeterBounds - * - * Returns the perimeter bounds for the given terminal, edge pair as an - * <mxRectangle>. - * - * If you have a model where each terminal has a relative child that should - * act as the graphical endpoint for a connection from/to the terminal, then - * this method can be replaced as follows: - * - * (code) - * var oldGetPerimeterBounds = mxGraphView.prototype.getPerimeterBounds; - * mxGraphView.prototype.getPerimeterBounds = function(terminal, edge, isSource) - * { - * var model = this.graph.getModel(); - * var childCount = model.getChildCount(terminal.cell); - * - * if (childCount > 0) - * { - * var child = model.getChildAt(terminal.cell, 0); - * var geo = model.getGeometry(child); - * - * if (geo != null && - * geo.relative) - * { - * var state = this.getState(child); - * - * if (state != null) - * { - * terminal = state; - * } - * } - * } - * - * return oldGetPerimeterBounds.apply(this, arguments); - * }; - * (end) - * - * Parameters: - * - * terminal - <mxCellState> that represents the terminal. - * border - Number that adds a border between the shape and the perimeter. - */ -mxGraphView.prototype.getPerimeterBounds = function(terminal, border) -{ - border = (border != null) ? border : 0; - - if (terminal != null) - { - border += parseFloat(terminal.style[mxConstants.STYLE_PERIMETER_SPACING] || 0); - } - - return terminal.getPerimeterBounds(border * this.scale); -}; - -/** - * Function: getPerimeterFunction - * - * Returns the perimeter function for the given state. - */ -mxGraphView.prototype.getPerimeterFunction = function(state) -{ - var perimeter = state.style[mxConstants.STYLE_PERIMETER]; - - // Converts string values to objects - if (typeof(perimeter) == "string") - { - var tmp = mxStyleRegistry.getValue(perimeter); - - if (tmp == null && this.isAllowEval()) - { - tmp = mxUtils.eval(perimeter); - } - - perimeter = tmp; - } - - if (typeof(perimeter) == "function") - { - return perimeter; - } - - return null; -}; - -/** - * Function: getNextPoint - * - * Returns the nearest point in the list of absolute points or the center - * of the opposite terminal. - * - * Parameters: - * - * edge - <mxCellState> that represents the edge. - * opposite - <mxCellState> that represents the opposite terminal. - * source - Boolean indicating if the next point for the source or target - * should be returned. - */ -mxGraphView.prototype.getNextPoint = function(edge, opposite, source) -{ - var pts = edge.absolutePoints; - var point = null; - - if (pts != null && (source || pts.length > 2 || opposite == null)) - { - var count = pts.length; - point = pts[(source) ? Math.min(1, count - 1) : Math.max(0, count - 2)]; - } - - if (point == null && opposite != null) - { - point = new mxPoint(opposite.getCenterX(), opposite.getCenterY()); - } - - return point; -}; - -/** - * Function: getVisibleTerminal - * - * Returns the nearest ancestor terminal that is visible. The edge appears - * to be connected to this terminal on the display. The result of this method - * is cached in <mxCellState.getVisibleTerminalState>. - * - * Parameters: - * - * edge - <mxCell> whose visible terminal should be returned. - * source - Boolean that specifies if the source or target terminal - * should be returned. - */ -mxGraphView.prototype.getVisibleTerminal = function(edge, source) -{ - var model = this.graph.getModel(); - var result = model.getTerminal(edge, source); - var best = result; - - while (result != null && result != this.currentRoot) - { - if (!this.graph.isCellVisible(best) || this.graph.isCellCollapsed(result)) - { - best = result; - } - - result = model.getParent(result); - } - - // Checks if the result is not a layer - if (model.getParent(best) == model.getRoot()) - { - best = null; - } - - return best; -}; - -/** - * Function: updateEdgeBounds - * - * Updates the given state using the bounding box of the absolute points. - * Also updates <mxCellState.terminalDistance>, <mxCellState.length> and - * <mxCellState.segments>. - * - * Parameters: - * - * state - <mxCellState> whose bounds should be updated. - */ -mxGraphView.prototype.updateEdgeBounds = function(state) -{ - var points = state.absolutePoints; - state.length = 0; - - if (points != null && points.length > 0) - { - var p0 = points[0]; - var pe = points[points.length - 1]; - - if (p0 == null || pe == null) - { - // Drops the edge state if the edge is not the root - if (state.cell != this.currentRoot) - { - // Note: This condition normally occurs if a connected edge has a - // null-terminal, ie. edge.source == null or edge.target == null, - // and no corresponding terminal point defined, which happens for - // example if the terminal-id was not resolved at cell decoding time. - this.clear(state.cell, true); - } - } - else - { - if (p0.x != pe.x || p0.y != pe.y) - { - var dx = pe.x - p0.x; - var dy = pe.y - p0.y; - state.terminalDistance = Math.sqrt(dx * dx + dy * dy); - } - else - { - state.terminalDistance = 0; - } - - var length = 0; - var segments = []; - var pt = p0; - - if (pt != null) - { - var minX = pt.x; - var minY = pt.y; - var maxX = minX; - var maxY = minY; - - for (var i = 1; i < points.length; i++) - { - var tmp = points[i]; - - if (tmp != null) - { - var dx = pt.x - tmp.x; - var dy = pt.y - tmp.y; - - var segment = Math.sqrt(dx * dx + dy * dy); - segments.push(segment); - length += segment; - - pt = tmp; - - minX = Math.min(pt.x, minX); - minY = Math.min(pt.y, minY); - maxX = Math.max(pt.x, maxX); - maxY = Math.max(pt.y, maxY); - } - } - - state.length = length; - state.segments = segments; - - var markerSize = 1; // TODO: include marker size - - state.x = minX; - state.y = minY; - state.width = Math.max(markerSize, maxX - minX); - state.height = Math.max(markerSize, maxY - minY); - } - } - } -}; - -/** - * Function: getPoint - * - * Returns the absolute point on the edge for the given relative - * <mxGeometry> as an <mxPoint>. The edge is represented by the given - * <mxCellState>. - * - * Parameters: - * - * state - <mxCellState> that represents the state of the parent edge. - * geometry - <mxGeometry> that represents the relative location. - */ -mxGraphView.prototype.getPoint = function(state, geometry) -{ - var x = state.getCenterX(); - var y = state.getCenterY(); - - if (state.segments != null && (geometry == null || geometry.relative)) - { - var gx = (geometry != null) ? geometry.x / 2 : 0; - var pointCount = state.absolutePoints.length; - var dist = (gx + 0.5) * state.length; - var segment = state.segments[0]; - var length = 0; - var index = 1; - - while (dist > length + segment && index < pointCount-1) - { - length += segment; - segment = state.segments[index++]; - } - - var factor = (segment == 0) ? 0 : (dist - length) / segment; - var p0 = state.absolutePoints[index-1]; - var pe = state.absolutePoints[index]; - - if (p0 != null && pe != null) - { - var gy = 0; - var offsetX = 0; - var offsetY = 0; - - if (geometry != null) - { - gy = geometry.y; - var offset = geometry.offset; - - if (offset != null) - { - offsetX = offset.x; - offsetY = offset.y; - } - } - - var dx = pe.x - p0.x; - var dy = pe.y - p0.y; - var nx = (segment == 0) ? 0 : dy / segment; - var ny = (segment == 0) ? 0 : dx / segment; - - x = p0.x + dx * factor + (nx * gy + offsetX) * this.scale; - y = p0.y + dy * factor - (ny * gy - offsetY) * this.scale; - } - } - else if (geometry != null) - { - var offset = geometry.offset; - - if (offset != null) - { - x += offset.x; - y += offset.y; - } - } - - return new mxPoint(x, y); -}; - -/** - * Function: getRelativePoint - * - * Gets the relative point that describes the given, absolute label - * position for the given edge state. - * - * Parameters: - * - * state - <mxCellState> that represents the state of the parent edge. - * x - Specifies the x-coordinate of the absolute label location. - * y - Specifies the y-coordinate of the absolute label location. - */ -mxGraphView.prototype.getRelativePoint = function(edgeState, x, y) -{ - var model = this.graph.getModel(); - var geometry = model.getGeometry(edgeState.cell); - - if (geometry != null) - { - var pointCount = edgeState.absolutePoints.length; - - if (geometry.relative && pointCount > 1) - { - var totalLength = edgeState.length; - var segments = edgeState.segments; - - // Works which line segment the point of the label is closest to - var p0 = edgeState.absolutePoints[0]; - var pe = edgeState.absolutePoints[1]; - var minDist = mxUtils.ptSegDistSq(p0.x, p0.y, pe.x, pe.y, x, y); - - var index = 0; - var tmp = 0; - var length = 0; - - for (var i = 2; i < pointCount; i++) - { - tmp += segments[i - 2]; - pe = edgeState.absolutePoints[i]; - var dist = mxUtils.ptSegDistSq(p0.x, p0.y, pe.x, pe.y, x, y); - - if (dist <= minDist) - { - minDist = dist; - index = i - 1; - length = tmp; - } - - p0 = pe; - } - - var seg = segments[index]; - p0 = edgeState.absolutePoints[index]; - pe = edgeState.absolutePoints[index + 1]; - - var x2 = p0.x; - var y2 = p0.y; - - var x1 = pe.x; - var y1 = pe.y; - - var px = x; - var py = y; - - var xSegment = x2 - x1; - var ySegment = y2 - y1; - - px -= x1; - py -= y1; - var projlenSq = 0; - - px = xSegment - px; - py = ySegment - py; - var dotprod = px * xSegment + py * ySegment; - - if (dotprod <= 0.0) - { - projlenSq = 0; - } - else - { - projlenSq = dotprod * dotprod - / (xSegment * xSegment + ySegment * ySegment); - } - - var projlen = Math.sqrt(projlenSq); - - if (projlen > seg) - { - projlen = seg; - } - - var yDistance = Math.sqrt(mxUtils.ptSegDistSq(p0.x, p0.y, pe - .x, pe.y, x, y)); - var direction = mxUtils.relativeCcw(p0.x, p0.y, pe.x, pe.y, x, y); - - if (direction == -1) - { - yDistance = -yDistance; - } - - // Constructs the relative point for the label - return new mxPoint(((totalLength / 2 - length - projlen) / totalLength) * -2, - yDistance / this.scale); - } - } - - return new mxPoint(); -}; - -/** - * Function: updateEdgeLabelOffset - * - * Updates <mxCellState.absoluteOffset> for the given state. The absolute - * offset is normally used for the position of the edge label. Is is - * calculated from the geometry as an absolute offset from the center - * between the two endpoints if the geometry is absolute, or as the - * relative distance between the center along the line and the absolute - * orthogonal distance if the geometry is relative. - * - * Parameters: - * - * state - <mxCellState> whose absolute offset should be updated. - */ -mxGraphView.prototype.updateEdgeLabelOffset = function(state) -{ - var points = state.absolutePoints; - - state.absoluteOffset.x = state.getCenterX(); - state.absoluteOffset.y = state.getCenterY(); - - if (points != null && points.length > 0 && state.segments != null) - { - var geometry = this.graph.getCellGeometry(state.cell); - - if (geometry.relative) - { - var offset = this.getPoint(state, geometry); - - if (offset != null) - { - state.absoluteOffset = offset; - } - } - else - { - var p0 = points[0]; - var pe = points[points.length - 1]; - - if (p0 != null && pe != null) - { - var dx = pe.x - p0.x; - var dy = pe.y - p0.y; - var x0 = 0; - var y0 = 0; - - var off = geometry.offset; - - if (off != null) - { - x0 = off.x; - y0 = off.y; - } - - var x = p0.x + dx / 2 + x0 * this.scale; - var y = p0.y + dy / 2 + y0 * this.scale; - - state.absoluteOffset.x = x; - state.absoluteOffset.y = y; - } - } - } -}; - -/** - * Function: getState - * - * Returns the <mxCellState> for the given cell. If create is true, then - * the state is created if it does not yet exist. - * - * Parameters: - * - * cell - <mxCell> for which the <mxCellState> should be returned. - * create - Optional boolean indicating if a new state should be created - * if it does not yet exist. Default is false. - */ -mxGraphView.prototype.getState = function(cell, create) -{ - create = create || false; - var state = null; - - if (cell != null) - { - state = this.states.get(cell); - - if (this.graph.isCellVisible(cell)) - { - if (state == null && create && this.graph.isCellVisible(cell)) - { - state = this.createState(cell); - this.states.put(cell, state); - } - else if (create && state != null && this.updateStyle) - { - state.style = this.graph.getCellStyle(cell); - } - } - } - - return state; -}; - -/** - * Function: isRendering - * - * Returns <rendering>. - */ -mxGraphView.prototype.isRendering = function() -{ - return this.rendering; -}; - -/** - * Function: setRendering - * - * Sets <rendering>. - */ -mxGraphView.prototype.setRendering = function(value) -{ - this.rendering = value; -}; - -/** - * Function: isAllowEval - * - * Returns <allowEval>. - */ -mxGraphView.prototype.isAllowEval = function() -{ - return this.allowEval; -}; - -/** - * Function: setAllowEval - * - * Sets <allowEval>. - */ -mxGraphView.prototype.setAllowEval = function(value) -{ - this.allowEval = value; -}; - -/** - * Function: getStates - * - * Returns <states>. - */ -mxGraphView.prototype.getStates = function() -{ - return this.states; -}; - -/** - * Function: setStates - * - * Sets <states>. - */ -mxGraphView.prototype.setStates = function(value) -{ - this.states = value; -}; - -/** - * Function: getCellStates - * - * Returns the <mxCellStates> for the given array of <mxCells>. The array - * contains all states that are not null, that is, the returned array may - * have less elements than the given array. If no argument is given, then - * this returns <states>. - */ -mxGraphView.prototype.getCellStates = function(cells) -{ - if (cells == null) - { - return this.states; - } - else - { - var result = []; - - for (var i = 0; i < cells.length; i++) - { - var state = this.getState(cells[i]); - - if (state != null) - { - result.push(state); - } - } - - return result; - } -}; - -/** - * Function: removeState - * - * Removes and returns the <mxCellState> for the given cell. - * - * Parameters: - * - * cell - <mxCell> for which the <mxCellState> should be removed. - */ -mxGraphView.prototype.removeState = function(cell) -{ - var state = null; - - if (cell != null) - { - state = this.states.remove(cell); - - if (state != null) - { - this.graph.cellRenderer.destroy(state); - state.destroy(); - } - } - - return state; -}; - -/** - * Function: createState - * - * Creates and returns an <mxCellState> for the given cell and initializes - * it using <mxCellRenderer.initialize>. - * - * Parameters: - * - * cell - <mxCell> for which a new <mxCellState> should be created. - */ -mxGraphView.prototype.createState = function(cell) -{ - var style = this.graph.getCellStyle(cell); - var state = new mxCellState(this, cell, style); - this.graph.cellRenderer.initialize(state, this.isRendering()); - - return state; -}; - -/** - * Function: getCanvas - * - * Returns the DOM node that contains the background-, draw- and - * overlaypane. - */ -mxGraphView.prototype.getCanvas = function() -{ - return this.canvas; -}; - -/** - * Function: getBackgroundPane - * - * Returns the DOM node that represents the background layer. - */ -mxGraphView.prototype.getBackgroundPane = function() -{ - return this.backgroundPane; -}; - -/** - * Function: getDrawPane - * - * Returns the DOM node that represents the main drawing layer. - */ -mxGraphView.prototype.getDrawPane = function() -{ - return this.drawPane; -}; - -/** - * Function: getOverlayPane - * - * Returns the DOM node that represents the topmost drawing layer. - */ -mxGraphView.prototype.getOverlayPane = function() -{ - return this.overlayPane; -}; - -/** - * Function: isContainerEvent - * - * Returns true if the event origin is one of the drawing panes or - * containers of the view. - */ -mxGraphView.prototype.isContainerEvent = function(evt) -{ - var source = mxEvent.getSource(evt); - - return (source == this.graph.container || - source.parentNode == this.backgroundPane || - (source.parentNode != null && - source.parentNode.parentNode == this.backgroundPane) || - source == this.canvas.parentNode || - source == this.canvas || - source == this.backgroundPane || - source == this.drawPane || - source == this.overlayPane); -}; - -/** - * Function: isScrollEvent - * - * Returns true if the event origin is one of the scrollbars of the - * container in IE. Such events are ignored. - */ - mxGraphView.prototype.isScrollEvent = function(evt) -{ - var offset = mxUtils.getOffset(this.graph.container); - var pt = new mxPoint(evt.clientX - offset.x, evt.clientY - offset.y); - - var outWidth = this.graph.container.offsetWidth; - var inWidth = this.graph.container.clientWidth; - - if (outWidth > inWidth && pt.x > inWidth + 2 && pt.x <= outWidth) - { - return true; - } - - var outHeight = this.graph.container.offsetHeight; - var inHeight = this.graph.container.clientHeight; - - if (outHeight > inHeight && pt.y > inHeight + 2 && pt.y <= outHeight) - { - return true; - } - - return false; -}; - -/** - * Function: init - * - * Initializes the graph event dispatch loop for the specified container - * and invokes <create> to create the required DOM nodes for the display. - */ -mxGraphView.prototype.init = function() -{ - this.installListeners(); - - // Creates the DOM nodes for the respective display dialect - var graph = this.graph; - - if (graph.dialect == mxConstants.DIALECT_SVG) - { - this.createSvg(); - } - else if (graph.dialect == mxConstants.DIALECT_VML) - { - this.createVml(); - } - else - { - this.createHtml(); - } -}; - -/** - * Function: installListeners - * - * Installs the required listeners in the container. - */ -mxGraphView.prototype.installListeners = function() -{ - var graph = this.graph; - var container = graph.container; - - if (container != null) - { - var md = (mxClient.IS_TOUCH) ? 'touchstart' : 'mousedown'; - var mm = (mxClient.IS_TOUCH) ? 'touchmove' : 'mousemove'; - var mu = (mxClient.IS_TOUCH) ? 'touchend' : 'mouseup'; - - // Adds basic listeners for graph event dispatching - mxEvent.addListener(container, md, - mxUtils.bind(this, function(evt) - { - // Workaround for touch-based device not transferring - // the focus while editing with virtual keyboard - if (mxClient.IS_TOUCH && graph.isEditing()) - { - graph.stopEditing(!graph.isInvokesStopCellEditing()); - } - - // Condition to avoid scrollbar events starting a rubberband - // selection - if (this.isContainerEvent(evt) && ((!mxClient.IS_IE && - !mxClient.IS_GC && !mxClient.IS_OP && !mxClient.IS_SF) || - !this.isScrollEvent(evt))) - { - graph.fireMouseEvent(mxEvent.MOUSE_DOWN, - new mxMouseEvent(evt)); - } - }) - ); - mxEvent.addListener(container, mm, - mxUtils.bind(this, function(evt) - { - if (this.isContainerEvent(evt)) - { - graph.fireMouseEvent(mxEvent.MOUSE_MOVE, - new mxMouseEvent(evt)); - } - }) - ); - mxEvent.addListener(container, mu, - mxUtils.bind(this, function(evt) - { - if (this.isContainerEvent(evt)) - { - graph.fireMouseEvent(mxEvent.MOUSE_UP, - new mxMouseEvent(evt)); - } - }) - ); - - // Adds listener for double click handling on background - mxEvent.addListener(container, 'dblclick', - mxUtils.bind(this, function(evt) - { - graph.dblClick(evt); - }) - ); - - // Workaround for touch events which started on some DOM node - // on top of the container, in which case the cells under the - // mouse for the move and up events are not detected. - var getState = function(evt) - { - var state = null; - - // Workaround for touch events which started on some DOM node - // on top of the container, in which case the cells under the - // mouse for the move and up events are not detected. - if (mxClient.IS_TOUCH) - { - var x = mxEvent.getClientX(evt); - var y = mxEvent.getClientY(evt); - - // Dispatches the drop event to the graph which - // consumes and executes the source function - var pt = mxUtils.convertPoint(container, x, y); - state = graph.view.getState(graph.getCellAt(pt.x, pt.y)); - } - - return state; - }; - - // Adds basic listeners for graph event dispatching outside of the - // container and finishing the handling of a single gesture - // Implemented via graph event dispatch loop to avoid duplicate events - // in Firefox and Chrome - graph.addMouseListener( - { - mouseDown: function(sender, me) - { - graph.panningHandler.hideMenu(); - }, - mouseMove: function() { }, - mouseUp: function() { } - }); - mxEvent.addListener(document, mm, - mxUtils.bind(this, function(evt) - { - // Hides the tooltip if mouse is outside container - if (graph.tooltipHandler != null && - graph.tooltipHandler.isHideOnHover()) - { - graph.tooltipHandler.hide(); - } - - if (this.captureDocumentGesture && graph.isMouseDown && - !mxEvent.isConsumed(evt)) - { - graph.fireMouseEvent(mxEvent.MOUSE_MOVE, - new mxMouseEvent(evt, getState(evt))); - } - }) - ); - mxEvent.addListener(document, mu, - mxUtils.bind(this, function(evt) - { - if (this.captureDocumentGesture) - { - graph.fireMouseEvent(mxEvent.MOUSE_UP, - new mxMouseEvent(evt)); - } - }) - ); - } -}; - -/** - * Function: create - * - * Creates the DOM nodes for the HTML display. - */ -mxGraphView.prototype.createHtml = function() -{ - var container = this.graph.container; - - if (container != null) - { - this.canvas = this.createHtmlPane('100%', '100%'); - - // Uses minimal size for inner DIVs on Canvas. This is required - // for correct event processing in IE. If we have an overlapping - // DIV then the events on the cells are only fired for labels. - this.backgroundPane = this.createHtmlPane('1px', '1px'); - this.drawPane = this.createHtmlPane('1px', '1px'); - this.overlayPane = this.createHtmlPane('1px', '1px'); - - this.canvas.appendChild(this.backgroundPane); - this.canvas.appendChild(this.drawPane); - this.canvas.appendChild(this.overlayPane); - - container.appendChild(this.canvas); - - // Implements minWidth/minHeight in quirks mode - if (mxClient.IS_QUIRKS) - { - var onResize = mxUtils.bind(this, function(evt) - { - var bounds = this.getGraphBounds(); - var width = bounds.x + bounds.width + this.graph.border; - var height = bounds.y + bounds.height + this.graph.border; - - this.updateHtmlCanvasSize(width, height); - }); - - mxEvent.addListener(window, 'resize', onResize); - } - } -}; - -/** - * Function: updateHtmlCanvasSize - * - * Updates the size of the HTML canvas. - */ -mxGraphView.prototype.updateHtmlCanvasSize = function(width, height) -{ - if (this.graph.container != null) - { - var ow = this.graph.container.offsetWidth; - var oh = this.graph.container.offsetHeight; - - if (ow < width) - { - this.canvas.style.width = width + 'px'; - } - else - { - this.canvas.style.width = '100%'; - } - - if (oh < height) - { - this.canvas.style.height = height + 'px'; - } - else - { - this.canvas.style.height = '100%'; - } - } -}; - -/** - * Function: createHtmlPane - * - * Creates and returns a drawing pane in HTML (DIV). - */ -mxGraphView.prototype.createHtmlPane = function(width, height) -{ - var pane = document.createElement('DIV'); - - if (width != null && height != null) - { - pane.style.position = 'absolute'; - pane.style.left = '0px'; - pane.style.top = '0px'; - - pane.style.width = width; - pane.style.height = height; - } - else - { - pane.style.position = 'relative'; - } - - return pane; -}; - -/** - * Function: create - * - * Creates the DOM nodes for the VML display. - */ -mxGraphView.prototype.createVml = function() -{ - var container = this.graph.container; - - if (container != null) - { - var width = container.offsetWidth; - var height = container.offsetHeight; - this.canvas = this.createVmlPane(width, height); - - this.backgroundPane = this.createVmlPane(width, height); - this.drawPane = this.createVmlPane(width, height); - this.overlayPane = this.createVmlPane(width, height); - - this.canvas.appendChild(this.backgroundPane); - this.canvas.appendChild(this.drawPane); - this.canvas.appendChild(this.overlayPane); - - container.appendChild(this.canvas); - } -}; - -/** - * Function: createVmlPane - * - * Creates a drawing pane in VML (group). - */ -mxGraphView.prototype.createVmlPane = function(width, height) -{ - var pane = document.createElement('v:group'); - - // At this point the width and height are potentially - // uninitialized. That's OK. - pane.style.position = 'absolute'; - pane.style.left = '0px'; - pane.style.top = '0px'; - - pane.style.width = width+'px'; - pane.style.height = height+'px'; - - pane.setAttribute('coordsize', width+','+height); - pane.setAttribute('coordorigin', '0,0'); - - return pane; -}; - -/** - * Function: create - * - * Creates and returns the DOM nodes for the SVG display. - */ -mxGraphView.prototype.createSvg = function() -{ - var container = this.graph.container; - this.canvas = document.createElementNS(mxConstants.NS_SVG, 'g'); - - // For background image - this.backgroundPane = document.createElementNS(mxConstants.NS_SVG, 'g'); - this.canvas.appendChild(this.backgroundPane); - - // Adds two layers (background is early feature) - this.drawPane = document.createElementNS(mxConstants.NS_SVG, 'g'); - this.canvas.appendChild(this.drawPane); - - this.overlayPane = document.createElementNS(mxConstants.NS_SVG, 'g'); - this.canvas.appendChild(this.overlayPane); - - var root = document.createElementNS(mxConstants.NS_SVG, 'svg'); - root.style.width = '100%'; - root.style.height = '100%'; - - if (mxClient.IS_IE) - { - root.style.marginBottom = '-4px'; - } - - root.appendChild(this.canvas); - - if (container != null) - { - container.appendChild(root); - - // Workaround for offset of container - var style = mxUtils.getCurrentStyle(container); - - if (style.position == 'static') - { - container.style.position = 'relative'; - } - } -}; - -/** - * Function: destroy - * - * Destroys the view and all its resources. - */ -mxGraphView.prototype.destroy = function() -{ - var root = (this.canvas != null) ? this.canvas.ownerSVGElement : null; - - if (root == null) - { - root = this.canvas; - } - - if (root != null && root.parentNode != null) - { - this.clear(this.currentRoot, true); - mxEvent.removeAllListeners(document); - mxEvent.release(this.graph.container); - root.parentNode.removeChild(root); - - this.canvas = null; - this.backgroundPane = null; - this.drawPane = null; - this.overlayPane = null; - } -}; - -/** - * Class: mxCurrentRootChange - * - * Action to change the current root in a view. - * - * Constructor: mxCurrentRootChange - * - * Constructs a change of the current root in the given view. - */ -function mxCurrentRootChange(view, root) -{ - this.view = view; - this.root = root; - this.previous = root; - this.isUp = root == null; - - if (!this.isUp) - { - var tmp = this.view.currentRoot; - var model = this.view.graph.getModel(); - - while (tmp != null) - { - if (tmp == root) - { - this.isUp = true; - break; - } - - tmp = model.getParent(tmp); - } - } -}; - -/** - * Function: execute - * - * Changes the current root of the view. - */ -mxCurrentRootChange.prototype.execute = function() -{ - var tmp = this.view.currentRoot; - this.view.currentRoot = this.previous; - this.previous = tmp; - - var translate = this.view.graph.getTranslateForRoot(this.view.currentRoot); - - if (translate != null) - { - this.view.translate = new mxPoint(-translate.x, -translate.y); - } - - var name = (this.isUp) ? mxEvent.UP : mxEvent.DOWN; - this.view.fireEvent(new mxEventObject(name, - 'root', this.view.currentRoot, 'previous', this.previous)); - - if (this.isUp) - { - this.view.clear(this.view.currentRoot, true); - this.view.validate(); - } - else - { - this.view.refresh(); - } - - this.isUp = !this.isUp; -}; diff --git a/src/js/view/mxLayoutManager.js b/src/js/view/mxLayoutManager.js deleted file mode 100644 index ee8ec65..0000000 --- a/src/js/view/mxLayoutManager.js +++ /dev/null @@ -1,375 +0,0 @@ -/** - * $Id: mxLayoutManager.js,v 1.21 2012-01-04 10:01:16 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -/** - * Class: mxLayoutManager - * - * Implements a layout manager that updates the layout for a given transaction. - * - * Example: - * - * (code) - * var layoutMgr = new mxLayoutManager(graph); - * layoutMgr.getLayout = function(cell) - * { - * return layout; - * }; - * (end) - * - * Event: mxEvent.LAYOUT_CELLS - * - * Fires between begin- and endUpdate after all cells have been layouted in - * <layoutCells>. The <code>cells</code> property contains all cells that have - * been passed to <layoutCells>. - * - * Constructor: mxLayoutManager - * - * Constructs a new automatic layout for the given graph. - * - * Arguments: - * - * graph - Reference to the enclosing graph. - */ -function mxLayoutManager(graph) -{ - // Executes the layout before the changes are dispatched - this.undoHandler = mxUtils.bind(this, function(sender, evt) - { - if (this.isEnabled()) - { - this.beforeUndo(evt.getProperty('edit')); - } - }); - - // Notifies the layout of a move operation inside a parent - this.moveHandler = mxUtils.bind(this, function(sender, evt) - { - if (this.isEnabled()) - { - this.cellsMoved(evt.getProperty('cells'), evt.getProperty('event')); - } - }); - - this.setGraph(graph); -}; - -/** - * Extends mxEventSource. - */ -mxLayoutManager.prototype = new mxEventSource(); -mxLayoutManager.prototype.constructor = mxLayoutManager; - -/** - * Variable: graph - * - * Reference to the enclosing <mxGraph>. - */ -mxLayoutManager.prototype.graph = null; - -/** - * Variable: bubbling - * - * Specifies if the layout should bubble along - * the cell hierarchy. Default is true. - */ -mxLayoutManager.prototype.bubbling = true; - -/** - * Variable: enabled - * - * Specifies if event handling is enabled. Default is true. - */ -mxLayoutManager.prototype.enabled = true; - -/** - * Variable: updateHandler - * - * Holds the function that handles the endUpdate event. - */ -mxLayoutManager.prototype.updateHandler = null; - -/** - * Variable: moveHandler - * - * Holds the function that handles the move event. - */ -mxLayoutManager.prototype.moveHandler = null; - -/** - * Function: isEnabled - * - * Returns true if events are handled. This implementation - * returns <enabled>. - */ -mxLayoutManager.prototype.isEnabled = function() -{ - return this.enabled; -}; - -/** - * Function: setEnabled - * - * Enables or disables event handling. This implementation - * updates <enabled>. - * - * Parameters: - * - * enabled - Boolean that specifies the new enabled state. - */ -mxLayoutManager.prototype.setEnabled = function(enabled) -{ - this.enabled = enabled; -}; - -/** - * Function: isBubbling - * - * Returns true if a layout should bubble, that is, if the parent layout - * should be executed whenever a cell layout (layout of the children of - * a cell) has been executed. This implementation returns <bubbling>. - */ -mxLayoutManager.prototype.isBubbling = function() -{ - return this.bubbling; -}; - -/** - * Function: setBubbling - * - * Sets <bubbling>. - */ -mxLayoutManager.prototype.setBubbling = function(value) -{ - this.bubbling = value; -}; - -/** - * Function: getGraph - * - * Returns the graph that this layout operates on. - */ -mxLayoutManager.prototype.getGraph = function() -{ - return this.graph; -}; - -/** - * Function: setGraph - * - * Sets the graph that the layouts operate on. - */ -mxLayoutManager.prototype.setGraph = function(graph) -{ - if (this.graph != null) - { - var model = this.graph.getModel(); - model.removeListener(this.undoHandler); - this.graph.removeListener(this.moveHandler); - } - - this.graph = graph; - - if (this.graph != null) - { - var model = this.graph.getModel(); - model.addListener(mxEvent.BEFORE_UNDO, this.undoHandler); - this.graph.addListener(mxEvent.MOVE_CELLS, this.moveHandler); - } -}; - -/** - * Function: getLayout - * - * Returns the layout to be executed for the given graph and parent. - */ -mxLayoutManager.prototype.getLayout = function(parent) -{ - return null; -}; - -/** - * Function: beforeUndo - * - * Called from the undoHandler. - * - * Parameters: - * - * cell - Array of <mxCells> that have been moved. - * evt - Mouse event that represents the mousedown. - */ -mxLayoutManager.prototype.beforeUndo = function(undoableEdit) -{ - var cells = this.getCellsForChanges(undoableEdit.changes); - var model = this.getGraph().getModel(); - - // Adds all parent ancestors - if (this.isBubbling()) - { - var tmp = model.getParents(cells); - - while (tmp.length > 0) - { - cells = cells.concat(tmp); - tmp = model.getParents(tmp); - } - } - - this.layoutCells(mxUtils.sortCells(cells, false)); -}; - -/** - * Function: cellsMoved - * - * Called from the moveHandler. - * - * Parameters: - * - * cell - Array of <mxCells> that have been moved. - * evt - Mouse event that represents the mousedown. - */ -mxLayoutManager.prototype.cellsMoved = function(cells, evt) -{ - if (cells != null && - evt != null) - { - var point = mxUtils.convertPoint(this.getGraph().container, - mxEvent.getClientX(evt), mxEvent.getClientY(evt)); - var model = this.getGraph().getModel(); - - // Checks if a layout exists to take care of the moving - for (var i = 0; i < cells.length; i++) - { - var layout = this.getLayout(model.getParent(cells[i])); - - if (layout != null) - { - layout.moveCell(cells[i], point.x, point.y); - } - } - } -}; - -/** - * Function: getCellsForEdit - * - * Returns the cells to be layouted for the given sequence of changes. - */ -mxLayoutManager.prototype.getCellsForChanges = function(changes) -{ - var result = []; - var hash = new Object(); - - for (var i = 0; i < changes.length; i++) - { - var change = changes[i]; - - if (change instanceof mxRootChange) - { - return []; - } - else - { - var cells = this.getCellsForChange(change); - - for (var j = 0; j < cells.length; j++) - { - if (cells[j] != null) - { - var id = mxCellPath.create(cells[j]); - - if (hash[id] == null) - { - hash[id] = cells[j]; - result.push(cells[j]); - } - } - } - } - } - - return result; -}; - -/** - * Function: getCellsForChange - * - * Executes all layouts which have been scheduled during the - * changes. - */ -mxLayoutManager.prototype.getCellsForChange = function(change) -{ - var model = this.getGraph().getModel(); - - if (change instanceof mxChildChange) - { - return [change.child, change.previous, model.getParent(change.child)]; - } - else if (change instanceof mxTerminalChange || - change instanceof mxGeometryChange) - { - return [change.cell, model.getParent(change.cell)]; - } - - return []; -}; - -/** - * Function: layoutCells - * - * Executes all layouts which have been scheduled during the - * changes. - */ -mxLayoutManager.prototype.layoutCells = function(cells) -{ - if (cells.length > 0) - { - // Invokes the layouts while removing duplicates - var model = this.getGraph().getModel(); - - model.beginUpdate(); - try - { - var last = null; - - for (var i = 0; i < cells.length; i++) - { - if (cells[i] != model.getRoot() && - cells[i] != last) - { - last = cells[i]; - this.executeLayout(this.getLayout(last), last); - } - } - - this.fireEvent(new mxEventObject(mxEvent.LAYOUT_CELLS, 'cells', cells)); - } - finally - { - model.endUpdate(); - } - } -}; - -/** - * Function: executeLayout - * - * Executes the given layout on the given parent. - */ -mxLayoutManager.prototype.executeLayout = function(layout, parent) -{ - if (layout != null && parent != null) - { - layout.execute(parent); - } -}; - -/** - * Function: destroy - * - * Removes all handlers from the <graph> and deletes the reference to it. - */ -mxLayoutManager.prototype.destroy = function() -{ - this.setGraph(null); -}; diff --git a/src/js/view/mxMultiplicity.js b/src/js/view/mxMultiplicity.js deleted file mode 100644 index c927d3f..0000000 --- a/src/js/view/mxMultiplicity.js +++ /dev/null @@ -1,257 +0,0 @@ -/** - * $Id: mxMultiplicity.js,v 1.24 2010-11-03 14:52:40 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -/** - * Class: mxMultiplicity - * - * Defines invalid connections along with the error messages that they produce. - * To add or remove rules on a graph, you must add/remove instances of this - * class to <mxGraph.multiplicities>. - * - * Example: - * - * (code) - * graph.multiplicities.push(new mxMultiplicity( - * true, 'rectangle', null, null, 0, 2, ['circle'], - * 'Only 2 targets allowed', - * 'Only circle targets allowed')); - * (end) - * - * Defines a rule where each rectangle must be connected to no more than 2 - * circles and no other types of targets are allowed. - * - * Constructor: mxMultiplicity - * - * Instantiate class mxMultiplicity in order to describe allowed - * connections in a graph. Not all constraints can be enforced while - * editing, some must be checked at validation time. The <countError> and - * <typeError> are treated as resource keys in <mxResources>. - * - * Parameters: - * - * source - Boolean indicating if this rule applies to the source or target - * terminal. - * type - Type of the source or target terminal that this rule applies to. - * See <type> for more information. - * attr - Optional attribute name to match the source or target terminal. - * value - Optional attribute value to match the source or target terminal. - * min - Minimum number of edges for this rule. Default is 1. - * max - Maximum number of edges for this rule. n means infinite. Default - * is n. - * validNeighbors - Array of types of the opposite terminal for which this - * rule applies. - * countError - Error to be displayed for invalid number of edges. - * typeError - Error to be displayed for invalid opposite terminals. - * validNeighborsAllowed - Optional boolean indicating if the array of - * opposite types should be valid or invalid. - */ -function mxMultiplicity(source, type, attr, value, min, max, - validNeighbors, countError, typeError, validNeighborsAllowed) -{ - this.source = source; - this.type = type; - this.attr = attr; - this.value = value; - this.min = (min != null) ? min : 0; - this.max = (max != null) ? max : 'n'; - this.validNeighbors = validNeighbors; - this.countError = mxResources.get(countError) || countError; - this.typeError = mxResources.get(typeError) || typeError; - this.validNeighborsAllowed = (validNeighborsAllowed != null) ? - validNeighborsAllowed : true; -}; - -/** - * Variable: type - * - * Defines the type of the source or target terminal. The type is a string - * passed to <mxUtils.isNode> together with the source or target vertex - * value as the first argument. - */ -mxMultiplicity.prototype.type = null; - -/** - * Variable: attr - * - * Optional string that specifies the attributename to be passed to - * <mxUtils.isNode> to check if the rule applies to a cell. - */ -mxMultiplicity.prototype.attr = null; - -/** - * Variable: value - * - * Optional string that specifies the value of the attribute to be passed - * to <mxUtils.isNode> to check if the rule applies to a cell. - */ -mxMultiplicity.prototype.value = null; - -/** - * Variable: source - * - * Boolean that specifies if the rule is applied to the source or target - * terminal of an edge. - */ -mxMultiplicity.prototype.source = null; - -/** - * Variable: min - * - * Defines the minimum number of connections for which this rule applies. - * Default is 0. - */ -mxMultiplicity.prototype.min = null; - -/** - * Variable: max - * - * Defines the maximum number of connections for which this rule applies. - * A value of 'n' means unlimited times. Default is 'n'. - */ -mxMultiplicity.prototype.max = null; - -/** - * Variable: validNeighbors - * - * Holds an array of strings that specify the type of neighbor for which - * this rule applies. The strings are used in <mxCell.is> on the opposite - * terminal to check if the rule applies to the connection. - */ -mxMultiplicity.prototype.validNeighbors = null; - -/** - * Variable: validNeighborsAllowed - * - * Boolean indicating if the list of validNeighbors are those that are allowed - * for this rule or those that are not allowed for this rule. - */ -mxMultiplicity.prototype.validNeighborsAllowed = true; - -/** - * Variable: countError - * - * Holds the localized error message to be displayed if the number of - * connections for which the rule applies is smaller than <min> or greater - * than <max>. - */ -mxMultiplicity.prototype.countError = null; - -/** - * Variable: typeError - * - * Holds the localized error message to be displayed if the type of the - * neighbor for a connection does not match the rule. - */ -mxMultiplicity.prototype.typeError = null; - -/** - * Function: check - * - * Checks the multiplicity for the given arguments and returns the error - * for the given connection or null if the multiplicity does not apply. - * - * Parameters: - * - * graph - Reference to the enclosing <mxGraph> instance. - * edge - <mxCell> that represents the edge to validate. - * source - <mxCell> that represents the source terminal. - * target - <mxCell> that represents the target terminal. - * sourceOut - Number of outgoing edges from the source terminal. - * targetIn - Number of incoming edges for the target terminal. - */ -mxMultiplicity.prototype.check = function(graph, edge, source, target, sourceOut, targetIn) -{ - var error = ''; - - if ((this.source && this.checkTerminal(graph, source, edge)) || - (!this.source && this.checkTerminal(graph, target, edge))) - { - if (this.countError != null && - ((this.source && (this.max == 0 || (sourceOut >= this.max))) || - (!this.source && (this.max == 0 || (targetIn >= this.max))))) - { - error += this.countError + '\n'; - } - - if (this.validNeighbors != null && this.typeError != null && this.validNeighbors.length > 0) - { - var isValid = this.checkNeighbors(graph, edge, source, target); - - if (!isValid) - { - error += this.typeError + '\n'; - } - } - } - - return (error.length > 0) ? error : null; -}; - -/** - * Function: checkNeighbors - * - * Checks if there are any valid neighbours in <validNeighbors>. This is only - * called if <validNeighbors> is a non-empty array. - */ -mxMultiplicity.prototype.checkNeighbors = function(graph, edge, source, target) -{ - var sourceValue = graph.model.getValue(source); - var targetValue = graph.model.getValue(target); - var isValid = !this.validNeighborsAllowed; - var valid = this.validNeighbors; - - for (var j = 0; j < valid.length; j++) - { - if (this.source && - this.checkType(graph, targetValue, valid[j])) - { - isValid = this.validNeighborsAllowed; - break; - } - else if (!this.source && - this.checkType(graph, sourceValue, valid[j])) - { - isValid = this.validNeighborsAllowed; - break; - } - } - - return isValid; -}; - -/** - * Function: checkTerminal - * - * Checks the given terminal cell and returns true if this rule applies. The - * given cell is the source or target of the given edge, depending on - * <source>. This implementation uses <checkType> on the terminal's value. - */ -mxMultiplicity.prototype.checkTerminal = function(graph, terminal, edge) -{ - var value = graph.model.getValue(terminal); - - return this.checkType(graph, value, this.type, this.attr, this.value); -}; - -/** - * Function: checkType - * - * Checks the type of the given value. - */ -mxMultiplicity.prototype.checkType = function(graph, value, type, attr, attrValue) -{ - if (value != null) - { - if (!isNaN(value.nodeType)) // Checks if value is a DOM node - { - return mxUtils.isNode(value, type, attr, attrValue); - } - else - { - return value == type; - } - } - - return false; -}; diff --git a/src/js/view/mxOutline.js b/src/js/view/mxOutline.js deleted file mode 100644 index a0d6fd3..0000000 --- a/src/js/view/mxOutline.js +++ /dev/null @@ -1,649 +0,0 @@ -/** - * $Id: mxOutline.js,v 1.81 2012-06-20 14:13:37 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -/** - * Class: mxOutline - * - * Implements an outline (aka overview) for a graph. Set <updateOnPan> to true - * to enable updates while the source graph is panning. - * - * Example: - * - * (code) - * var outline = new mxOutline(graph, div); - * (end) - * - * If the selection border in the outline appears behind the contents of the - * graph, then you can use the following code. (This may happen when using a - * transparent container for the outline in IE.) - * - * (code) - * mxOutline.prototype.graphRenderHint = mxConstants.RENDERING_HINT_EXACT; - * (end) - * - * To move the graph to the top, left corner the following code can be used. - * - * (code) - * var scale = graph.view.scale; - * var bounds = graph.getGraphBounds(); - * graph.view.setTranslate(-bounds.x / scale, -bounds.y / scale); - * (end) - * - * To toggle the suspended mode, the following can be used. - * - * (code) - * outline.suspended = !outln.suspended; - * if (!outline.suspended) - * { - * outline.update(true); - * } - * (end) - * - * Constructor: mxOutline - * - * Constructs a new outline for the specified graph inside the given - * container. - * - * Parameters: - * - * source - <mxGraph> to create the outline for. - * container - DOM node that will contain the outline. - */ -function mxOutline(source, container) -{ - this.source = source; - - if (container != null) - { - this.init(container); - } -}; - -/** - * Function: source - * - * Reference to the source <mxGraph>. - */ -mxOutline.prototype.source = null; - -/** - * Function: outline - * - * Reference to the outline <mxGraph>. - */ -mxOutline.prototype.outline = null; - -/** - * Function: graphRenderHint - * - * Renderhint to be used for the outline graph. Default is faster. - */ -mxOutline.prototype.graphRenderHint = mxConstants.RENDERING_HINT_FASTER; - -/** - * Variable: enabled - * - * Specifies if events are handled. Default is true. - */ -mxOutline.prototype.enabled = true; - -/** - * Variable: showViewport - * - * Specifies a viewport rectangle should be shown. Default is true. - */ -mxOutline.prototype.showViewport = true; - -/** - * Variable: border - * - * Border to be added at the bottom and right. Default is 10. - */ -mxOutline.prototype.border = 10; - -/** - * Variable: enabled - * - * Specifies the size of the sizer handler. Default is 8. - */ -mxOutline.prototype.sizerSize = 8; - -/** - * Variable: updateOnPan - * - * Specifies if <update> should be called for <mxEvent.PAN> in the source - * graph. Default is false. - */ -mxOutline.prototype.updateOnPan = false; - -/** - * Variable: sizerImage - * - * Optional <mxImage> to be used for the sizer. Default is null. - */ -mxOutline.prototype.sizerImage = null; - -/** - * Variable: suspended - * - * Optional boolean flag to suspend updates. Default is false. This flag will - * also suspend repaints of the outline. To toggle this switch, use the - * following code. - * - * (code) - * nav.suspended = !nav.suspended; - * - * if (!nav.suspended) - * { - * nav.update(true); - * } - * (end) - */ -mxOutline.prototype.suspended = false; - -/** - * Function: init - * - * Initializes the outline inside the given container. - */ -mxOutline.prototype.init = function(container) -{ - this.outline = new mxGraph(container, this.source.getModel(), this.graphRenderHint, this.source.getStylesheet()); - this.outline.foldingEnabled = false; - this.outline.autoScroll = false; - - // Do not repaint when suspended - var outlineGraphModelChanged = this.outline.graphModelChanged; - this.outline.graphModelChanged = mxUtils.bind(this, function(changes) - { - if (!this.suspended && this.outline != null) - { - outlineGraphModelChanged.apply(this.outline, arguments); - } - }); - - // Enables faster painting in SVG - if (mxClient.IS_SVG) - { - var node = this.outline.getView().getCanvas().parentNode; - node.setAttribute('shape-rendering', 'optimizeSpeed'); - node.setAttribute('image-rendering', 'optimizeSpeed'); - } - - // Hides cursors and labels - this.outline.labelsVisible = false; - this.outline.setEnabled(false); - - this.updateHandler = mxUtils.bind(this, function(sender, evt) - { - if (!this.suspended && !this.active) - { - this.update(); - } - }); - - // Updates the scale of the outline after a change of the main graph - this.source.getModel().addListener(mxEvent.CHANGE, this.updateHandler); - this.outline.addMouseListener(this); - - // Adds listeners to keep the outline in sync with the source graph - var view = this.source.getView(); - view.addListener(mxEvent.SCALE, this.updateHandler); - view.addListener(mxEvent.TRANSLATE, this.updateHandler); - view.addListener(mxEvent.SCALE_AND_TRANSLATE, this.updateHandler); - view.addListener(mxEvent.DOWN, this.updateHandler); - view.addListener(mxEvent.UP, this.updateHandler); - - // Updates blue rectangle on scroll - mxEvent.addListener(this.source.container, 'scroll', this.updateHandler); - - this.panHandler = mxUtils.bind(this, function(sender) - { - if (this.updateOnPan) - { - this.updateHandler.apply(this, arguments); - } - }); - this.source.addListener(mxEvent.PAN, this.panHandler); - - // Refreshes the graph in the outline after a refresh of the main graph - this.refreshHandler = mxUtils.bind(this, function(sender) - { - this.outline.setStylesheet(this.source.getStylesheet()); - this.outline.refresh(); - }); - this.source.addListener(mxEvent.REFRESH, this.refreshHandler); - - // Creates the blue rectangle for the viewport - this.bounds = new mxRectangle(0, 0, 0, 0); - this.selectionBorder = new mxRectangleShape(this.bounds, null, - mxConstants.OUTLINE_COLOR, mxConstants.OUTLINE_STROKEWIDTH); - this.selectionBorder.dialect = - (this.outline.dialect != mxConstants.DIALECT_SVG) ? - mxConstants.DIALECT_VML : mxConstants.DIALECT_SVG; - this.selectionBorder.crisp = true; - this.selectionBorder.init(this.outline.getView().getOverlayPane()); - mxEvent.redirectMouseEvents(this.selectionBorder.node, this.outline); - this.selectionBorder.node.style.background = ''; - - // Creates a small blue rectangle for sizing (sizer handle) - this.sizer = this.createSizer(); - this.sizer.init(this.outline.getView().getOverlayPane()); - - if (this.enabled) - { - this.sizer.node.style.cursor = 'pointer'; - } - - // Redirects all events from the sizerhandle to the outline - mxEvent.addListener(this.sizer.node, (mxClient.IS_TOUCH) ? 'touchstart' : 'mousedown', - mxUtils.bind(this, function(evt) - { - this.outline.fireMouseEvent(mxEvent.MOUSE_DOWN, new mxMouseEvent(evt)); - }) - ); - - this.selectionBorder.node.style.display = (this.showViewport) ? '' : 'none'; - this.sizer.node.style.display = this.selectionBorder.node.style.display; - this.selectionBorder.node.style.cursor = 'move'; - - this.update(false); -}; - -/** - * Function: isEnabled - * - * Returns true if events are handled. This implementation - * returns <enabled>. - */ -mxOutline.prototype.isEnabled = function() -{ - return this.enabled; -}; - -/** - * Function: setEnabled - * - * Enables or disables event handling. This implementation - * updates <enabled>. - * - * Parameters: - * - * value - Boolean that specifies the new enabled state. - */ -mxOutline.prototype.setEnabled = function(value) -{ - this.enabled = value; -}; - -/** - * Function: setZoomEnabled - * - * Enables or disables the zoom handling by showing or hiding the respective - * handle. - * - * Parameters: - * - * value - Boolean that specifies the new enabled state. - */ -mxOutline.prototype.setZoomEnabled = function(value) -{ - this.sizer.node.style.visibility = (value) ? 'visible' : 'hidden'; -}; - -/** - * Function: refresh - * - * Invokes <update> and revalidate the outline. This method is deprecated. - */ -mxOutline.prototype.refresh = function() -{ - this.update(true); -}; - -/** - * Function: createSizer - * - * Creates the shape used as the sizer. - */ -mxOutline.prototype.createSizer = function() -{ - if (this.sizerImage != null) - { - var sizer = new mxImageShape(new mxRectangle(0, 0, this.sizerImage.width, this.sizerImage.height), this.sizerImage.src); - sizer.dialect = this.outline.dialect; - - return sizer; - } - else - { - var sizer = new mxRectangleShape(new mxRectangle(0, 0, this.sizerSize, this.sizerSize), - mxConstants.OUTLINE_HANDLE_FILLCOLOR, mxConstants.OUTLINE_HANDLE_STROKECOLOR); - sizer.dialect = this.outline.dialect; - sizer.crisp = true; - - return sizer; - } -}; - -/** - * Function: getSourceContainerSize - * - * Returns the size of the source container. - */ -mxOutline.prototype.getSourceContainerSize = function() -{ - return new mxRectangle(0, 0, this.source.container.scrollWidth, this.source.container.scrollHeight); -}; - -/** - * Function: getOutlineOffset - * - * Returns the offset for drawing the outline graph. - */ -mxOutline.prototype.getOutlineOffset = function(scale) -{ - return null; -}; - -/** - * Function: update - * - * Updates the outline. - */ -mxOutline.prototype.update = function(revalidate) -{ - if (this.source != null) - { - var sourceScale = this.source.view.scale; - var scaledGraphBounds = this.source.getGraphBounds(); - var unscaledGraphBounds = new mxRectangle(scaledGraphBounds.x / sourceScale + this.source.panDx, - scaledGraphBounds.y / sourceScale + this.source.panDy, scaledGraphBounds.width / sourceScale, - scaledGraphBounds.height / sourceScale); - - var unscaledFinderBounds = new mxRectangle(0, 0, - this.source.container.clientWidth / sourceScale, - this.source.container.clientHeight / sourceScale); - - var union = unscaledGraphBounds.clone(); - union.add(unscaledFinderBounds); - - // Zooms to the scrollable area if that is bigger than the graph - var size = this.getSourceContainerSize(); - var completeWidth = Math.max(size.width / sourceScale, union.width); - var completeHeight = Math.max(size.height / sourceScale, union.height); - - var availableWidth = Math.max(0, this.outline.container.clientWidth - this.border); - var availableHeight = Math.max(0, this.outline.container.clientHeight - this.border); - - var outlineScale = Math.min(availableWidth / completeWidth, availableHeight / completeHeight); - var scale = outlineScale; - - if (scale > 0) - { - if (this.outline.getView().scale != scale) - { - this.outline.getView().scale = scale; - revalidate = true; - } - - var navView = this.outline.getView(); - - if (navView.currentRoot != this.source.getView().currentRoot) - { - navView.setCurrentRoot(this.source.getView().currentRoot); - } - - var t = this.source.view.translate; - var tx = t.x + this.source.panDx; - var ty = t.y + this.source.panDy; - - var off = this.getOutlineOffset(scale); - - if (off != null) - { - tx += off.x; - ty += off.y; - } - - if (unscaledGraphBounds.x < 0) - { - tx = tx - unscaledGraphBounds.x; - } - if (unscaledGraphBounds.y < 0) - { - ty = ty - unscaledGraphBounds.y; - } - - if (navView.translate.x != tx || navView.translate.y != ty) - { - navView.translate.x = tx; - navView.translate.y = ty; - revalidate = true; - } - - // Prepares local variables for computations - var t2 = navView.translate; - scale = this.source.getView().scale; - var scale2 = scale / navView.scale; - var scale3 = 1.0 / navView.scale; - var container = this.source.container; - - // Updates the bounds of the viewrect in the navigation - this.bounds = new mxRectangle( - (t2.x - t.x - this.source.panDx) / scale3, - (t2.y - t.y - this.source.panDy) / scale3, - (container.clientWidth / scale2), - (container.clientHeight / scale2)); - - // Adds the scrollbar offset to the finder - this.bounds.x += this.source.container.scrollLeft * navView.scale / scale; - this.bounds.y += this.source.container.scrollTop * navView.scale / scale; - - var b = this.selectionBorder.bounds; - - if (b.x != this.bounds.x || b.y != this.bounds.y || b.width != this.bounds.width || b.height != this.bounds.height) - { - this.selectionBorder.bounds = this.bounds; - this.selectionBorder.redraw(); - } - - // Updates the bounds of the zoom handle at the bottom right - var b = this.sizer.bounds; - var b2 = new mxRectangle(this.bounds.x + this.bounds.width - b.width / 2, - this.bounds.y + this.bounds.height - b.height / 2, b.width, b.height); - - if (b.x != b2.x || b.y != b2.y || b.width != b2.width || b.height != b2.height) - { - this.sizer.bounds = b2; - - // Avoids update of visibility in redraw for VML - if (this.sizer.node.style.visibility != 'hidden') - { - this.sizer.redraw(); - } - } - - if (revalidate) - { - this.outline.view.revalidate(); - } - } - } -}; - -/** - * Function: mouseDown - * - * Handles the event by starting a translation or zoom. - */ -mxOutline.prototype.mouseDown = function(sender, me) -{ - if (this.enabled && this.showViewport) - { - this.zoom = me.isSource(this.sizer); - this.startX = me.getX(); - this.startY = me.getY(); - this.active = true; - - if (this.source.useScrollbarsForPanning && - mxUtils.hasScrollbars(this.source.container)) - { - this.dx0 = this.source.container.scrollLeft; - this.dy0 = this.source.container.scrollTop; - } - else - { - this.dx0 = 0; - this.dy0 = 0; - } - } - - me.consume(); -}; - -/** - * Function: mouseMove - * - * Handles the event by previewing the viewrect in <graph> and updating the - * rectangle that represents the viewrect in the outline. - */ -mxOutline.prototype.mouseMove = function(sender, me) -{ - if (this.active) - { - this.selectionBorder.node.style.display = (this.showViewport) ? '' : 'none'; - this.sizer.node.style.display = this.selectionBorder.node.style.display; - - var dx = me.getX() - this.startX; - var dy = me.getY() - this.startY; - var bounds = null; - - if (!this.zoom) - { - // Previews the panning on the source graph - var scale = this.outline.getView().scale; - bounds = new mxRectangle(this.bounds.x + dx, - this.bounds.y + dy, this.bounds.width, this.bounds.height); - this.selectionBorder.bounds = bounds; - this.selectionBorder.redraw(); - dx /= scale; - dx *= this.source.getView().scale; - dy /= scale; - dy *= this.source.getView().scale; - this.source.panGraph(-dx - this.dx0, -dy - this.dy0); - } - else - { - // Does *not* preview zooming on the source graph - var container = this.source.container; - var viewRatio = container.clientWidth / container.clientHeight; - dy = dx / viewRatio; - bounds = new mxRectangle(this.bounds.x, - this.bounds.y, - Math.max(1, this.bounds.width + dx), - Math.max(1, this.bounds.height + dy)); - this.selectionBorder.bounds = bounds; - this.selectionBorder.redraw(); - } - - // Updates the zoom handle - var b = this.sizer.bounds; - this.sizer.bounds = new mxRectangle( - bounds.x + bounds.width - b.width / 2, - bounds.y + bounds.height - b.height / 2, - b.width, b.height); - - // Avoids update of visibility in redraw for VML - if (this.sizer.node.style.visibility != 'hidden') - { - this.sizer.redraw(); - } - - me.consume(); - } -}; - -/** - * Function: mouseUp - * - * Handles the event by applying the translation or zoom to <graph>. - */ -mxOutline.prototype.mouseUp = function(sender, me) -{ - if (this.active) - { - var dx = me.getX() - this.startX; - var dy = me.getY() - this.startY; - - if (Math.abs(dx) > 0 || Math.abs(dy) > 0) - { - if (!this.zoom) - { - // Applies the new translation if the source - // has no scrollbars - if (!this.source.useScrollbarsForPanning || - !mxUtils.hasScrollbars(this.source.container)) - { - this.source.panGraph(0, 0); - dx /= this.outline.getView().scale; - dy /= this.outline.getView().scale; - var t = this.source.getView().translate; - this.source.getView().setTranslate(t.x - dx, t.y - dy); - } - } - else - { - // Applies the new zoom - var w = this.selectionBorder.bounds.width; - var scale = this.source.getView().scale; - this.source.zoomTo(scale - (dx * scale) / w, false); - } - - this.update(); - me.consume(); - } - - // Resets the state of the handler - this.index = null; - this.active = false; - } -}; - -/** - * Function: destroy - * - * Destroy this outline and removes all listeners from <source>. - */ -mxOutline.prototype.destroy = function() -{ - if (this.source != null) - { - this.source.removeListener(this.panHandler); - this.source.removeListener(this.refreshHandler); - this.source.getModel().removeListener(this.updateHandler); - this.source.getView().removeListener(this.updateHandler); - mxEvent.addListener(this.source.container, 'scroll', this.updateHandler); - this.source = null; - } - - if (this.outline != null) - { - this.outline.removeMouseListener(this); - this.outline.destroy(); - this.outline = null; - } - - if (this.selectionBorder != null) - { - this.selectionBorder.destroy(); - this.selectionBorder = null; - } - - if (this.sizer != null) - { - this.sizer.destroy(); - this.sizer = null; - } -}; diff --git a/src/js/view/mxPerimeter.js b/src/js/view/mxPerimeter.js deleted file mode 100644 index 7aaa187..0000000 --- a/src/js/view/mxPerimeter.js +++ /dev/null @@ -1,484 +0,0 @@ -/** - * $Id: mxPerimeter.js,v 1.28 2012-01-11 09:06:56 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -var mxPerimeter = -{ - /** - * Class: mxPerimeter - * - * Provides various perimeter functions to be used in a style - * as the value of <mxConstants.STYLE_PERIMETER>. Perimeters for - * rectangle, circle, rhombus and triangle are available. - * - * Example: - * - * (code) - * <add as="perimeter">mxPerimeter.RightAngleRectanglePerimeter</add> - * (end) - * - * Or programmatically: - * - * (code) - * style[mxConstants.STYLE_PERIMETER] = mxPerimeter.RectanglePerimeter; - * (end) - * - * When adding new perimeter functions, it is recommended to use the - * mxPerimeter-namespace as follows: - * - * (code) - * mxPerimeter.CustomPerimeter = function (bounds, vertex, next, orthogonal) - * { - * var x = 0; // Calculate x-coordinate - * var y = 0; // Calculate y-coordainte - * - * return new mxPoint(x, y); - * } - * (end) - * - * The new perimeter should then be registered in the <mxStyleRegistry> as follows: - * (code) - * mxStyleRegistry.putValue('customPerimeter', mxPerimeter.CustomPerimeter); - * (end) - * - * The custom perimeter above can now be used in a specific vertex as follows: - * - * (code) - * model.setStyle(vertex, 'perimeter=customPerimeter'); - * (end) - * - * Note that the key of the <mxStyleRegistry> entry for the function should - * be used in string values, unless <mxGraphView.allowEval> is true, in - * which case you can also use mxPerimeter.CustomPerimeter for the value in - * the cell style above. - * - * Or it can be used for all vertices in the graph as follows: - * - * (code) - * var style = graph.getStylesheet().getDefaultVertexStyle(); - * style[mxConstants.STYLE_PERIMETER] = mxPerimeter.CustomPerimeter; - * (end) - * - * Note that the object can be used directly when programmatically setting - * the value, but the key in the <mxStyleRegistry> should be used when - * setting the value via a key, value pair in a cell style. - * - * The parameters are explained in <RectanglePerimeter>. - * - * Function: RectanglePerimeter - * - * Describes a rectangular perimeter for the given bounds. - * - * Parameters: - * - * bounds - <mxRectangle> that represents the absolute bounds of the - * vertex. - * vertex - <mxCellState> that represents the vertex. - * next - <mxPoint> that represents the nearest neighbour point on the - * given edge. - * orthogonal - Boolean that specifies if the orthogonal projection onto - * the perimeter should be returned. If this is false then the intersection - * of the perimeter and the line between the next and the center point is - * returned. - */ - RectanglePerimeter: function (bounds, vertex, next, orthogonal) - { - var cx = bounds.getCenterX(); - var cy = bounds.getCenterY(); - var dx = next.x - cx; - var dy = next.y - cy; - var alpha = Math.atan2(dy, dx); - var p = new mxPoint(0, 0); - var pi = Math.PI; - var pi2 = Math.PI/2; - var beta = pi2 - alpha; - var t = Math.atan2(bounds.height, bounds.width); - - if (alpha < -pi + t || alpha > pi - t) - { - // Left edge - p.x = bounds.x; - p.y = cy - bounds.width * Math.tan(alpha) / 2; - } - else if (alpha < -t) - { - // Top Edge - p.y = bounds.y; - p.x = cx - bounds.height * Math.tan(beta) / 2; - } - else if (alpha < t) - { - // Right Edge - p.x = bounds.x + bounds.width; - p.y = cy + bounds.width * Math.tan(alpha) / 2; - } - else - { - // Bottom Edge - p.y = bounds.y + bounds.height; - p.x = cx + bounds.height * Math.tan(beta) / 2; - } - - if (orthogonal) - { - if (next.x >= bounds.x && - next.x <= bounds.x + bounds.width) - { - p.x = next.x; - } - else if (next.y >= bounds.y && - next.y <= bounds.y + bounds.height) - { - p.y = next.y; - } - if (next.x < bounds.x) - { - p.x = bounds.x; - } - else if (next.x > bounds.x + bounds.width) - { - p.x = bounds.x + bounds.width; - } - if (next.y < bounds.y) - { - p.y = bounds.y; - } - else if (next.y > bounds.y + bounds.height) - { - p.y = bounds.y + bounds.height; - } - } - - return p; - }, - - /** - * Function: EllipsePerimeter - * - * Describes an elliptic perimeter. See <RectanglePerimeter> - * for a description of the parameters. - */ - EllipsePerimeter: function (bounds, vertex, next, orthogonal) - { - var x = bounds.x; - var y = bounds.y; - var a = bounds.width / 2; - var b = bounds.height / 2; - var cx = x + a; - var cy = y + b; - var px = next.x; - var py = next.y; - - // Calculates straight line equation through - // point and ellipse center y = d * x + h - var dx = parseInt(px - cx); - var dy = parseInt(py - cy); - - if (dx == 0 && dy != 0) - { - return new mxPoint(cx, cy + b * dy / Math.abs(dy)); - } - else if (dx == 0 && dy == 0) - { - return new mxPoint(px, py); - } - - if (orthogonal) - { - if (py >= y && py <= y + bounds.height) - { - var ty = py - cy; - var tx = Math.sqrt(a*a*(1-(ty*ty)/(b*b))) || 0; - - if (px <= x) - { - tx = -tx; - } - - return new mxPoint(cx+tx, py); - } - - if (px >= x && px <= x + bounds.width) - { - var tx = px - cx; - var ty = Math.sqrt(b*b*(1-(tx*tx)/(a*a))) || 0; - - if (py <= y) - { - ty = -ty; - } - - return new mxPoint(px, cy+ty); - } - } - - // Calculates intersection - var d = dy / dx; - var h = cy - d * cx; - var e = a * a * d * d + b * b; - var f = -2 * cx * e; - var g = a * a * d * d * cx * cx + - b * b * cx * cx - - a * a * b * b; - var det = Math.sqrt(f * f - 4 * e * g); - - // Two solutions (perimeter points) - var xout1 = (-f + det) / (2 * e); - var xout2 = (-f - det) / (2 * e); - var yout1 = d * xout1 + h; - var yout2 = d * xout2 + h; - var dist1 = Math.sqrt(Math.pow((xout1 - px), 2) - + Math.pow((yout1 - py), 2)); - var dist2 = Math.sqrt(Math.pow((xout2 - px), 2) - + Math.pow((yout2 - py), 2)); - - // Correct solution - var xout = 0; - var yout = 0; - - if (dist1 < dist2) - { - xout = xout1; - yout = yout1; - } - else - { - xout = xout2; - yout = yout2; - } - - return new mxPoint(xout, yout); - }, - - /** - * Function: RhombusPerimeter - * - * Describes a rhombus (aka diamond) perimeter. See <RectanglePerimeter> - * for a description of the parameters. - */ - RhombusPerimeter: function (bounds, vertex, next, orthogonal) - { - var x = bounds.x; - var y = bounds.y; - var w = bounds.width; - var h = bounds.height; - - var cx = x + w / 2; - var cy = y + h / 2; - - var px = next.x; - var py = next.y; - - // Special case for intersecting the diamond's corners - if (cx == px) - { - if (cy > py) - { - return new mxPoint(cx, y); // top - } - else - { - return new mxPoint(cx, y + h); // bottom - } - } - else if (cy == py) - { - if (cx > px) - { - return new mxPoint(x, cy); // left - } - else - { - return new mxPoint(x + w, cy); // right - } - } - - var tx = cx; - var ty = cy; - - if (orthogonal) - { - if (px >= x && px <= x + w) - { - tx = px; - } - else if (py >= y && py <= y + h) - { - ty = py; - } - } - - // In which quadrant will the intersection be? - // set the slope and offset of the border line accordingly - if (px < cx) - { - if (py < cy) - { - return mxUtils.intersection(px, py, tx, ty, cx, y, x, cy); - } - else - { - return mxUtils.intersection(px, py, tx, ty, cx, y + h, x, cy); - } - } - else if (py < cy) - { - return mxUtils.intersection(px, py, tx, ty, cx, y, x + w, cy); - } - else - { - return mxUtils.intersection(px, py, tx, ty, cx, y + h, x + w, cy); - } - }, - - /** - * Function: TrianglePerimeter - * - * Describes a triangle perimeter. See <RectanglePerimeter> - * for a description of the parameters. - */ - TrianglePerimeter: function (bounds, vertex, next, orthogonal) - { - var direction = (vertex != null) ? - vertex.style[mxConstants.STYLE_DIRECTION] : null; - var vertical = direction == mxConstants.DIRECTION_NORTH || - direction == mxConstants.DIRECTION_SOUTH; - - var x = bounds.x; - var y = bounds.y; - var w = bounds.width; - var h = bounds.height; - - var cx = x + w / 2; - var cy = y + h / 2; - - var start = new mxPoint(x, y); - var corner = new mxPoint(x + w, cy); - var end = new mxPoint(x, y + h); - - if (direction == mxConstants.DIRECTION_NORTH) - { - start = end; - corner = new mxPoint(cx, y); - end = new mxPoint(x + w, y + h); - } - else if (direction == mxConstants.DIRECTION_SOUTH) - { - corner = new mxPoint(cx, y + h); - end = new mxPoint(x + w, y); - } - else if (direction == mxConstants.DIRECTION_WEST) - { - start = new mxPoint(x + w, y); - corner = new mxPoint(x, cy); - end = new mxPoint(x + w, y + h); - } - - var dx = next.x - cx; - var dy = next.y - cy; - - var alpha = (vertical) ? Math.atan2(dx, dy) : Math.atan2(dy, dx); - var t = (vertical) ? Math.atan2(w, h) : Math.atan2(h, w); - - var base = false; - - if (direction == mxConstants.DIRECTION_NORTH || - direction == mxConstants.DIRECTION_WEST) - { - base = alpha > -t && alpha < t; - } - else - { - base = alpha < -Math.PI + t || alpha > Math.PI - t; - } - - var result = null; - - if (base) - { - if (orthogonal && ((vertical && next.x >= start.x && next.x <= end.x) || - (!vertical && next.y >= start.y && next.y <= end.y))) - { - if (vertical) - { - result = new mxPoint(next.x, start.y); - } - else - { - result = new mxPoint(start.x, next.y); - } - } - else - { - if (direction == mxConstants.DIRECTION_NORTH) - { - result = new mxPoint(x + w / 2 + h * Math.tan(alpha) / 2, - y + h); - } - else if (direction == mxConstants.DIRECTION_SOUTH) - { - result = new mxPoint(x + w / 2 - h * Math.tan(alpha) / 2, - y); - } - else if (direction == mxConstants.DIRECTION_WEST) - { - result = new mxPoint(x + w, y + h / 2 + - w * Math.tan(alpha) / 2); - } - else - { - result = new mxPoint(x, y + h / 2 - - w * Math.tan(alpha) / 2); - } - } - } - else - { - if (orthogonal) - { - var pt = new mxPoint(cx, cy); - - if (next.y >= y && next.y <= y + h) - { - pt.x = (vertical) ? cx : ( - (direction == mxConstants.DIRECTION_WEST) ? - x + w : x); - pt.y = next.y; - } - else if (next.x >= x && next.x <= x + w) - { - pt.x = next.x; - pt.y = (!vertical) ? cy : ( - (direction == mxConstants.DIRECTION_NORTH) ? - y + h : y); - } - - // Compute angle - dx = next.x - pt.x; - dy = next.y - pt.y; - - cx = pt.x; - cy = pt.y; - } - - if ((vertical && next.x <= x + w / 2) || - (!vertical && next.y <= y + h / 2)) - { - result = mxUtils.intersection(next.x, next.y, cx, cy, - start.x, start.y, corner.x, corner.y); - } - else - { - result = mxUtils.intersection(next.x, next.y, cx, cy, - corner.x, corner.y, end.x, end.y); - } - } - - if (result == null) - { - result = new mxPoint(cx, cy); - } - - return result; - } -}; diff --git a/src/js/view/mxPrintPreview.js b/src/js/view/mxPrintPreview.js deleted file mode 100644 index 24a65e6..0000000 --- a/src/js/view/mxPrintPreview.js +++ /dev/null @@ -1,801 +0,0 @@ -/** - * $Id: mxPrintPreview.js,v 1.61 2012-05-15 14:12:40 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -/** - * Class: mxPrintPreview - * - * Implements printing of a diagram across multiple pages. The following opens - * a print preview for an existing graph: - * - * (code) - * var preview = new mxPrintPreview(graph); - * preview.open(); - * (end) - * - * Use <mxUtils.getScaleForPageCount> as follows in order to print the graph - * across a given number of pages: - * - * (code) - * var pageCount = mxUtils.prompt('Enter page count', '1'); - * - * if (pageCount != null) - * { - * var scale = mxUtils.getScaleForPageCount(pageCount, graph); - * var preview = new mxPrintPreview(graph, scale); - * preview.open(); - * } - * (end) - * - * Headers: - * - * Apart from setting the title argument in the mxPrintPreview constructor you - * can override <renderPage> as follows to add a header to any page: - * - * (code) - * var oldRenderPage = mxPrintPreview.prototype.renderPage; - * mxPrintPreview.prototype.renderPage = function(w, h, dx, dy, scale, pageNumber) - * { - * var div = oldRenderPage.apply(this, arguments); - * - * var header = document.createElement('div'); - * header.style.position = 'absolute'; - * header.style.top = '0px'; - * header.style.width = '100%'; - * header.style.textAlign = 'right'; - * mxUtils.write(header, 'Your header here - Page ' + pageNumber + ' / ' + this.pageCount); - * div.firstChild.appendChild(header); - * - * return div; - * }; - * (end) - * - * Page Format: - * - * For landscape printing, use <mxConstants.PAGE_FORMAT_A4_LANDSCAPE> as - * the pageFormat in <mxUtils.getScaleForPageCount> and <mxPrintPreview>. - * Keep in mind that one can not set the defaults for the print dialog - * of the operating system from JavaScript so the user must manually choose - * a page format that matches this setting. - * - * You can try passing the following CSS directive to <open> to set the - * page format in the print dialog to landscape. However, this CSS - * directive seems to be ignored in most major browsers, including IE. - * - * (code) - * @page { - * size: landscape; - * } - * (end) - * - * Note that the print preview behaves differently in IE when used from the - * filesystem or via HTTP so printing should always be tested via HTTP. - * - * If you are using a DOCTYPE in the source page you can override <getDoctype> - * and provide the same DOCTYPE for the print preview if required. Here is - * an example for IE8 standards mode. - * - * (code) - * var preview = new mxPrintPreview(graph); - * preview.getDoctype = function() - * { - * return '<!--[if IE]><meta http-equiv="X-UA-Compatible" content="IE=5,IE=8" ><![endif]-->'; - * }; - * preview.open(); - * (end) - * - * Constructor: mxPrintPreview - * - * Constructs a new print preview for the given parameters. - * - * Parameters: - * - * graph - <mxGraph> to be previewed. - * scale - Optional scale of the output. Default is 1 / <mxGraph.pageScale>. - * border - Border in pixels along each side of every page. Note that the - * actual print function in the browser will add another border for - * printing. - * pageFormat - <mxRectangle> that specifies the page format (in pixels). - * This should match the page format of the printer. Default uses the - * <mxGraph.pageFormat> of the given graph. - * x0 - Optional left offset of the output. Default is 0. - * y0 - Optional top offset of the output. Default is 0. - * borderColor - Optional color of the page border. Default is no border. - * Note that a border is sometimes useful to highlight the printed page - * border in the print preview of the browser. - * title - Optional string that is used for the window title. Default - * is 'Printer-friendly version'. - * pageSelector - Optional boolean that specifies if the page selector - * should appear in the window with the print preview. Default is true. - */ -function mxPrintPreview(graph, scale, pageFormat, border, x0, y0, borderColor, title, pageSelector) -{ - this.graph = graph; - this.scale = (scale != null) ? scale : 1 / graph.pageScale; - this.border = (border != null) ? border : 0; - this.pageFormat = (pageFormat != null) ? pageFormat : graph.pageFormat; - this.title = (title != null) ? title : 'Printer-friendly version'; - this.x0 = (x0 != null) ? x0 : 0; - this.y0 = (y0 != null) ? y0 : 0; - this.borderColor = borderColor; - this.pageSelector = (pageSelector != null) ? pageSelector : true; -}; - -/** - * Variable: graph - * - * Reference to the <mxGraph> that should be previewed. - */ -mxPrintPreview.prototype.graph = null; - -/** - * Variable: pageFormat - * - * Holds the <mxRectangle> that defines the page format. - */ -mxPrintPreview.prototype.pageFormat = null; - -/** - * Variable: scale - * - * Holds the scale of the print preview. - */ -mxPrintPreview.prototype.scale = null; - -/** - * Variable: border - * - * The border inset around each side of every page in the preview. This is set - * to 0 if autoOrigin is false. - */ -mxPrintPreview.prototype.border = 0; - -/** -/** - * Variable: x0 - * - * Holds the horizontal offset of the output. - */ -mxPrintPreview.prototype.x0 = 0; - -/** - * Variable: y0 - * - * Holds the vertical offset of the output. - */ -mxPrintPreview.prototype.y0 = 0; - -/** - * Variable: autoOrigin - * - * Specifies if the origin should be automatically computed based on the top, - * left corner of the actual diagram contents. If this is set to false then the - * values for <x0> and <y0> will be overridden in <open>. Default is true. - */ -mxPrintPreview.prototype.autoOrigin = true; - -/** - * Variable: printOverlays - * - * Specifies if overlays should be printed. Default is false. - */ -mxPrintPreview.prototype.printOverlays = false; - -/** - * Variable: borderColor - * - * Holds the color value for the page border. - */ -mxPrintPreview.prototype.borderColor = null; - -/** - * Variable: title - * - * Holds the title of the preview window. - */ -mxPrintPreview.prototype.title = null; - -/** - * Variable: pageSelector - * - * Boolean that specifies if the page selector should be - * displayed. Default is true. - */ -mxPrintPreview.prototype.pageSelector = null; - -/** - * Variable: wnd - * - * Reference to the preview window. - */ -mxPrintPreview.prototype.wnd = null; - -/** - * Variable: pageCount - * - * Holds the actual number of pages in the preview. - */ -mxPrintPreview.prototype.pageCount = 0; - -/** - * Function: getWindow - * - * Returns <wnd>. - */ -mxPrintPreview.prototype.getWindow = function() -{ - return this.wnd; -}; - -/** - * Function: getDocType - * - * Returns the string that should go before the HTML tag in the print preview - * page. This implementation returns an empty string. - */ -mxPrintPreview.prototype.getDoctype = function() -{ - return ''; -}; - -/** - * Function: open - * - * Shows the print preview window. The window is created here if it does - * not exist. - * - * Parameters: - * - * css - Optional CSS string to be used in the new page's head section. - */ -mxPrintPreview.prototype.open = function(css) -{ - // Closing the window while the page is being rendered may cause an - // exception in IE. This and any other exceptions are simply ignored. - var previousInitializeOverlay = this.graph.cellRenderer.initializeOverlay; - var div = null; - - try - { - // Temporarily overrides the method to redirect rendering of overlays - // to the draw pane so that they are visible in the printout - if (this.printOverlays) - { - this.graph.cellRenderer.initializeOverlay = function(state, overlay) - { - overlay.init(state.view.getDrawPane()); - }; - } - - if (this.wnd == null) - { - this.wnd = window.open(); - var doc = this.wnd.document; - var dt = this.getDoctype(); - - if (dt != null && dt.length > 0) - { - doc.writeln(dt); - } - - doc.writeln('<html>'); - doc.writeln('<head>'); - this.writeHead(doc, css); - doc.writeln('</head>'); - doc.writeln('<body class="mxPage">'); - - // Adds all required stylesheets and namespaces - mxClient.link('stylesheet', mxClient.basePath + '/css/common.css', doc); - - if (mxClient.IS_IE && document.documentMode != 9) - { - doc.namespaces.add('v', 'urn:schemas-microsoft-com:vml'); - doc.namespaces.add('o', 'urn:schemas-microsoft-com:office:office'); - var ss = doc.createStyleSheet(); - ss.cssText = 'v\\:*{behavior:url(#default#VML)}o\\:*{behavior:url(#default#VML)}'; - mxClient.link('stylesheet', mxClient.basePath + '/css/explorer.css', doc); - } - - // Computes the horizontal and vertical page count - var bounds = this.graph.getGraphBounds().clone(); - var currentScale = this.graph.getView().getScale(); - var sc = currentScale / this.scale; - var tr = this.graph.getView().getTranslate(); - - // Uses the absolute origin with no offset for all printing - if (!this.autoOrigin) - { - this.x0 = -tr.x * this.scale; - this.y0 = -tr.y * this.scale; - bounds.width += bounds.x; - bounds.height += bounds.y; - bounds.x = 0; - bounds.y = 0; - this.border = 0; - } - - // Compute the unscaled, untranslated bounds to find - // the number of vertical and horizontal pages - bounds.width /= sc; - bounds.height /= sc; - - // Store the available page area - var availableWidth = this.pageFormat.width - (this.border * 2); - var availableHeight = this.pageFormat.height - (this.border * 2); - - var hpages = Math.max(1, Math.ceil((bounds.width + this.x0) / availableWidth)); - var vpages = Math.max(1, Math.ceil((bounds.height + this.y0) / availableHeight)); - this.pageCount = hpages * vpages; - - var writePageSelector = mxUtils.bind(this, function() - { - if (this.pageSelector && (vpages > 1 || hpages > 1)) - { - var table = this.createPageSelector(vpages, hpages); - doc.body.appendChild(table); - - // Workaround for position: fixed which isn't working in IE - if (mxClient.IS_IE) - { - table.style.position = 'absolute'; - - var update = function() - { - table.style.top = (doc.body.scrollTop + 10) + 'px'; - }; - - mxEvent.addListener(this.wnd, 'scroll', function(evt) - { - update(); - }); - - mxEvent.addListener(this.wnd, 'resize', function(evt) - { - update(); - }); - } - } - }); - - // Stores pages for later retrieval - var pages = null; - - // Workaround for aspect of image shapes updated asynchronously - // in VML so we need to fetch the markup of the DIV containing - // the image after the udpate of the style of the DOM node. - // LATER: Allow document for display markup to be customized. - if (mxClient.IS_IE && document.documentMode != 9) - { - pages = []; - - // Overrides asynchronous loading of images for fetching HTML markup - var waitCounter = 0; - var isDone = false; - - var mxImageShapeScheduleUpdateAspect = mxImageShape.prototype.scheduleUpdateAspect; - var mxImageShapeUpdateAspect = mxImageShape.prototype.updateAspect; - - var writePages = function() - { - if (isDone && waitCounter == 0) - { - // Restores previous implementations - mxImageShape.prototype.scheduleUpdateAspect = mxImageShapeScheduleUpdateAspect; - mxImageShape.prototype.updateAspect = mxImageShapeUpdateAspect; - - var markup = ''; - - for (var i = 0; i < pages.length; i++) - { - markup += pages[i].outerHTML; - pages[i].parentNode.removeChild(pages[i]); - - if (i < pages.length - 1) - { - markup += '<hr/>'; - } - } - - doc.body.innerHTML = markup; - writePageSelector(); - } - }; - - // Overrides functions to implement wait counter - mxImageShape.prototype.scheduleUpdateAspect = function() - { - waitCounter++; - mxImageShapeScheduleUpdateAspect.apply(this, arguments); - }; - - // Overrides functions to implement wait counter - mxImageShape.prototype.updateAspect = function() - { - mxImageShapeUpdateAspect.apply(this, arguments); - waitCounter--; - writePages(); - }; - } - - // Appends each page to the page output for printing, making - // sure there will be a page break after each page (ie. div) - for (var i = 0; i < vpages; i++) - { - var dy = i * availableHeight / this.scale - this.y0 / this.scale + - (bounds.y - tr.y * currentScale) / currentScale; - - for (var j = 0; j < hpages; j++) - { - if (this.wnd == null) - { - return null; - } - - var dx = j * availableWidth / this.scale - this.x0 / this.scale + - (bounds.x - tr.x * currentScale) / currentScale; - var pageNum = i * hpages + j + 1; - - div = this.renderPage(this.pageFormat.width, this.pageFormat.height, - -dx, -dy, this.scale, pageNum); - - // Gives the page a unique ID for later accessing the page - div.setAttribute('id', 'mxPage-'+pageNum); - - // Border of the DIV (aka page) inside the document - if (this.borderColor != null) - { - div.style.borderColor = this.borderColor; - div.style.borderStyle = 'solid'; - div.style.borderWidth = '1px'; - } - - // Needs to be assigned directly because IE doesn't support - // child selectors, eg. body > div { background: white; } - div.style.background = 'white'; - - if (i < vpages - 1 || j < hpages - 1) - { - div.style.pageBreakAfter = 'always'; - } - - // NOTE: We are dealing with cross-window DOM here, which - // is a problem in IE, so we copy the HTML markup instead. - // The underlying problem is that the graph display markup - // creation (in mxShape, mxGraphView) is hardwired to using - // document.createElement and hence we must use document - // to create the complete page and then copy it over to the - // new window.document. This can be fixed later by using the - // ownerDocument of the container in mxShape and mxGraphView. - if (mxClient.IS_IE) - { - // For some obscure reason, removing the DIV from the - // parent before fetching its outerHTML has missing - // fillcolor properties and fill children, so the div - // must be removed afterwards to keep the fillcolors. - // For delayed output we remote the DIV from the - // original document when we write out all pages. - doc.writeln(div.outerHTML); - - if (pages != null) - { - pages.push(div); - } - else - { - div.parentNode.removeChild(div); - } - } - else - { - div.parentNode.removeChild(div); - doc.body.appendChild(div); - } - - if (i < vpages - 1 || j < hpages - 1) - { - var hr = doc.createElement('hr'); - hr.className = 'mxPageBreak'; - doc.body.appendChild(hr); - } - } - } - - doc.writeln('</body>'); - doc.writeln('</html>'); - doc.close(); - - // Marks the printing complete for async handling - if (pages != null) - { - isDone = true; - writePages(); - } - else - { - writePageSelector(); - } - - // Removes all event handlers in the print output - mxEvent.release(doc.body); - } - - this.wnd.focus(); - } - catch (e) - { - // Removes the DIV from the document in case of an error - if (div != null && div.parentNode != null) - { - div.parentNode.removeChild(div); - } - } - finally - { - this.graph.cellRenderer.initializeOverlay = previousInitializeOverlay; - } - - return this.wnd; -}; - -/** - * Function: writeHead - * - * Writes the HEAD section into the given document, without the opening - * and closing HEAD tags. - */ -mxPrintPreview.prototype.writeHead = function(doc, css) -{ - if (this.title != null) - { - doc.writeln('<title>' + this.title + '</title>'); - } - - // Makes sure no horizontal rulers are printed - doc.writeln('<style type="text/css">'); - doc.writeln('@media print {'); - doc.writeln(' table.mxPageSelector { display: none; }'); - doc.writeln(' hr.mxPageBreak { display: none; }'); - doc.writeln('}'); - doc.writeln('@media screen {'); - - // NOTE: position: fixed is not supported in IE, so the page selector - // position (absolute) needs to be updated in IE (see below) - doc.writeln(' table.mxPageSelector { position: fixed; right: 10px; top: 10px;' + - 'font-family: Arial; font-size:10pt; border: solid 1px darkgray;' + - 'background: white; border-collapse:collapse; }'); - doc.writeln(' table.mxPageSelector td { border: solid 1px gray; padding:4px; }'); - doc.writeln(' body.mxPage { background: gray; }'); - doc.writeln('}'); - - if (css != null) - { - doc.writeln(css); - } - - doc.writeln('</style>'); -}; - -/** - * Function: createPageSelector - * - * Creates the page selector table. - */ -mxPrintPreview.prototype.createPageSelector = function(vpages, hpages) -{ - var doc = this.wnd.document; - var table = doc.createElement('table'); - table.className = 'mxPageSelector'; - table.setAttribute('border', '0'); - - var tbody = doc.createElement('tbody'); - - for (var i = 0; i < vpages; i++) - { - var row = doc.createElement('tr'); - - for (var j = 0; j < hpages; j++) - { - var pageNum = i * hpages + j + 1; - var cell = doc.createElement('td'); - - // Needs anchor for all browers to work without JavaScript - // LATER: Does not work in Firefox because the generated document - // has the URL of the opening document, the anchor is appended - // to that URL and the full URL is loaded on click. - if (!mxClient.IS_NS || mxClient.IS_SF || mxClient.IS_GC) - { - var a = doc.createElement('a'); - a.setAttribute('href', '#mxPage-' + pageNum); - mxUtils.write(a, pageNum, doc); - cell.appendChild(a); - } - else - { - mxUtils.write(cell, pageNum, doc); - } - - row.appendChild(cell); - } - - tbody.appendChild(row); - } - - table.appendChild(tbody); - - return table; -}; - -/** - * Function: renderPage - * - * Creates a DIV that prints a single page of the given - * graph using the given scale and returns the DIV that - * represents the page. - * - * Parameters: - * - * w - Width of the page in pixels. - * h - Height of the page in pixels. - * dx - Horizontal translation for the diagram. - * dy - Vertical translation for the diagram. - * scale - Scale for the diagram. - * pageNumber - Number of the page to be rendered. - */ -mxPrintPreview.prototype.renderPage = function(w, h, dx, dy, scale, pageNumber) -{ - var div = document.createElement('div'); - - try - { - div.style.width = w + 'px'; - div.style.height = h + 'px'; - div.style.overflow = 'hidden'; - div.style.pageBreakInside = 'avoid'; - - var innerDiv = document.createElement('div'); - innerDiv.style.top = this.border + 'px'; - innerDiv.style.left = this.border + 'px'; - innerDiv.style.width = (w - 2 * this.border) + 'px'; - innerDiv.style.height = (h - 2 * this.border) + 'px'; - innerDiv.style.overflow = 'hidden'; - - if (this.graph.dialect == mxConstants.DIALECT_VML) - { - innerDiv.style.position = 'absolute'; - } - - div.appendChild(innerDiv); - document.body.appendChild(div); - var view = this.graph.getView(); - - var previousContainer = this.graph.container; - this.graph.container = innerDiv; - - var canvas = view.getCanvas(); - var backgroundPane = view.getBackgroundPane(); - var drawPane = view.getDrawPane(); - var overlayPane = view.getOverlayPane(); - - if (this.graph.dialect == mxConstants.DIALECT_SVG) - { - view.createSvg(); - } - else if (this.graph.dialect == mxConstants.DIALECT_VML) - { - view.createVml(); - } - else - { - view.createHtml(); - } - - // Disables events on the view - var eventsEnabled = view.isEventsEnabled(); - view.setEventsEnabled(false); - - // Disables the graph to avoid cursors - var graphEnabled = this.graph.isEnabled(); - this.graph.setEnabled(false); - - // Resets the translation - var translate = view.getTranslate(); - view.translate = new mxPoint(dx, dy); - - var temp = null; - - try - { - // Creates the temporary cell states in the view and - // draws them onto the temporary DOM nodes in the view - var model = this.graph.getModel(); - var cells = [model.getRoot()]; - temp = new mxTemporaryCellStates(view, scale, cells); - } - finally - { - // Removes overlay pane with selection handles - // controls and icons from the print output - if (mxClient.IS_IE) - { - view.overlayPane.innerHTML = ''; - } - else - { - // Removes everything but the SVG node - var tmp = innerDiv.firstChild; - - while (tmp != null) - { - var next = tmp.nextSibling; - var name = tmp.nodeName.toLowerCase(); - - // Note: Width and heigh are required in FF 11 - if (name == 'svg') - { - tmp.setAttribute('width', parseInt(innerDiv.style.width)); - tmp.setAttribute('height', parseInt(innerDiv.style.height)); - } - // Tries to fetch all text labels and only text labels - else if (tmp.style.cursor != 'default' && name != 'table') - { - tmp.parentNode.removeChild(tmp); - } - - tmp = next; - } - } - - // Completely removes the overlay pane to remove more handles - view.overlayPane.parentNode.removeChild(view.overlayPane); - - // Restores the state of the view - this.graph.setEnabled(graphEnabled); - this.graph.container = previousContainer; - view.canvas = canvas; - view.backgroundPane = backgroundPane; - view.drawPane = drawPane; - view.overlayPane = overlayPane; - view.translate = translate; - temp.destroy(); - view.setEventsEnabled(eventsEnabled); - } - } - catch (e) - { - div.parentNode.removeChild(div); - div = null; - - throw e; - } - - return div; -}; - -/** - * Function: print - * - * Opens the print preview and shows the print dialog. - */ -mxPrintPreview.prototype.print = function() -{ - var wnd = this.open(); - - if (wnd != null) - { - wnd.print(); - } -}; - -/** - * Function: close - * - * Closes the print preview window. - */ -mxPrintPreview.prototype.close = function() -{ - if (this.wnd != null) - { - this.wnd.close(); - this.wnd = null; - } -}; diff --git a/src/js/view/mxSpaceManager.js b/src/js/view/mxSpaceManager.js deleted file mode 100644 index 2a2dd11..0000000 --- a/src/js/view/mxSpaceManager.js +++ /dev/null @@ -1,460 +0,0 @@ -/** - * $Id: mxSpaceManager.js,v 1.9 2010-01-02 09:45:15 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -/** - * Class: mxSpaceManager - * - * In charge of moving cells after a resize. - * - * Constructor: mxSpaceManager - * - * Constructs a new automatic layout for the given graph. - * - * Arguments: - * - * graph - Reference to the enclosing graph. - */ -function mxSpaceManager(graph, shiftRightwards, shiftDownwards, extendParents) -{ - this.resizeHandler = mxUtils.bind(this, function(sender, evt) - { - if (this.isEnabled()) - { - this.cellsResized(evt.getProperty('cells')); - } - }); - - this.foldHandler = mxUtils.bind(this, function(sender, evt) - { - if (this.isEnabled()) - { - this.cellsResized(evt.getProperty('cells')); - } - }); - - this.shiftRightwards = (shiftRightwards != null) ? shiftRightwards : true; - this.shiftDownwards = (shiftDownwards != null) ? shiftDownwards : true; - this.extendParents = (extendParents != null) ? extendParents : true; - this.setGraph(graph); -}; - -/** - * Extends mxEventSource. - */ -mxSpaceManager.prototype = new mxEventSource(); -mxSpaceManager.prototype.constructor = mxSpaceManager; - -/** - * Variable: graph - * - * Reference to the enclosing <mxGraph>. - */ -mxSpaceManager.prototype.graph = null; - -/** - * Variable: enabled - * - * Specifies if event handling is enabled. Default is true. - */ -mxSpaceManager.prototype.enabled = true; - -/** - * Variable: shiftRightwards - * - * Specifies if event handling is enabled. Default is true. - */ -mxSpaceManager.prototype.shiftRightwards = true; - -/** - * Variable: shiftDownwards - * - * Specifies if event handling is enabled. Default is true. - */ -mxSpaceManager.prototype.shiftDownwards = true; - -/** - * Variable: extendParents - * - * Specifies if event handling is enabled. Default is true. - */ -mxSpaceManager.prototype.extendParents = true; - -/** - * Variable: resizeHandler - * - * Holds the function that handles the move event. - */ -mxSpaceManager.prototype.resizeHandler = null; - -/** - * Variable: foldHandler - * - * Holds the function that handles the fold event. - */ -mxSpaceManager.prototype.foldHandler = null; - -/** - * Function: isCellIgnored - * - * Sets the graph that the layouts operate on. - */ -mxSpaceManager.prototype.isCellIgnored = function(cell) -{ - return !this.getGraph().getModel().isVertex(cell); -}; - -/** - * Function: isCellShiftable - * - * Sets the graph that the layouts operate on. - */ -mxSpaceManager.prototype.isCellShiftable = function(cell) -{ - return this.getGraph().getModel().isVertex(cell) && - this.getGraph().isCellMovable(cell); -}; - -/** - * Function: isEnabled - * - * Returns true if events are handled. This implementation - * returns <enabled>. - */ -mxSpaceManager.prototype.isEnabled = function() -{ - return this.enabled; -}; - -/** - * Function: setEnabled - * - * Enables or disables event handling. This implementation - * updates <enabled>. - * - * Parameters: - * - * enabled - Boolean that specifies the new enabled state. - */ -mxSpaceManager.prototype.setEnabled = function(value) -{ - this.enabled = value; -}; - -/** - * Function: isShiftRightwards - * - * Returns true if events are handled. This implementation - * returns <enabled>. - */ -mxSpaceManager.prototype.isShiftRightwards = function() -{ - return this.shiftRightwards; -}; - -/** - * Function: setShiftRightwards - * - * Enables or disables event handling. This implementation - * updates <enabled>. - * - * Parameters: - * - * enabled - Boolean that specifies the new enabled state. - */ -mxSpaceManager.prototype.setShiftRightwards = function(value) -{ - this.shiftRightwards = value; -}; - -/** - * Function: isShiftDownwards - * - * Returns true if events are handled. This implementation - * returns <enabled>. - */ -mxSpaceManager.prototype.isShiftDownwards = function() -{ - return this.shiftDownwards; -}; - -/** - * Function: setShiftDownwards - * - * Enables or disables event handling. This implementation - * updates <enabled>. - * - * Parameters: - * - * enabled - Boolean that specifies the new enabled state. - */ -mxSpaceManager.prototype.setShiftDownwards = function(value) -{ - this.shiftDownwards = value; -}; - -/** - * Function: isExtendParents - * - * Returns true if events are handled. This implementation - * returns <enabled>. - */ -mxSpaceManager.prototype.isExtendParents = function() -{ - return this.extendParents; -}; - -/** - * Function: setShiftDownwards - * - * Enables or disables event handling. This implementation - * updates <enabled>. - * - * Parameters: - * - * enabled - Boolean that specifies the new enabled state. - */ -mxSpaceManager.prototype.setExtendParents = function(value) -{ - this.extendParents = value; -}; - -/** - * Function: getGraph - * - * Returns the graph that this layout operates on. - */ -mxSpaceManager.prototype.getGraph = function() -{ - return this.graph; -}; - -/** - * Function: setGraph - * - * Sets the graph that the layouts operate on. - */ -mxSpaceManager.prototype.setGraph = function(graph) -{ - if (this.graph != null) - { - this.graph.removeListener(this.resizeHandler); - this.graph.removeListener(this.foldHandler); - } - - this.graph = graph; - - if (this.graph != null) - { - this.graph.addListener(mxEvent.RESIZE_CELLS, this.resizeHandler); - this.graph.addListener(mxEvent.FOLD_CELLS, this.foldHandler); - } -}; - -/** - * Function: cellsResized - * - * Called from <moveCellsIntoParent> to invoke the <move> hook in the - * automatic layout of each modified cell's parent. The event is used to - * define the x- and y-coordinates passed to the move function. - * - * Parameters: - * - * cell - Array of <mxCells> that have been resized. - */ -mxSpaceManager.prototype.cellsResized = function(cells) -{ - if (cells != null) - { - var model = this.graph.getModel(); - - // Raising the update level should not be required - // since only one call is made below - model.beginUpdate(); - try - { - for (var i = 0; i < cells.length; i++) - { - if (!this.isCellIgnored(cells[i])) - { - this.cellResized(cells[i]); - break; - } - } - } - finally - { - model.endUpdate(); - } - } -}; - -/** - * Function: cellResized - * - * Called from <moveCellsIntoParent> to invoke the <move> hook in the - * automatic layout of each modified cell's parent. The event is used to - * define the x- and y-coordinates passed to the move function. - * - * Parameters: - * - * cell - <mxCell> that has been resized. - */ -mxSpaceManager.prototype.cellResized = function(cell) -{ - var graph = this.getGraph(); - var view = graph.getView(); - var model = graph.getModel(); - - var state = view.getState(cell); - var pstate = view.getState(model.getParent(cell)); - - if (state != null && - pstate != null) - { - var cells = this.getCellsToShift(state); - var geo = model.getGeometry(cell); - - if (cells != null && - geo != null) - { - var tr = view.translate; - var scale = view.scale; - - var x0 = state.x - pstate.origin.x - tr.x * scale; - var y0 = state.y - pstate.origin.y - tr.y * scale; - var right = state.x + state.width; - var bottom = state.y + state.height; - - var dx = state.width - geo.width * scale + x0 - geo.x * scale; - var dy = state.height - geo.height * scale + y0 - geo.y * scale; - - var fx = 1 - geo.width * scale / state.width; - var fy = 1 - geo.height * scale / state.height; - - model.beginUpdate(); - try - { - for (var i = 0; i < cells.length; i++) - { - if (cells[i] != cell && - this.isCellShiftable(cells[i])) - { - this.shiftCell(cells[i], dx, dy, x0, y0, right, bottom, fx, fy, - this.isExtendParents() && - graph.isExtendParent(cells[i])); - } - } - } - finally - { - model.endUpdate(); - } - } - } -}; - -/** - * Function: shiftCell - * - * Called from <moveCellsIntoParent> to invoke the <move> hook in the - * automatic layout of each modified cell's parent. The event is used to - * define the x- and y-coordinates passed to the move function. - * - * Parameters: - * - * cell - Array of <mxCells> that have been moved. - * evt - Mouse event that represents the mousedown. - */ -mxSpaceManager.prototype.shiftCell = function(cell, dx, dy, Ox0, y0, right, - bottom, fx, fy, extendParent) -{ - var graph = this.getGraph(); - var state = graph.getView().getState(cell); - - if (state != null) - { - var model = graph.getModel(); - var geo = model.getGeometry(cell); - - if (geo != null) - { - model.beginUpdate(); - try - { - if (this.isShiftRightwards()) - { - if (state.x >= right) - { - geo = geo.clone(); - geo.translate(-dx, 0); - } - else - { - var tmpDx = Math.max(0, state.x - x0); - geo = geo.clone(); - geo.translate(-fx * tmpDx, 0); - } - } - - if (this.isShiftDownwards()) - { - if (state.y >= bottom) - { - geo = geo.clone(); - geo.translate(0, -dy); - } - else - { - var tmpDy = Math.max(0, state.y - y0); - geo = geo.clone(); - geo.translate(0, -fy * tmpDy); - } - } - - if (geo != model.getGeometry(cell)) - { - model.setGeometry(cell, geo); - - // Parent size might need to be updated if this - // is seen as part of the resize - if (extendParent) - { - graph.extendParent(cell); - } - } - } - finally - { - model.endUpdate(); - } - } - } -}; - -/** - * Function: getCellsToShift - * - * Returns the cells to shift after a resize of the - * specified <mxCellState>. - */ -mxSpaceManager.prototype.getCellsToShift = function(state) -{ - var graph = this.getGraph(); - var parent = graph.getModel().getParent(state.cell); - var down = this.isShiftDownwards(); - var right = this.isShiftRightwards(); - - return graph.getCellsBeyond(state.x + ((down) ? 0 : state.width), - state.y + ((down && right) ? 0 : state.height), parent, right, down); -}; - -/** - * Function: destroy - * - * Removes all handlers from the <graph> and deletes the reference to it. - */ -mxSpaceManager.prototype.destroy = function() -{ - this.setGraph(null); -}; diff --git a/src/js/view/mxStyleRegistry.js b/src/js/view/mxStyleRegistry.js deleted file mode 100644 index 6ad878d..0000000 --- a/src/js/view/mxStyleRegistry.js +++ /dev/null @@ -1,70 +0,0 @@ -/** - * $Id: mxStyleRegistry.js,v 1.10 2011-04-27 10:15:39 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -var mxStyleRegistry = -{ - /** - * Class: mxStyleRegistry - * - * Singleton class that acts as a global converter from string to object values - * in a style. This is currently only used to perimeters and edge styles. - * - * Variable: values - * - * Maps from strings to objects. - */ - values: [], - - /** - * Function: putValue - * - * Puts the given object into the registry under the given name. - */ - putValue: function(name, obj) - { - mxStyleRegistry.values[name] = obj; - }, - - /** - * Function: getValue - * - * Returns the value associated with the given name. - */ - getValue: function(name) - { - return mxStyleRegistry.values[name]; - }, - - /** - * Function: getName - * - * Returns the name for the given value. - */ - getName: function(value) - { - for (var key in mxStyleRegistry.values) - { - if (mxStyleRegistry.values[key] == value) - { - return key; - } - } - - return null; - } - -}; - -mxStyleRegistry.putValue(mxConstants.EDGESTYLE_ELBOW, mxEdgeStyle.ElbowConnector); -mxStyleRegistry.putValue(mxConstants.EDGESTYLE_ENTITY_RELATION, mxEdgeStyle.EntityRelation); -mxStyleRegistry.putValue(mxConstants.EDGESTYLE_LOOP, mxEdgeStyle.Loop); -mxStyleRegistry.putValue(mxConstants.EDGESTYLE_SIDETOSIDE, mxEdgeStyle.SideToSide); -mxStyleRegistry.putValue(mxConstants.EDGESTYLE_TOPTOBOTTOM, mxEdgeStyle.TopToBottom); -mxStyleRegistry.putValue(mxConstants.EDGESTYLE_ORTHOGONAL, mxEdgeStyle.OrthConnector); -mxStyleRegistry.putValue(mxConstants.EDGESTYLE_SEGMENT, mxEdgeStyle.SegmentConnector); - -mxStyleRegistry.putValue(mxConstants.PERIMETER_ELLIPSE, mxPerimeter.EllipsePerimeter); -mxStyleRegistry.putValue(mxConstants.PERIMETER_RECTANGLE, mxPerimeter.RectanglePerimeter); -mxStyleRegistry.putValue(mxConstants.PERIMETER_RHOMBUS, mxPerimeter.RhombusPerimeter); -mxStyleRegistry.putValue(mxConstants.PERIMETER_TRIANGLE, mxPerimeter.TrianglePerimeter); diff --git a/src/js/view/mxStylesheet.js b/src/js/view/mxStylesheet.js deleted file mode 100644 index 82a520e..0000000 --- a/src/js/view/mxStylesheet.js +++ /dev/null @@ -1,266 +0,0 @@ -/** - * $Id: mxStylesheet.js,v 1.35 2010-03-26 10:24:58 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -/** - * Class: mxStylesheet - * - * Defines the appearance of the cells in a graph. See <putCellStyle> for an - * example of creating a new cell style. It is recommended to use objects, not - * arrays for holding cell styles. Existing styles can be cloned using - * <mxUtils.clone> and turned into a string for debugging using - * <mxUtils.toString>. - * - * Default Styles: - * - * The stylesheet contains two built-in styles, which are used if no style is - * defined for a cell: - * - * defaultVertex - Default style for vertices - * defaultEdge - Default style for edges - * - * Example: - * - * (code) - * var vertexStyle = stylesheet.getDefaultVertexStyle(); - * vertexStyle[mxConstants.ROUNDED] = true; - * var edgeStyle = stylesheet.getDefaultEdgeStyle(); - * edgeStyle[mxConstants.STYLE_EDGE] = mxEdgeStyle.EntityRelation; - * (end) - * - * Modifies the built-in default styles. - * - * To avoid the default style for a cell, add a leading semicolon - * to the style definition, eg. - * - * (code) - * ;shadow=1 - * (end) - * - * Removing keys: - * - * For removing a key in a cell style of the form [stylename;|key=value;] the - * special value none can be used, eg. highlight;fillColor=none - * - * See also the helper methods in mxUtils to modify strings of this format, - * namely <mxUtils.setStyle>, <mxUtils.indexOfStylename>, - * <mxUtils.addStylename>, <mxUtils.removeStylename>, - * <mxUtils.removeAllStylenames> and <mxUtils.setStyleFlag>. - * - * Constructor: mxStylesheet - * - * Constructs a new stylesheet and assigns default styles. - */ -function mxStylesheet() -{ - this.styles = new Object(); - - this.putDefaultVertexStyle(this.createDefaultVertexStyle()); - this.putDefaultEdgeStyle(this.createDefaultEdgeStyle()); -}; - -/** - * Function: styles - * - * Maps from names to cell styles. Each cell style is a map of key, - * value pairs. - */ -mxStylesheet.prototype.styles; - -/** - * Function: createDefaultVertexStyle - * - * Creates and returns the default vertex style. - */ -mxStylesheet.prototype.createDefaultVertexStyle = function() -{ - var style = new Object(); - - style[mxConstants.STYLE_SHAPE] = mxConstants.SHAPE_RECTANGLE; - style[mxConstants.STYLE_PERIMETER] = mxPerimeter.RectanglePerimeter; - style[mxConstants.STYLE_VERTICAL_ALIGN] = mxConstants.ALIGN_MIDDLE; - style[mxConstants.STYLE_ALIGN] = mxConstants.ALIGN_CENTER; - style[mxConstants.STYLE_FILLCOLOR] = '#C3D9FF'; - style[mxConstants.STYLE_STROKECOLOR] = '#6482B9'; - style[mxConstants.STYLE_FONTCOLOR] = '#774400'; - - return style; -}; - -/** - * Function: createDefaultEdgeStyle - * - * Creates and returns the default edge style. - */ -mxStylesheet.prototype.createDefaultEdgeStyle = function() -{ - var style = new Object(); - - style[mxConstants.STYLE_SHAPE] = mxConstants.SHAPE_CONNECTOR; - style[mxConstants.STYLE_ENDARROW] = mxConstants.ARROW_CLASSIC; - style[mxConstants.STYLE_VERTICAL_ALIGN] = mxConstants.ALIGN_MIDDLE; - style[mxConstants.STYLE_ALIGN] = mxConstants.ALIGN_CENTER; - style[mxConstants.STYLE_STROKECOLOR] = '#6482B9'; - style[mxConstants.STYLE_FONTCOLOR] = '#446299'; - - return style; -}; - -/** - * Function: putDefaultVertexStyle - * - * Sets the default style for vertices using defaultVertex as the - * stylename. - * - * Parameters: - * style - Key, value pairs that define the style. - */ -mxStylesheet.prototype.putDefaultVertexStyle = function(style) -{ - this.putCellStyle('defaultVertex', style); -}; - -/** - * Function: putDefaultEdgeStyle - * - * Sets the default style for edges using defaultEdge as the stylename. - */ -mxStylesheet.prototype.putDefaultEdgeStyle = function(style) -{ - this.putCellStyle('defaultEdge', style); -}; - -/** - * Function: getDefaultVertexStyle - * - * Returns the default style for vertices. - */ -mxStylesheet.prototype.getDefaultVertexStyle = function() -{ - return this.styles['defaultVertex']; -}; - -/** - * Function: getDefaultEdgeStyle - * - * Sets the default style for edges. - */ -mxStylesheet.prototype.getDefaultEdgeStyle = function() -{ - return this.styles['defaultEdge']; -}; - -/** - * Function: putCellStyle - * - * Stores the given map of key, value pairs under the given name in - * <styles>. - * - * Example: - * - * The following example adds a new style called 'rounded' into an - * existing stylesheet: - * - * (code) - * var style = new Object(); - * style[mxConstants.STYLE_SHAPE] = mxConstants.SHAPE_RECTANGLE; - * style[mxConstants.STYLE_PERIMETER] = mxPerimeter.RectanglePerimeter; - * style[mxConstants.STYLE_ROUNDED] = true; - * graph.getStylesheet().putCellStyle('rounded', style); - * (end) - * - * In the above example, the new style is an object. The possible keys of - * the object are all the constants in <mxConstants> that start with STYLE - * and the values are either JavaScript objects, such as - * <mxPerimeter.RightAngleRectanglePerimeter> (which is in fact a function) - * or expressions, such as true. Note that not all keys will be - * interpreted by all shapes (eg. the line shape ignores the fill color). - * The final call to this method associates the style with a name in the - * stylesheet. The style is used in a cell with the following code: - * - * (code) - * model.setStyle(cell, 'rounded'); - * (end) - * - * Parameters: - * - * name - Name for the style to be stored. - * style - Key, value pairs that define the style. - */ -mxStylesheet.prototype.putCellStyle = function(name, style) -{ - this.styles[name] = style; -}; - -/** - * Function: getCellStyle - * - * Returns the cell style for the specified stylename or the given - * defaultStyle if no style can be found for the given stylename. - * - * Parameters: - * - * name - String of the form [(stylename|key=value);] that represents the - * style. - * defaultStyle - Default style to be returned if no style can be found. - */ -mxStylesheet.prototype.getCellStyle = function(name, defaultStyle) -{ - var style = defaultStyle; - - if (name != null && name.length > 0) - { - var pairs = name.split(';'); - - if (style != null && - name.charAt(0) != ';') - { - style = mxUtils.clone(style); - } - else - { - style = new Object(); - } - - // Parses each key, value pair into the existing style - for (var i = 0; i < pairs.length; i++) - { - var tmp = pairs[i]; - var pos = tmp.indexOf('='); - - if (pos >= 0) - { - var key = tmp.substring(0, pos); - var value = tmp.substring(pos + 1); - - if (value == mxConstants.NONE) - { - delete style[key]; - } - else if (mxUtils.isNumeric(value)) - { - style[key] = parseFloat(value); - } - else - { - style[key] = value; - } - } - else - { - // Merges the entries from a named style - var tmpStyle = this.styles[tmp]; - - if (tmpStyle != null) - { - for (var key in tmpStyle) - { - style[key] = tmpStyle[key]; - } - } - } - } - } - - return style; -}; diff --git a/src/js/view/mxSwimlaneManager.js b/src/js/view/mxSwimlaneManager.js deleted file mode 100644 index fe40613..0000000 --- a/src/js/view/mxSwimlaneManager.js +++ /dev/null @@ -1,449 +0,0 @@ -/** - * $Id: mxSwimlaneManager.js,v 1.17 2011-01-14 15:21:10 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -/** - * Class: mxSwimlaneManager - * - * Manager for swimlanes and nested swimlanes that sets the size of newly added - * swimlanes to that of their siblings, and propagates changes to the size of a - * swimlane to its siblings, if <siblings> is true, and its ancestors, if - * <bubbling> is true. - * - * Constructor: mxSwimlaneManager - * - * Constructs a new swimlane manager for the given graph. - * - * Arguments: - * - * graph - Reference to the enclosing graph. - */ -function mxSwimlaneManager(graph, horizontal, addEnabled, resizeEnabled) -{ - this.horizontal = (horizontal != null) ? horizontal : true; - this.addEnabled = (addEnabled != null) ? addEnabled : true; - this.resizeEnabled = (resizeEnabled != null) ? resizeEnabled : true; - - this.addHandler = mxUtils.bind(this, function(sender, evt) - { - if (this.isEnabled() && this.isAddEnabled()) - { - this.cellsAdded(evt.getProperty('cells')); - } - }); - - this.resizeHandler = mxUtils.bind(this, function(sender, evt) - { - if (this.isEnabled() && this.isResizeEnabled()) - { - this.cellsResized(evt.getProperty('cells')); - } - }); - - this.setGraph(graph); -}; - -/** - * Extends mxEventSource. - */ -mxSwimlaneManager.prototype = new mxEventSource(); -mxSwimlaneManager.prototype.constructor = mxSwimlaneManager; - -/** - * Variable: graph - * - * Reference to the enclosing <mxGraph>. - */ -mxSwimlaneManager.prototype.graph = null; - -/** - * Variable: enabled - * - * Specifies if event handling is enabled. Default is true. - */ -mxSwimlaneManager.prototype.enabled = true; - -/** - * Variable: horizontal - * - * Specifies the orientation of the swimlanes. Default is true. - */ -mxSwimlaneManager.prototype.horizontal = true; - -/** - * Variable: addEnabled - * - * Specifies if newly added cells should be resized to match the size of their - * existing siblings. Default is true. - */ -mxSwimlaneManager.prototype.addEnabled = true; - -/** - * Variable: resizeEnabled - * - * Specifies if resizing of swimlanes should be handled. Default is true. - */ -mxSwimlaneManager.prototype.resizeEnabled = true; - -/** - * Variable: moveHandler - * - * Holds the function that handles the move event. - */ -mxSwimlaneManager.prototype.addHandler = null; - -/** - * Variable: moveHandler - * - * Holds the function that handles the move event. - */ -mxSwimlaneManager.prototype.resizeHandler = null; - -/** - * Function: isEnabled - * - * Returns true if events are handled. This implementation - * returns <enabled>. - */ -mxSwimlaneManager.prototype.isEnabled = function() -{ - return this.enabled; -}; - -/** - * Function: setEnabled - * - * Enables or disables event handling. This implementation - * updates <enabled>. - * - * Parameters: - * - * enabled - Boolean that specifies the new enabled state. - */ -mxSwimlaneManager.prototype.setEnabled = function(value) -{ - this.enabled = value; -}; - -/** - * Function: isHorizontal - * - * Returns <horizontal>. - */ -mxSwimlaneManager.prototype.isHorizontal = function() -{ - return this.horizontal; -}; - -/** - * Function: setHorizontal - * - * Sets <horizontal>. - */ -mxSwimlaneManager.prototype.setHorizontal = function(value) -{ - this.horizontal = value; -}; - -/** - * Function: isAddEnabled - * - * Returns <addEnabled>. - */ -mxSwimlaneManager.prototype.isAddEnabled = function() -{ - return this.addEnabled; -}; - -/** - * Function: setAddEnabled - * - * Sets <addEnabled>. - */ -mxSwimlaneManager.prototype.setAddEnabled = function(value) -{ - this.addEnabled = value; -}; - -/** - * Function: isResizeEnabled - * - * Returns <resizeEnabled>. - */ -mxSwimlaneManager.prototype.isResizeEnabled = function() -{ - return this.resizeEnabled; -}; - -/** - * Function: setResizeEnabled - * - * Sets <resizeEnabled>. - */ -mxSwimlaneManager.prototype.setResizeEnabled = function(value) -{ - this.resizeEnabled = value; -}; - -/** - * Function: getGraph - * - * Returns the graph that this manager operates on. - */ -mxSwimlaneManager.prototype.getGraph = function() -{ - return this.graph; -}; - -/** - * Function: setGraph - * - * Sets the graph that the manager operates on. - */ -mxSwimlaneManager.prototype.setGraph = function(graph) -{ - if (this.graph != null) - { - this.graph.removeListener(this.addHandler); - this.graph.removeListener(this.resizeHandler); - } - - this.graph = graph; - - if (this.graph != null) - { - this.graph.addListener(mxEvent.ADD_CELLS, this.addHandler); - this.graph.addListener(mxEvent.CELLS_RESIZED, this.resizeHandler); - } -}; - -/** - * Function: isSwimlaneIgnored - * - * Returns true if the given swimlane should be ignored. - */ -mxSwimlaneManager.prototype.isSwimlaneIgnored = function(swimlane) -{ - return !this.getGraph().isSwimlane(swimlane); -}; - -/** - * Function: isCellHorizontal - * - * Returns true if the given cell is horizontal. If the given cell is not a - * swimlane, then the global orientation is returned. - */ -mxSwimlaneManager.prototype.isCellHorizontal = function(cell) -{ - if (this.graph.isSwimlane(cell)) - { - var state = this.graph.view.getState(cell); - var style = (state != null) ? state.style : this.graph.getCellStyle(cell); - - return mxUtils.getValue(style, mxConstants.STYLE_HORIZONTAL, 1) == 1; - } - - return !this.isHorizontal(); -}; - -/** - * Function: cellsAdded - * - * Called if any cells have been added. - * - * Parameters: - * - * cell - Array of <mxCells> that have been added. - */ -mxSwimlaneManager.prototype.cellsAdded = function(cells) -{ - if (cells != null) - { - var model = this.getGraph().getModel(); - - model.beginUpdate(); - try - { - for (var i = 0; i < cells.length; i++) - { - if (!this.isSwimlaneIgnored(cells[i])) - { - this.swimlaneAdded(cells[i]); - } - } - } - finally - { - model.endUpdate(); - } - } -}; - -/** - * Function: swimlaneAdded - * - * Updates the size of the given swimlane to match that of any existing - * siblings swimlanes. - * - * Parameters: - * - * swimlane - <mxCell> that represents the new swimlane. - */ -mxSwimlaneManager.prototype.swimlaneAdded = function(swimlane) -{ - var model = this.getGraph().getModel(); - var parent = model.getParent(swimlane); - var childCount = model.getChildCount(parent); - var geo = null; - - // Finds the first valid sibling swimlane as reference - for (var i = 0; i < childCount; i++) - { - var child = model.getChildAt(parent, i); - - if (child != swimlane && !this.isSwimlaneIgnored(child)) - { - geo = model.getGeometry(child); - - if (geo != null) - { - break; - } - } - } - - // Applies the size of the refernece to the newly added swimlane - if (geo != null) - { - this.resizeSwimlane(swimlane, geo.width, geo.height); - } -}; - -/** - * Function: cellsResized - * - * Called if any cells have been resizes. Calls <swimlaneResized> for all - * swimlanes where <isSwimlaneIgnored> returns false. - * - * Parameters: - * - * cells - Array of <mxCells> whose size was changed. - */ -mxSwimlaneManager.prototype.cellsResized = function(cells) -{ - if (cells != null) - { - var model = this.getGraph().getModel(); - - model.beginUpdate(); - try - { - // Finds the top-level swimlanes and adds offsets - for (var i = 0; i < cells.length; i++) - { - if (!this.isSwimlaneIgnored(cells[i])) - { - var geo = model.getGeometry(cells[i]); - - if (geo != null) - { - var size = new mxRectangle(0, 0, geo.width, geo.height); - var top = cells[i]; - var current = top; - - while (current != null) - { - top = current; - current = model.getParent(current); - var tmp = (this.graph.isSwimlane(current)) ? - this.graph.getStartSize(current) : - new mxRectangle(); - size.width += tmp.width; - size.height += tmp.height; - } - - this.resizeSwimlane(top, size.width, size.height); - } - } - } - } - finally - { - model.endUpdate(); - } - } -}; - -/** - * Function: resizeSwimlane - * - * Called from <cellsResized> for all swimlanes that are not ignored to update - * the size of the siblings and the size of the parent swimlanes, recursively, - * if <bubbling> is true. - * - * Parameters: - * - * swimlane - <mxCell> whose size has changed. - */ -mxSwimlaneManager.prototype.resizeSwimlane = function(swimlane, w, h) -{ - var model = this.getGraph().getModel(); - - model.beginUpdate(); - try - { - if (!this.isSwimlaneIgnored(swimlane)) - { - var geo = model.getGeometry(swimlane); - - if (geo != null) - { - var horizontal = this.isCellHorizontal(swimlane); - - if ((horizontal && geo.height != h) || (!horizontal && geo.width != w)) - { - geo = geo.clone(); - - if (horizontal) - { - geo.height = h; - } - else - { - geo.width = w; - } - - model.setGeometry(swimlane, geo); - } - } - } - - var tmp = (this.graph.isSwimlane(swimlane)) ? - this.graph.getStartSize(swimlane) : - new mxRectangle(); - w -= tmp.width; - h -= tmp.height; - - var childCount = model.getChildCount(swimlane); - - for (var i = 0; i < childCount; i++) - { - var child = model.getChildAt(swimlane, i); - this.resizeSwimlane(child, w, h); - } - } - finally - { - model.endUpdate(); - } -}; - -/** - * Function: destroy - * - * Removes all handlers from the <graph> and deletes the reference to it. - */ -mxSwimlaneManager.prototype.destroy = function() -{ - this.setGraph(null); -}; diff --git a/src/js/view/mxTemporaryCellStates.js b/src/js/view/mxTemporaryCellStates.js deleted file mode 100644 index ce8232c..0000000 --- a/src/js/view/mxTemporaryCellStates.js +++ /dev/null @@ -1,105 +0,0 @@ -/** - * $Id: mxTemporaryCellStates.js,v 1.10 2010-04-20 14:43:12 gaudenz Exp $ - * Copyright (c) 2006-2010, JGraph Ltd - */ -/** - * Class: mxTemporaryCellStates - * - * Extends <mxPoint> to implement a 2-dimensional rectangle with double - * precision coordinates. - * - * Constructor: mxRectangle - * - * Constructs a new rectangle for the optional parameters. If no parameters - * are given then the respective default values are used. - */ -function mxTemporaryCellStates(view, scale, cells) -{ - this.view = view; - scale = (scale != null) ? scale : 1; - - // Stores the previous state - this.oldBounds = view.getGraphBounds(); - this.oldStates = view.getStates(); - this.oldScale = view.getScale(); - - // Creates space for new states - view.setStates(new mxDictionary()); - view.setScale(scale); - - if (cells != null) - { - // Creates virtual parent state for validation - var state = view.createState(new mxCell()); - - // Validates the vertices and edges without adding them to - // the model so that the original cells are not modified - for (var i = 0; i < cells.length; i++) - { - view.validateBounds(state, cells[i]); - } - - var bbox = null; - - for (var i = 0; i < cells.length; i++) - { - var bounds = view.validatePoints(state, cells[i]); - - if (bbox == null) - { - bbox = bounds; - } - else - { - bbox.add(bounds); - } - } - - if (bbox == null) - { - bbox = new mxRectangle(); - } - - view.setGraphBounds(bbox); - } -}; - -/** - * Variable: view - * - * Holds the width of the rectangle. Default is 0. - */ -mxTemporaryCellStates.prototype.view = null; - -/** - * Variable: oldStates - * - * Holds the height of the rectangle. Default is 0. - */ -mxTemporaryCellStates.prototype.oldStates = null; - -/** - * Variable: oldBounds - * - * Holds the height of the rectangle. Default is 0. - */ -mxTemporaryCellStates.prototype.oldBounds = null; - -/** - * Variable: oldScale - * - * Holds the height of the rectangle. Default is 0. - */ -mxTemporaryCellStates.prototype.oldScale = null; - -/** - * Function: destroy - * - * Returns the top, left corner as a new <mxPoint>. - */ -mxTemporaryCellStates.prototype.destroy = function() -{ - this.view.setScale(this.oldScale); - this.view.setStates(this.oldStates); - this.view.setGraphBounds(this.oldBounds); -}; diff --git a/src/js/xcos/core/details.js b/src/js/xcos/core/details.js deleted file mode 100644 index fbeffda..0000000 --- a/src/js/xcos/core/details.js +++ /dev/null @@ -1,204 +0,0 @@ -// All arrays - separated by ',' or ';' or ' ' are taken to be 1 Dimensional -// Only during printing, their nomenclature will change -// Good read: http://javascript.info/tutorial/arguments#keyword-arguments - -function scicos_block() { - var options = arguments[0] || new Object(); - this.graphics = options.graphics || new scicos_graphics(); - this.model = options.model || new scicos_model(); - this.gui = options.gui || ''; - this.docs = options.docs || []; -} - -function scicos_graphics() { - var options = arguments[0] || new Object(); - this.orig = options.orig || [0, 0]; - this.sz = options.sz || [80, 80]; // Space and comma works the same! - this.flip = options.flip || true; - this.theta = options.theta || 0; - this.exprs = options.exprs || []; - this.pin = options.pin || []; - this.pout = options.pout || []; - this.pein = options.pein || []; - this.peout = options.peout || []; - this.gr_i = options.gr_i || []; - this.id = options.id || ''; - this.in_implicit = options.in_implicit || []; - this.out_implicit = options.out_implicit || ''; // There is only one! - this.in_style = options.in_style || []; - this.out_style = options.out_style || ''; - this.in_label = options.in_label || []; - this.out_label = options.out_label || ''; - this.style = options.style || ''; -} - -function scicos_model() { - var options = arguments[0] || new Object(); - this.sim = options.sim || ''; - this.in = options.in || []; - this.in2 = options.in2 || []; - this.intyp = options.intyp || []; - this.out = options.out || []; - this.out2 = options.out2 || []; - this.outtyp = options.outtyp || 1; - this.evtin = options.evtin || []; - this.evtout = options.evtout || []; - this.state = options.state || []; - this.dstate = options.dstate || []; - this.odstate = options.odstate || []; - this.ipar = options.ipar || []; - this.rpar = options.rpar || []; - this.opar = options.opar || []; - this.blocktype = options.blocktype || 'c'; - this.firing = options.firing || []; - this.dep_ut = options.dep_ut || [false, false]; - this.label = options.label || ''; // If label not available, use image - this.nzcross = options.nzcross || 0; - this.nmode = options.nmode || 0; - this.equations = options.equations || []; - this.uid = options.uid || ''; -} - -// This might also have to be overloaded -function scicos_diagram() { - this.props = new scicos_params(); - this.objs = []; - this.version = ''; - this.contrib = []; -} - -// This might also have to be overloaded -function scicos_params() { - this.wpar = [600, 450, 0, 0, 600, 450]; - this.titlex = 'Untitled'; - this.tf = 100000; - this.tol = [Math.pow(10, -6), Math.pow(10, -6), Math.pow(10, -10), this.tf+1, 0, 1, 0]; - this.context = []; - this.void1 = []; - this.options = new default_options(); - this.void2 = []; - this.void3 = []; - this.doc = []; -} - -// This might also have to be overloaded -function default_options() { - var options = new Object(); - var col3d = [0.8, 0.8, 0.8]; - options['3D'] = [true, 33]; - options['Background'] = [8, 1]; // white,black - options['Link'] = [1, 5]; // black,red - options['ID'] = [[4, 1, 10, 1], [4, 1, 2, 1]]; - options['Cmap'] = col3d; - return options; -} - -function zeros(n){ - return new Array(n+1).join('0').split('').map(parseFloat); -} - -function standard_define() { - var sz = arguments[0]; - var model = arguments[1]; - var label = arguments[2]; - var gr_i = arguments[3] || []; - - var pin = []; - var pout = []; - var pein = []; - var peout = []; - - var nin = model.in.length; - if(nin > 0){ - pin = zeros(nin); - } - var nout = model.out.length; - if(nout > 0){ - pout = zeros(nout); - } - var ncin = model.evtin.length; - if(ncin > 0){ - pein = zeros(ncin); - } - var ncout = model.evtout.length; - if(ncout > 0){ - peout = zeros(ncout); - } - gr_i = [gr_i, 8]; - if(gr_i[1] == []){ - gr_i[1] = 8; - } - if(gr_i[1] == 0){ - gr_i[1] = []; - } - var graphics_options = { - sz: sz, - pin: pin, - pout: pout, - pein: pein, - peout: peout, - gr_i: gr_i, - exprs: label - }; - var graphics = new scicos_graphics(graphics_options); - var block_options = { - graphics: graphics, - model: model, - gui: arguments.callee.caller.name - }; - return new scicos_block(block_options); -} - -function scicos_link (){ - this.xx = []; - this.yy = []; - this.id = ''; - this.thick = [0, 0]; - this.ct = [1, 1]; - this.from = []; - this.to = []; -} - -function ANDLOG_f(){ - var model = new scicos_model(); - model.sim = "andlog"; - model.out = [1]; - model.out2 = [1]; // null -> 1 - model.evtin = [-1,-1]; // 1, 1 -> -1, -1 - model.blocktype = "d"; - model.firing = []; - model.dep_ut = [false, false]; - var gr_i = "xstringb(orig(1),orig(2),txt,sz(1),sz(2),'fill');"; - var block = new standard_define([80,80], model, 'LOGICAL<BR>AND', gr_i); // 3 -> 80 - - // Style - block.graphics.out_implicit = "E"; - block.graphics.out_style = "ExplicitOutputPort;align=right;verticalAlign=middle;spacing=10.0;rotation=0"; - block.graphics.style = "ANDLOG_f"; - return block; -} - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/resources/editor.properties b/src/resources/editor.properties deleted file mode 100644 index 23432a8..0000000 --- a/src/resources/editor.properties +++ /dev/null @@ -1,5 +0,0 @@ -askZoom=Enter zoom (%25) -properties=Properties -outline=Outline -tasks=Tasks -help=Help diff --git a/src/resources/graph.properties b/src/resources/graph.properties deleted file mode 100644 index baf61f8..0000000 --- a/src/resources/graph.properties +++ /dev/null @@ -1,11 +0,0 @@ -alreadyConnected=Nodes already connected -containsValidationErrors=Contains validation errors -updatingDocument=Updating Document. Please wait... -updatingSelection=Updating Selection. Please wait... -collapse-expand=Collapse/Expand -doubleClickOrientation=Doubleclick to change orientation -close=Close -error=Error -done=Done -cancel=Cancel -ok=OK |