diff options
author | adhitya | 2016-04-10 12:28:28 +0000 |
---|---|---|
committer | adhitya | 2016-04-10 12:28:28 +0000 |
commit | 0b1c069f88dab0288a01c6aed4d77f4e6d2f6474 (patch) | |
tree | b5ae6b1f512a674f79674a12f675d22324cd268f /src/js/view/mxGraph.js | |
parent | 1993f1da86e293aaf9996b8d7a4f6d9a9224f270 (diff) | |
download | xcos-on-web-0b1c069f88dab0288a01c6aed4d77f4e6d2f6474.tar.gz xcos-on-web-0b1c069f88dab0288a01c6aed4d77f4e6d2f6474.tar.bz2 xcos-on-web-0b1c069f88dab0288a01c6aed4d77f4e6d2f6474.zip |
Removed (un)necessary files
Diffstat (limited to 'src/js/view/mxGraph.js')
-rw-r--r-- | src/js/view/mxGraph.js | 11176 |
1 files changed, 0 insertions, 11176 deletions
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; - } -}; |